// // 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;
}
// GL_ANGLE_request_extension case GL_NUM_REQUESTABLE_EXTENSIONS_ANGLE:
*params = static_cast<GLint>(mRequestableExtensionStrings.size()); break;
// GL_KHR_debug case GL_MAX_DEBUG_MESSAGE_LENGTH:
*params = mState.mCaps.maxDebugMessageLength; break; case GL_MAX_DEBUG_LOGGED_MESSAGES:
*params = mState.mCaps.maxDebugLoggedMessages; break; case GL_MAX_DEBUG_GROUP_STACK_DEPTH:
*params = mState.mCaps.maxDebugGroupStackDepth; break; case GL_MAX_LABEL_LENGTH:
*params = mState.mCaps.maxLabelLength; break;
// GL_OVR_multiview2 case GL_MAX_VIEWS_OVR:
*params = mState.mCaps.maxViews; break;
// GL_EXT_disjoint_timer_query case GL_GPU_DISJOINT_EXT:
*params = mImplementation->getGPUDisjoint(); break; case GL_MAX_FRAMEBUFFER_WIDTH:
*params = mState.mCaps.maxFramebufferWidth; break; case GL_MAX_FRAMEBUFFER_HEIGHT:
*params = mState.mCaps.maxFramebufferHeight; break; case GL_MAX_FRAMEBUFFER_SAMPLES:
*params = mState.mCaps.maxFramebufferSamples; break; case GL_MAX_SAMPLE_MASK_WORDS:
*params = mState.mCaps.maxSampleMaskWords; break; case GL_MAX_COLOR_TEXTURE_SAMPLES:
*params = mState.mCaps.maxColorTextureSamples; break; case GL_MAX_DEPTH_TEXTURE_SAMPLES:
*params = mState.mCaps.maxDepthTextureSamples; break; case GL_MAX_INTEGER_SAMPLES:
*params = mState.mCaps.maxIntegerSamples; break; case GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET:
*params = mState.mCaps.maxVertexAttribRelativeOffset; break; case GL_MAX_VERTEX_ATTRIB_BINDINGS:
*params = mState.mCaps.maxVertexAttribBindings; break; case GL_MAX_VERTEX_ATTRIB_STRIDE:
*params = mState.mCaps.maxVertexAttribStride; break; case GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS:
*params = mState.mCaps.maxShaderAtomicCounterBuffers[ShaderType::Vertex]; break; case GL_MAX_VERTEX_ATOMIC_COUNTERS:
*params = mState.mCaps.maxShaderAtomicCounters[ShaderType::Vertex]; break; case GL_MAX_VERTEX_IMAGE_UNIFORMS:
*params = mState.mCaps.maxShaderImageUniforms[ShaderType::Vertex]; break; case GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS:
*params = mState.mCaps.maxShaderStorageBlocks[ShaderType::Vertex]; break; case GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS:
*params = mState.mCaps.maxShaderAtomicCounterBuffers[ShaderType::Fragment]; break; case GL_MAX_FRAGMENT_ATOMIC_COUNTERS:
*params = mState.mCaps.maxShaderAtomicCounters[ShaderType::Fragment]; break; case GL_MAX_FRAGMENT_IMAGE_UNIFORMS:
*params = mState.mCaps.maxShaderImageUniforms[ShaderType::Fragment]; break; case GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS:
*params = mState.mCaps.maxShaderStorageBlocks[ShaderType::Fragment]; break; case GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET:
*params = mState.mCaps.minProgramTextureGatherOffset; break; case GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET:
*params = mState.mCaps.maxProgramTextureGatherOffset; break; case GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS:
*params = mState.mCaps.maxComputeWorkGroupInvocations; break; case GL_MAX_COMPUTE_UNIFORM_BLOCKS:
*params = mState.mCaps.maxShaderUniformBlocks[ShaderType::Compute]; break; case GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS:
*params = mState.mCaps.maxShaderTextureImageUnits[ShaderType::Compute]; break; case GL_MAX_COMPUTE_SHARED_MEMORY_SIZE:
*params = mState.mCaps.maxComputeSharedMemorySize; break; case GL_MAX_COMPUTE_UNIFORM_COMPONENTS:
*params = mState.mCaps.maxShaderUniformComponents[ShaderType::Compute]; break; case GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS:
*params = mState.mCaps.maxShaderAtomicCounterBuffers[ShaderType::Compute]; break; case GL_MAX_COMPUTE_ATOMIC_COUNTERS:
*params = mState.mCaps.maxShaderAtomicCounters[ShaderType::Compute]; break; case GL_MAX_COMPUTE_IMAGE_UNIFORMS:
*params = mState.mCaps.maxShaderImageUniforms[ShaderType::Compute]; break; case GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS:
*params = static_cast<GLint>(
mState.mCaps.maxCombinedShaderUniformComponents[ShaderType::Compute]); break; case GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS:
*params = mState.mCaps.maxShaderStorageBlocks[ShaderType::Compute]; break; case GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES:
*params = mState.mCaps.maxCombinedShaderOutputResources; break; case GL_MAX_UNIFORM_LOCATIONS:
*params = mState.mCaps.maxUniformLocations; break; case GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS:
*params = mState.mCaps.maxAtomicCounterBufferBindings; break; case GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE:
*params = mState.mCaps.maxAtomicCounterBufferSize; break; case GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS:
*params = mState.mCaps.maxCombinedAtomicCounterBuffers; break; case GL_MAX_COMBINED_ATOMIC_COUNTERS:
*params = mState.mCaps.maxCombinedAtomicCounters; break; case GL_MAX_IMAGE_UNITS:
*params = mState.mCaps.maxImageUnits; break; case GL_MAX_COMBINED_IMAGE_UNIFORMS:
*params = mState.mCaps.maxCombinedImageUniforms; break; case GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS:
*params = mState.mCaps.maxShaderStorageBufferBindings; break; case GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS:
*params = mState.mCaps.maxCombinedShaderStorageBlocks; break; case GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT:
*params = mState.mCaps.shaderStorageBufferOffsetAlignment; break;
// GL_EXT_geometry_shader case GL_MAX_FRAMEBUFFER_LAYERS_EXT:
*params = mState.mCaps.maxFramebufferLayers; break; case GL_LAYER_PROVOKING_VERTEX_EXT:
*params = mState.mCaps.layerProvokingVertex; break; case GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_EXT:
*params = mState.mCaps.maxShaderUniformComponents[ShaderType::Geometry]; break; case GL_MAX_GEOMETRY_UNIFORM_BLOCKS_EXT:
*params = mState.mCaps.maxShaderUniformBlocks[ShaderType::Geometry]; break; case GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS_EXT:
*params = static_cast<GLint>(
mState.mCaps.maxCombinedShaderUniformComponents[ShaderType::Geometry]); break; case GL_MAX_GEOMETRY_INPUT_COMPONENTS_EXT:
*params = mState.mCaps.maxGeometryInputComponents; break; case GL_MAX_GEOMETRY_OUTPUT_COMPONENTS_EXT:
*params = mState.mCaps.maxGeometryOutputComponents; break; case GL_MAX_GEOMETRY_OUTPUT_VERTICES_EXT:
*params = mState.mCaps.maxGeometryOutputVertices; break; case GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_EXT:
*params = mState.mCaps.maxGeometryTotalOutputComponents; break; case GL_MAX_GEOMETRY_SHADER_INVOCATIONS_EXT:
*params = mState.mCaps.maxGeometryShaderInvocations; break; case GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_EXT:
*params = mState.mCaps.maxShaderTextureImageUnits[ShaderType::Geometry]; break; case GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS_EXT:
*params = mState.mCaps.maxShaderAtomicCounterBuffers[ShaderType::Geometry]; break; case GL_MAX_GEOMETRY_ATOMIC_COUNTERS_EXT:
*params = mState.mCaps.maxShaderAtomicCounters[ShaderType::Geometry]; break; case GL_MAX_GEOMETRY_IMAGE_UNIFORMS_EXT:
*params = mState.mCaps.maxShaderImageUniforms[ShaderType::Geometry]; break; case GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS_EXT:
*params = mState.mCaps.maxShaderStorageBlocks[ShaderType::Geometry]; break; // GL_EXT_tessellation_shader case GL_MAX_PATCH_VERTICES_EXT:
*params = mState.mCaps.maxPatchVertices; break; case GL_MAX_TESS_GEN_LEVEL_EXT:
*params = mState.mCaps.maxTessGenLevel; break; case GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS_EXT:
*params = mState.mCaps.maxShaderUniformComponents[ShaderType::TessControl]; break; case GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS_EXT:
*params = mState.mCaps.maxShaderUniformComponents[ShaderType::TessEvaluation]; break; case GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS_EXT:
*params = mState.mCaps.maxShaderTextureImageUnits[ShaderType::TessControl]; break; case GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS_EXT:
*params = mState.mCaps.maxShaderTextureImageUnits[ShaderType::TessEvaluation]; break; case GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS_EXT:
*params = mState.mCaps.maxTessControlOutputComponents; break; case GL_MAX_TESS_PATCH_COMPONENTS_EXT:
*params = mState.mCaps.maxTessPatchComponents; break; case GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS_EXT:
*params = mState.mCaps.maxTessControlTotalOutputComponents; break; case GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS_EXT:
*params = mState.mCaps.maxTessEvaluationOutputComponents; break; case GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS_EXT:
*params = mState.mCaps.maxShaderUniformBlocks[ShaderType::TessControl]; break; case GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS_EXT:
*params = mState.mCaps.maxShaderUniformBlocks[ShaderType::TessEvaluation]; break; case GL_MAX_TESS_CONTROL_INPUT_COMPONENTS_EXT:
*params = mState.mCaps.maxTessControlInputComponents; break; case GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS_EXT:
*params = mState.mCaps.maxTessEvaluationInputComponents; break; case GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS_EXT:
*params = static_cast<GLint>(
mState.mCaps.maxCombinedShaderUniformComponents[ShaderType::TessControl]); break; case GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS_EXT:
*params = static_cast<GLint>(
mState.mCaps.maxCombinedShaderUniformComponents[ShaderType::TessEvaluation]); break; case GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS_EXT:
*params = mState.mCaps.maxShaderAtomicCounterBuffers[ShaderType::TessControl]; break; case GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS_EXT:
*params = mState.mCaps.maxShaderAtomicCounterBuffers[ShaderType::TessEvaluation]; break; case GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS_EXT:
*params = mState.mCaps.maxShaderAtomicCounters[ShaderType::TessControl]; break; case GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS_EXT:
*params = mState.mCaps.maxShaderAtomicCounters[ShaderType::TessEvaluation]; break; case GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS_EXT:
*params = mState.mCaps.maxShaderImageUniforms[ShaderType::TessControl]; break; case GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS_EXT:
*params = mState.mCaps.maxShaderImageUniforms[ShaderType::TessEvaluation]; break; case GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS_EXT:
*params = mState.mCaps.maxShaderStorageBlocks[ShaderType::TessControl]; break; case GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS_EXT:
*params = mState.mCaps.maxShaderStorageBlocks[ShaderType::TessEvaluation]; break; // GLES1 emulation: Caps queries case GL_MAX_TEXTURE_UNITS:
*params = mState.mCaps.maxMultitextureUnits; break; case GL_MAX_MODELVIEW_STACK_DEPTH:
*params = mState.mCaps.maxModelviewMatrixStackDepth; break; case GL_MAX_PROJECTION_STACK_DEPTH:
*params = mState.mCaps.maxProjectionMatrixStackDepth; break; case GL_MAX_TEXTURE_STACK_DEPTH:
*params = mState.mCaps.maxTextureMatrixStackDepth; break; case GL_MAX_LIGHTS:
*params = mState.mCaps.maxLights; break;
// case GL_MAX_CLIP_DISTANCES_EXT: Conflict enum value case GL_MAX_CLIP_PLANES: if (getClientVersion().major >= 2)
{ // GL_APPLE_clip_distance/GL_EXT_clip_cull_distance
*params = mState.mCaps.maxClipDistances;
} else
{
*params = mState.mCaps.maxClipPlanes;
} break; case GL_MAX_CULL_DISTANCES_EXT:
*params = mState.mCaps.maxCullDistances; break; case GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES_EXT:
*params = mState.mCaps.maxCombinedClipAndCullDistances; break; // GLES1 emulation: Vertex attribute queries case GL_VERTEX_ARRAY_BUFFER_BINDING: case GL_NORMAL_ARRAY_BUFFER_BINDING: case GL_COLOR_ARRAY_BUFFER_BINDING: case GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES: case GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING:
getIntegerVertexAttribImpl(pname, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, params); break; case GL_VERTEX_ARRAY_STRIDE: case GL_NORMAL_ARRAY_STRIDE: case GL_COLOR_ARRAY_STRIDE: case GL_POINT_SIZE_ARRAY_STRIDE_OES: case GL_TEXTURE_COORD_ARRAY_STRIDE:
getIntegerVertexAttribImpl(pname, GL_VERTEX_ATTRIB_ARRAY_STRIDE, params); break; case GL_VERTEX_ARRAY_SIZE: case GL_COLOR_ARRAY_SIZE: case GL_TEXTURE_COORD_ARRAY_SIZE:
getIntegerVertexAttribImpl(pname, GL_VERTEX_ATTRIB_ARRAY_SIZE, params); break; case GL_VERTEX_ARRAY_TYPE: case GL_COLOR_ARRAY_TYPE: case GL_NORMAL_ARRAY_TYPE: case GL_POINT_SIZE_ARRAY_TYPE_OES: case GL_TEXTURE_COORD_ARRAY_TYPE:
getIntegerVertexAttribImpl(pname, GL_VERTEX_ATTRIB_ARRAY_TYPE, params); break;
// GL_KHR_parallel_shader_compile case GL_MAX_SHADER_COMPILER_THREADS_KHR:
*params = mState.getMaxShaderCompilerThreads(); break;
// GL_EXT_blend_func_extended case GL_MAX_DUAL_SOURCE_DRAW_BUFFERS_EXT:
*params = mState.mCaps.maxDualSourceDrawBuffers; break;
// OES_shader_multisample_interpolation case GL_FRAGMENT_INTERPOLATION_OFFSET_BITS_OES:
*params = mState.mCaps.subPixelInterpolationOffsetBits; break;
// GL_OES_texture_buffer case GL_MAX_TEXTURE_BUFFER_SIZE:
*params = mState.mCaps.maxTextureBufferSize; break; case GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT:
*params = mState.mCaps.textureBufferOffsetAlignment; break;
// GL_EXT_clip_control case GL_CLIP_ORIGIN_EXT:
*params = mState.mClipControlOrigin; break; case GL_CLIP_DEPTH_MODE_EXT:
*params = mState.mClipControlDepth; break;
// ANGLE_shader_pixel_local_storage case GL_MAX_PIXEL_LOCAL_STORAGE_PLANES_ANGLE:
*params = mState.mCaps.maxPixelLocalStoragePlanes; break; case GL_MAX_COLOR_ATTACHMENTS_WITH_ACTIVE_PIXEL_LOCAL_STORAGE_ANGLE:
*params = mState.mCaps.maxColorAttachmentsWithActivePixelLocalStorage; break; case GL_MAX_COMBINED_DRAW_BUFFERS_AND_PIXEL_LOCAL_STORAGE_PLANES_ANGLE:
*params = mState.mCaps.maxCombinedDrawBuffersAndPixelLocalStoragePlanes; break;
void Context::getInteger64vImpl(GLenum pname, GLint64 *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_ELEMENT_INDEX:
*params = mState.mCaps.maxElementIndex; break; case GL_MAX_UNIFORM_BLOCK_SIZE:
*params = mState.mCaps.maxUniformBlockSize; break; case GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS:
*params = mState.mCaps.maxCombinedShaderUniformComponents[ShaderType::Vertex]; break; case GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS:
*params = mState.mCaps.maxCombinedShaderUniformComponents[ShaderType::Fragment]; break; case GL_MAX_SERVER_WAIT_TIMEOUT:
*params = mState.mCaps.maxServerWaitTimeout; break;
// GL_EXT_disjoint_timer_query case GL_TIMESTAMP_EXT:
*params = mImplementation->getTimestamp(); break;
void Context::getIntegeri_v(GLenum target, GLuint index, GLint *data)
{ // Queries about context capabilities and maximums are answered by Context. // Queries about current GL state values are answered by State.
void Context::getInteger64i_v(GLenum target, GLuint index, GLint64 *data)
{ // Queries about context capabilities and maximums are answered by Context. // Queries about current GL state values are answered by State.
void Context::getBooleani_v(GLenum target, GLuint index, GLboolean *data)
{ // Queries about context capabilities and maximums are answered by Context. // Queries about current GL state values are answered by State.
void Context::texParameteri(TextureType target, GLenum pname, GLint param)
{ // 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;
}
void Context::drawArraysInstanced(PrimitiveMode mode,
GLint first,
GLsizei count,
GLsizei instanceCount)
{ // No-op if count draws no primitives for given mode if (noopDrawInstanced(mode, count, instanceCount))
{
ANGLE_CONTEXT_TRY(mImplementation->handleNoopDrawEvent()); return;
}
void Context::drawElementsInstanced(PrimitiveMode mode,
GLsizei count,
DrawElementsType type, constvoid *indices,
GLsizei instances)
{ // No-op if count draws no primitives for given mode if (noopDrawInstanced(mode, count, instances))
{
ANGLE_CONTEXT_TRY(mImplementation->handleNoopDrawEvent()); return;
}
void Context::drawElementsBaseVertex(PrimitiveMode mode,
GLsizei count,
DrawElementsType type, constvoid *indices,
GLint basevertex)
{ // No-op if count draws no primitives for given mode if (noopDraw(mode, count))
{
ANGLE_CONTEXT_TRY(mImplementation->handleNoopDrawEvent()); return;
}
if (marker == nullptr)
{ // From the EXT_debug_marker spec, // "If <marker> is null then an empty string is pushed on the stack."
ANGLE_CONTEXT_TRY(mImplementation->pushGroupMarker(length, ""));
} else
{
ANGLE_CONTEXT_TRY(mImplementation->pushGroupMarker(length, marker));
}
}
// Get one of the recorded errors and clear its flag, if any. // [OpenGL ES 2.0.24] section 2.5 page 13.
GLenum Context::getError()
{ if (mErrors.empty())
{ return GL_NO_ERROR;
} else
{ return mErrors.popError();
}
}
// NOTE: this function should not assume that this context is current! void Context::markContextLost(GraphicsResetStatus status)
{
ASSERT(status != GraphicsResetStatus::NoError); if (mResetStrategy == GL_LOSE_CONTEXT_ON_RESET_EXT)
{
mResetStatus = status;
mContextLostForced = true;
}
setContextLost();
}
// Stop skipping validation, since many implementation entrypoint assume they can't // be called when lost, or with null object arguments, etc.
mSkipValidation = false;
// Make sure we update TLS. #ifdefined(ANGLE_PLATFORM_APPLE)
SetCurrentValidContextTLS(nullptr); #else
gCurrentValidContext = nullptr; #endif
}
GLenum Context::getGraphicsResetStatus()
{ // Even if the application doesn't want to know about resets, we want to know // as it will allow us to skip all the calls. if (mResetStrategy == GL_NO_RESET_NOTIFICATION_EXT)
{ if (!isContextLost() && mImplementation->getResetStatus() != GraphicsResetStatus::NoError)
{
setContextLost();
}
// EXT_robustness, section 2.6: If the reset notification behavior is // NO_RESET_NOTIFICATION_EXT, then the implementation will never deliver notification of // reset events, and GetGraphicsResetStatusEXT will always return NO_ERROR. return GL_NO_ERROR;
}
// The GL_EXT_robustness spec says that if a reset is encountered, a reset // status should be returned at least once, and GL_NO_ERROR should be returned // once the device has finished resetting. if (!isContextLost())
{
ASSERT(mResetStatus == GraphicsResetStatus::NoError);
mResetStatus = mImplementation->getResetStatus();
if (mResetStatus != GraphicsResetStatus::NoError)
{
setContextLost();
}
} elseif (!mContextLostForced && mResetStatus != GraphicsResetStatus::NoError)
{ // If markContextLost was used to mark the context lost then // assume that is not recoverable, and continue to report the // lost reset status for the lifetime of this context.
mResetStatus = mImplementation->getResetStatus();
}
VertexArray *Context::checkVertexArrayAllocation(VertexArrayID vertexArrayHandle)
{ // Only called after a prior call to Gen.
VertexArray *vertexArray = getVertexArray(vertexArrayHandle); if (!vertexArray)
{
vertexArray = new VertexArray(mImplementation.get(), vertexArrayHandle,
mState.mCaps.maxVertexAttributes, mState.mCaps.maxVertexAttribBindings);
vertexArray->setBufferAccessValidationEnabled(mBufferAccessValidationEnabled);
TransformFeedback *Context::checkTransformFeedbackAllocation(
TransformFeedbackID transformFeedbackHandle)
{ // Only called after a prior call to Gen.
TransformFeedback *transformFeedback = getTransformFeedback(transformFeedbackHandle); if (!transformFeedback)
{
transformFeedback = new TransformFeedback(mImplementation.get(), transformFeedbackHandle, mState.mCaps);
transformFeedback->addRef();
mTransformFeedbackMap.assign(transformFeedbackHandle, transformFeedback);
}
void Context::detachTexture(TextureID texture)
{ // The State cannot unbind image observers itself, they are owned by the Context
Texture *tex = mState.mTextureManager->getTexture(texture); for (auto &imageBinding : mImageObserverBindings)
{ if (imageBinding.getSubject() == tex)
{
imageBinding.reset();
}
}
// Simple pass-through to State's detachTexture method, as textures do not require // allocation map management either here or in the resource manager at detach time. // Zero textures are held by the Context, and we don't attempt to request them from // the State.
mState.detachTexture(this, mZeroTextures, texture);
}
void Context::detachBuffer(Buffer *buffer)
{ // Simple pass-through to State's detachBuffer method, since // only buffer attachments to container objects that are bound to the current context // should be detached. And all those are available in State.
// [OpenGL ES 3.2] section 5.1.2 page 45: // Attachments to unbound container objects, such as // deletion of a buffer attached to a vertex array object which is not bound to the context, // are not affected and continue to act as references on the deleted object
ANGLE_CONTEXT_TRY(mState.detachBuffer(this, buffer));
}
void Context::detachFramebuffer(FramebufferID framebuffer)
{ // Framebuffer detachment is handled by Context, because 0 is a valid // Framebuffer object, and a pointer to it must be passed from Context // to State at binding time.
// [OpenGL ES 2.0.24] section 4.4 page 107: // If a framebuffer that is currently bound to the target FRAMEBUFFER is deleted, it is as // though BindFramebuffer had been executed with the target of FRAMEBUFFER and framebuffer of // zero.
if (mState.removeReadFramebufferBinding(framebuffer) && framebuffer.value != 0)
{
bindReadFramebuffer({0});
}
if (mState.removeDrawFramebufferBinding(framebuffer) && framebuffer.value != 0)
{
bindDrawFramebuffer({0});
}
}
void Context::detachVertexArray(VertexArrayID vertexArray)
{ // Vertex array detachment is handled by Context, because 0 is a valid // VAO, and a pointer to it must be passed from Context to State at // binding time.
// [OpenGL ES 3.0.2] section 2.10 page 43: // If a vertex array object that is currently bound is deleted, the binding // for that object reverts to zero and the default vertex array becomes current. if (mState.removeVertexArrayBinding(this, vertexArray))
{
bindVertexArray({0});
}
}
void Context::detachTransformFeedback(TransformFeedbackID transformFeedback)
{ // Transform feedback detachment is handled by Context, because 0 is a valid // transform feedback, and a pointer to it must be passed from Context to State at // binding time.
// The OpenGL specification doesn't mention what should happen when the currently bound // transform feedback object is deleted. Since it is a container object, we treat it like // VAOs and FBOs and set the current bound transform feedback back to 0. if (mState.removeTransformFeedbackBinding(this, transformFeedback))
{
bindTransformFeedback(GL_TRANSFORM_FEEDBACK, {0});
mStateCache.onActiveTransformFeedbackChange(this);
}
}
// Release the shader compiler so it will be re-created with the requested extensions enabled.
releaseShaderCompiler();
// Invalidate all textures and framebuffer. Some extensions make new formats renderable or // sampleable.
mState.mTextureManager->signalAllTexturesDirty(); for (auto &zeroTexture : mZeroTextures)
{ if (zeroTexture.get() != nullptr)
{
zeroTexture->signalDirtyStorage(InitState::Initialized);
}
}
// Support GL_EXT_texture_norm16 on non-WebGL ES2 contexts. This is needed for R16/RG16 // texturing for HDR video playback in Chromium which uses ES2 for compositor contexts. // Remove this workaround after Chromium migrates to ES3 for compositor contexts. if (mWebGLContext || getClientVersion() < ES_2_0)
{
supportedExtensions.textureNorm16EXT = false;
}
// Require ES 3.1 but could likely be exposed on 3.0
supportedExtensions.textureCubeMapArrayEXT = false;
supportedExtensions.textureCubeMapArrayOES = false;
// Require RED and RG formats
supportedExtensions.textureSRGBR8EXT = false;
supportedExtensions.textureSRGBRG8EXT = false;
// Don't expose GL_EXT_texture_sRGB_decode without sRGB texture support if (!supportedExtensions.sRGBEXT)
{
supportedExtensions.textureSRGBDecodeEXT = false;
}
// Don't expose GL_OES_texture_float_linear without full legacy float texture support // The renderer may report OES_texture_float_linear without OES_texture_float // This is valid in a GLES 3.0 context, but not in a GLES 2.0 context if (!(supportedExtensions.textureFloatOES && supportedExtensions.textureHalfFloatOES))
{
supportedExtensions.textureFloatLinearOES = false;
supportedExtensions.textureHalfFloatLinearOES = false;
}
// Because of the difference in the SNORM to FLOAT conversion formula // between GLES 2.0 and 3.0, vertex type 10_10_10_2 is disabled // when the context version is lower than 3.0
supportedExtensions.vertexType1010102OES = false;
// TODO(http://anglebug.com/2775): Multisample arrays could be supported on ES 3.0 as well // once 2D multisample texture extension is exposed there.
supportedExtensions.textureStorageMultisample2dArrayOES = false;
}
if (getClientVersion() > ES_2_0)
{ // FIXME(geofflang): Don't support EXT_sRGB in non-ES2 contexts // supportedExtensions.sRGB = false;
// If colorBufferFloatEXT is disabled but colorBufferHalfFloatEXT is enabled, then we will // expose some floating-point formats as color buffer targets but reject blits between // fixed-point and floating-point formats (this behavior is only enabled in // colorBufferFloatEXT, and must be rejected if only colorBufferHalfFloatEXT is enabled). // dEQP does not check for this, and will assume that floating-point and fixed-point formats // can be blit onto each other if the format is available. // We require colorBufferFloatEXT to be present in order to enable colorBufferHalfFloatEXT, // so that blitting is always allowed if the requested formats are exposed and have the // correct feature capabilities. WebGL 2 wants to support colorBufferHalfFloatEXT without // colorBufferFloatEXT. if (!supportedExtensions.colorBufferFloatEXT && !mWebGLContext)
{
supportedExtensions.colorBufferHalfFloatEXT = false;
}
// Disable support for CHROMIUM_color_buffer_float_rgb[a] in ES 3.0+, these extensions are // non-conformant in ES 3.0 and superseded by EXT_color_buffer_float.
supportedExtensions.colorBufferFloatRgbCHROMIUM = false;
supportedExtensions.colorBufferFloatRgbaCHROMIUM = false;
}
if (getFrontendFeatures().disableDrawBuffersIndexed.enabled)
{
supportedExtensions.drawBuffersIndexedEXT = false;
supportedExtensions.drawBuffersIndexedOES = false;
}
if (getFrontendFeatures().disableAnisotropicFiltering.enabled)
{
supportedExtensions.textureFilterAnisotropicEXT = false;
}
if (!getFrontendFeatures().emulatePixelLocalStorage.enabled)
{
supportedExtensions.shaderPixelLocalStorageANGLE = false;
supportedExtensions.shaderPixelLocalStorageCoherentANGLE = false;
}
// Some extensions are always available because they are implemented in the GL layer.
supportedExtensions.bindUniformLocationCHROMIUM = true;
supportedExtensions.vertexArrayObjectOES = true;
supportedExtensions.bindGeneratesResourceCHROMIUM = true;
supportedExtensions.clientArraysANGLE = true;
supportedExtensions.requestExtensionANGLE = true;
supportedExtensions.multiDrawANGLE = true;
// Enable the no error extension if the context was created with the flag.
supportedExtensions.noErrorKHR = mSkipValidation;
// Enable surfaceless to advertise we'll have the correct behavior when there is no default FBO
supportedExtensions.surfacelessContextOES = mSurfacelessSupported;
// mState.mExtensions.robustBufferAccessBehaviorKHR is true only if robust access is true and // the backend supports it.
supportedExtensions.robustBufferAccessBehaviorKHR =
mState.hasRobustAccess() && supportedExtensions.robustBufferAccessBehaviorKHR;
// Enable the cache control query unconditionally.
supportedExtensions.programCacheControlANGLE = true;
// If EGL_KHR_fence_sync is not enabled, don't expose GL_OES_EGL_sync.
ASSERT(mDisplay); if (!mDisplay->getExtensions().fenceSync)
{
supportedExtensions.EGLSyncOES = false;
}
if (mDisplay->getExtensions().robustnessVideoMemoryPurgeNV)
{
supportedExtensions.robustnessVideoMemoryPurgeNV = true;
}
supportedExtensions.memorySizeANGLE = true;
// GL_CHROMIUM_lose_context is implemented in the frontend
supportedExtensions.loseContextCHROMIUM = true;
// The ASTC texture extensions have dependency requirements. if (supportedExtensions.textureCompressionAstcHdrKHR ||
supportedExtensions.textureCompressionAstcSliced3dKHR)
{ // GL_KHR_texture_compression_astc_hdr cannot be exposed without also exposing // GL_KHR_texture_compression_astc_ldr
ASSERT(supportedExtensions.textureCompressionAstcLdrKHR);
}
if (supportedExtensions.textureCompressionAstcOES)
{ // GL_OES_texture_compression_astc cannot be exposed without also exposing // GL_KHR_texture_compression_astc_ldr and GL_KHR_texture_compression_astc_hdr
ASSERT(supportedExtensions.textureCompressionAstcLdrKHR);
ASSERT(supportedExtensions.textureCompressionAstcHdrKHR);
}
// GL_KHR_protected_textures // If EGL_KHR_protected_content is not supported then GL_EXT_protected_texture // can not be supported. if (!mDisplay->getExtensions().protectedContentEXT)
{
supportedExtensions.protectedTexturesEXT = false;
}
// GL_ANGLE_get_tex_level_parameter is implemented in the front-end
supportedExtensions.getTexLevelParameterANGLE = true;
// Always enabled. Will return a default string if capture is not enabled.
supportedExtensions.getSerializedContextStringANGLE = true;
// Performance counter queries are always supported. Different groups exist on each back-end.
supportedExtensions.performanceMonitorAMD = true;
// WebGL compatibility
mState.mExtensions.webglCompatibilityANGLE = mWebGLContext; for (constauto &extensionInfo : GetExtensionInfoMap())
{ // If the user has requested that extensions start disabled and they are requestable, // disable them. if (!mExtensionsEnabled && extensionInfo.second.Requestable)
{
mState.mExtensions.*(extensionInfo.second.ExtensionsMember) = false;
}
}
// Hide emulated ETC1 extension from WebGL contexts. if (mWebGLContext && getLimitations().emulatedEtc1)
{
mSupportedExtensions.compressedETC1RGB8SubTextureEXT = false;
mSupportedExtensions.compressedETC1RGB8TextureOES = false;
}
if (getLimitations().emulatedAstc)
{ // Hide emulated ASTC extension from WebGL contexts. if (mWebGLContext)
{
mSupportedExtensions.textureCompressionAstcLdrKHR = false;
mState.mExtensions.textureCompressionAstcLdrKHR = false;
} #if !defined(ANGLE_HAS_ASTCENC) // Don't expose emulated ASTC when it's not built.
mSupportedExtensions.textureCompressionAstcLdrKHR = false;
mState.mExtensions.textureCompressionAstcLdrKHR = false; #endif
}
// If we're capturing application calls for replay, apply some feature limits to increase // portability of the trace. if (getShareGroup()->getFrameCaptureShared()->enabled() ||
getFrontendFeatures().enableCaptureLimits.enabled)
{
INFO() << "Limit some features because "
<< (getShareGroup()->getFrameCaptureShared()->enabled()
? "FrameCapture is enabled"
: "FrameCapture limits were forced")
<< std::endl;
if (!getFrontendFeatures().enableProgramBinaryForCapture.enabled)
{ // Some apps insist on being able to use glProgramBinary. For those, we'll allow the // extension to remain on. Otherwise, force the extension off.
INFO() << "Disabling GL_OES_get_program_binary for trace portability";
mDisplay->overrideFrontendFeatures({"disable_program_binary"}, true);
}
// Set to the most common limit per gpuinfo.org. Required for several platforms we test.
constexpr GLint maxImageUnits = 8;
INFO() << "Limiting image unit count to " << maxImageUnits;
ANGLE_LIMIT_CAP(mState.mCaps.maxImageUnits, maxImageUnits); for (ShaderType shaderType : AllShaderTypes())
{
ANGLE_LIMIT_CAP(mState.mCaps.maxShaderImageUniforms[shaderType], maxImageUnits);
}
// Set a large uniform buffer offset alignment that works on multiple platforms. // The offset used by the trace needs to be divisible by the device's actual value. // Values seen during development: ARM (16), Intel (32), Qualcomm (128), Nvidia (256)
constexpr GLint uniformBufferOffsetAlignment = 256;
ASSERT(uniformBufferOffsetAlignment % mState.mCaps.uniformBufferOffsetAlignment == 0);
INFO() << "Setting uniform buffer offset alignment to " << uniformBufferOffsetAlignment;
mState.mCaps.uniformBufferOffsetAlignment = uniformBufferOffsetAlignment;
// Also limit texture buffer offset alignment, if enabled if (mState.mExtensions.textureBufferAny())
{
constexpr GLint textureBufferOffsetAlignment =
gl::limits::kMinTextureBufferOffsetAlignment;
ASSERT(textureBufferOffsetAlignment % mState.mCaps.textureBufferOffsetAlignment == 0);
INFO() << "Setting texture buffer offset alignment to " << textureBufferOffsetAlignment;
mState.mCaps.textureBufferOffsetAlignment = textureBufferOffsetAlignment;
}
INFO() << "Disabling GL_EXT_map_buffer_range and GL_OES_mapbuffer during capture, which " "are not supported on some native drivers";
mState.mExtensions.mapBufferRangeEXT = false;
mState.mExtensions.mapbufferOES = false;
INFO() << "Disabling GL_CHROMIUM_bind_uniform_location during capture, which is not " "supported on native drivers";
mState.mExtensions.bindUniformLocationCHROMIUM = false;
INFO() << "Disabling GL_NV_shader_noperspective_interpolation during capture, which is not " "supported on some native drivers";
mState.mExtensions.shaderNoperspectiveInterpolationNV = false;
INFO() << "Disabling GL_NV_framebuffer_blit during capture, which is not " "supported on some native drivers";
mState.mExtensions.framebufferBlitNV = false;
// Unity based applications are sending down GL streams with undefined behavior. // Disabling EGL_KHR_create_context_no_error (which enables a new EGL attrib) prevents that, // but we don't have the infrastructure for disabling EGL extensions yet. // Instead, disable GL_KHR_no_error (which disables exposing the GL extension), which // prevents writing invalid calls to the capture.
INFO() << "Enabling validation to prevent invalid calls from being captured. This " "effectively disables GL_KHR_no_error and enables GL_ANGLE_robust_client_memory.";
mSkipValidation = false;
mState.mExtensions.noErrorKHR = mSkipValidation;
mState.mExtensions.robustClientMemoryANGLE = !mSkipValidation;
INFO() << "Disabling GL_OES_depth32 during capture, which is not widely supported on " "mobile";
mState.mExtensions.depth32OES = false;
// Pixel 4 (Qualcomm) only supports 6 atomic counter buffer bindings.
constexpr GLint maxAtomicCounterBufferBindings = 6;
INFO() << "Limiting max atomic counter buffer bindings to "
<< maxAtomicCounterBufferBindings;
ANGLE_LIMIT_CAP(mState.mCaps.maxAtomicCounterBufferBindings,
maxAtomicCounterBufferBindings); for (gl::ShaderType shaderType : gl::AllShaderTypes())
{
ANGLE_LIMIT_CAP(mState.mCaps.maxShaderAtomicCounterBuffers[shaderType],
maxAtomicCounterBufferBindings);
}
// SwiftShader only supports 12 shader storage buffer bindings.
constexpr GLint maxShaderStorageBufferBindings = 12;
INFO() << "Limiting max shader storage buffer bindings to "
<< maxShaderStorageBufferBindings;
ANGLE_LIMIT_CAP(mState.mCaps.maxShaderStorageBufferBindings,
maxShaderStorageBufferBindings); for (gl::ShaderType shaderType : gl::AllShaderTypes())
{
ANGLE_LIMIT_CAP(mState.mCaps.maxShaderStorageBlocks[shaderType],
maxShaderStorageBufferBindings);
}
// Pixel 4 only supports GL_MAX_SAMPLES of 4
constexpr GLint maxSamples = 4;
INFO() << "Limiting GL_MAX_SAMPLES to " << maxSamples;
ANGLE_LIMIT_CAP(mState.mCaps.maxSamples, maxSamples);
}
// Disable support for OES_get_program_binary if (mDisplay->getFrontendFeatures().disableProgramBinary.enabled)
{
mState.mExtensions.getProgramBinaryOES = false;
mState.mCaps.shaderBinaryFormats.clear();
mState.mCaps.programBinaryFormats.clear();
mMemoryProgramCache = nullptr;
}
if (mSupportedExtensions.shaderPixelLocalStorageANGLE)
{ int maxDrawableAttachments =
std::min(mState.mCaps.maxDrawBuffers, mState.mCaps.maxColorAttachments);
ShPixelLocalStorageType plsType = mImplementation->getNativePixelLocalStorageType(); if (ShPixelLocalStorageTypeUsesImages(plsType))
{
mState.mCaps.maxPixelLocalStoragePlanes =
mState.mCaps.maxShaderImageUniforms[ShaderType::Fragment];
ANGLE_LIMIT_CAP(mState.mCaps.maxPixelLocalStoragePlanes,
IMPLEMENTATION_MAX_PIXEL_LOCAL_STORAGE_PLANES);
mState.mCaps.maxColorAttachmentsWithActivePixelLocalStorage =
mState.mCaps.maxColorAttachments;
mState.mCaps.maxCombinedDrawBuffersAndPixelLocalStoragePlanes = std::min<GLint>(
mState.mCaps.maxPixelLocalStoragePlanes +
std::min(mState.mCaps.maxDrawBuffers, mState.mCaps.maxColorAttachments),
mState.mCaps.maxCombinedShaderOutputResources);
} else
{
ASSERT(plsType == ShPixelLocalStorageType::FramebufferFetch);
mState.mCaps.maxPixelLocalStoragePlanes = maxDrawableAttachments;
ANGLE_LIMIT_CAP(mState.mCaps.maxPixelLocalStoragePlanes,
IMPLEMENTATION_MAX_PIXEL_LOCAL_STORAGE_PLANES); if (!mSupportedExtensions.drawBuffersIndexedAny())
{ // When pixel local storage is implemented as framebuffer attachments, we need to // disable color masks and blending to its attachments. If the backend context // doesn't have indexed blend and color mask support, then we will have have to // disable them globally. This also means the application can't have its own draw // buffers while PLS is active.
mState.mCaps.maxColorAttachmentsWithActivePixelLocalStorage = 0;
} else
{
mState.mCaps.maxColorAttachmentsWithActivePixelLocalStorage =
maxDrawableAttachments - 1;
}
mState.mCaps.maxCombinedDrawBuffersAndPixelLocalStoragePlanes = maxDrawableAttachments;
}
}
// Update the format caps based on the client version and extensions. // Caps are AND'd with the renderer caps because some core formats are still unsupported in // ES3.
formatCaps.texturable = formatCaps.texturable &&
formatInfo.textureSupport(getClientVersion(), mState.mExtensions);
formatCaps.filterable = formatCaps.filterable &&
formatInfo.filterSupport(getClientVersion(), mState.mExtensions);
formatCaps.textureAttachment =
formatCaps.textureAttachment &&
formatInfo.textureAttachmentSupport(getClientVersion(), mState.mExtensions);
formatCaps.renderbuffer =
formatCaps.renderbuffer &&
formatInfo.renderbufferSupport(getClientVersion(), mState.mExtensions);
formatCaps.blendable =
formatCaps.blendable && formatInfo.blendSupport(getClientVersion(), mState.mExtensions);
// OpenGL ES does not support multisampling with non-rendererable formats // OpenGL ES 3.0 or prior does not support multisampling with integer formats if (!formatCaps.renderbuffer ||
(getClientVersion() < ES_3_1 && !mState.mExtensions.textureMultisampleANGLE &&
formatInfo.isInt()))
{
formatCaps.sampleCounts.clear();
} else
{ // We may have limited the max samples for some required renderbuffer formats due to // non-conformant formats. In this case MAX_SAMPLES needs to be lowered accordingly.
GLuint formatMaxSamples = formatCaps.getMaxSamples();
// GLES 3.0.5 section 4.4.2.2: "Implementations must support creation of renderbuffers // in these required formats with up to the value of MAX_SAMPLES multisamples, with the // exception of signed and unsigned integer formats." if (!formatInfo.isInt() && formatInfo.isRequiredRenderbufferFormat(getClientVersion()))
{
ASSERT(getClientVersion() < ES_3_0 || formatMaxSamples >= 4);
mState.mCaps.maxSamples =
std::min(static_cast<GLuint>(mState.mCaps.maxSamples), formatMaxSamples);
}
// Handle GLES 3.1 MAX_*_SAMPLES values similarly to MAX_SAMPLES. if (getClientVersion() >= ES_3_1 || mState.mExtensions.textureMultisampleANGLE)
{ // GLES 3.1 section 9.2.5: "Implementations must support creation of renderbuffers // in these required formats with up to the value of MAX_SAMPLES multisamples, with // the exception that the signed and unsigned integer formats are required only to // support creation of renderbuffers with up to the value of MAX_INTEGER_SAMPLES // multisamples, which must be at least one." if (formatInfo.isInt())
{
mState.mCaps.maxIntegerSamples = std::min( static_cast<GLuint>(mState.mCaps.maxIntegerSamples), formatMaxSamples);
}
// If program binary is disabled, blank out the memory cache pointer. if (!mSupportedExtensions.getProgramBinaryOES)
{
mMemoryProgramCache = nullptr;
}
// Compute which buffer types are allowed
mValidBufferBindings.reset();
mValidBufferBindings.set(BufferBinding::ElementArray);
mValidBufferBindings.set(BufferBinding::Array);
if (mState.mExtensions.pixelBufferObjectNV || getClientVersion() >= ES_3_0)
{
mValidBufferBindings.set(BufferBinding::PixelPack);
mValidBufferBindings.set(BufferBinding::PixelUnpack);
}
if (getClientVersion() >= ES_3_0)
{
mValidBufferBindings.set(BufferBinding::CopyRead);
mValidBufferBindings.set(BufferBinding::CopyWrite);
mValidBufferBindings.set(BufferBinding::TransformFeedback);
mValidBufferBindings.set(BufferBinding::Uniform);
}
if (getClientVersion() >= ES_3_1)
{
mValidBufferBindings.set(BufferBinding::AtomicCounter);
mValidBufferBindings.set(BufferBinding::ShaderStorage);
mValidBufferBindings.set(BufferBinding::DrawIndirect);
mValidBufferBindings.set(BufferBinding::DispatchIndirect);
}
if (getClientVersion() >= ES_3_2 || mState.mExtensions.textureBufferAny())
{
mValidBufferBindings.set(BufferBinding::Texture);
}
// Reinitialize some dirty bits that depend on extensions. if (mState.isRobustResourceInitEnabled())
{
mDrawDirtyObjects.set(State::DIRTY_OBJECT_DRAW_ATTACHMENTS);
mDrawDirtyObjects.set(State::DIRTY_OBJECT_TEXTURES_INIT);
mDrawDirtyObjects.set(State::DIRTY_OBJECT_IMAGES_INIT);
mBlitDirtyObjects.set(State::DIRTY_OBJECT_DRAW_ATTACHMENTS);
mBlitDirtyObjects.set(State::DIRTY_OBJECT_READ_ATTACHMENTS);
mComputeDirtyObjects.set(State::DIRTY_OBJECT_TEXTURES_INIT);
mComputeDirtyObjects.set(State::DIRTY_OBJECT_IMAGES_INIT);
mReadPixelsDirtyObjects.set(State::DIRTY_OBJECT_READ_ATTACHMENTS);
mCopyImageDirtyBits.set(State::DIRTY_BIT_READ_FRAMEBUFFER_BINDING);
mCopyImageDirtyObjects.set(State::DIRTY_OBJECT_READ_ATTACHMENTS);
}
// We need to validate buffer bounds if we are in a WebGL or robust access context and the // back-end does not support robust buffer access behaviour.
mBufferAccessValidationEnabled = (!mSupportedExtensions.robustBufferAccessBehaviorKHR &&
(mState.isWebGL() || mState.hasRobustAccess()));
// Cache this in the VertexArrays. They need to check it in state change notifications. for (auto vaoIter : mVertexArrayMap)
{
VertexArray *vao = vaoIter.second;
vao->setBufferAccessValidationEnabled(mBufferAccessValidationEnabled);
}
// Reinitialize state cache after extension changes.
mStateCache.initialize(this);
}
ANGLE_INLINE angle::Result Context::prepareForDispatch()
{ // Converting a PPO from graphics to compute requires re-linking it. // The compute shader must have successfully linked before being included in the PPO, so no link // errors that would have been caught during validation should be possible when re-linking the // PPO with the compute shader.
Program *program = mState.getProgram();
ProgramPipeline *pipeline = mState.getProgramPipeline(); if (!program && pipeline)
{ // Linking the PPO can't fail due to a validation error within the compute program, // since it successfully linked already in order to become part of the PPO in the first // place.
pipeline->resolveLink(this);
ANGLE_CHECK(this, pipeline->isLinked(), "Program pipeline link failed",
GL_INVALID_OPERATION);
}
angle::Result Context::prepareForInvalidate(GLenum target)
{ // Only sync the FBO that's being invalidated. Per the GLES3 spec, GL_FRAMEBUFFER is equivalent // to GL_DRAW_FRAMEBUFFER for the purposes of invalidation.
GLenum effectiveTarget = target; if (effectiveTarget == GL_FRAMEBUFFER)
{
effectiveTarget = GL_DRAW_FRAMEBUFFER;
}
ANGLE_TRY(mState.syncDirtyObject(this, effectiveTarget)); return syncDirtyBits(effectiveTarget == GL_READ_FRAMEBUFFER ? mReadInvalidateDirtyBits
: mDrawInvalidateDirtyBits,
Command::Invalidate);
}
// Note that blitting is called against draw framebuffer. // See the code in gl::Context::blitFramebuffer. if ((mask & GL_COLOR_BUFFER_BIT) && !drawFramebuffer->hasEnabledDrawBuffer())
{
mask &= ~GL_COLOR_BUFFER_BIT;
}
// Early out if none of the specified attachments exist or are enabled. if (mask == 0)
{
ANGLE_PERF_WARNING(mState.getDebug(), GL_DEBUG_SEVERITY_LOW, "BlitFramebuffer called for non-existing buffers"); return;
}
void Context::clear(GLbitfield mask)
{ if (mState.isRasterizerDiscardEnabled())
{ return;
}
// Noop empty scissors. if (IsEmptyScissor(mState))
{ return;
}
// Remove clear bits that are ineffective. An effective clear changes at least one fragment. If // color/depth/stencil masks make the clear ineffective we skip it altogether.
// If all color channels in all draw buffers are masked, don't attempt to clear color. if (mState.allActiveDrawBufferChannelsMasked())
{
mask &= ~GL_COLOR_BUFFER_BIT;
}
// If depth write is disabled, don't attempt to clear depth. if (mState.getDrawFramebuffer()->getDepthAttachment() == nullptr ||
!mState.getDepthStencilState().depthMask)
{
mask &= ~GL_DEPTH_BUFFER_BIT;
}
// If all stencil bits are masked, don't attempt to clear stencil. if (mState.getDrawFramebuffer()->getStencilAttachment() == nullptr ||
(angle::BitMask<uint32_t>(
mState.getDrawFramebuffer()->getStencilAttachment()->getStencilSize()) &
mState.getDepthStencilState().stencilWritemask) == 0)
{
mask &= ~GL_STENCIL_BUFFER_BIT;
}
if (mask == 0)
{
ANGLE_PERF_WARNING(mState.getDebug(), GL_DEBUG_SEVERITY_LOW, "Clear called for non-existing buffers"); return;
}
Framebuffer *framebufferObject = mState.getDrawFramebuffer(); const FramebufferAttachment *attachment = nullptr; if (buffer == GL_DEPTH)
{
attachment = framebufferObject->getDepthAttachment();
} elseif (buffer == GL_COLOR && static_cast<size_t>(drawbuffer) < framebufferObject->getNumColorAttachments())
{
attachment = framebufferObject->getColorAttachment(drawbuffer);
} // It's not an error to try to clear a non-existent buffer, but it's a no-op. We early out so // that the backend doesn't need to take this case into account. if (!attachment)
{ return;
}
ANGLE_CONTEXT_TRY(prepareForClearBuffer(buffer, drawbuffer));
ANGLE_CONTEXT_TRY(framebufferObject->clearBufferfv(this, buffer, drawbuffer, values));
}
Framebuffer *framebufferObject = mState.getDrawFramebuffer(); const FramebufferAttachment *attachment = nullptr; if (buffer == GL_COLOR && static_cast<size_t>(drawbuffer) < framebufferObject->getNumColorAttachments())
{
attachment = framebufferObject->getColorAttachment(drawbuffer);
} // It's not an error to try to clear a non-existent buffer, but it's a no-op. We early out so // that the backend doesn't need to take this case into account. if (!attachment)
{ return;
}
ANGLE_CONTEXT_TRY(prepareForClearBuffer(buffer, drawbuffer));
ANGLE_CONTEXT_TRY(framebufferObject->clearBufferuiv(this, buffer, drawbuffer, values));
}
Framebuffer *framebufferObject = mState.getDrawFramebuffer(); const FramebufferAttachment *attachment = nullptr; if (buffer == GL_STENCIL)
{
attachment = framebufferObject->getStencilAttachment();
} elseif (buffer == GL_COLOR && static_cast<size_t>(drawbuffer) < framebufferObject->getNumColorAttachments())
{
attachment = framebufferObject->getColorAttachment(drawbuffer);
} // It's not an error to try to clear a non-existent buffer, but it's a no-op. We early out so // that the backend doesn't need to take this case into account. if (!attachment)
{ return;
}
ANGLE_CONTEXT_TRY(prepareForClearBuffer(buffer, drawbuffer));
ANGLE_CONTEXT_TRY(framebufferObject->clearBufferiv(this, buffer, drawbuffer, values));
}
// If a buffer is not present, the clear has no effect if (framebufferObject->getDepthAttachment() == nullptr &&
framebufferObject->getStencilAttachment() == nullptr)
{ return;
}
void Context::copyImageSubData(GLuint srcName,
GLenum srcTarget,
GLint srcLevel,
GLint srcX,
GLint srcY,
GLint srcZ,
GLuint dstName,
GLenum dstTarget,
GLint dstLevel,
GLint dstX,
GLint dstY,
GLint dstZ,
GLsizei srcWidth,
GLsizei srcHeight,
GLsizei srcDepth)
{ // if copy region is zero, the copy is a successful no-op if ((srcWidth == 0) || (srcHeight == 0) || (srcDepth == 0))
{ return;
}
if (srcTarget == GL_RENDERBUFFER)
{ // Source target is a Renderbuffer
Renderbuffer *readBuffer = getRenderbuffer(PackParam<RenderbufferID>(srcName)); if (dstTarget == GL_RENDERBUFFER)
{ // Destination target is a Renderbuffer
Renderbuffer *writeBuffer = getRenderbuffer(PackParam<RenderbufferID>(dstName));
if (dstTarget == GL_RENDERBUFFER)
{ // Destination target is a Renderbuffer
Renderbuffer *writeBuffer = getRenderbuffer(PackParam<RenderbufferID>(dstName));
void Context::discardFramebuffer(GLenum target, GLsizei numAttachments, const GLenum *attachments)
{ // The specification isn't clear what should be done when the framebuffer isn't complete. // We threat it the same way as GLES3 glInvalidateFramebuffer.
invalidateFramebuffer(target, numAttachments, attachments);
}
Extents size(width, height, 1);
Texture *texture = getTextureByTarget(target); // From OpenGL ES 3 spec: All pixel storage modes are ignored when decoding a compressed texture // image. So we use an empty PixelUnpackState.
ANGLE_CONTEXT_TRY(texture->setCompressedImage(this, PixelUnpackState(), target, level,
internalformat, size, imageSize, static_cast<const uint8_t *>(data)));
}
Extents size(width, height, depth);
Texture *texture = getTextureByTarget(target); // From OpenGL ES 3 spec: All pixel storage modes are ignored when decoding a compressed texture // image. So we use an empty PixelUnpackState.
ANGLE_CONTEXT_TRY(texture->setCompressedImage(this, PixelUnpackState(), target, level,
internalformat, size, imageSize, static_cast<const uint8_t *>(data)));
}
Box area(xoffset, yoffset, 0, width, height, 1);
Texture *texture = getTextureByTarget(target); // From OpenGL ES 3 spec: All pixel storage modes are ignored when decoding a compressed texture // image. So we use an empty PixelUnpackState.
ANGLE_CONTEXT_TRY(texture->setCompressedSubImage(this, PixelUnpackState(), target, level, area,
format, imageSize, static_cast<const uint8_t *>(data)));
}
void Context::compressedTexSubImage3D(TextureTarget target,
GLint level,
GLint xoffset,
GLint yoffset,
GLint zoffset,
GLsizei width,
GLsizei height,
GLsizei depth,
GLenum format,
GLsizei imageSize, constvoid *data)
{ // Zero sized uploads are valid but no-ops if (width == 0 || height == 0)
{ return;
}
ANGLE_CONTEXT_TRY(syncStateForTexImage());
Box area(xoffset, yoffset, zoffset, width, height, depth);
Texture *texture = getTextureByTarget(target); // From OpenGL ES 3 spec: All pixel storage modes are ignored when decoding a compressed texture // image. So we use an empty PixelUnpackState.
ANGLE_CONTEXT_TRY(texture->setCompressedSubImage(this, PixelUnpackState(), target, level, area,
format, imageSize, static_cast<const uint8_t *>(data)));
}
void Context::flushMappedBufferRange(BufferBinding /*target*/,
GLintptr /*offset*/,
GLsizeiptr /*length*/)
{ // We do not currently support a non-trivial implementation of FlushMappedBufferRange
}
angle::Result Context::syncTextureForCopy(Texture *texture)
{
ASSERT(texture); // Sync texture not active but scheduled for a copy if (texture->hasAnyDirtyBit())
{ return texture->syncState(this, Command::Other);
}
case GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES:
mState.setFragmentShaderDerivativeHint(mode); break;
case GL_PERSPECTIVE_CORRECTION_HINT: case GL_POINT_SMOOTH_HINT: case GL_LINE_SMOOTH_HINT: case GL_FOG_HINT:
mState.gles1().setHint(target, mode); break; case GL_TEXTURE_FILTERING_HINT_CHROMIUM:
mState.setTextureFilteringHint(mode); break; default:
UNREACHABLE(); return;
}
}
void Context::copyBufferSubData(BufferBinding readTarget,
BufferBinding writeTarget,
GLintptr readOffset,
GLintptr writeOffset,
GLsizeiptr size)
{ // if size is zero, the copy is a successful no-op if (size == 0)
{ return;
}
void Context::bindAttribLocation(ShaderProgramID program, GLuint index, const GLchar *name)
{ // Ideally we could share the program query with the validation layer if possible.
Program *programObject = getProgramResolveLink(program);
ASSERT(programObject);
programObject->bindAttributeLocation(index, name);
}
void Context::getMultisamplefv(GLenum pname, GLuint index, GLfloat *val)
{ // According to spec 3.1 Table 20.49: Framebuffer Dependent Values, // the sample position should be queried by DRAW_FRAMEBUFFER.
ANGLE_CONTEXT_TRY(mState.syncDirtyObject(this, GL_DRAW_FRAMEBUFFER)); const Framebuffer *framebuffer = mState.getDrawFramebuffer();
angle::Result result =
mImplementation->dispatchCompute(this, numGroupsX, numGroupsY, numGroupsZ);
// This must be called before convertPpoToComputeOrDraw() so it uses the PPO's compute values // before convertPpoToComputeOrDraw() reverts the PPO back to graphics.
MarkShaderStorageUsage(this);
if (ANGLE_UNLIKELY(IsError(result)))
{ return;
}
}
// The input gl_InstanceID does not follow the baseinstance. gl_InstanceID always falls on // the half-open range [0, instancecount). No need to set other stuff. Except for Vulkan.
void Context::deleteBuffers(GLsizei n, const BufferID *buffers)
{ for (int i = 0; i < n; i++)
{
deleteBuffer(buffers[i]);
}
}
void Context::deleteFramebuffers(GLsizei n, const FramebufferID *framebuffers)
{ for (int i = 0; i < n; i++)
{ if (framebuffers[i].value != 0)
{
deleteFramebuffer(framebuffers[i]);
}
}
}
void Context::deleteRenderbuffers(GLsizei n, const RenderbufferID *renderbuffers)
{ for (int i = 0; i < n; i++)
{
deleteRenderbuffer(renderbuffers[i]);
}
}
void Context::deleteTextures(GLsizei n, const TextureID *textures)
{ for (int i = 0; i < n; i++)
{ if (textures[i].value != 0)
{
deleteTexture(textures[i]);
}
}
}
switch (shadertype)
{ case GL_VERTEX_SHADER: switch (precisiontype)
{ case GL_LOW_FLOAT:
mState.mCaps.vertexLowpFloat.get(range, precision); break; case GL_MEDIUM_FLOAT:
mState.mCaps.vertexMediumpFloat.get(range, precision); break; case GL_HIGH_FLOAT:
mState.mCaps.vertexHighpFloat.get(range, precision); break;
case GL_LOW_INT:
mState.mCaps.vertexLowpInt.get(range, precision); break; case GL_MEDIUM_INT:
mState.mCaps.vertexMediumpInt.get(range, precision); break; case GL_HIGH_INT:
mState.mCaps.vertexHighpInt.get(range, precision); break;
default:
UNREACHABLE(); return;
} break;
case GL_FRAGMENT_SHADER: switch (precisiontype)
{ case GL_LOW_FLOAT:
mState.mCaps.fragmentLowpFloat.get(range, precision); break; case GL_MEDIUM_FLOAT:
mState.mCaps.fragmentMediumpFloat.get(range, precision); break; case GL_HIGH_FLOAT:
mState.mCaps.fragmentHighpFloat.get(range, precision); break;
case GL_LOW_INT:
mState.mCaps.fragmentLowpInt.get(range, precision); break; case GL_MEDIUM_INT:
mState.mCaps.fragmentMediumpInt.get(range, precision); break; case GL_HIGH_INT:
mState.mCaps.fragmentHighpInt.get(range, precision); break;
Program *Context::getActiveLinkedProgram() const
{
Program *program = mState.getLinkedProgram(this); if (!program)
{
ProgramPipeline *programPipelineObject = mState.getProgramPipeline(); if (programPipelineObject)
{
program = programPipelineObject->getLinkedActiveShaderProgram(this);
}
}
void Context::validateProgramPipeline(ProgramPipelineID pipeline)
{ // GLES spec 3.2, Section 7.4 "Program Pipeline Objects" // If pipeline is a name that has been generated (without subsequent deletion) by // GenProgramPipelines, but refers to a program pipeline object that has not been // previously bound, the GL first creates a new state vector in the same manner as // when BindProgramPipeline creates a new program pipeline object. // // void BindProgramPipeline( uint pipeline ); // pipeline is the program pipeline object name. The resulting program pipeline // object is a new state vector, comprising all the state and with the same initial values // listed in table 21.20. // // If we do not have a pipeline object that's been created with glBindProgramPipeline, we leave // VALIDATE_STATUS at it's default false value without generating a pipeline object. if (!getProgramPipeline(pipeline))
{ return;
}
void Context::genTransformFeedbacks(GLsizei n, TransformFeedbackID *ids)
{ for (int i = 0; i < n; i++)
{
TransformFeedbackID transformFeedback = {mTransformFeedbackHandleAllocator.allocate()};
mTransformFeedbackMap.assign(transformFeedback, nullptr);
ids[i] = transformFeedback;
}
}
GLboolean Context::isTransformFeedback(TransformFeedbackID id) const
{ if (id.value == 0)
{ // The 3.0.4 spec [section 6.1.11] states that if ID is zero, IsTransformFeedback // returns FALSE return GL_FALSE;
}
// Note: If the Program is shared between Contexts we would be better using Observer/Subject. if (programObject->isInUse())
{
mState.setObjectDirty(GL_PROGRAM);
mStateCache.onUniformBufferStateChange(this);
}
}
switch (pname)
{ case GL_FENCE_STATUS_NV:
{ // GL_NV_fence spec: // Once the status of a fence has been finished (via FinishFenceNV) or tested and // the returned status is TRUE (via either TestFenceNV or GetFenceivNV querying the // FENCE_STATUS_NV), the status remains TRUE until the next SetFenceNV of the fence.
GLboolean status = GL_TRUE; if (fenceObject->getStatus() != GL_TRUE)
{
ANGLE_CONTEXT_TRY(fenceObject->test(this, &status));
}
*params = status; break;
}
case GL_FENCE_CONDITION_NV:
{
*params = static_cast<GLint>(fenceObject->getCondition()); break;
}
// GL_NV_fence spec: // A name returned by GenFencesNV, but not yet set via SetFenceNV, is not the name of an // existing fence. return fenceObject->isSet();
}
void Context::readnPixels(GLint x,
GLint y,
GLsizei width,
GLsizei height,
GLenum format,
GLenum type,
GLsizei bufSize, void *data)
{ return readPixels(x, y, width, height, format, type, data);
}
GLboolean result = GL_TRUE; if (fenceObject->test(this, &result) == angle::Result::Stop)
{ return GL_TRUE;
}
return result;
}
void Context::deleteMemoryObjects(GLsizei n, const MemoryObjectID *memoryObjects)
{ for (int i = 0; i < n; i++)
{
deleteMemoryObject(memoryObjects[i]);
}
}
switch (target)
{ case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING: case GL_UNIFORM_BUFFER_BINDING:
{
*type = GL_INT;
*numParams = 1; returntrue;
} case GL_TRANSFORM_FEEDBACK_BUFFER_START: case GL_TRANSFORM_FEEDBACK_BUFFER_SIZE: case GL_UNIFORM_BUFFER_START: case GL_UNIFORM_BUFFER_SIZE:
{
*type = GL_INT_64_ANGLEX;
*numParams = 1; returntrue;
}
}
if (mSupportedExtensions.drawBuffersIndexedAny())
{ switch (target)
{ case GL_BLEND_SRC_RGB: case GL_BLEND_SRC_ALPHA: case GL_BLEND_DST_RGB: case GL_BLEND_DST_ALPHA: case GL_BLEND_EQUATION_RGB: case GL_BLEND_EQUATION_ALPHA:
{
*type = GL_INT;
*numParams = 1; returntrue;
} case GL_COLOR_WRITEMASK:
{
*type = GL_BOOL;
*numParams = 4; returntrue;
}
}
}
if (mSupportedExtensions.shaderPixelLocalStorageANGLE)
{ switch (target)
{ case GL_PIXEL_LOCAL_FORMAT_ANGLE: case GL_PIXEL_LOCAL_TEXTURE_NAME_ANGLE: case GL_PIXEL_LOCAL_TEXTURE_LEVEL_ANGLE: case GL_PIXEL_LOCAL_TEXTURE_LAYER_ANGLE:
*type = GL_INT;
*numParams = 1; returntrue;
}
}
if (getClientVersion() < Version(3, 1))
{ returnfalse;
}
switch (target)
{ case GL_IMAGE_BINDING_LAYERED:
{
*type = GL_BOOL;
*numParams = 1; returntrue;
} case GL_MAX_COMPUTE_WORK_GROUP_COUNT: case GL_MAX_COMPUTE_WORK_GROUP_SIZE: case GL_ATOMIC_COUNTER_BUFFER_BINDING: case GL_SHADER_STORAGE_BUFFER_BINDING: case GL_VERTEX_BINDING_BUFFER: case GL_VERTEX_BINDING_DIVISOR: case GL_VERTEX_BINDING_OFFSET: case GL_VERTEX_BINDING_STRIDE: case GL_SAMPLE_MASK_VALUE: case GL_IMAGE_BINDING_NAME: case GL_IMAGE_BINDING_LEVEL: case GL_IMAGE_BINDING_LAYER: case GL_IMAGE_BINDING_ACCESS: case GL_IMAGE_BINDING_FORMAT:
{
*type = GL_INT;
*numParams = 1; returntrue;
} case GL_ATOMIC_COUNTER_BUFFER_START: case GL_ATOMIC_COUNTER_BUFFER_SIZE: case GL_SHADER_STORAGE_BUFFER_START: case GL_SHADER_STORAGE_BUFFER_SIZE:
{
*type = GL_INT_64_ANGLEX;
*numParams = 1; returntrue;
}
}
returnfalse;
}
Program *Context::getProgramNoResolveLink(ShaderProgramID handle) const
{ return mState.mShaderProgramManager->getProgram(handle);
}
angle::Result Context::onProgramLink(Program *programObject)
{ // Don't parallel link a program which is active in any GL contexts. With this assumption, we // don't need to worry that: // 1. Draw calls after link use the new executable code or the old one depending on the link // result. // 2. When a backend program, e.g., ProgramD3D is linking, other backend classes like // StateManager11, Renderer11, etc., may have a chance to make unexpected calls to // ProgramD3D. if (programObject->isInUse())
{
programObject->resolveLink(this); if (programObject->isLinked())
{
ANGLE_TRY(mState.onProgramExecutableChange(this, programObject));
programObject->onStateChange(angle::SubjectMessage::ProgramRelinked);
}
mStateCache.onProgramExecutableChange(this);
}
if (readSurface && (drawSurface != readSurface))
{
ANGLE_TRY(readSurface->makeCurrent(this));
}
// Update default framebuffer, the binding of the previous default // framebuffer (or lack of) will have a nullptr.
mState.mFramebufferManager->setDefaultFramebuffer(mDefaultFramebuffer.get()); if (mState.getDrawFramebuffer() == nullptr)
{
bindDrawFramebuffer(mDefaultFramebuffer->id());
} if (mState.getReadFramebuffer() == nullptr)
{
bindReadFramebuffer(mDefaultFramebuffer->id());
}
void Context::onGPUSwitch()
{ // Re-initialize the renderer string, which just changed, and // which must be visible to applications.
initRendererString();
}
// VAO can be null on Context startup. If we make this computation lazier we could ASSERT. // If there are no buffered attributes then we should not limit the draw call count. if (!vao || !mCachedActiveBufferedAttribsMask.any())
{ return;
}
// If tessellation is active primitive mode must be GL_PATCHES. if (programExecutable && programExecutable->hasLinkedTessellationShader())
{
setValidDrawModes(false, false, false, false, false, true); return;
}
if (mCachedTransformFeedbackActiveUnpaused)
{
TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
// ES Spec 3.0 validation text: // When transform feedback is active and not paused, all geometric primitives generated must // match the value of primitiveMode passed to BeginTransformFeedback. The error // INVALID_OPERATION is generated by DrawArrays and DrawArraysInstanced if mode is not // identical to primitiveMode. The error INVALID_OPERATION is also generated by // DrawElements, DrawElementsInstanced, and DrawRangeElements while transform feedback is // active and not paused, regardless of mode. Any primitive type may be used while transform // feedback is paused. if (!context->getExtensions().geometryShaderAny() &&
!context->getExtensions().tessellationShaderEXT && context->getClientVersion() < ES_3_2)
{
mCachedValidDrawModes.fill(false);
mCachedValidDrawModes[curTransformFeedback->getPrimitiveMode()] = true; return;
}
}
if (!programExecutable || !programExecutable->hasLinkedShaderStage(ShaderType::Geometry))
{ // All draw modes are valid, since drawing without a program does not generate an error and // and operations requiring a GS will trigger other validation errors. // `patchOK = false` due to checking above already enabling it if a TS is present.
setValidDrawModes(true, true, true, true, true, false); return;
}
¤ 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.0.415Bemerkung:
(vorverarbeitet am 2026-04-28)
¤
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.