// // Copyright 2002 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. //
// Display.cpp: Implements the egl::Display class, representing the abstract // display on which graphics are drawn. Implements EGLDisplay. // [EGL 1.4] section 2.1.2 page 3.
static constexpr size_t kWindowSurfaceMapSize = 32; typedef angle::FlatUnorderedMap<EGLNativeWindowType, Surface *, kWindowSurfaceMapSize>
WindowSurfaceMap; // Get a map of all EGL window surfaces to validate that no window has more than one EGL surface // associated with it. static WindowSurfaceMap *GetWindowSurfaces()
{ static angle::base::NoDestructor<WindowSurfaceMap> windowSurfaces; return windowSurfaces.get();
}
switch (eglDevice->getType())
{ #ifdefined(ANGLE_ENABLE_D3D11) case EGL_D3D11_DEVICE_ANGLE:
impl = new rx::DisplayD3D(state); break; #endif #ifdefined(ANGLE_ENABLE_D3D9) case EGL_D3D9_DEVICE_ANGLE: // Currently the only way to get EGLDeviceEXT representing a D3D9 device // is to retrieve one from an already-existing EGLDisplay. // When eglGetPlatformDisplayEXT is called with a D3D9 EGLDeviceEXT, // the already-existing display should be returned. // Therefore this codepath to create a new display from the device // should never be hit.
UNREACHABLE(); break; #endif default:
UNREACHABLE(); break;
}
ASSERT(impl != nullptr); return impl;
}
// On platforms with support for multiple back-ends, allow an environment variable to control // the default. This is useful to run angle with benchmarks without having to modify the // benchmark source. Possible values for this environment variable (ANGLE_DEFAULT_PLATFORM) // are: vulkan, gl, d3d11, null.
EGLAttrib GetDisplayTypeFromEnvironment()
{
std::string angleDefaultEnv = angle::GetEnvironmentVar("ANGLE_DEFAULT_PLATFORM");
angle::ToLower(&angleDefaultEnv);
switch (displayType)
{ case EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE:
UNREACHABLE(); break;
case EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE: case EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE: #ifdefined(ANGLE_ENABLE_D3D9) || defined(ANGLE_ENABLE_D3D11)
impl = new rx::DisplayD3D(state); break; #else // A D3D display was requested on a platform that doesn't support it
UNREACHABLE(); break; #endif
case EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE: #ifdefined(ANGLE_ENABLE_OPENGL) # ifdefined(ANGLE_PLATFORM_WINDOWS)
impl = new rx::DisplayWGL(state); break;
# elif defined(ANGLE_PLATFORM_LINUX) # ifdefined(ANGLE_USE_GBM) if (platformType == 0)
{ // If platformType is unknown, use DisplayGbm now. In the future, it should use // DisplayEGL letting native EGL decide what display to use.
impl = new rx::DisplayGbm(state); break;
} # endif if (deviceType == EGL_PLATFORM_ANGLE_DEVICE_TYPE_EGL_ANGLE)
{
impl = new rx::DisplayEGL(state); break;
} # ifdefined(ANGLE_USE_X11) if (platformType == EGL_PLATFORM_X11_EXT)
{
impl = new rx::DisplayGLX(state); break;
} # endif break;
# elif defined(ANGLE_PLATFORM_ANDROID) // No GL support on this platform, fail display creation.
impl = nullptr; break;
# else # error Unsupported OpenGL platform. # endif #else // No display available
UNREACHABLE(); break;
#endif// defined(ANGLE_ENABLE_OPENGL)
case EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE: #ifdefined(ANGLE_ENABLE_OPENGL) # ifdefined(ANGLE_PLATFORM_WINDOWS)
impl = new rx::DisplayWGL(state); # elif defined(ANGLE_PLATFORM_LINUX) # ifdefined(ANGLE_USE_GBM) if (platformType == 0 ||
platformType == EGL_PLATFORM_VULKAN_DISPLAY_MODE_HEADLESS_ANGLE)
{ // If platformType is unknown, use DisplayGbm now. In the future, it should use // DisplayEGL letting native EGL decide what display to use. // platformType == EGL_PLATFORM_VULKAN_DISPLAY_MODE_HEADLESS_ANGLE is a hack, // to allow ChromeOS GLES backend to continue functioning when Vulkan is enabled.
impl = new rx::DisplayGbm(state); break;
} # endif if (deviceType == EGL_PLATFORM_ANGLE_DEVICE_TYPE_EGL_ANGLE)
{
impl = new rx::DisplayEGL(state); break;
} else
{ # ifdefined(ANGLE_USE_X11) if (platformType == EGL_PLATFORM_X11_EXT)
{
impl = new rx::DisplayGLX(state); break;
} # endif
} # elif defined(ANGLE_PLATFORM_ANDROID)
impl = new rx::DisplayAndroid(state); # else // No GLES support on this platform, fail display creation.
impl = nullptr; # endif #endif// defined(ANGLE_ENABLE_OPENGL) break;
case EGL_PLATFORM_ANGLE_TYPE_METAL_ANGLE: #ifdefined(ANGLE_ENABLE_METAL) if (rx::IsMetalDisplayAvailable())
{
impl = rx::CreateMetalDisplay(state); break;
} #endif // No display available
UNREACHABLE(); break;
case EGL_PLATFORM_ANGLE_TYPE_NULL_ANGLE: #ifdefined(ANGLE_ENABLE_NULL)
impl = new rx::DisplayNULL(state); break; #else // No display available
UNREACHABLE(); break; #endif// defined(ANGLE_ENABLE_NULL)
if (display == nullptr)
{ // Validate the native display if (!Display::isValidNativeDisplay(nativeDisplay))
{ return nullptr;
}
display = new Display(platform, nativeDisplay, nullptr);
displays->insert(std::make_pair(displayKey, display));
} // Apply new attributes if the display is not initialized yet. if (!display->isInitialized())
{
display->setAttributes(updatedAttribMap);
EGLAttrib displayType = display->mAttributeMap.get(EGL_PLATFORM_ANGLE_TYPE_ANGLE);
EGLAttrib deviceType = display->mAttributeMap.get(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE);
EGLAttrib platformType = platform; if (platform == EGL_PLATFORM_ANGLE_ANGLE)
{
platformType =
display->mAttributeMap.get(EGL_PLATFORM_ANGLE_NATIVE_PLATFORM_TYPE_ANGLE);
}
rx::DisplayImpl *impl =
CreateDisplayFromAttribs(displayType, deviceType, platformType, display->getState()); if (impl == nullptr)
{ // No valid display implementation for these attributes return nullptr;
}
// First see if this eglDevice is in use by a Display created using ANGLE platform for (auto &displayMapEntry : *anglePlatformDisplays)
{
egl::Display *iterDisplay = displayMapEntry.second; if (iterDisplay->getDevice() == device)
{
display = iterDisplay;
}
}
if (display == nullptr)
{ // See if the eglDevice is in use by a Display created using the DEVICE platform constauto &iter = devicePlatformDisplays->find(device); if (iter != devicePlatformDisplays->end())
{
display = iter->second;
}
}
if (display == nullptr)
{ // Otherwise create a new Display
display = new Display(EGL_PLATFORM_DEVICE_EXT, 0, device);
devicePlatformDisplays->insert(std::make_pair(device, display));
}
// Apply new attributes if the display is not initialized yet. if (!display->isInitialized())
{
display->setAttributes(attribMap);
rx::DisplayImpl *impl = CreateDisplayFromDevice(device, display->getState());
display->setupDisplayPlatform(impl);
}
// Enable shader caching if debug layers are turned on. This allows us to test that shaders are // properly saved & restored on all platforms. The cache won't allocate space until it's used // and will be ignored entirely if the application / system sets it's own cache functions. if (rx::ShouldUseDebugLayers(mAttributeMap))
{
mBlobCache.resize(1024 * 1024);
}
mConfigSet = mImplementation->generateConfigs(); if (mConfigSet.size() == 0)
{
mImplementation->terminate(); return EglNotInitialized() << "No configs were generated.";
}
// OpenGL ES1 is implemented in the frontend, explicitly add ES1 support to all configs for (auto &config : mConfigSet)
{ // TODO(geofflang): Enable the conformant bit once we pass enough tests // config.second.conformant |= EGL_OPENGL_ES_BIT;
// If we aren't using desktop GL entry points, remove desktop GL support from all configs #if !defined(ANGLE_ENABLE_GL_DESKTOP_FRONTEND)
config.second.renderableType &= ~EGL_OPENGL_BIT; #endif
}
if (!mState.featuresAllDisabled)
{
initializeFrontendFeatures();
}
// All subsequent calls assume the display to be valid and terminated by app. // If it is not terminated or if it isn't even initialized, early return. if (!mTerminatedByApi || !mInitialized)
{ return NoError();
}
// EGL 1.5 Specification // 3.2 Initialization // Termination marks all EGL-specific resources, such as contexts and surfaces, associated // with the specified display for deletion. Handles to all such resources are invalid as soon // as eglTerminate returns. Cache EGL objects that are no longer valid. // // It is fairly common for apps to call eglTerminate while some contexts and/or surfaces are // still current on some thread. Since objects are refCounted, trying to destroy them right away // would only result in a decRef. We instead cache such invalid objects and use other EGL // entrypoints like eglReleaseThread or thread exit events (on the Android platform) to // perform the necessary cleanup.
mInvalidImageSet.insert(mImageSet.begin(), mImageSet.end());
mImageSet.clear();
// Cache total number of contexts before invalidation. This is used as a check to verify that // no context is "lost" while being moved between the various sets.
size_t contextSetSizeBeforeInvalidation = mState.contextSet.size() + mInvalidContextSet.size();
// If app called eglTerminate and no active threads remain, // force realease any context that is still current.
ContextSet contextsStillCurrent = {}; for (gl::Context *context : mState.contextSet)
{ if (context->getRefCount() > 0)
{ if (terminateReason == TerminateReason::NoActiveThreads)
{
ASSERT(mTerminatedByApi);
context->release();
(void)context->unMakeCurrent(this);
} else
{
contextsStillCurrent.emplace(context); continue;
}
}
// Add context that is not current to mInvalidContextSet for cleanup.
mInvalidContextSet.emplace(context);
}
// There are many methods that require contexts that are still current to be present in // display's contextSet like during context release or to notify of state changes in a subject. // So as to not interrupt this flow, do not remove contexts that are still current on some // thread from display's contextSet even though eglTerminate marks such contexts as invalid. // // "mState.contextSet" will now contain only those contexts that are still current on some // thread.
mState.contextSet = std::move(contextsStillCurrent);
// Assert that the total number of contexts is the same before and after context invalidation.
ASSERT(contextSetSizeBeforeInvalidation ==
mState.contextSet.size() + mInvalidContextSet.size());
if (!mState.contextSet.empty())
{ // There was atleast 1 context that was current on some thread, early return. return NoError();
}
// The global texture and semaphore managers should be deleted with the last context that uses // it.
ASSERT(mGlobalTextureShareGroupUsers == 0 && mTextureManager == nullptr);
ASSERT(mGlobalSemaphoreShareGroupUsers == 0 && mSemaphoreManager == nullptr);
// Clean up all invalid objects
ANGLE_TRY(destroyInvalidEglObjects());
mConfigSet.clear();
if (mDevice != nullptr && mDevice->getOwningDisplay() != nullptr)
{ // Don't delete the device if it was created externally using eglCreateDeviceANGLE // We also shouldn't set it to null in case eglInitialize() is called again later
SafeDelete(mDevice);
}
mImplementation->terminate();
mDeviceLost = false;
mInitialized = false;
gl::UninitializeDebugAnnotations();
// TODO(jmadill): Store Platform in Display and deinit here.
ANGLEResetDisplayPlatform(this);
// Insert default values for attributes that have either an Exact or Mask selection criteria, // and a default value that matters (e.g. isn't EGL_DONT_CARE):
attribsWithDefaults.insert(EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER);
attribsWithDefaults.insert(EGL_LEVEL, 0);
attribsWithDefaults.insert(EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT);
attribsWithDefaults.insert(EGL_SURFACE_TYPE, EGL_WINDOW_BIT);
attribsWithDefaults.insert(EGL_TRANSPARENT_TYPE, EGL_NONE); if (getExtensions().pixelFormatFloat)
{
attribsWithDefaults.insert(EGL_COLOR_COMPONENT_TYPE_EXT,
EGL_COLOR_COMPONENT_TYPE_FIXED_EXT);
}
// Add the caller-specified values (Note: the poorly-named insert() method will replace any // of the default values from above): for (auto attribIter = attribs.begin(); attribIter != attribs.end(); attribIter++)
{
attribsWithDefaults.insert(attribIter->first, attribIter->second);
}
if (mImplementation->testDeviceLost())
{
ANGLE_TRY(restoreLostDevice());
}
// This display texture sharing will allow the first context to create the texture share group. bool usingDisplayTextureShareGroup =
attribs.get(EGL_DISPLAY_TEXTURE_SHARE_GROUP_ANGLE, EGL_FALSE) == EGL_TRUE;
gl::TextureManager *shareTextures = nullptr;
if (usingDisplayTextureShareGroup)
{
ASSERT((mTextureManager == nullptr) == (mGlobalTextureShareGroupUsers == 0)); if (mTextureManager == nullptr)
{
mTextureManager = new gl::TextureManager();
}
gl::MemoryProgramCache *programCachePointer = &mMemoryProgramCache; // Check context creation attributes to see if we are using EGL_ANGLE_program_cache_control. // If not, keep caching enabled for EGL_ANDROID_blob_cache, which can have its callbacks set // at any time. bool usesProgramCacheControl = attribs.contains(EGL_CONTEXT_PROGRAM_BINARY_CACHE_ENABLED_ANGLE); if (usesProgramCacheControl)
{ bool programCacheControlEnabled =
(attribs.get(EGL_CONTEXT_PROGRAM_BINARY_CACHE_ENABLED_ANGLE, GL_FALSE) == GL_TRUE); // A program cache size of zero indicates it should be disabled. if (!programCacheControlEnabled || mMemoryProgramCache.maxSize() == 0)
{
programCachePointer = nullptr;
}
}
gl::MemoryShaderCache *shaderCachePointer = &mMemoryShaderCache; // Check if shader caching frontend feature is enabled. if (!mFrontendFeatures.cacheCompiledShader.enabled)
{
shaderCachePointer = nullptr;
}
auto error = previousContext->unMakeCurrent(this); if (previousContext->getRefCount() == 0 && previousContext->isDestroyed())
{ // The previous Context may have been created with a different Display.
Display *previousDisplay = previousContext->getDisplay();
ANGLE_TRY(previousDisplay->releaseContext(previousContext, thread));
}
ANGLE_TRY(error);
}
if (context != nullptr)
{
ANGLE_TRY(context->makeCurrent(this, drawSurface, readSurface)); if (contextChanged)
{
context->addRef();
}
}
// Tick all the scratch buffers to make sure they get cleaned up eventually if they stop being // used.
{
std::lock_guard<std::mutex> lock(mScratchBufferMutex);
for (angle::ScratchBuffer &scatchBuffer : mScratchBuffers)
{
scatchBuffer.tick();
} for (angle::ScratchBuffer &zeroFilledBuffer : mZeroFilledBuffers)
{
zeroFilledBuffer.tick();
}
}
return NoError();
}
Error Display::restoreLostDevice()
{ for (ContextSet::iterator ctx = mState.contextSet.begin(); ctx != mState.contextSet.end();
ctx++)
{ if ((*ctx)->isResetNotificationEnabled())
{ // If reset notifications have been requested, application must delete all contexts // first return EglContextLost();
}
}
// releaseContext must be called with the context being deleted as current. // To do that we can only call this in two places, Display::makeCurrent at the point where this // context is being made uncurrent and in Display::destroyContext where we make the context current // as part of destruction.
Error Display::releaseContext(gl::Context *context, Thread *thread)
{ return releaseContextImpl(context, &mState.contextSet);
}
// Use scoped_ptr to make sure the context is always freed.
std::unique_ptr<gl::Context> unique_context(context);
ASSERT(contexts->find(context) != contexts->end());
contexts->erase(context);
if (context->usingDisplayTextureShareGroup())
{
ASSERT(mGlobalTextureShareGroupUsers >= 1 && mTextureManager != nullptr); if (mGlobalTextureShareGroupUsers == 1)
{ // If this is the last context using the global share group, destroy the global // texture manager so that the textures can be destroyed while a context still // exists
mTextureManager->release(context);
mTextureManager = nullptr;
}
mGlobalTextureShareGroupUsers--;
}
if (context->usingDisplaySemaphoreShareGroup())
{
ASSERT(mGlobalSemaphoreShareGroupUsers >= 1 && mSemaphoreManager != nullptr); if (mGlobalSemaphoreShareGroupUsers == 1)
{ // If this is the last context using the global share group, destroy the global // semaphore manager so that the semaphores can be destroyed while a context still // exists
mSemaphoreManager->release(context);
mSemaphoreManager = nullptr;
}
mGlobalSemaphoreShareGroupUsers--;
}
ANGLE_TRY(context->onDestroy(this));
return NoError();
}
Error Display::destroyContext(Thread *thread, gl::Context *context)
{ auto *currentContext = thread->getContext(); auto *currentDrawSurface = thread->getCurrentDrawSurface(); auto *currentReadSurface = thread->getCurrentReadSurface();
context->setIsDestroyed();
// If the context is still current on at least 1 thread, just return since it'll be released // once no threads have it current anymore. if (context->getRefCount() > 0)
{ return NoError();
}
// For external context, we cannot change the current native context, and the API user should // make sure the native context is current. if (context->isExternal())
{
ANGLE_TRY(releaseContext(context, thread));
} else
{ // Keep |currentContext| alive, while releasing |context|.
gl::ScopedContextRef scopedContextRef(currentContext);
// keep |currentDrawSurface| and |currentReadSurface| alive as well // while releasing |context|.
ScopedSurfaceRef drawSurfaceRef(currentDrawSurface);
ScopedSurfaceRef readSurfaceRef(
currentReadSurface == currentDrawSurface ? nullptr : currentReadSurface);
// Make the context current, so we can release resources belong to the context, and then // when context is released from the current, it will be destroyed. // TODO(http://www.anglebug.com/6322): Don't require a Context to be current in order to // destroy it.
ANGLE_TRY(makeCurrent(thread, currentContext, nullptr, nullptr, context));
ANGLE_TRY(
makeCurrent(thread, context, currentDrawSurface, currentReadSurface, currentContext));
}
// If eglTerminate() has previously been called and this is the last Context the Display owns, // we can now fully terminate the display and release all of its resources. if (mTerminatedByApi)
{ for (const gl::Context *ctx : mState.contextSet)
{ if (ctx->getRefCount() > 0)
{ return NoError();
}
}
// Some extensions are always available because they are implemented in the EGL layer.
mDisplayExtensions.createContext = true;
mDisplayExtensions.createContextNoError = !mFrontendFeatures.forceGlErrorChecking.enabled;
mDisplayExtensions.createContextWebGLCompatibility = true;
mDisplayExtensions.createContextBindGeneratesResource = true;
--> --------------------
--> maximum size reached
--> --------------------
Messung V0.5
¤ Dauer der Verarbeitung: 0.24 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.