Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/gfx/angle/checkout/src/libANGLE/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 366 kB image not shown  

Quelle  Context.cpp   Sprache: C

 
//
// 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"

#include <stdarg.h>
#include <stdio.h>
#include <string.h>

#include <iterator>
#include <sstream>
#include <vector>

#include "common/PackedEnums.h"
#include "common/angle_version_info.h"
#include "common/matrix_utils.h"
#include "common/platform.h"
#include "common/system_utils.h"
#include "common/utilities.h"
#include "libANGLE/Buffer.h"
#include "libANGLE/Compiler.h"
#include "libANGLE/Display.h"
#include "libANGLE/Fence.h"
#include "libANGLE/FramebufferAttachment.h"
#include "libANGLE/MemoryObject.h"
#include "libANGLE/PixelLocalStorage.h"
#include "libANGLE/Program.h"
#include "libANGLE/ProgramPipeline.h"
#include "libANGLE/Query.h"
#include "libANGLE/Renderbuffer.h"
#include "libANGLE/ResourceManager.h"
#include "libANGLE/Sampler.h"
#include "libANGLE/Semaphore.h"
#include "libANGLE/Surface.h"
#include "libANGLE/Texture.h"
#include "libANGLE/TransformFeedback.h"
#include "libANGLE/VertexArray.h"
#include "libANGLE/capture/FrameCapture.h"
#include "libANGLE/capture/frame_capture_utils.h"
#include "libANGLE/formatutils.h"
#include "libANGLE/queryconversions.h"
#include "libANGLE/queryutils.h"
#include "libANGLE/renderer/DisplayImpl.h"
#include "libANGLE/renderer/Format.h"
#include "libANGLE/validationES.h"

#if defined(ANGLE_PLATFORM_APPLE)
#    include <dispatch/dispatch.h>
#    include "common/tls.h"
#endif

namespace gl
{
namespace
{

egl::ShareGroup *AllocateOrGetShareGroup(egl::Display *display, const gl::Context *shareContext)
{
    if (shareContext)
    {
        egl::ShareGroup *shareGroup = shareContext->getState().getShareGroup();
        shareGroup->addRef();
        return shareGroup;
    }
    else
    {
        return new egl::ShareGroup(display->getImplementation());
    }
}

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;
    }
}

// Attribute map queries.
EGLint GetClientMajorVersion(const egl::AttributeMap &attribs)
{
    return static_cast<EGLint>(attribs.get(EGL_CONTEXT_CLIENT_VERSION, 1));
}

EGLint GetClientMinorVersion(const egl::AttributeMap &attribs)
{
    return static_cast<EGLint>(attribs.get(EGL_CONTEXT_MINOR_VERSION, 0));
}

bool GetBackwardCompatibleContext(const egl::AttributeMap &attribs)
{
    return attribs.get(EGL_CONTEXT_OPENGL_BACKWARDS_COMPATIBLE_ANGLE, EGL_TRUE) == EGL_TRUE;
}

bool GetWebGLContext(const egl::AttributeMap &attribs)
{
    return (attribs.get(EGL_CONTEXT_WEBGL_COMPATIBILITY_ANGLE, EGL_FALSE) == EGL_TRUE);
}

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;
        }
        else if (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
            const bool isWebGL = GetWebGLContext(attribs);
            return isWebGL ? std::min(conformantVersion, Version(3, 1)) : conformantVersion;
        }
    }
    else
    {
        return requestedVersion;
    }
}

EGLint GetProfileMask(const egl::AttributeMap &attribs)
{
    return attribs.getAsInt(EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT);
}

GLenum GetResetStrategy(const egl::AttributeMap &attribs)
{
    EGLAttrib resetStrategyExt =
        attribs.get(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT, EGL_NO_RESET_NOTIFICATION);
    EGLAttrib resetStrategyCore =
        attribs.get(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY, resetStrategyExt);

    switch (resetStrategyCore)
    {
        case EGL_NO_RESET_NOTIFICATION:
            return GL_NO_RESET_NOTIFICATION_EXT;
        case EGL_LOSE_CONTEXT_ON_RESET:
            return GL_LOSE_CONTEXT_ON_RESET_EXT;
        default:
            UNREACHABLE();
            return GL_NONE;
    }
}

bool GetRobustAccess(const egl::AttributeMap &attribs)
{
    EGLAttrib robustAccessExt  = attribs.get(EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT, EGL_FALSE);
    EGLAttrib robustAccessCore = attribs.get(EGL_CONTEXT_OPENGL_ROBUST_ACCESS, robustAccessExt);

    bool attribRobustAccess = (robustAccessCore == EGL_TRUE);
    bool contextFlagsRobustAccess =
        ((attribs.get(EGL_CONTEXT_FLAGS_KHR, 0) & EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR) != 0);

    return (attribRobustAccess || contextFlagsRobustAccess);
}

bool GetDebug(const egl::AttributeMap &attribs)
{
    return (attribs.get(EGL_CONTEXT_OPENGL_DEBUG, EGL_FALSE) == EGL_TRUE) ||
           ((attribs.get(EGL_CONTEXT_FLAGS_KHR, 0) & EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR) != 0);
}

bool GetNoError(const egl::AttributeMap &attribs)
{
    return (attribs.get(EGL_CONTEXT_OPENGL_NO_ERROR_KHR, EGL_FALSE) == EGL_TRUE);
}

bool GetExtensionsEnabled(const egl::AttributeMap &attribs, bool webGLContext)
{
    // If the context is WebGL, extensions are disabled by default
    EGLAttrib defaultValue = webGLContext ? EGL_FALSE : EGL_TRUE;
    return (attribs.get(EGL_EXTENSIONS_ENABLED_ANGLE, defaultValue) == EGL_TRUE);
}

bool GetBindGeneratesResource(const egl::AttributeMap &attribs)
{
    return (attribs.get(EGL_CONTEXT_BIND_GENERATES_RESOURCE_CHROMIUM, EGL_TRUE) == EGL_TRUE);
}

