From a6a12d8c0fc918972c15268f749ecc7c90b95d6c Mon Sep 17 00:00:00 2001 From: Andrew Knight Date: Tue, 5 Aug 2014 12:59:44 +0300 Subject: ANGLE: upgrade to 2.1~07d49ef5350a This version of ANGLE provides partial ES3 support, numerous bug fixes, and several potentially useful vendor extensions. All patches have been rebased. The following changes are noted: 0000-General-fixes-for-ANGLE-2.1.patch contains compile fixes for the new ANGLE 0004-Make-it-possible-to-link-ANGLE-statically-for-single.patch has incorporated patch 0015. 0007-Make-DX9-DX11-mutually-exclusive.patch has been removed as it was fixed upstream. 0007-Fix-ANGLE-build-with-Microsoft-Visual-Studio-14-CTP.patch has been moved up to fill the patch number gap. 0010-ANGLE-Enable-D3D11-for-feature-level-9-cards.patch now contains patch 0014 and 0017. 0013-ANGLE-Allow-for-universal-program-binaries.patch has been removed as it is no longer relevant. 0014-ANGLE-D3D11-Fix-internal-index-buffer-for-level-9-ha.patch has been merged with patch 0010. 0015-ANGLE-Don-t-export-DLLMain-functions-for-static-buil.patch has been merged with patch 0004. 0016-ANGLE-WinRT-Call-Trim-when-application-suspends.patch has been removed and will be replaced by a follow-up patch using a different technique. 0017-ANGLE-D3D11-Don-t-use-mipmaps-in-level-9-textures.patch has been merged with patch 0010. 0018-ANGLE-WinRT-Create-swap-chain-using-physical-resolut.patch has been removed and will be replaced by a follow-up patch extending the EGL_ANGLE_window_fixed_size extension. 0019-Fix-ANGLE-build-with-Microsoft-Visual-Studio-14-CTP.patch is now patch 0007. [ChangeLog][Third-party libraries] ANGLE has been upgraded to version 2.1, bringing partial support for OpenGL ES3 over Direct3D 11, numerous bug fixes, and several new vendor extensions. Change-Id: I6d95ce1480462d67228d83c1e5c74a1706b5b21c Reviewed-by: Friedemann Kleint --- src/3rdparty/angle/src/libGLESv2/Context.cpp | 2999 +++++++++++--------------- 1 file changed, 1286 insertions(+), 1713 deletions(-) (limited to 'src/3rdparty/angle/src/libGLESv2/Context.cpp') diff --git a/src/3rdparty/angle/src/libGLESv2/Context.cpp b/src/3rdparty/angle/src/libGLESv2/Context.cpp index e651785aed..8201acda10 100644 --- a/src/3rdparty/angle/src/libGLESv2/Context.cpp +++ b/src/3rdparty/angle/src/libGLESv2/Context.cpp @@ -1,6 +1,6 @@ #include "precompiled.h" // -// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // @@ -11,19 +11,25 @@ #include "libGLESv2/Context.h" #include "libGLESv2/main.h" -#include "libGLESv2/utilities.h" +#include "common/utilities.h" +#include "libGLESv2/formatutils.h" #include "libGLESv2/Buffer.h" #include "libGLESv2/Fence.h" #include "libGLESv2/Framebuffer.h" +#include "libGLESv2/FramebufferAttachment.h" #include "libGLESv2/Renderbuffer.h" #include "libGLESv2/Program.h" #include "libGLESv2/ProgramBinary.h" #include "libGLESv2/Query.h" #include "libGLESv2/Texture.h" #include "libGLESv2/ResourceManager.h" -#include "libGLESv2/renderer/IndexDataManager.h" +#include "libGLESv2/renderer/d3d/IndexDataManager.h" #include "libGLESv2/renderer/RenderTarget.h" #include "libGLESv2/renderer/Renderer.h" +#include "libGLESv2/VertexArray.h" +#include "libGLESv2/Sampler.h" +#include "libGLESv2/validationES.h" +#include "libGLESv2/TransformFeedback.h" #include "libEGL/Surface.h" @@ -32,95 +38,17 @@ namespace gl { -static const char* makeStaticString(const std::string& str) -{ - static std::set strings; - std::set::iterator it = strings.find(str); - if (it != strings.end()) - return it->c_str(); - - return strings.insert(str).first->c_str(); -} -Context::Context(const gl::Context *shareContext, rx::Renderer *renderer, bool notifyResets, bool robustAccess) : mRenderer(renderer) +Context::Context(int clientVersion, const gl::Context *shareContext, rx::Renderer *renderer, bool notifyResets, bool robustAccess) + : mRenderer(renderer) { ASSERT(robustAccess == false); // Unimplemented - mFenceHandleAllocator.setBaseHandle(0); - - setClearColor(0.0f, 0.0f, 0.0f, 0.0f); - - mState.depthClearValue = 1.0f; - mState.stencilClearValue = 0; - - mState.rasterizer.cullFace = false; - mState.rasterizer.cullMode = GL_BACK; - mState.rasterizer.frontFace = GL_CCW; - mState.rasterizer.polygonOffsetFill = false; - mState.rasterizer.polygonOffsetFactor = 0.0f; - mState.rasterizer.polygonOffsetUnits = 0.0f; - mState.rasterizer.pointDrawMode = false; - mState.rasterizer.multiSample = false; - mState.scissorTest = false; - mState.scissor.x = 0; - mState.scissor.y = 0; - mState.scissor.width = 0; - mState.scissor.height = 0; - - mState.blend.blend = false; - mState.blend.sourceBlendRGB = GL_ONE; - mState.blend.sourceBlendAlpha = GL_ONE; - mState.blend.destBlendRGB = GL_ZERO; - mState.blend.destBlendAlpha = GL_ZERO; - mState.blend.blendEquationRGB = GL_FUNC_ADD; - mState.blend.blendEquationAlpha = GL_FUNC_ADD; - mState.blend.sampleAlphaToCoverage = false; - mState.blend.dither = true; - - mState.blendColor.red = 0; - mState.blendColor.green = 0; - mState.blendColor.blue = 0; - mState.blendColor.alpha = 0; - - mState.depthStencil.depthTest = false; - mState.depthStencil.depthFunc = GL_LESS; - mState.depthStencil.depthMask = true; - mState.depthStencil.stencilTest = false; - mState.depthStencil.stencilFunc = GL_ALWAYS; - mState.depthStencil.stencilMask = -1; - mState.depthStencil.stencilWritemask = -1; - mState.depthStencil.stencilBackFunc = GL_ALWAYS; - mState.depthStencil.stencilBackMask = - 1; - mState.depthStencil.stencilBackWritemask = -1; - mState.depthStencil.stencilFail = GL_KEEP; - mState.depthStencil.stencilPassDepthFail = GL_KEEP; - mState.depthStencil.stencilPassDepthPass = GL_KEEP; - mState.depthStencil.stencilBackFail = GL_KEEP; - mState.depthStencil.stencilBackPassDepthFail = GL_KEEP; - mState.depthStencil.stencilBackPassDepthPass = GL_KEEP; - - mState.stencilRef = 0; - mState.stencilBackRef = 0; - - mState.sampleCoverage = false; - mState.sampleCoverageValue = 1.0f; - mState.sampleCoverageInvert = false; - mState.generateMipmapHint = GL_DONT_CARE; - mState.fragmentShaderDerivativeHint = GL_DONT_CARE; - - mState.lineWidth = 1.0f; - - mState.viewport.x = 0; - mState.viewport.y = 0; - mState.viewport.width = 0; - mState.viewport.height = 0; - mState.zNear = 0.0f; - mState.zFar = 1.0f; - - mState.blend.colorMaskRed = true; - mState.blend.colorMaskGreen = true; - mState.blend.colorMaskBlue = true; - mState.blend.colorMaskAlpha = true; + initCaps(clientVersion); + + mClientVersion = clientVersion; + + mFenceNVHandleAllocator.setBaseHandle(0); if (shareContext != NULL) { @@ -138,10 +66,12 @@ Context::Context(const gl::Context *shareContext, rx::Renderer *renderer, bool n // In order that access to these initial textures not be lost, they are treated as texture // objects all of whose names are 0. - mTexture2DZero.set(new Texture2D(mRenderer, 0)); - mTextureCubeMapZero.set(new TextureCubeMap(mRenderer, 0)); + mTexture2DZero.set(new Texture2D(mRenderer->createTexture2D(), 0)); + mTextureCubeMapZero.set(new TextureCubeMap(mRenderer->createTextureCube(), 0)); + mTexture3DZero.set(new Texture3D(mRenderer->createTexture3D(), 0)); + mTexture2DArrayZero.set(new Texture2DArray(mRenderer->createTexture2DArray(), 0)); - mState.activeSampler = 0; + bindVertexArray(0); bindArrayBuffer(0); bindElementArrayBuffer(0); bindTextureCubeMap(0); @@ -150,15 +80,29 @@ Context::Context(const gl::Context *shareContext, rx::Renderer *renderer, bool n bindDrawFramebuffer(0); bindRenderbuffer(0); - mState.currentProgram = 0; - mCurrentProgramBinary.set(NULL); + bindGenericUniformBuffer(0); + for (int i = 0; i < IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS; i++) + { + bindIndexedUniformBuffer(0, i, 0, -1); + } + + bindGenericTransformFeedbackBuffer(0); + for (int i = 0; i < IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS; i++) + { + bindIndexedTransformFeedbackBuffer(0, i, 0, -1); + } - mState.packAlignment = 4; - mState.unpackAlignment = 4; - mState.packReverseRowOrder = false; + bindCopyReadBuffer(0); + bindCopyWriteBuffer(0); + bindPixelPackBuffer(0); + bindPixelUnpackBuffer(0); - mExtensionString = NULL; - mRendererString = NULL; + // [OpenGL ES 3.0.2] section 2.14.1 pg 85: + // In the initial state, a default transform feedback object is bound and treated as + // a transform feedback object with a name of zero. That object is bound any time + // BindTransformFeedback is called with id of zero + mTransformFeedbackZero.set(new TransformFeedback(0)); + bindTransformFeedback(0); mInvalidEnum = false; mInvalidValue = false; @@ -172,36 +116,33 @@ Context::Context(const gl::Context *shareContext, rx::Renderer *renderer, bool n mResetStrategy = (notifyResets ? GL_LOSE_CONTEXT_ON_RESET_EXT : GL_NO_RESET_NOTIFICATION_EXT); mRobustAccess = robustAccess; - mSupportsBGRATextures = false; - mSupportsDXT1Textures = false; - mSupportsDXT3Textures = false; - mSupportsDXT5Textures = false; - mSupportsEventQueries = false; - mSupportsOcclusionQueries = false; mNumCompressedTextureFormats = 0; + + mState.setContext(this); } Context::~Context() { - if (mState.currentProgram != 0) + GLuint currentProgram = mState.getCurrentProgramId(); + if (currentProgram != 0) { - Program *programObject = mResourceManager->getProgram(mState.currentProgram); + Program *programObject = mResourceManager->getProgram(currentProgram); if (programObject) { programObject->release(); } - mState.currentProgram = 0; + currentProgram = 0; } - mCurrentProgramBinary.set(NULL); + mState.setCurrentProgram(0, NULL); while (!mFramebufferMap.empty()) { deleteFramebuffer(mFramebufferMap.begin()->first); } - while (!mFenceMap.empty()) + while (!mFenceNVMap.empty()) { - deleteFence(mFenceMap.begin()->first); + deleteFenceNV(mFenceNVMap.begin()->first); } while (!mQueryMap.empty()) @@ -209,35 +150,26 @@ Context::~Context() deleteQuery(mQueryMap.begin()->first); } - for (int type = 0; type < TEXTURE_TYPE_COUNT; type++) - { - for (int sampler = 0; sampler < IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS; sampler++) - { - mState.samplerTexture[type][sampler].set(NULL); - } - } - - for (int type = 0; type < TEXTURE_TYPE_COUNT; type++) + while (!mVertexArrayMap.empty()) { - mIncompleteTextures[type].set(NULL); + deleteVertexArray(mVertexArrayMap.begin()->first); } - for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++) + mTransformFeedbackZero.set(NULL); + while (!mTransformFeedbackMap.empty()) { - mState.vertexAttribute[i].mBoundBuffer.set(NULL); + deleteTransformFeedback(mTransformFeedbackMap.begin()->first); } - for (int i = 0; i < QUERY_TYPE_COUNT; i++) + for (int type = 0; type < TEXTURE_TYPE_COUNT; type++) { - mState.activeQuery[i].set(NULL); + mIncompleteTextures[type].set(NULL); } - mState.arrayBuffer.set(NULL); - mState.elementArrayBuffer.set(NULL); - mState.renderbuffer.set(NULL); - mTexture2DZero.set(NULL); mTextureCubeMapZero.set(NULL); + mTexture3DZero.set(NULL); + mTexture2DArrayZero.set(NULL); mResourceManager->release(); } @@ -247,61 +179,27 @@ void Context::makeCurrent(egl::Surface *surface) if (!mHasBeenCurrent) { mMajorShaderModel = mRenderer->getMajorShaderModel(); - mMaximumPointSize = mRenderer->getMaxPointSize(); mSupportsVertexTexture = mRenderer->getVertexTextureSupport(); - mSupportsNonPower2Texture = mRenderer->getNonPower2TextureSupport(); - mSupportsInstancing = mRenderer->getInstancingSupport(); - - mMaxViewportDimension = mRenderer->getMaxViewportDimension(); - mMaxTextureDimension = std::min(std::min(mRenderer->getMaxTextureWidth(), mRenderer->getMaxTextureHeight()), - (int)gl::IMPLEMENTATION_MAX_TEXTURE_SIZE); - mMaxCubeTextureDimension = std::min(mMaxTextureDimension, (int)gl::IMPLEMENTATION_MAX_CUBE_MAP_TEXTURE_SIZE); - mMaxRenderbufferDimension = mMaxTextureDimension; - mMaxTextureLevel = log2(mMaxTextureDimension) + 1; - mMaxTextureAnisotropy = mRenderer->getTextureMaxAnisotropy(); - TRACE("MaxTextureDimension=%d, MaxCubeTextureDimension=%d, MaxRenderbufferDimension=%d, MaxTextureLevel=%d, MaxTextureAnisotropy=%f", - mMaxTextureDimension, mMaxCubeTextureDimension, mMaxRenderbufferDimension, mMaxTextureLevel, mMaxTextureAnisotropy); - - mSupportsEventQueries = mRenderer->getEventQuerySupport(); - mSupportsOcclusionQueries = mRenderer->getOcclusionQuerySupport(); - mSupportsBGRATextures = mRenderer->getBGRATextureSupport(); - mSupportsDXT1Textures = mRenderer->getDXT1TextureSupport(); - mSupportsDXT3Textures = mRenderer->getDXT3TextureSupport(); - mSupportsDXT5Textures = mRenderer->getDXT5TextureSupport(); - mSupportsFloat32Textures = mRenderer->getFloat32TextureSupport(&mSupportsFloat32LinearFilter, &mSupportsFloat32RenderableTextures); - mSupportsFloat16Textures = mRenderer->getFloat16TextureSupport(&mSupportsFloat16LinearFilter, &mSupportsFloat16RenderableTextures); - mSupportsLuminanceTextures = mRenderer->getLuminanceTextureSupport(); - mSupportsLuminanceAlphaTextures = mRenderer->getLuminanceAlphaTextureSupport(); - mSupportsDepthTextures = mRenderer->getDepthTextureSupport(); - mSupportsTextureFilterAnisotropy = mRenderer->getTextureFilterAnisotropySupport(); - mSupports32bitIndices = mRenderer->get32BitIndexSupport(); mNumCompressedTextureFormats = 0; - if (supportsDXT1Textures()) + if (mExtensions.textureCompressionDXT1) { mNumCompressedTextureFormats += 2; } - if (supportsDXT3Textures()) + if (mExtensions.textureCompressionDXT3) { mNumCompressedTextureFormats += 1; } - if (supportsDXT5Textures()) + if (mExtensions.textureCompressionDXT5) { mNumCompressedTextureFormats += 1; } - initExtensionString(); initRendererString(); + initExtensionStrings(); - mState.viewport.x = 0; - mState.viewport.y = 0; - mState.viewport.width = surface->getWidth(); - mState.viewport.height = surface->getHeight(); - - mState.scissor.x = 0; - mState.scissor.y = 0; - mState.scissor.width = surface->getWidth(); - mState.scissor.height = surface->getHeight(); + mState.setViewportParams(0, 0, surface->getWidth(), surface->getHeight()); + mState.setScissorParams(0, 0, surface->getWidth(), surface->getHeight()); mHasBeenCurrent = true; } @@ -314,6 +212,9 @@ void Context::makeCurrent(egl::Surface *surface) Framebuffer *framebufferZero = new DefaultFramebuffer(mRenderer, colorbufferZero, depthStencilbufferZero); setFramebufferZero(framebufferZero); + + // Store the current client version in the renderer + mRenderer->setCurrentClientVersion(mClientVersion); } // NOTE: this function should not assume that this context is current! @@ -329,623 +230,461 @@ bool Context::isContextLost() return mContextLost; } -void Context::setClearColor(float red, float green, float blue, float alpha) +GLuint Context::createBuffer() { - mState.colorClearValue.red = red; - mState.colorClearValue.green = green; - mState.colorClearValue.blue = blue; - mState.colorClearValue.alpha = alpha; + return mResourceManager->createBuffer(); } -void Context::setClearDepth(float depth) +GLuint Context::createProgram() { - mState.depthClearValue = depth; + return mResourceManager->createProgram(); } -void Context::setClearStencil(int stencil) +GLuint Context::createShader(GLenum type) { - mState.stencilClearValue = stencil; + return mResourceManager->createShader(type); } -void Context::setCullFace(bool enabled) +GLuint Context::createTexture() { - mState.rasterizer.cullFace = enabled; + return mResourceManager->createTexture(); } -bool Context::isCullFaceEnabled() const +GLuint Context::createRenderbuffer() { - return mState.rasterizer.cullFace; + return mResourceManager->createRenderbuffer(); } -void Context::setCullMode(GLenum mode) +GLsync Context::createFenceSync(GLenum condition) { - mState.rasterizer.cullMode = mode; -} + GLuint handle = mResourceManager->createFenceSync(); -void Context::setFrontFace(GLenum front) -{ - mState.rasterizer.frontFace = front; -} + gl::FenceSync *fenceSync = mResourceManager->getFenceSync(handle); + ASSERT(fenceSync); -void Context::setDepthTest(bool enabled) -{ - mState.depthStencil.depthTest = enabled; -} + fenceSync->set(condition); -bool Context::isDepthTestEnabled() const -{ - return mState.depthStencil.depthTest; + return reinterpret_cast(handle); } -void Context::setDepthFunc(GLenum depthFunc) +GLuint Context::createVertexArray() { - mState.depthStencil.depthFunc = depthFunc; -} + GLuint handle = mVertexArrayHandleAllocator.allocate(); -void Context::setDepthRange(float zNear, float zFar) -{ - mState.zNear = zNear; - mState.zFar = zFar; + // Although the spec states VAO state is not initialized until the object is bound, + // we create it immediately. The resulting behaviour is transparent to the application, + // since it's not currently possible to access the state until the object is bound. + VertexArray *vertexArray = new VertexArray(mRenderer->createVertexArray(), handle, MAX_VERTEX_ATTRIBS); + mVertexArrayMap[handle] = vertexArray; + return handle; } -void Context::setBlend(bool enabled) +GLuint Context::createSampler() { - mState.blend.blend = enabled; + return mResourceManager->createSampler(); } -bool Context::isBlendEnabled() const +GLuint Context::createTransformFeedback() { - return mState.blend.blend; + GLuint handle = mTransformFeedbackAllocator.allocate(); + TransformFeedback *transformFeedback = new TransformFeedback(handle); + transformFeedback->addRef(); + mTransformFeedbackMap[handle] = transformFeedback; + return handle; } -void Context::setBlendFactors(GLenum sourceRGB, GLenum destRGB, GLenum sourceAlpha, GLenum destAlpha) +// Returns an unused framebuffer name +GLuint Context::createFramebuffer() { - mState.blend.sourceBlendRGB = sourceRGB; - mState.blend.destBlendRGB = destRGB; - mState.blend.sourceBlendAlpha = sourceAlpha; - mState.blend.destBlendAlpha = destAlpha; -} + GLuint handle = mFramebufferHandleAllocator.allocate(); -void Context::setBlendColor(float red, float green, float blue, float alpha) -{ - mState.blendColor.red = red; - mState.blendColor.green = green; - mState.blendColor.blue = blue; - mState.blendColor.alpha = alpha; -} + mFramebufferMap[handle] = NULL; -void Context::setBlendEquation(GLenum rgbEquation, GLenum alphaEquation) -{ - mState.blend.blendEquationRGB = rgbEquation; - mState.blend.blendEquationAlpha = alphaEquation; + return handle; } -void Context::setStencilTest(bool enabled) +GLuint Context::createFenceNV() { - mState.depthStencil.stencilTest = enabled; -} + GLuint handle = mFenceNVHandleAllocator.allocate(); -bool Context::isStencilTestEnabled() const -{ - return mState.depthStencil.stencilTest; -} + mFenceNVMap[handle] = new FenceNV(mRenderer); -void Context::setStencilParams(GLenum stencilFunc, GLint stencilRef, GLuint stencilMask) -{ - mState.depthStencil.stencilFunc = stencilFunc; - mState.stencilRef = (stencilRef > 0) ? stencilRef : 0; - mState.depthStencil.stencilMask = stencilMask; + return handle; } -void Context::setStencilBackParams(GLenum stencilBackFunc, GLint stencilBackRef, GLuint stencilBackMask) +// Returns an unused query name +GLuint Context::createQuery() { - mState.depthStencil.stencilBackFunc = stencilBackFunc; - mState.stencilBackRef = (stencilBackRef > 0) ? stencilBackRef : 0; - mState.depthStencil.stencilBackMask = stencilBackMask; -} + GLuint handle = mQueryHandleAllocator.allocate(); -void Context::setStencilWritemask(GLuint stencilWritemask) -{ - mState.depthStencil.stencilWritemask = stencilWritemask; -} + mQueryMap[handle] = NULL; -void Context::setStencilBackWritemask(GLuint stencilBackWritemask) -{ - mState.depthStencil.stencilBackWritemask = stencilBackWritemask; + return handle; } -void Context::setStencilOperations(GLenum stencilFail, GLenum stencilPassDepthFail, GLenum stencilPassDepthPass) +void Context::deleteBuffer(GLuint buffer) { - mState.depthStencil.stencilFail = stencilFail; - mState.depthStencil.stencilPassDepthFail = stencilPassDepthFail; - mState.depthStencil.stencilPassDepthPass = stencilPassDepthPass; -} + if (mResourceManager->getBuffer(buffer)) + { + detachBuffer(buffer); + } -void Context::setStencilBackOperations(GLenum stencilBackFail, GLenum stencilBackPassDepthFail, GLenum stencilBackPassDepthPass) -{ - mState.depthStencil.stencilBackFail = stencilBackFail; - mState.depthStencil.stencilBackPassDepthFail = stencilBackPassDepthFail; - mState.depthStencil.stencilBackPassDepthPass = stencilBackPassDepthPass; + mResourceManager->deleteBuffer(buffer); } -void Context::setPolygonOffsetFill(bool enabled) +void Context::deleteShader(GLuint shader) { - mState.rasterizer.polygonOffsetFill = enabled; + mResourceManager->deleteShader(shader); } -bool Context::isPolygonOffsetFillEnabled() const +void Context::deleteProgram(GLuint program) { - return mState.rasterizer.polygonOffsetFill; + mResourceManager->deleteProgram(program); } -void Context::setPolygonOffsetParams(GLfloat factor, GLfloat units) +void Context::deleteTexture(GLuint texture) { - // An application can pass NaN values here, so handle this gracefully - mState.rasterizer.polygonOffsetFactor = factor != factor ? 0.0f : factor; - mState.rasterizer.polygonOffsetUnits = units != units ? 0.0f : units; -} + if (mResourceManager->getTexture(texture)) + { + detachTexture(texture); + } -void Context::setSampleAlphaToCoverage(bool enabled) -{ - mState.blend.sampleAlphaToCoverage = enabled; + mResourceManager->deleteTexture(texture); } -bool Context::isSampleAlphaToCoverageEnabled() const +void Context::deleteRenderbuffer(GLuint renderbuffer) { - return mState.blend.sampleAlphaToCoverage; -} + if (mResourceManager->getRenderbuffer(renderbuffer)) + { + detachRenderbuffer(renderbuffer); + } -void Context::setSampleCoverage(bool enabled) -{ - mState.sampleCoverage = enabled; + mResourceManager->deleteRenderbuffer(renderbuffer); } -bool Context::isSampleCoverageEnabled() const +void Context::deleteFenceSync(GLsync fenceSync) { - return mState.sampleCoverage; + // The spec specifies the underlying Fence object is not deleted until all current + // wait commands finish. However, since the name becomes invalid, we cannot query the fence, + // and since our API is currently designed for being called from a single thread, we can delete + // the fence immediately. + mResourceManager->deleteFenceSync(reinterpret_cast(fenceSync)); } -void Context::setSampleCoverageParams(GLclampf value, bool invert) +void Context::deleteVertexArray(GLuint vertexArray) { - mState.sampleCoverageValue = value; - mState.sampleCoverageInvert = invert; -} + auto vertexArrayObject = mVertexArrayMap.find(vertexArray); -void Context::setScissorTest(bool enabled) -{ - mState.scissorTest = enabled; -} + if (vertexArrayObject != mVertexArrayMap.end()) + { + detachVertexArray(vertexArray); -bool Context::isScissorTestEnabled() const -{ - return mState.scissorTest; + mVertexArrayHandleAllocator.release(vertexArrayObject->first); + delete vertexArrayObject->second; + mVertexArrayMap.erase(vertexArrayObject); + } } -void Context::setDither(bool enabled) +void Context::deleteSampler(GLuint sampler) { - mState.blend.dither = enabled; -} + if (mResourceManager->getSampler(sampler)) + { + detachSampler(sampler); + } -bool Context::isDitherEnabled() const -{ - return mState.blend.dither; + mResourceManager->deleteSampler(sampler); } -void Context::setLineWidth(GLfloat width) +void Context::deleteTransformFeedback(GLuint transformFeedback) { - mState.lineWidth = width; + TransformFeedbackMap::const_iterator iter = mTransformFeedbackMap.find(transformFeedback); + if (iter != mTransformFeedbackMap.end()) + { + detachTransformFeedback(transformFeedback); + mTransformFeedbackAllocator.release(transformFeedback); + iter->second->release(); + mTransformFeedbackMap.erase(iter); + } } -void Context::setGenerateMipmapHint(GLenum hint) +void Context::deleteFramebuffer(GLuint framebuffer) { - mState.generateMipmapHint = hint; -} + FramebufferMap::iterator framebufferObject = mFramebufferMap.find(framebuffer); -void Context::setFragmentShaderDerivativeHint(GLenum hint) -{ - mState.fragmentShaderDerivativeHint = hint; - // TODO: Propagate the hint to shader translator so we can write - // ddx, ddx_coarse, or ddx_fine depending on the hint. - // Ignore for now. It is valid for implementations to ignore hint. -} + if (framebufferObject != mFramebufferMap.end()) + { + detachFramebuffer(framebuffer); -void Context::setViewportParams(GLint x, GLint y, GLsizei width, GLsizei height) -{ - mState.viewport.x = x; - mState.viewport.y = y; - mState.viewport.width = width; - mState.viewport.height = height; + mFramebufferHandleAllocator.release(framebufferObject->first); + delete framebufferObject->second; + mFramebufferMap.erase(framebufferObject); + } } -void Context::setScissorParams(GLint x, GLint y, GLsizei width, GLsizei height) +void Context::deleteFenceNV(GLuint fence) { - mState.scissor.x = x; - mState.scissor.y = y; - mState.scissor.width = width; - mState.scissor.height = height; + FenceNVMap::iterator fenceObject = mFenceNVMap.find(fence); + + if (fenceObject != mFenceNVMap.end()) + { + mFenceNVHandleAllocator.release(fenceObject->first); + delete fenceObject->second; + mFenceNVMap.erase(fenceObject); + } } -void Context::setColorMask(bool red, bool green, bool blue, bool alpha) +void Context::deleteQuery(GLuint query) { - mState.blend.colorMaskRed = red; - mState.blend.colorMaskGreen = green; - mState.blend.colorMaskBlue = blue; - mState.blend.colorMaskAlpha = alpha; + QueryMap::iterator queryObject = mQueryMap.find(query); + if (queryObject != mQueryMap.end()) + { + mQueryHandleAllocator.release(queryObject->first); + if (queryObject->second) + { + queryObject->second->release(); + } + mQueryMap.erase(queryObject); + } } -void Context::setDepthMask(bool mask) +Buffer *Context::getBuffer(GLuint handle) { - mState.depthStencil.depthMask = mask; + return mResourceManager->getBuffer(handle); } -void Context::setActiveSampler(unsigned int active) +Shader *Context::getShader(GLuint handle) const { - mState.activeSampler = active; + return mResourceManager->getShader(handle); } -GLuint Context::getReadFramebufferHandle() const +Program *Context::getProgram(GLuint handle) const { - return mState.readFramebuffer; + return mResourceManager->getProgram(handle); } -GLuint Context::getDrawFramebufferHandle() const +Texture *Context::getTexture(GLuint handle) const { - return mState.drawFramebuffer; + return mResourceManager->getTexture(handle); } -GLuint Context::getRenderbufferHandle() const +Renderbuffer *Context::getRenderbuffer(GLuint handle) { - return mState.renderbuffer.id(); + return mResourceManager->getRenderbuffer(handle); } -GLuint Context::getArrayBufferHandle() const +FenceSync *Context::getFenceSync(GLsync handle) const { - return mState.arrayBuffer.id(); + return mResourceManager->getFenceSync(reinterpret_cast(handle)); } -GLuint Context::getActiveQuery(GLenum target) const +VertexArray *Context::getVertexArray(GLuint handle) const { - Query *queryObject = NULL; - - switch (target) - { - case GL_ANY_SAMPLES_PASSED_EXT: - queryObject = mState.activeQuery[QUERY_ANY_SAMPLES_PASSED].get(); - break; - case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT: - queryObject = mState.activeQuery[QUERY_ANY_SAMPLES_PASSED_CONSERVATIVE].get(); - break; - default: - ASSERT(false); - } + auto vertexArray = mVertexArrayMap.find(handle); - if (queryObject) + if (vertexArray == mVertexArrayMap.end()) { - return queryObject->id(); + return NULL; } else { - return 0; + return vertexArray->second; } } -void Context::setEnableVertexAttribArray(unsigned int attribNum, bool enabled) +Sampler *Context::getSampler(GLuint handle) const { - mState.vertexAttribute[attribNum].mArrayEnabled = enabled; + return mResourceManager->getSampler(handle); } -const VertexAttribute &Context::getVertexAttribState(unsigned int attribNum) +TransformFeedback *Context::getTransformFeedback(GLuint handle) const { - return mState.vertexAttribute[attribNum]; + if (handle == 0) + { + return mTransformFeedbackZero.get(); + } + else + { + TransformFeedbackMap::const_iterator iter = mTransformFeedbackMap.find(handle); + return (iter != mTransformFeedbackMap.end()) ? iter->second : NULL; + } } -void Context::setVertexAttribState(unsigned int attribNum, Buffer *boundBuffer, GLint size, GLenum type, bool normalized, - GLsizei stride, const void *pointer) +bool Context::isSampler(GLuint samplerName) const { - mState.vertexAttribute[attribNum].mBoundBuffer.set(boundBuffer); - mState.vertexAttribute[attribNum].mSize = size; - mState.vertexAttribute[attribNum].mType = type; - mState.vertexAttribute[attribNum].mNormalized = normalized; - mState.vertexAttribute[attribNum].mStride = stride; - mState.vertexAttribute[attribNum].mPointer = pointer; + return mResourceManager->isSampler(samplerName); } -const void *Context::getVertexAttribPointer(unsigned int attribNum) const +void Context::bindArrayBuffer(unsigned int buffer) { - return mState.vertexAttribute[attribNum].mPointer; -} + mResourceManager->checkBufferAllocation(buffer); -void Context::setPackAlignment(GLint alignment) -{ - mState.packAlignment = alignment; + mState.setArrayBufferBinding(getBuffer(buffer)); } -GLint Context::getPackAlignment() const +void Context::bindElementArrayBuffer(unsigned int buffer) { - return mState.packAlignment; + mResourceManager->checkBufferAllocation(buffer); + + mState.getVertexArray()->setElementArrayBuffer(getBuffer(buffer)); } -void Context::setUnpackAlignment(GLint alignment) +void Context::bindTexture2D(GLuint texture) { - mState.unpackAlignment = alignment; + mResourceManager->checkTextureAllocation(texture, TEXTURE_2D); + + mState.setSamplerTexture(TEXTURE_2D, getTexture(texture)); } -GLint Context::getUnpackAlignment() const +void Context::bindTextureCubeMap(GLuint texture) { - return mState.unpackAlignment; + mResourceManager->checkTextureAllocation(texture, TEXTURE_CUBE); + + mState.setSamplerTexture(TEXTURE_CUBE, getTexture(texture)); } -void Context::setPackReverseRowOrder(bool reverseRowOrder) +void Context::bindTexture3D(GLuint texture) { - mState.packReverseRowOrder = reverseRowOrder; + mResourceManager->checkTextureAllocation(texture, TEXTURE_3D); + + mState.setSamplerTexture(TEXTURE_3D, getTexture(texture)); } -bool Context::getPackReverseRowOrder() const +void Context::bindTexture2DArray(GLuint texture) { - return mState.packReverseRowOrder; + mResourceManager->checkTextureAllocation(texture, TEXTURE_2D_ARRAY); + + mState.setSamplerTexture(TEXTURE_2D_ARRAY, getTexture(texture)); } -GLuint Context::createBuffer() +void Context::bindReadFramebuffer(GLuint framebuffer) { - return mResourceManager->createBuffer(); + if (!getFramebuffer(framebuffer)) + { + mFramebufferMap[framebuffer] = new Framebuffer(mRenderer, framebuffer); + } + + mState.setReadFramebufferBinding(getFramebuffer(framebuffer)); } -GLuint Context::createProgram() +void Context::bindDrawFramebuffer(GLuint framebuffer) { - return mResourceManager->createProgram(); + if (!getFramebuffer(framebuffer)) + { + mFramebufferMap[framebuffer] = new Framebuffer(mRenderer, framebuffer); + } + + mState.setDrawFramebufferBinding(getFramebuffer(framebuffer)); } -GLuint Context::createShader(GLenum type) +void Context::bindRenderbuffer(GLuint renderbuffer) { - return mResourceManager->createShader(type); + mResourceManager->checkRenderbufferAllocation(renderbuffer); + + mState.setRenderbufferBinding(getRenderbuffer(renderbuffer)); } -GLuint Context::createTexture() +void Context::bindVertexArray(GLuint vertexArray) { - return mResourceManager->createTexture(); + if (!getVertexArray(vertexArray)) + { + VertexArray *vertexArrayObject = new VertexArray(mRenderer->createVertexArray(), vertexArray, MAX_VERTEX_ATTRIBS); + mVertexArrayMap[vertexArray] = vertexArrayObject; + } + + mState.setVertexArrayBinding(getVertexArray(vertexArray)); } -GLuint Context::createRenderbuffer() +void Context::bindSampler(GLuint textureUnit, GLuint sampler) { - return mResourceManager->createRenderbuffer(); + ASSERT(textureUnit < IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS); // TODO: Update for backend-determined array size + mResourceManager->checkSamplerAllocation(sampler); + + mState.setSamplerBinding(textureUnit, getSampler(sampler)); } -// Returns an unused framebuffer name -GLuint Context::createFramebuffer() +void Context::bindGenericUniformBuffer(GLuint buffer) { - GLuint handle = mFramebufferHandleAllocator.allocate(); - - mFramebufferMap[handle] = NULL; + mResourceManager->checkBufferAllocation(buffer); - return handle; + mState.setGenericUniformBufferBinding(getBuffer(buffer)); } -GLuint Context::createFence() +void Context::bindIndexedUniformBuffer(GLuint buffer, GLuint index, GLintptr offset, GLsizeiptr size) { - GLuint handle = mFenceHandleAllocator.allocate(); - - mFenceMap[handle] = new Fence(mRenderer); + mResourceManager->checkBufferAllocation(buffer); - return handle; + mState.setIndexedUniformBufferBinding(index, getBuffer(buffer), offset, size); } -// Returns an unused query name -GLuint Context::createQuery() +void Context::bindGenericTransformFeedbackBuffer(GLuint buffer) { - GLuint handle = mQueryHandleAllocator.allocate(); - - mQueryMap[handle] = NULL; + mResourceManager->checkBufferAllocation(buffer); - return handle; + mState.setGenericTransformFeedbackBufferBinding(getBuffer(buffer)); } -void Context::deleteBuffer(GLuint buffer) +void Context::bindIndexedTransformFeedbackBuffer(GLuint buffer, GLuint index, GLintptr offset, GLsizeiptr size) { - if (mResourceManager->getBuffer(buffer)) - { - detachBuffer(buffer); - } - - mResourceManager->deleteBuffer(buffer); + mResourceManager->checkBufferAllocation(buffer); + + mState.setIndexedTransformFeedbackBufferBinding(index, getBuffer(buffer), offset, size); } -void Context::deleteShader(GLuint shader) +void Context::bindCopyReadBuffer(GLuint buffer) { - mResourceManager->deleteShader(shader); + mResourceManager->checkBufferAllocation(buffer); + + mState.setCopyReadBufferBinding(getBuffer(buffer)); } -void Context::deleteProgram(GLuint program) +void Context::bindCopyWriteBuffer(GLuint buffer) { - mResourceManager->deleteProgram(program); + mResourceManager->checkBufferAllocation(buffer); + + mState.setCopyWriteBufferBinding(getBuffer(buffer)); } -void Context::deleteTexture(GLuint texture) +void Context::bindPixelPackBuffer(GLuint buffer) { - if (mResourceManager->getTexture(texture)) - { - detachTexture(texture); - } + mResourceManager->checkBufferAllocation(buffer); - mResourceManager->deleteTexture(texture); + mState.setPixelPackBufferBinding(getBuffer(buffer)); } -void Context::deleteRenderbuffer(GLuint renderbuffer) +void Context::bindPixelUnpackBuffer(GLuint buffer) { - if (mResourceManager->getRenderbuffer(renderbuffer)) - { - detachRenderbuffer(renderbuffer); - } - - mResourceManager->deleteRenderbuffer(renderbuffer); + mResourceManager->checkBufferAllocation(buffer); + + mState.setPixelUnpackBufferBinding(getBuffer(buffer)); } -void Context::deleteFramebuffer(GLuint framebuffer) +void Context::useProgram(GLuint program) { - FramebufferMap::iterator framebufferObject = mFramebufferMap.find(framebuffer); + GLuint priorProgramId = mState.getCurrentProgramId(); + Program *priorProgram = mResourceManager->getProgram(priorProgramId); - if (framebufferObject != mFramebufferMap.end()) + if (priorProgramId != program) { - detachFramebuffer(framebuffer); + mState.setCurrentProgram(program, mResourceManager->getProgram(program)); - mFramebufferHandleAllocator.release(framebufferObject->first); - delete framebufferObject->second; - mFramebufferMap.erase(framebufferObject); + if (priorProgram) + { + priorProgram->release(); + } } } -void Context::deleteFence(GLuint fence) +void Context::linkProgram(GLuint program) { - FenceMap::iterator fenceObject = mFenceMap.find(fence); - - if (fenceObject != mFenceMap.end()) - { - mFenceHandleAllocator.release(fenceObject->first); - delete fenceObject->second; - mFenceMap.erase(fenceObject); - } -} - -void Context::deleteQuery(GLuint query) -{ - QueryMap::iterator queryObject = mQueryMap.find(query); - if (queryObject != mQueryMap.end()) - { - mQueryHandleAllocator.release(queryObject->first); - if (queryObject->second) - { - queryObject->second->release(); - } - mQueryMap.erase(queryObject); - } -} - -Buffer *Context::getBuffer(GLuint handle) -{ - return mResourceManager->getBuffer(handle); -} - -Shader *Context::getShader(GLuint handle) -{ - return mResourceManager->getShader(handle); -} - -Program *Context::getProgram(GLuint handle) -{ - return mResourceManager->getProgram(handle); -} - -Texture *Context::getTexture(GLuint handle) -{ - return mResourceManager->getTexture(handle); -} - -Renderbuffer *Context::getRenderbuffer(GLuint handle) -{ - return mResourceManager->getRenderbuffer(handle); -} - -Framebuffer *Context::getReadFramebuffer() -{ - return getFramebuffer(mState.readFramebuffer); -} - -Framebuffer *Context::getDrawFramebuffer() -{ - return mBoundDrawFramebuffer; -} - -void Context::bindArrayBuffer(unsigned int buffer) -{ - mResourceManager->checkBufferAllocation(buffer); - - mState.arrayBuffer.set(getBuffer(buffer)); -} - -void Context::bindElementArrayBuffer(unsigned int buffer) -{ - mResourceManager->checkBufferAllocation(buffer); - - mState.elementArrayBuffer.set(getBuffer(buffer)); -} - -void Context::bindTexture2D(GLuint texture) -{ - mResourceManager->checkTextureAllocation(texture, TEXTURE_2D); - - mState.samplerTexture[TEXTURE_2D][mState.activeSampler].set(getTexture(texture)); -} - -void Context::bindTextureCubeMap(GLuint texture) -{ - mResourceManager->checkTextureAllocation(texture, TEXTURE_CUBE); - - mState.samplerTexture[TEXTURE_CUBE][mState.activeSampler].set(getTexture(texture)); -} - -void Context::bindReadFramebuffer(GLuint framebuffer) -{ - if (!getFramebuffer(framebuffer)) - { - mFramebufferMap[framebuffer] = new Framebuffer(mRenderer); - } - - mState.readFramebuffer = framebuffer; -} - -void Context::bindDrawFramebuffer(GLuint framebuffer) -{ - if (!getFramebuffer(framebuffer)) - { - mFramebufferMap[framebuffer] = new Framebuffer(mRenderer); - } - - mState.drawFramebuffer = framebuffer; - - mBoundDrawFramebuffer = getFramebuffer(framebuffer); -} - -void Context::bindRenderbuffer(GLuint renderbuffer) -{ - mResourceManager->checkRenderbufferAllocation(renderbuffer); - - mState.renderbuffer.set(getRenderbuffer(renderbuffer)); -} - -void Context::useProgram(GLuint program) -{ - GLuint priorProgram = mState.currentProgram; - mState.currentProgram = program; // Must switch before trying to delete, otherwise it only gets flagged. - - if (priorProgram != program) - { - Program *newProgram = mResourceManager->getProgram(program); - Program *oldProgram = mResourceManager->getProgram(priorProgram); - mCurrentProgramBinary.set(NULL); - - if (newProgram) - { - newProgram->addRef(); - mCurrentProgramBinary.set(newProgram->getProgramBinary()); - } - - if (oldProgram) - { - oldProgram->release(); - } - } -} - -void Context::linkProgram(GLuint program) -{ - Program *programObject = mResourceManager->getProgram(program); + Program *programObject = mResourceManager->getProgram(program); bool linked = programObject->link(); // if the current program was relinked successfully we // need to install the new executables - if (linked && program == mState.currentProgram) + if (linked && program == mState.getCurrentProgramId()) { - mCurrentProgramBinary.set(programObject->getProgramBinary()); + mState.setCurrentProgramBinary(programObject->getProgramBinary()); } } @@ -957,68 +696,25 @@ void Context::setProgramBinary(GLuint program, const void *binary, GLint length) // if the current program was reloaded successfully we // need to install the new executables - if (loaded && program == mState.currentProgram) + if (loaded && program == mState.getCurrentProgramId()) { - mCurrentProgramBinary.set(programObject->getProgramBinary()); + mState.setCurrentProgramBinary(programObject->getProgramBinary()); } } -void Context::beginQuery(GLenum target, GLuint query) +void Context::bindTransformFeedback(GLuint transformFeedback) { - // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an - // of zero, if the active query object name for is non-zero (for the - // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if - // the active query for either target is non-zero), if is the name of an - // existing query object whose type does not match , or if is the - // active query object name for any query type, the error INVALID_OPERATION is - // generated. - - // Ensure no other queries are active - // NOTE: If other queries than occlusion are supported, we will need to check - // separately that: - // a) The query ID passed is not the current active query for any target/type - // b) There are no active queries for the requested target (and in the case - // of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, - // no query may be active for either if glBeginQuery targets either. - for (int i = 0; i < QUERY_TYPE_COUNT; i++) - { - if (mState.activeQuery[i].get() != NULL) - { - return gl::error(GL_INVALID_OPERATION); - } - } - - QueryType qType; - switch (target) - { - case GL_ANY_SAMPLES_PASSED_EXT: - qType = QUERY_ANY_SAMPLES_PASSED; - break; - case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT: - qType = QUERY_ANY_SAMPLES_PASSED_CONSERVATIVE; - break; - default: - ASSERT(false); - return; - } + mState.setTransformFeedbackBinding(getTransformFeedback(transformFeedback)); +} +void Context::beginQuery(GLenum target, GLuint query) +{ Query *queryObject = getQuery(query, true, target); - - // check that name was obtained with glGenQueries - if (!queryObject) - { - return gl::error(GL_INVALID_OPERATION); - } - - // check for type mismatch - if (queryObject->getType() != target) - { - return gl::error(GL_INVALID_OPERATION); - } + ASSERT(queryObject); // set query as active for specified target - mState.activeQuery[qType].set(queryObject); + mState.setActiveQuery(target, queryObject); // begin query queryObject->begin(); @@ -1026,76 +722,62 @@ void Context::beginQuery(GLenum target, GLuint query) void Context::endQuery(GLenum target) { - QueryType qType; - - switch (target) - { - case GL_ANY_SAMPLES_PASSED_EXT: - qType = QUERY_ANY_SAMPLES_PASSED; - break; - case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT: - qType = QUERY_ANY_SAMPLES_PASSED_CONSERVATIVE; - break; - default: - ASSERT(false); - return; - } - - Query *queryObject = mState.activeQuery[qType].get(); - - if (queryObject == NULL) - { - return gl::error(GL_INVALID_OPERATION); - } + Query *queryObject = mState.getActiveQuery(target); + ASSERT(queryObject); queryObject->end(); - mState.activeQuery[qType].set(NULL); + mState.setActiveQuery(target, NULL); } void Context::setFramebufferZero(Framebuffer *buffer) { - delete mFramebufferMap[0]; - mFramebufferMap[0] = buffer; - if (mState.drawFramebuffer == 0) + // First, check to see if the old default framebuffer + // was set for draw or read framebuffer, and change + // the bindings to point to the new one before deleting it. + if (mState.getDrawFramebuffer()->id() == 0) + { + mState.setDrawFramebufferBinding(buffer); + } + + if (mState.getReadFramebuffer()->id() == 0) { - mBoundDrawFramebuffer = buffer; + mState.setReadFramebufferBinding(buffer); } + + delete mFramebufferMap[0]; + mFramebufferMap[0] = buffer; } void Context::setRenderbufferStorage(GLsizei width, GLsizei height, GLenum internalformat, GLsizei samples) { + ASSERT(getTextureCaps().get(internalformat).renderable); + RenderbufferStorage *renderbuffer = NULL; - switch (internalformat) + + if (GetDepthBits(internalformat) > 0 && GetStencilBits(internalformat) > 0) + { + renderbuffer = new gl::DepthStencilbuffer(mRenderer, width, height, samples); + } + else if (GetDepthBits(internalformat) > 0) { - case GL_DEPTH_COMPONENT16: renderbuffer = new gl::Depthbuffer(mRenderer, width, height, samples); - break; - case GL_RGBA4: - case GL_RGB5_A1: - case GL_RGB565: - case GL_RGB8_OES: - case GL_RGBA8_OES: - case GL_BGRA8_EXT: - renderbuffer = new gl::Colorbuffer(mRenderer,width, height, internalformat, samples); - break; - case GL_STENCIL_INDEX8: + } + else if (GetStencilBits(internalformat) > 0) + { renderbuffer = new gl::Stencilbuffer(mRenderer, width, height, samples); - break; - case GL_DEPTH24_STENCIL8_OES: - renderbuffer = new gl::DepthStencilbuffer(mRenderer, width, height, samples); - break; - default: - UNREACHABLE(); return; + } + else + { + renderbuffer = new gl::Colorbuffer(mRenderer, width, height, internalformat, samples); } - Renderbuffer *renderbufferObject = mState.renderbuffer.get(); - renderbufferObject->setStorage(renderbuffer); + mState.getCurrentRenderbuffer()->setStorage(renderbuffer); } -Framebuffer *Context::getFramebuffer(unsigned int handle) +Framebuffer *Context::getFramebuffer(unsigned int handle) const { - FramebufferMap::iterator framebuffer = mFramebufferMap.find(handle); + FramebufferMap::const_iterator framebuffer = mFramebufferMap.find(handle); if (framebuffer == mFramebufferMap.end()) { @@ -1107,11 +789,11 @@ Framebuffer *Context::getFramebuffer(unsigned int handle) } } -Fence *Context::getFence(unsigned int handle) +FenceNV *Context::getFenceNV(unsigned int handle) { - FenceMap::iterator fence = mFenceMap.find(handle); + FenceNVMap::iterator fence = mFenceNVMap.find(handle); - if (fence == mFenceMap.end()) + if (fence == mFenceNVMap.end()) { return NULL; } @@ -1140,390 +822,248 @@ Query *Context::getQuery(unsigned int handle, bool create, GLenum type) } } -Buffer *Context::getArrayBuffer() +Texture *Context::getTargetTexture(GLenum target) const { - return mState.arrayBuffer.get(); + if (!ValidTextureTarget(this, target)) + { + return NULL; + } + + switch (target) + { + case GL_TEXTURE_2D: return getTexture2D(); + case GL_TEXTURE_CUBE_MAP: return getTextureCubeMap(); + case GL_TEXTURE_3D: return getTexture3D(); + case GL_TEXTURE_2D_ARRAY: return getTexture2DArray(); + default: return NULL; + } } -Buffer *Context::getElementArrayBuffer() +Texture2D *Context::getTexture2D() const { - return mState.elementArrayBuffer.get(); + return static_cast(getSamplerTexture(mState.getActiveSampler(), TEXTURE_2D)); } -ProgramBinary *Context::getCurrentProgramBinary() +TextureCubeMap *Context::getTextureCubeMap() const { - return mCurrentProgramBinary.get(); + return static_cast(getSamplerTexture(mState.getActiveSampler(), TEXTURE_CUBE)); } -Texture2D *Context::getTexture2D() +Texture3D *Context::getTexture3D() const { - return static_cast(getSamplerTexture(mState.activeSampler, TEXTURE_2D)); + return static_cast(getSamplerTexture(mState.getActiveSampler(), TEXTURE_3D)); } -TextureCubeMap *Context::getTextureCubeMap() +Texture2DArray *Context::getTexture2DArray() const { - return static_cast(getSamplerTexture(mState.activeSampler, TEXTURE_CUBE)); + return static_cast(getSamplerTexture(mState.getActiveSampler(), TEXTURE_2D_ARRAY)); } -Texture *Context::getSamplerTexture(unsigned int sampler, TextureType type) +Texture *Context::getSamplerTexture(unsigned int sampler, TextureType type) const { - GLuint texid = mState.samplerTexture[type][sampler].id(); - - if (texid == 0) // Special case: 0 refers to different initial textures based on the target + if (mState.getSamplerTextureId(sampler, type) == 0) { switch (type) { default: UNREACHABLE(); - case TEXTURE_2D: return mTexture2DZero.get(); - case TEXTURE_CUBE: return mTextureCubeMapZero.get(); + case TEXTURE_2D: return mTexture2DZero.get(); + case TEXTURE_CUBE: return mTextureCubeMapZero.get(); + case TEXTURE_3D: return mTexture3DZero.get(); + case TEXTURE_2D_ARRAY: return mTexture2DArrayZero.get(); } } - - return mState.samplerTexture[type][sampler].get(); + else + { + return mState.getSamplerTexture(sampler, type); + } } -bool Context::getBooleanv(GLenum pname, GLboolean *params) +void Context::getBooleanv(GLenum pname, GLboolean *params) { switch (pname) { case GL_SHADER_COMPILER: *params = GL_TRUE; break; - case GL_SAMPLE_COVERAGE_INVERT: *params = mState.sampleCoverageInvert; break; - case GL_DEPTH_WRITEMASK: *params = mState.depthStencil.depthMask; break; - case GL_COLOR_WRITEMASK: - params[0] = mState.blend.colorMaskRed; - params[1] = mState.blend.colorMaskGreen; - params[2] = mState.blend.colorMaskBlue; - params[3] = mState.blend.colorMaskAlpha; - break; - case GL_CULL_FACE: *params = mState.rasterizer.cullFace; break; - case GL_POLYGON_OFFSET_FILL: *params = mState.rasterizer.polygonOffsetFill; break; - case GL_SAMPLE_ALPHA_TO_COVERAGE: *params = mState.blend.sampleAlphaToCoverage; break; - case GL_SAMPLE_COVERAGE: *params = mState.sampleCoverage; break; - case GL_SCISSOR_TEST: *params = mState.scissorTest; break; - case GL_STENCIL_TEST: *params = mState.depthStencil.stencilTest; break; - case GL_DEPTH_TEST: *params = mState.depthStencil.depthTest; break; - case GL_BLEND: *params = mState.blend.blend; break; - case GL_DITHER: *params = mState.blend.dither; break; case GL_CONTEXT_ROBUST_ACCESS_EXT: *params = mRobustAccess ? GL_TRUE : GL_FALSE; break; default: - return false; + mState.getBooleanv(pname, params); + break; } - - return true; } -bool Context::getFloatv(GLenum pname, GLfloat *params) +void Context::getFloatv(GLenum pname, GLfloat *params) { - // Please note: DEPTH_CLEAR_VALUE is included in our internal getFloatv implementation - // because it is stored as a float, despite the fact that the GL ES 2.0 spec names - // GetIntegerv as its native query function. As it would require conversion in any - // case, this should make no difference to the calling application. + // Queries about context capabilities and maximums are answered by Context. + // Queries about current GL state values are answered by State. switch (pname) { - case GL_LINE_WIDTH: *params = mState.lineWidth; break; - case GL_SAMPLE_COVERAGE_VALUE: *params = mState.sampleCoverageValue; break; - case GL_DEPTH_CLEAR_VALUE: *params = mState.depthClearValue; break; - case GL_POLYGON_OFFSET_FACTOR: *params = mState.rasterizer.polygonOffsetFactor; break; - case GL_POLYGON_OFFSET_UNITS: *params = mState.rasterizer.polygonOffsetUnits; break; case GL_ALIASED_LINE_WIDTH_RANGE: - params[0] = gl::ALIASED_LINE_WIDTH_RANGE_MIN; - params[1] = gl::ALIASED_LINE_WIDTH_RANGE_MAX; + params[0] = mCaps.minAliasedLineWidth; + params[1] = mCaps.maxAliasedLineWidth; break; case GL_ALIASED_POINT_SIZE_RANGE: - params[0] = gl::ALIASED_POINT_SIZE_RANGE_MIN; - params[1] = getMaximumPointSize(); - break; - case GL_DEPTH_RANGE: - params[0] = mState.zNear; - params[1] = mState.zFar; - break; - case GL_COLOR_CLEAR_VALUE: - params[0] = mState.colorClearValue.red; - params[1] = mState.colorClearValue.green; - params[2] = mState.colorClearValue.blue; - params[3] = mState.colorClearValue.alpha; - break; - case GL_BLEND_COLOR: - params[0] = mState.blendColor.red; - params[1] = mState.blendColor.green; - params[2] = mState.blendColor.blue; - params[3] = mState.blendColor.alpha; + params[0] = mCaps.minAliasedPointSize; + params[1] = mCaps.maxAliasedPointSize; break; case GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT: - if (!supportsTextureFilterAnisotropy()) - { - return false; - } - *params = mMaxTextureAnisotropy; + ASSERT(mExtensions.textureFilterAnisotropic); + *params = mExtensions.maxTextureAnisotropy; break; default: - return false; + mState.getFloatv(pname, params); + break; } - - return true; } -bool Context::getIntegerv(GLenum pname, GLint *params) +void Context::getIntegerv(GLenum pname, GLint *params) { - if (pname >= GL_DRAW_BUFFER0_EXT && pname <= GL_DRAW_BUFFER15_EXT) - { - unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0_EXT); - - if (colorAttachment >= mRenderer->getMaxRenderTargets()) - { - // return true to stop further operation in the parent call - return gl::error(GL_INVALID_OPERATION, true); - } - - Framebuffer *framebuffer = getDrawFramebuffer(); - - *params = framebuffer->getDrawBufferState(colorAttachment); - return true; - } + // Queries about context capabilities and maximums are answered by Context. + // Queries about current GL state values are answered by State. - // Please note: DEPTH_CLEAR_VALUE is not included in our internal getIntegerv implementation - // because it is stored as a float, despite the fact that the GL ES 2.0 spec names - // GetIntegerv as its native query function. As it would require conversion in any - // case, this should make no difference to the calling application. You may find it in - // Context::getFloatv. switch (pname) { - case GL_MAX_VERTEX_ATTRIBS: *params = gl::MAX_VERTEX_ATTRIBS; break; - case GL_MAX_VERTEX_UNIFORM_VECTORS: *params = mRenderer->getMaxVertexUniformVectors(); break; - case GL_MAX_VARYING_VECTORS: *params = mRenderer->getMaxVaryingVectors(); break; - case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: *params = mRenderer->getMaxCombinedTextureImageUnits(); break; - case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS: *params = mRenderer->getMaxVertexTextureImageUnits(); break; - case GL_MAX_TEXTURE_IMAGE_UNITS: *params = gl::MAX_TEXTURE_IMAGE_UNITS; break; - case GL_MAX_FRAGMENT_UNIFORM_VECTORS: *params = mRenderer->getMaxFragmentUniformVectors(); break; - case GL_MAX_RENDERBUFFER_SIZE: *params = getMaximumRenderbufferDimension(); break; - case GL_MAX_COLOR_ATTACHMENTS_EXT: *params = mRenderer->getMaxRenderTargets(); break; - case GL_MAX_DRAW_BUFFERS_EXT: *params = mRenderer->getMaxRenderTargets(); break; - case GL_NUM_SHADER_BINARY_FORMATS: *params = 0; break; - case GL_SHADER_BINARY_FORMATS: /* no shader binary formats are supported */ break; - case GL_ARRAY_BUFFER_BINDING: *params = mState.arrayBuffer.id(); break; - case GL_ELEMENT_ARRAY_BUFFER_BINDING: *params = mState.elementArrayBuffer.id(); break; - //case GL_FRAMEBUFFER_BINDING: // now equivalent to GL_DRAW_FRAMEBUFFER_BINDING_ANGLE - case GL_DRAW_FRAMEBUFFER_BINDING_ANGLE: *params = mState.drawFramebuffer; break; - case GL_READ_FRAMEBUFFER_BINDING_ANGLE: *params = mState.readFramebuffer; break; - case GL_RENDERBUFFER_BINDING: *params = mState.renderbuffer.id(); break; - case GL_CURRENT_PROGRAM: *params = mState.currentProgram; break; - case GL_PACK_ALIGNMENT: *params = mState.packAlignment; break; - case GL_PACK_REVERSE_ROW_ORDER_ANGLE: *params = mState.packReverseRowOrder; break; - case GL_UNPACK_ALIGNMENT: *params = mState.unpackAlignment; break; - case GL_GENERATE_MIPMAP_HINT: *params = mState.generateMipmapHint; break; - case GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES: *params = mState.fragmentShaderDerivativeHint; break; - case GL_ACTIVE_TEXTURE: *params = (mState.activeSampler + GL_TEXTURE0); break; - case GL_STENCIL_FUNC: *params = mState.depthStencil.stencilFunc; break; - case GL_STENCIL_REF: *params = mState.stencilRef; break; - case GL_STENCIL_VALUE_MASK: *params = mState.depthStencil.stencilMask; break; - case GL_STENCIL_BACK_FUNC: *params = mState.depthStencil.stencilBackFunc; break; - case GL_STENCIL_BACK_REF: *params = mState.stencilBackRef; break; - case GL_STENCIL_BACK_VALUE_MASK: *params = mState.depthStencil.stencilBackMask; break; - case GL_STENCIL_FAIL: *params = mState.depthStencil.stencilFail; break; - case GL_STENCIL_PASS_DEPTH_FAIL: *params = mState.depthStencil.stencilPassDepthFail; break; - case GL_STENCIL_PASS_DEPTH_PASS: *params = mState.depthStencil.stencilPassDepthPass; break; - case GL_STENCIL_BACK_FAIL: *params = mState.depthStencil.stencilBackFail; break; - case GL_STENCIL_BACK_PASS_DEPTH_FAIL: *params = mState.depthStencil.stencilBackPassDepthFail; break; - case GL_STENCIL_BACK_PASS_DEPTH_PASS: *params = mState.depthStencil.stencilBackPassDepthPass; break; - case GL_DEPTH_FUNC: *params = mState.depthStencil.depthFunc; break; - case GL_BLEND_SRC_RGB: *params = mState.blend.sourceBlendRGB; break; - case GL_BLEND_SRC_ALPHA: *params = mState.blend.sourceBlendAlpha; break; - case GL_BLEND_DST_RGB: *params = mState.blend.destBlendRGB; break; - case GL_BLEND_DST_ALPHA: *params = mState.blend.destBlendAlpha; break; - case GL_BLEND_EQUATION_RGB: *params = mState.blend.blendEquationRGB; break; - case GL_BLEND_EQUATION_ALPHA: *params = mState.blend.blendEquationAlpha; break; - case GL_STENCIL_WRITEMASK: *params = mState.depthStencil.stencilWritemask; break; - case GL_STENCIL_BACK_WRITEMASK: *params = mState.depthStencil.stencilBackWritemask; break; - case GL_STENCIL_CLEAR_VALUE: *params = mState.stencilClearValue; break; - case GL_SUBPIXEL_BITS: *params = 4; break; - case GL_MAX_TEXTURE_SIZE: *params = getMaximumTextureDimension(); break; - case GL_MAX_CUBE_MAP_TEXTURE_SIZE: *params = getMaximumCubeTextureDimension(); break; - case GL_NUM_COMPRESSED_TEXTURE_FORMATS: + case GL_MAX_VERTEX_ATTRIBS: *params = gl::MAX_VERTEX_ATTRIBS; break; + case GL_MAX_VERTEX_UNIFORM_VECTORS: *params = mRenderer->getMaxVertexUniformVectors(); break; + case GL_MAX_VERTEX_UNIFORM_COMPONENTS: *params = mRenderer->getMaxVertexUniformVectors() * 4; break; + case GL_MAX_VARYING_VECTORS: *params = mRenderer->getMaxVaryingVectors(); break; + case GL_MAX_VARYING_COMPONENTS: *params = mRenderer->getMaxVaryingVectors() * 4; break; + case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: *params = mRenderer->getMaxCombinedTextureImageUnits(); break; + case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS: *params = mRenderer->getMaxVertexTextureImageUnits(); break; + case GL_MAX_TEXTURE_IMAGE_UNITS: *params = gl::MAX_TEXTURE_IMAGE_UNITS; break; + case GL_MAX_FRAGMENT_UNIFORM_VECTORS: *params = mRenderer->getMaxFragmentUniformVectors(); break; + case GL_MAX_FRAGMENT_UNIFORM_COMPONENTS: *params = mRenderer->getMaxFragmentUniformVectors() * 4; break; + case GL_MAX_RENDERBUFFER_SIZE: *params = mCaps.maxRenderbufferSize; break; + case GL_MAX_COLOR_ATTACHMENTS_EXT: *params = mCaps.maxColorAttachments; break; + case GL_MAX_DRAW_BUFFERS_EXT: *params = mCaps.maxDrawBuffers; break; + case GL_NUM_SHADER_BINARY_FORMATS: *params = 0; break; + case GL_SHADER_BINARY_FORMATS: /* no shader binary formats are supported */ break; + //case GL_FRAMEBUFFER_BINDING: // now equivalent to GL_DRAW_FRAMEBUFFER_BINDING_ANGLE + case GL_SUBPIXEL_BITS: *params = 4; break; + case GL_MAX_TEXTURE_SIZE: *params = mCaps.max2DTextureSize; break; + case GL_MAX_CUBE_MAP_TEXTURE_SIZE: *params = mCaps.maxCubeMapTextureSize; break; + case GL_MAX_3D_TEXTURE_SIZE: *params = mCaps.max3DTextureSize; break; + case GL_MAX_ARRAY_TEXTURE_LAYERS: *params = mCaps.maxArrayTextureLayers; break; + case GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT: *params = getUniformBufferOffsetAlignment(); break; + case GL_MAX_UNIFORM_BUFFER_BINDINGS: *params = getMaximumCombinedUniformBufferBindings(); break; + case GL_MAX_VERTEX_UNIFORM_BLOCKS: *params = mRenderer->getMaxVertexShaderUniformBuffers(); break; + case GL_MAX_FRAGMENT_UNIFORM_BLOCKS: *params = mRenderer->getMaxFragmentShaderUniformBuffers(); break; + case GL_MAX_COMBINED_UNIFORM_BLOCKS: *params = getMaximumCombinedUniformBufferBindings(); break; + case GL_MAJOR_VERSION: *params = mClientVersion; break; + case GL_MINOR_VERSION: *params = 0; break; + case GL_MAX_ELEMENTS_INDICES: *params = mRenderer->getMaxRecommendedElementsIndices(); break; + case GL_MAX_ELEMENTS_VERTICES: *params = mRenderer->getMaxRecommendedElementsVertices(); break; + case GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS: *params = mRenderer->getMaxTransformFeedbackInterleavedComponents(); break; + case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS: *params = mRenderer->getMaxTransformFeedbackBuffers(); break; + case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS: *params = mRenderer->getMaxTransformFeedbackSeparateComponents(); break; + case GL_NUM_COMPRESSED_TEXTURE_FORMATS: params[0] = mNumCompressedTextureFormats; break; case GL_MAX_SAMPLES_ANGLE: - { - GLsizei maxSamples = getMaxSupportedSamples(); - if (maxSamples != 0) - { - *params = maxSamples; - } - else - { - return false; - } - - break; - } - case GL_SAMPLE_BUFFERS: - case GL_SAMPLES: - { - gl::Framebuffer *framebuffer = getDrawFramebuffer(); - if (framebuffer->completeness() == GL_FRAMEBUFFER_COMPLETE) - { - switch (pname) - { - case GL_SAMPLE_BUFFERS: - if (framebuffer->getSamples() != 0) - { - *params = 1; - } - else - { - *params = 0; - } - break; - case GL_SAMPLES: - *params = framebuffer->getSamples(); - break; - } - } - else - { - *params = 0; - } - } + *params = static_cast(getMaxSupportedSamples()); break; case GL_IMPLEMENTATION_COLOR_READ_TYPE: case GL_IMPLEMENTATION_COLOR_READ_FORMAT: { - GLenum format, type; - if (getCurrentReadFormatType(&format, &type)) - { - if (pname == GL_IMPLEMENTATION_COLOR_READ_FORMAT) - *params = format; - else - *params = type; - } + GLenum internalFormat, format, type; + getCurrentReadFormatType(&internalFormat, &format, &type); + if (pname == GL_IMPLEMENTATION_COLOR_READ_FORMAT) + *params = format; + else + *params = type; } break; case GL_MAX_VIEWPORT_DIMS: { - params[0] = mMaxViewportDimension; - params[1] = mMaxViewportDimension; + params[0] = mCaps.maxViewportWidth; + params[1] = mCaps.maxViewportHeight; } break; case GL_COMPRESSED_TEXTURE_FORMATS: { - if (supportsDXT1Textures()) + if (mExtensions.textureCompressionDXT1) { *params++ = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; *params++ = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; } - if (supportsDXT3Textures()) + if (mExtensions.textureCompressionDXT3) { *params++ = GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE; } - if (supportsDXT5Textures()) + if (mExtensions.textureCompressionDXT5) { *params++ = GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE; } } break; - case GL_VIEWPORT: - params[0] = mState.viewport.x; - params[1] = mState.viewport.y; - params[2] = mState.viewport.width; - params[3] = mState.viewport.height; + case GL_RESET_NOTIFICATION_STRATEGY_EXT: + *params = mResetStrategy; break; - case GL_SCISSOR_BOX: - params[0] = mState.scissor.x; - params[1] = mState.scissor.y; - params[2] = mState.scissor.width; - params[3] = mState.scissor.height; + case GL_NUM_PROGRAM_BINARY_FORMATS_OES: + *params = 1; break; - case GL_CULL_FACE_MODE: *params = mState.rasterizer.cullMode; break; - case GL_FRONT_FACE: *params = mState.rasterizer.frontFace; break; - case GL_RED_BITS: - case GL_GREEN_BITS: - case GL_BLUE_BITS: - case GL_ALPHA_BITS: - { - gl::Framebuffer *framebuffer = getDrawFramebuffer(); - gl::Renderbuffer *colorbuffer = framebuffer->getFirstColorbuffer(); - - if (colorbuffer) - { - switch (pname) - { - case GL_RED_BITS: *params = colorbuffer->getRedSize(); break; - case GL_GREEN_BITS: *params = colorbuffer->getGreenSize(); break; - case GL_BLUE_BITS: *params = colorbuffer->getBlueSize(); break; - case GL_ALPHA_BITS: *params = colorbuffer->getAlphaSize(); break; - } - } - else - { - *params = 0; - } - } + case GL_PROGRAM_BINARY_FORMATS_OES: + *params = GL_PROGRAM_BINARY_ANGLE; break; - case GL_DEPTH_BITS: - { - gl::Framebuffer *framebuffer = getDrawFramebuffer(); - gl::Renderbuffer *depthbuffer = framebuffer->getDepthbuffer(); - - if (depthbuffer) - { - *params = depthbuffer->getDepthSize(); - } - else - { - *params = 0; - } - } + case GL_NUM_EXTENSIONS: + *params = static_cast(mExtensionStrings.size()); break; - case GL_STENCIL_BITS: - { - gl::Framebuffer *framebuffer = getDrawFramebuffer(); - gl::Renderbuffer *stencilbuffer = framebuffer->getStencilbuffer(); + default: + mState.getIntegerv(pname, params); + break; + } +} - if (stencilbuffer) - { - *params = stencilbuffer->getStencilSize(); - } - else - { - *params = 0; - } - } +void Context::getInteger64v(GLenum pname, GLint64 *params) +{ + // Queries about context capabilities and maximums are answered by Context. + // Queries about current GL state values are answered by State. + switch (pname) + { + case GL_MAX_ELEMENT_INDEX: + *params = mCaps.maxElementIndex; break; - case GL_TEXTURE_BINDING_2D: + case GL_MAX_UNIFORM_BLOCK_SIZE: + *params = static_cast(mRenderer->getMaxUniformBufferSize()); + break; + case GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS: { - if (mState.activeSampler > mRenderer->getMaxCombinedTextureImageUnits() - 1) - { - gl::error(GL_INVALID_OPERATION); - return false; - } - - *params = mState.samplerTexture[TEXTURE_2D][mState.activeSampler].id(); + GLint64 uniformBufferComponents = static_cast(mRenderer->getMaxVertexShaderUniformBuffers()) * static_cast(mRenderer->getMaxUniformBufferSize() / 4); + GLint64 defaultBufferComponents = static_cast(mRenderer->getMaxVertexUniformVectors() * 4); + *params = uniformBufferComponents + defaultBufferComponents; } break; - case GL_TEXTURE_BINDING_CUBE_MAP: + case GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS: { - if (mState.activeSampler > mRenderer->getMaxCombinedTextureImageUnits() - 1) - { - gl::error(GL_INVALID_OPERATION); - return false; - } - - *params = mState.samplerTexture[TEXTURE_CUBE][mState.activeSampler].id(); + GLint64 uniformBufferComponents = static_cast(mRenderer->getMaxFragmentShaderUniformBuffers()) * static_cast(mRenderer->getMaxUniformBufferSize() / 4); + GLint64 defaultBufferComponents = static_cast(mRenderer->getMaxVertexUniformVectors() * 4); + *params = uniformBufferComponents + defaultBufferComponents; } break; - case GL_RESET_NOTIFICATION_STRATEGY_EXT: - *params = mResetStrategy; - break; - case GL_NUM_PROGRAM_BINARY_FORMATS_OES: - *params = 1; - break; - case GL_PROGRAM_BINARY_FORMATS_OES: - *params = GL_PROGRAM_BINARY_ANGLE; + case GL_MAX_SERVER_WAIT_TIMEOUT: + // We do not wait for server fence objects internally, so report a max timeout of zero. + *params = 0; break; default: - return false; + UNREACHABLE(); + break; } +} - return true; +bool Context::getIndexedIntegerv(GLenum target, GLuint index, GLint *data) +{ + // Queries about context capabilities and maximums are answered by Context. + // Queries about current GL state values are answered by State. + // Indexed integer queries all refer to current state, so this function is a + // mere passthrough. + return mState.getIndexedIntegerv(target, index, data); +} + +bool Context::getIndexedInteger64v(GLenum target, GLuint index, GLint64 *data) +{ + // Queries about context capabilities and maximums are answered by Context. + // Queries about current GL state values are answered by State. + // Indexed integer queries all refer to current state, so this function is a + // mere passthrough. + return mState.getIndexedInteger64v(target, index, data); } bool Context::getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *numParams) @@ -1538,7 +1078,7 @@ bool Context::getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *nu // Please note: the query type returned for DEPTH_CLEAR_VALUE in this implementation // is FLOAT rather than INT, as would be suggested by the GL ES 2.0 spec. This is due // to the fact that it is stored internally as a float, and so would require conversion - // if returned from Context::getIntegerv. Since this conversion is already implemented + // if returned from Context::getIntegerv. Since this conversion is already implemented // in the case that one calls glGetIntegerv to retrieve a float-typed state variable, we // place DEPTH_CLEAR_VALUE with the floats. This should make no difference to the calling // application. @@ -1549,13 +1089,13 @@ bool Context::getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *nu *type = GL_INT; *numParams = mNumCompressedTextureFormats; } - break; + return true; case GL_SHADER_BINARY_FORMATS: { *type = GL_INT; *numParams = 0; } - break; + return true; case GL_MAX_VERTEX_ATTRIBS: case GL_MAX_VERTEX_UNIFORM_VECTORS: case GL_MAX_VARYING_VECTORS: @@ -1569,7 +1109,9 @@ bool Context::getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *nu case GL_NUM_SHADER_BINARY_FORMATS: case GL_NUM_COMPRESSED_TEXTURE_FORMATS: case GL_ARRAY_BUFFER_BINDING: - case GL_FRAMEBUFFER_BINDING: + //case GL_FRAMEBUFFER_BINDING: // equivalent to DRAW_FRAMEBUFFER_BINDING_ANGLE + case GL_DRAW_FRAMEBUFFER_BINDING_ANGLE: + case GL_READ_FRAMEBUFFER_BINDING_ANGLE: case GL_RENDERBUFFER_BINDING: case GL_CURRENT_PROGRAM: case GL_PACK_ALIGNMENT: @@ -1625,10 +1167,24 @@ bool Context::getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *nu *type = GL_INT; *numParams = 1; } - break; - case GL_MAX_SAMPLES_ANGLE: + return true; + case GL_MAX_SAMPLES_ANGLE: + { + if (mExtensions.framebufferMultisample) + { + *type = GL_INT; + *numParams = 1; + } + else + { + return false; + } + } + return true; + case GL_PIXEL_PACK_BUFFER_BINDING: + case GL_PIXEL_UNPACK_BUFFER_BINDING: { - if (getMaxSupportedSamples() != 0) + if (mExtensions.pixelBufferObject) { *type = GL_INT; *numParams = 1; @@ -1638,20 +1194,20 @@ bool Context::getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *nu return false; } } - break; + return true; case GL_MAX_VIEWPORT_DIMS: { *type = GL_INT; *numParams = 2; } - break; + return true; case GL_VIEWPORT: case GL_SCISSOR_BOX: { *type = GL_INT; *numParams = 4; } - break; + return true; case GL_SHADER_COMPILER: case GL_SAMPLE_COVERAGE_INVERT: case GL_DEPTH_WRITEMASK: @@ -1669,13 +1225,13 @@ bool Context::getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *nu *type = GL_BOOL; *numParams = 1; } - break; + return true; case GL_COLOR_WRITEMASK: { *type = GL_BOOL; *numParams = 4; } - break; + return true; case GL_POLYGON_OFFSET_FACTOR: case GL_POLYGON_OFFSET_UNITS: case GL_SAMPLE_COVERAGE_VALUE: @@ -1685,7 +1241,7 @@ bool Context::getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *nu *type = GL_FLOAT; *numParams = 1; } - break; + return true; case GL_ALIASED_LINE_WIDTH_RANGE: case GL_ALIASED_POINT_SIZE_RANGE: case GL_DEPTH_RANGE: @@ -1693,49 +1249,133 @@ bool Context::getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *nu *type = GL_FLOAT; *numParams = 2; } - break; + return true; case GL_COLOR_CLEAR_VALUE: case GL_BLEND_COLOR: { *type = GL_FLOAT; *numParams = 4; } - break; + return true; case GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT: - if (!supportsTextureFilterAnisotropy()) + if (!mExtensions.maxTextureAnisotropy) { return false; } *type = GL_FLOAT; *numParams = 1; - break; - default: + return true; + } + + if (mClientVersion < 3) + { return false; } - return true; + // Check for ES3.0+ parameter names + switch (pname) + { + case GL_MAX_UNIFORM_BUFFER_BINDINGS: + case GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT: + case GL_UNIFORM_BUFFER_BINDING: + case GL_TRANSFORM_FEEDBACK_BINDING: + case GL_COPY_READ_BUFFER_BINDING: + case GL_COPY_WRITE_BUFFER_BINDING: + case GL_TEXTURE_BINDING_3D: + case GL_TEXTURE_BINDING_2D_ARRAY: + case GL_MAX_3D_TEXTURE_SIZE: + case GL_MAX_ARRAY_TEXTURE_LAYERS: + case GL_MAX_VERTEX_UNIFORM_BLOCKS: + case GL_MAX_FRAGMENT_UNIFORM_BLOCKS: + case GL_MAX_COMBINED_UNIFORM_BLOCKS: + case GL_MAX_VARYING_COMPONENTS: + case GL_VERTEX_ARRAY_BINDING: + case GL_MAX_VERTEX_UNIFORM_COMPONENTS: + case GL_MAX_FRAGMENT_UNIFORM_COMPONENTS: + case GL_NUM_EXTENSIONS: + case GL_MAJOR_VERSION: + case GL_MINOR_VERSION: + case GL_MAX_ELEMENTS_INDICES: + case GL_MAX_ELEMENTS_VERTICES: + case GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS: + case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS: + case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS: + { + *type = GL_INT; + *numParams = 1; + } + return true; + + case GL_MAX_ELEMENT_INDEX: + case GL_MAX_UNIFORM_BLOCK_SIZE: + case GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS: + case GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS: + case GL_MAX_SERVER_WAIT_TIMEOUT: + { + *type = GL_INT_64_ANGLEX; + *numParams = 1; + } + return true; + + case GL_TRANSFORM_FEEDBACK_ACTIVE: + case GL_TRANSFORM_FEEDBACK_PAUSED: + { + *type = GL_BOOL; + *numParams = 1; + } + return true; + } + + return false; } -// Applies the render target surface, depth stencil surface, viewport rectangle and -// scissor rectangle to the renderer -bool Context::applyRenderTarget(GLenum drawMode, bool ignoreViewport) +bool Context::getIndexedQueryParameterInfo(GLenum target, GLenum *type, unsigned int *numParams) { - Framebuffer *framebufferObject = getDrawFramebuffer(); + if (mClientVersion < 3) + { + return false; + } - if (!framebufferObject || framebufferObject->completeness() != GL_FRAMEBUFFER_COMPLETE) + switch (target) { - return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION, false); + 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 false; +} + +// Applies the render target surface, depth stencil surface, viewport rectangle and +// scissor rectangle to the renderer +bool Context::applyRenderTarget(GLenum drawMode, bool ignoreViewport) +{ + Framebuffer *framebufferObject = mState.getDrawFramebuffer(); + ASSERT(framebufferObject && framebufferObject->completeness() == GL_FRAMEBUFFER_COMPLETE); + mRenderer->applyRenderTarget(framebufferObject); - if (!mRenderer->setViewport(mState.viewport, mState.zNear, mState.zFar, drawMode, mState.rasterizer.frontFace, + float nearZ, farZ; + mState.getDepthRange(&nearZ, &farZ); + if (!mRenderer->setViewport(mState.getViewport(), nearZ, farZ, drawMode, mState.getRasterizerState().frontFace, ignoreViewport)) { return false; } - mRenderer->setScissorRectangle(mState.scissor, mState.scissorTest); + mRenderer->setScissorRectangle(mState.getScissor(), mState.isScissorTestEnabled()); return true; } @@ -1743,17 +1383,22 @@ bool Context::applyRenderTarget(GLenum drawMode, bool ignoreViewport) // Applies the fixed-function state (culling, depth test, alpha blending, stenciling, etc) to the Direct3D 9 device void Context::applyState(GLenum drawMode) { - Framebuffer *framebufferObject = getDrawFramebuffer(); + Framebuffer *framebufferObject = mState.getDrawFramebuffer(); int samples = framebufferObject->getSamples(); - mState.rasterizer.pointDrawMode = (drawMode == GL_POINTS); - mState.rasterizer.multiSample = (samples != 0); - mRenderer->setRasterizerState(mState.rasterizer); + RasterizerState rasterizer = mState.getRasterizerState(); + rasterizer.pointDrawMode = (drawMode == GL_POINTS); + rasterizer.multiSample = (samples != 0); + + mRenderer->setRasterizerState(rasterizer); unsigned int mask = 0; - if (mState.sampleCoverage) + if (mState.isSampleCoverageEnabled()) { - if (mState.sampleCoverageValue != 0) + GLclampf coverageValue; + bool coverageInvert = false; + mState.getSampleCoverageParams(&coverageValue, &coverageInvert); + if (coverageValue != 0) { float threshold = 0.5f; @@ -1762,7 +1407,7 @@ void Context::applyState(GLenum drawMode) { mask <<= 1; - if ((i + 1) * mState.sampleCoverageValue >= threshold) + if ((i + 1) * coverageValue >= threshold) { threshold += 1.0f; mask |= 1; @@ -1770,7 +1415,7 @@ void Context::applyState(GLenum drawMode) } } - if (mState.sampleCoverageInvert) + if (coverageInvert) { mask = ~mask; } @@ -1779,192 +1424,333 @@ void Context::applyState(GLenum drawMode) { mask = 0xFFFFFFFF; } - mRenderer->setBlendState(framebufferObject, mState.blend, mState.blendColor, mask); + mRenderer->setBlendState(framebufferObject, mState.getBlendState(), mState.getBlendColor(), mask); - mRenderer->setDepthStencilState(mState.depthStencil, mState.stencilRef, mState.stencilBackRef, - mState.rasterizer.frontFace == GL_CCW); + mRenderer->setDepthStencilState(mState.getDepthStencilState(), mState.getStencilRef(), mState.getStencilBackRef(), + rasterizer.frontFace == GL_CCW); } // Applies the shaders and shader constants to the Direct3D 9 device -void Context::applyShaders() +void Context::applyShaders(ProgramBinary *programBinary, bool transformFeedbackActive) { - ProgramBinary *programBinary = getCurrentProgramBinary(); + const VertexAttribute *vertexAttributes = mState.getVertexArray()->getVertexAttributes(); + + VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS]; + VertexFormat::GetInputLayout(inputLayout, programBinary, vertexAttributes, mState.getVertexAttribCurrentValues()); + + const Framebuffer *fbo = mState.getDrawFramebuffer(); + + mRenderer->applyShaders(programBinary, inputLayout, fbo, mState.getRasterizerState().rasterizerDiscard, transformFeedbackActive); - mRenderer->applyShaders(programBinary); - programBinary->applyUniforms(); } -// Applies the textures and sampler states to the Direct3D 9 device -void Context::applyTextures() +size_t Context::getCurrentTexturesAndSamplerStates(ProgramBinary *programBinary, SamplerType type, Texture **outTextures, + TextureType *outTextureTypes, SamplerState *outSamplers) { - applyTextures(SAMPLER_PIXEL); + size_t samplerRange = programBinary->getUsedSamplerRange(type); + for (size_t i = 0; i < samplerRange; i++) + { + outTextureTypes[i] = programBinary->getSamplerTextureType(type, i); + GLint textureUnit = programBinary->getSamplerMapping(type, i); // OpenGL texture image unit index + if (textureUnit != -1) + { + outTextures[i] = getSamplerTexture(textureUnit, outTextureTypes[i]); + outTextures[i]->getSamplerStateWithNativeOffset(&outSamplers[i]); + Sampler *samplerObject = mState.getSampler(textureUnit); + if (samplerObject) + { + samplerObject->getState(&outSamplers[i]); + } + } + else + { + outTextures[i] = NULL; + } + } - if (mSupportsVertexTexture) + return samplerRange; +} + +void Context::generateSwizzles(Texture *textures[], size_t count) +{ + for (size_t i = 0; i < count; i++) { - applyTextures(SAMPLER_VERTEX); + if (textures[i] && textures[i]->getSamplerState().swizzleRequired()) + { + mRenderer->generateSwizzle(textures[i]); + } } } -// For each Direct3D 9 sampler of either the pixel or vertex stage, +// For each Direct3D sampler of either the pixel or vertex stage, // looks up the corresponding OpenGL texture image unit and texture type, // and sets the texture and its addressing/filtering state (or NULL when inactive). -void Context::applyTextures(SamplerType type) +void Context::applyTextures(SamplerType shaderType, Texture *textures[], TextureType *textureTypes, SamplerState *samplers, + size_t textureCount, const FramebufferTextureSerialArray& framebufferSerials, + size_t framebufferSerialCount) { - ProgramBinary *programBinary = getCurrentProgramBinary(); - - FramebufferTextureSerialSet boundFramebufferTextures = getBoundFramebufferTextureSerials(); - // Range of Direct3D samplers of given sampler type - int samplerCount = (type == SAMPLER_PIXEL) ? MAX_TEXTURE_IMAGE_UNITS : mRenderer->getMaxVertexTextureImageUnits(); - int samplerRange = programBinary->getUsedSamplerRange(type); + size_t samplerCount = (shaderType == SAMPLER_PIXEL) ? MAX_TEXTURE_IMAGE_UNITS + : mRenderer->getMaxVertexTextureImageUnits(); - for (int samplerIndex = 0; samplerIndex < samplerRange; samplerIndex++) + for (size_t samplerIndex = 0; samplerIndex < textureCount; samplerIndex++) { - int textureUnit = programBinary->getSamplerMapping(type, samplerIndex); // OpenGL texture image unit index + Texture *texture = textures[samplerIndex]; + const SamplerState &sampler = samplers[samplerIndex]; + TextureType textureType = textureTypes[samplerIndex]; - if (textureUnit != -1) + if (texture) { - TextureType textureType = programBinary->getSamplerTextureType(type, samplerIndex); - Texture *texture = getSamplerTexture(textureUnit, textureType); - - if (texture->isSamplerComplete() && - boundFramebufferTextures.find(texture->getTextureSerial()) == boundFramebufferTextures.end()) + // TODO: std::binary_search may become unavailable using older versions of GCC + if (texture->isSamplerComplete(sampler) && + !std::binary_search(framebufferSerials.begin(), framebufferSerials.begin() + framebufferSerialCount, texture->getTextureSerial())) { - SamplerState samplerState; - texture->getSamplerState(&samplerState); - mRenderer->setSamplerState(type, samplerIndex, samplerState); - - mRenderer->setTexture(type, samplerIndex, texture); - + mRenderer->setSamplerState(shaderType, samplerIndex, sampler); + mRenderer->setTexture(shaderType, samplerIndex, texture); texture->resetDirty(); } else { - mRenderer->setTexture(type, samplerIndex, getIncompleteTexture(textureType)); + Texture *incompleteTexture = getIncompleteTexture(textureType); + mRenderer->setTexture(shaderType, samplerIndex, incompleteTexture); + incompleteTexture->resetDirty(); } } else { - mRenderer->setTexture(type, samplerIndex, NULL); + mRenderer->setTexture(shaderType, samplerIndex, NULL); } } - for (int samplerIndex = samplerRange; samplerIndex < samplerCount; samplerIndex++) + for (size_t samplerIndex = textureCount; samplerIndex < samplerCount; samplerIndex++) { - mRenderer->setTexture(type, samplerIndex, NULL); + mRenderer->setTexture(shaderType, samplerIndex, NULL); } } -void Context::readPixels(GLint x, GLint y, GLsizei width, GLsizei height, - GLenum format, GLenum type, GLsizei *bufSize, void* pixels) +bool Context::applyUniformBuffers() { - Framebuffer *framebuffer = getReadFramebuffer(); + Program *programObject = getProgram(mState.getCurrentProgramId()); + ProgramBinary *programBinary = programObject->getProgramBinary(); + + std::vector boundBuffers; - if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE) + for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < programBinary->getActiveUniformBlockCount(); uniformBlockIndex++) { - return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION); + GLuint blockBinding = programObject->getUniformBlockBinding(uniformBlockIndex); + + if (mState.getIndexedUniformBuffer(blockBinding)->id() == 0) + { + // undefined behaviour + return false; + } + else + { + Buffer *uniformBuffer = mState.getIndexedUniformBuffer(blockBinding); + ASSERT(uniformBuffer); + boundBuffers.push_back(uniformBuffer); + } } - if (getReadFramebufferHandle() != 0 && framebuffer->getSamples() != 0) + return programBinary->applyUniformBuffers(boundBuffers); +} + +bool Context::applyTransformFeedbackBuffers() +{ + TransformFeedback *curTransformFeedback = mState.getCurrentTransformFeedback(); + if (curTransformFeedback && curTransformFeedback->isStarted() && !curTransformFeedback->isPaused()) + { + Buffer *transformFeedbackBuffers[IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS]; + GLintptr transformFeedbackOffsets[IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS]; + for (size_t i = 0; i < IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS; i++) + { + transformFeedbackBuffers[i] = mState.getIndexedTransformFeedbackBuffer(i); + transformFeedbackOffsets[i] = mState.getIndexedTransformFeedbackBufferOffset(i); + } + mRenderer->applyTransformFeedbackBuffers(transformFeedbackBuffers, transformFeedbackOffsets); + return true; + } + else { - return gl::error(GL_INVALID_OPERATION); + return false; } +} - GLsizei outputPitch = ComputePitch(width, ConvertSizedInternalFormat(format, type), getPackAlignment()); - // sized query sanity check - if (bufSize) +void Context::markTransformFeedbackUsage() +{ + for (size_t i = 0; i < IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS; i++) { - int requiredSize = outputPitch * height; - if (requiredSize > *bufSize) + Buffer *buffer = mState.getIndexedTransformFeedbackBuffer(i); + if (buffer) { - return gl::error(GL_INVALID_OPERATION); + buffer->markTransformFeedbackUsage(); } } - - mRenderer->readPixels(framebuffer, x, y, width, height, format, type, outputPitch, getPackReverseRowOrder(), getPackAlignment(), pixels); } void Context::clear(GLbitfield mask) { - Framebuffer *framebufferObject = getDrawFramebuffer(); + if (mState.isRasterizerDiscardEnabled()) + { + return; + } + + ClearParameters clearParams = mState.getClearParameters(mask); - if (!framebufferObject || framebufferObject->completeness() != GL_FRAMEBUFFER_COMPLETE) + if (!applyRenderTarget(GL_TRIANGLES, true)) // Clips the clear to the scissor rectangle but not the viewport { - return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION); + return; } - DWORD flags = 0; - GLbitfield finalMask = 0; + mRenderer->clear(clearParams, mState.getDrawFramebuffer()); +} - if (mask & GL_COLOR_BUFFER_BIT) +void Context::clearBufferfv(GLenum buffer, int drawbuffer, const float *values) +{ + if (mState.isRasterizerDiscardEnabled()) { - mask &= ~GL_COLOR_BUFFER_BIT; + return; + } - if (framebufferObject->hasEnabledColorAttachment()) + // glClearBufferfv can be called to clear the color buffer or depth buffer + ClearParameters clearParams = mState.getClearParameters(0); + + if (buffer == GL_COLOR) + { + for (unsigned int i = 0; i < ArraySize(clearParams.clearColor); i++) { - finalMask |= GL_COLOR_BUFFER_BIT; + clearParams.clearColor[i] = (drawbuffer == static_cast(i)); } + clearParams.colorFClearValue = ColorF(values[0], values[1], values[2], values[3]); + clearParams.colorClearType = GL_FLOAT; + } + + if (buffer == GL_DEPTH) + { + clearParams.clearDepth = true; + clearParams.depthClearValue = values[0]; + } + + if (!applyRenderTarget(GL_TRIANGLES, true)) // Clips the clear to the scissor rectangle but not the viewport + { + return; + } + + mRenderer->clear(clearParams, mState.getDrawFramebuffer()); +} + +void Context::clearBufferuiv(GLenum buffer, int drawbuffer, const unsigned int *values) +{ + if (mState.isRasterizerDiscardEnabled()) + { + return; + } + + // glClearBufferuv can only be called to clear a color buffer + ClearParameters clearParams = mState.getClearParameters(0); + for (unsigned int i = 0; i < ArraySize(clearParams.clearColor); i++) + { + clearParams.clearColor[i] = (drawbuffer == static_cast(i)); + } + clearParams.colorUIClearValue = ColorUI(values[0], values[1], values[2], values[3]); + clearParams.colorClearType = GL_UNSIGNED_INT; + + if (!applyRenderTarget(GL_TRIANGLES, true)) // Clips the clear to the scissor rectangle but not the viewport + { + return; + } + + mRenderer->clear(clearParams, mState.getDrawFramebuffer()); +} + +void Context::clearBufferiv(GLenum buffer, int drawbuffer, const int *values) +{ + if (mState.isRasterizerDiscardEnabled()) + { + return; } - if (mask & GL_DEPTH_BUFFER_BIT) + // glClearBufferfv can be called to clear the color buffer or stencil buffer + ClearParameters clearParams = mState.getClearParameters(0); + + if (buffer == GL_COLOR) { - mask &= ~GL_DEPTH_BUFFER_BIT; - if (mState.depthStencil.depthMask && framebufferObject->getDepthbufferType() != GL_NONE) + for (unsigned int i = 0; i < ArraySize(clearParams.clearColor); i++) { - finalMask |= GL_DEPTH_BUFFER_BIT; + clearParams.clearColor[i] = (drawbuffer == static_cast(i)); } + clearParams.colorIClearValue = ColorI(values[0], values[1], values[2], values[3]); + clearParams.colorClearType = GL_INT; } - if (mask & GL_STENCIL_BUFFER_BIT) + if (buffer == GL_STENCIL) { - mask &= ~GL_STENCIL_BUFFER_BIT; - if (framebufferObject->getStencilbufferType() != GL_NONE) - { - rx::RenderTarget *depthStencil = framebufferObject->getStencilbuffer()->getDepthStencil(); - if (!depthStencil) - { - ERR("Depth stencil pointer unexpectedly null."); - return; - } + clearParams.clearStencil = true; + clearParams.stencilClearValue = values[1]; + } - if (GetStencilSize(depthStencil->getActualFormat()) > 0) - { - finalMask |= GL_STENCIL_BUFFER_BIT; - } - } + if (!applyRenderTarget(GL_TRIANGLES, true)) // Clips the clear to the scissor rectangle but not the viewport + { + return; } - if (mask != 0) + mRenderer->clear(clearParams, mState.getDrawFramebuffer()); +} + +void Context::clearBufferfi(GLenum buffer, int drawbuffer, float depth, int stencil) +{ + if (mState.isRasterizerDiscardEnabled()) { - return gl::error(GL_INVALID_VALUE); + return; } + // glClearBufferfi can only be called to clear a depth stencil buffer + ClearParameters clearParams = mState.getClearParameters(0); + clearParams.clearDepth = true; + clearParams.depthClearValue = depth; + clearParams.clearStencil = true; + clearParams.stencilClearValue = stencil; + if (!applyRenderTarget(GL_TRIANGLES, true)) // Clips the clear to the scissor rectangle but not the viewport { return; } - ClearParameters clearParams; - clearParams.mask = finalMask; - clearParams.colorClearValue = mState.colorClearValue; - clearParams.colorMaskRed = mState.blend.colorMaskRed; - clearParams.colorMaskGreen = mState.blend.colorMaskGreen; - clearParams.colorMaskBlue = mState.blend.colorMaskBlue; - clearParams.colorMaskAlpha = mState.blend.colorMaskAlpha; - clearParams.depthClearValue = mState.depthClearValue; - clearParams.stencilClearValue = mState.stencilClearValue; - clearParams.stencilWriteMask = mState.depthStencil.stencilWritemask; + mRenderer->clear(clearParams, mState.getDrawFramebuffer()); +} + +void Context::readPixels(GLint x, GLint y, GLsizei width, GLsizei height, + GLenum format, GLenum type, GLsizei *bufSize, void* pixels) +{ + gl::Framebuffer *framebuffer = mState.getReadFramebuffer(); + + bool isSized = IsSizedInternalFormat(format); + GLenum sizedInternalFormat = (isSized ? format : GetSizedInternalFormat(format, type)); + GLuint outputPitch = GetRowPitch(sizedInternalFormat, type, width, mState.getPackAlignment()); - mRenderer->clear(clearParams, framebufferObject); + mRenderer->readPixels(framebuffer, x, y, width, height, format, type, outputPitch, mState.getPackState(), pixels); } void Context::drawArrays(GLenum mode, GLint first, GLsizei count, GLsizei instances) { - if (!mState.currentProgram) - { - return gl::error(GL_INVALID_OPERATION); - } + ASSERT(mState.getCurrentProgramId() != 0); + + ProgramBinary *programBinary = mState.getCurrentProgramBinary(); + programBinary->updateSamplerMapping(); + + Texture *vsTextures[IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS]; + TextureType vsTextureTypes[IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS]; + SamplerState vsSamplers[IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS]; + size_t vsTextureCount = getCurrentTexturesAndSamplerStates(programBinary, SAMPLER_VERTEX, vsTextures, vsTextureTypes, vsSamplers); + + Texture *psTextures[MAX_TEXTURE_IMAGE_UNITS]; + TextureType psTextureTypes[MAX_TEXTURE_IMAGE_UNITS]; + SamplerState psSamplers[MAX_TEXTURE_IMAGE_UNITS]; + size_t psTextureCount = getCurrentTexturesAndSamplerStates(programBinary, SAMPLER_PIXEL, psTextures, psTextureTypes, psSamplers); + + generateSwizzles(vsTextures, vsTextureCount); + generateSwizzles(psTextures, psTextureCount); if (!mRenderer->applyPrimitiveType(mode, count)) { @@ -1978,40 +1764,58 @@ void Context::drawArrays(GLenum mode, GLint first, GLsizei count, GLsizei instan applyState(mode); - ProgramBinary *programBinary = getCurrentProgramBinary(); - - GLenum err = mRenderer->applyVertexBuffer(programBinary, mState.vertexAttribute, first, count, instances); + GLenum err = mRenderer->applyVertexBuffer(programBinary, mState.getVertexArray()->getVertexAttributes(), mState.getVertexAttribCurrentValues(), first, count, instances); if (err != GL_NO_ERROR) { return gl::error(err); } - applyShaders(); - applyTextures(); + bool transformFeedbackActive = applyTransformFeedbackBuffers(); + + applyShaders(programBinary, transformFeedbackActive); + + FramebufferTextureSerialArray frameBufferSerials; + size_t framebufferSerialCount = getBoundFramebufferTextureSerials(&frameBufferSerials); + + applyTextures(SAMPLER_VERTEX, vsTextures, vsTextureTypes, vsSamplers, vsTextureCount, frameBufferSerials, framebufferSerialCount); + applyTextures(SAMPLER_PIXEL, psTextures, psTextureTypes, psSamplers, psTextureCount, frameBufferSerials, framebufferSerialCount); - if (!programBinary->validateSamplers(NULL)) + if (!applyUniformBuffers()) { - return gl::error(GL_INVALID_OPERATION); + return; } if (!skipDraw(mode)) { - mRenderer->drawArrays(mode, count, instances); + mRenderer->drawArrays(mode, count, instances, transformFeedbackActive); + + if (transformFeedbackActive) + { + markTransformFeedbackUsage(); + } } } void Context::drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei instances) { - if (!mState.currentProgram) - { - return gl::error(GL_INVALID_OPERATION); - } + ASSERT(mState.getCurrentProgramId() != 0); + + ProgramBinary *programBinary = mState.getCurrentProgramBinary(); + programBinary->updateSamplerMapping(); + + Texture *vsTextures[IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS]; + TextureType vsTextureTypes[IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS]; + SamplerState vsSamplers[IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS]; + size_t vsTextureCount = getCurrentTexturesAndSamplerStates(programBinary, SAMPLER_VERTEX, vsTextures, vsTextureTypes, vsSamplers); + + Texture *psTextures[MAX_TEXTURE_IMAGE_UNITS]; + TextureType psTextureTypes[MAX_TEXTURE_IMAGE_UNITS]; + SamplerState psSamplers[MAX_TEXTURE_IMAGE_UNITS]; + size_t psTextureCount = getCurrentTexturesAndSamplerStates(programBinary, SAMPLER_PIXEL, psTextures, psTextureTypes, psSamplers); + + generateSwizzles(vsTextures, vsTextureCount); + generateSwizzles(psTextures, psTextureCount); - if (!indices && !mState.elementArrayBuffer) - { - return gl::error(GL_INVALID_OPERATION); - } - if (!mRenderer->applyPrimitiveType(mode, count)) { return; @@ -2024,33 +1828,42 @@ void Context::drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid applyState(mode); + VertexArray *vao = mState.getVertexArray(); rx::TranslatedIndexData indexInfo; - GLenum err = mRenderer->applyIndexBuffer(indices, mState.elementArrayBuffer.get(), count, mode, type, &indexInfo); + GLenum err = mRenderer->applyIndexBuffer(indices, vao->getElementArrayBuffer(), count, mode, type, &indexInfo); if (err != GL_NO_ERROR) { return gl::error(err); } - ProgramBinary *programBinary = getCurrentProgramBinary(); - GLsizei vertexCount = indexInfo.maxIndex - indexInfo.minIndex + 1; - err = mRenderer->applyVertexBuffer(programBinary, mState.vertexAttribute, indexInfo.minIndex, vertexCount, instances); + err = mRenderer->applyVertexBuffer(programBinary, vao->getVertexAttributes(), mState.getVertexAttribCurrentValues(), indexInfo.minIndex, vertexCount, instances); if (err != GL_NO_ERROR) { return gl::error(err); } - applyShaders(); - applyTextures(); + bool transformFeedbackActive = applyTransformFeedbackBuffers(); + // Transform feedback is not allowed for DrawElements, this error should have been caught at the API validation + // layer. + ASSERT(!transformFeedbackActive); + + applyShaders(programBinary, transformFeedbackActive); + + FramebufferTextureSerialArray frameBufferSerials; + size_t framebufferSerialCount = getBoundFramebufferTextureSerials(&frameBufferSerials); + + applyTextures(SAMPLER_VERTEX, vsTextures, vsTextureTypes, vsSamplers, vsTextureCount, frameBufferSerials, framebufferSerialCount); + applyTextures(SAMPLER_PIXEL, psTextures, psTextureTypes, psSamplers, psTextureCount, frameBufferSerials, framebufferSerialCount); - if (!programBinary->validateSamplers(NULL)) + if (!applyUniformBuffers()) { - return gl::error(GL_INVALID_OPERATION); + return; } if (!skipDraw(mode)) { - mRenderer->drawElements(mode, count, type, indices, mState.elementArrayBuffer.get(), indexInfo, instances); + mRenderer->drawElements(mode, count, type, indices, vao->getElementArrayBuffer(), indexInfo, instances); } } @@ -2146,254 +1959,139 @@ GLenum Context::getResetStatus() { mResetStatus = GL_NO_ERROR; } - } - - return status; -} - -bool Context::isResetNotificationEnabled() -{ - return (mResetStrategy == GL_LOSE_CONTEXT_ON_RESET_EXT); -} - -int Context::getMajorShaderModel() const -{ - return mMajorShaderModel; -} - -float Context::getMaximumPointSize() const -{ - return mMaximumPointSize; -} - -unsigned int Context::getMaximumCombinedTextureImageUnits() const -{ - return mRenderer->getMaxCombinedTextureImageUnits(); -} - -int Context::getMaxSupportedSamples() const -{ - return mRenderer->getMaxSupportedSamples(); -} - -unsigned int Context::getMaximumRenderTargets() const -{ - return mRenderer->getMaxRenderTargets(); -} - -bool Context::supportsEventQueries() const -{ - return mSupportsEventQueries; -} - -bool Context::supportsOcclusionQueries() const -{ - return mSupportsOcclusionQueries; -} - -bool Context::supportsBGRATextures() const -{ - return mSupportsBGRATextures; -} - -bool Context::supportsDXT1Textures() const -{ - return mSupportsDXT1Textures; -} - -bool Context::supportsDXT3Textures() const -{ - return mSupportsDXT3Textures; -} - -bool Context::supportsDXT5Textures() const -{ - return mSupportsDXT5Textures; -} + } -bool Context::supportsFloat32Textures() const -{ - return mSupportsFloat32Textures; + return status; } -bool Context::supportsFloat32LinearFilter() const +bool Context::isResetNotificationEnabled() { - return mSupportsFloat32LinearFilter; + return (mResetStrategy == GL_LOSE_CONTEXT_ON_RESET_EXT); } -bool Context::supportsFloat32RenderableTextures() const +int Context::getClientVersion() const { - return mSupportsFloat32RenderableTextures; + return mClientVersion; } -bool Context::supportsFloat16Textures() const +const Caps &Context::getCaps() const { - return mSupportsFloat16Textures; + return mCaps; } -bool Context::supportsFloat16LinearFilter() const +const TextureCapsMap &Context::getTextureCaps() const { - return mSupportsFloat16LinearFilter; + return mTextureCaps; } -bool Context::supportsFloat16RenderableTextures() const +const Extensions &Context::getExtensions() const { - return mSupportsFloat16RenderableTextures; + return mExtensions; } -int Context::getMaximumRenderbufferDimension() const +int Context::getMajorShaderModel() const { - return mMaxRenderbufferDimension; + return mMajorShaderModel; } -int Context::getMaximumTextureDimension() const +unsigned int Context::getMaximumCombinedTextureImageUnits() const { - return mMaxTextureDimension; + return mRenderer->getMaxCombinedTextureImageUnits(); } -int Context::getMaximumCubeTextureDimension() const +unsigned int Context::getMaximumCombinedUniformBufferBindings() const { - return mMaxCubeTextureDimension; + return mRenderer->getMaxVertexShaderUniformBuffers() + + mRenderer->getMaxFragmentShaderUniformBuffers(); } -int Context::getMaximumTextureLevel() const +int Context::getMaxSupportedSamples() const { - return mMaxTextureLevel; + return mRenderer->getMaxSupportedSamples(); } -bool Context::supportsLuminanceTextures() const +GLsizei Context::getMaxSupportedFormatSamples(GLenum internalFormat) const { - return mSupportsLuminanceTextures; + return mRenderer->getMaxSupportedFormatSamples(internalFormat); } -bool Context::supportsLuminanceAlphaTextures() const +GLsizei Context::getNumSampleCounts(GLenum internalFormat) const { - return mSupportsLuminanceAlphaTextures; + return mRenderer->getNumSampleCounts(internalFormat); } -bool Context::supportsDepthTextures() const +void Context::getSampleCounts(GLenum internalFormat, GLsizei bufSize, GLint *params) const { - return mSupportsDepthTextures; + mRenderer->getSampleCounts(internalFormat, bufSize, params); } -bool Context::supports32bitIndices() const +unsigned int Context::getMaxTransformFeedbackBufferBindings() const { - return mSupports32bitIndices; + return mRenderer->getMaxTransformFeedbackBuffers(); } -bool Context::supportsNonPower2Texture() const +GLintptr Context::getUniformBufferOffsetAlignment() const { - return mSupportsNonPower2Texture; + // setting a large alignment forces uniform buffers to bind with zero offset + return static_cast(std::numeric_limits::max()); } -bool Context::supportsInstancing() const +void Context::getCurrentReadFormatType(GLenum *internalFormat, GLenum *format, GLenum *type) { - return mSupportsInstancing; -} + Framebuffer *framebuffer = mState.getReadFramebuffer(); + ASSERT(framebuffer && framebuffer->completeness() == GL_FRAMEBUFFER_COMPLETE); -bool Context::supportsTextureFilterAnisotropy() const -{ - return mSupportsTextureFilterAnisotropy; -} + FramebufferAttachment *attachment = framebuffer->getReadColorbuffer(); + ASSERT(attachment); -float Context::getTextureMaxAnisotropy() const -{ - return mMaxTextureAnisotropy; + *internalFormat = attachment->getActualFormat(); + *format = gl::GetFormat(attachment->getActualFormat()); + *type = gl::GetType(attachment->getActualFormat()); } -bool Context::getCurrentReadFormatType(GLenum *format, GLenum *type) +void Context::detachTexture(GLuint texture) { - Framebuffer *framebuffer = getReadFramebuffer(); - if (!framebuffer || framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE) - { - return gl::error(GL_INVALID_OPERATION, false); - } - - Renderbuffer *renderbuffer = framebuffer->getReadColorbuffer(); - if (!renderbuffer) - { - return gl::error(GL_INVALID_OPERATION, false); - } - - *format = gl::ExtractFormat(renderbuffer->getActualFormat()); - *type = gl::ExtractType(renderbuffer->getActualFormat()); - - return true; + // Simple pass-through to State's detachTexture method, as textures do not require + // allocation map management either here or in the resource manager at detach time. + // Zero textures are held by the Context, and we don't attempt to request them from + // the State. + mState.detachTexture(texture); } void Context::detachBuffer(GLuint buffer) { + // Buffer detachment is handled by Context, because the buffer must also be + // attached from any VAOs in existence, and Context holds the VAO map. + // [OpenGL ES 2.0.24] section 2.9 page 22: // If a buffer object is deleted while it is bound, all bindings to that object in the current context // (i.e. in the thread that called Delete-Buffers) are reset to zero. - if (mState.arrayBuffer.id() == buffer) - { - mState.arrayBuffer.set(NULL); - } - - if (mState.elementArrayBuffer.id() == buffer) - { - mState.elementArrayBuffer.set(NULL); - } - - for (int attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++) - { - if (mState.vertexAttribute[attribute].mBoundBuffer.id() == buffer) - { - mState.vertexAttribute[attribute].mBoundBuffer.set(NULL); - } - } -} - -void Context::detachTexture(GLuint texture) -{ - // [OpenGL ES 2.0.24] section 3.8 page 84: - // If a texture object is deleted, it is as if all texture units which are bound to that texture object are - // rebound to texture object zero - - for (int type = 0; type < TEXTURE_TYPE_COUNT; type++) - { - for (int sampler = 0; sampler < IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS; sampler++) - { - if (mState.samplerTexture[type][sampler].id() == texture) - { - mState.samplerTexture[type][sampler].set(NULL); - } - } - } - - // [OpenGL ES 2.0.24] section 4.4 page 112: - // If a texture object is deleted while its image is attached to the currently bound framebuffer, then it is - // as if FramebufferTexture2D had been called, with a texture of 0, for each attachment point to which this - // image was attached in the currently bound framebuffer. + mState.removeArrayBufferBinding(buffer); - Framebuffer *readFramebuffer = getReadFramebuffer(); - Framebuffer *drawFramebuffer = getDrawFramebuffer(); - - if (readFramebuffer) - { - readFramebuffer->detachTexture(texture); - } - - if (drawFramebuffer && drawFramebuffer != readFramebuffer) + // mark as freed among the vertex array objects + for (auto vaoIt = mVertexArrayMap.begin(); vaoIt != mVertexArrayMap.end(); vaoIt++) { - drawFramebuffer->detachTexture(texture); + vaoIt->second->detachBuffer(buffer); } } void Context::detachFramebuffer(GLuint framebuffer) { + // Framebuffer detachment is handled by Context, because 0 is a valid + // Framebuffer object, and a pointer to it must be passed from Context + // to State at binding time. + // [OpenGL ES 2.0.24] section 4.4 page 107: // If a framebuffer that is currently bound to the target FRAMEBUFFER is deleted, it is as though // BindFramebuffer had been executed with the target of FRAMEBUFFER and framebuffer of zero. - if (mState.readFramebuffer == framebuffer) + if (mState.removeReadFramebufferBinding(framebuffer)) { bindReadFramebuffer(0); } - if (mState.drawFramebuffer == framebuffer) + if (mState.removeDrawFramebufferBinding(framebuffer)) { bindDrawFramebuffer(0); } @@ -2401,32 +2099,32 @@ void Context::detachFramebuffer(GLuint framebuffer) void Context::detachRenderbuffer(GLuint renderbuffer) { - // [OpenGL ES 2.0.24] section 4.4 page 109: - // If a renderbuffer that is currently bound to RENDERBUFFER is deleted, it is as though BindRenderbuffer - // had been executed with the target RENDERBUFFER and name of zero. - - if (mState.renderbuffer.id() == renderbuffer) - { - bindRenderbuffer(0); - } - - // [OpenGL ES 2.0.24] section 4.4 page 111: - // If a renderbuffer object is deleted while its image is attached to the currently bound framebuffer, - // then it is as if FramebufferRenderbuffer had been called, with a renderbuffer of 0, for each attachment - // point to which this image was attached in the currently bound framebuffer. + mState.detachRenderbuffer(renderbuffer); +} - Framebuffer *readFramebuffer = getReadFramebuffer(); - Framebuffer *drawFramebuffer = getDrawFramebuffer(); +void Context::detachVertexArray(GLuint vertexArray) +{ + // Vertex array detachment is handled by Context, because 0 is a valid + // VAO, and a pointer to it must be passed from Context to State at + // binding time. - if (readFramebuffer) + // [OpenGL ES 3.0.2] section 2.10 page 43: + // If a vertex array object that is currently bound is deleted, the binding + // for that object reverts to zero and the default vertex array becomes current. + if (mState.removeVertexArrayBinding(vertexArray)) { - readFramebuffer->detachRenderbuffer(renderbuffer); + bindVertexArray(0); } +} - if (drawFramebuffer && drawFramebuffer != readFramebuffer) - { - drawFramebuffer->detachRenderbuffer(renderbuffer); - } +void Context::detachTransformFeedback(GLuint transformFeedback) +{ + mState.detachTransformFeedback(transformFeedback); +} + +void Context::detachSampler(GLuint sampler) +{ + mState.detachSampler(sampler); } Texture *Context::getIncompleteTexture(TextureType type) @@ -2435,7 +2133,8 @@ Texture *Context::getIncompleteTexture(TextureType type) if (t == NULL) { - static const GLubyte color[] = { 0, 0, 0, 255 }; + const GLubyte color[] = { 0, 0, 0, 255 }; + const PixelUnpackState incompleteUnpackState(1); switch (type) { @@ -2445,26 +2144,44 @@ Texture *Context::getIncompleteTexture(TextureType type) case TEXTURE_2D: { - Texture2D *incomplete2d = new Texture2D(mRenderer, Texture::INCOMPLETE_TEXTURE_ID); - incomplete2d->setImage(0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color); + Texture2D *incomplete2d = new Texture2D(mRenderer->createTexture2D(), Texture::INCOMPLETE_TEXTURE_ID); + incomplete2d->setImage(0, 1, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color); t = incomplete2d; } break; case TEXTURE_CUBE: { - TextureCubeMap *incompleteCube = new TextureCubeMap(mRenderer, Texture::INCOMPLETE_TEXTURE_ID); + TextureCubeMap *incompleteCube = new TextureCubeMap(mRenderer->createTextureCube(), Texture::INCOMPLETE_TEXTURE_ID); - incompleteCube->setImagePosX(0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color); - incompleteCube->setImageNegX(0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color); - incompleteCube->setImagePosY(0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color); - incompleteCube->setImageNegY(0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color); - incompleteCube->setImagePosZ(0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color); - incompleteCube->setImageNegZ(0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color); + incompleteCube->setImagePosX(0, 1, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color); + incompleteCube->setImageNegX(0, 1, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color); + incompleteCube->setImagePosY(0, 1, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color); + incompleteCube->setImageNegY(0, 1, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color); + incompleteCube->setImagePosZ(0, 1, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color); + incompleteCube->setImageNegZ(0, 1, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color); t = incompleteCube; } break; + + case TEXTURE_3D: + { + Texture3D *incomplete3d = new Texture3D(mRenderer->createTexture3D(), Texture::INCOMPLETE_TEXTURE_ID); + incomplete3d->setImage(0, 1, 1, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color); + + t = incomplete3d; + } + break; + + case TEXTURE_2D_ARRAY: + { + Texture2DArray *incomplete2darray = new Texture2DArray(mRenderer->createTexture2DArray(), Texture::INCOMPLETE_TEXTURE_ID); + incomplete2darray->setImage(0, 1, 1, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color); + + t = incomplete2darray; + } + break; } mIncompleteTextures[type].set(t); @@ -2480,9 +2197,9 @@ bool Context::skipDraw(GLenum drawMode) // ProgramBinary assumes non-point rendering if gl_PointSize isn't written, // which affects varying interpolation. Since the value of gl_PointSize is // undefined when not written, just skip drawing to avoid unexpected results. - if (!getCurrentProgramBinary()->usesPointSize()) + if (!mState.getCurrentProgramBinary()->usesPointSize()) { - // This is stictly speaking not an error, but developers should be + // This is stictly speaking not an error, but developers should be // notified of risking undefined behavior. ERR("Point rendering without writing to gl_PointSize."); @@ -2491,7 +2208,7 @@ bool Context::skipDraw(GLenum drawMode) } else if (IsTriangleMode(drawMode)) { - if (mState.rasterizer.cullFace && mState.rasterizer.cullMode == GL_FRONT_AND_BACK) + if (mState.getRasterizerState().cullFace && mState.getRasterizerState().cullMode == GL_FRONT_AND_BACK) { return true; } @@ -2500,148 +2217,97 @@ bool Context::skipDraw(GLenum drawMode) return false; } -void Context::setVertexAttrib(GLuint index, const GLfloat *values) -{ - ASSERT(index < gl::MAX_VERTEX_ATTRIBS); - - mState.vertexAttribute[index].mCurrentValue[0] = values[0]; - mState.vertexAttribute[index].mCurrentValue[1] = values[1]; - mState.vertexAttribute[index].mCurrentValue[2] = values[2]; - mState.vertexAttribute[index].mCurrentValue[3] = values[3]; -} - void Context::setVertexAttribDivisor(GLuint index, GLuint divisor) { - ASSERT(index < gl::MAX_VERTEX_ATTRIBS); - - mState.vertexAttribute[index].mDivisor = divisor; + mState.getVertexArray()->setVertexAttribDivisor(index, divisor); } -// keep list sorted in following order -// OES extensions -// EXT extensions -// Vendor extensions -void Context::initExtensionString() +void Context::samplerParameteri(GLuint sampler, GLenum pname, GLint param) { - std::string extensionString = ""; - - // OES extensions - if (supports32bitIndices()) - { - extensionString += "GL_OES_element_index_uint "; - } - - extensionString += "GL_OES_packed_depth_stencil "; - extensionString += "GL_OES_get_program_binary "; - extensionString += "GL_OES_rgb8_rgba8 "; - if (mRenderer->getDerivativeInstructionSupport()) - { - extensionString += "GL_OES_standard_derivatives "; - } - - if (supportsFloat16Textures()) - { - extensionString += "GL_OES_texture_half_float "; - } - if (supportsFloat16LinearFilter()) - { - extensionString += "GL_OES_texture_half_float_linear "; - } - if (supportsFloat32Textures()) - { - extensionString += "GL_OES_texture_float "; - } - if (supportsFloat32LinearFilter()) - { - extensionString += "GL_OES_texture_float_linear "; - } + mResourceManager->checkSamplerAllocation(sampler); - if (supportsNonPower2Texture()) - { - extensionString += "GL_OES_texture_npot "; - } - - // Multi-vendor (EXT) extensions - if (supportsOcclusionQueries()) - { - extensionString += "GL_EXT_occlusion_query_boolean "; - } - - extensionString += "GL_EXT_read_format_bgra "; - extensionString += "GL_EXT_robustness "; - - if (supportsDXT1Textures()) - { - extensionString += "GL_EXT_texture_compression_dxt1 "; - } - - if (supportsTextureFilterAnisotropy()) - { - extensionString += "GL_EXT_texture_filter_anisotropic "; - } + Sampler *samplerObject = getSampler(sampler); + ASSERT(samplerObject); - if (supportsBGRATextures()) - { - extensionString += "GL_EXT_texture_format_BGRA8888 "; - } - - if (mRenderer->getMaxRenderTargets() > 1) + switch (pname) { - extensionString += "GL_EXT_draw_buffers "; + case GL_TEXTURE_MIN_FILTER: samplerObject->setMinFilter(static_cast(param)); break; + case GL_TEXTURE_MAG_FILTER: samplerObject->setMagFilter(static_cast(param)); break; + case GL_TEXTURE_WRAP_S: samplerObject->setWrapS(static_cast(param)); break; + case GL_TEXTURE_WRAP_T: samplerObject->setWrapT(static_cast(param)); break; + case GL_TEXTURE_WRAP_R: samplerObject->setWrapR(static_cast(param)); break; + case GL_TEXTURE_MIN_LOD: samplerObject->setMinLod(static_cast(param)); break; + case GL_TEXTURE_MAX_LOD: samplerObject->setMaxLod(static_cast(param)); break; + case GL_TEXTURE_COMPARE_MODE: samplerObject->setComparisonMode(static_cast(param)); break; + case GL_TEXTURE_COMPARE_FUNC: samplerObject->setComparisonFunc(static_cast(param)); break; + default: UNREACHABLE(); break; } +} - extensionString += "GL_EXT_texture_storage "; - extensionString += "GL_EXT_frag_depth "; +void Context::samplerParameterf(GLuint sampler, GLenum pname, GLfloat param) +{ + mResourceManager->checkSamplerAllocation(sampler); - // ANGLE-specific extensions - if (supportsDepthTextures()) - { - extensionString += "GL_ANGLE_depth_texture "; - } + Sampler *samplerObject = getSampler(sampler); + ASSERT(samplerObject); - extensionString += "GL_ANGLE_framebuffer_blit "; - if (getMaxSupportedSamples() != 0) + switch (pname) { - extensionString += "GL_ANGLE_framebuffer_multisample "; + case GL_TEXTURE_MIN_FILTER: samplerObject->setMinFilter(uiround(param)); break; + case GL_TEXTURE_MAG_FILTER: samplerObject->setMagFilter(uiround(param)); break; + case GL_TEXTURE_WRAP_S: samplerObject->setWrapS(uiround(param)); break; + case GL_TEXTURE_WRAP_T: samplerObject->setWrapT(uiround(param)); break; + case GL_TEXTURE_WRAP_R: samplerObject->setWrapR(uiround(param)); break; + case GL_TEXTURE_MIN_LOD: samplerObject->setMinLod(param); break; + case GL_TEXTURE_MAX_LOD: samplerObject->setMaxLod(param); break; + case GL_TEXTURE_COMPARE_MODE: samplerObject->setComparisonMode(uiround(param)); break; + case GL_TEXTURE_COMPARE_FUNC: samplerObject->setComparisonFunc(uiround(param)); break; + default: UNREACHABLE(); break; } +} - if (supportsInstancing()) - { - extensionString += "GL_ANGLE_instanced_arrays "; - } +GLint Context::getSamplerParameteri(GLuint sampler, GLenum pname) +{ + mResourceManager->checkSamplerAllocation(sampler); - extensionString += "GL_ANGLE_pack_reverse_row_order "; + Sampler *samplerObject = getSampler(sampler); + ASSERT(samplerObject); - if (supportsDXT3Textures()) - { - extensionString += "GL_ANGLE_texture_compression_dxt3 "; - } - if (supportsDXT5Textures()) + switch (pname) { - extensionString += "GL_ANGLE_texture_compression_dxt5 "; + case GL_TEXTURE_MIN_FILTER: return static_cast(samplerObject->getMinFilter()); + case GL_TEXTURE_MAG_FILTER: return static_cast(samplerObject->getMagFilter()); + case GL_TEXTURE_WRAP_S: return static_cast(samplerObject->getWrapS()); + case GL_TEXTURE_WRAP_T: return static_cast(samplerObject->getWrapT()); + case GL_TEXTURE_WRAP_R: return static_cast(samplerObject->getWrapR()); + case GL_TEXTURE_MIN_LOD: return uiround(samplerObject->getMinLod()); + case GL_TEXTURE_MAX_LOD: return uiround(samplerObject->getMaxLod()); + case GL_TEXTURE_COMPARE_MODE: return static_cast(samplerObject->getComparisonMode()); + case GL_TEXTURE_COMPARE_FUNC: return static_cast(samplerObject->getComparisonFunc()); + default: UNREACHABLE(); return 0; } +} - extensionString += "GL_ANGLE_texture_usage "; - extensionString += "GL_ANGLE_translated_shader_source "; +GLfloat Context::getSamplerParameterf(GLuint sampler, GLenum pname) +{ + mResourceManager->checkSamplerAllocation(sampler); - // Other vendor-specific extensions - if (supportsEventQueries()) - { - extensionString += "GL_NV_fence "; - } + Sampler *samplerObject = getSampler(sampler); + ASSERT(samplerObject); - std::string::size_type end = extensionString.find_last_not_of(' '); - if (end != std::string::npos) + switch (pname) { - extensionString.resize(end+1); + case GL_TEXTURE_MIN_FILTER: return static_cast(samplerObject->getMinFilter()); + case GL_TEXTURE_MAG_FILTER: return static_cast(samplerObject->getMagFilter()); + case GL_TEXTURE_WRAP_S: return static_cast(samplerObject->getWrapS()); + case GL_TEXTURE_WRAP_T: return static_cast(samplerObject->getWrapT()); + case GL_TEXTURE_WRAP_R: return static_cast(samplerObject->getWrapR()); + case GL_TEXTURE_MIN_LOD: return samplerObject->getMinLod(); + case GL_TEXTURE_MAX_LOD: return samplerObject->getMaxLod(); + case GL_TEXTURE_COMPARE_MODE: return static_cast(samplerObject->getComparisonMode()); + case GL_TEXTURE_COMPARE_FUNC: return static_cast(samplerObject->getComparisonFunc()); + default: UNREACHABLE(); return 0; } - - mExtensionString = makeStaticString(extensionString); -} - -const char *Context::getExtensionString() const -{ - return mExtensionString; } void Context::initRendererString() @@ -2651,319 +2317,226 @@ void Context::initRendererString() rendererString << mRenderer->getRendererDescription(); rendererString << ")"; - mRendererString = makeStaticString(rendererString.str()); + mRendererString = MakeStaticString(rendererString.str()); } -const char *Context::getRendererString() const +const std::string &Context::getRendererString() const { return mRendererString; } -Context::FramebufferTextureSerialSet Context::getBoundFramebufferTextureSerials() +void Context::initExtensionStrings() { - FramebufferTextureSerialSet set; - - Framebuffer *drawFramebuffer = getDrawFramebuffer(); - for (unsigned int i = 0; i < IMPLEMENTATION_MAX_DRAW_BUFFERS; i++) - { - Renderbuffer *renderBuffer = drawFramebuffer->getColorbuffer(i); - if (renderBuffer && renderBuffer->getTextureSerial() != 0) - { - set.insert(renderBuffer->getTextureSerial()); - } - } + mExtensionStrings = mExtensions.getStrings(); - Renderbuffer *depthStencilBuffer = drawFramebuffer->getDepthOrStencilbuffer(); - if (depthStencilBuffer && depthStencilBuffer->getTextureSerial() != 0) - { - set.insert(depthStencilBuffer->getTextureSerial()); - } - - return set; + std::ostringstream combinedStringStream; + std::copy(mExtensionStrings.begin(), mExtensionStrings.end(), std::ostream_iterator(combinedStringStream, " ")); + mExtensionString = combinedStringStream.str(); } -void Context::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, - GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, - GLbitfield mask) +const std::string &Context::getExtensionString() const { - Framebuffer *readFramebuffer = getReadFramebuffer(); - Framebuffer *drawFramebuffer = getDrawFramebuffer(); - - if (!readFramebuffer || readFramebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE || - !drawFramebuffer || drawFramebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE) - { - return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION); - } - - if (drawFramebuffer->getSamples() != 0) - { - return gl::error(GL_INVALID_OPERATION); - } - - Renderbuffer *readColorBuffer = readFramebuffer->getReadColorbuffer(); - Renderbuffer *drawColorBuffer = drawFramebuffer->getFirstColorbuffer(); - - if (drawColorBuffer == NULL) - { - ERR("Draw buffers formats don't match, which is not supported in this implementation of BlitFramebufferANGLE"); - return gl::error(GL_INVALID_OPERATION); - } - - int readBufferWidth = readColorBuffer->getWidth(); - int readBufferHeight = readColorBuffer->getHeight(); - int drawBufferWidth = drawColorBuffer->getWidth(); - int drawBufferHeight = drawColorBuffer->getHeight(); - - Rectangle sourceRect; - Rectangle destRect; + return mExtensionString; +} - if (srcX0 < srcX1) - { - sourceRect.x = srcX0; - destRect.x = dstX0; - sourceRect.width = srcX1 - srcX0; - destRect.width = dstX1 - dstX0; - } - else - { - sourceRect.x = srcX1; - destRect.x = dstX1; - sourceRect.width = srcX0 - srcX1; - destRect.width = dstX0 - dstX1; - } +const std::string &Context::getExtensionString(size_t idx) const +{ + return mExtensionStrings[idx]; +} - if (srcY0 < srcY1) - { - sourceRect.height = srcY1 - srcY0; - destRect.height = dstY1 - dstY0; - sourceRect.y = srcY0; - destRect.y = dstY0; - } - else - { - sourceRect.height = srcY0 - srcY1; - destRect.height = dstY0 - srcY1; - sourceRect.y = srcY1; - destRect.y = dstY1; - } +size_t Context::getExtensionStringCount() const +{ + return mExtensionStrings.size(); +} - Rectangle sourceScissoredRect = sourceRect; - Rectangle destScissoredRect = destRect; +size_t Context::getBoundFramebufferTextureSerials(FramebufferTextureSerialArray *outSerialArray) +{ + size_t serialCount = 0; - if (mState.scissorTest) + Framebuffer *drawFramebuffer = mState.getDrawFramebuffer(); + for (unsigned int i = 0; i < IMPLEMENTATION_MAX_DRAW_BUFFERS; i++) { - // Only write to parts of the destination framebuffer which pass the scissor test. - if (destRect.x < mState.scissor.x) - { - int xDiff = mState.scissor.x - destRect.x; - destScissoredRect.x = mState.scissor.x; - destScissoredRect.width -= xDiff; - sourceScissoredRect.x += xDiff; - sourceScissoredRect.width -= xDiff; - - } - - if (destRect.x + destRect.width > mState.scissor.x + mState.scissor.width) - { - int xDiff = (destRect.x + destRect.width) - (mState.scissor.x + mState.scissor.width); - destScissoredRect.width -= xDiff; - sourceScissoredRect.width -= xDiff; - } - - if (destRect.y < mState.scissor.y) + FramebufferAttachment *attachment = drawFramebuffer->getColorbuffer(i); + if (attachment && attachment->isTexture()) { - int yDiff = mState.scissor.y - destRect.y; - destScissoredRect.y = mState.scissor.y; - destScissoredRect.height -= yDiff; - sourceScissoredRect.y += yDiff; - sourceScissoredRect.height -= yDiff; - } - - if (destRect.y + destRect.height > mState.scissor.y + mState.scissor.height) - { - int yDiff = (destRect.y + destRect.height) - (mState.scissor.y + mState.scissor.height); - destScissoredRect.height -= yDiff; - sourceScissoredRect.height -= yDiff; + (*outSerialArray)[serialCount++] = attachment->getTextureSerial(); } } - bool blitRenderTarget = false; - bool blitDepthStencil = false; - - Rectangle sourceTrimmedRect = sourceScissoredRect; - Rectangle destTrimmedRect = destScissoredRect; - - // The source & destination rectangles also may need to be trimmed if they fall out of the bounds of - // the actual draw and read surfaces. - if (sourceTrimmedRect.x < 0) + FramebufferAttachment *depthStencilAttachment = drawFramebuffer->getDepthOrStencilbuffer(); + if (depthStencilAttachment && depthStencilAttachment->isTexture()) { - int xDiff = 0 - sourceTrimmedRect.x; - sourceTrimmedRect.x = 0; - sourceTrimmedRect.width -= xDiff; - destTrimmedRect.x += xDiff; - destTrimmedRect.width -= xDiff; + (*outSerialArray)[serialCount++] = depthStencilAttachment->getTextureSerial(); } - if (sourceTrimmedRect.x + sourceTrimmedRect.width > readBufferWidth) - { - int xDiff = (sourceTrimmedRect.x + sourceTrimmedRect.width) - readBufferWidth; - sourceTrimmedRect.width -= xDiff; - destTrimmedRect.width -= xDiff; - } + std::sort(outSerialArray->begin(), outSerialArray->begin() + serialCount); - if (sourceTrimmedRect.y < 0) - { - int yDiff = 0 - sourceTrimmedRect.y; - sourceTrimmedRect.y = 0; - sourceTrimmedRect.height -= yDiff; - destTrimmedRect.y += yDiff; - destTrimmedRect.height -= yDiff; - } + return serialCount; +} - if (sourceTrimmedRect.y + sourceTrimmedRect.height > readBufferHeight) - { - int yDiff = (sourceTrimmedRect.y + sourceTrimmedRect.height) - readBufferHeight; - sourceTrimmedRect.height -= yDiff; - destTrimmedRect.height -= yDiff; - } +void Context::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, + GLbitfield mask, GLenum filter) +{ + Framebuffer *readFramebuffer = mState.getReadFramebuffer(); + Framebuffer *drawFramebuffer = mState.getDrawFramebuffer(); - if (destTrimmedRect.x < 0) + bool blitRenderTarget = false; + bool blitDepth = false; + bool blitStencil = false; + if ((mask & GL_COLOR_BUFFER_BIT) && readFramebuffer->getReadColorbuffer() && drawFramebuffer->getFirstColorbuffer()) { - int xDiff = 0 - destTrimmedRect.x; - destTrimmedRect.x = 0; - destTrimmedRect.width -= xDiff; - sourceTrimmedRect.x += xDiff; - sourceTrimmedRect.width -= xDiff; + blitRenderTarget = true; } - - if (destTrimmedRect.x + destTrimmedRect.width > drawBufferWidth) + if ((mask & GL_STENCIL_BUFFER_BIT) && readFramebuffer->getStencilbuffer() && drawFramebuffer->getStencilbuffer()) { - int xDiff = (destTrimmedRect.x + destTrimmedRect.width) - drawBufferWidth; - destTrimmedRect.width -= xDiff; - sourceTrimmedRect.width -= xDiff; + blitStencil = true; } - - if (destTrimmedRect.y < 0) + if ((mask & GL_DEPTH_BUFFER_BIT) && readFramebuffer->getDepthbuffer() && drawFramebuffer->getDepthbuffer()) { - int yDiff = 0 - destTrimmedRect.y; - destTrimmedRect.y = 0; - destTrimmedRect.height -= yDiff; - sourceTrimmedRect.y += yDiff; - sourceTrimmedRect.height -= yDiff; + blitDepth = true; } - if (destTrimmedRect.y + destTrimmedRect.height > drawBufferHeight) + gl::Rectangle srcRect(srcX0, srcY0, srcX1 - srcX0, srcY1 - srcY0); + gl::Rectangle dstRect(dstX0, dstY0, dstX1 - dstX0, dstY1 - dstY0); + if (blitRenderTarget || blitDepth || blitStencil) { - int yDiff = (destTrimmedRect.y + destTrimmedRect.height) - drawBufferHeight; - destTrimmedRect.height -= yDiff; - sourceTrimmedRect.height -= yDiff; + const gl::Rectangle *scissor = mState.isScissorTestEnabled() ? &mState.getScissor() : NULL; + mRenderer->blitRect(readFramebuffer, srcRect, drawFramebuffer, dstRect, scissor, + blitRenderTarget, blitDepth, blitStencil, filter); } +} - bool partialBufferCopy = false; - if (sourceTrimmedRect.height < readBufferHeight || - sourceTrimmedRect.width < readBufferWidth || - destTrimmedRect.height < drawBufferHeight || - destTrimmedRect.width < drawBufferWidth || - sourceTrimmedRect.y != 0 || destTrimmedRect.y != 0 || sourceTrimmedRect.x != 0 || destTrimmedRect.x != 0) +void Context::invalidateFrameBuffer(GLenum target, GLsizei numAttachments, const GLenum* attachments, + GLint x, GLint y, GLsizei width, GLsizei height) +{ + Framebuffer *frameBuffer = NULL; + switch (target) { - partialBufferCopy = true; + case GL_FRAMEBUFFER: + case GL_DRAW_FRAMEBUFFER: + frameBuffer = mState.getDrawFramebuffer(); + break; + case GL_READ_FRAMEBUFFER: + frameBuffer = mState.getReadFramebuffer(); + break; + default: + UNREACHABLE(); } - if (mask & GL_COLOR_BUFFER_BIT) + if (frameBuffer && frameBuffer->completeness() == GL_FRAMEBUFFER_COMPLETE) { - const GLenum readColorbufferType = readFramebuffer->getReadColorbufferType(); - const bool validReadType = (readColorbufferType == GL_TEXTURE_2D) || (readColorbufferType == GL_RENDERBUFFER); - bool validDrawType = true; - bool validDrawFormat = true; - - for (unsigned int colorAttachment = 0; colorAttachment < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++) + for (int i = 0; i < numAttachments; ++i) { - if (drawFramebuffer->isEnabledColorAttachment(colorAttachment)) + rx::RenderTarget *renderTarget = NULL; + + if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT15) + { + gl::FramebufferAttachment *attachment = frameBuffer->getColorbuffer(attachments[i] - GL_COLOR_ATTACHMENT0); + if (attachment) + { + renderTarget = attachment->getRenderTarget(); + } + } + else if (attachments[i] == GL_COLOR) + { + gl::FramebufferAttachment *attachment = frameBuffer->getColorbuffer(0); + if (attachment) + { + renderTarget = attachment->getRenderTarget(); + } + } + else { - if (drawFramebuffer->getColorbufferType(colorAttachment) != GL_TEXTURE_2D && - drawFramebuffer->getColorbufferType(colorAttachment) != GL_RENDERBUFFER) + gl::FramebufferAttachment *attachment = NULL; + switch (attachments[i]) { - validDrawType = false; + case GL_DEPTH_ATTACHMENT: + case GL_DEPTH: + attachment = frameBuffer->getDepthbuffer(); + break; + case GL_STENCIL_ATTACHMENT: + case GL_STENCIL: + attachment = frameBuffer->getStencilbuffer(); + break; + case GL_DEPTH_STENCIL_ATTACHMENT: + attachment = frameBuffer->getDepthOrStencilbuffer(); + break; + default: + UNREACHABLE(); } - if (drawFramebuffer->getColorbuffer(colorAttachment)->getActualFormat() != readColorBuffer->getActualFormat()) + if (attachment) { - validDrawFormat = false; + renderTarget = attachment->getDepthStencil(); } } - } - if (!validReadType || !validDrawType || !validDrawFormat) - { - ERR("Color buffer format conversion in BlitFramebufferANGLE not supported by this implementation"); - return gl::error(GL_INVALID_OPERATION); - } - - if (partialBufferCopy && readFramebuffer->getSamples() != 0) - { - return gl::error(GL_INVALID_OPERATION); + if (renderTarget) + { + renderTarget->invalidate(x, y, width, height); + } } - - blitRenderTarget = true; - } +} - if (mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) +bool Context::hasMappedBuffer(GLenum target) const +{ + if (target == GL_ARRAY_BUFFER) { - Renderbuffer *readDSBuffer = NULL; - Renderbuffer *drawDSBuffer = NULL; - - // We support OES_packed_depth_stencil, and do not support a separately attached depth and stencil buffer, so if we have - // both a depth and stencil buffer, it will be the same buffer. - - if (mask & GL_DEPTH_BUFFER_BIT) + for (unsigned int attribIndex = 0; attribIndex < gl::MAX_VERTEX_ATTRIBS; attribIndex++) { - if (readFramebuffer->getDepthbuffer() && drawFramebuffer->getDepthbuffer()) + const gl::VertexAttribute &vertexAttrib = mState.getVertexAttribState(attribIndex); + gl::Buffer *boundBuffer = vertexAttrib.buffer.get(); + if (vertexAttrib.enabled && boundBuffer && boundBuffer->isMapped()) { - if (readFramebuffer->getDepthbufferType() != drawFramebuffer->getDepthbufferType() || - readFramebuffer->getDepthbuffer()->getActualFormat() != drawFramebuffer->getDepthbuffer()->getActualFormat()) - { - return gl::error(GL_INVALID_OPERATION); - } - - blitDepthStencil = true; - readDSBuffer = readFramebuffer->getDepthbuffer(); - drawDSBuffer = drawFramebuffer->getDepthbuffer(); + return true; } } + } + else if (target == GL_ELEMENT_ARRAY_BUFFER) + { + Buffer *elementBuffer = mState.getTargetBuffer(target); + return (elementBuffer && elementBuffer->isMapped()); + } + else if (target == GL_TRANSFORM_FEEDBACK_BUFFER) + { + UNIMPLEMENTED(); + } + else UNREACHABLE(); + return false; +} - if (mask & GL_STENCIL_BUFFER_BIT) - { - if (readFramebuffer->getStencilbuffer() && drawFramebuffer->getStencilbuffer()) - { - if (readFramebuffer->getStencilbufferType() != drawFramebuffer->getStencilbufferType() || - readFramebuffer->getStencilbuffer()->getActualFormat() != drawFramebuffer->getStencilbuffer()->getActualFormat()) - { - return gl::error(GL_INVALID_OPERATION); - } +void Context::initCaps(GLuint clientVersion) +{ + mCaps = mRenderer->getRendererCaps(); - blitDepthStencil = true; - readDSBuffer = readFramebuffer->getStencilbuffer(); - drawDSBuffer = drawFramebuffer->getStencilbuffer(); - } - } + mExtensions = mRenderer->getRendererExtensions(); - if (partialBufferCopy) - { - ERR("Only whole-buffer depth and stencil blits are supported by this implementation."); - return gl::error(GL_INVALID_OPERATION); // only whole-buffer copies are permitted - } + if (clientVersion < 3) + { + // Disable ES3+ extensions + mExtensions.colorBufferFloat = false; + } - if ((drawDSBuffer && drawDSBuffer->getSamples() != 0) || - (readDSBuffer && readDSBuffer->getSamples() != 0)) - { - return gl::error(GL_INVALID_OPERATION); - } + if (clientVersion > 2) + { + // FIXME(geofflang): Don't support EXT_sRGB in non-ES2 contexts + //mExtensions.sRGB = false; } - if (blitRenderTarget || blitDepthStencil) + const TextureCapsMap &rendererFormats = mRenderer->getRendererTextureCaps(); + for (TextureCapsMap::const_iterator i = rendererFormats.begin(); i != rendererFormats.end(); i++) { - mRenderer->blitRect(readFramebuffer, sourceTrimmedRect, drawFramebuffer, destTrimmedRect, blitRenderTarget, blitDepthStencil); + GLenum format = i->first; + TextureCaps formatCaps = i->second; + + if (formatCaps.texturable && IsValidInternalFormat(format, mExtensions, clientVersion)) + { + // Update the format caps based on the client version and extensions + formatCaps.renderable = IsRenderingSupported(format, mExtensions, clientVersion); + formatCaps.filterable = IsFilteringSupported(format, mExtensions, clientVersion); + mTextureCaps.insert(format, formatCaps); + } } } @@ -2971,9 +2544,9 @@ void Context::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1 extern "C" { -gl::Context *glCreateContext(const gl::Context *shareContext, rx::Renderer *renderer, bool notifyResets, bool robustAccess) +gl::Context *glCreateContext(int clientVersion, const gl::Context *shareContext, rx::Renderer *renderer, bool notifyResets, bool robustAccess) { - return new gl::Context(shareContext, renderer, notifyResets, robustAccess); + return new gl::Context(clientVersion, shareContext, renderer, notifyResets, robustAccess); } void glDestroyContext(gl::Context *context) -- cgit v1.2.3