// // 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. //
// Context.cpp: Implements the gl::Context class, managing all GL state and performing // rendering operations. It is the GLES2 specific implementation of EGLContext. #include"libANGLE/Context.inl.h"
template <typename T>
angle::Result GetQueryObjectParameter(const Context *context, Query *query, GLenum pname, T *params)
{ if (!query)
{ // Some applications call into glGetQueryObjectuiv(...) prior to calling glBeginQuery(...) // This wouldn't be an issue since the validation layer will handle such a usecases but when // the app enables EGL_KHR_create_context_no_error extension, we skip the validation layer. switch (pname)
{ case GL_QUERY_RESULT_EXT:
*params = 0; break; case GL_QUERY_RESULT_AVAILABLE_EXT:
*params = GL_FALSE; break; default:
UNREACHABLE(); return angle::Result::Stop;
} return angle::Result::Continue;
}
switch (pname)
{ case GL_QUERY_RESULT_EXT: return query->getResult(context, params); case GL_QUERY_RESULT_AVAILABLE_EXT:
{ bool available = false; if (context->isContextLost())
{
available = true;
} else
{
ANGLE_TRY(query->isResultAvailable(context, &available));
}
*params = CastFromStateValue<T>(pname, static_cast<GLuint>(available)); return angle::Result::Continue;
} default:
UNREACHABLE(); return angle::Result::Stop;
}
}
Version GetClientVersion(egl::Display *display, const egl::AttributeMap &attribs, const EGLenum clientType)
{
Version requestedVersion =
Version(GetClientMajorVersion(attribs), GetClientMinorVersion(attribs)); if (GetBackwardCompatibleContext(attribs))
{ if (clientType == EGL_OPENGL_API)
{
Optional<gl::Version> maxSupportedDesktopVersion =
display->getImplementation()->getMaxSupportedDesktopVersion(); if (maxSupportedDesktopVersion.valid()) return std::max(maxSupportedDesktopVersion.value(), requestedVersion); else return requestedVersion;
} elseif (requestedVersion.major == 1)
{ // If the user requests an ES1 context, we cannot return an ES 2+ context. return Version(1, 1);
} else
{ // Always up the version to at least the max conformant version this display supports. // Only return a higher client version if requested. const Version conformantVersion = std::max(
display->getImplementation()->getMaxConformantESVersion(), requestedVersion); // Limit the WebGL context to at most version 3.1 constbool isWebGL = GetWebGLContext(attribs); return isWebGL ? std::min(conformantVersion, Version(3, 1)) : conformantVersion;
}
} else
{ return requestedVersion;
}
}
// [OpenGL ES 2.0.24] section 3.7 page 83: // In the initial state, TEXTURE_2D and TEXTURE_CUBE_MAP have two-dimensional // and cube map texture state vectors respectively associated with them. // In order that access to these initial textures not be lost, they are treated as texture // objects all of whose names are 0.
Texture *zeroTexture2D = new Texture(mImplementation.get(), {0}, TextureType::_2D);
mZeroTextures[TextureType::_2D].set(this, zeroTexture2D);
Texture *zeroTextureCube = new Texture(mImplementation.get(), {0}, TextureType::CubeMap);
mZeroTextures[TextureType::CubeMap].set(this, zeroTextureCube);
if (getClientVersion() >= Version(3, 0) || mSupportedExtensions.texture3DOES)
{
Texture *zeroTexture3D = new Texture(mImplementation.get(), {0}, TextureType::_3D);
mZeroTextures[TextureType::_3D].set(this, zeroTexture3D);
} if (getClientVersion() >= Version(3, 0))
{
Texture *zeroTexture2DArray = new Texture(mImplementation.get(), {0}, TextureType::_2DArray);
mZeroTextures[TextureType::_2DArray].set(this, zeroTexture2DArray);
} if (getClientVersion() >= Version(3, 1) || mSupportedExtensions.textureMultisampleANGLE)
{
Texture *zeroTexture2DMultisample = new Texture(mImplementation.get(), {0}, TextureType::_2DMultisample);
mZeroTextures[TextureType::_2DMultisample].set(this, zeroTexture2DMultisample);
} if (getClientVersion() >= Version(3, 1))
{
Texture *zeroTexture2DMultisampleArray = new Texture(mImplementation.get(), {0}, TextureType::_2DMultisampleArray);
mZeroTextures[TextureType::_2DMultisampleArray].set(this, zeroTexture2DMultisampleArray);
for (int i = 0; i < mState.mCaps.maxAtomicCounterBufferBindings; i++)
{
bindBufferRange(BufferBinding::AtomicCounter, i, {0}, 0, 0);
}
for (int i = 0; i < mState.mCaps.maxShaderStorageBufferBindings; i++)
{
bindBufferRange(BufferBinding::ShaderStorage, i, {0}, 0, 0);
}
}
if (mSupportedExtensions.textureRectangleANGLE)
{
Texture *zeroTextureRectangle = new Texture(mImplementation.get(), {0}, TextureType::Rectangle);
mZeroTextures[TextureType::Rectangle].set(this, zeroTextureRectangle);
}
if (mSupportedExtensions.EGLImageExternalOES ||
mSupportedExtensions.EGLStreamConsumerExternalNV)
{
Texture *zeroTextureExternal = new Texture(mImplementation.get(), {0}, TextureType::External);
mZeroTextures[TextureType::External].set(this, zeroTextureExternal);
}
// This may change native TEXTURE_2D, TEXTURE_EXTERNAL_OES and TEXTURE_RECTANGLE, // binding states. Ensure state manager is aware of this when binding // this texture type. if (mSupportedExtensions.videoTextureWEBGL)
{
Texture *zeroTextureVideoImage = new Texture(mImplementation.get(), {0}, TextureType::VideoImage);
mZeroTextures[TextureType::VideoImage].set(this, zeroTextureVideoImage);
}
// Add context into the share group
mState.getShareGroup()->addSharedContext(this);
bindVertexArray({0});
if (getClientVersion() >= Version(3, 0))
{ // [OpenGL ES 3.0.2] section 2.14.1 pg 85: // In the initial state, a default transform feedback object is bound and treated as // a transform feedback object with a name of zero. That object is bound any time // BindTransformFeedback is called with id of zero
bindTransformFeedback(GL_TRANSFORM_FEEDBACK, {0});
}
for (auto type : angle::AllEnums<BufferBinding>())
{
bindBuffer(type, {0});
}
bindRenderbuffer(GL_RENDERBUFFER, {0});
for (int i = 0; i < mState.mCaps.maxUniformBufferBindings; i++)
{
bindBufferRange(BufferBinding::Uniform, i, {0}, 0, -1);
}
// Initialize GLES1 renderer if appropriate. if (getClientVersion() < Version(2, 0))
{
mGLES1Renderer.reset(new GLES1Renderer());
}
// Initialize dirty bit masks
mAllDirtyBits.set();
mTexImageDirtyBits.set(State::DIRTY_BIT_UNPACK_STATE);
mTexImageDirtyBits.set(State::DIRTY_BIT_UNPACK_BUFFER_BINDING);
mTexImageDirtyBits.set(State::DIRTY_BIT_EXTENDED); // No dirty objects.
// Readpixels uses the pack state and read FBO
mReadPixelsDirtyBits.set(State::DIRTY_BIT_PACK_STATE);
mReadPixelsDirtyBits.set(State::DIRTY_BIT_PACK_BUFFER_BINDING);
mReadPixelsDirtyBits.set(State::DIRTY_BIT_READ_FRAMEBUFFER_BINDING);
mReadPixelsDirtyObjects.set(State::DIRTY_OBJECT_READ_FRAMEBUFFER);
egl::Error Context::onDestroy(const egl::Display *display)
{ if (!mHasBeenCurrent)
{ // The context is never current, so default resources are not allocated. return egl::NoError();
}
// eglDestoryContext() must have been called for this Context and there must not be any Threads // that still have it current.
ASSERT(mIsDestroyed == true && mRefCount == 0);
// Dump frame capture if enabled.
getShareGroup()->getFrameCaptureShared()->onDestroyContext(this);
// Remove context from the capture share group
getShareGroup()->removeSharedContext(this);
if (mGLES1Renderer)
{
mGLES1Renderer->onDestroy(this, &mState);
}
for (auto fence : mFenceNVMap)
{ if (fence.second)
{
fence.second->onDestroy(this);
}
SafeDelete(fence.second);
}
mFenceNVMap.clear();
for (auto query : mQueryMap)
{ if (query.second != nullptr)
{
query.second->release(this);
}
}
mQueryMap.clear();
for (auto vertexArray : mVertexArrayMap)
{ if (vertexArray.second)
{
vertexArray.second->onDestroy(this);
}
}
mVertexArrayMap.clear();
for (auto transformFeedback : mTransformFeedbackMap)
{ if (transformFeedback.second != nullptr)
{
transformFeedback.second->release(this);
}
}
mTransformFeedbackMap.clear();
for (BindingPointer<Texture> &zeroTexture : mZeroTextures)
{ if (zeroTexture.get() != nullptr)
{
zeroTexture.set(this, nullptr);
}
}
releaseShaderCompiler();
mState.reset(this);
mState.mBufferManager->release(this); // mProgramPipelineManager must be before mShaderProgramManager to give each // PPO the chance to release any references they have to the Programs that // are bound to them before the Programs are released()'ed.
mState.mProgramPipelineManager->release(this);
mState.mShaderProgramManager->release(this);
mState.mTextureManager->release(this);
mState.mRenderbufferManager->release(this);
mState.mSamplerManager->release(this);
mState.mSyncManager->release(this);
mState.mFramebufferManager->release(this);
mState.mMemoryObjectManager->release(this);
mState.mSemaphoreManager->release(this);
// Notify the renderer of a context switch.
angle::Result implResult = mImplementation->onMakeCurrent(this);
// If the implementation fails onMakeCurrent, unset the default framebuffer. if (implResult != angle::Result::Continue)
{
ANGLE_TRY(unsetDefaultFramebuffer()); return angle::ResultToEGL(implResult);
}
// Return the scratch buffers to the display so they can be shared with other contexts while // this one is not current. if (mScratchBuffer.valid())
{
mDisplay->returnScratchBuffer(mScratchBuffer.release());
} if (mZeroFilledBuffer.valid())
{
mDisplay->returnZeroFilledBuffer(mZeroFilledBuffer.release());
}
if (shaderObject->isCompiled(this))
{ // As per Khronos issue 2261: // https://gitlab.khronos.org/Tracker/vk-gl-cts/issues/2261 // We must wait to mark the program separable until it's successfully compiled.
programObject->setSeparable(true);
programObject->attachShader(shaderObject);
if (programObject->link(this) != angle::Result::Continue)
{
deleteShader(shaderID);
deleteProgram(programID); return 0u;
} if (onProgramLink(programObject) != angle::Result::Continue)
{
deleteShader(shaderID);
deleteProgram(programID); return 0u;
}
void Context::deleteSync(GLsync sync)
{ // The spec specifies the underlying Fence object is not deleted until all current // wait commands finish. However, since the name becomes invalid, we cannot query the fence, // and since our API is currently designed for being called from a single thread, we can delete // the fence immediately.
mState.mSyncManager->deleteObject(this, static_cast<GLuint>(reinterpret_cast<uintptr_t>(sync)));
}
// GL_CHROMIUM_lose_context void Context::loseContext(GraphicsResetStatus current, GraphicsResetStatus other)
{ // TODO(geofflang): mark the rest of the share group lost. Requires access to the entire share // group from a context. http://anglebug.com/3379
markContextLost(current);
}
void Context::deleteFramebuffer(FramebufferID framebufferID)
{ // We are responsible for deleting the GL objects from the Framebuffer's pixel local storage.
std::unique_ptr<PixelLocalStorage> plsToDelete;
// Delete the pixel local storage GL objects after the framebuffer, in order to avoid any // potential trickyness with orphaning. if (plsToDelete)
{
plsToDelete->deleteContextObjects(this);
}
}
void Context::deleteFencesNV(GLsizei n, const FenceNVID *fences)
{ for (int i = 0; i < n; i++)
{
FenceNVID fence = fences[i];
FenceNV *fenceObject = nullptr; if (mFenceNVMap.erase(fence, &fenceObject))
{
mFenceNVHandleAllocator.release(fence.value); if (fenceObject)
{
fenceObject->onDestroy(this);
} delete fenceObject;
}
}
}
gl::LabeledObject *Context::getLabeledObject(GLenum identifier, GLuint name) const
{ switch (identifier)
{ case GL_BUFFER: case GL_BUFFER_OBJECT_EXT: return getBuffer({name}); case GL_SHADER: case GL_SHADER_OBJECT_EXT: return getShader({name}); case GL_PROGRAM: case GL_PROGRAM_OBJECT_EXT: return getProgramNoResolveLink({name}); case GL_VERTEX_ARRAY: case GL_VERTEX_ARRAY_OBJECT_EXT: return getVertexArray({name}); case GL_QUERY: case GL_QUERY_OBJECT_EXT: return getQuery({name}); case GL_TRANSFORM_FEEDBACK: return getTransformFeedback({name}); case GL_SAMPLER: return getSampler({name}); case GL_TEXTURE: return getTexture({name}); case GL_RENDERBUFFER: return getRenderbuffer({name}); case GL_FRAMEBUFFER: return getFramebuffer({name}); case GL_PROGRAM_PIPELINE: case GL_PROGRAM_PIPELINE_OBJECT_EXT: return getProgramPipeline({name}); default:
UNREACHABLE(); return nullptr;
}
}
// TODO(jmadill): Determine if the object is dirty based on 'name'. Conservatively assume the // specified object is active until we do this.
mState.setObjectDirty(identifier);
}
void Context::bindTexture(TextureType target, TextureID handle)
{ // Some apps enable KHR_create_context_no_error but pass in an invalid texture type. // Workaround this by silently returning in such situations. if (target == TextureType::InvalidEnum)
{ return;
}
// begin query
ANGLE_CONTEXT_TRY(queryObject->begin(this));
// set query as active for specified target only if begin succeeded
mState.setActiveQuery(this, target, queryObject);
mStateCache.onQueryChange(this);
}
// Intentionally don't call try here. We don't want an early return.
(void)(queryObject->end(this));
// Always unbind the query, even if there was an error. This may delete the query object.
mState.setActiveQuery(this, target, nullptr);
mStateCache.onQueryChange(this);
}
void Context::getFloatvImpl(GLenum pname, GLfloat *params) const
{ // Queries about context capabilities and maximums are answered by Context. // Queries about current GL state values are answered by State. switch (pname)
{ case GL_ALIASED_LINE_WIDTH_RANGE:
params[0] = mState.mCaps.minAliasedLineWidth;
params[1] = mState.mCaps.maxAliasedLineWidth; break; case GL_ALIASED_POINT_SIZE_RANGE:
params[0] = mState.mCaps.minAliasedPointSize;
params[1] = mState.mCaps.maxAliasedPointSize; break; case GL_SMOOTH_POINT_SIZE_RANGE:
params[0] = mState.mCaps.minSmoothPointSize;
params[1] = mState.mCaps.maxSmoothPointSize; break; case GL_SMOOTH_LINE_WIDTH_RANGE:
params[0] = mState.mCaps.minSmoothLineWidth;
params[1] = mState.mCaps.maxSmoothLineWidth; break; case GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT:
ASSERT(mState.mExtensions.textureFilterAnisotropicEXT);
*params = mState.mCaps.maxTextureAnisotropy; break; case GL_MAX_TEXTURE_LOD_BIAS:
*params = mState.mCaps.maxLODBias; break; case GL_MIN_FRAGMENT_INTERPOLATION_OFFSET:
*params = mState.mCaps.minInterpolationOffset; break; case GL_MAX_FRAGMENT_INTERPOLATION_OFFSET:
*params = mState.mCaps.maxInterpolationOffset; break; case GL_PRIMITIVE_BOUNDING_BOX:
params[0] = mState.mBoundingBoxMinX;
params[1] = mState.mBoundingBoxMinY;
params[2] = mState.mBoundingBoxMinZ;
params[3] = mState.mBoundingBoxMinW;
params[4] = mState.mBoundingBoxMaxX;
params[5] = mState.mBoundingBoxMaxY;
params[6] = mState.mBoundingBoxMaxZ;
params[7] = mState.mBoundingBoxMaxW; break; default:
mState.getFloatv(pname, params); break;
}
}
void Context::getIntegervImpl(GLenum pname, GLint *params) const
{ // Queries about context capabilities and maximums are answered by Context. // Queries about current GL state values are answered by State.
switch (pname)
{ case GL_MAX_VERTEX_ATTRIBS:
*params = mState.mCaps.maxVertexAttributes; break; case GL_MAX_VERTEX_UNIFORM_VECTORS:
*params = mState.mCaps.maxVertexUniformVectors; break; case GL_MAX_VERTEX_UNIFORM_COMPONENTS:
*params = mState.mCaps.maxShaderUniformComponents[ShaderType::Vertex]; break; case GL_MAX_VARYING_VECTORS:
*params = mState.mCaps.maxVaryingVectors; break; case GL_MAX_VARYING_COMPONENTS:
*params = mState.mCaps.maxVaryingVectors * 4; break; case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
*params = mState.mCaps.maxCombinedTextureImageUnits; break; case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS:
*params = mState.mCaps.maxShaderTextureImageUnits[ShaderType::Vertex]; break; case GL_MAX_TEXTURE_IMAGE_UNITS:
*params = mState.mCaps.maxShaderTextureImageUnits[ShaderType::Fragment]; break; case GL_MAX_FRAGMENT_UNIFORM_VECTORS:
*params = mState.mCaps.maxFragmentUniformVectors; break; case GL_MAX_FRAGMENT_UNIFORM_COMPONENTS:
*params = mState.mCaps.maxShaderUniformComponents[ShaderType::Fragment]; break; case GL_MAX_RENDERBUFFER_SIZE:
*params = mState.mCaps.maxRenderbufferSize; break; case GL_MAX_COLOR_ATTACHMENTS_EXT:
*params = mState.mCaps.maxColorAttachments; break; case GL_MAX_DRAW_BUFFERS_EXT:
*params = mState.mCaps.maxDrawBuffers; break; case GL_SUBPIXEL_BITS:
*params = mState.mCaps.subPixelBits; break; case GL_MAX_TEXTURE_SIZE:
*params = mState.mCaps.max2DTextureSize; break; case GL_MAX_RECTANGLE_TEXTURE_SIZE_ANGLE:
*params = mState.mCaps.maxRectangleTextureSize; break; case GL_MAX_CUBE_MAP_TEXTURE_SIZE:
*params = mState.mCaps.maxCubeMapTextureSize; break; case GL_MAX_3D_TEXTURE_SIZE:
*params = mState.mCaps.max3DTextureSize; break; case GL_MAX_ARRAY_TEXTURE_LAYERS:
*params = mState.mCaps.maxArrayTextureLayers; break; case GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT:
*params = mState.mCaps.uniformBufferOffsetAlignment; break; case GL_MAX_UNIFORM_BUFFER_BINDINGS:
*params = mState.mCaps.maxUniformBufferBindings; break; case GL_MAX_VERTEX_UNIFORM_BLOCKS:
*params = mState.mCaps.maxShaderUniformBlocks[ShaderType::Vertex]; break; case GL_MAX_FRAGMENT_UNIFORM_BLOCKS:
*params = mState.mCaps.maxShaderUniformBlocks[ShaderType::Fragment]; break; case GL_MAX_COMBINED_UNIFORM_BLOCKS:
*params = mState.mCaps.maxCombinedUniformBlocks; break; case GL_MAX_VERTEX_OUTPUT_COMPONENTS:
*params = mState.mCaps.maxVertexOutputComponents; break; case GL_MAX_FRAGMENT_INPUT_COMPONENTS:
*params = mState.mCaps.maxFragmentInputComponents; break; case GL_MIN_PROGRAM_TEXEL_OFFSET:
*params = mState.mCaps.minProgramTexelOffset; break; case GL_MAX_PROGRAM_TEXEL_OFFSET:
*params = mState.mCaps.maxProgramTexelOffset; break; case GL_MAJOR_VERSION:
*params = getClientVersion().major; break; case GL_MINOR_VERSION:
*params = getClientVersion().minor; break; case GL_MAX_ELEMENTS_INDICES:
*params = mState.mCaps.maxElementsIndices; break; case GL_MAX_ELEMENTS_VERTICES:
*params = mState.mCaps.maxElementsVertices; break; case GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS:
*params = mState.mCaps.maxTransformFeedbackInterleavedComponents; break; case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS:
*params = mState.mCaps.maxTransformFeedbackSeparateAttributes; break; case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS:
*params = mState.mCaps.maxTransformFeedbackSeparateComponents; break; case GL_NUM_COMPRESSED_TEXTURE_FORMATS:
*params = static_cast<GLint>(mState.mCaps.compressedTextureFormats.size()); break; case GL_MAX_SAMPLES_ANGLE:
*params = mState.mCaps.maxSamples; break; case GL_MAX_VIEWPORT_DIMS:
{
params[0] = mState.mCaps.maxViewportWidth;
params[1] = mState.mCaps.maxViewportHeight;
} break; case GL_COMPRESSED_TEXTURE_FORMATS:
std::copy(mState.mCaps.compressedTextureFormats.begin(),
mState.mCaps.compressedTextureFormats.end(), params); break; case GL_RESET_NOTIFICATION_STRATEGY_EXT:
*params = mResetStrategy; break; case GL_NUM_SHADER_BINARY_FORMATS:
*params = static_cast<GLint>(mState.mCaps.shaderBinaryFormats.size()); break; case GL_SHADER_BINARY_FORMATS:
std::copy(mState.mCaps.shaderBinaryFormats.begin(),
mState.mCaps.shaderBinaryFormats.end(), params); break; case GL_NUM_PROGRAM_BINARY_FORMATS:
*params = static_cast<GLint>(mState.mCaps.programBinaryFormats.size()); break; case GL_PROGRAM_BINARY_FORMATS:
std::copy(mState.mCaps.programBinaryFormats.begin(),
mState.mCaps.programBinaryFormats.end(), params); break; case GL_NUM_EXTENSIONS:
*params = static_cast<GLint>(mExtensionStrings.size()); break;
// Desktop client flags case GL_CONTEXT_FLAGS:
{
GLint contextFlags = 0; if (mState.hasProtectedContent())
{
contextFlags |= GL_CONTEXT_FLAG_PROTECTED_CONTENT_BIT_EXT;
}
if (mState.isDebugContext())
{
contextFlags |= GL_CONTEXT_FLAG_DEBUG_BIT_KHR;
}
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.