bool GetClientArraysEnabled(const egl::AttributeMap &attribs)
{
    return (attribs.get(EGL_CONTEXT_CLIENT_ARRAYS_ENABLED_ANGLE, EGL_TRUE) == EGL_TRUE);
}

bool GetRobustResourceInit(egl::Display *display, const egl::AttributeMap &attribs)
{
    const angle::FrontendFeatures &frontendFeatures = display->getFrontendFeatures();
    return (frontendFeatures.forceRobustResourceInit.enabled ||
            attribs.get(EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE, EGL_FALSE) == EGL_TRUE);
}

EGLenum GetContextPriority(const egl::AttributeMap &attribs)
{
    return static_cast<EGLenum>(
        attribs.getAsInt(EGL_CONTEXT_PRIORITY_LEVEL_IMG, EGL_CONTEXT_PRIORITY_MEDIUM_IMG));
}

bool GetProtectedContent(const egl::AttributeMap &attribs)
{
    return static_cast<bool>(attribs.getAsInt(EGL_PROTECTED_CONTENT_EXT, EGL_FALSE));
}

std::string GetObjectLabelFromPointer(GLsizei length, const GLchar *label)
{
    std::string labelName;
    if (label != nullptr)
    {
        size_t labelLength = length < 0 ? strlen(label) : length;
        labelName          = std::string(label, labelLength);
    }
    return labelName;
}

void GetObjectLabelBase(const std::string &objectLabel,
                        GLsizei bufSize,
                        GLsizei *length,
                        GLchar *label)
{
    size_t writeLength = objectLabel.length();
    if (label != nullptr && bufSize > 0)
    {
        writeLength = std::min(static_cast<size_t>(bufSize) - 1, objectLabel.length());
        std::copy(objectLabel.begin(), objectLabel.begin() + writeLength, label);
        label[writeLength] = '\0';
    }

    if (length != nullptr)
    {
        *length = static_cast<GLsizei>(writeLength);
    }
}

enum SubjectIndexes : angle::SubjectIndex
{
    kTexture0SubjectIndex       = 0,
    kTextureMaxSubjectIndex     = kTexture0SubjectIndex + IMPLEMENTATION_MAX_ACTIVE_TEXTURES,
    kImage0SubjectIndex         = kTextureMaxSubjectIndex,
    kImageMaxSubjectIndex       = kImage0SubjectIndex + IMPLEMENTATION_MAX_IMAGE_UNITS,
    kUniformBuffer0SubjectIndex = kImageMaxSubjectIndex,
    kUniformBufferMaxSubjectIndex =
        kUniformBuffer0SubjectIndex + IMPLEMENTATION_MAX_UNIFORM_BUFFER_BINDINGS,
    kAtomicCounterBuffer0SubjectIndex = kUniformBufferMaxSubjectIndex,
    kAtomicCounterBufferMaxSubjectIndex =
        kAtomicCounterBuffer0SubjectIndex + IMPLEMENTATION_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS,
    kShaderStorageBuffer0SubjectIndex = kAtomicCounterBufferMaxSubjectIndex,
    kShaderStorageBufferMaxSubjectIndex =
        kShaderStorageBuffer0SubjectIndex + IMPLEMENTATION_MAX_SHADER_STORAGE_BUFFER_BINDINGS,
    kSampler0SubjectIndex    = kShaderStorageBufferMaxSubjectIndex,
    kSamplerMaxSubjectIndex  = kSampler0SubjectIndex + IMPLEMENTATION_MAX_ACTIVE_TEXTURES,
    kVertexArraySubjectIndex = kSamplerMaxSubjectIndex,
    kReadFramebufferSubjectIndex,
    kDrawFramebufferSubjectIndex,
    kProgramPipelineSubjectIndex,
};

bool IsClearBufferEnabled(const FramebufferState &fbState, GLenum buffer, GLint drawbuffer)
{
    return buffer != GL_COLOR || fbState.getEnabledDrawBuffers()[drawbuffer];
}

bool IsEmptyScissor(const State &glState)
{
    if (!glState.isScissorTestEnabled())
    {
        return false;
    }

    const Extents &dimensions = glState.getDrawFramebuffer()->getExtents();
    Rectangle framebufferArea(0, 0, dimensions.width, dimensions.height);
    return !ClipRectangle(framebufferArea, glState.getScissor(), nullptr);
}

bool IsColorMaskedOut(const BlendStateExt &blendStateExt, const GLint drawbuffer)
{
    ASSERT(static_cast<size_t>(drawbuffer) < blendStateExt.getDrawBufferCount());
    return blendStateExt.getColorMaskIndexed(static_cast<size_t>(drawbuffer)) == 0;
}

bool GetIsExternal(const egl::AttributeMap &attribs)
{
    return (attribs.get(EGL_EXTERNAL_CONTEXT_ANGLE, EGL_FALSE) == EGL_TRUE);
}

bool GetSaveAndRestoreState(const egl::AttributeMap &attribs)
{
    return (attribs.get(EGL_EXTERNAL_CONTEXT_SAVE_STATE_ANGLE, EGL_FALSE) == EGL_TRUE);
}

void GetPerfMonitorString(const std::string &name,
                          GLsizei bufSize,
                          GLsizei *length,
                          GLchar *stringOut)
{
    GLsizei numCharsWritten = std::min(bufSize, static_cast<GLsizei>(name.size()));

    if (length)
    {
        if (bufSize == 0)
        {
            *length = static_cast<GLsizei>(name.size());
        }
        else
        {
            // Excludes null terminator.
            ASSERT(numCharsWritten > 0);
            *length = numCharsWritten - 1;
        }
    }

    if (stringOut)
    {
        memcpy(stringOut, name.c_str(), numCharsWritten);
    }
}

