#include "libANGLE/Context.h"
#include "libANGLE/Context.inl.h"
#include <string.h>
#include <iterator>
#include <sstream>
#include <vector>
#include "common/PackedEnums.h"
#include "common/angle_version.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/Framebuffer.h"
#include "libANGLE/FramebufferAttachment.h"
#include "libANGLE/MemoryObject.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"
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)
{
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;
}
}
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;
}
Version GetClientVersion(egl::Display *display, const egl::AttributeMap &attribs)
{
Version requestedVersion =
Version(GetClientMajorVersion(attribs), GetClientMinorVersion(attribs));
if (GetBackwardCompatibleContext(attribs))
{
if (requestedVersion.major == 1)
{
return Version(1, 1);
}
else
{
return std::max(display->getImplementation()->getMaxConformantESVersion(),
requestedVersion);
}
}
else
{
return requestedVersion;
}
}
GLenum GetResetStrategy(const egl::AttributeMap &attribs)
{
EGLAttrib attrib =
attribs.get(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT, EGL_NO_RESET_NOTIFICATION);
switch (attrib)
{
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)
{
return (attribs.get(EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT, EGL_FALSE) == EGL_TRUE) ||
((attribs.get(EGL_CONTEXT_FLAGS_KHR, 0) & EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR) !=
0);
}
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 GetWebGLContext(const egl::AttributeMap &attribs)
{
return (attribs.get(EGL_CONTEXT_WEBGL_COMPATIBILITY_ANGLE, EGL_FALSE) == EGL_TRUE);
}
bool GetExtensionsEnabled(const egl::AttributeMap &attribs, bool webGLContext)
{
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
};
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.mMaxDrawBuffers);
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);
}
}
thread_local Context *gCurrentValidContext = nullptr;
Context::Context(egl::Display *display,
const egl::Config *config,
const Context *shareContext,
TextureManager *shareTextures,
SemaphoreManager *shareSemaphores,
MemoryProgramCache *memoryProgramCache,
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),
GetDebug(attribs),
GetBindGeneratesResource(attribs),
GetClientArraysEnabled(attribs),
GetRobustResourceInit(display, attribs),
memoryProgramCache != nullptr,
GetContextPriority(attribs),
GetProtectedContent(attribs)),
mShared(shareContext != 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)),
mRobustAccess(GetRobustAccess(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),
mVertexArrayObserverBinding(this, kVertexArraySubjectIndex),
mDrawFramebufferObserverBinding(this, kDrawFramebufferSubjectIndex),
mReadFramebufferObserverBinding(this, kReadFramebufferSubjectIndex),
mThreadPool(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);
}
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();
if (mDisplay->getFrontendFeatures().syncFramebufferBindingsOnTexImage.enabled)
{
mTexImageDirtyBits.set(State::DIRTY_BIT_READ_FRAMEBUFFER_BINDING);
mTexImageDirtyBits.set(State::DIRTY_BIT_DRAW_FRAMEBUFFER_BINDING);
}
mState.initialize(this);
mFenceNVHandleAllocator.setBaseHandle(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.textureMultisample)
{
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 (getClientVersion() >= Version(3, 2) || mSupportedExtensions.textureCubeMapArrayAny())
{
Texture *zeroTextureCubeMapArray =
new Texture(mImplementation.get(), {0}, TextureType::CubeMapArray);
mZeroTextures[TextureType::CubeMapArray].set(this, zeroTextureCubeMapArray);
}
if (getClientVersion() >= Version(3, 2) || mSupportedExtensions.textureBufferAny())
{
Texture *zeroTextureBuffer = new Texture(mImplementation.get(), {0}, TextureType::Buffer);
mZeroTextures[TextureType::Buffer].set(this, zeroTextureBuffer);
}
if (mSupportedExtensions.textureRectangle)
{
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);
}
if (mSupportedExtensions.webglVideoTexture)
{
Texture *zeroTextureVideoImage =
new Texture(mImplementation.get(), {0}, TextureType::VideoImage);
mZeroTextures[TextureType::VideoImage].set(this, zeroTextureVideoImage);
}
mState.initializeZeroTextures(this, mZeroTextures);
ANGLE_CONTEXT_TRY(mImplementation->initialize());
mState.getShareGroup()->addSharedContext(this);
bindVertexArray({0});
if (getClientVersion() >= Version(3, 0))
{
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);
}
if (getClientVersion() < Version(2, 0))
{
mGLES1Renderer.reset(new GLES1Renderer());
}
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_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);
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);
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_IMAGES);
mComputeDirtyObjects.set(State::DIRTY_OBJECT_SAMPLERS);
mCopyImageDirtyBits.set(State::DIRTY_BIT_READ_FRAMEBUFFER_BINDING);
mCopyImageDirtyObjects.set(State::DIRTY_OBJECT_READ_FRAMEBUFFER);
ANGLE_CONTEXT_TRY(mOverlay.init(this));
}
egl::Error Context::onDestroy(const egl::Display *display)
{
if (!mHasBeenCurrent)
{
return egl::NoError();
}
ASSERT(mIsDestroyed == true && mRefCount == 0);
getShareGroup()->getFrameCaptureShared()->onDestroyContext(this);
if (mGLES1Renderer)
{
mGLES1Renderer->onDestroy(this, &mState);
}
ANGLE_TRY(unMakeCurrent(display));
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);
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);
mThreadPool.reset();
mImplementation->onDestroy(this);
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);
mState.setAllDirtyBits();
mState.setAllDirtyObjects();
ANGLE_TRY(setDefaultFramebuffer(drawSurface, readSurface));
angle::Result implResult = mImplementation->onMakeCurrent(this);
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());
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();
}
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())
{
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;
}
if (!getShareGroup()->getFrameCaptureShared()->enabled())
{
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)
{
mState.mSyncManager->deleteObject(this, static_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);
}
void Context::loseContext(GraphicsResetStatus current, GraphicsResetStatus other)
{
markContextLost(current);
}
void Context::deleteFramebuffer(FramebufferID framebuffer)
{
if (mState.mFramebufferManager->getFramebuffer(framebuffer))
{
detachFramebuffer(framebuffer);
}
mState.mFramebufferManager->deleteObject(this, framebuffer);
}
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);
object->setLabel(this, labelName);
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);
}
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);
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)
{
Texture *texture = nullptr;
if (handle.value == 0)
{
texture = mZeroTextures[target].get();
}
else
{
texture =
mState.mTextureManager->checkTextureAllocation(mImplementation.get(), handle, target);
}
ASSERT(texture);
mState.setSamplerTexture(this, target, texture);
mStateCache.onActiveTextureChange(this);
}
void Context::bindReadFramebuffer(FramebufferID framebufferHandle)
{
Framebuffer *framebuffer = mState.mFramebufferManager->checkFramebufferAllocation(
mImplementation.get(), mState.mCaps, framebufferHandle, getShareGroup());
mState.setReadFramebufferBinding(framebuffer);
mReadFramebufferObserverBinding.bind(framebuffer);
}
void Context::bindDrawFramebuffer(FramebufferID framebufferHandle)
{
Framebuffer *framebuffer = mState.mFramebufferManager->checkFramebufferAllocation(
mImplementation.get(), mState.mCaps, framebufferHandle, getShareGroup());
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);
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(mState.useProgramStages(this, programPipeline, stages, shaderProgram));
mStateCache.onProgramExecutableChange(this);
}
void Context::bindTransformFeedback(GLenum target, TransformFeedbackID transformFeedbackHandle)
{
ASSERT(target == GL_TRANSFORM_FEEDBACK);
TransformFeedback *transformFeedback =
checkTransformFeedbackAllocation(transformFeedbackHandle);
mState.setTransformFeedbackBinding(this, transformFeedback);
}
void Context::bindProgramPipeline(ProgramPipelineID pipelineHandle)
{
ProgramPipeline *pipeline = mState.mProgramPipelineManager->checkProgramPipelineAllocation(
mImplementation.get(), pipelineHandle);
ANGLE_CONTEXT_TRY(mState.setProgramPipelineBinding(this, pipeline));
mStateCache.onProgramExecutableChange(this);
}
void Context::beginQuery(QueryType target, QueryID query)
{
Query *queryObject = getOrCreateQuery(query, target);
ASSERT(queryObject);
ANGLE_CONTEXT_TRY(queryObject->begin(this));
mState.setActiveQuery(this, target, queryObject);
mStateCache.onQueryChange(this);
}
void Context::endQuery(QueryType target)
{
Query *queryObject = mState.getActiveQuery(target);
ASSERT(queryObject);
(void)(queryObject->end(this));
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] = getExtensions().queryCounterBitsTimeElapsed;
break;
case QueryType::Timestamp:
params[0] = getExtensions().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(this, new 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(mRobustAccess);
break;
default:
mState.getBooleanv(pname, params);
break;
}
}
void Context::getFloatvImpl(GLenum pname, GLfloat *params) const
{
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.textureFilterAnisotropic);
*params = mState.mExtensions.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
{
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;
case GL_CONTEXT_FLAGS:
{
ASSERT(getClientType() == EGL_OPENGL_API);
GLint contextFlags = 0;
if (mState.hasProtectedContent())
{
contextFlags |= GL_CONTEXT_FLAG_PROTECTED_CONTENT_BIT_EXT;
}
*params = contextFlags;
}
break;
case GL_CONTEXT_PROFILE_MASK:
ASSERT(getClientType() == EGL_OPENGL_API);
*params = GL_CONTEXT_COMPATIBILITY_PROFILE_BIT;
break;
case GL_NUM_REQUESTABLE_EXTENSIONS_ANGLE:
*params = static_cast<GLint>(mRequestableExtensionStrings.size());
break;
case GL_MAX_DEBUG_MESSAGE_LENGTH:
*params = mState.mExtensions.maxDebugMessageLength;
break;
case GL_MAX_DEBUG_LOGGED_MESSAGES:
*params = mState.mExtensions.maxDebugLoggedMessages;
break;
case GL_MAX_DEBUG_GROUP_STACK_DEPTH:
*params = mState.mExtensions.maxDebugGroupStackDepth;
break;
case GL_MAX_LABEL_LENGTH:
*params = mState.mExtensions.maxLabelLength;
break;
case GL_MAX_VIEWS_OVR:
*params = mState.mExtensions.maxViews;
break;
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;
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;
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;
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_PLANES:
if (getClientVersion().major >= 2)
{
*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;
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;
case GL_MAX_SHADER_COMPILER_THREADS_KHR:
*params = mState.getMaxShaderCompilerThreads();
break;
case GL_MAX_DUAL_SOURCE_DRAW_BUFFERS_EXT:
*params = mState.mExtensions.maxDualSourceDrawBuffers;
break;
case GL_FRAGMENT_INTERPOLATION_OFFSET_BITS_OES:
*params = mState.mCaps.subPixelInterpolationOffsetBits;
break;
case GL_MAX_TEXTURE_BUFFER_SIZE:
*params = mState.mCaps.maxTextureBufferSize;
break;
case GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT:
*params = mState.mCaps.textureBufferOffsetAlignment;
break;
case GL_CLIP_ORIGIN_EXT:
*params = mState.mClipControlOrigin;
break;
case GL_CLIP_DEPTH_MODE_EXT:
*params = mState.mClipControlDepth;
break;
default:
ANGLE_CONTEXT_TRY(mState.getIntegerv(this, pname, params));
break;
}
}
void Context::getIntegerVertexAttribImpl(GLenum pname, GLenum attribpname, GLint *params) const
{
getVertexAttribivImpl(static_cast<GLuint>(vertexArrayIndex(ParamToVertexArrayType(pname))),
attribpname, params);
}
void Context::getInteger64vImpl(GLenum pname, GLint64 *params) const
{
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;
case GL_TIMESTAMP_EXT:
*params = mImplementation->getTimestamp();
break;
case GL_MAX_SHADER_STORAGE_BLOCK_SIZE:
*params = mState.mCaps.maxShaderStorageBlockSize;
break;
default:
UNREACHABLE();
break;
}
}
void Context::getPointerv(GLenum pname, void **params)
{
mState.getPointerv(this, pname, params);
}
void Context::getPointervRobustANGLERobust(GLenum pname,
GLsizei bufSize,
GLsizei *length,
void **params)
{
UNIMPLEMENTED();
}
void Context::getIntegeri_v(GLenum target, GLuint index, GLint *data)
{
GLenum nativeType;
unsigned int numParams;
bool queryStatus = getIndexedQueryParameterInfo(target, &nativeType, &numParams);
ASSERT(queryStatus);
if (nativeType == GL_INT)
{
switch (target)
{
case GL_MAX_COMPUTE_WORK_GROUP_COUNT:
ASSERT(index < 3u);
*data = mState.mCaps.maxComputeWorkGroupCount[index];
break;
case GL_MAX_COMPUTE_WORK_GROUP_SIZE:
ASSERT(index < 3u);
*data = mState.mCaps.maxComputeWorkGroupSize[index];
break;
default:
mState.getIntegeri_v(target, index, data);
}
}
else
{
CastIndexedStateValues(this, nativeType, target, index, numParams, data);
}
}
void Context::getIntegeri_vRobust(GLenum target,
GLuint index,
GLsizei bufSize,
GLsizei *length,
GLint *data)
{
getIntegeri_v(target, index, data);
}
void Context::getInteger64i_v(GLenum target, GLuint index, GLint64 *data)
{
GLenum nativeType;
unsigned int numParams;
bool queryStatus = getIndexedQueryParameterInfo(target, &nativeType, &numParams);
ASSERT(queryStatus);
if (nativeType == GL_INT_64_ANGLEX)
{
mState.getInteger64i_v(target, index, data);
}
else
{
CastIndexedStateValues(this, nativeType, target, index, numParams, data);
}
}
void Context::getInteger64i_vRobust(GLenum target,
GLuint index,
GLsizei bufSize,
GLsizei *length,
GLint64 *data)
{
getInteger64i_v(target, index, data);
}
void Context::getBooleani_v(GLenum target, GLuint index, GLboolean *data)
{
GLenum nativeType;
unsigned int numParams;
bool queryStatus = getIndexedQueryParameterInfo(target, &nativeType, &numParams);
ASSERT(queryStatus);
if (nativeType == GL_BOOL)
{
mState.getBooleani_v(target, index, data);
}
else
{
CastIndexedStateValues(this, nativeType, target, index, numParams, data);
}
}
void Context::getBooleani_vRobust(GLenum target,
GLuint index,
GLsizei bufSize,
GLsizei *length,
GLboolean *data)
{
getBooleani_v(target, index, data);
}
void Context::getBufferParameteriv(BufferBinding target, GLenum pname, GLint *params)
{
Buffer *buffer = mState.getTargetBuffer(target);
QueryBufferParameteriv(buffer, pname, params);
}
void Context::getBufferParameterivRobust(BufferBinding target,
GLenum pname,
GLsizei bufSize,
GLsizei *length,
GLint *params)
{
getBufferParameteriv(target, pname, params);
}
void Context::getFramebufferAttachmentParameteriv(GLenum target,
GLenum attachment,
GLenum pname,
GLint *params)
{
const Framebuffer *framebuffer = mState.getTargetFramebuffer(target);
QueryFramebufferAttachmentParameteriv(this, framebuffer, attachment, pname, params);
}
void Context::getFramebufferAttachmentParameterivRobust(GLenum target,
GLenum attachment,
GLenum pname,
GLsizei bufSize,
GLsizei *length,
GLint *params)
{
getFramebufferAttachmentParameteriv(target, attachment, pname, params);
}
void Context::getRenderbufferParameteriv(GLenum target, GLenum pname, GLint *params)
{
Renderbuffer *renderbuffer = mState.getCurrentRenderbuffer();
QueryRenderbufferiv(this, renderbuffer, pname, params);
}
void Context::getRenderbufferParameterivRobust(GLenum target,
GLenum pname,
GLsizei bufSize,
GLsizei *length,
GLint *params)
{
getRenderbufferParameteriv(target, pname, params);
}
void Context::texBuffer(TextureType target, GLenum internalformat, BufferID buffer)
{
ASSERT(target == TextureType::Buffer);
Texture *texture = getTextureByType(target);
Buffer *bufferObj = mState.mBufferManager->getBuffer(buffer);
ANGLE_CONTEXT_TRY(texture->setBuffer(this, bufferObj, internalformat));
}
void Context::texBufferRange(TextureType target,
GLenum internalformat,
BufferID buffer,
GLintptr offset,
GLsizeiptr size)
{
ASSERT(target == TextureType::Buffer);
Texture *texture = getTextureByType(target);
Buffer *bufferObj = mState.mBufferManager->getBuffer(buffer);
ANGLE_CONTEXT_TRY(texture->setBufferRange(this, bufferObj, internalformat, offset, size));
}
void Context::getTexParameterfv(TextureType target, GLenum pname, GLfloat *params)
{
const Texture *const texture = getTextureByType(target);
QueryTexParameterfv(this, texture, pname, params);
}
void Context::getTexParameterfvRobust(TextureType target,
GLenum pname,
GLsizei bufSize,
GLsizei *length,
GLfloat *params)
{
getTexParameterfv(target, pname, params);
}
void Context::getTexParameteriv(TextureType target, GLenum pname, GLint *params)
{
const Texture *const texture = getTextureByType(target);
QueryTexParameteriv(this, texture, pname, params);
}
void Context::getTexParameterIiv(TextureType target, GLenum pname, GLint *params)
{
const Texture *const texture = getTextureByType(target);
QueryTexParameterIiv(this, texture, pname, params);
}
void Context::getTexParameterIuiv(TextureType target, GLenum pname, GLuint *params)
{
const Texture *const texture = getTextureByType(target);
QueryTexParameterIuiv(this, texture, pname, params);
}
void Context::getTexParameterivRobust(TextureType target,
GLenum pname,
GLsizei bufSize,
GLsizei *length,
GLint *params)
{
getTexParameteriv(target, pname, params);
}
void Context::getTexParameterIivRobust(TextureType target,
GLenum pname,
GLsizei bufSize,
GLsizei *length,
GLint *params)
{
UNIMPLEMENTED();
}
void Context::getTexParameterIuivRobust(TextureType target,
GLenum pname,
GLsizei bufSize,
GLsizei *length,
GLuint *params)
{
UNIMPLEMENTED();
}
void Context::getTexLevelParameteriv(TextureTarget target, GLint level, GLenum pname, GLint *params)
{
Texture *texture = getTextureByTarget(target);
QueryTexLevelParameteriv(texture, target, level, pname, params);
}
void Context::getTexLevelParameterivRobust(TextureTarget target,
GLint level,
GLenum pname,
GLsizei bufSize,
GLsizei *length,
GLint *params)
{
UNIMPLEMENTED();
}
void Context::getTexLevelParameterfv(TextureTarget target,
GLint level,
GLenum pname,
GLfloat *params)
{
Texture *texture = getTextureByTarget(target);
QueryTexLevelParameterfv(texture, target, level, pname, params);
}
void Context::getTexLevelParameterfvRobust(TextureTarget target,
GLint level,
GLenum pname,
GLsizei bufSize,
GLsizei *length,
GLfloat *params)
{
UNIMPLEMENTED();
}
void Context::texParameterf(TextureType target, GLenum pname, GLfloat param)
{
Texture *const texture = getTextureByType(target);
SetTexParameterf(this, texture, pname, param);
}
void Context::texParameterfv(TextureType target, GLenum pname, const GLfloat *params)
{
Texture *const texture = getTextureByType(target);
SetTexParameterfv(this, texture, pname, params);
}
void Context::texParameterfvRobust(TextureType target,
GLenum pname,
GLsizei bufSize,
const GLfloat *params)
{
texParameterfv(target, pname, params);
}
void Context::texParameteri(TextureType target, GLenum pname, GLint param)
{
Texture *const texture = getTextureByType(target);
SetTexParameteri(this, texture, pname, param);
}
void Context::texParameteriv(TextureType target, GLenum pname, const GLint *params)
{
Texture *const texture = getTextureByType(target);
SetTexParameteriv(this, texture, pname, params);
}
void Context::texParameterIiv(TextureType target, GLenum pname, const GLint *params)
{
Texture *const texture = getTextureByType(target);
SetTexParameterIiv(this, texture, pname, params);
}
void Context::texParameterIuiv(TextureType target, GLenum pname, const GLuint *params)
{
Texture *const texture = getTextureByType(target);
SetTexParameterIuiv(this, texture, pname, params);
}
void Context::texParameterivRobust(TextureType target,
GLenum pname,
GLsizei bufSize,
const GLint *params)
{
texParameteriv(target, pname, params);
}
void Context::texParameterIivRobust(TextureType target,
GLenum pname,
GLsizei bufSize,
const GLint *params)
{
UNIMPLEMENTED();
}
void Context::texParameterIuivRobust(TextureType target,
GLenum pname,
GLsizei bufSize,
const GLuint *params)
{
UNIMPLEMENTED();
}
void Context::drawArraysInstanced(PrimitiveMode mode,
GLint first,
GLsizei count,
GLsizei instanceCount)
{
if (noopDrawInstanced(mode, count, instanceCount))
{
ANGLE_CONTEXT_TRY(mImplementation->handleNoopDrawEvent());
return;
}
ANGLE_CONTEXT_TRY(prepareForDraw(mode));
ANGLE_CONTEXT_TRY(
mImplementation->drawArraysInstanced(this, mode, first, count, instanceCount));
MarkTransformFeedbackBufferUsage(this, count, instanceCount);
MarkShaderStorageUsage(this);
}
void Context::drawElementsInstanced(PrimitiveMode mode,
GLsizei count,
DrawElementsType type,
const void *indices,
GLsizei instances)
{
if (noopDrawInstanced(mode, count, instances))
{
ANGLE_CONTEXT_TRY(mImplementation->handleNoopDrawEvent());
return;
}
ANGLE_CONTEXT_TRY(prepareForDraw(mode));
ANGLE_CONTEXT_TRY(
mImplementation->drawElementsInstanced(this, mode, count, type, indices, instances));
MarkShaderStorageUsage(this);
}
void Context::drawElementsBaseVertex(PrimitiveMode mode,
GLsizei count,
DrawElementsType type,
const void *indices,
GLint basevertex)
{
if (noopDraw(mode, count))
{
ANGLE_CONTEXT_TRY(mImplementation->handleNoopDrawEvent());
return;
}
ANGLE_CONTEXT_TRY(prepareForDraw(mode));
ANGLE_CONTEXT_TRY(
mImplementation->drawElementsBaseVertex(this, mode, count, type, indices, basevertex));
MarkShaderStorageUsage(this);
}
void Context::drawElementsInstancedBaseVertex(PrimitiveMode mode,
GLsizei count,
DrawElementsType type,
const void *indices,
GLsizei instancecount,
GLint basevertex)
{
if (noopDrawInstanced(mode, count, instancecount))
{
ANGLE_CONTEXT_TRY(mImplementation->handleNoopDrawEvent());
return;
}
ANGLE_CONTEXT_TRY(prepareForDraw(mode));
ANGLE_CONTEXT_TRY(mImplementation->drawElementsInstancedBaseVertex(
this, mode, count, type, indices, instancecount, basevertex));
MarkShaderStorageUsage(this);
}
void Context::drawRangeElements(PrimitiveMode mode,
GLuint start,
GLuint end,
GLsizei count,
DrawElementsType type,
const void *indices)
{
if (noopDraw(mode, count))
{
ANGLE_CONTEXT_TRY(mImplementation->handleNoopDrawEvent());
return;
}
ANGLE_CONTEXT_TRY(prepareForDraw(mode));
ANGLE_CONTEXT_TRY(
mImplementation->drawRangeElements(this, mode, start, end, count, type, indices));
MarkShaderStorageUsage(this);
}
void Context::drawRangeElementsBaseVertex(PrimitiveMode mode,
GLuint start,
GLuint end,
GLsizei count,
DrawElementsType type,
const void *indices,
GLint basevertex)
{
if (noopDraw(mode, count))
{
ANGLE_CONTEXT_TRY(mImplementation->handleNoopDrawEvent());
return;
}
ANGLE_CONTEXT_TRY(prepareForDraw(mode));
ANGLE_CONTEXT_TRY(mImplementation->drawRangeElementsBaseVertex(this, mode, start, end, count,
type, indices, basevertex));
MarkShaderStorageUsage(this);
}
void Context::drawArraysIndirect(PrimitiveMode mode, const void *indirect)
{
ANGLE_CONTEXT_TRY(prepareForDraw(mode));
ANGLE_CONTEXT_TRY(mImplementation->drawArraysIndirect(this, mode, indirect));
MarkShaderStorageUsage(this);
}
void Context::drawElementsIndirect(PrimitiveMode mode, DrawElementsType type, const void *indirect)
{
ANGLE_CONTEXT_TRY(prepareForDraw(mode));
ANGLE_CONTEXT_TRY(mImplementation->drawElementsIndirect(this, mode, type, indirect));
MarkShaderStorageUsage(this);
}
void Context::flush()
{
ANGLE_CONTEXT_TRY(mImplementation->flush(this));
}
void Context::finish()
{
ANGLE_CONTEXT_TRY(mImplementation->finish(this));
}
void Context::insertEventMarker(GLsizei length, const char *marker)
{
ASSERT(mImplementation);
ANGLE_CONTEXT_TRY(mImplementation->insertEventMarker(length, marker));
}
void Context::pushGroupMarker(GLsizei length, const char *marker)
{
ASSERT(mImplementation);
if (marker == nullptr)
{
ANGLE_CONTEXT_TRY(mImplementation->pushGroupMarker(length, ""));
}
else
{
ANGLE_CONTEXT_TRY(mImplementation->pushGroupMarker(length, marker));
}
}
void Context::popGroupMarker()
{
ASSERT(mImplementation);
ANGLE_CONTEXT_TRY(mImplementation->popGroupMarker());
}
void Context::bindUniformLocation(ShaderProgramID program,
UniformLocation location,
const GLchar *name)
{
Program *programObject = getProgramResolveLink(program);
ASSERT(programObject);
programObject->bindUniformLocation(location, name);
}
void Context::coverageModulation(GLenum components)
{
mState.setCoverageModulation(components);
}
GLuint Context::getProgramResourceIndex(ShaderProgramID program,
GLenum programInterface,
const GLchar *name)
{
const Program *programObject = getProgramResolveLink(program);
return QueryProgramResourceIndex(programObject, programInterface, name);
}
void Context::getProgramResourceName(ShaderProgramID program,
GLenum programInterface,
GLuint index,
GLsizei bufSize,
GLsizei *length,
GLchar *name)
{
const Program *programObject = getProgramResolveLink(program);
QueryProgramResourceName(programObject, programInterface, index, bufSize, length, name);
}
GLint Context::getProgramResourceLocation(ShaderProgramID program,
GLenum programInterface,
const GLchar *name)
{
const Program *programObject = getProgramResolveLink(program);
return QueryProgramResourceLocation(programObject, programInterface, name);
}
void Context::getProgramResourceiv(ShaderProgramID program,
GLenum programInterface,
GLuint index,
GLsizei propCount,
const GLenum *props,
GLsizei bufSize,
GLsizei *length,
GLint *params)
{
const Program *programObject = getProgramResolveLink(program);
QueryProgramResourceiv(programObject, programInterface, {index}, propCount, props, bufSize,
length, params);
}
void Context::getProgramInterfaceiv(ShaderProgramID program,
GLenum programInterface,
GLenum pname,
GLint *params)
{
const Program *programObject = getProgramResolveLink(program);
QueryProgramInterfaceiv(programObject, programInterface, pname, params);
}
void Context::getProgramInterfaceivRobust(ShaderProgramID program,
GLenum programInterface,
GLenum pname,
GLsizei bufSize,
GLsizei *length,
GLint *params)
{
UNIMPLEMENTED();
}
void Context::handleError(GLenum errorCode,
const char *message,
const char *file,
const char *function,
unsigned int line)
{
mErrors.handleError(errorCode, message, file, function, line);
}
void Context::validationError(GLenum errorCode, const char *message) const
{
const_cast<Context *>(this)->mErrors.validationError(errorCode, message);
}
GLenum Context::getError()
{
if (mErrors.empty())
{
return GL_NO_ERROR;
}
else
{
return mErrors.popError();
}
}
void Context::markContextLost(GraphicsResetStatus status)
{
ASSERT(status != GraphicsResetStatus::NoError);
if (mResetStrategy == GL_LOSE_CONTEXT_ON_RESET_EXT)
{
mResetStatus = status;
mContextLostForced = true;
}
setContextLost();
}
void Context::setContextLost()
{
mContextLost = true;
mSkipValidation = false;
gCurrentValidContext = nullptr;
}
GLenum Context::getGraphicsResetStatus()
{
if (mResetStrategy == GL_NO_RESET_NOTIFICATION_EXT)
{
if (!isContextLost() && mImplementation->getResetStatus() != GraphicsResetStatus::NoError)
{
setContextLost();
}
return GL_NO_ERROR;
}
if (!isContextLost())
{
ASSERT(mResetStatus == GraphicsResetStatus::NoError);
mResetStatus = mImplementation->getResetStatus();
if (mResetStatus != GraphicsResetStatus::NoError)
{
setContextLost();
}
}
else if (!mContextLostForced && mResetStatus != GraphicsResetStatus::NoError)
{
mResetStatus = mImplementation->getResetStatus();
}
return ToGLenum(mResetStatus);
}
bool Context::isResetNotificationEnabled() const
{
return (mResetStrategy == GL_LOSE_CONTEXT_ON_RESET_EXT);
}
const egl::Config *Context::getConfig() const
{
return mConfig;
}
EGLenum Context::getClientType() const
{
return mState.getClientType();
}
EGLenum Context::getRenderBuffer() const
{
const Framebuffer *framebuffer =
mState.mFramebufferManager->getFramebuffer(Framebuffer::kDefaultDrawFramebufferHandle);
if (framebuffer == nullptr)
{
return EGL_NONE;
}
const FramebufferAttachment *backAttachment = framebuffer->getAttachment(this, GL_BACK);
ASSERT(backAttachment != nullptr);
return backAttachment->getSurface()->getRenderBuffer();
}
VertexArray *Context::checkVertexArrayAllocation(VertexArrayID vertexArrayHandle)
{
VertexArray *vertexArray = getVertexArray(vertexArrayHandle);
if (!vertexArray)
{
vertexArray =
new VertexArray(mImplementation.get(), vertexArrayHandle,
mState.mCaps.maxVertexAttributes, mState.mCaps.maxVertexAttribBindings);
vertexArray->setBufferAccessValidationEnabled(mBufferAccessValidationEnabled);
mVertexArrayMap.assign(vertexArrayHandle, vertexArray);
}
return vertexArray;
}
TransformFeedback *Context::checkTransformFeedbackAllocation(
TransformFeedbackID transformFeedbackHandle)
{
TransformFeedback *transformFeedback = getTransformFeedback(transformFeedbackHandle);
if (!transformFeedback)
{
transformFeedback =
new TransformFeedback(mImplementation.get(), transformFeedbackHandle, mState.mCaps);
transformFeedback->addRef();
mTransformFeedbackMap.assign(transformFeedbackHandle, transformFeedback);
}
return transformFeedback;
}
bool Context::isVertexArrayGenerated(VertexArrayID vertexArray) const
{
ASSERT(mVertexArrayMap.contains({0}));
return mVertexArrayMap.contains(vertexArray);
}
bool Context::isTransformFeedbackGenerated(TransformFeedbackID transformFeedback) const
{
ASSERT(mTransformFeedbackMap.contains({0}));
return mTransformFeedbackMap.contains(transformFeedback);
}
void Context::detachTexture(TextureID texture)
{
Texture *tex = mState.mTextureManager->getTexture(texture);
for (auto &imageBinding : mImageObserverBindings)
{
if (imageBinding.getSubject() == tex)
{
imageBinding.reset();
}
}
mState.detachTexture(this, mZeroTextures, texture);
}
void Context::detachBuffer(Buffer *buffer)
{
ANGLE_CONTEXT_TRY(mState.detachBuffer(this, buffer));
}
void Context::detachFramebuffer(FramebufferID framebuffer)
{
if (mState.removeReadFramebufferBinding(framebuffer) && framebuffer.value != 0)
{
bindReadFramebuffer({0});
}
if (mState.removeDrawFramebufferBinding(framebuffer) && framebuffer.value != 0)
{
bindDrawFramebuffer({0});
}
}
void Context::detachRenderbuffer(RenderbufferID renderbuffer)
{
mState.detachRenderbuffer(this, renderbuffer);
}
void Context::detachVertexArray(VertexArrayID vertexArray)
{
if (mState.removeVertexArrayBinding(this, vertexArray))
{
bindVertexArray({0});
}
}
void Context::detachTransformFeedback(TransformFeedbackID transformFeedback)
{
if (mState.removeTransformFeedbackBinding(this, transformFeedback))
{
bindTransformFeedback(GL_TRANSFORM_FEEDBACK, {0});
}
}
void Context::detachSampler(SamplerID sampler)
{
mState.detachSampler(this, sampler);
}
void Context::detachProgramPipeline(ProgramPipelineID pipeline)
{
mState.detachProgramPipeline(this, pipeline);
}
void Context::vertexAttribDivisor(GLuint index, GLuint divisor)
{
mState.setVertexAttribDivisor(this, index, divisor);
mStateCache.onVertexArrayStateChange(this);
}
void Context::samplerParameteri(SamplerID sampler, GLenum pname, GLint param)
{
Sampler *const samplerObject =
mState.mSamplerManager->checkSamplerAllocation(mImplementation.get(), sampler);
SetSamplerParameteri(this, samplerObject, pname, param);
}
void Context::samplerParameteriv(SamplerID sampler, GLenum pname, const GLint *param)
{
Sampler *const samplerObject =
mState.mSamplerManager->checkSamplerAllocation(mImplementation.get(), sampler);
SetSamplerParameteriv(this, samplerObject, pname, param);
}
void Context::samplerParameterIiv(SamplerID sampler, GLenum pname, const GLint *param)
{
Sampler *const samplerObject =
mState.mSamplerManager->checkSamplerAllocation(mImplementation.get(), sampler);
SetSamplerParameterIiv(this, samplerObject, pname, param);
}
void Context::samplerParameterIuiv(SamplerID sampler, GLenum pname, const GLuint *param)
{
Sampler *const samplerObject =
mState.mSamplerManager->checkSamplerAllocation(mImplementation.get(), sampler);
SetSamplerParameterIuiv(this, samplerObject, pname, param);
}
void Context::samplerParameterivRobust(SamplerID sampler,
GLenum pname,
GLsizei bufSize,
const GLint *param)
{
samplerParameteriv(sampler, pname, param);
}
void Context::samplerParameterIivRobust(SamplerID sampler,
GLenum pname,
GLsizei bufSize,
const GLint *param)
{
UNIMPLEMENTED();
}
void Context::samplerParameterIuivRobust(SamplerID sampler,
GLenum pname,
GLsizei bufSize,
const GLuint *param)
{
UNIMPLEMENTED();
}
void Context::samplerParameterf(SamplerID sampler, GLenum pname, GLfloat param)
{
Sampler *const samplerObject =
mState.mSamplerManager->checkSamplerAllocation(mImplementation.get(), sampler);
SetSamplerParameterf(this, samplerObject, pname, param);
}
void Context::samplerParameterfv(SamplerID sampler, GLenum pname, const GLfloat *param)
{
Sampler *const samplerObject =
mState.mSamplerManager->checkSamplerAllocation(mImplementation.get(), sampler);
SetSamplerParameterfv(this, samplerObject, pname, param);
}
void Context::samplerParameterfvRobust(SamplerID sampler,
GLenum pname,
GLsizei bufSize,
const GLfloat *param)
{
samplerParameterfv(sampler, pname, param);
}
void Context::getSamplerParameteriv(SamplerID sampler, GLenum pname, GLint *params)
{
const Sampler *const samplerObject =
mState.mSamplerManager->checkSamplerAllocation(mImplementation.get(), sampler);
QuerySamplerParameteriv(samplerObject, pname, params);
}
void Context::getSamplerParameterIiv(SamplerID sampler, GLenum pname, GLint *params)
{
const Sampler *const samplerObject =
mState.mSamplerManager->checkSamplerAllocation(mImplementation.get(), sampler);
QuerySamplerParameterIiv(samplerObject, pname, params);
}
void Context::getSamplerParameterIuiv(SamplerID sampler, GLenum pname, GLuint *params)
{
const Sampler *const samplerObject =
mState.mSamplerManager->checkSamplerAllocation(mImplementation.get(), sampler);
QuerySamplerParameterIuiv(samplerObject, pname, params);
}
void Context::getSamplerParameterivRobust(SamplerID sampler,
GLenum pname,
GLsizei bufSize,
GLsizei *length,
GLint *params)
{
getSamplerParameteriv(sampler, pname, params);
}
void Context::getSamplerParameterIivRobust(SamplerID sampler,
GLenum pname,
GLsizei bufSize,
GLsizei *length,
GLint *params)
{
UNIMPLEMENTED();
}
void Context::getSamplerParameterIuivRobust(SamplerID sampler,
GLenum pname,
GLsizei bufSize,
GLsizei *length,
GLuint *params)
{
UNIMPLEMENTED();
}
void Context::getSamplerParameterfv(SamplerID sampler, GLenum pname, GLfloat *params)
{
const Sampler *const samplerObject =
mState.mSamplerManager->checkSamplerAllocation(mImplementation.get(), sampler);
QuerySamplerParameterfv(samplerObject, pname, params);
}
void Context::getSamplerParameterfvRobust(SamplerID sampler,
GLenum pname,
GLsizei bufSize,
GLsizei *length,
GLfloat *params)
{
getSamplerParameterfv(sampler, pname, params);
}
void Context::programParameteri(ShaderProgramID program, GLenum pname, GLint value)
{
gl::Program *programObject = getProgramResolveLink(program);
SetProgramParameteri(programObject, pname, value);
}
void Context::initRendererString()
{
std::ostringstream frontendRendererString;
std::string vendorString(mDisplay->getBackendVendorString());
std::string rendererString(mDisplay->getBackendRendererDescription());
std::string versionString(mDisplay->getBackendVersionString());
vendorString.erase(std::remove(vendorString.begin(), vendorString.end(), ','),
vendorString.end());
rendererString.erase(std::remove(rendererString.begin(), rendererString.end(), ','),
rendererString.end());
versionString.erase(std::remove(versionString.begin(), versionString.end(), ','),
versionString.end());
frontendRendererString << "ANGLE (";
frontendRendererString << vendorString;
frontendRendererString << ", ";
frontendRendererString << rendererString;
frontendRendererString << ", ";
frontendRendererString << versionString;
frontendRendererString << ")";
mRendererString = MakeStaticString(frontendRendererString.str());
}
void Context::initVersionStrings()
{
const Version &clientVersion = getClientVersion();
std::ostringstream versionString;
if (getClientType() == EGL_OPENGL_ES_API)
{
versionString << "OpenGL ES ";
}
versionString << clientVersion.major << "." << clientVersion.minor << ".0 (ANGLE "
<< ANGLE_VERSION_STRING << ")";
mVersionString = MakeStaticString(versionString.str());
std::ostringstream shadingLanguageVersionString;
if (getClientType() == EGL_OPENGL_ES_API)
{
shadingLanguageVersionString << "OpenGL ES GLSL ES ";
}
else
{
ASSERT(getClientType() == EGL_OPENGL_API);
shadingLanguageVersionString << "OpenGL GLSL ";
}
shadingLanguageVersionString << (clientVersion.major == 2 ? 1 : clientVersion.major) << "."
<< clientVersion.minor << "0 (ANGLE " << ANGLE_VERSION_STRING
<< ")";
mShadingLanguageString = MakeStaticString(shadingLanguageVersionString.str());
}
void Context::initExtensionStrings()
{
auto mergeExtensionStrings = [](const std::vector<const char *> &strings) {
std::ostringstream combinedStringStream;
std::copy(strings.begin(), strings.end(),
std::ostream_iterator<const char *>(combinedStringStream, " "));
return MakeStaticString(combinedStringStream.str());
};
mExtensionStrings.clear();
for (const auto &extensionString : mState.mExtensions.getStrings())
{
mExtensionStrings.push_back(MakeStaticString(extensionString));
}
mExtensionString = mergeExtensionStrings(mExtensionStrings);
mRequestableExtensionStrings.clear();
for (const auto &extensionInfo : GetExtensionInfoMap())
{
if (extensionInfo.second.Requestable &&
!(mState.mExtensions.*(extensionInfo.second.ExtensionsMember)) &&
mSupportedExtensions.*(extensionInfo.second.ExtensionsMember))
{
mRequestableExtensionStrings.push_back(MakeStaticString(extensionInfo.first));
}
}
mRequestableExtensionString = mergeExtensionStrings(mRequestableExtensionStrings);
}
const GLubyte *Context::getString(GLenum name)
{
return static_cast<const Context *>(this)->getString(name);
}
const GLubyte *Context::getStringi(GLenum name, GLuint index)
{
return static_cast<const Context *>(this)->getStringi(name, index);
}
const GLubyte *Context::getString(GLenum name) const
{
switch (name)
{
case GL_VENDOR:
return reinterpret_cast<const GLubyte *>(mDisplay->getVendorString().c_str());
case GL_RENDERER:
return reinterpret_cast<const GLubyte *>(mRendererString);
case GL_VERSION:
return reinterpret_cast<const GLubyte *>(mVersionString);
case GL_SHADING_LANGUAGE_VERSION:
return reinterpret_cast<const GLubyte *>(mShadingLanguageString);
case GL_EXTENSIONS:
return reinterpret_cast<const GLubyte *>(mExtensionString);
case GL_REQUESTABLE_EXTENSIONS_ANGLE:
return reinterpret_cast<const GLubyte *>(mRequestableExtensionString);
case GL_SERIALIZED_CONTEXT_STRING_ANGLE:
if (angle::SerializeContextToString(this, &mCachedSerializedStateString) ==
angle::Result::Continue)
{
return reinterpret_cast<const GLubyte *>(mCachedSerializedStateString.c_str());
}
else
{
return nullptr;
}
default:
UNREACHABLE();
return nullptr;
}
}
const GLubyte *Context::getStringi(GLenum name, GLuint index) const
{
switch (name)
{
case GL_EXTENSIONS:
return reinterpret_cast<const GLubyte *>(mExtensionStrings[index]);
case GL_REQUESTABLE_EXTENSIONS_ANGLE:
return reinterpret_cast<const GLubyte *>(mRequestableExtensionStrings[index]);
default:
UNREACHABLE();
return nullptr;
}
}
size_t Context::getExtensionStringCount() const
{
return mExtensionStrings.size();
}
bool Context::isExtensionRequestable(const char *name) const
{
const ExtensionInfoMap &extensionInfos = GetExtensionInfoMap();
auto extension = extensionInfos.find(name);
return extension != extensionInfos.end() && extension->second.Requestable &&
mSupportedExtensions.*(extension->second.ExtensionsMember);
}
bool Context::isExtensionDisablable(const char *name) const
{
const ExtensionInfoMap &extensionInfos = GetExtensionInfoMap();
auto extension = extensionInfos.find(name);
return extension != extensionInfos.end() && extension->second.Disablable &&
mSupportedExtensions.*(extension->second.ExtensionsMember);
}
void Context::requestExtension(const char *name)
{
setExtensionEnabled(name, true);
}
void Context::disableExtension(const char *name)
{
setExtensionEnabled(name, false);
}
void Context::setExtensionEnabled(const char *name, bool enabled)
{
if (strcmp(name, "GL_OVR_multiview2") == 0)
{
setExtensionEnabled("GL_OVR_multiview", enabled);
}
const ExtensionInfoMap &extensionInfos = GetExtensionInfoMap();
ASSERT(extensionInfos.find(name) != extensionInfos.end());
const auto &extension = extensionInfos.at(name);
ASSERT(extension.Requestable);
ASSERT(isExtensionRequestable(name));
if (mState.mExtensions.*(extension.ExtensionsMember) == enabled)
{
return;
}
mState.mExtensions.*(extension.ExtensionsMember) = enabled;
reinitializeAfterExtensionsChanged();
}
void Context::reinitializeAfterExtensionsChanged()
{
updateCaps();
initExtensionStrings();
releaseShaderCompiler();
mState.mTextureManager->signalAllTexturesDirty();
for (auto &zeroTexture : mZeroTextures)
{
if (zeroTexture.get() != nullptr)
{
zeroTexture->signalDirtyStorage(InitState::Initialized);
}
}
mState.mFramebufferManager->invalidateFramebufferCompletenessCache();
}
size_t Context::getRequestableExtensionStringCount() const
{
return mRequestableExtensionStrings.size();
}
void Context::beginTransformFeedback(PrimitiveMode primitiveMode)
{
TransformFeedback *transformFeedback = mState.getCurrentTransformFeedback();
ASSERT(transformFeedback != nullptr);
ASSERT(!transformFeedback->isPaused());
ANGLE_CONTEXT_TRY(transformFeedback->begin(this, primitiveMode, mState.getProgram()));
mStateCache.onActiveTransformFeedbackChange(this);
}
bool Context::hasActiveTransformFeedback(ShaderProgramID program) const
{
for (auto pair : mTransformFeedbackMap)
{
if (pair.second != nullptr && pair.second->hasBoundProgram(program))
{
return true;
}
}
return false;
}
Extensions Context::generateSupportedExtensions() const
{
Extensions supportedExtensions = mImplementation->getNativeExtensions();
supportedExtensions.parallelShaderCompile = true;
if (getClientVersion() < ES_2_0)
{
supportedExtensions.pointSizeArrayOES = true;
supportedExtensions.textureCubeMapOES = true;
supportedExtensions.pointSpriteOES = true;
supportedExtensions.drawTextureOES = true;
supportedExtensions.framebufferObjectOES = true;
supportedExtensions.parallelShaderCompile = false;
supportedExtensions.texture3DOES = false;
supportedExtensions.clipDistanceAPPLE = false;
}
if (getClientVersion() < ES_3_0)
{
supportedExtensions.colorBufferFloat = false;
supportedExtensions.eglImageExternalEssl3OES = false;
supportedExtensions.textureNorm16 = false;
supportedExtensions.multiview = false;
supportedExtensions.multiview2 = false;
supportedExtensions.maxViews = 1u;
supportedExtensions.copyTexture3d = false;
supportedExtensions.textureMultisample = false;
supportedExtensions.drawBuffersIndexedEXT = false;
supportedExtensions.drawBuffersIndexedOES = false;
supportedExtensions.eglImageArray = false;
supportedExtensions.textureSRGBOverride = false;
supportedExtensions.textureCompressionASTCOES = false;
if (!supportedExtensions.sRGB)
{
supportedExtensions.textureSRGBDecode = false;
}
if (!(supportedExtensions.textureFloatOES && supportedExtensions.textureHalfFloat))
{
supportedExtensions.textureFloatLinearOES = false;
supportedExtensions.textureHalfFloatLinear = false;
}
supportedExtensions.vertexAttribType1010102OES = false;
supportedExtensions.yuvTargetEXT = false;
supportedExtensions.clipCullDistanceEXT = false;
}
if (getClientVersion() < ES_3_1)
{
supportedExtensions.geometryShaderEXT = false;
supportedExtensions.geometryShaderOES = false;
supportedExtensions.tessellationShaderEXT = false;
supportedExtensions.textureStorageMultisample2DArrayOES = false;
}
if (getClientVersion() > ES_2_0)
{
if (!supportedExtensions.colorBufferFloat && !mWebGLContext)
{
supportedExtensions.colorBufferHalfFloat = false;
}
supportedExtensions.colorBufferFloatRGB = false;
supportedExtensions.colorBufferFloatRGBA = false;
}
if (getFrontendFeatures().disableAnisotropicFiltering.enabled)
{
supportedExtensions.textureFilterAnisotropic = false;
}
supportedExtensions.bindUniformLocation = true;
supportedExtensions.vertexArrayObjectOES = true;
supportedExtensions.bindGeneratesResource = true;
supportedExtensions.clientArrays = true;
supportedExtensions.requestExtension = true;
supportedExtensions.multiDraw = true;
supportedExtensions.noError = mSkipValidation;
supportedExtensions.surfacelessContextOES = mSurfacelessSupported;
supportedExtensions.debug = true;
supportedExtensions.maxDebugMessageLength = 1024;
supportedExtensions.maxDebugLoggedMessages = 1024;
supportedExtensions.maxDebugGroupStackDepth = 1024;
supportedExtensions.maxLabelLength = 1024;
supportedExtensions.debugLabel = true;
supportedExtensions.robustClientMemory = !mSkipValidation;
supportedExtensions.robustResourceInitialization = mState.isRobustResourceInitEnabled();
supportedExtensions.robustBufferAccessBehavior =
mRobustAccess && supportedExtensions.robustBufferAccessBehavior;
supportedExtensions.programCacheControl = true;
ASSERT(mDisplay);
if (!mDisplay->getExtensions().fenceSync)
{
supportedExtensions.eglSyncOES = false;
}
if (mDisplay->getExtensions().robustnessVideoMemoryPurgeNV)
{
supportedExtensions.robustnessVideoMemoryPurgeNV = true;
}
supportedExtensions.memorySize = true;
supportedExtensions.loseContextCHROMIUM = true;
if (supportedExtensions.textureCompressionASTCHDRKHR ||
supportedExtensions.textureCompressionSliced3dASTCKHR)
{
ASSERT(supportedExtensions.textureCompressionASTCLDRKHR);
}
if (supportedExtensions.textureCompressionASTCOES)
{
ASSERT(supportedExtensions.textureCompressionASTCLDRKHR);
ASSERT(supportedExtensions.textureCompressionASTCHDRKHR);
}
if (!mDisplay->getExtensions().protectedContentEXT)
{
supportedExtensions.protectedTexturesEXT = false;
}
supportedExtensions.getTexLevelParameterANGLE = true;
supportedExtensions.getSerializedContextStringANGLE = true;
return supportedExtensions;
}
void Context::initCaps()
{
mState.mCaps = mImplementation->getNativeCaps();
mSupportedExtensions = generateSupportedExtensions();
if (!mDisplay->getFrontendFeatures().allowCompressedFormats.enabled)
{
INFO() << "Limiting compressed format support.\n";
mSupportedExtensions.compressedEACR11SignedTextureOES = false;
mSupportedExtensions.compressedEACR11UnsignedTextureOES = false;
mSupportedExtensions.compressedEACRG11SignedTextureOES = false;
mSupportedExtensions.compressedEACRG11UnsignedTextureOES = false;
mSupportedExtensions.compressedETC1RGB8SubTexture = false;
mSupportedExtensions.compressedETC1RGB8TextureOES = false;
mSupportedExtensions.compressedETC2PunchthroughARGB8TextureOES = false;
mSupportedExtensions.compressedETC2PunchthroughAsRGB8AlphaTextureOES = false;
mSupportedExtensions.compressedETC2RGB8TextureOES = false;
mSupportedExtensions.compressedETC2RGBA8TextureOES = false;
mSupportedExtensions.compressedETC2sRGB8Alpha8TextureOES = false;
mSupportedExtensions.compressedETC2sRGB8TextureOES = false;
mSupportedExtensions.compressedTextureETC = false;
mSupportedExtensions.compressedTexturePVRTC = false;
mSupportedExtensions.compressedTexturePVRTCsRGB = false;
mSupportedExtensions.copyCompressedTexture = false;
mSupportedExtensions.textureCompressionASTCHDRKHR = false;
mSupportedExtensions.textureCompressionASTCLDRKHR = false;
mSupportedExtensions.textureCompressionASTCOES = false;
mSupportedExtensions.textureCompressionBPTC = false;
mSupportedExtensions.textureCompressionDXT1 = false;
mSupportedExtensions.textureCompressionDXT3 = false;
mSupportedExtensions.textureCompressionDXT5 = false;
mSupportedExtensions.textureCompressionRGTC = false;
mSupportedExtensions.textureCompressionS3TCsRGB = false;
mSupportedExtensions.textureCompressionSliced3dASTCKHR = false;
mSupportedExtensions.textureFilteringCHROMIUM = false;
mState.mCaps.compressedTextureFormats.clear();
}
mState.mExtensions = mSupportedExtensions;
mState.mLimitations = mImplementation->getNativeLimitations();
if (getClientType() == EGL_OPENGL_API || getClientVersion() < Version(2, 0))
{
mState.mCaps.maxMultitextureUnits = 4;
mState.mCaps.maxClipPlanes = 6;
mState.mCaps.maxLights = 8;
mState.mCaps.maxModelviewMatrixStackDepth = Caps::GlobalMatrixStackDepth;
mState.mCaps.maxProjectionMatrixStackDepth = Caps::GlobalMatrixStackDepth;
mState.mCaps.maxTextureMatrixStackDepth = Caps::GlobalMatrixStackDepth;
mState.mCaps.minSmoothPointSize = 1.0f;
mState.mCaps.maxSmoothPointSize = 1.0f;
mState.mCaps.minSmoothLineWidth = 1.0f;
mState.mCaps.maxSmoothLineWidth = 1.0f;
}
#if 0
# define ANGLE_LOG_LIMITED_CAP(cap, limit) \
INFO() << "Limiting " << #cap << " to implementation limit " << (limit) << " (was " \
<< (cap) << ")."
#else
# define ANGLE_LOG_LIMITED_CAP(cap, limit)
#endif
#define ANGLE_LIMIT_CAP(cap, limit) \
do \
{ \
if ((cap) > (limit)) \
{ \
ANGLE_LOG_LIMITED_CAP(cap, limit); \
(cap) = (limit); \
} \
} while (0)
ANGLE_LIMIT_CAP(mState.mCaps.maxVertexAttributes, MAX_VERTEX_ATTRIBS);
ANGLE_LIMIT_CAP(mState.mCaps.maxVertexAttribStride,
static_cast<GLint>(limits::kMaxVertexAttribStride));
ASSERT(mState.mCaps.minAliasedPointSize >= 1.0f);
if (getClientVersion() < ES_3_1)
{
mState.mCaps.maxVertexAttribBindings = mState.mCaps.maxVertexAttributes;
}
else
{
ANGLE_LIMIT_CAP(mState.mCaps.maxVertexAttribBindings, MAX_VERTEX_ATTRIB_BINDINGS);
}
ANGLE_LIMIT_CAP(mState.mCaps.max2DTextureSize, IMPLEMENTATION_MAX_2D_TEXTURE_SIZE);
ANGLE_LIMIT_CAP(mState.mCaps.maxCubeMapTextureSize, IMPLEMENTATION_MAX_CUBE_MAP_TEXTURE_SIZE);
ANGLE_LIMIT_CAP(mState.mCaps.max3DTextureSize, IMPLEMENTATION_MAX_3D_TEXTURE_SIZE);
ANGLE_LIMIT_CAP(mState.mCaps.maxArrayTextureLayers, IMPLEMENTATION_MAX_2D_ARRAY_TEXTURE_LAYERS);
ANGLE_LIMIT_CAP(mState.mCaps.maxRectangleTextureSize, IMPLEMENTATION_MAX_2D_TEXTURE_SIZE);
ANGLE_LIMIT_CAP(mState.mCaps.maxShaderUniformBlocks[ShaderType::Vertex],
IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS);
ANGLE_LIMIT_CAP(mState.mCaps.maxShaderUniformBlocks[ShaderType::Geometry],
IMPLEMENTATION_MAX_GEOMETRY_SHADER_UNIFORM_BUFFERS);
ANGLE_LIMIT_CAP(mState.mCaps.maxShaderUniformBlocks[ShaderType::Fragment],
IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS);
ANGLE_LIMIT_CAP(mState.mCaps.maxShaderUniformBlocks[ShaderType::Compute],
IMPLEMENTATION_MAX_COMPUTE_SHADER_UNIFORM_BUFFERS);
ANGLE_LIMIT_CAP(mState.mCaps.maxCombinedUniformBlocks,
IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS);
ANGLE_LIMIT_CAP(mState.mCaps.maxUniformBufferBindings,
IMPLEMENTATION_MAX_UNIFORM_BUFFER_BINDINGS);
ANGLE_LIMIT_CAP(mState.mCaps.maxVertexOutputComponents, IMPLEMENTATION_MAX_VARYING_VECTORS * 4);
ANGLE_LIMIT_CAP(mState.mCaps.maxFragmentInputComponents,
IMPLEMENTATION_MAX_VARYING_VECTORS * 4);
ANGLE_LIMIT_CAP(mState.mCaps.maxTransformFeedbackInterleavedComponents,
IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS);
ANGLE_LIMIT_CAP(mState.mCaps.maxTransformFeedbackSeparateAttributes,
IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS);
ANGLE_LIMIT_CAP(mState.mCaps.maxTransformFeedbackSeparateComponents,
IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS);
if (getClientVersion() < ES_3_2 && !mState.mExtensions.tessellationShaderEXT)
{
ANGLE_LIMIT_CAP(mState.mCaps.maxCombinedTextureImageUnits,
IMPLEMENTATION_MAX_ES31_ACTIVE_TEXTURES);
}
else
{
ANGLE_LIMIT_CAP(mState.mCaps.maxCombinedTextureImageUnits,
IMPLEMENTATION_MAX_ACTIVE_TEXTURES);
}
for (ShaderType shaderType : AllShaderTypes())
{
ANGLE_LIMIT_CAP(mState.mCaps.maxShaderTextureImageUnits[shaderType],
IMPLEMENTATION_MAX_SHADER_TEXTURES);
}
ANGLE_LIMIT_CAP(mState.mCaps.maxImageUnits, IMPLEMENTATION_MAX_IMAGE_UNITS);
ANGLE_LIMIT_CAP(mState.mCaps.maxCombinedImageUniforms, IMPLEMENTATION_MAX_IMAGE_UNITS);
for (ShaderType shaderType : AllShaderTypes())
{
ANGLE_LIMIT_CAP(mState.mCaps.maxShaderImageUniforms[shaderType],
IMPLEMENTATION_MAX_IMAGE_UNITS);
}
for (ShaderType shaderType : AllShaderTypes())
{
ANGLE_LIMIT_CAP(mState.mCaps.maxShaderAtomicCounterBuffers[shaderType],
IMPLEMENTATION_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS);
}
ANGLE_LIMIT_CAP(mState.mCaps.maxAtomicCounterBufferBindings,
IMPLEMENTATION_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS);
ANGLE_LIMIT_CAP(mState.mCaps.maxCombinedAtomicCounterBuffers,
IMPLEMENTATION_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS);
for (ShaderType shaderType : AllShaderTypes())
{
ANGLE_LIMIT_CAP(mState.mCaps.maxShaderStorageBlocks[shaderType],
IMPLEMENTATION_MAX_SHADER_STORAGE_BUFFER_BINDINGS);
}
ANGLE_LIMIT_CAP(mState.mCaps.maxShaderStorageBufferBindings,
IMPLEMENTATION_MAX_SHADER_STORAGE_BUFFER_BINDINGS);
ANGLE_LIMIT_CAP(mState.mCaps.maxCombinedShaderStorageBlocks,
IMPLEMENTATION_MAX_SHADER_STORAGE_BUFFER_BINDINGS);
ANGLE_LIMIT_CAP(mState.mCaps.maxClipDistances, IMPLEMENTATION_MAX_CLIP_DISTANCES);
ANGLE_LIMIT_CAP(mState.mCaps.maxFramebufferLayers, IMPLEMENTATION_MAX_FRAMEBUFFER_LAYERS);
ANGLE_LIMIT_CAP(mState.mCaps.maxSampleMaskWords, MAX_SAMPLE_MASK_WORDS);
ANGLE_LIMIT_CAP(mState.mExtensions.maxViews, IMPLEMENTATION_ANGLE_MULTIVIEW_MAX_VIEWS);
ANGLE_LIMIT_CAP(mState.mExtensions.maxDualSourceDrawBuffers,
IMPLEMENTATION_MAX_DUAL_SOURCE_DRAW_BUFFERS);
mState.mExtensions.webglCompatibility = mWebGLContext;
for (const auto &extensionInfo : GetExtensionInfoMap())
{
if (!mExtensionsEnabled && extensionInfo.second.Requestable)
{
mState.mExtensions.*(extensionInfo.second.ExtensionsMember) = false;
}
}
if (mWebGLContext && getLimitations().emulatedEtc1)
{
mSupportedExtensions.compressedETC1RGB8TextureOES = false;
}
if (getShareGroup()->getFrameCaptureShared()->enabled() ||
getFrontendFeatures().captureLimits.enabled)
{
INFO() << "Limit some features because "
<< (getShareGroup()->getFrameCaptureShared()->enabled()
? "FrameCapture is enabled"
: "FrameCapture limits were forced")
<< std::endl;
if (!getFrontendFeatures().enableProgramBinaryForCapture.enabled)
{
INFO() << "Disabling GL_OES_get_program_binary for trace portability";
mDisplay->overrideFrontendFeatures({"disable_program_binary"}, true);
}
constexpr GLint maxImageUnits = 8;
INFO() << "Limiting image unit count to " << maxImageUnits;
ANGLE_LIMIT_CAP(mState.mCaps.maxImageUnits, maxImageUnits);
constexpr GLint uniformBufferOffsetAlignment = 256;
ASSERT(uniformBufferOffsetAlignment % mState.mCaps.uniformBufferOffsetAlignment == 0);
INFO() << "Setting uniform buffer offset alignment to " << uniformBufferOffsetAlignment;
mState.mCaps.uniformBufferOffsetAlignment = uniformBufferOffsetAlignment;
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.mapBufferRange = false;
mState.mExtensions.mapBufferOES = false;
INFO() << "Disabling GL_CHROMIUM_bind_uniform_location during capture, which is not "
"supported on native drivers";
mState.mExtensions.bindUniformLocation = false;
INFO() << "Disabling GL_NV_shader_noperspective_interpolation during capture, which is not "
"supported on some native drivers";
mState.mExtensions.noperspectiveInterpolationNV = false;
constexpr GLint maxDrawBuffers = 4;
INFO() << "Limiting draw buffer count to " << maxDrawBuffers;
ANGLE_LIMIT_CAP(mState.mCaps.maxDrawBuffers, maxDrawBuffers);
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.noError = mSkipValidation;
mState.mExtensions.robustClientMemory = !mSkipValidation;
INFO() << "Disabling GL_OES_depth32 during capture, which is not widely supported on "
"mobile";
mState.mExtensions.depth32OES = false;
}
if (mDisplay->getFrontendFeatures().disableProgramBinary.enabled)
{
mState.mExtensions.getProgramBinaryOES = false;
mState.mCaps.shaderBinaryFormats.clear();
mState.mCaps.programBinaryFormats.clear();
mMemoryProgramCache = nullptr;
}
#undef ANGLE_LIMIT_CAP
#undef ANGLE_LOG_CAP_LIMIT
updateCaps();
}
void Context::updateCaps()
{
mState.mCaps.compressedTextureFormats.clear();
mState.mTextureCaps.clear();
for (GLenum sizedInternalFormat : GetAllSizedInternalFormats())
{
TextureCaps formatCaps = mImplementation->getNativeTextureCaps().get(sizedInternalFormat);
const InternalFormat &formatInfo = GetSizedInternalFormatInfo(sizedInternalFormat);
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);
if (!formatCaps.renderbuffer ||
(getClientVersion() < ES_3_1 && !mSupportedExtensions.textureMultisample &&
formatInfo.isInt()))
{
formatCaps.sampleCounts.clear();
}
else
{
GLuint formatMaxSamples = formatCaps.getMaxSamples();
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);
}
if (getClientVersion() >= ES_3_1 || mSupportedExtensions.textureMultisample)
{
if (formatInfo.isInt())
{
mState.mCaps.maxIntegerSamples = std::min(
static_cast<GLuint>(mState.mCaps.maxIntegerSamples), formatMaxSamples);
}
if (formatCaps.texturable)
{
if (formatInfo.depthBits > 0)
{
mState.mCaps.maxDepthTextureSamples =
std::min(static_cast<GLuint>(mState.mCaps.maxDepthTextureSamples),
formatMaxSamples);
}
else if (formatInfo.redBits > 0)
{
mState.mCaps.maxColorTextureSamples =
std::min(static_cast<GLuint>(mState.mCaps.maxColorTextureSamples),
formatMaxSamples);
}
}
}
}
if (formatCaps.texturable && formatInfo.compressed)
{
mState.mCaps.compressedTextureFormats.push_back(sizedInternalFormat);
}
mState.mTextureCaps.insert(sizedInternalFormat, formatCaps);
}
if (!mSupportedExtensions.getProgramBinaryOES)
{
mMemoryProgramCache = nullptr;
}
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);
}
mThreadPool = angle::WorkerThreadPool::Create(
mState.mExtensions.parallelShaderCompile ||
getFrontendFeatures().enableCompressingPipelineCacheInThreadPool.enabled);
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);
}
mBufferAccessValidationEnabled =
(!mSupportedExtensions.robustBufferAccessBehavior && (mState.isWebGL() || mRobustAccess));
for (auto vaoIter : mVertexArrayMap)
{
VertexArray *vao = vaoIter.second;
vao->setBufferAccessValidationEnabled(mBufferAccessValidationEnabled);
}
mStateCache.initialize(this);
}
bool Context::noopDrawInstanced(PrimitiveMode mode, GLsizei count, GLsizei instanceCount) const
{
return (instanceCount == 0) || noopDraw(mode, count);
}
angle::Result Context::prepareForClear(GLbitfield mask)
{
ANGLE_TRY(mState.getDrawFramebuffer()->ensureClearAttachmentsInitialized(this, mask));
return syncStateForClear();
}
angle::Result Context::prepareForClearBuffer(GLenum buffer, GLint drawbuffer)
{
ANGLE_TRY(mState.getDrawFramebuffer()->ensureClearBufferAttachmentsInitialized(this, buffer,
drawbuffer));
return syncStateForClear();
}
ANGLE_INLINE angle::Result Context::prepareForCopyImage()
{
ANGLE_TRY(syncDirtyObjects(mCopyImageDirtyObjects, Command::CopyImage));
return syncDirtyBits(mCopyImageDirtyBits);
}
ANGLE_INLINE angle::Result Context::prepareForDispatch()
{
convertPpoToComputeOrDraw(true);
Program *program = mState.getProgram();
ProgramPipeline *pipeline = mState.getProgramPipeline();
if (!program && pipeline)
{
bool goodResult = pipeline->link(this) == angle::Result::Continue;
ANGLE_CHECK(this, goodResult, "Program pipeline link failed", GL_INVALID_OPERATION);
}
ANGLE_TRY(syncDirtyObjects(mComputeDirtyObjects, Command::Dispatch));
return syncDirtyBits(mComputeDirtyBits);
}
angle::Result Context::syncState(const State::DirtyBits &bitMask,
const State::DirtyObjects &objectMask,
Command command)
{
ANGLE_TRY(syncDirtyObjects(objectMask, command));
ANGLE_TRY(syncDirtyBits(bitMask));
return angle::Result::Continue;
}
void Context::blitFramebuffer(GLint srcX0,
GLint srcY0,
GLint srcX1,
GLint srcY1,
GLint dstX0,
GLint dstY0,
GLint dstX1,
GLint dstY1,
GLbitfield mask,
GLenum filter)
{
if (mask == 0)
{
return;
}
Framebuffer *drawFramebuffer = mState.getDrawFramebuffer();
ASSERT(drawFramebuffer);
if ((mask & GL_COLOR_BUFFER_BIT) && !drawFramebuffer->hasEnabledDrawBuffer())
{
mask &= ~GL_COLOR_BUFFER_BIT;
}
if ((mask & GL_STENCIL_BUFFER_BIT) &&
drawFramebuffer->getState().getStencilAttachment() == nullptr)
{
mask &= ~GL_STENCIL_BUFFER_BIT;
}
if ((mask & GL_DEPTH_BUFFER_BIT) && drawFramebuffer->getState().getDepthAttachment() == nullptr)
{
mask &= ~GL_DEPTH_BUFFER_BIT;
}
if (mask == 0)
{
ANGLE_PERF_WARNING(mState.getDebug(), GL_DEBUG_SEVERITY_LOW,
"BlitFramebuffer called for non-existing buffers");
return;
}
Rectangle srcArea(srcX0, srcY0, srcX1 - srcX0, srcY1 - srcY0);
Rectangle dstArea(dstX0, dstY0, dstX1 - dstX0, dstY1 - dstY0);
if (dstArea.width == 0 || dstArea.height == 0)
{
return;
}
ANGLE_CONTEXT_TRY(syncStateForBlit());
ANGLE_CONTEXT_TRY(drawFramebuffer->blit(this, srcArea, dstArea, mask, filter));
}
void Context::blitFramebufferNV(GLint srcX0,
GLint srcY0,
GLint srcX1,
GLint srcY1,
GLint dstX0,
GLint dstY0,
GLint dstX1,
GLint dstY1,
GLbitfield mask,
GLenum filter)
{
blitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
}
void Context::clear(GLbitfield mask)
{
if (mState.isRasterizerDiscardEnabled())
{
return;
}
if (IsEmptyScissor(mState))
{
return;
}
if (mState.allActiveDrawBufferChannelsMasked())
{
mask &= ~GL_COLOR_BUFFER_BIT;
}
if (mState.getDrawFramebuffer()->getDepthAttachment() == nullptr ||
!mState.getDepthStencilState().depthMask)
{
mask &= ~GL_DEPTH_BUFFER_BIT;
}
if (mState.getDrawFramebuffer()->getStencilAttachment() == nullptr ||
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;
}
ANGLE_CONTEXT_TRY(prepareForClear(mask));
ANGLE_CONTEXT_TRY(mState.getDrawFramebuffer()->clear(this, mask));
}
bool Context::isClearBufferMaskedOut(GLenum buffer, GLint drawbuffer) const
{
switch (buffer)
{
case GL_COLOR:
return IsColorMaskedOut(mState.getBlendStateExt(), drawbuffer);
case GL_DEPTH:
return mState.getDepthStencilState().isDepthMaskedOut();
case GL_STENCIL:
return mState.getDepthStencilState().isStencilMaskedOut();
case GL_DEPTH_STENCIL:
return mState.getDepthStencilState().isDepthMaskedOut() &&
mState.getDepthStencilState().isStencilMaskedOut();
default:
UNREACHABLE();
return true;
}
}
bool Context::noopClearBuffer(GLenum buffer, GLint drawbuffer) const
{
Framebuffer *framebufferObject = mState.getDrawFramebuffer();
return !IsClearBufferEnabled(framebufferObject->getState(), buffer, drawbuffer) ||
mState.isRasterizerDiscardEnabled() || isClearBufferMaskedOut(buffer, drawbuffer) ||
IsEmptyScissor(mState);
}
void Context::clearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat *values)
{
if (noopClearBuffer(buffer, drawbuffer))
{
return;
}
Framebuffer *framebufferObject = mState.getDrawFramebuffer();
const FramebufferAttachment *attachment = nullptr;
if (buffer == GL_DEPTH)
{
attachment = framebufferObject->getDepthAttachment();
}
else if (buffer == GL_COLOR &&
static_cast<size_t>(drawbuffer) < framebufferObject->getNumColorAttachments())
{
attachment = framebufferObject->getColorAttachment(drawbuffer);
}
if (!attachment)
{
return;
}
ANGLE_CONTEXT_TRY(prepareForClearBuffer(buffer, drawbuffer));
ANGLE_CONTEXT_TRY(framebufferObject->clearBufferfv(this, buffer, drawbuffer, values));
}
void Context::clearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint *values)
{
if (noopClearBuffer(buffer, drawbuffer))
{
return;
}
Framebuffer *framebufferObject = mState.getDrawFramebuffer();
const FramebufferAttachment *attachment = nullptr;
if (buffer == GL_COLOR &&
static_cast<size_t>(drawbuffer) < framebufferObject->getNumColorAttachments())
{
attachment = framebufferObject->getColorAttachment(drawbuffer);
}
if (!attachment)
{
return;
}
ANGLE_CONTEXT_TRY(prepareForClearBuffer(buffer, drawbuffer));
ANGLE_CONTEXT_TRY(framebufferObject->clearBufferuiv(this, buffer, drawbuffer, values));
}
void Context::clearBufferiv(GLenum buffer, GLint drawbuffer, const GLint *values)
{
if (noopClearBuffer(buffer, drawbuffer))
{
return;
}
Framebuffer *framebufferObject = mState.getDrawFramebuffer();
const FramebufferAttachment *attachment = nullptr;
if (buffer == GL_STENCIL)
{
attachment = framebufferObject->getStencilAttachment();
}
else if (buffer == GL_COLOR &&
static_cast<size_t>(drawbuffer) < framebufferObject->getNumColorAttachments())
{
attachment = framebufferObject->getColorAttachment(drawbuffer);
}
if (!attachment)
{
return;
}
ANGLE_CONTEXT_TRY(prepareForClearBuffer(buffer, drawbuffer));
ANGLE_CONTEXT_TRY(framebufferObject->clearBufferiv(this, buffer, drawbuffer, values));
}
void Context::clearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil)
{
if (noopClearBuffer(buffer, drawbuffer))
{
return;
}
Framebuffer *framebufferObject = mState.getDrawFramebuffer();
ASSERT(framebufferObject);
if (framebufferObject->getDepthAttachment() == nullptr &&
framebufferObject->getStencilAttachment() == nullptr)
{
return;
}
ANGLE_CONTEXT_TRY(prepareForClearBuffer(buffer, drawbuffer));
ANGLE_CONTEXT_TRY(framebufferObject->clearBufferfi(this, buffer, drawbuffer, depth, stencil));
}
void Context::readPixels(GLint x,
GLint y,
GLsizei width,
GLsizei height,
GLenum format,
GLenum type,
void *pixels)
{
if (width == 0 || height == 0)
{
return;
}
ANGLE_CONTEXT_TRY(syncStateForReadPixels());
Framebuffer *readFBO = mState.getReadFramebuffer();
ASSERT(readFBO);
Rectangle area(x, y, width, height);
PixelPackState packState = mState.getPackState();
Buffer *packBuffer = mState.getTargetBuffer(gl::BufferBinding::PixelPack);
ANGLE_CONTEXT_TRY(readFBO->readPixels(this, area, format, type, packState, packBuffer, pixels));
}
void Context::readPixelsRobust(GLint x,
GLint y,
GLsizei width,
GLsizei height,
GLenum format,
GLenum type,
GLsizei bufSize,
GLsizei *length,
GLsizei *columns,
GLsizei *rows,
void *pixels)
{
readPixels(x, y, width, height, format, type, pixels);
}
void Context::readnPixelsRobust(GLint x,
GLint y,
GLsizei width,
GLsizei height,
GLenum format,
GLenum type,
GLsizei bufSize,
GLsizei *length,
GLsizei *columns,
GLsizei *rows,
void *data)
{
readPixels(x, y, width, height, format, type, data);
}
void Context::copyTexImage2D(TextureTarget target,
GLint level,
GLenum internalformat,
GLint x,
GLint y,
GLsizei width,
GLsizei height,
GLint border)
{
ANGLE_CONTEXT_TRY(prepareForCopyImage());
Rectangle sourceArea(x, y, width, height);
Framebuffer *framebuffer = mState.getReadFramebuffer();
Texture *texture = getTextureByTarget(target);
ANGLE_CONTEXT_TRY(
texture->copyImage(this, target, level, sourceArea, internalformat, framebuffer));
}
void Context::copyTexSubImage2D(TextureTarget target,
GLint level,
GLint xoffset,
GLint yoffset,
GLint x,
GLint y,
GLsizei width,
GLsizei height)
{
if (width == 0 || height == 0)
{
return;
}
ANGLE_CONTEXT_TRY(prepareForCopyImage());
Offset destOffset(xoffset, yoffset, 0);
Rectangle sourceArea(x, y, width, height);
ImageIndex index = ImageIndex::MakeFromTarget(target, level, 1);
Framebuffer *framebuffer = mState.getReadFramebuffer();
Texture *texture = getTextureByTarget(target);
ANGLE_CONTEXT_TRY(texture->copySubImage(this, index, destOffset, sourceArea, framebuffer));
}
void Context::copyTexSubImage3D(TextureTarget target,
GLint level,
GLint xoffset,
GLint yoffset,
GLint zoffset,
GLint x,
GLint y,
GLsizei width,
GLsizei height)
{
if (width == 0 || height == 0)
{
return;
}
ANGLE_CONTEXT_TRY(prepareForCopyImage());
Offset destOffset(xoffset, yoffset, zoffset);
Rectangle sourceArea(x, y, width, height);
ImageIndex index = ImageIndex::MakeFromType(TextureTargetToType(target), level, zoffset);
Framebuffer *framebuffer = mState.getReadFramebuffer();
Texture *texture = getTextureByTarget(target);
ANGLE_CONTEXT_TRY(texture->copySubImage(this, index, destOffset, sourceArea, framebuffer));
}
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 ((srcWidth == 0) || (srcHeight == 0) || (srcDepth == 0))
{
return;
}
if (srcTarget == GL_RENDERBUFFER)
{
Renderbuffer *readBuffer = getRenderbuffer(PackParam<RenderbufferID>(srcName));
if (dstTarget == GL_RENDERBUFFER)
{
Renderbuffer *writeBuffer = getRenderbuffer(PackParam<RenderbufferID>(dstName));
ANGLE_CONTEXT_TRY(writeBuffer->copyRenderbufferSubData(
this, readBuffer, srcLevel, srcX, srcY, srcZ, dstLevel, dstX, dstY, dstZ, srcWidth,
srcHeight, srcDepth));
}
else
{
ASSERT(dstTarget == GL_TEXTURE_2D || dstTarget == GL_TEXTURE_2D_ARRAY ||
dstTarget == GL_TEXTURE_3D || dstTarget == GL_TEXTURE_CUBE_MAP);
Texture *writeTexture = getTexture(PackParam<TextureID>(dstName));
ANGLE_CONTEXT_TRY(syncTextureForCopy(writeTexture));
ANGLE_CONTEXT_TRY(writeTexture->copyRenderbufferSubData(
this, readBuffer, srcLevel, srcX, srcY, srcZ, dstLevel, dstX, dstY, dstZ, srcWidth,
srcHeight, srcDepth));
}
}
else
{
ASSERT(srcTarget == GL_TEXTURE_2D || srcTarget == GL_TEXTURE_2D_ARRAY ||
srcTarget == GL_TEXTURE_3D || srcTarget == GL_TEXTURE_CUBE_MAP);
Texture *readTexture = getTexture(PackParam<TextureID>(srcName));
ANGLE_CONTEXT_TRY(syncTextureForCopy(readTexture));
if (dstTarget == GL_RENDERBUFFER)
{
Renderbuffer *writeBuffer = getRenderbuffer(PackParam<RenderbufferID>(dstName));
ANGLE_CONTEXT_TRY(writeBuffer->copyTextureSubData(this, readTexture, srcLevel, srcX,
srcY, srcZ, dstLevel, dstX, dstY,
dstZ, srcWidth, srcHeight, srcDepth));
}
else
{
ASSERT(dstTarget == GL_TEXTURE_2D || dstTarget == GL_TEXTURE_2D_ARRAY ||
dstTarget == GL_TEXTURE_3D || dstTarget == GL_TEXTURE_CUBE_MAP);
Texture *writeTexture = getTexture(PackParam<TextureID>(dstName));
ANGLE_CONTEXT_TRY(syncTextureForCopy(writeTexture));
ANGLE_CONTEXT_TRY(writeTexture->copyTextureSubData(
this, readTexture, srcLevel, srcX, srcY, srcZ, dstLevel, dstX, dstY, dstZ, srcWidth,
srcHeight, srcDepth));
}
}
}
void Context::framebufferTexture2D(GLenum target,
GLenum attachment,
TextureTarget textarget,
TextureID texture,
GLint level)
{
Framebuffer *framebuffer = mState.getTargetFramebuffer(target);
ASSERT(framebuffer);
if (texture.value != 0)
{
Texture *textureObj = getTexture(texture);
ImageIndex index = ImageIndex::MakeFromTarget(textarget, level, 1);
framebuffer->setAttachment(this, GL_TEXTURE, attachment, index, textureObj);
}
else
{
framebuffer->resetAttachment(this, attachment);
}
mState.setObjectDirty(target);
}
void Context::framebufferTexture3D(GLenum target,
GLenum attachment,
TextureTarget textargetPacked,
TextureID texture,
GLint level,
GLint zoffset)
{
Framebuffer *framebuffer = mState.getTargetFramebuffer(target);
ASSERT(framebuffer);
if (texture.value != 0)
{
Texture *textureObj = getTexture(texture);
ImageIndex index = ImageIndex::Make3D(level, zoffset);
framebuffer->setAttachment(this, GL_TEXTURE, attachment, index, textureObj);
}
else
{
framebuffer->resetAttachment(this, attachment);
}
mState.setObjectDirty(target);
}
void Context::framebufferRenderbuffer(GLenum target,
GLenum attachment,
GLenum renderbuffertarget,
RenderbufferID renderbuffer)
{
Framebuffer *framebuffer = mState.getTargetFramebuffer(target);
ASSERT(framebuffer);
if (renderbuffer.value != 0)
{
Renderbuffer *renderbufferObject = getRenderbuffer(renderbuffer);
GLsizei rbSamples = renderbufferObject->getState().getSamples();
framebuffer->setAttachmentMultisample(this, GL_RENDERBUFFER, attachment, gl::ImageIndex(),
renderbufferObject, rbSamples);
}
else
{
framebuffer->resetAttachment(this, attachment);
}
mState.setObjectDirty(target);
}
void Context::framebufferTextureLayer(GLenum target,
GLenum attachment,
TextureID texture,
GLint level,
GLint layer)
{
Framebuffer *framebuffer = mState.getTargetFramebuffer(target);
ASSERT(framebuffer);
if (texture.value != 0)
{
Texture *textureObject = getTexture(texture);
ImageIndex index = ImageIndex::MakeFromType(textureObject->getType(), level, layer);
framebuffer->setAttachment(this, GL_TEXTURE, attachment, index, textureObject);
}
else
{
framebuffer->resetAttachment(this, attachment);
}
mState.setObjectDirty(target);
}
void Context::framebufferTextureMultiview(GLenum target,
GLenum attachment,
TextureID texture,
GLint level,
GLint baseViewIndex,
GLsizei numViews)
{
Framebuffer *framebuffer = mState.getTargetFramebuffer(target);
ASSERT(framebuffer);
if (texture.value != 0)
{
Texture *textureObj = getTexture(texture);
ImageIndex index;
if (textureObj->getType() == TextureType::_2DArray)
{
index = ImageIndex::Make2DArrayRange(level, baseViewIndex, numViews);
}
else
{
ASSERT(textureObj->getType() == TextureType::_2DMultisampleArray);
ASSERT(level == 0);
index = ImageIndex::Make2DMultisampleArrayRange(baseViewIndex, numViews);
}
framebuffer->setAttachmentMultiview(this, GL_TEXTURE, attachment, index, textureObj,
numViews, baseViewIndex);
}
else
{
framebuffer->resetAttachment(this, attachment);
}
mState.setObjectDirty(target);
}
void Context::framebufferTexture(GLenum target, GLenum attachment, TextureID texture, GLint level)
{
Framebuffer *framebuffer = mState.getTargetFramebuffer(target);
ASSERT(framebuffer);
if (texture.value != 0)
{
Texture *textureObj = getTexture(texture);
ImageIndex index = ImageIndex::MakeFromType(
textureObj->getType(), level, ImageIndex::kEntireLevel, ImageIndex::kEntireLevel);
framebuffer->setAttachment(this, GL_TEXTURE, attachment, index, textureObj);
}
else
{
framebuffer->resetAttachment(this, attachment);
}
mState.setObjectDirty(target);
}
void Context::drawBuffers(GLsizei n, const GLenum *bufs)
{
Framebuffer *framebuffer = mState.getDrawFramebuffer();
ASSERT(framebuffer);
framebuffer->setDrawBuffers(n, bufs);
mState.setDrawFramebufferDirty();
mStateCache.onDrawFramebufferChange(this);
}
void Context::readBuffer(GLenum mode)
{
Framebuffer *readFBO = mState.getReadFramebuffer();
readFBO->setReadBuffer(mode);
mState.setObjectDirty(GL_READ_FRAMEBUFFER);
}
void Context::discardFramebuffer(GLenum target, GLsizei numAttachments, const GLenum *attachments)
{
ANGLE_CONTEXT_TRY(mState.syncDirtyObject(this, target));
Framebuffer *framebuffer = mState.getTargetFramebuffer(target);
ASSERT(framebuffer);
ANGLE_CONTEXT_TRY(framebuffer->discard(this, numAttachments, attachments));
}
void Context::invalidateFramebuffer(GLenum target,
GLsizei numAttachments,
const GLenum *attachments)
{
Framebuffer *framebuffer = mState.getTargetFramebuffer(target);
ASSERT(framebuffer);
if (!framebuffer->isComplete(this))
{
return;
}
ANGLE_CONTEXT_TRY(mState.syncDirtyObject(this, target));
ANGLE_CONTEXT_TRY(framebuffer->invalidate(this, numAttachments, attachments));
}
void Context::invalidateSubFramebuffer(GLenum target,
GLsizei numAttachments,
const GLenum *attachments,
GLint x,
GLint y,
GLsizei width,
GLsizei height)
{
Framebuffer *framebuffer = mState.getTargetFramebuffer(target);
ASSERT(framebuffer);
if (!framebuffer->isComplete(this))
{
return;
}
Rectangle area(x, y, width, height);
ANGLE_CONTEXT_TRY(mState.syncDirtyObject(this, target));
ANGLE_CONTEXT_TRY(framebuffer->invalidateSub(this, numAttachments, attachments, area));
}
void Context::texImage2D(TextureTarget target,
GLint level,
GLint internalformat,
GLsizei width,
GLsizei height,
GLint border,
GLenum format,
GLenum type,
const void *pixels)
{
ANGLE_CONTEXT_TRY(syncStateForTexImage());
gl::Buffer *unpackBuffer = mState.getTargetBuffer(gl::BufferBinding::PixelUnpack);
Extents size(width, height, 1);
Texture *texture = getTextureByTarget(target);
ANGLE_CONTEXT_TRY(texture->setImage(this, mState.getUnpackState(), unpackBuffer, target, level,
internalformat, size, format, type,
static_cast<const uint8_t *>(pixels)));
}
void Context::texImage2DRobust(TextureTarget target,
GLint level,
GLint internalformat,
GLsizei width,
GLsizei height,
GLint border,
GLenum format,
GLenum type,
GLsizei bufSize,
const void *pixels)
{
texImage2D(target, level, internalformat, width, height, border, format, type, pixels);
}
void Context::texImage3D(TextureTarget target,
GLint level,
GLint internalformat,
GLsizei width,
GLsizei height,
GLsizei depth,
GLint border,
GLenum format,
GLenum type,
const void *pixels)
{
ANGLE_CONTEXT_TRY(syncStateForTexImage());
gl::Buffer *unpackBuffer = mState.getTargetBuffer(gl::BufferBinding::PixelUnpack);
Extents size(width, height, depth);
Texture *texture = getTextureByTarget(target);
ANGLE_CONTEXT_TRY(texture->setImage(this, mState.getUnpackState(), unpackBuffer, target, level,
internalformat, size, format, type,
static_cast<const uint8_t *>(pixels)));
}
void Context::texImage3DRobust(TextureTarget target,
GLint level,
GLint internalformat,
GLsizei width,
GLsizei height,
GLsizei depth,
GLint border,
GLenum format,
GLenum type,
GLsizei bufSize,
const void *pixels)
{
texImage3D(target, level, internalformat, width, height, depth, border, format, type, pixels);
}
void Context::texSubImage2D(TextureTarget target,
GLint level,
GLint xoffset,
GLint yoffset,
GLsizei width,
GLsizei height,
GLenum format,
GLenum type,
const void *pixels)
{
if (width == 0 || height == 0)
{
return;
}
ANGLE_CONTEXT_TRY(syncStateForTexImage());
Box area(xoffset, yoffset, 0, width, height, 1);
Texture *texture = getTextureByTarget(target);
gl::Buffer *unpackBuffer = mState.getTargetBuffer(gl::BufferBinding::PixelUnpack);
ANGLE_CONTEXT_TRY(texture->setSubImage(this, mState.getUnpackState(), unpackBuffer, target,
level, area, format, type,
static_cast<const uint8_t *>(pixels)));
}
void Context::texSubImage2DRobust(TextureTarget target,
GLint level,
GLint xoffset,
GLint yoffset,
GLsizei width,
GLsizei height,
GLenum format,
GLenum type,
GLsizei bufSize,
const void *pixels)
{
texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels);
}
void Context::texSubImage3D(TextureTarget target,
GLint level,
GLint xoffset,
GLint yoffset,
GLint zoffset,
GLsizei width,
GLsizei height,
GLsizei depth,
GLenum format,
GLenum type,
const void *pixels)
{
if (width == 0 || height == 0 || depth == 0)
{
return;
}
ANGLE_CONTEXT_TRY(syncStateForTexImage());
Box area(xoffset, yoffset, zoffset, width, height, depth);
Texture *texture = getTextureByTarget(target);
gl::Buffer *unpackBuffer = mState.getTargetBuffer(gl::BufferBinding::PixelUnpack);
ANGLE_CONTEXT_TRY(texture->setSubImage(this, mState.getUnpackState(), unpackBuffer, target,
level, area, format, type,
static_cast<const uint8_t *>(pixels)));
}
void Context::texSubImage3DRobust(TextureTarget target,
GLint level,
GLint xoffset,
GLint yoffset,
GLint zoffset,
GLsizei width,
GLsizei height,
GLsizei depth,
GLenum format,
GLenum type,
GLsizei bufSize,
const void *pixels)
{
texSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type,
pixels);
}
void Context::compressedTexImage2D(TextureTarget target,
GLint level,
GLenum internalformat,
GLsizei width,
GLsizei height,
GLint border,
GLsizei imageSize,
const void *data)
{
ANGLE_CONTEXT_TRY(syncStateForTexImage());
Extents size(width, height, 1);
Texture *texture = getTextureByTarget(target);
ANGLE_CONTEXT_TRY(texture->setCompressedImage(this, mState.getUnpackState(), target, level,
internalformat, size, imageSize,
static_cast<const uint8_t *>(data)));
}
void Context::compressedTexImage2DRobust(TextureTarget target,
GLint level,
GLenum internalformat,
GLsizei width,
GLsizei height,
GLint border,
GLsizei imageSize,
GLsizei dataSize,
const GLvoid *data)
{
compressedTexImage2D(target, level, internalformat, width, height, border, imageSize, data);
}
void Context::compressedTexImage3D(TextureTarget target,
GLint level,
GLenum internalformat,
GLsizei width,
GLsizei height,
GLsizei depth,
GLint border,
GLsizei imageSize,
const void *data)
{
ANGLE_CONTEXT_TRY(syncStateForTexImage());
Extents size(width, height, depth);
Texture *texture = getTextureByTarget(target);
ANGLE_CONTEXT_TRY(texture->setCompressedImage(this, mState.getUnpackState(), target, level,
internalformat, size, imageSize,
static_cast<const uint8_t *>(data)));
}
void Context::compressedTexImage3DRobust(TextureTarget target,
GLint level,
GLenum internalformat,
GLsizei width,
GLsizei height,
GLsizei depth,
GLint border,
GLsizei imageSize,
GLsizei dataSize,
const GLvoid *data)
{
compressedTexImage3D(target, level, internalformat, width, height, depth, border, imageSize,
data);
}
void Context::compressedTexSubImage2D(TextureTarget target,
GLint level,
GLint xoffset,
GLint yoffset,
GLsizei width,
GLsizei height,
GLenum format,
GLsizei imageSize,
const void *data)
{
ANGLE_CONTEXT_TRY(syncStateForTexImage());
Box area(xoffset, yoffset, 0, width, height, 1);
Texture *texture = getTextureByTarget(target);
ANGLE_CONTEXT_TRY(texture->setCompressedSubImage(this, mState.getUnpackState(), target, level,
area, format, imageSize,
static_cast<const uint8_t *>(data)));
}
void Context::compressedTexSubImage2DRobust(TextureTarget target,
GLint level,
GLint xoffset,
GLint yoffset,
GLsizei width,
GLsizei height,
GLenum format,
GLsizei imageSize,
GLsizei dataSize,
const GLvoid *data)
{
compressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, imageSize,
data);
}
void Context::compressedTexSubImage3D(TextureTarget target,
GLint level,
GLint xoffset,
GLint yoffset,
GLint zoffset,
GLsizei width,
GLsizei height,
GLsizei depth,
GLenum format,
GLsizei imageSize,
const void *data)
{
if (width == 0 || height == 0)
{
return;
}
ANGLE_CONTEXT_TRY(syncStateForTexImage());
Box area(xoffset, yoffset, zoffset, width, height, depth);
Texture *texture = getTextureByTarget(target);
ANGLE_CONTEXT_TRY(texture->setCompressedSubImage(this, mState.getUnpackState(), target, level,
area, format, imageSize,
static_cast<const uint8_t *>(data)));
}
void Context::compressedTexSubImage3DRobust(TextureTarget target,
GLint level,
GLint xoffset,
GLint yoffset,
GLint zoffset,
GLsizei width,
GLsizei height,
GLsizei depth,
GLenum format,
GLsizei imageSize,
GLsizei dataSize,
const GLvoid *data)
{
compressedTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format,
imageSize, data);
}
void Context::generateMipmap(TextureType target)
{
Texture *texture = getTextureByType(target);
ANGLE_CONTEXT_TRY(texture->generateMipmap(this));
}
void Context::copyTexture(TextureID sourceId,
GLint sourceLevel,
TextureTarget destTarget,
TextureID destId,
GLint destLevel,
GLint internalFormat,
GLenum destType,
GLboolean unpackFlipY,
GLboolean unpackPremultiplyAlpha,
GLboolean unpackUnmultiplyAlpha)
{
ANGLE_CONTEXT_TRY(syncStateForTexImage());
gl::Texture *sourceTexture = getTexture(sourceId);
gl::Texture *destTexture = getTexture(destId);
ANGLE_CONTEXT_TRY(
destTexture->copyTexture(this, destTarget, destLevel, internalFormat, destType, sourceLevel,
ConvertToBool(unpackFlipY), ConvertToBool(unpackPremultiplyAlpha),
ConvertToBool(unpackUnmultiplyAlpha), sourceTexture));
}
void Context::copySubTexture(TextureID sourceId,
GLint sourceLevel,
TextureTarget destTarget,
TextureID destId,
GLint destLevel,
GLint xoffset,
GLint yoffset,
GLint x,
GLint y,
GLsizei width,
GLsizei height,
GLboolean unpackFlipY,
GLboolean unpackPremultiplyAlpha,
GLboolean unpackUnmultiplyAlpha)
{
if (width == 0 || height == 0)
{
return;
}
ANGLE_CONTEXT_TRY(syncStateForTexImage());
gl::Texture *sourceTexture = getTexture(sourceId);
gl::Texture *destTexture = getTexture(destId);
Offset offset(xoffset, yoffset, 0);
Box box(x, y, 0, width, height, 1);
ANGLE_CONTEXT_TRY(destTexture->copySubTexture(
this, destTarget, destLevel, offset, sourceLevel, box, ConvertToBool(unpackFlipY),
ConvertToBool(unpackPremultiplyAlpha), ConvertToBool(unpackUnmultiplyAlpha),
sourceTexture));
}
void Context::copyTexture3D(TextureID sourceId,
GLint sourceLevel,
TextureTarget destTarget,
TextureID destId,
GLint destLevel,
GLint internalFormat,
GLenum destType,
GLboolean unpackFlipY,
GLboolean unpackPremultiplyAlpha,
GLboolean unpackUnmultiplyAlpha)
{
ANGLE_CONTEXT_TRY(syncStateForTexImage());
Texture *sourceTexture = getTexture(sourceId);
Texture *destTexture = getTexture(destId);
ANGLE_CONTEXT_TRY(
destTexture->copyTexture(this, destTarget, destLevel, internalFormat, destType, sourceLevel,
ConvertToBool(unpackFlipY), ConvertToBool(unpackPremultiplyAlpha),
ConvertToBool(unpackUnmultiplyAlpha), sourceTexture));
}
void Context::copySubTexture3D(TextureID sourceId,
GLint sourceLevel,
TextureTarget destTarget,
TextureID destId,
GLint destLevel,
GLint xoffset,
GLint yoffset,
GLint zoffset,
GLint x,
GLint y,
GLint z,
GLsizei width,
GLsizei height,
GLsizei depth,
GLboolean unpackFlipY,
GLboolean unpackPremultiplyAlpha,
GLboolean unpackUnmultiplyAlpha)
{
if (width == 0 || height == 0 || depth == 0)
{
return;
}
ANGLE_CONTEXT_TRY(syncStateForTexImage());
Texture *sourceTexture = getTexture(sourceId);
Texture *destTexture = getTexture(destId);
Offset offset(xoffset, yoffset, zoffset);
Box box(x, y, z, width, height, depth);
ANGLE_CONTEXT_TRY(destTexture->copySubTexture(
this, destTarget, destLevel, offset, sourceLevel, box, ConvertToBool(unpackFlipY),
ConvertToBool(unpackPremultiplyAlpha), ConvertToBool(unpackUnmultiplyAlpha),
sourceTexture));
}
void Context::compressedCopyTexture(TextureID sourceId, TextureID destId)
{
ANGLE_CONTEXT_TRY(syncStateForTexImage());
gl::Texture *sourceTexture = getTexture(sourceId);
gl::Texture *destTexture = getTexture(destId);
ANGLE_CONTEXT_TRY(destTexture->copyCompressedTexture(this, sourceTexture));
}
void Context::getBufferPointerv(BufferBinding target, GLenum pname, void **params)
{
Buffer *buffer = mState.getTargetBuffer(target);
ASSERT(buffer);
QueryBufferPointerv(buffer, pname, params);
}
void Context::getBufferPointervRobust(BufferBinding target,
GLenum pname,
GLsizei bufSize,
GLsizei *length,
void **params)
{
getBufferPointerv(target, pname, params);
}
void *Context::mapBuffer(BufferBinding target, GLenum access)
{
Buffer *buffer = mState.getTargetBuffer(target);
ASSERT(buffer);
if (buffer->map(this, access) == angle::Result::Stop)
{
return nullptr;
}
return buffer->getMapPointer();
}
GLboolean Context::unmapBuffer(BufferBinding target)
{
Buffer *buffer = mState.getTargetBuffer(target);
ASSERT(buffer);
GLboolean result;
if (buffer->unmap(this, &result) == angle::Result::Stop)
{
return GL_FALSE;
}
return result;
}
void *Context::mapBufferRange(BufferBinding target,
GLintptr offset,
GLsizeiptr length,
GLbitfield access)
{
Buffer *buffer = mState.getTargetBuffer(target);
ASSERT(buffer);
if (buffer->mapRange(this, offset, length, access) == angle::Result::Stop)
{
return nullptr;
}
return buffer->getMapPointer();
}
void Context::flushMappedBufferRange(BufferBinding ,
GLintptr ,
GLsizeiptr )
{
}
angle::Result Context::syncStateForReadPixels()
{
return syncState(mReadPixelsDirtyBits, mReadPixelsDirtyObjects, Command::ReadPixels);
}
angle::Result Context::syncStateForTexImage()
{
return syncState(mTexImageDirtyBits, mTexImageDirtyObjects, Command::TexImage);
}
angle::Result Context::syncStateForBlit()
{
return syncState(mBlitDirtyBits, mBlitDirtyObjects, Command::Blit);
}
angle::Result Context::syncStateForClear()
{
return syncState(mClearDirtyBits, mClearDirtyObjects, Command::Clear);
}
angle::Result Context::syncTextureForCopy(Texture *texture)
{
ASSERT(texture);
if (texture->hasAnyDirtyBit())
{
return texture->syncState(this, Command::Other);
}
return angle::Result::Continue;
}
void Context::activeShaderProgram(ProgramPipelineID pipeline, ShaderProgramID program)
{
Program *shaderProgram = getProgramNoResolveLink(program);
ProgramPipeline *programPipeline =
mState.mProgramPipelineManager->checkProgramPipelineAllocation(mImplementation.get(),
pipeline);
ASSERT(programPipeline);
programPipeline->activeShaderProgram(shaderProgram);
}
void Context::activeTexture(GLenum texture)
{
mState.setActiveSampler(texture - GL_TEXTURE0);
}
void Context::blendBarrier()
{
UNIMPLEMENTED();
}
void Context::blendColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha)
{
mState.setBlendColor(red, green, blue, alpha);
}
void Context::blendEquation(GLenum mode)
{
mState.setBlendEquation(mode, mode);
}
void Context::blendEquationi(GLuint buf, GLenum mode)
{
mState.setBlendEquationIndexed(mode, mode, buf);
}
void Context::blendEquationSeparate(GLenum modeRGB, GLenum modeAlpha)
{
mState.setBlendEquation(modeRGB, modeAlpha);
}
void Context::blendEquationSeparatei(GLuint buf, GLenum modeRGB, GLenum modeAlpha)
{
mState.setBlendEquationIndexed(modeRGB, modeAlpha, buf);
}
void Context::blendFunc(GLenum sfactor, GLenum dfactor)
{
mState.setBlendFactors(sfactor, dfactor, sfactor, dfactor);
}
void Context::blendFunci(GLuint buf, GLenum src, GLenum dst)
{
mState.setBlendFactorsIndexed(src, dst, src, dst, buf);
if (mState.noSimultaneousConstantColorAndAlphaBlendFunc())
{
mStateCache.onBlendFuncIndexedChange(this);
}
}
void Context::blendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha)
{
mState.setBlendFactors(srcRGB, dstRGB, srcAlpha, dstAlpha);
}
void Context::blendFuncSeparatei(GLuint buf,
GLenum srcRGB,
GLenum dstRGB,
GLenum srcAlpha,
GLenum dstAlpha)
{
mState.setBlendFactorsIndexed(srcRGB, dstRGB, srcAlpha, dstAlpha, buf);
if (mState.noSimultaneousConstantColorAndAlphaBlendFunc())
{
mStateCache.onBlendFuncIndexedChange(this);
}
}
void Context::clearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha)
{
mState.setColorClearValue(red, green, blue, alpha);
}
void Context::clearDepthf(GLfloat depth)
{
mState.setDepthClearValue(clamp01(depth));
}
void Context::clearStencil(GLint s)
{
mState.setStencilClearValue(s);
}
void Context::colorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha)
{
mState.setColorMask(ConvertToBool(red), ConvertToBool(green), ConvertToBool(blue),
ConvertToBool(alpha));
mStateCache.onColorMaskChange(this);
}
void Context::colorMaski(GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a)
{
mState.setColorMaskIndexed(ConvertToBool(r), ConvertToBool(g), ConvertToBool(b),
ConvertToBool(a), index);
mStateCache.onColorMaskChange(this);
}
void Context::cullFace(CullFaceMode mode)
{
mState.setCullMode(mode);
}
void Context::depthFunc(GLenum func)
{
mState.setDepthFunc(func);
}
void Context::depthMask(GLboolean flag)
{
mState.setDepthMask(ConvertToBool(flag));
}
void Context::depthRangef(GLfloat zNear, GLfloat zFar)
{
mState.setDepthRange(clamp01(zNear), clamp01(zFar));
}
void Context::clipControl(GLenum origin, GLenum depth)
{
mState.setClipControl(origin, depth);
}
void Context::disable(GLenum cap)
{
mState.setEnableFeature(cap, false);
mStateCache.onContextCapChange(this);
}
void Context::disablei(GLenum target, GLuint index)
{
mState.setEnableFeatureIndexed(target, false, index);
mStateCache.onContextCapChange(this);
}
void Context::disableVertexAttribArray(GLuint index)
{
mState.setEnableVertexAttribArray(index, false);
mStateCache.onVertexArrayStateChange(this);
}
void Context::enable(GLenum cap)
{
mState.setEnableFeature(cap, true);
mStateCache.onContextCapChange(this);
}
void Context::enablei(GLenum target, GLuint index)
{
mState.setEnableFeatureIndexed(target, true, index);
mStateCache.onContextCapChange(this);
}
void Context::enableVertexAttribArray(GLuint index)
{
mState.setEnableVertexAttribArray(index, true);
mStateCache.onVertexArrayStateChange(this);
}
void Context::frontFace(GLenum mode)
{
mState.setFrontFace(mode);
}
void Context::hint(GLenum target, GLenum mode)
{
switch (target)
{
case GL_GENERATE_MIPMAP_HINT:
mState.setGenerateMipmapHint(mode);
break;
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::lineWidth(GLfloat width)
{
mState.setLineWidth(width);
}
void Context::pixelStorei(GLenum pname, GLint param)
{
switch (pname)
{
case GL_UNPACK_ALIGNMENT:
mState.setUnpackAlignment(param);
break;
case GL_PACK_ALIGNMENT:
mState.setPackAlignment(param);
break;
case GL_PACK_REVERSE_ROW_ORDER_ANGLE:
mState.setPackReverseRowOrder(param != 0);
break;
case GL_UNPACK_ROW_LENGTH:
ASSERT((getClientMajorVersion() >= 3) || getExtensions().unpackSubimage);
mState.setUnpackRowLength(param);
break;
case GL_UNPACK_IMAGE_HEIGHT:
ASSERT(getClientMajorVersion() >= 3);
mState.setUnpackImageHeight(param);
break;
case GL_UNPACK_SKIP_IMAGES:
ASSERT(getClientMajorVersion() >= 3);
mState.setUnpackSkipImages(param);
break;
case GL_UNPACK_SKIP_ROWS:
ASSERT((getClientMajorVersion() >= 3) || getExtensions().unpackSubimage);
mState.setUnpackSkipRows(param);
break;
case GL_UNPACK_SKIP_PIXELS:
ASSERT((getClientMajorVersion() >= 3) || getExtensions().unpackSubimage);
mState.setUnpackSkipPixels(param);
break;
case GL_PACK_ROW_LENGTH:
ASSERT((getClientMajorVersion() >= 3) || getExtensions().packSubimage);
mState.setPackRowLength(param);
break;
case GL_PACK_SKIP_ROWS:
ASSERT((getClientMajorVersion() >= 3) || getExtensions().packSubimage);
mState.setPackSkipRows(param);
break;
case GL_PACK_SKIP_PIXELS:
ASSERT((getClientMajorVersion() >= 3) || getExtensions().packSubimage);
mState.setPackSkipPixels(param);
break;
default:
UNREACHABLE();
return;
}
}
void Context::polygonOffset(GLfloat factor, GLfloat units)
{
mState.setPolygonOffsetParams(factor, units);
}
void Context::sampleCoverage(GLfloat value, GLboolean invert)
{
mState.setSampleCoverageParams(clamp01(value), ConvertToBool(invert));
}
void Context::sampleMaski(GLuint maskNumber, GLbitfield mask)
{
mState.setSampleMaskParams(maskNumber, mask);
}
void Context::scissor(GLint x, GLint y, GLsizei width, GLsizei height)
{
mState.setScissorParams(x, y, width, height);
}
void Context::stencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask)
{
GLint clampedRef = gl::clamp(ref, 0, std::numeric_limits<uint8_t>::max());
if (face == GL_FRONT || face == GL_FRONT_AND_BACK)
{
mState.setStencilParams(func, clampedRef, mask);
}
if (face == GL_BACK || face == GL_FRONT_AND_BACK)
{
mState.setStencilBackParams(func, clampedRef, mask);
}
mStateCache.onStencilStateChange(this);
}
void Context::stencilMaskSeparate(GLenum face, GLuint mask)
{
if (face == GL_FRONT || face == GL_FRONT_AND_BACK)
{
mState.setStencilWritemask(mask);
}
if (face == GL_BACK || face == GL_FRONT_AND_BACK)
{
mState.setStencilBackWritemask(mask);
}
mStateCache.onStencilStateChange(this);
}
void Context::stencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass)
{
if (face == GL_FRONT || face == GL_FRONT_AND_BACK)
{
mState.setStencilOperations(fail, zfail, zpass);
}
if (face == GL_BACK || face == GL_FRONT_AND_BACK)
{
mState.setStencilBackOperations(fail, zfail, zpass);
}
}
void Context::vertexAttrib1f(GLuint index, GLfloat x)
{
GLfloat vals[4] = {x, 0, 0, 1};
mState.setVertexAttribf(index, vals);
mStateCache.onDefaultVertexAttributeChange(this);
}
void Context::vertexAttrib1fv(GLuint index, const GLfloat *values)
{
GLfloat vals[4] = {values[0], 0, 0, 1};
mState.setVertexAttribf(index, vals);
mStateCache.onDefaultVertexAttributeChange(this);
}
void Context::vertexAttrib2f(GLuint index, GLfloat x, GLfloat y)
{
GLfloat vals[4] = {x, y, 0, 1};
mState.setVertexAttribf(index, vals);
mStateCache.onDefaultVertexAttributeChange(this);
}
void Context::vertexAttrib2fv(GLuint index, const GLfloat *values)
{
GLfloat vals[4] = {values[0], values[1], 0, 1};
mState.setVertexAttribf(index, vals);
mStateCache.onDefaultVertexAttributeChange(this);
}
void Context::vertexAttrib3f(GLuint index, GLfloat x, GLfloat y, GLfloat z)
{
GLfloat vals[4] = {x, y, z, 1};
mState.setVertexAttribf(index, vals);
mStateCache.onDefaultVertexAttributeChange(this);
}
void Context::vertexAttrib3fv(GLuint index, const GLfloat *values)
{
GLfloat vals[4] = {values[0], values[1], values[2], 1};
mState.setVertexAttribf(index, vals);
mStateCache.onDefaultVertexAttributeChange(this);
}
void Context::vertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
{
GLfloat vals[4] = {x, y, z, w};
mState.setVertexAttribf(index, vals);
mStateCache.onDefaultVertexAttributeChange(this);
}
void Context::vertexAttrib4fv(GLuint index, const GLfloat *values)
{
mState.setVertexAttribf(index, values);
mStateCache.onDefaultVertexAttributeChange(this);
}
void Context::vertexAttribPointer(GLuint index,
GLint size,
VertexAttribType type,
GLboolean normalized,
GLsizei stride,
const void *ptr)
{
mState.setVertexAttribPointer(this, index, mState.getTargetBuffer(BufferBinding::Array), size,
type, ConvertToBool(normalized), stride, ptr);
mStateCache.onVertexArrayStateChange(this);
}
void Context::vertexAttribFormat(GLuint attribIndex,
GLint size,
VertexAttribType type,
GLboolean normalized,
GLuint relativeOffset)
{
mState.setVertexAttribFormat(attribIndex, size, type, ConvertToBool(normalized), false,
relativeOffset);
mStateCache.onVertexArrayFormatChange(this);
}
void Context::vertexAttribIFormat(GLuint attribIndex,
GLint size,
VertexAttribType type,
GLuint relativeOffset)
{
mState.setVertexAttribFormat(attribIndex, size, type, false, true, relativeOffset);
mStateCache.onVertexArrayFormatChange(this);
}
void Context::vertexAttribBinding(GLuint attribIndex, GLuint bindingIndex)
{
mState.setVertexAttribBinding(this, attribIndex, bindingIndex);
mStateCache.onVertexArrayStateChange(this);
}
void Context::vertexBindingDivisor(GLuint bindingIndex, GLuint divisor)
{
mState.setVertexBindingDivisor(bindingIndex, divisor);
mStateCache.onVertexArrayFormatChange(this);
}
void Context::viewport(GLint x, GLint y, GLsizei width, GLsizei height)
{
mState.setViewportParams(x, y, width, height);
}
void Context::vertexAttribIPointer(GLuint index,
GLint size,
VertexAttribType type,
GLsizei stride,
const void *pointer)
{
mState.setVertexAttribIPointer(this, index, mState.getTargetBuffer(BufferBinding::Array), size,
type, stride, pointer);
mStateCache.onVertexArrayStateChange(this);
}
void Context::vertexAttribI4i(GLuint index, GLint x, GLint y, GLint z, GLint w)
{
GLint vals[4] = {x, y, z, w};
mState.setVertexAttribi(index, vals);
mStateCache.onDefaultVertexAttributeChange(this);
}
void Context::vertexAttribI4ui(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w)
{
GLuint vals[4] = {x, y, z, w};
mState.setVertexAttribu(index, vals);
mStateCache.onDefaultVertexAttributeChange(this);
}
void Context::vertexAttribI4iv(GLuint index, const GLint *v)
{
mState.setVertexAttribi(index, v);
mStateCache.onDefaultVertexAttributeChange(this);
}
void Context::vertexAttribI4uiv(GLuint index, const GLuint *v)
{
mState.setVertexAttribu(index, v);
mStateCache.onDefaultVertexAttributeChange(this);
}
void Context::getVertexAttribivImpl(GLuint index, GLenum pname, GLint *params) const
{
const VertexAttribCurrentValueData ¤tValues =
getState().getVertexAttribCurrentValue(index);
const VertexArray *vao = getState().getVertexArray();
QueryVertexAttribiv(vao->getVertexAttribute(index), vao->getBindingFromAttribIndex(index),
currentValues, pname, params);
}
void Context::getVertexAttribiv(GLuint index, GLenum pname, GLint *params)
{
return getVertexAttribivImpl(index, pname, params);
}
void Context::getVertexAttribivRobust(GLuint index,
GLenum pname,
GLsizei bufSize,
GLsizei *length,
GLint *params)
{
getVertexAttribiv(index, pname, params);
}
void Context::getVertexAttribfv(GLuint index, GLenum pname, GLfloat *params)
{
const VertexAttribCurrentValueData ¤tValues =
getState().getVertexAttribCurrentValue(index);
const VertexArray *vao = getState().getVertexArray();
QueryVertexAttribfv(vao->getVertexAttribute(index), vao->getBindingFromAttribIndex(index),
currentValues, pname, params);
}
void Context::getVertexAttribfvRobust(GLuint index,
GLenum pname,
GLsizei bufSize,
GLsizei *length,
GLfloat *params)
{
getVertexAttribfv(index, pname, params);
}
void Context::getVertexAttribIiv(GLuint index, GLenum pname, GLint *params)
{
const VertexAttribCurrentValueData ¤tValues =
getState().getVertexAttribCurrentValue(index);
const VertexArray *vao = getState().getVertexArray();
QueryVertexAttribIiv(vao->getVertexAttribute(index), vao->getBindingFromAttribIndex(index),
currentValues, pname, params);
}
void Context::getVertexAttribIivRobust(GLuint index,
GLenum pname,
GLsizei bufSize,
GLsizei *length,
GLint *params)
{
getVertexAttribIiv(index, pname, params);
}
void Context::getVertexAttribIuiv(GLuint index, GLenum pname, GLuint *params)
{
const VertexAttribCurrentValueData ¤tValues =
getState().getVertexAttribCurrentValue(index);
const VertexArray *vao = getState().getVertexArray();
QueryVertexAttribIuiv(vao->getVertexAttribute(index), vao->getBindingFromAttribIndex(index),
currentValues, pname, params);
}
void Context::getVertexAttribIuivRobust(GLuint index,
GLenum pname,
GLsizei bufSize,
GLsizei *length,
GLuint *params)
{
getVertexAttribIuiv(index, pname, params);
}
void Context::getVertexAttribPointerv(GLuint index, GLenum pname, void **pointer)
{
const VertexAttribute &attrib = getState().getVertexArray()->getVertexAttribute(index);
QueryVertexAttribPointerv(attrib, pname, pointer);
}
void Context::getVertexAttribPointervRobust(GLuint index,
GLenum pname,
GLsizei bufSize,
GLsizei *length,
void **pointer)
{
getVertexAttribPointerv(index, pname, pointer);
}
void Context::debugMessageControl(GLenum source,
GLenum type,
GLenum severity,
GLsizei count,
const GLuint *ids,
GLboolean enabled)
{
std::vector<GLuint> idVector(ids, ids + count);
mState.getDebug().setMessageControl(source, type, severity, std::move(idVector),
ConvertToBool(enabled));
}
void Context::debugMessageInsert(GLenum source,
GLenum type,
GLuint id,
GLenum severity,
GLsizei length,
const GLchar *buf)
{
std::string msg(buf, (length > 0) ? static_cast<size_t>(length) : strlen(buf));
mState.getDebug().insertMessage(source, type, id, severity, std::move(msg), gl::LOG_INFO);
}
void Context::debugMessageCallback(GLDEBUGPROCKHR callback, const void *userParam)
{
mState.getDebug().setCallback(callback, userParam);
}
GLuint Context::getDebugMessageLog(GLuint count,
GLsizei bufSize,
GLenum *sources,
GLenum *types,
GLuint *ids,
GLenum *severities,
GLsizei *lengths,
GLchar *messageLog)
{
return static_cast<GLuint>(mState.getDebug().getMessages(count, bufSize, sources, types, ids,
severities, lengths, messageLog));
}
void Context::pushDebugGroup(GLenum source, GLuint id, GLsizei length, const GLchar *message)
{
std::string msg(message, (length > 0) ? static_cast<size_t>(length) : strlen(message));
ANGLE_CONTEXT_TRY(mImplementation->pushDebugGroup(this, source, id, msg));
mState.getDebug().pushGroup(source, id, std::move(msg));
}
angle::Result Context::handleNoopDrawEvent()
{
return (mImplementation->handleNoopDrawEvent());
}
void Context::popDebugGroup()
{
mState.getDebug().popGroup();
ANGLE_CONTEXT_TRY(mImplementation->popDebugGroup(this));
}
void Context::primitiveBoundingBox(GLfloat minX,
GLfloat minY,
GLfloat minZ,
GLfloat minW,
GLfloat maxX,
GLfloat maxY,
GLfloat maxZ,
GLfloat maxW)
{
mState.mBoundingBoxMinX = minX;
mState.mBoundingBoxMinY = minY;
mState.mBoundingBoxMinZ = minZ;
mState.mBoundingBoxMinW = minW;
mState.mBoundingBoxMaxX = maxX;
mState.mBoundingBoxMaxY = maxY;
mState.mBoundingBoxMaxZ = maxZ;
mState.mBoundingBoxMaxW = maxW;
}
void Context::bufferStorage(BufferBinding target,
GLsizeiptr size,
const void *data,
GLbitfield flags)
{
Buffer *buffer = mState.getTargetBuffer(target);
ASSERT(buffer);
ANGLE_CONTEXT_TRY(buffer->bufferStorage(this, target, size, data, flags));
}
void Context::bufferStorageExternal(BufferBinding target,
GLintptr offset,
GLsizeiptr size,
GLeglClientBufferEXT clientBuffer,
GLbitfield flags)
{
Buffer *buffer = mState.getTargetBuffer(target);
ASSERT(buffer);
ANGLE_CONTEXT_TRY(buffer->bufferStorageExternal(this, target, size, clientBuffer, flags));
}
void Context::namedBufferStorageExternal(GLuint buffer,
GLintptr offset,
GLsizeiptr size,
GLeglClientBufferEXT clientBuffer,
GLbitfield flags)
{
UNIMPLEMENTED();
}
void Context::bufferData(BufferBinding target, GLsizeiptr size, const void *data, BufferUsage usage)
{
Buffer *buffer = mState.getTargetBuffer(target);
ASSERT(buffer);
ANGLE_CONTEXT_TRY(buffer->bufferData(this, target, data, size, usage));
}
void Context::bufferSubData(BufferBinding target,
GLintptr offset,
GLsizeiptr size,
const void *data)
{
if (data == nullptr || size == 0)
{
return;
}
Buffer *buffer = mState.getTargetBuffer(target);
ASSERT(buffer);
ANGLE_CONTEXT_TRY(buffer->bufferSubData(this, target, data, size, offset));
}
void Context::attachShader(ShaderProgramID program, ShaderProgramID shader)
{
Program *programObject = mState.mShaderProgramManager->getProgram(program);
Shader *shaderObject = mState.mShaderProgramManager->getShader(shader);
ASSERT(programObject && shaderObject);
programObject->attachShader(shaderObject);
}
void Context::copyBufferSubData(BufferBinding readTarget,
BufferBinding writeTarget,
GLintptr readOffset,
GLintptr writeOffset,
GLsizeiptr size)
{
if (size == 0)
{
return;
}
Buffer *readBuffer = mState.getTargetBuffer(readTarget);
Buffer *writeBuffer = mState.getTargetBuffer(writeTarget);
ANGLE_CONTEXT_TRY(
writeBuffer->copyBufferSubData(this, readBuffer, readOffset, writeOffset, size));
}
void Context::bindAttribLocation(ShaderProgramID program, GLuint index, const GLchar *name)
{
Program *programObject = getProgramResolveLink(program);
ASSERT(programObject);
programObject->bindAttributeLocation(index, name);
}
void Context::bindBufferBase(BufferBinding target, GLuint index, BufferID buffer)
{
bindBufferRange(target, index, buffer, 0, 0);
}
void Context::bindBufferRange(BufferBinding target,
GLuint index,
BufferID buffer,
GLintptr offset,
GLsizeiptr size)
{
Buffer *object = mState.mBufferManager->checkBufferAllocation(mImplementation.get(), buffer);
ANGLE_CONTEXT_TRY(mState.setIndexedBufferBinding(this, target, index, object, offset, size));
if (target == BufferBinding::Uniform)
{
mUniformBufferObserverBindings[index].bind(object);
mStateCache.onUniformBufferStateChange(this);
}
else if (target == BufferBinding::AtomicCounter)
{
mAtomicCounterBufferObserverBindings[index].bind(object);
mStateCache.onAtomicCounterBufferStateChange(this);
}
else if (target == BufferBinding::ShaderStorage)
{
mShaderStorageBufferObserverBindings[index].bind(object);
mStateCache.onShaderStorageBufferStateChange(this);
}
else
{
mStateCache.onBufferBindingChange(this);
}
}
void Context::bindFramebuffer(GLenum target, FramebufferID framebuffer)
{
if (target == GL_READ_FRAMEBUFFER || target == GL_FRAMEBUFFER)
{
bindReadFramebuffer(framebuffer);
}
if (target == GL_DRAW_FRAMEBUFFER || target == GL_FRAMEBUFFER)
{
bindDrawFramebuffer(framebuffer);
}
}
void Context::bindRenderbuffer(GLenum target, RenderbufferID renderbuffer)
{
ASSERT(target == GL_RENDERBUFFER);
Renderbuffer *object = mState.mRenderbufferManager->checkRenderbufferAllocation(
mImplementation.get(), renderbuffer);
mState.setRenderbufferBinding(this, object);
}
void Context::texStorage2DMultisample(TextureType target,
GLsizei samples,
GLenum internalformat,
GLsizei width,
GLsizei height,
GLboolean fixedsamplelocations)
{
Extents size(width, height, 1);
Texture *texture = getTextureByType(target);
ANGLE_CONTEXT_TRY(texture->setStorageMultisample(this, target, samples, internalformat, size,
ConvertToBool(fixedsamplelocations)));
}
void Context::texStorage3DMultisample(TextureType target,
GLsizei samples,
GLenum internalformat,
GLsizei width,
GLsizei height,
GLsizei depth,
GLboolean fixedsamplelocations)
{
Extents size(width, height, depth);
Texture *texture = getTextureByType(target);
ANGLE_CONTEXT_TRY(texture->setStorageMultisample(this, target, samples, internalformat, size,
ConvertToBool(fixedsamplelocations)));
}
void Context::texImage2DExternal(TextureTarget target,
GLint level,
GLint internalformat,
GLsizei width,
GLsizei height,
GLint border,
GLenum format,
GLenum type)
{
Extents size(width, height, 1);
Texture *texture = getTextureByTarget(target);
ANGLE_CONTEXT_TRY(
texture->setImageExternal(this, target, level, internalformat, size, format, type));
}
void Context::invalidateTexture(TextureType target)
{
mImplementation->invalidateTexture(target);
mState.invalidateTextureBindings(target);
}
void Context::getMultisamplefv(GLenum pname, GLuint index, GLfloat *val)
{
ANGLE_CONTEXT_TRY(mState.syncDirtyObject(this, GL_DRAW_FRAMEBUFFER));
const Framebuffer *framebuffer = mState.getDrawFramebuffer();
switch (pname)
{
case GL_SAMPLE_POSITION:
ANGLE_CONTEXT_TRY(framebuffer->getSamplePosition(this, index, val));
break;
default:
UNREACHABLE();
}
}
void Context::getMultisamplefvRobust(GLenum pname,
GLuint index,
GLsizei bufSize,
GLsizei *length,
GLfloat *val)
{
UNIMPLEMENTED();
}
void Context::renderbufferStorage(GLenum target,
GLenum internalformat,
GLsizei width,
GLsizei height)
{
GLenum convertedInternalFormat = getConvertedRenderbufferFormat(internalformat);
Renderbuffer *renderbuffer = mState.getCurrentRenderbuffer();
ANGLE_CONTEXT_TRY(renderbuffer->setStorage(this, convertedInternalFormat, width, height));
}
void Context::renderbufferStorageMultisample(GLenum target,
GLsizei samples,
GLenum internalformat,
GLsizei width,
GLsizei height)
{
renderbufferStorageMultisampleImpl(target, samples, internalformat, width, height,
MultisamplingMode::Regular);
}
void Context::renderbufferStorageMultisampleEXT(GLenum target,
GLsizei samples,
GLenum internalformat,
GLsizei width,
GLsizei height)
{
renderbufferStorageMultisampleImpl(target, samples, internalformat, width, height,
MultisamplingMode::MultisampledRenderToTexture);
}
void Context::renderbufferStorageMultisampleImpl(GLenum target,
GLsizei samples,
GLenum internalformat,
GLsizei width,
GLsizei height,
MultisamplingMode mode)
{
GLenum convertedInternalFormat = getConvertedRenderbufferFormat(internalformat);
Renderbuffer *renderbuffer = mState.getCurrentRenderbuffer();
ANGLE_CONTEXT_TRY(renderbuffer->setStorageMultisample(this, samples, convertedInternalFormat,
width, height, mode));
}
void Context::framebufferTexture2DMultisample(GLenum target,
GLenum attachment,
TextureTarget textarget,
TextureID texture,
GLint level,
GLsizei samples)
{
Framebuffer *framebuffer = mState.getTargetFramebuffer(target);
ASSERT(framebuffer);
if (texture.value != 0)
{
Texture *textureObj = getTexture(texture);
ImageIndex index = ImageIndex::MakeFromTarget(textarget, level, 1);
framebuffer->setAttachmentMultisample(this, GL_TEXTURE, attachment, index, textureObj,
samples);
}
else
{
framebuffer->resetAttachment(this, attachment);
}
mState.setObjectDirty(target);
}
void Context::getSynciv(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values)
{
const Sync *syncObject = nullptr;
if (!isContextLost())
{
syncObject = getSync(sync);
}
ANGLE_CONTEXT_TRY(QuerySynciv(this, syncObject, pname, bufSize, length, values));
}
void Context::getFramebufferParameteriv(GLenum target, GLenum pname, GLint *params)
{
Framebuffer *framebuffer = mState.getTargetFramebuffer(target);
QueryFramebufferParameteriv(framebuffer, pname, params);
}
void Context::getFramebufferParameterivRobust(GLenum target,
GLenum pname,
GLsizei bufSize,
GLsizei *length,
GLint *params)
{
UNIMPLEMENTED();
}
void Context::framebufferParameteri(GLenum target, GLenum pname, GLint param)
{
Framebuffer *framebuffer = mState.getTargetFramebuffer(target);
SetFramebufferParameteri(this, framebuffer, pname, param);
}
bool Context::getScratchBuffer(size_t requstedSizeBytes,
angle::MemoryBuffer **scratchBufferOut) const
{
if (!mScratchBuffer.valid())
{
mScratchBuffer = mDisplay->requestScratchBuffer();
}
ASSERT(mScratchBuffer.valid());
return mScratchBuffer.value().get(requstedSizeBytes, scratchBufferOut);
}
angle::ScratchBuffer *Context::getScratchBuffer() const
{
if (!mScratchBuffer.valid())
{
mScratchBuffer = mDisplay->requestScratchBuffer();
}
ASSERT(mScratchBuffer.valid());
return &mScratchBuffer.value();
}
bool Context::getZeroFilledBuffer(size_t requstedSizeBytes,
angle::MemoryBuffer **zeroBufferOut) const
{
if (!mZeroFilledBuffer.valid())
{
mZeroFilledBuffer = mDisplay->requestZeroFilledBuffer();
}
ASSERT(mZeroFilledBuffer.valid());
return mZeroFilledBuffer.value().getInitialized(requstedSizeBytes, zeroBufferOut, 0);
}
void Context::dispatchCompute(GLuint numGroupsX, GLuint numGroupsY, GLuint numGroupsZ)
{
if (numGroupsX == 0u || numGroupsY == 0u || numGroupsZ == 0u)
{
return;
}
ANGLE_CONTEXT_TRY(prepareForDispatch());
angle::Result result =
mImplementation->dispatchCompute(this, numGroupsX, numGroupsY, numGroupsZ);
MarkShaderStorageUsage(this);
convertPpoToComputeOrDraw(false);
if (ANGLE_UNLIKELY(IsError(result)))
{
return;
}
}
void Context::convertPpoToComputeOrDraw(bool isCompute)
{
Program *program = mState.getProgram();
ProgramPipeline *pipeline = mState.getProgramPipeline();
if (!program && pipeline)
{
pipeline->getExecutable().setIsCompute(isCompute);
pipeline->resetIsLinked();
mState.mDirtyBits.set(State::DirtyBitType::DIRTY_BIT_PROGRAM_EXECUTABLE);
mStateCache.onProgramExecutableChange(this);
}
}
void Context::dispatchComputeIndirect(GLintptr indirect)
{
ANGLE_CONTEXT_TRY(prepareForDispatch());
ANGLE_CONTEXT_TRY(mImplementation->dispatchComputeIndirect(this, indirect));
MarkShaderStorageUsage(this);
}
void Context::texStorage2D(TextureType target,
GLsizei levels,
GLenum internalFormat,
GLsizei width,
GLsizei height)
{
Extents size(width, height, 1);
Texture *texture = getTextureByType(target);
ANGLE_CONTEXT_TRY(texture->setStorage(this, target, levels, internalFormat, size));
}
void Context::texStorage3D(TextureType target,
GLsizei levels,
GLenum internalFormat,
GLsizei width,
GLsizei height,
GLsizei depth)
{
Extents size(width, height, depth);
Texture *texture = getTextureByType(target);
ANGLE_CONTEXT_TRY(texture->setStorage(this, target, levels, internalFormat, size));
}
void Context::memoryBarrier(GLbitfield barriers)
{
ANGLE_CONTEXT_TRY(mImplementation->memoryBarrier(this, barriers));
}
void Context::memoryBarrierByRegion(GLbitfield barriers)
{
ANGLE_CONTEXT_TRY(mImplementation->memoryBarrierByRegion(this, barriers));
}
void Context::multiDrawArrays(PrimitiveMode mode,
const GLint *firsts,
const GLsizei *counts,
GLsizei drawcount)
{
ANGLE_CONTEXT_TRY(prepareForDraw(mode));
ANGLE_CONTEXT_TRY(mImplementation->multiDrawArrays(this, mode, firsts, counts, drawcount));
}
void Context::multiDrawArraysInstanced(PrimitiveMode mode,
const GLint *firsts,
const GLsizei *counts,
const GLsizei *instanceCounts,
GLsizei drawcount)
{
ANGLE_CONTEXT_TRY(prepareForDraw(mode));
ANGLE_CONTEXT_TRY(mImplementation->multiDrawArraysInstanced(this, mode, firsts, counts,
instanceCounts, drawcount));
}
void Context::multiDrawElements(PrimitiveMode mode,
const GLsizei *counts,
DrawElementsType type,
const GLvoid *const *indices,
GLsizei drawcount)
{
ANGLE_CONTEXT_TRY(prepareForDraw(mode));
ANGLE_CONTEXT_TRY(
mImplementation->multiDrawElements(this, mode, counts, type, indices, drawcount));
}
void Context::multiDrawElementsInstanced(PrimitiveMode mode,
const GLsizei *counts,
DrawElementsType type,
const GLvoid *const *indices,
const GLsizei *instanceCounts,
GLsizei drawcount)
{
ANGLE_CONTEXT_TRY(prepareForDraw(mode));
ANGLE_CONTEXT_TRY(mImplementation->multiDrawElementsInstanced(this, mode, counts, type, indices,
instanceCounts, drawcount));
}
void Context::drawArraysInstancedBaseInstance(PrimitiveMode mode,
GLint first,
GLsizei count,
GLsizei instanceCount,
GLuint baseInstance)
{
if (noopDraw(mode, count))
{
ANGLE_CONTEXT_TRY(mImplementation->handleNoopDrawEvent());
return;
}
ANGLE_CONTEXT_TRY(prepareForDraw(mode));
Program *programObject = mState.getLinkedProgram(this);
const bool hasBaseInstance = programObject && programObject->hasBaseInstanceUniform();
if (hasBaseInstance)
{
programObject->setBaseInstanceUniform(baseInstance);
}
rx::ResetBaseVertexBaseInstance resetUniforms(programObject, false, hasBaseInstance);
ANGLE_CONTEXT_TRY(mImplementation->drawArraysInstancedBaseInstance(
this, mode, first, count, instanceCount, baseInstance));
MarkTransformFeedbackBufferUsage(this, count, 1);
}
void Context::drawElementsInstancedBaseVertexBaseInstance(PrimitiveMode mode,
GLsizei count,
DrawElementsType type,
const GLvoid *indices,
GLsizei instanceCounts,
GLint baseVertex,
GLuint baseInstance)
{
if (noopDraw(mode, count))
{
ANGLE_CONTEXT_TRY(mImplementation->handleNoopDrawEvent());
return;
}
ANGLE_CONTEXT_TRY(prepareForDraw(mode));
Program *programObject = mState.getLinkedProgram(this);
const bool hasBaseVertex = programObject && programObject->hasBaseVertexUniform();
if (hasBaseVertex)
{
programObject->setBaseVertexUniform(baseVertex);
}
const bool hasBaseInstance = programObject && programObject->hasBaseInstanceUniform();
if (hasBaseInstance)
{
programObject->setBaseInstanceUniform(baseInstance);
}
rx::ResetBaseVertexBaseInstance resetUniforms(programObject, hasBaseVertex, hasBaseInstance);
ANGLE_CONTEXT_TRY(mImplementation->drawElementsInstancedBaseVertexBaseInstance(
this, mode, count, type, indices, instanceCounts, baseVertex, baseInstance));
}
void Context::multiDrawArraysInstancedBaseInstance(PrimitiveMode mode,
const GLint *firsts,
const GLsizei *counts,
const GLsizei *instanceCounts,
const GLuint *baseInstances,
GLsizei drawcount)
{
ANGLE_CONTEXT_TRY(prepareForDraw(mode));
ANGLE_CONTEXT_TRY(mImplementation->multiDrawArraysInstancedBaseInstance(
this, mode, firsts, counts, instanceCounts, baseInstances, drawcount));
}
void Context::multiDrawElementsInstancedBaseVertexBaseInstance(PrimitiveMode mode,
const GLsizei *counts,
DrawElementsType type,
const GLvoid *const *indices,
const GLsizei *instanceCounts,
const GLint *baseVertices,
const GLuint *baseInstances,
GLsizei drawcount)
{
ANGLE_CONTEXT_TRY(prepareForDraw(mode));
ANGLE_CONTEXT_TRY(mImplementation->multiDrawElementsInstancedBaseVertexBaseInstance(
this, mode, counts, type, indices, instanceCounts, baseVertices, baseInstances, drawcount));
}
void Context::provokingVertex(ProvokingVertexConvention provokeMode)
{
mState.setProvokingVertex(provokeMode);
}
GLenum Context::checkFramebufferStatus(GLenum target)
{
Framebuffer *framebuffer = mState.getTargetFramebuffer(target);
ASSERT(framebuffer);
return framebuffer->checkStatus(this).status;
}
void Context::compileShader(ShaderProgramID shader)
{
Shader *shaderObject = GetValidShader(this, shader);
if (!shaderObject)
{
return;
}
shaderObject->compile(this);
}
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]);
}
}
}
void Context::detachShader(ShaderProgramID program, ShaderProgramID shader)
{
Program *programObject = getProgramNoResolveLink(program);
ASSERT(programObject);
Shader *shaderObject = getShader(shader);
ASSERT(shaderObject);
programObject->detachShader(this, shaderObject);
}
void Context::genBuffers(GLsizei n, BufferID *buffers)
{
for (int i = 0; i < n; i++)
{
buffers[i] = createBuffer();
}
}
void Context::genFramebuffers(GLsizei n, FramebufferID *framebuffers)
{
for (int i = 0; i < n; i++)
{
framebuffers[i] = createFramebuffer();
}
}
void Context::genRenderbuffers(GLsizei n, RenderbufferID *renderbuffers)
{
for (int i = 0; i < n; i++)
{
renderbuffers[i] = createRenderbuffer();
}
}
void Context::genTextures(GLsizei n, TextureID *textures)
{
for (int i = 0; i < n; i++)
{
textures[i] = createTexture();
}
}
void Context::getActiveAttrib(ShaderProgramID program,
GLuint index,
GLsizei bufsize,
GLsizei *length,
GLint *size,
GLenum *type,
GLchar *name)
{
Program *programObject = getProgramResolveLink(program);
ASSERT(programObject);
programObject->getActiveAttribute(index, bufsize, length, size, type, name);
}
void Context::getActiveUniform(ShaderProgramID program,
GLuint index,
GLsizei bufsize,
GLsizei *length,
GLint *size,
GLenum *type,
GLchar *name)
{
Program *programObject = getProgramResolveLink(program);
ASSERT(programObject);
programObject->getActiveUniform(index, bufsize, length, size, type, name);
}
void Context::getAttachedShaders(ShaderProgramID program,
GLsizei maxcount,
GLsizei *count,
ShaderProgramID *shaders)
{
Program *programObject = getProgramNoResolveLink(program);
ASSERT(programObject);
programObject->getAttachedShaders(maxcount, count, shaders);
}
GLint Context::getAttribLocation(ShaderProgramID program, const GLchar *name)
{
Program *programObject = getProgramResolveLink(program);
ASSERT(programObject);
return programObject->getAttributeLocation(name);
}
void Context::getBooleanv(GLenum pname, GLboolean *params)
{
GLenum nativeType;
unsigned int numParams = 0;
getQueryParameterInfo(pname, &nativeType, &numParams);
if (nativeType == GL_BOOL)
{
getBooleanvImpl(pname, params);
}
else
{
CastStateValues(this, nativeType, pname, numParams, params);
}
}
void Context::getBooleanvRobust(GLenum pname, GLsizei bufSize, GLsizei *length, GLboolean *params)
{
getBooleanv(pname, params);
}
void Context::getFloatv(GLenum pname, GLfloat *params)
{
GLenum nativeType;
unsigned int numParams = 0;
getQueryParameterInfo(pname, &nativeType, &numParams);
if (nativeType == GL_FLOAT)
{
getFloatvImpl(pname, params);
}
else
{
CastStateValues(this, nativeType, pname, numParams, params);
}
}
void Context::getFloatvRobust(GLenum pname, GLsizei bufSize, GLsizei *length, GLfloat *params)
{
getFloatv(pname, params);
}
void Context::getIntegerv(GLenum pname, GLint *params)
{
GLenum nativeType = GL_NONE;
unsigned int numParams = 0;
getQueryParameterInfo(pname, &nativeType, &numParams);
if (nativeType == GL_INT)
{
getIntegervImpl(pname, params);
}
else
{
CastStateValues(this, nativeType, pname, numParams, params);
}
}
void Context::getIntegervRobust(GLenum pname, GLsizei bufSize, GLsizei *length, GLint *data)
{
getIntegerv(pname, data);
}
void Context::getProgramiv(ShaderProgramID program, GLenum pname, GLint *params)
{
Program *programObject = getProgramNoResolveLink(program);
if (!isContextLost() && pname != GL_COMPLETION_STATUS_KHR)
{
programObject = getProgramResolveLink(program);
}
ASSERT(programObject);
QueryProgramiv(this, programObject, pname, params);
}
void Context::getProgramivRobust(ShaderProgramID program,
GLenum pname,
GLsizei bufSize,
GLsizei *length,
GLint *params)
{
getProgramiv(program, pname, params);
}
void Context::getProgramPipelineiv(ProgramPipelineID pipeline, GLenum pname, GLint *params)
{
ProgramPipeline *programPipeline = nullptr;
if (!mContextLost)
{
programPipeline = getProgramPipeline(pipeline);
}
QueryProgramPipelineiv(this, programPipeline, pname, params);
}
MemoryObject *Context::getMemoryObject(MemoryObjectID handle) const
{
return mState.mMemoryObjectManager->getMemoryObject(handle);
}
Semaphore *Context::getSemaphore(SemaphoreID handle) const
{
return mState.mSemaphoreManager->getSemaphore(handle);
}
void Context::getProgramInfoLog(ShaderProgramID program,
GLsizei bufsize,
GLsizei *length,
GLchar *infolog)
{
Program *programObject = getProgramResolveLink(program);
ASSERT(programObject);
programObject->getExecutable().getInfoLog(bufsize, length, infolog);
}
void Context::getProgramPipelineInfoLog(ProgramPipelineID pipeline,
GLsizei bufSize,
GLsizei *length,
GLchar *infoLog)
{
ProgramPipeline *programPipeline = getProgramPipeline(pipeline);
if (programPipeline)
{
programPipeline->getExecutable().getInfoLog(bufSize, length, infoLog);
}
else
{
*length = 0;
*infoLog = '\0';
}
}
void Context::getShaderiv(ShaderProgramID shader, GLenum pname, GLint *params)
{
Shader *shaderObject = nullptr;
if (!isContextLost())
{
shaderObject = getShader(shader);
ASSERT(shaderObject);
}
QueryShaderiv(this, shaderObject, pname, params);
}
void Context::getShaderivRobust(ShaderProgramID shader,
GLenum pname,
GLsizei bufSize,
GLsizei *length,
GLint *params)
{
getShaderiv(shader, pname, params);
}
void Context::getShaderInfoLog(ShaderProgramID shader,
GLsizei bufsize,
GLsizei *length,
GLchar *infolog)
{
Shader *shaderObject = getShader(shader);
ASSERT(shaderObject);
shaderObject->getInfoLog(bufsize, length, infolog);
}
void Context::getShaderPrecisionFormat(GLenum shadertype,
GLenum precisiontype,
GLint *range,
GLint *precision)
{
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;
default:
UNREACHABLE();
return;
}
break;
default:
UNREACHABLE();
return;
}
}
void Context::getShaderSource(ShaderProgramID shader,
GLsizei bufsize,
GLsizei *length,
GLchar *source)
{
Shader *shaderObject = getShader(shader);
ASSERT(shaderObject);
shaderObject->getSource(bufsize, length, source);
}
void Context::getUniformfv(ShaderProgramID program, UniformLocation location, GLfloat *params)
{
Program *programObject = getProgramResolveLink(program);
ASSERT(programObject);
programObject->getUniformfv(this, location, params);
}
void Context::getUniformfvRobust(ShaderProgramID program,
UniformLocation location,
GLsizei bufSize,
GLsizei *length,
GLfloat *params)
{
getUniformfv(program, location, params);
}
void Context::getUniformiv(ShaderProgramID program, UniformLocation location, GLint *params)
{
Program *programObject = getProgramResolveLink(program);
ASSERT(programObject);
programObject->getUniformiv(this, location, params);
}
void Context::getUniformivRobust(ShaderProgramID program,
UniformLocation location,
GLsizei bufSize,
GLsizei *length,
GLint *params)
{
getUniformiv(program, location, params);
}
GLint Context::getUniformLocation(ShaderProgramID program, const GLchar *name)
{
Program *programObject = getProgramResolveLink(program);
ASSERT(programObject);
return programObject->getUniformLocation(name).value;
}
GLboolean Context::isBuffer(BufferID buffer) const
{
if (buffer.value == 0)
{
return GL_FALSE;
}
return ConvertToGLBoolean(getBuffer(buffer));
}
GLboolean Context::isEnabled(GLenum cap) const
{
return mState.getEnableFeature(cap);
}
GLboolean Context::isEnabledi(GLenum target, GLuint index) const
{
return mState.getEnableFeatureIndexed(target, index);
}
GLboolean Context::isFramebuffer(FramebufferID framebuffer) const
{
if (framebuffer.value == 0)
{
return GL_FALSE;
}
return ConvertToGLBoolean(getFramebuffer(framebuffer));
}
GLboolean Context::isProgram(ShaderProgramID program) const
{
if (program.value == 0)
{
return GL_FALSE;
}
return ConvertToGLBoolean(getProgramNoResolveLink(program));
}
GLboolean Context::isRenderbuffer(RenderbufferID renderbuffer) const
{
if (renderbuffer.value == 0)
{
return GL_FALSE;
}
return ConvertToGLBoolean(getRenderbuffer(renderbuffer));
}
GLboolean Context::isShader(ShaderProgramID shader) const
{
if (shader.value == 0)
{
return GL_FALSE;
}
return ConvertToGLBoolean(getShader(shader));
}
GLboolean Context::isTexture(TextureID texture) const
{
if (texture.value == 0)
{
return GL_FALSE;
}
return ConvertToGLBoolean(getTexture(texture));
}
void Context::linkProgram(ShaderProgramID program)
{
Program *programObject = getProgramNoResolveLink(program);
ASSERT(programObject);
ANGLE_CONTEXT_TRY(programObject->link(this));
ANGLE_CONTEXT_TRY(onProgramLink(programObject));
}
void Context::releaseShaderCompiler()
{
mCompiler.set(this, nullptr);
}
void Context::shaderBinary(GLsizei n,
const ShaderProgramID *shaders,
GLenum binaryformat,
const void *binary,
GLsizei length)
{
UNIMPLEMENTED();
}
void Context::bindFragDataLocationIndexed(ShaderProgramID program,
GLuint colorNumber,
GLuint index,
const char *name)
{
Program *programObject = getProgramNoResolveLink(program);
programObject->bindFragmentOutputLocation(colorNumber, name);
programObject->bindFragmentOutputIndex(index, name);
}
void Context::bindFragDataLocation(ShaderProgramID program, GLuint colorNumber, const char *name)
{
bindFragDataLocationIndexed(program, colorNumber, 0u, name);
}
int Context::getFragDataIndex(ShaderProgramID program, const char *name)
{
Program *programObject = getProgramResolveLink(program);
return programObject->getFragDataIndex(name);
}
int Context::getProgramResourceLocationIndex(ShaderProgramID program,
GLenum programInterface,
const char *name)
{
Program *programObject = getProgramResolveLink(program);
ASSERT(programInterface == GL_PROGRAM_OUTPUT);
return programObject->getFragDataIndex(name);
}
void Context::shaderSource(ShaderProgramID shader,
GLsizei count,
const GLchar *const *string,
const GLint *length)
{
Shader *shaderObject = getShader(shader);
ASSERT(shaderObject);
shaderObject->setSource(count, string, length);
}
void Context::stencilFunc(GLenum func, GLint ref, GLuint mask)
{
stencilFuncSeparate(GL_FRONT_AND_BACK, func, ref, mask);
}
void Context::stencilMask(GLuint mask)
{
stencilMaskSeparate(GL_FRONT_AND_BACK, mask);
}
void Context::stencilOp(GLenum fail, GLenum zfail, GLenum zpass)
{
stencilOpSeparate(GL_FRONT_AND_BACK, fail, zfail, zpass);
}
void Context::patchParameteri(GLenum pname, GLint value)
{
switch (pname)
{
case GL_PATCH_VERTICES:
mState.setPatchVertices(value);
break;
default:
break;
}
}
Program *Context::getActiveLinkedProgram() const
{
Program *program = mState.getLinkedProgram(this);
if (!program)
{
ProgramPipeline *programPipelineObject = mState.getProgramPipeline();
if (programPipelineObject)
{
program = programPipelineObject->getLinkedActiveShaderProgram(this);
}
}
return program;
}
void Context::uniform1f(UniformLocation location, GLfloat x)
{
Program *program = getActiveLinkedProgram();
program->setUniform1fv(location, 1, &x);
}
void Context::uniform1fv(UniformLocation location, GLsizei count, const GLfloat *v)
{
Program *program = getActiveLinkedProgram();
program->setUniform1fv(location, count, v);
}
void Context::setUniform1iImpl(Program *program,
UniformLocation location,
GLsizei count,
const GLint *v)
{
program->setUniform1iv(this, location, count, v);
}
void Context::onSamplerUniformChange(size_t textureUnitIndex)
{
mState.onActiveTextureChange(this, textureUnitIndex);
mStateCache.onActiveTextureChange(this);
}
void Context::uniform1i(UniformLocation location, GLint x)
{
Program *program = getActiveLinkedProgram();
setUniform1iImpl(program, location, 1, &x);
}
void Context::uniform1iv(UniformLocation location, GLsizei count, const GLint *v)
{
Program *program = getActiveLinkedProgram();
setUniform1iImpl(program, location, count, v);
}
void Context::uniform2f(UniformLocation location, GLfloat x, GLfloat y)
{
GLfloat xy[2] = {x, y};
Program *program = getActiveLinkedProgram();
program->setUniform2fv(location, 1, xy);
}
void Context::uniform2fv(UniformLocation location, GLsizei count, const GLfloat *v)
{
Program *program = getActiveLinkedProgram();
program->setUniform2fv(location, count, v);
}
void Context::uniform2i(UniformLocation location, GLint x, GLint y)
{
GLint xy[2] = {x, y};
Program *program = getActiveLinkedProgram();
program->setUniform2iv(location, 1, xy);
}
void Context::uniform2iv(UniformLocation location, GLsizei count, const GLint *v)
{
Program *program = getActiveLinkedProgram();
program->setUniform2iv(location, count, v);
}
void Context::uniform3f(UniformLocation location, GLfloat x, GLfloat y, GLfloat z)
{
GLfloat xyz[3] = {x, y, z};
Program *program = getActiveLinkedProgram();
program->setUniform3fv(location, 1, xyz);
}
void Context::uniform3fv(UniformLocation location, GLsizei count, const GLfloat *v)
{
Program *program = getActiveLinkedProgram();
program->setUniform3fv(location, count, v);
}
void Context::uniform3i(UniformLocation location, GLint x, GLint y, GLint z)
{
GLint xyz[3] = {x, y, z};
Program *program = getActiveLinkedProgram();
program->setUniform3iv(location, 1, xyz);
}
void Context::uniform3iv(UniformLocation location, GLsizei count, const GLint *v)
{
Program *program = getActiveLinkedProgram();
program->setUniform3iv(location, count, v);
}
void Context::uniform4f(UniformLocation location, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
{
GLfloat xyzw[4] = {x, y, z, w};
Program *program = getActiveLinkedProgram();
program->setUniform4fv(location, 1, xyzw);
}
void Context::uniform4fv(UniformLocation location, GLsizei count, const GLfloat *v)
{
Program *program = getActiveLinkedProgram();
program->setUniform4fv(location, count, v);
}
void Context::uniform4i(UniformLocation location, GLint x, GLint y, GLint z, GLint w)
{
GLint xyzw[4] = {x, y, z, w};
Program *program = getActiveLinkedProgram();
program->setUniform4iv(location, 1, xyzw);
}
void Context::uniform4iv(UniformLocation location, GLsizei count, const GLint *v)
{
Program *program = getActiveLinkedProgram();
program->setUniform4iv(location, count, v);
}
void Context::uniformMatrix2fv(UniformLocation location,
GLsizei count,
GLboolean transpose,
const GLfloat *value)
{
Program *program = getActiveLinkedProgram();
program->setUniformMatrix2fv(location, count, transpose, value);
}
void Context::uniformMatrix3fv(UniformLocation location,
GLsizei count,
GLboolean transpose,
const GLfloat *value)
{
Program *program = getActiveLinkedProgram();
program->setUniformMatrix3fv(location, count, transpose, value);
}
void Context::uniformMatrix4fv(UniformLocation location,
GLsizei count,
GLboolean transpose,
const GLfloat *value)
{
Program *program = getActiveLinkedProgram();
program->setUniformMatrix4fv(location, count, transpose, value);
}
void Context::validateProgram(ShaderProgramID program)
{
Program *programObject = getProgramResolveLink(program);
ASSERT(programObject);
programObject->validate(mState.mCaps);
}
void Context::validateProgramPipeline(ProgramPipelineID pipeline)
{
if (!getProgramPipeline(pipeline))
{
return;
}
ProgramPipeline *programPipeline =
mState.mProgramPipelineManager->checkProgramPipelineAllocation(mImplementation.get(),
pipeline);
ASSERT(programPipeline);
programPipeline->validate(this);
}
void Context::getProgramBinary(ShaderProgramID program,
GLsizei bufSize,
GLsizei *length,
GLenum *binaryFormat,
void *binary)
{
Program *programObject = getProgramResolveLink(program);
ASSERT(programObject != nullptr);
ANGLE_CONTEXT_TRY(programObject->saveBinary(this, binaryFormat, binary, bufSize, length));
}
void Context::programBinary(ShaderProgramID program,
GLenum binaryFormat,
const void *binary,
GLsizei length)
{
Program *programObject = getProgramResolveLink(program);
ASSERT(programObject != nullptr);
ANGLE_CONTEXT_TRY(programObject->loadBinary(this, binaryFormat, binary, length));
ANGLE_CONTEXT_TRY(onProgramLink(programObject));
}
void Context::uniform1ui(UniformLocation location, GLuint v0)
{
Program *program = getActiveLinkedProgram();
program->setUniform1uiv(location, 1, &v0);
}
void Context::uniform2ui(UniformLocation location, GLuint v0, GLuint v1)
{
Program *program = getActiveLinkedProgram();
const GLuint xy[] = {v0, v1};
program->setUniform2uiv(location, 1, xy);
}
void Context::uniform3ui(UniformLocation location, GLuint v0, GLuint v1, GLuint v2)
{
Program *program = getActiveLinkedProgram();
const GLuint xyz[] = {v0, v1, v2};
program->setUniform3uiv(location, 1, xyz);
}
void Context::uniform4ui(UniformLocation location, GLuint v0, GLuint v1, GLuint v2, GLuint v3)
{
Program *program = getActiveLinkedProgram();
const GLuint xyzw[] = {v0, v1, v2, v3};
program->setUniform4uiv(location, 1, xyzw);
}
void Context::uniform1uiv(UniformLocation location, GLsizei count, const GLuint *value)
{
Program *program = getActiveLinkedProgram();
program->setUniform1uiv(location, count, value);
}
void Context::uniform2uiv(UniformLocation location, GLsizei count, const GLuint *value)
{
Program *program = getActiveLinkedProgram();
program->setUniform2uiv(location, count, value);
}
void Context::uniform3uiv(UniformLocation location, GLsizei count, const GLuint *value)
{
Program *program = getActiveLinkedProgram();
program->setUniform3uiv(location, count, value);
}
void Context::uniform4uiv(UniformLocation location, GLsizei count, const GLuint *value)
{
Program *program = getActiveLinkedProgram();
program->setUniform4uiv(location, count, value);
}
void Context::genQueries(GLsizei n, QueryID *ids)
{
for (GLsizei i = 0; i < n; i++)
{
QueryID handle = QueryID{mQueryHandleAllocator.allocate()};
mQueryMap.assign(handle, nullptr);
ids[i] = handle;
}
}
void Context::deleteQueries(GLsizei n, const QueryID *ids)
{
for (int i = 0; i < n; i++)
{
QueryID query = ids[i];
Query *queryObject = nullptr;
if (mQueryMap.erase(query, &queryObject))
{
mQueryHandleAllocator.release(query.value);
if (queryObject)
{
queryObject->release(this);
}
}
}
}
bool Context::isQueryGenerated(QueryID query) const
{
return mQueryMap.contains(query);
}
GLboolean Context::isQuery(QueryID id) const
{
return ConvertToGLBoolean(getQuery(id) != nullptr);
}
void Context::uniformMatrix2x3fv(UniformLocation location,
GLsizei count,
GLboolean transpose,
const GLfloat *value)
{
Program *program = getActiveLinkedProgram();
program->setUniformMatrix2x3fv(location, count, transpose, value);
}
void Context::uniformMatrix3x2fv(UniformLocation location,
GLsizei count,
GLboolean transpose,
const GLfloat *value)
{
Program *program = getActiveLinkedProgram();
program->setUniformMatrix3x2fv(location, count, transpose, value);
}
void Context::uniformMatrix2x4fv(UniformLocation location,
GLsizei count,
GLboolean transpose,
const GLfloat *value)
{
Program *program = getActiveLinkedProgram();
program->setUniformMatrix2x4fv(location, count, transpose, value);
}
void Context::uniformMatrix4x2fv(UniformLocation location,
GLsizei count,
GLboolean transpose,
const GLfloat *value)
{
Program *program = getActiveLinkedProgram();
program->setUniformMatrix4x2fv(location, count, transpose, value);
}
void Context::uniformMatrix3x4fv(UniformLocation location,
GLsizei count,
GLboolean transpose,
const GLfloat *value)
{
Program *program = getActiveLinkedProgram();
program->setUniformMatrix3x4fv(location, count, transpose, value);
}
void Context::uniformMatrix4x3fv(UniformLocation location,
GLsizei count,
GLboolean transpose,
const GLfloat *value)
{
Program *program = getActiveLinkedProgram();
program->setUniformMatrix4x3fv(location, count, transpose, value);
}
void Context::deleteVertexArrays(GLsizei n, const VertexArrayID *arrays)
{
for (int arrayIndex = 0; arrayIndex < n; arrayIndex++)
{
VertexArrayID vertexArray = arrays[arrayIndex];
if (arrays[arrayIndex].value != 0)
{
VertexArray *vertexArrayObject = nullptr;
if (mVertexArrayMap.erase(vertexArray, &vertexArrayObject))
{
if (vertexArrayObject != nullptr)
{
detachVertexArray(vertexArray);
vertexArrayObject->onDestroy(this);
}
mVertexArrayHandleAllocator.release(vertexArray.value);
}
}
}
}
void Context::genVertexArrays(GLsizei n, VertexArrayID *arrays)
{
for (int arrayIndex = 0; arrayIndex < n; arrayIndex++)
{
VertexArrayID vertexArray = {mVertexArrayHandleAllocator.allocate()};
mVertexArrayMap.assign(vertexArray, nullptr);
arrays[arrayIndex] = vertexArray;
}
}
GLboolean Context::isVertexArray(VertexArrayID array) const
{
if (array.value == 0)
{
return GL_FALSE;
}
VertexArray *vao = getVertexArray(array);
return ConvertToGLBoolean(vao != nullptr);
}
void Context::endTransformFeedback()
{
TransformFeedback *transformFeedback = mState.getCurrentTransformFeedback();
ANGLE_CONTEXT_TRY(transformFeedback->end(this));
mStateCache.onActiveTransformFeedbackChange(this);
}
void Context::transformFeedbackVaryings(ShaderProgramID program,
GLsizei count,
const GLchar *const *varyings,
GLenum bufferMode)
{
Program *programObject = getProgramResolveLink(program);
ASSERT(programObject);
programObject->setTransformFeedbackVaryings(count, varyings, bufferMode);
}
void Context::getTransformFeedbackVarying(ShaderProgramID program,
GLuint index,
GLsizei bufSize,
GLsizei *length,
GLsizei *size,
GLenum *type,
GLchar *name)
{
Program *programObject = getProgramResolveLink(program);
ASSERT(programObject);
programObject->getTransformFeedbackVarying(index, bufSize, length, size, type, name);
}
void Context::deleteTransformFeedbacks(GLsizei n, const TransformFeedbackID *ids)
{
for (int i = 0; i < n; i++)
{
TransformFeedbackID transformFeedback = ids[i];
if (transformFeedback.value == 0)
{
continue;
}
TransformFeedback *transformFeedbackObject = nullptr;
if (mTransformFeedbackMap.erase(transformFeedback, &transformFeedbackObject))
{
if (transformFeedbackObject != nullptr)
{
detachTransformFeedback(transformFeedback);
transformFeedbackObject->release(this);
}
mTransformFeedbackHandleAllocator.release(transformFeedback.value);
}
}
}
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)
{
return GL_FALSE;
}
const TransformFeedback *transformFeedback = getTransformFeedback(id);
return ConvertToGLBoolean(transformFeedback != nullptr);
}
void Context::pauseTransformFeedback()
{
TransformFeedback *transformFeedback = mState.getCurrentTransformFeedback();
ANGLE_CONTEXT_TRY(transformFeedback->pause(this));
mStateCache.onActiveTransformFeedbackChange(this);
}
void Context::resumeTransformFeedback()
{
TransformFeedback *transformFeedback = mState.getCurrentTransformFeedback();
ANGLE_CONTEXT_TRY(transformFeedback->resume(this));
mStateCache.onActiveTransformFeedbackChange(this);
}
void Context::getUniformuiv(ShaderProgramID program, UniformLocation location, GLuint *params)
{
const Program *programObject = getProgramResolveLink(program);
programObject->getUniformuiv(this, location, params);
}
void Context::getUniformuivRobust(ShaderProgramID program,
UniformLocation location,
GLsizei bufSize,
GLsizei *length,
GLuint *params)
{
getUniformuiv(program, location, params);
}
GLint Context::getFragDataLocation(ShaderProgramID program, const GLchar *name)
{
const Program *programObject = getProgramResolveLink(program);
return programObject->getFragDataLocation(name);
}
void Context::getUniformIndices(ShaderProgramID program,
GLsizei uniformCount,
const GLchar *const *uniformNames,
GLuint *uniformIndices)
{
const Program *programObject = getProgramResolveLink(program);
if (!programObject->isLinked())
{
for (int uniformId = 0; uniformId < uniformCount; uniformId++)
{
uniformIndices[uniformId] = GL_INVALID_INDEX;
}
}
else
{
for (int uniformId = 0; uniformId < uniformCount; uniformId++)
{
uniformIndices[uniformId] = programObject->getUniformIndex(uniformNames[uniformId]);
}
}
}
void Context::getActiveUniformsiv(ShaderProgramID program,
GLsizei uniformCount,
const GLuint *uniformIndices,
GLenum pname,
GLint *params)
{
const Program *programObject = getProgramResolveLink(program);
for (int uniformId = 0; uniformId < uniformCount; uniformId++)
{
const GLuint index = uniformIndices[uniformId];
params[uniformId] = GetUniformResourceProperty(programObject, index, pname);
}
}
GLuint Context::getUniformBlockIndex(ShaderProgramID program, const GLchar *uniformBlockName)
{
const Program *programObject = getProgramResolveLink(program);
return programObject->getUniformBlockIndex(uniformBlockName);
}
void Context::getActiveUniformBlockiv(ShaderProgramID program,
UniformBlockIndex uniformBlockIndex,
GLenum pname,
GLint *params)
{
const Program *programObject = getProgramResolveLink(program);
QueryActiveUniformBlockiv(programObject, uniformBlockIndex, pname, params);
}
void Context::getActiveUniformBlockivRobust(ShaderProgramID program,
UniformBlockIndex uniformBlockIndex,
GLenum pname,
GLsizei bufSize,
GLsizei *length,
GLint *params)
{
getActiveUniformBlockiv(program, uniformBlockIndex, pname, params);
}
void Context::getActiveUniformBlockName(ShaderProgramID program,
UniformBlockIndex uniformBlockIndex,
GLsizei bufSize,
GLsizei *length,
GLchar *uniformBlockName)
{
const Program *programObject = getProgramResolveLink(program);
programObject->getActiveUniformBlockName(uniformBlockIndex, bufSize, length, uniformBlockName);
}
void Context::uniformBlockBinding(ShaderProgramID program,
UniformBlockIndex uniformBlockIndex,
GLuint uniformBlockBinding)
{
Program *programObject = getProgramResolveLink(program);
programObject->bindUniformBlock(uniformBlockIndex, uniformBlockBinding);
if (programObject->isInUse())
{
mState.setObjectDirty(GL_PROGRAM);
mStateCache.onUniformBufferStateChange(this);
}
}
GLsync Context::fenceSync(GLenum condition, GLbitfield flags)
{
GLuint handle = mState.mSyncManager->createSync(mImplementation.get());
GLsync syncHandle = reinterpret_cast<GLsync>(static_cast<uintptr_t>(handle));
Sync *syncObject = getSync(syncHandle);
if (syncObject->set(this, condition, flags) == angle::Result::Stop)
{
deleteSync(syncHandle);
return nullptr;
}
return syncHandle;
}
GLboolean Context::isSync(GLsync sync) const
{
return (getSync(sync) != nullptr);
}
GLenum Context::clientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout)
{
Sync *syncObject = getSync(sync);
GLenum result = GL_WAIT_FAILED;
if (syncObject->clientWait(this, flags, timeout, &result) == angle::Result::Stop)
{
return GL_WAIT_FAILED;
}
return result;
}
void Context::waitSync(GLsync sync, GLbitfield flags, GLuint64 timeout)
{
Sync *syncObject = getSync(sync);
ANGLE_CONTEXT_TRY(syncObject->serverWait(this, flags, timeout));
}
void Context::getInteger64v(GLenum pname, GLint64 *params)
{
GLenum nativeType = GL_NONE;
unsigned int numParams = 0;
getQueryParameterInfo(pname, &nativeType, &numParams);
if (nativeType == GL_INT_64_ANGLEX)
{
getInteger64vImpl(pname, params);
}
else
{
CastStateValues(this, nativeType, pname, numParams, params);
}
}
void Context::getInteger64vRobust(GLenum pname, GLsizei bufSize, GLsizei *length, GLint64 *data)
{
getInteger64v(pname, data);
}
void Context::getBufferParameteri64v(BufferBinding target, GLenum pname, GLint64 *params)
{
Buffer *buffer = mState.getTargetBuffer(target);
QueryBufferParameteri64v(buffer, pname, params);
}
void Context::getBufferParameteri64vRobust(BufferBinding target,
GLenum pname,
GLsizei bufSize,
GLsizei *length,
GLint64 *params)
{
getBufferParameteri64v(target, pname, params);
}
void Context::genSamplers(GLsizei count, SamplerID *samplers)
{
for (int i = 0; i < count; i++)
{
samplers[i] = mState.mSamplerManager->createSampler();
}
}
void Context::deleteSamplers(GLsizei count, const SamplerID *samplers)
{
for (int i = 0; i < count; i++)
{
SamplerID sampler = samplers[i];
if (mState.mSamplerManager->getSampler(sampler))
{
detachSampler(sampler);
}
mState.mSamplerManager->deleteObject(this, sampler);
}
}
void Context::minSampleShading(GLfloat value)
{
mState.setMinSampleShading(value);
}
void Context::getInternalformativ(GLenum target,
GLenum internalformat,
GLenum pname,
GLsizei bufSize,
GLint *params)
{
const TextureCaps &formatCaps = mState.mTextureCaps.get(internalformat);
QueryInternalFormativ(formatCaps, pname, bufSize, params);
}
void Context::getInternalformativRobust(GLenum target,
GLenum internalformat,
GLenum pname,
GLsizei bufSize,
GLsizei *length,
GLint *params)
{
getInternalformativ(target, internalformat, pname, bufSize, params);
}
void Context::programUniform1i(ShaderProgramID program, UniformLocation location, GLint v0)
{
programUniform1iv(program, location, 1, &v0);
}
void Context::programUniform2i(ShaderProgramID program,
UniformLocation location,
GLint v0,
GLint v1)
{
GLint xy[2] = {v0, v1};
programUniform2iv(program, location, 1, xy);
}
void Context::programUniform3i(ShaderProgramID program,
UniformLocation location,
GLint v0,
GLint v1,
GLint v2)
{
GLint xyz[3] = {v0, v1, v2};
programUniform3iv(program, location, 1, xyz);
}
void Context::programUniform4i(ShaderProgramID program,
UniformLocation location,
GLint v0,
GLint v1,
GLint v2,
GLint v3)
{
GLint xyzw[4] = {v0, v1, v2, v3};
programUniform4iv(program, location, 1, xyzw);
}
void Context::programUniform1ui(ShaderProgramID program, UniformLocation location, GLuint v0)
{
programUniform1uiv(program, location, 1, &v0);
}
void Context::programUniform2ui(ShaderProgramID program,
UniformLocation location,
GLuint v0,
GLuint v1)
{
GLuint xy[2] = {v0, v1};
programUniform2uiv(program, location, 1, xy);
}
void Context::programUniform3ui(ShaderProgramID program,
UniformLocation location,
GLuint v0,
GLuint v1,
GLuint v2)
{
GLuint xyz[3] = {v0, v1, v2};
programUniform3uiv(program, location, 1, xyz);
}
void Context::programUniform4ui(ShaderProgramID program,
UniformLocation location,
GLuint v0,
GLuint v1,
GLuint v2,
GLuint v3)
{
GLuint xyzw[4] = {v0, v1, v2, v3};
programUniform4uiv(program, location, 1, xyzw);
}
void Context::programUniform1f(ShaderProgramID program, UniformLocation location, GLfloat v0)
{
programUniform1fv(program, location, 1, &v0);
}
void Context::programUniform2f(ShaderProgramID program,
UniformLocation location,
GLfloat v0,
GLfloat v1)
{
GLfloat xy[2] = {v0, v1};
programUniform2fv(program, location, 1, xy);
}
void Context::programUniform3f(ShaderProgramID program,
UniformLocation location,
GLfloat v0,
GLfloat v1,
GLfloat v2)
{
GLfloat xyz[3] = {v0, v1, v2};
programUniform3fv(program, location, 1, xyz);
}
void Context::programUniform4f(ShaderProgramID program,
UniformLocation location,
GLfloat v0,
GLfloat v1,
GLfloat v2,
GLfloat v3)
{
GLfloat xyzw[4] = {v0, v1, v2, v3};
programUniform4fv(program, location, 1, xyzw);
}
void Context::programUniform1iv(ShaderProgramID program,
UniformLocation location,
GLsizei count,
const GLint *value)
{
Program *programObject = getProgramResolveLink(program);
ASSERT(programObject);
setUniform1iImpl(programObject, location, count, value);
}
void Context::programUniform2iv(ShaderProgramID program,
UniformLocation location,
GLsizei count,
const GLint *value)
{
Program *programObject = getProgramResolveLink(program);
ASSERT(programObject);
programObject->setUniform2iv(location, count, value);
}
void Context::programUniform3iv(ShaderProgramID program,
UniformLocation location,
GLsizei count,
const GLint *value)
{
Program *programObject = getProgramResolveLink(program);
ASSERT(programObject);
programObject->setUniform3iv(location, count, value);
}
void Context::programUniform4iv(ShaderProgramID program,
UniformLocation location,
GLsizei count,
const GLint *value)
{
Program *programObject = getProgramResolveLink(program);
ASSERT(programObject);
programObject->setUniform4iv(location, count, value);
}
void Context::programUniform1uiv(ShaderProgramID program,
UniformLocation location,
GLsizei count,
const GLuint *value)
{
Program *programObject = getProgramResolveLink(program);
ASSERT(programObject);
programObject->setUniform1uiv(location, count, value);
}
void Context::programUniform2uiv(ShaderProgramID program,
UniformLocation location,
GLsizei count,
const GLuint *value)
{
Program *programObject = getProgramResolveLink(program);
ASSERT(programObject);
programObject->setUniform2uiv(location, count, value);
}
void Context::programUniform3uiv(ShaderProgramID program,
UniformLocation location,
GLsizei count,
const GLuint *value)
{
Program *programObject = getProgramResolveLink(program);
ASSERT(programObject);
programObject->setUniform3uiv(location, count, value);
}
void Context::programUniform4uiv(ShaderProgramID program,
UniformLocation location,
GLsizei count,
const GLuint *value)
{
Program *programObject = getProgramResolveLink(program);
ASSERT(programObject);
programObject->setUniform4uiv(location, count, value);
}
void Context::programUniform1fv(ShaderProgramID program,
UniformLocation location,
GLsizei count,
const GLfloat *value)
{
Program *programObject = getProgramResolveLink(program);
ASSERT(programObject);
programObject->setUniform1fv(location, count, value);
}
void Context::programUniform2fv(ShaderProgramID program,
UniformLocation location,
GLsizei count,
const GLfloat *value)
{
Program *programObject = getProgramResolveLink(program);
ASSERT(programObject);
programObject->setUniform2fv(location, count, value);
}
void Context::programUniform3fv(ShaderProgramID program,
UniformLocation location,
GLsizei count,
const GLfloat *value)
{
Program *programObject = getProgramResolveLink(program);
ASSERT(programObject);
programObject->setUniform3fv(location, count, value);
}
void Context::programUniform4fv(ShaderProgramID program,
UniformLocation location,
GLsizei count,
const GLfloat *value)
{
Program *programObject = getProgramResolveLink(program);
ASSERT(programObject);
programObject->setUniform4fv(location, count, value);
}
void Context::programUniformMatrix2fv(ShaderProgramID program,
UniformLocation location,
GLsizei count,
GLboolean transpose,
const GLfloat *value)
{
Program *programObject = getProgramResolveLink(program);
ASSERT(programObject);
programObject->setUniformMatrix2fv(location, count, transpose, value);
}
void Context::programUniformMatrix3fv(ShaderProgramID program,
UniformLocation location,
GLsizei count,
GLboolean transpose,
const GLfloat *value)
{
Program *programObject = getProgramResolveLink(program);
ASSERT(programObject);
programObject->setUniformMatrix3fv(location, count, transpose, value);
}
void Context::programUniformMatrix4fv(ShaderProgramID program,
UniformLocation location,
GLsizei count,
GLboolean transpose,
const GLfloat *value)
{
Program *programObject = getProgramResolveLink(program);
ASSERT(programObject);
programObject->setUniformMatrix4fv(location, count, transpose, value);
}
void Context::programUniformMatrix2x3fv(ShaderProgramID program,
UniformLocation location,
GLsizei count,
GLboolean transpose,
const GLfloat *value)
{
Program *programObject = getProgramResolveLink(program);
ASSERT(programObject);
programObject->setUniformMatrix2x3fv(location, count, transpose, value);
}
void Context::programUniformMatrix3x2fv(ShaderProgramID program,
UniformLocation location,
GLsizei count,
GLboolean transpose,
const GLfloat *value)
{
Program *programObject = getProgramResolveLink(program);
ASSERT(programObject);
programObject->setUniformMatrix3x2fv(location, count, transpose, value);
}
void Context::programUniformMatrix2x4fv(ShaderProgramID program,
UniformLocation location,
GLsizei count,
GLboolean transpose,
const GLfloat *value)
{
Program *programObject = getProgramResolveLink(program);
ASSERT(programObject);
programObject->setUniformMatrix2x4fv(location, count, transpose, value);
}
void Context::programUniformMatrix4x2fv(ShaderProgramID program,
UniformLocation location,
GLsizei count,
GLboolean transpose,
const GLfloat *value)
{
Program *programObject = getProgramResolveLink(program);
ASSERT(programObject);
programObject->setUniformMatrix4x2fv(location, count, transpose, value);
}
void Context::programUniformMatrix3x4fv(ShaderProgramID program,
UniformLocation location,
GLsizei count,
GLboolean transpose,
const GLfloat *value)
{
Program *programObject = getProgramResolveLink(program);
ASSERT(programObject);
programObject->setUniformMatrix3x4fv(location, count, transpose, value);
}
void Context::programUniformMatrix4x3fv(ShaderProgramID program,
UniformLocation location,
GLsizei count,
GLboolean transpose,
const GLfloat *value)
{
Program *programObject = getProgramResolveLink(program);
ASSERT(programObject);
programObject->setUniformMatrix4x3fv(location, count, transpose, value);
}
bool Context::isCurrentTransformFeedback(const TransformFeedback *tf) const
{
return mState.isCurrentTransformFeedback(tf);
}
void Context::genProgramPipelines(GLsizei count, ProgramPipelineID *pipelines)
{
for (int i = 0; i < count; i++)
{
pipelines[i] = createProgramPipeline();
}
}
void Context::deleteProgramPipelines(GLsizei count, const ProgramPipelineID *pipelines)
{
for (int i = 0; i < count; i++)
{
if (pipelines[i].value != 0)
{
deleteProgramPipeline(pipelines[i]);
}
}
}
GLboolean Context::isProgramPipeline(ProgramPipelineID pipeline) const
{
if (pipeline.value == 0)
{
return GL_FALSE;
}
if (getProgramPipeline(pipeline))
{
return GL_TRUE;
}
return GL_FALSE;
}
void Context::finishFenceNV(FenceNVID fence)
{
FenceNV *fenceObject = getFenceNV(fence);
ASSERT(fenceObject && fenceObject->isSet());
ANGLE_CONTEXT_TRY(fenceObject->finish(this));
}
void Context::getFenceivNV(FenceNVID fence, GLenum pname, GLint *params)
{
FenceNV *fenceObject = getFenceNV(fence);
ASSERT(fenceObject && fenceObject->isSet());
switch (pname)
{
case GL_FENCE_STATUS_NV:
{
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;
}
default:
UNREACHABLE();
}
}
void Context::getTranslatedShaderSource(ShaderProgramID shader,
GLsizei bufsize,
GLsizei *length,
GLchar *source)
{
Shader *shaderObject = getShader(shader);
ASSERT(shaderObject);
shaderObject->getTranslatedSourceWithDebugInfo(bufsize, length, source);
}
void Context::getnUniformfv(ShaderProgramID program,
UniformLocation location,
GLsizei bufSize,
GLfloat *params)
{
Program *programObject = getProgramResolveLink(program);
ASSERT(programObject);
programObject->getUniformfv(this, location, params);
}
void Context::getnUniformfvRobust(ShaderProgramID program,
UniformLocation location,
GLsizei bufSize,
GLsizei *length,
GLfloat *params)
{
UNIMPLEMENTED();
}
void Context::getnUniformiv(ShaderProgramID program,
UniformLocation location,
GLsizei bufSize,
GLint *params)
{
Program *programObject = getProgramResolveLink(program);
ASSERT(programObject);
programObject->getUniformiv(this, location, params);
}
void Context::getnUniformivRobust(ShaderProgramID program,
UniformLocation location,
GLsizei bufSize,
GLsizei *length,
GLint *params)
{
UNIMPLEMENTED();
}
void Context::getnUniformuivRobust(ShaderProgramID program,
UniformLocation location,
GLsizei bufSize,
GLsizei *length,
GLuint *params)
{
UNIMPLEMENTED();
}
GLboolean Context::isFenceNV(FenceNVID fence) const
{
FenceNV *fenceObject = getFenceNV(fence);
if (fenceObject == nullptr)
{
return GL_FALSE;
}
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);
}
void Context::setFenceNV(FenceNVID fence, GLenum condition)
{
ASSERT(condition == GL_ALL_COMPLETED_NV);
FenceNV *fenceObject = getFenceNV(fence);
ASSERT(fenceObject != nullptr);
ANGLE_CONTEXT_TRY(fenceObject->set(this, condition));
}
GLboolean Context::testFenceNV(FenceNVID fence)
{
FenceNV *fenceObject = getFenceNV(fence);
ASSERT(fenceObject != nullptr);
ASSERT(fenceObject->isSet() == GL_TRUE);
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]);
}
}
GLboolean Context::isMemoryObject(MemoryObjectID memoryObject) const
{
if (memoryObject.value == 0)
{
return GL_FALSE;
}
return ConvertToGLBoolean(getMemoryObject(memoryObject));
}
void Context::createMemoryObjects(GLsizei n, MemoryObjectID *memoryObjects)
{
for (int i = 0; i < n; i++)
{
memoryObjects[i] = createMemoryObject();
}
}
void Context::memoryObjectParameteriv(MemoryObjectID memory, GLenum pname, const GLint *params)
{
MemoryObject *memoryObject = getMemoryObject(memory);
ASSERT(memoryObject);
ANGLE_CONTEXT_TRY(SetMemoryObjectParameteriv(this, memoryObject, pname, params));
}
void Context::getMemoryObjectParameteriv(MemoryObjectID memory, GLenum pname, GLint *params)
{
const MemoryObject *memoryObject = getMemoryObject(memory);
ASSERT(memoryObject);
QueryMemoryObjectParameteriv(memoryObject, pname, params);
}
void Context::texStorageMem2D(TextureType target,
GLsizei levels,
GLenum internalFormat,
GLsizei width,
GLsizei height,
MemoryObjectID memory,
GLuint64 offset)
{
texStorageMemFlags2D(target, levels, internalFormat, width, height, memory, offset, 0,
std::numeric_limits<uint32_t>::max());
}
void Context::texStorageMem2DMultisample(TextureType target,
GLsizei samples,
GLenum internalFormat,
GLsizei width,
GLsizei height,
GLboolean fixedSampleLocations,
MemoryObjectID memory,
GLuint64 offset)
{
UNIMPLEMENTED();
}
void Context::texStorageMem3D(TextureType target,
GLsizei levels,
GLenum internalFormat,
GLsizei width,
GLsizei height,
GLsizei depth,
MemoryObjectID memory,
GLuint64 offset)
{
UNIMPLEMENTED();
}
void Context::texStorageMem3DMultisample(TextureType target,
GLsizei samples,
GLenum internalFormat,
GLsizei width,
GLsizei height,
GLsizei depth,
GLboolean fixedSampleLocations,
MemoryObjectID memory,
GLuint64 offset)
{
UNIMPLEMENTED();
}
void Context::bufferStorageMem(TextureType target,
GLsizeiptr size,
MemoryObjectID memory,
GLuint64 offset)
{
UNIMPLEMENTED();
}
void Context::importMemoryFd(MemoryObjectID memory, GLuint64 size, HandleType handleType, GLint fd)
{
MemoryObject *memoryObject = getMemoryObject(memory);
ASSERT(memoryObject != nullptr);
ANGLE_CONTEXT_TRY(memoryObject->importFd(this, size, handleType, fd));
}
void Context::texStorageMemFlags2D(TextureType target,
GLsizei levels,
GLenum internalFormat,
GLsizei width,
GLsizei height,
MemoryObjectID memory,
GLuint64 offset,
GLbitfield createFlags,
GLbitfield usageFlags)
{
MemoryObject *memoryObject = getMemoryObject(memory);
ASSERT(memoryObject);
Extents size(width, height, 1);
Texture *texture = getTextureByType(target);
ANGLE_CONTEXT_TRY(texture->setStorageExternalMemory(
this, target, levels, internalFormat, size, memoryObject, offset, createFlags, usageFlags));
}
void Context::texStorageMemFlags2DMultisample(TextureType target,
GLsizei samples,
GLenum internalFormat,
GLsizei width,
GLsizei height,
GLboolean fixedSampleLocations,
MemoryObjectID memory,
GLuint64 offset,
GLbitfield createFlags,
GLbitfield usageFlags)
{
UNIMPLEMENTED();
}
void Context::texStorageMemFlags3D(TextureType target,
GLsizei levels,
GLenum internalFormat,
GLsizei width,
GLsizei height,
GLsizei depth,
MemoryObjectID memory,
GLuint64 offset,
GLbitfield createFlags,
GLbitfield usageFlags)
{
UNIMPLEMENTED();
}
void Context::texStorageMemFlags3DMultisample(TextureType target,
GLsizei samples,
GLenum internalFormat,
GLsizei width,
GLsizei height,
GLsizei depth,
GLboolean fixedSampleLocations,
MemoryObjectID memory,
GLuint64 offset,
GLbitfield createFlags,
GLbitfield usageFlags)
{
UNIMPLEMENTED();
}
void Context::importMemoryZirconHandle(MemoryObjectID memory,
GLuint64 size,
HandleType handleType,
GLuint handle)
{
MemoryObject *memoryObject = getMemoryObject(memory);
ASSERT(memoryObject != nullptr);
ANGLE_CONTEXT_TRY(memoryObject->importZirconHandle(this, size, handleType, handle));
}
void Context::genSemaphores(GLsizei n, SemaphoreID *semaphores)
{
for (int i = 0; i < n; i++)
{
semaphores[i] = createSemaphore();
}
}
void Context::deleteSemaphores(GLsizei n, const SemaphoreID *semaphores)
{
for (int i = 0; i < n; i++)
{
deleteSemaphore(semaphores[i]);
}
}
GLboolean Context::isSemaphore(SemaphoreID semaphore) const
{
if (semaphore.value == 0)
{
return GL_FALSE;
}
return ConvertToGLBoolean(getSemaphore(semaphore));
}
void Context::semaphoreParameterui64v(SemaphoreID semaphore, GLenum pname, const GLuint64 *params)
{
UNIMPLEMENTED();
}
void Context::getSemaphoreParameterui64v(SemaphoreID semaphore, GLenum pname, GLuint64 *params)
{
UNIMPLEMENTED();
}
void Context::waitSemaphore(SemaphoreID semaphoreHandle,
GLuint numBufferBarriers,
const BufferID *buffers,
GLuint numTextureBarriers,
const TextureID *textures,
const GLenum *srcLayouts)
{
Semaphore *semaphore = getSemaphore(semaphoreHandle);
ASSERT(semaphore);
BufferBarrierVector bufferBarriers(numBufferBarriers);
for (GLuint bufferBarrierIdx = 0; bufferBarrierIdx < numBufferBarriers; bufferBarrierIdx++)
{
bufferBarriers[bufferBarrierIdx] = getBuffer(buffers[bufferBarrierIdx]);
}
TextureBarrierVector textureBarriers(numTextureBarriers);
for (GLuint textureBarrierIdx = 0; textureBarrierIdx < numTextureBarriers; textureBarrierIdx++)
{
textureBarriers[textureBarrierIdx].texture = getTexture(textures[textureBarrierIdx]);
textureBarriers[textureBarrierIdx].layout = srcLayouts[textureBarrierIdx];
}
ANGLE_CONTEXT_TRY(semaphore->wait(this, bufferBarriers, textureBarriers));
}
void Context::signalSemaphore(SemaphoreID semaphoreHandle,
GLuint numBufferBarriers,
const BufferID *buffers,
GLuint numTextureBarriers,
const TextureID *textures,
const GLenum *dstLayouts)
{
Semaphore *semaphore = getSemaphore(semaphoreHandle);
ASSERT(semaphore);
BufferBarrierVector bufferBarriers(numBufferBarriers);
for (GLuint bufferBarrierIdx = 0; bufferBarrierIdx < numBufferBarriers; bufferBarrierIdx++)
{
bufferBarriers[bufferBarrierIdx] = getBuffer(buffers[bufferBarrierIdx]);
}
TextureBarrierVector textureBarriers(numTextureBarriers);
for (GLuint textureBarrierIdx = 0; textureBarrierIdx < numTextureBarriers; textureBarrierIdx++)
{
textureBarriers[textureBarrierIdx].texture = getTexture(textures[textureBarrierIdx]);
textureBarriers[textureBarrierIdx].layout = dstLayouts[textureBarrierIdx];
}
ANGLE_CONTEXT_TRY(semaphore->signal(this, bufferBarriers, textureBarriers));
}
void Context::importSemaphoreFd(SemaphoreID semaphore, HandleType handleType, GLint fd)
{
Semaphore *semaphoreObject = getSemaphore(semaphore);
ASSERT(semaphoreObject != nullptr);
ANGLE_CONTEXT_TRY(semaphoreObject->importFd(this, handleType, fd));
}
void Context::importSemaphoreZirconHandle(SemaphoreID semaphore,
HandleType handleType,
GLuint handle)
{
Semaphore *semaphoreObject = getSemaphore(semaphore);
ASSERT(semaphoreObject != nullptr);
ANGLE_CONTEXT_TRY(semaphoreObject->importZirconHandle(this, handleType, handle));
}
void Context::eGLImageTargetTexture2D(TextureType target, GLeglImageOES image)
{
Texture *texture = getTextureByType(target);
egl::Image *imageObject = static_cast<egl::Image *>(image);
ANGLE_CONTEXT_TRY(texture->setEGLImageTarget(this, target, imageObject));
}
void Context::eGLImageTargetRenderbufferStorage(GLenum target, GLeglImageOES image)
{
Renderbuffer *renderbuffer = mState.getCurrentRenderbuffer();
egl::Image *imageObject = static_cast<egl::Image *>(image);
ANGLE_CONTEXT_TRY(renderbuffer->setStorageEGLImageTarget(this, imageObject));
}
void Context::framebufferFetchBarrier()
{
mImplementation->framebufferFetchBarrier();
}
void Context::texStorage1D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width)
{
UNIMPLEMENTED();
}
bool Context::getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *numParams) const
{
return GetQueryParameterInfo(mState, pname, type, numParams);
}
bool Context::getIndexedQueryParameterInfo(GLenum target,
GLenum *type,
unsigned int *numParams) const
{
if (getClientVersion() < Version(3, 0))
{
return false;
}
switch (target)
{
case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING:
case GL_UNIFORM_BUFFER_BINDING:
{
*type = GL_INT;
*numParams = 1;
return true;
}
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;
return true;
}
}
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;
return true;
}
case GL_COLOR_WRITEMASK:
{
*type = GL_BOOL;
*numParams = 4;
return true;
}
}
}
if (getClientVersion() < Version(3, 1))
{
return false;
}
switch (target)
{
case GL_IMAGE_BINDING_LAYERED:
{
*type = GL_BOOL;
*numParams = 1;
return true;
}
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;
return true;
}
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;
return true;
}
}
return false;
}
Program *Context::getProgramNoResolveLink(ShaderProgramID handle) const
{
return mState.mShaderProgramManager->getProgram(handle);
}
Shader *Context::getShader(ShaderProgramID handle) const
{
return mState.mShaderProgramManager->getShader(handle);
}
const angle::FrontendFeatures &Context::getFrontendFeatures() const
{
return mDisplay->getFrontendFeatures();
}
bool Context::isRenderbufferGenerated(RenderbufferID renderbuffer) const
{
return mState.mRenderbufferManager->isHandleGenerated(renderbuffer);
}
bool Context::isFramebufferGenerated(FramebufferID framebuffer) const
{
return mState.mFramebufferManager->isHandleGenerated(framebuffer);
}
bool Context::isProgramPipelineGenerated(ProgramPipelineID pipeline) const
{
return mState.mProgramPipelineManager->isHandleGenerated(pipeline);
}
bool Context::usingDisplayTextureShareGroup() const
{
return mDisplayTextureShareGroup;
}
bool Context::usingDisplaySemaphoreShareGroup() const
{
return mDisplaySemaphoreShareGroup;
}
GLenum Context::getConvertedRenderbufferFormat(GLenum internalformat) const
{
if (mState.mExtensions.webglCompatibility && mState.mClientVersion.major == 2 &&
internalformat == GL_DEPTH_STENCIL)
{
return GL_DEPTH24_STENCIL8;
}
if (getClientType() == EGL_OPENGL_API && internalformat == GL_DEPTH_COMPONENT)
{
return GL_DEPTH_COMPONENT24;
}
return internalformat;
}
void Context::maxShaderCompilerThreads(GLuint count)
{
GLuint oldCount = mState.getMaxShaderCompilerThreads();
mState.setMaxShaderCompilerThreads(count);
if ((oldCount == 0 || count == 0) && (oldCount != 0 || count != 0))
{
mThreadPool = angle::WorkerThreadPool::Create(count > 0);
}
mThreadPool->setMaxThreads(count);
mImplementation->setMaxShaderCompilerThreads(count);
}
bool Context::isGLES1() const
{
return mState.getClientVersion() < Version(2, 0);
}
void Context::onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMessage message)
{
switch (index)
{
case kVertexArraySubjectIndex:
switch (message)
{
case angle::SubjectMessage::ContentsChanged:
mState.setObjectDirty(GL_VERTEX_ARRAY);
mStateCache.onVertexArrayBufferContentsChange(this);
break;
case angle::SubjectMessage::SubjectMapped:
case angle::SubjectMessage::SubjectUnmapped:
case angle::SubjectMessage::BindingChanged:
mStateCache.onVertexArrayBufferStateChange(this);
break;
default:
break;
}
break;
case kReadFramebufferSubjectIndex:
switch (message)
{
case angle::SubjectMessage::DirtyBitsFlagged:
mState.setReadFramebufferDirty();
break;
case angle::SubjectMessage::SurfaceChanged:
mState.setReadFramebufferBindingDirty();
break;
default:
UNREACHABLE();
break;
}
break;
case kDrawFramebufferSubjectIndex:
switch (message)
{
case angle::SubjectMessage::DirtyBitsFlagged:
mState.setDrawFramebufferDirty();
mStateCache.onDrawFramebufferChange(this);
break;
case angle::SubjectMessage::SurfaceChanged:
mState.setDrawFramebufferBindingDirty();
break;
default:
UNREACHABLE();
break;
}
break;
default:
if (index < kTextureMaxSubjectIndex)
{
if (message != angle::SubjectMessage::ContentsChanged &&
message != angle::SubjectMessage::BindingChanged)
{
mState.onActiveTextureStateChange(this, index);
mStateCache.onActiveTextureChange(this);
}
}
else if (index < kImageMaxSubjectIndex)
{
mState.onImageStateChange(this, index - kImage0SubjectIndex);
if (message == angle::SubjectMessage::ContentsChanged)
{
mState.mDirtyBits.set(State::DirtyBitType::DIRTY_BIT_IMAGE_BINDINGS);
}
}
else if (index < kUniformBufferMaxSubjectIndex)
{
mState.onUniformBufferStateChange(index - kUniformBuffer0SubjectIndex);
mStateCache.onUniformBufferStateChange(this);
}
else if (index < kAtomicCounterBufferMaxSubjectIndex)
{
mState.onAtomicCounterBufferStateChange(index - kAtomicCounterBuffer0SubjectIndex);
mStateCache.onAtomicCounterBufferStateChange(this);
}
else if (index < kShaderStorageBufferMaxSubjectIndex)
{
mState.onShaderStorageBufferStateChange(index - kShaderStorageBuffer0SubjectIndex);
mStateCache.onShaderStorageBufferStateChange(this);
}
else
{
ASSERT(index < kSamplerMaxSubjectIndex);
mState.setSamplerDirty(index - kSampler0SubjectIndex);
mState.onActiveTextureStateChange(this, index - kSampler0SubjectIndex);
}
break;
}
}
angle::Result Context::onProgramLink(Program *programObject)
{
if (programObject->isInUse())
{
programObject->resolveLink(this);
if (programObject->isLinked())
{
ANGLE_TRY(mState.onProgramExecutableChange(this, programObject));
programObject->onStateChange(angle::SubjectMessage::ProgramRelinked);
}
mStateCache.onProgramExecutableChange(this);
}
return angle::Result::Continue;
}
egl::Error Context::setDefaultFramebuffer(egl::Surface *drawSurface, egl::Surface *readSurface)
{
ASSERT(mCurrentDrawSurface == nullptr);
ASSERT(mCurrentReadSurface == nullptr);
Framebuffer *newDefaultFramebuffer = nullptr;
mCurrentDrawSurface = drawSurface;
mCurrentReadSurface = readSurface;
if (drawSurface != nullptr)
{
ANGLE_TRY(drawSurface->makeCurrent(this));
newDefaultFramebuffer = drawSurface->createDefaultFramebuffer(this, readSurface);
}
else
{
newDefaultFramebuffer = new Framebuffer(this, mImplementation.get(), readSurface);
}
ASSERT(newDefaultFramebuffer);
if (readSurface && (drawSurface != readSurface))
{
ANGLE_TRY(readSurface->makeCurrent(this));
}
mState.mFramebufferManager->setDefaultFramebuffer(newDefaultFramebuffer);
if (mState.getDrawFramebuffer() == nullptr)
{
bindDrawFramebuffer(newDefaultFramebuffer->id());
}
if (mState.getReadFramebuffer() == nullptr)
{
bindReadFramebuffer(newDefaultFramebuffer->id());
}
return egl::NoError();
}
egl::Error Context::unsetDefaultFramebuffer()
{
gl::Framebuffer *defaultFramebuffer =
mState.mFramebufferManager->getFramebuffer(Framebuffer::kDefaultDrawFramebufferHandle);
if (mState.getReadFramebuffer() == defaultFramebuffer)
{
mState.setReadFramebufferBinding(nullptr);
mReadFramebufferObserverBinding.bind(nullptr);
}
if (mState.getDrawFramebuffer() == defaultFramebuffer)
{
mState.setDrawFramebufferBinding(nullptr);
mDrawFramebufferObserverBinding.bind(nullptr);
}
if (defaultFramebuffer)
{
defaultFramebuffer->onDestroy(this);
delete defaultFramebuffer;
}
mState.mFramebufferManager->setDefaultFramebuffer(nullptr);
egl::Surface *drawSurface = mCurrentDrawSurface;
egl::Surface *readSurface = mCurrentReadSurface;
mCurrentDrawSurface = nullptr;
mCurrentReadSurface = nullptr;
if (drawSurface)
{
ANGLE_TRY(drawSurface->unMakeCurrent(this));
}
if (drawSurface != readSurface)
{
ANGLE_TRY(readSurface->unMakeCurrent(this));
}
return egl::NoError();
}
void Context::onPreSwap() const
{
getShareGroup()->getFrameCaptureShared()->onEndFrame(this);
}
void Context::getTexImage(TextureTarget target,
GLint level,
GLenum format,
GLenum type,
void *pixels)
{
Texture *texture = getTextureByTarget(target);
Buffer *packBuffer = mState.getTargetBuffer(BufferBinding::PixelPack);
ANGLE_CONTEXT_TRY(texture->getTexImage(this, mState.getPackState(), packBuffer, target, level,
format, type, pixels));
}
void Context::getRenderbufferImage(GLenum target, GLenum format, GLenum type, void *pixels)
{
Renderbuffer *renderbuffer = mState.getCurrentRenderbuffer();
Buffer *packBuffer = mState.getTargetBuffer(BufferBinding::PixelPack);
ANGLE_CONTEXT_TRY(renderbuffer->getRenderbufferImage(this, mState.getPackState(), packBuffer,
format, type, pixels));
}
egl::Error Context::releaseHighPowerGPU()
{
return mImplementation->releaseHighPowerGPU(this);
}
egl::Error Context::reacquireHighPowerGPU()
{
return mImplementation->reacquireHighPowerGPU(this);
}
void Context::onGPUSwitch()
{
initRendererString();
}
std::mutex &Context::getProgramCacheMutex() const
{
return mDisplay->getProgramCacheMutex();
}
bool Context::supportsGeometryOrTesselation() const
{
return mState.getClientVersion() == ES_3_2 || mState.getExtensions().geometryShaderAny() ||
mState.getExtensions().tessellationShaderEXT;
}
void Context::dirtyAllState()
{
mState.setAllDirtyBits();
mState.setAllDirtyObjects();
mState.gles1().setAllDirty();
}
void Context::finishImmutable() const
{
ANGLE_CONTEXT_TRY(mImplementation->finish(this));
}
ErrorSet::ErrorSet(Context *context) : mContext(context) {}
ErrorSet::~ErrorSet() = default;
void ErrorSet::handleError(GLenum errorCode,
const char *message,
const char *file,
const char *function,
unsigned int line)
{
if (errorCode == GL_OUT_OF_MEMORY &&
mContext->getGraphicsResetStrategy() == GL_LOSE_CONTEXT_ON_RESET_EXT &&
mContext->getDisplay()->getFrontendFeatures().loseContextOnOutOfMemory.enabled)
{
mContext->markContextLost(GraphicsResetStatus::UnknownContextReset);
}
std::stringstream errorStream;
errorStream << "Error: " << gl::FmtHex(errorCode) << ", in " << file << ", " << function << ":"
<< line << ". " << message;
std::string formattedMessage = errorStream.str();
ASSERT(errorCode != GL_NO_ERROR);
mErrors.insert(errorCode);
mContext->getState().getDebug().insertMessage(GL_DEBUG_SOURCE_API, GL_DEBUG_TYPE_ERROR,
errorCode, GL_DEBUG_SEVERITY_HIGH, message,
gl::LOG_WARN);
}
void ErrorSet::validationError(GLenum errorCode, const char *message)
{
ASSERT(errorCode != GL_NO_ERROR);
mErrors.insert(errorCode);
mContext->getState().getDebug().insertMessage(GL_DEBUG_SOURCE_API, GL_DEBUG_TYPE_ERROR,
errorCode, GL_DEBUG_SEVERITY_HIGH, message,
gl::LOG_INFO);
}
bool ErrorSet::empty() const
{
return mErrors.empty();
}
GLenum ErrorSet::popError()
{
ASSERT(!empty());
GLenum error = *mErrors.begin();
mErrors.erase(mErrors.begin());
return error;
}
StateCache::StateCache()
: mCachedHasAnyEnabledClientAttrib(false),
mCachedNonInstancedVertexElementLimit(0),
mCachedInstancedVertexElementLimit(0),
mCachedBasicDrawStatesError(kInvalidPointer),
mCachedBasicDrawElementsError(kInvalidPointer),
mCachedTransformFeedbackActiveUnpaused(false),
mCachedCanDraw(false)
{
mCachedValidDrawModes.fill(false);
}
StateCache::~StateCache() = default;
ANGLE_INLINE void StateCache::updateVertexElementLimits(Context *context)
{
if (context->isBufferAccessValidationEnabled())
{
updateVertexElementLimitsImpl(context);
}
}
void StateCache::initialize(Context *context)
{
updateValidDrawModes(context);
updateValidBindTextureTypes(context);
updateValidDrawElementsTypes(context);
updateBasicDrawStatesError();
updateBasicDrawElementsError();
updateVertexAttribTypesValidation(context);
updateCanDraw(context);
}
void StateCache::updateActiveAttribsMask(Context *context)
{
bool isGLES1 = context->isGLES1();
const State &glState = context->getState();
if (!isGLES1 && !glState.getProgramExecutable())
{
mCachedActiveBufferedAttribsMask = AttributesMask();
mCachedActiveClientAttribsMask = AttributesMask();
mCachedActiveDefaultAttribsMask = AttributesMask();
return;
}
AttributesMask activeAttribs =
isGLES1 ? glState.gles1().getActiveAttributesMask()
: glState.getProgramExecutable()->getActiveAttribLocationsMask();
const VertexArray *vao = glState.getVertexArray();
ASSERT(vao);
const AttributesMask &clientAttribs = vao->getClientAttribsMask();
const AttributesMask &enabledAttribs = vao->getEnabledAttributesMask();
const AttributesMask &activeEnabled = activeAttribs & enabledAttribs;
mCachedActiveClientAttribsMask = activeEnabled & clientAttribs;
mCachedActiveBufferedAttribsMask = activeEnabled & ~clientAttribs;
mCachedActiveDefaultAttribsMask = activeAttribs & ~enabledAttribs;
mCachedHasAnyEnabledClientAttrib = (clientAttribs & enabledAttribs).any();
}
void StateCache::updateVertexElementLimitsImpl(Context *context)
{
ASSERT(context->isBufferAccessValidationEnabled());
const VertexArray *vao = context->getState().getVertexArray();
mCachedNonInstancedVertexElementLimit = std::numeric_limits<GLint64>::max();
mCachedInstancedVertexElementLimit = std::numeric_limits<GLint64>::max();
if (!vao || !mCachedActiveBufferedAttribsMask.any())
{
return;
}
const auto &vertexAttribs = vao->getVertexAttributes();
const auto &vertexBindings = vao->getVertexBindings();
for (size_t attributeIndex : mCachedActiveBufferedAttribsMask)
{
const VertexAttribute &attrib = vertexAttribs[attributeIndex];
const VertexBinding &binding = vertexBindings[attrib.bindingIndex];
ASSERT(context->isGLES1() ||
context->getState().getProgramExecutable()->isAttribLocationActive(attributeIndex));
GLint64 limit = attrib.getCachedElementLimit();
if (binding.getDivisor() > 0)
{
mCachedInstancedVertexElementLimit =
std::min(mCachedInstancedVertexElementLimit, limit);
}
else
{
mCachedNonInstancedVertexElementLimit =
std::min(mCachedNonInstancedVertexElementLimit, limit);
}
}
}
void StateCache::updateBasicDrawStatesError()
{
mCachedBasicDrawStatesError = kInvalidPointer;
}
void StateCache::updateBasicDrawElementsError()
{
mCachedBasicDrawElementsError = kInvalidPointer;
}
intptr_t StateCache::getBasicDrawStatesErrorImpl(const Context *context) const
{
ASSERT(mCachedBasicDrawStatesError == kInvalidPointer);
mCachedBasicDrawStatesError = reinterpret_cast<intptr_t>(ValidateDrawStates(context));
return mCachedBasicDrawStatesError;
}
intptr_t StateCache::getBasicDrawElementsErrorImpl(const Context *context) const
{
ASSERT(mCachedBasicDrawElementsError == kInvalidPointer);
mCachedBasicDrawElementsError = reinterpret_cast<intptr_t>(ValidateDrawElementsStates(context));
return mCachedBasicDrawElementsError;
}
void StateCache::onVertexArrayBindingChange(Context *context)
{
updateActiveAttribsMask(context);
updateVertexElementLimits(context);
updateBasicDrawStatesError();
updateBasicDrawElementsError();
}
void StateCache::onProgramExecutableChange(Context *context)
{
updateActiveAttribsMask(context);
updateVertexElementLimits(context);
updateBasicDrawStatesError();
updateValidDrawModes(context);
updateActiveShaderStorageBufferIndices(context);
updateActiveImageUnitIndices(context);
updateCanDraw(context);
}
void StateCache::onVertexArrayFormatChange(Context *context)
{
updateVertexElementLimits(context);
}
void StateCache::onVertexArrayBufferContentsChange(Context *context)
{
updateVertexElementLimits(context);
updateBasicDrawStatesError();
}
void StateCache::onVertexArrayStateChange(Context *context)
{
updateActiveAttribsMask(context);
updateVertexElementLimits(context);
updateBasicDrawStatesError();
updateBasicDrawElementsError();
}
void StateCache::onVertexArrayBufferStateChange(Context *context)
{
updateBasicDrawStatesError();
updateBasicDrawElementsError();
}
void StateCache::onGLES1ClientStateChange(Context *context)
{
updateActiveAttribsMask(context);
}
void StateCache::onDrawFramebufferChange(Context *context)
{
updateBasicDrawStatesError();
}
void StateCache::onContextCapChange(Context *context)
{
updateBasicDrawStatesError();
}
void StateCache::onStencilStateChange(Context *context)
{
updateBasicDrawStatesError();
}
void StateCache::onDefaultVertexAttributeChange(Context *context)
{
updateBasicDrawStatesError();
}
void StateCache::onActiveTextureChange(Context *context)
{
updateBasicDrawStatesError();
}
void StateCache::onQueryChange(Context *context)
{
updateBasicDrawStatesError();
}
void StateCache::onActiveTransformFeedbackChange(Context *context)
{
updateTransformFeedbackActiveUnpaused(context);
updateBasicDrawStatesError();
updateBasicDrawElementsError();
updateValidDrawModes(context);
}
void StateCache::onUniformBufferStateChange(Context *context)
{
updateBasicDrawStatesError();
}
void StateCache::onAtomicCounterBufferStateChange(Context *context)
{
updateBasicDrawStatesError();
}
void StateCache::onShaderStorageBufferStateChange(Context *context)
{
updateBasicDrawStatesError();
}
void StateCache::onColorMaskChange(Context *context)
{
updateBasicDrawStatesError();
}
void StateCache::onBlendFuncIndexedChange(Context *context)
{
updateBasicDrawStatesError();
}
void StateCache::setValidDrawModes(bool pointsOK,
bool linesOK,
bool trisOK,
bool lineAdjOK,
bool triAdjOK,
bool patchOK)
{
mCachedValidDrawModes[PrimitiveMode::Points] = pointsOK;
mCachedValidDrawModes[PrimitiveMode::Lines] = linesOK;
mCachedValidDrawModes[PrimitiveMode::LineLoop] = linesOK;
mCachedValidDrawModes[PrimitiveMode::LineStrip] = linesOK;
mCachedValidDrawModes[PrimitiveMode::Triangles] = trisOK;
mCachedValidDrawModes[PrimitiveMode::TriangleStrip] = trisOK;
mCachedValidDrawModes[PrimitiveMode::TriangleFan] = trisOK;
mCachedValidDrawModes[PrimitiveMode::LinesAdjacency] = lineAdjOK;
mCachedValidDrawModes[PrimitiveMode::LineStripAdjacency] = lineAdjOK;
mCachedValidDrawModes[PrimitiveMode::TrianglesAdjacency] = triAdjOK;
mCachedValidDrawModes[PrimitiveMode::TriangleStripAdjacency] = triAdjOK;
mCachedValidDrawModes[PrimitiveMode::Patches] = patchOK;
}
void StateCache::updateValidDrawModes(Context *context)
{
const State &state = context->getState();
const ProgramExecutable *programExecutable = context->getState().getProgramExecutable();
if (programExecutable && programExecutable->hasLinkedTessellationShader())
{
setValidDrawModes(false, false, false, false, false, true);
return;
}
if (mCachedTransformFeedbackActiveUnpaused)
{
TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
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))
{
setValidDrawModes(true, true, true, true, true, false);
return;
}
PrimitiveMode gsMode = programExecutable->getGeometryShaderInputPrimitiveType();
bool pointsOK = gsMode == PrimitiveMode::Points;
bool linesOK = gsMode == PrimitiveMode::Lines;
bool trisOK = gsMode == PrimitiveMode::Triangles;
bool lineAdjOK = gsMode == PrimitiveMode::LinesAdjacency;
bool triAdjOK = gsMode == PrimitiveMode::TrianglesAdjacency;
setValidDrawModes(pointsOK, linesOK, trisOK, lineAdjOK, triAdjOK, false);
}
void StateCache::updateValidBindTextureTypes(Context *context)
{
const Extensions &exts = context->getExtensions();
bool isGLES3 = context->getClientMajorVersion() >= 3;
bool isGLES31 = context->getClientVersion() >= Version(3, 1);
mCachedValidBindTextureTypes = {{
{TextureType::_2D, true},
{TextureType::_2DArray, isGLES3},
{TextureType::_2DMultisample, isGLES31 || exts.textureMultisample},
{TextureType::_2DMultisampleArray, exts.textureStorageMultisample2DArrayOES},
{TextureType::_3D, isGLES3 || exts.texture3DOES},
{TextureType::External, exts.eglImageExternalOES || exts.eglStreamConsumerExternalNV},
{TextureType::Rectangle, exts.textureRectangle},
{TextureType::CubeMap, true},
{TextureType::CubeMapArray, exts.textureCubeMapArrayAny()},
{TextureType::VideoImage, exts.webglVideoTexture},
{TextureType::Buffer, exts.textureBufferAny()},
}};
}
void StateCache::updateValidDrawElementsTypes(Context *context)
{
bool supportsUint =
(context->getClientMajorVersion() >= 3 || context->getExtensions().elementIndexUintOES);
mCachedValidDrawElementsTypes = {{
{DrawElementsType::UnsignedByte, true},
{DrawElementsType::UnsignedShort, true},
{DrawElementsType::UnsignedInt, supportsUint},
}};
}
void StateCache::updateTransformFeedbackActiveUnpaused(Context *context)
{
TransformFeedback *xfb = context->getState().getCurrentTransformFeedback();
mCachedTransformFeedbackActiveUnpaused = xfb && xfb->isActive() && !xfb->isPaused();
}
void StateCache::updateVertexAttribTypesValidation(Context *context)
{
VertexAttribTypeCase halfFloatValidity = (context->getExtensions().vertexHalfFloatOES)
? VertexAttribTypeCase::Valid
: VertexAttribTypeCase::Invalid;
VertexAttribTypeCase vertexType1010102Validity =
(context->getExtensions().vertexAttribType1010102OES) ? VertexAttribTypeCase::ValidSize3or4
: VertexAttribTypeCase::Invalid;
if (context->getClientMajorVersion() <= 2)
{
mCachedVertexAttribTypesValidation = {{
{VertexAttribType::Byte, VertexAttribTypeCase::Valid},
{VertexAttribType::Short, VertexAttribTypeCase::Valid},
{VertexAttribType::UnsignedByte, VertexAttribTypeCase::Valid},
{VertexAttribType::UnsignedShort, VertexAttribTypeCase::Valid},
{VertexAttribType::Float, VertexAttribTypeCase::Valid},
{VertexAttribType::Fixed, VertexAttribTypeCase::Valid},
{VertexAttribType::HalfFloatOES, halfFloatValidity},
}};
}
else
{
mCachedVertexAttribTypesValidation = {{
{VertexAttribType::Byte, VertexAttribTypeCase::Valid},
{VertexAttribType::Short, VertexAttribTypeCase::Valid},
{VertexAttribType::Int, VertexAttribTypeCase::Valid},
{VertexAttribType::UnsignedByte, VertexAttribTypeCase::Valid},
{VertexAttribType::UnsignedShort, VertexAttribTypeCase::Valid},
{VertexAttribType::UnsignedInt, VertexAttribTypeCase::Valid},
{VertexAttribType::Float, VertexAttribTypeCase::Valid},
{VertexAttribType::HalfFloat, VertexAttribTypeCase::Valid},
{VertexAttribType::Fixed, VertexAttribTypeCase::Valid},
{VertexAttribType::Int2101010, VertexAttribTypeCase::ValidSize4Only},
{VertexAttribType::HalfFloatOES, halfFloatValidity},
{VertexAttribType::UnsignedInt2101010, VertexAttribTypeCase::ValidSize4Only},
{VertexAttribType::Int1010102, vertexType1010102Validity},
{VertexAttribType::UnsignedInt1010102, vertexType1010102Validity},
}};
mCachedIntegerVertexAttribTypesValidation = {{
{VertexAttribType::Byte, VertexAttribTypeCase::Valid},
{VertexAttribType::Short, VertexAttribTypeCase::Valid},
{VertexAttribType::Int, VertexAttribTypeCase::Valid},
{VertexAttribType::UnsignedByte, VertexAttribTypeCase::Valid},
{VertexAttribType::UnsignedShort, VertexAttribTypeCase::Valid},
{VertexAttribType::UnsignedInt, VertexAttribTypeCase::Valid},
}};
}
}
void StateCache::updateActiveShaderStorageBufferIndices(Context *context)
{
mCachedActiveShaderStorageBufferIndices.reset();
const ProgramExecutable *executable = context->getState().getProgramExecutable();
if (executable)
{
for (const InterfaceBlock &block : executable->getShaderStorageBlocks())
{
mCachedActiveShaderStorageBufferIndices.set(block.binding);
}
}
}
void StateCache::updateActiveImageUnitIndices(Context *context)
{
mCachedActiveImageUnitIndices.reset();
const ProgramExecutable *executable = context->getState().getProgramExecutable();
if (executable)
{
for (const ImageBinding &imageBinding : executable->getImageBindings())
{
for (GLuint binding : imageBinding.boundImageUnits)
{
mCachedActiveImageUnitIndices.set(binding);
}
}
}
}
void StateCache::updateCanDraw(Context *context)
{
mCachedCanDraw =
(context->isGLES1() || (context->getState().getProgramExecutable() &&
context->getState().getProgramExecutable()->hasVertexShader()));
}
}