bool CanSupportAEP(const gl::Version &version, const gl::Extensions &extensions)
{
    // From the GL_ANDROID_extension_pack_es31a extension spec:
    // OpenGL ES 3.1 and GLSL ES 3.10 are required.
    // The following extensions are required:
    // * KHR_debug
    // * KHR_texture_compression_astc_ldr
    // * KHR_blend_equation_advanced
    // * OES_sample_shading
    // * OES_sample_variables
    // * OES_shader_image_atomic
    // * OES_shader_multisample_interpolation
    // * OES_texture_stencil8
    // * OES_texture_storage_multisample_2d_array
    // * EXT_copy_image
    // * EXT_draw_buffers_indexed
    // * EXT_geometry_shader
    // * EXT_gpu_shader5
    // * EXT_primitive_bounding_box
    // * EXT_shader_io_blocks
    // * EXT_tessellation_shader
    // * EXT_texture_border_clamp
    // * EXT_texture_buffer
    // * EXT_texture_cube_map_array
    // * EXT_texture_sRGB_decode
    return (version >= ES_3_1 && extensions.debugKHR && extensions.textureCompressionAstcLdrKHR &&
            extensions.blendEquationAdvancedKHR && extensions.sampleShadingOES &&
            extensions.sampleVariablesOES && extensions.shaderImageAtomicOES &&
            extensions.shaderMultisampleInterpolationOES && extensions.textureStencil8OES &&
            extensions.textureStorageMultisample2dArrayOES && extensions.copyImageEXT &&
            extensions.drawBuffersIndexedEXT && extensions.geometryShaderEXT &&
            extensions.gpuShader5EXT && extensions.primitiveBoundingBoxEXT &&
            extensions.shaderIoBlocksEXT && extensions.tessellationShaderEXT &&
            extensions.textureBorderClampEXT && extensions.textureBufferEXT &&
            extensions.textureCubeMapArrayEXT && extensions.textureSRGBDecodeEXT);
}
}  // anonymous namespace

#if defined(ANGLE_PLATFORM_APPLE)
// TODO(angleproject:6479): Due to a bug in Apple's dyld loader, `thread_local` will cause
// excessive memory use. Temporarily avoid it by using pthread's thread
// local storage instead.
static TLSIndex GetCurrentValidContextTLSIndex()
{
    static TLSIndex CurrentValidContextIndex = TLS_INVALID_INDEX;
    static dispatch_once_t once;
    dispatch_once(&once, ^{
      ASSERT(CurrentValidContextIndex == TLS_INVALID_INDEX);
      CurrentValidContextIndex = CreateTLSIndex(nullptr);
    });
    return CurrentValidContextIndex;
}
Context *GetCurrentValidContextTLS()
{
    TLSIndex CurrentValidContextIndex = GetCurrentValidContextTLSIndex();
    ASSERT(CurrentValidContextIndex != TLS_INVALID_INDEX);
    return static_cast<Context *>(GetTLSValue(CurrentValidContextIndex));
}
void SetCurrentValidContextTLS(Context *context)
{
    TLSIndex CurrentValidContextIndex = GetCurrentValidContextTLSIndex();
    ASSERT(CurrentValidContextIndex != TLS_INVALID_INDEX);
    SetTLSValue(CurrentValidContextIndex, context);
}
#else
thread_local Context *gCurrentValidContext = nullptr;
#endif

Context::Context(egl::Display *display,
                 const egl::Config *config,
                 const Context *shareContext,
                 TextureManager *shareTextures,
                 SemaphoreManager *shareSemaphores,
                 MemoryProgramCache *memoryProgramCache,
                 MemoryShaderCache *memoryShaderCache,
                 const EGLenum clientType,
                 const egl::AttributeMap &attribs,
                 const egl::DisplayExtensions &displayExtensions,
                 const egl::ClientExtensions &clientExtensions)
    : mState(shareContext ? &shareContext->mState : nullptr,
             AllocateOrGetShareGroup(display, shareContext),
             shareTextures,
             shareSemaphores,
             &mOverlay,
             clientType,
             GetClientVersion(display, attribs, clientType),
             GetProfileMask(attribs),
             GetDebug(attribs),
             GetBindGeneratesResource(attribs),
             GetClientArraysEnabled(attribs),
             GetRobustResourceInit(display, attribs),
             memoryProgramCache != nullptr,
             GetContextPriority(attribs),
             GetRobustAccess(attribs),
             GetProtectedContent(attribs)),
      mShared(shareContext != nullptr || shareTextures != nullptr || shareSemaphores != nullptr),
      mSkipValidation(GetNoError(attribs)),
      mDisplayTextureShareGroup(shareTextures != nullptr),
      mDisplaySemaphoreShareGroup(shareSemaphores != nullptr),
      mErrors(this),
      mImplementation(display->getImplementation()
                          ->createContext(mState, &mErrors, config, shareContext, attribs)),
      mLabel(nullptr),
      mCompiler(),
      mConfig(config),
      mHasBeenCurrent(false),
      mContextLost(false),
      mResetStatus(GraphicsResetStatus::NoError),
      mContextLostForced(false),
      mResetStrategy(GetResetStrategy(attribs)),
      mSurfacelessSupported(displayExtensions.surfacelessContext),
      mCurrentDrawSurface(static_cast<egl::Surface *>(EGL_NO_SURFACE)),
      mCurrentReadSurface(static_cast<egl::Surface *>(EGL_NO_SURFACE)),
      mDisplay(display),
      mWebGLContext(GetWebGLContext(attribs)),
      mBufferAccessValidationEnabled(false),
      mExtensionsEnabled(GetExtensionsEnabled(attribs, mWebGLContext)),
      mMemoryProgramCache(memoryProgramCache),
      mMemoryShaderCache(memoryShaderCache),
      mVertexArrayObserverBinding(this, kVertexArraySubjectIndex),
      mDrawFramebufferObserverBinding(this, kDrawFramebufferSubjectIndex),
      mReadFramebufferObserverBinding(this, kReadFramebufferSubjectIndex),
      mProgramPipelineObserverBinding(this, kProgramPipelineSubjectIndex),
      mSingleThreadPool(nullptr),
      mMultiThreadPool(nullptr),
      mFrameCapture(new angle::FrameCapture),
      mRefCount(0),
      mOverlay(mImplementation.get()),
      mIsExternal(GetIsExternal(attribs)),
      mSaveAndRestoreState(GetSaveAndRestoreState(attribs)),
      mIsDestroyed(false)
{
    for (angle::SubjectIndex uboIndex = kUniformBuffer0SubjectIndex;
         uboIndex < kUniformBufferMaxSubjectIndex; ++uboIndex)
    {
        mUniformBufferObserverBindings.emplace_back(this, uboIndex);
    }

    for (angle::SubjectIndex acbIndex = kAtomicCounterBuffer0SubjectIndex;
         acbIndex < kAtomicCounterBufferMaxSubjectIndex; ++acbIndex)
    {
        mAtomicCounterBufferObserverBindings.emplace_back(this, acbIndex);
    }

    for (angle::SubjectIndex ssboIndex = kShaderStorageBuffer0SubjectIndex;
         ssboIndex < kShaderStorageBufferMaxSubjectIndex; ++ssboIndex)
    {
        mShaderStorageBufferObserverBindings.emplace_back(this, ssboIndex);
    }

    for (angle::SubjectIndex samplerIndex = kSampler0SubjectIndex;
         samplerIndex < kSamplerMaxSubjectIndex; ++samplerIndex)
    {
        mSamplerObserverBindings.emplace_back(this, samplerIndex);
    }

    for (angle::SubjectIndex imageIndex = kImage0SubjectIndex; imageIndex < kImageMaxSubjectIndex;
         ++imageIndex)
    {
        mImageObserverBindings.emplace_back(this, imageIndex);
    }

    // Implementations now require the display to be set at context creation.
    ASSERT(mDisplay);
}

egl::Error Context::initialize()
{
    if (!mImplementation)
        return egl::Error(EGL_NOT_INITIALIZED, "native context creation failed");
    return egl::NoError();
}

void Context::initializeDefaultResources()
{
    mImplementation->setMemoryProgramCache(mMemoryProgramCache);

    initCaps();

    mState.initialize(this);

    mDefaultFramebuffer = std::make_unique<Framebuffer>(this, mImplementation.get());

    mFenceNVHandleAllocator.setBaseHandle(0);

    // [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 ((getClientType() != EGL_OPENGL_API && getClientVersion() >= Version(3, 2)) ||
        mSupportedExtensions.textureCubeMapArrayAny())
    {
        Texture *zeroTextureCubeMapArray =
            new Texture(mImplementation.get(), {0}, TextureType::CubeMapArray);
        mZeroTextures[TextureType::CubeMapArray].set(this, zeroTextureCubeMapArray);
    }

    if ((getClientType() != EGL_OPENGL_API && getClientVersion() >= Version(3, 2)) ||
        mSupportedExtensions.textureBufferAny())
    {
        Texture *zeroTextureBuffer = new Texture(mImplementation.get(), {0}, TextureType::Buffer);
        mZeroTextures[TextureType::Buffer].set(this, zeroTextureBuffer);
    }

    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);
    }

    mState.initializeZeroTextures(this, mZeroTextures);

    ANGLE_CONTEXT_TRY(mImplementation->initialize());

    // 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();

    mDrawDirtyObjects.set(State::DIRTY_OBJECT_ACTIVE_TEXTURES);
    mDrawDirtyObjects.set(State::DIRTY_OBJECT_DRAW_FRAMEBUFFER);
    mDrawDirtyObjects.set(State::DIRTY_OBJECT_VERTEX_ARRAY);
    mDrawDirtyObjects.set(State::DIRTY_OBJECT_TEXTURES);
    mDrawDirtyObjects.set(State::DIRTY_OBJECT_PROGRAM);
    mDrawDirtyObjects.set(State::DIRTY_OBJECT_PROGRAM_PIPELINE_OBJECT);
    mDrawDirtyObjects.set(State::DIRTY_OBJECT_SAMPLERS);
    mDrawDirtyObjects.set(State::DIRTY_OBJECT_IMAGES);

    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);

    mClearDirtyBits.set(State::DIRTY_BIT_RASTERIZER_DISCARD_ENABLED);
    mClearDirtyBits.set(State::DIRTY_BIT_SCISSOR_TEST_ENABLED);
    mClearDirtyBits.set(State::DIRTY_BIT_SCISSOR);
    mClearDirtyBits.set(State::DIRTY_BIT_VIEWPORT);
    mClearDirtyBits.set(State::DIRTY_BIT_CLEAR_COLOR);
    mClearDirtyBits.set(State::DIRTY_BIT_CLEAR_DEPTH);
    mClearDirtyBits.set(State::DIRTY_BIT_CLEAR_STENCIL);
    mClearDirtyBits.set(State::DIRTY_BIT_COLOR_MASK);
    mClearDirtyBits.set(State::DIRTY_BIT_DEPTH_MASK);
    mClearDirtyBits.set(State::DIRTY_BIT_STENCIL_WRITEMASK_FRONT);
    mClearDirtyBits.set(State::DIRTY_BIT_STENCIL_WRITEMASK_BACK);
    mClearDirtyBits.set(State::DIRTY_BIT_DRAW_FRAMEBUFFER_BINDING);
    mClearDirtyObjects.set(State::DIRTY_OBJECT_DRAW_FRAMEBUFFER);

    // We sync the draw Framebuffer manually in prepareForClear to allow the clear calls to do
    // more custom handling for robust resource init.

    mBlitDirtyBits.set(State::DIRTY_BIT_SCISSOR_TEST_ENABLED);
    mBlitDirtyBits.set(State::DIRTY_BIT_SCISSOR);
    mBlitDirtyBits.set(State::DIRTY_BIT_FRAMEBUFFER_SRGB_WRITE_CONTROL_MODE);
    mBlitDirtyBits.set(State::DIRTY_BIT_READ_FRAMEBUFFER_BINDING);
    mBlitDirtyBits.set(State::DIRTY_BIT_DRAW_FRAMEBUFFER_BINDING);
    mBlitDirtyObjects.set(State::DIRTY_OBJECT_READ_FRAMEBUFFER);
    mBlitDirtyObjects.set(State::DIRTY_OBJECT_DRAW_FRAMEBUFFER);

    mComputeDirtyBits.set(State::DIRTY_BIT_SHADER_STORAGE_BUFFER_BINDING);
    mComputeDirtyBits.set(State::DIRTY_BIT_UNIFORM_BUFFER_BINDINGS);
    mComputeDirtyBits.set(State::DIRTY_BIT_ATOMIC_COUNTER_BUFFER_BINDING);
    mComputeDirtyBits.set(State::DIRTY_BIT_PROGRAM_BINDING);
    mComputeDirtyBits.set(State::DIRTY_BIT_PROGRAM_EXECUTABLE);
    mComputeDirtyBits.set(State::DIRTY_BIT_TEXTURE_BINDINGS);
    mComputeDirtyBits.set(State::DIRTY_BIT_SAMPLER_BINDINGS);
    mComputeDirtyBits.set(State::DIRTY_BIT_IMAGE_BINDINGS);
    mComputeDirtyBits.set(State::DIRTY_BIT_DISPATCH_INDIRECT_BUFFER_BINDING);
    mComputeDirtyObjects.set(State::DIRTY_OBJECT_ACTIVE_TEXTURES);
    mComputeDirtyObjects.set(State::DIRTY_OBJECT_TEXTURES);
    mComputeDirtyObjects.set(State::DIRTY_OBJECT_PROGRAM);
    mComputeDirtyObjects.set(State::DIRTY_OBJECT_PROGRAM_PIPELINE_OBJECT);
    mComputeDirtyObjects.set(State::DIRTY_OBJECT_IMAGES);
    mComputeDirtyObjects.set(State::DIRTY_OBJECT_SAMPLERS);

    mCopyImageDirtyBits.set(State::DIRTY_BIT_READ_FRAMEBUFFER_BINDING);
    mCopyImageDirtyObjects.set(State::DIRTY_OBJECT_READ_FRAMEBUFFER);

    mReadInvalidateDirtyBits.set(State::DIRTY_BIT_READ_FRAMEBUFFER_BINDING);
    mDrawInvalidateDirtyBits.set(State::DIRTY_BIT_DRAW_FRAMEBUFFER_BINDING);

    mOverlay.init();
}

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);
    }

    ANGLE_TRY(unMakeCurrent(display));

    mDefaultFramebuffer->onDestroy(this);
    mDefaultFramebuffer.reset();

    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);

    mSingleThreadPool.reset();
    mMultiThreadPool.reset();

    mImplementation->onDestroy(this);

    // Backend requires implementation to be destroyed first to close down all the objects
    mState.mShareGroup->release(display);

    mOverlay.destroy(this);

    return egl::NoError();
}

Context::~Context() {}

void Context::setLabel(EGLLabelKHR label)
{
    mLabel = label;
}

EGLLabelKHR Context::getLabel() const
{
    return mLabel;
}

egl::Error Context::makeCurrent(egl::Display *display,
                                egl::Surface *drawSurface,
                                egl::Surface *readSurface)
{
    mDisplay = display;

    if (!mHasBeenCurrent)
    {
        initializeDefaultResources();
        initRendererString();
        initVersionStrings();
        initExtensionStrings();

        int width  = 0;
        int height = 0;
        if (drawSurface != nullptr)
        {
            width  = drawSurface->getWidth();
            height = drawSurface->getHeight();
        }

        mState.setViewportParams(0, 0, width, height);
        mState.setScissorParams(0, 0, width, height);

        mHasBeenCurrent = true;
    }

    ANGLE_TRY(unsetDefaultFramebuffer());

    getShareGroup()->getFrameCaptureShared()->onMakeCurrent(this, drawSurface);

    // TODO(jmadill): Rework this when we support ContextImpl
    mState.setAllDirtyBits();
    mState.setAllDirtyObjects();

    ANGLE_TRY(setDefaultFramebuffer(drawSurface, readSurface));

    // 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 egl::NoError();
}

egl::Error Context::unMakeCurrent(const egl::Display *display)
{
    ANGLE_TRY(angle::ResultToEGL(mImplementation->onUnMakeCurrent(this)));

    ANGLE_TRY(unsetDefaultFramebuffer());

    // 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());
    }

    return egl::NoError();
}

BufferID Context::createBuffer()
{
    return mState.mBufferManager->createBuffer();
}

GLuint Context::createProgram()
{
    return mState.mShaderProgramManager->createProgram(mImplementation.get()).value;
}

GLuint Context::createShader(ShaderType type)
{
    return mState.mShaderProgramManager
        ->createShader(mImplementation.get(), mState.mLimitations, type)
        .value;
}

TextureID Context::createTexture()
{
    return mState.mTextureManager->createTexture();
}

RenderbufferID Context::createRenderbuffer()
{
    return mState.mRenderbufferManager->createRenderbuffer();
}

// Returns an unused framebuffer name
FramebufferID Context::createFramebuffer()
{
    return mState.mFramebufferManager->createFramebuffer();
}

void Context::genFencesNV(GLsizei n, FenceNVID *fences)
{
    for (int i = 0; i < n; i++)
    {
        GLuint handle = mFenceNVHandleAllocator.allocate();
        mFenceNVMap.assign({handle}, new FenceNV(mImplementation.get()));
        fences[i] = {handle};
    }
}

ProgramPipelineID Context::createProgramPipeline()
{
    return mState.mProgramPipelineManager->createProgramPipeline();
}

GLuint Context::createShaderProgramv(ShaderType type, GLsizei count, const GLchar *const *strings)
{
    const ShaderProgramID shaderID = PackParam<ShaderProgramID>(createShader(type));
    if (shaderID.value)
    {
        Shader *shaderObject = getShader(shaderID);
        ASSERT(shaderObject);
        shaderObject->setSource(count, strings, nullptr);
        shaderObject->compile(this);
        const ShaderProgramID programID = PackParam<ShaderProgramID>(createProgram());
        if (programID.value)
        {
            gl::Program *programObject = getProgramNoResolveLink(programID);
            ASSERT(programObject);

            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;
                }

                programObject->detachShader(this, shaderObject);
            }

            InfoLog &programInfoLog = programObject->getExecutable().getInfoLog();
            programInfoLog << shaderObject->getInfoLogString();
        }

        deleteShader(shaderID);

        return programID.value;
    }

    return 0u;
}

MemoryObjectID Context::createMemoryObject()
{
    return mState.mMemoryObjectManager->createMemoryObject(mImplementation.get());
}

SemaphoreID Context::createSemaphore()
{
    return mState.mSemaphoreManager->createSemaphore(mImplementation.get());
}

void Context::deleteBuffer(BufferID bufferName)
{
    Buffer *buffer = mState.mBufferManager->getBuffer(bufferName);
    if (buffer)
    {
        detachBuffer(buffer);
    }

    mState.mBufferManager->deleteObject(this, bufferName);
}

void Context::deleteShader(ShaderProgramID shader)
{
    mState.mShaderProgramManager->deleteShader(this, shader);
}

void Context::deleteProgram(ShaderProgramID program)
{
    mState.mShaderProgramManager->deleteProgram(this, program);
}

void Context::deleteTexture(TextureID texture)
{
    if (mState.mTextureManager->getTexture(texture))
    {
        detachTexture(texture);
    }

    mState.mTextureManager->deleteObject(this, texture);
}

void Context::deleteRenderbuffer(RenderbufferID renderbuffer)
{
    if (mState.mRenderbufferManager->getRenderbuffer(renderbuffer))
    {
        detachRenderbuffer(renderbuffer);
    }

    mState.mRenderbufferManager->deleteObject(this, renderbuffer);
}

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(thisstatic_cast<GLuint>(reinterpret_cast<uintptr_t>(sync)));
}

void Context::deleteProgramPipeline(ProgramPipelineID pipelineID)
{
    ProgramPipeline *pipeline = mState.mProgramPipelineManager->getProgramPipeline(pipelineID);
    if (pipeline)
    {
        detachProgramPipeline(pipelineID);
    }

    mState.mProgramPipelineManager->deleteObject(this, pipelineID);
}

void Context::deleteMemoryObject(MemoryObjectID memoryObject)
{
    mState.mMemoryObjectManager->deleteMemoryObject(this, memoryObject);
}

void Context::deleteSemaphore(SemaphoreID semaphore)
{
    mState.mSemaphoreManager->deleteSemaphore(this, semaphore);
}

// 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;

    Framebuffer *framebuffer = mState.mFramebufferManager->getFramebuffer(framebufferID);
    if (framebuffer)
    {
        plsToDelete = framebuffer->detachPixelLocalStorage();
        detachFramebuffer(framebufferID);
    }

    mState.mFramebufferManager->deleteObject(this, framebufferID);

    // 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;
        }
    }
}

Buffer *Context::getBuffer(BufferID handle) const
{
    return mState.mBufferManager->getBuffer(handle);
}

Renderbuffer *Context::getRenderbuffer(RenderbufferID handle) const
{
    return mState.mRenderbufferManager->getRenderbuffer(handle);
}

EGLenum Context::getContextPriority() const
{
    return egl::ToEGLenum(mImplementation->getContextPriority());
}

Sync *Context::getSync(GLsync handle) const
{
    return mState.mSyncManager->getSync(static_cast<GLuint>(reinterpret_cast<uintptr_t>(handle)));
}

VertexArray *Context::getVertexArray(VertexArrayID handle) const
{
    return mVertexArrayMap.query(handle);
}

Sampler *Context::getSampler(SamplerID handle) const
{
    return mState.mSamplerManager->getSampler(handle);
}

TransformFeedback *Context::getTransformFeedback(TransformFeedbackID handle) const
{
    return mTransformFeedbackMap.query(handle);
}

ProgramPipeline *Context::getProgramPipeline(ProgramPipelineID handle) const
{
    return mState.mProgramPipelineManager->getProgramPipeline(handle);
}

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;
    }
}

gl::LabeledObject *Context::getLabeledObjectFromPtr(const void *ptr) const
{
    return getSync(reinterpret_cast<GLsync>(const_cast<void *>(ptr)));
}

void Context::objectLabel(GLenum identifier, GLuint name, GLsizei length, const GLchar *label)
{
    gl::LabeledObject *object = getLabeledObject(identifier, name);
    ASSERT(object != nullptr);

    std::string labelName = GetObjectLabelFromPointer(length, label);
    ANGLE_CONTEXT_TRY(object->setLabel(this, labelName));

    // 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::labelObject(GLenum type, GLuint object, GLsizei length, const GLchar *label)
{
    gl::LabeledObject *obj = getLabeledObject(type, object);
    ASSERT(obj != nullptr);

    std::string labelName = "";
    if (label != nullptr)
    {
        size_t labelLength = length == 0 ? strlen(label) : length;
        labelName          = std::string(label, labelLength);
    }
    ANGLE_CONTEXT_TRY(obj->setLabel(this, labelName));
    mState.setObjectDirty(type);
}

void Context::objectPtrLabel(const void *ptr, GLsizei length, const GLchar *label)
{
    gl::LabeledObject *object = getLabeledObjectFromPtr(ptr);
    ASSERT(object != nullptr);

    std::string labelName = GetObjectLabelFromPointer(length, label);
    ANGLE_CONTEXT_TRY(object->setLabel(this, labelName));
}

void Context::getObjectLabel(GLenum identifier,
                             GLuint name,
                             GLsizei bufSize,
                             GLsizei *length,
                             GLchar *label)
{
    gl::LabeledObject *object = getLabeledObject(identifier, name);
    ASSERT(object != nullptr);

    const std::string &objectLabel = object->getLabel();
    GetObjectLabelBase(objectLabel, bufSize, length, label);
}

void Context::getObjectPtrLabel(const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label)
{
    gl::LabeledObject *object = getLabeledObjectFromPtr(ptr);
    ASSERT(object != nullptr);

    const std::string &objectLabel = object->getLabel();
    GetObjectLabelBase(objectLabel, bufSize, length, label);
}

GLboolean Context::isSampler(SamplerID samplerName) const
{
    return mState.mSamplerManager->isSampler(samplerName);
}

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;
    }

    Texture *texture = nullptr;
    if (handle.value == 0)
    {
        texture = mZeroTextures[target].get();
    }
    else
    {
        texture =
            mState.mTextureManager->checkTextureAllocation(mImplementation.get(), handle, target);
    }

    ASSERT(texture);
    // Early return if rebinding the same texture
    if (texture == mState.getTargetTexture(target))
    {
        return;
    }

    mState.setSamplerTexture(this, target, texture);
    mStateCache.onActiveTextureChange(this);
}

void Context::bindReadFramebuffer(FramebufferID framebufferHandle)
{
    Framebuffer *framebuffer = mState.mFramebufferManager->checkFramebufferAllocation(
        mImplementation.get(), this, framebufferHandle);
    mState.setReadFramebufferBinding(framebuffer);
    mReadFramebufferObserverBinding.bind(framebuffer);
}

void Context::bindDrawFramebuffer(FramebufferID framebufferHandle)
{
    Framebuffer *framebuffer = mState.mFramebufferManager->checkFramebufferAllocation(
        mImplementation.get(), this, framebufferHandle);
    mState.setDrawFramebufferBinding(framebuffer);
    mDrawFramebufferObserverBinding.bind(framebuffer);
    mStateCache.onDrawFramebufferChange(this);
}

void Context::bindVertexArray(VertexArrayID vertexArrayHandle)
{
    VertexArray *vertexArray = checkVertexArrayAllocation(vertexArrayHandle);
    mState.setVertexArrayBinding(this, vertexArray);
    mVertexArrayObserverBinding.bind(vertexArray);
    mStateCache.onVertexArrayBindingChange(this);
}

void Context::bindVertexBuffer(GLuint bindingIndex,
                               BufferID bufferHandle,
                               GLintptr offset,
                               GLsizei stride)
{
    Buffer *buffer =
        mState.mBufferManager->checkBufferAllocation(mImplementation.get(), bufferHandle);
    mState.bindVertexBuffer(this, bindingIndex, buffer, offset, stride);
    mStateCache.onVertexArrayStateChange(this);
}

void Context::bindSampler(GLuint textureUnit, SamplerID samplerHandle)
{
    ASSERT(textureUnit < static_cast<GLuint>(mState.mCaps.maxCombinedTextureImageUnits));
    Sampler *sampler =
        mState.mSamplerManager->checkSamplerAllocation(mImplementation.get(), samplerHandle);

    // Early return if rebinding the same sampler
    if (sampler == mState.getSampler(textureUnit))
    {
        return;
    }

    mState.setSamplerBinding(this, textureUnit, sampler);
    mSamplerObserverBindings[textureUnit].bind(sampler);
    mStateCache.onActiveTextureChange(this);
}

void Context::bindImageTexture(GLuint unit,
                               TextureID texture,
                               GLint level,
                               GLboolean layered,
                               GLint layer,
                               GLenum access,
                               GLenum format)
{
    Texture *tex = mState.mTextureManager->getTexture(texture);
    mState.setImageUnit(this, unit, tex, level, layered, layer, access, format);
    mImageObserverBindings[unit].bind(tex);
}

void Context::useProgram(ShaderProgramID program)
{
    ANGLE_CONTEXT_TRY(mState.setProgram(this, getProgramResolveLink(program)));
    mStateCache.onProgramExecutableChange(this);
}

void Context::useProgramStages(ProgramPipelineID pipeline,
                               GLbitfield stages,
                               ShaderProgramID program)
{
    Program *shaderProgram = getProgramNoResolveLink(program);
    ProgramPipeline *programPipeline =
        mState.mProgramPipelineManager->checkProgramPipelineAllocation(mImplementation.get(),
                                                                       pipeline);

    ASSERT(programPipeline);
    ANGLE_CONTEXT_TRY(programPipeline->useProgramStages(this, stages, shaderProgram));
}

void Context::bindTransformFeedback(GLenum target, TransformFeedbackID transformFeedbackHandle)
{
    ASSERT(target == GL_TRANSFORM_FEEDBACK);
    TransformFeedback *transformFeedback =
        checkTransformFeedbackAllocation(transformFeedbackHandle);
    mState.setTransformFeedbackBinding(this, transformFeedback);
    mStateCache.onActiveTransformFeedbackChange(this);
}

void Context::bindProgramPipeline(ProgramPipelineID pipelineHandle)
{
    ProgramPipeline *pipeline = mState.mProgramPipelineManager->checkProgramPipelineAllocation(
        mImplementation.get(), pipelineHandle);
    ANGLE_CONTEXT_TRY(mState.setProgramPipelineBinding(this, pipeline));
    mStateCache.onProgramExecutableChange(this);
    mProgramPipelineObserverBinding.bind(pipeline);
}

void Context::beginQuery(QueryType target, QueryID query)
{
    Query *queryObject = getOrCreateQuery(query, target);
    ASSERT(queryObject);

    // 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);
}

void Context::endQuery(QueryType target)
{
    Query *queryObject = mState.getActiveQuery(target);
    ASSERT(queryObject);

    // 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::queryCounter(QueryID id, QueryType target)
{
    ASSERT(target == QueryType::Timestamp);

    Query *queryObject = getOrCreateQuery(id, target);
    ASSERT(queryObject);

    ANGLE_CONTEXT_TRY(queryObject->queryCounter(this));
}

void Context::getQueryiv(QueryType target, GLenum pname, GLint *params)
{
    switch (pname)
    {
        case GL_CURRENT_QUERY_EXT:
            params[0] = mState.getActiveQueryId(target).value;
            break;
        case GL_QUERY_COUNTER_BITS_EXT:
            switch (target)
            {
                case QueryType::TimeElapsed:
                    params[0] = getCaps().queryCounterBitsTimeElapsed;
                    break;
                case QueryType::Timestamp:
                    params[0] = getCaps().queryCounterBitsTimestamp;
                    break;
                default:
                    UNREACHABLE();
                    params[0] = 0;
                    break;
            }
            break;
        default:
            UNREACHABLE();
            return;
    }
}

void Context::getQueryivRobust(QueryType target,
                               GLenum pname,
                               GLsizei bufSize,
                               GLsizei *length,
                               GLint *params)
{
    getQueryiv(target, pname, params);
}

void Context::getUnsignedBytev(GLenum pname, GLubyte *data)
{
    UNIMPLEMENTED();
}

void Context::getUnsignedBytei_v(GLenum target, GLuint index, GLubyte *data)
{
    UNIMPLEMENTED();
}

void Context::getQueryObjectiv(QueryID id, GLenum pname, GLint *params)
{
    ANGLE_CONTEXT_TRY(GetQueryObjectParameter(this, getQuery(id), pname, params));
}

void Context::getQueryObjectivRobust(QueryID id,
                                     GLenum pname,
                                     GLsizei bufSize,
                                     GLsizei *length,
                                     GLint *params)
{
    getQueryObjectiv(id, pname, params);
}

void Context::getQueryObjectuiv(QueryID id, GLenum pname, GLuint *params)
{
    ANGLE_CONTEXT_TRY(GetQueryObjectParameter(this, getQuery(id), pname, params));
}

void Context::getQueryObjectuivRobust(QueryID id,
                                      GLenum pname,
                                      GLsizei bufSize,
                                      GLsizei *length,
                                      GLuint *params)
{
    getQueryObjectuiv(id, pname, params);
}

void Context::getQueryObjecti64v(QueryID id, GLenum pname, GLint64 *params)
{
    ANGLE_CONTEXT_TRY(GetQueryObjectParameter(this, getQuery(id), pname, params));
}

void Context::getQueryObjecti64vRobust(QueryID id,
                                       GLenum pname,
                                       GLsizei bufSize,
                                       GLsizei *length,
                                       GLint64 *params)
{
    getQueryObjecti64v(id, pname, params);
}

void Context::getQueryObjectui64v(QueryID id, GLenum pname, GLuint64 *params)
{
    ANGLE_CONTEXT_TRY(GetQueryObjectParameter(this, getQuery(id), pname, params));
}

void Context::getQueryObjectui64vRobust(QueryID id,
                                        GLenum pname,
                                        GLsizei bufSize,
                                        GLsizei *length,
                                        GLuint64 *params)
{
    getQueryObjectui64v(id, pname, params);
}

Framebuffer *Context::getFramebuffer(FramebufferID handle) const
{
    return mState.mFramebufferManager->getFramebuffer(handle);
}

FenceNV *Context::getFenceNV(FenceNVID handle) const
{
    return mFenceNVMap.query(handle);
}

Query *Context::getOrCreateQuery(QueryID handle, QueryType type)
{
    if (!mQueryMap.contains(handle))
    {
        return nullptr;
    }

    Query *query = mQueryMap.query(handle);
    if (!query)
    {
        ASSERT(type != QueryType::InvalidEnum);
        query = new Query(mImplementation.get(), type, handle);
        query->addRef();
        mQueryMap.assign(handle, query);
    }
    return query;
}

Query *Context::getQuery(QueryID handle) const
{
    return mQueryMap.query(handle);
}

Texture *Context::getTextureByType(TextureType type) const
{
    ASSERT(ValidTextureTarget(this, type) || ValidTextureExternalTarget(this, type));
    return mState.getTargetTexture(type);
}

Texture *Context::getTextureByTarget(TextureTarget target) const
{
    return getTextureByType(TextureTargetToType(target));
}

Texture *Context::getSamplerTexture(unsigned int sampler, TextureType type) const
{
    return mState.getSamplerTexture(sampler, type);
}

Compiler *Context::getCompiler() const
{
    if (mCompiler.get() == nullptr)
    {
        mCompiler.set(thisnew Compiler(mImplementation.get(), mState, mDisplay));
    }
    return mCompiler.get();
}

void Context::getBooleanvImpl(GLenum pname, GLboolean *params) const
{
    switch (pname)
    {
        case GL_SHADER_COMPILER:
            *params = GL_TRUE;
            break;
        case GL_CONTEXT_ROBUST_ACCESS_EXT:
            *params = ConvertToGLBoolean(mState.hasRobustAccess());
            break;

        default:
            mState.getBooleanv(pname, params);
            break;
    }
}

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;
            }

            if (mState.hasRobustAccess())
            {
                contextFlags |= GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT;
            }
            *params = contextFlags;
        }
        break;
        case GL_CONTEXT_PROFILE_MASK:
            ASSERT(getClientType() == EGL_OPENGL_API);
            *params = mState.getProfileMask();
            break;

        // 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:
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=92 H=94 G=92

¤ Dauer der Verarbeitung: 0.23 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

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.