diff options
Diffstat (limited to 'Source/ThirdParty/ANGLE/src/libGLESv2/Context.cpp')
-rw-r--r-- | Source/ThirdParty/ANGLE/src/libGLESv2/Context.cpp | 1926 |
1 files changed, 1310 insertions, 616 deletions
diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/Context.cpp b/Source/ThirdParty/ANGLE/src/libGLESv2/Context.cpp index 9be59c4..66cd5c0 100644 --- a/Source/ThirdParty/ANGLE/src/libGLESv2/Context.cpp +++ b/Source/ThirdParty/ANGLE/src/libGLESv2/Context.cpp @@ -1,5 +1,5 @@ // -// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2002-2012 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. // @@ -22,20 +22,27 @@ #include "libGLESv2/Fence.h" #include "libGLESv2/FrameBuffer.h" #include "libGLESv2/Program.h" +#include "libGLESv2/Query.h" #include "libGLESv2/RenderBuffer.h" #include "libGLESv2/Shader.h" #include "libGLESv2/Texture.h" -#include "libGLESv2/geometry/VertexDataManager.h" -#include "libGLESv2/geometry/IndexDataManager.h" +#include "libGLESv2/VertexDataManager.h" +#include "libGLESv2/IndexDataManager.h" #undef near #undef far namespace gl { -Context::Context(const egl::Config *config, const gl::Context *shareContext) - : mConfig(config) +Context::Context(const egl::Config *config, const gl::Context *shareContext, bool notifyResets, bool robustAccess) : mConfig(config) { + ASSERT(robustAccess == false); // Unimplemented + + mDisplay = NULL; + mDevice = NULL; + + mFenceHandleAllocator.setBaseHandle(0); + setClearColor(0.0f, 0.0f, 0.0f, 0.0f); mState.depthClearValue = 1.0f; @@ -136,10 +143,12 @@ Context::Context(const egl::Config *config, const gl::Context *shareContext) mState.packAlignment = 4; mState.unpackAlignment = 4; + mState.packReverseRowOrder = false; mVertexDataManager = NULL; mIndexDataManager = NULL; mBlit = NULL; + mLineLoopIB = NULL; mInvalidEnum = false; mInvalidValue = false; @@ -148,9 +157,17 @@ Context::Context(const egl::Config *config, const gl::Context *shareContext) mInvalidFramebufferOperation = false; mHasBeenCurrent = false; - - mSupportsCompressedTextures = false; + mContextLost = false; + mResetStatus = GL_NO_ERROR; + mResetStrategy = (notifyResets ? GL_LOSE_CONTEXT_ON_RESET_EXT : GL_NO_RESET_NOTIFICATION_EXT); + mRobustAccess = robustAccess; + + mSupportsDXT1Textures = false; + mSupportsDXT3Textures = false; + mSupportsDXT5Textures = false; mSupportsEventQueries = false; + mSupportsOcclusionQueries = false; + mNumCompressedTextureFormats = 0; mMaxSupportedSamples = 0; mMaskedClearSavedState = NULL; markAllStateDirty(); @@ -178,21 +195,26 @@ Context::~Context() deleteFence(mFenceMap.begin()->first); } + while (!mQueryMap.empty()) + { + deleteQuery(mQueryMap.begin()->first); + } + while (!mMultiSampleSupport.empty()) { delete [] mMultiSampleSupport.begin()->second; mMultiSampleSupport.erase(mMultiSampleSupport.begin()); } - for (int type = 0; type < SAMPLER_TYPE_COUNT; type++) + for (int type = 0; type < TEXTURE_TYPE_COUNT; type++) { - for (int sampler = 0; sampler < MAX_TEXTURE_IMAGE_UNITS; sampler++) + for (int sampler = 0; sampler < MAX_COMBINED_TEXTURE_IMAGE_UNITS_VTF; sampler++) { mState.samplerTexture[type][sampler].set(NULL); } } - for (int type = 0; type < SAMPLER_TYPE_COUNT; type++) + for (int type = 0; type < TEXTURE_TYPE_COUNT; type++) { mIncompleteTextures[type].set(NULL); } @@ -202,6 +224,11 @@ Context::~Context() mState.vertexAttribute[i].mBoundBuffer.set(NULL); } + for (int i = 0; i < QUERY_TYPE_COUNT; i++) + { + mState.activeQuery[i].set(NULL); + } + mState.arrayBuffer.set(NULL); mState.elementArrayBuffer.set(NULL); mState.renderbuffer.set(NULL); @@ -212,6 +239,7 @@ Context::~Context() delete mVertexDataManager; delete mIndexDataManager; delete mBlit; + delete mLineLoopIB; if (mMaskedClearSavedState) { @@ -223,17 +251,21 @@ Context::~Context() void Context::makeCurrent(egl::Display *display, egl::Surface *surface) { - IDirect3DDevice9 *device = display->getDevice(); + mDisplay = display; + mDevice = mDisplay->getDevice(); if (!mHasBeenCurrent) { - mDeviceCaps = display->getDeviceCaps(); + mDeviceCaps = mDisplay->getDeviceCaps(); - mVertexDataManager = new VertexDataManager(this, device); - mIndexDataManager = new IndexDataManager(this, device); + mVertexDataManager = new VertexDataManager(this, mDevice); + mIndexDataManager = new IndexDataManager(this, mDevice); mBlit = new Blit(this); - mSupportsShaderModel3 = mDeviceCaps.PixelShaderVersion == D3DPS_VERSION(3, 0); + mSupportsShaderModel3 = mDeviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0); + mSupportsVertexTexture = mDisplay->getVertexTextureSupport(); + mSupportsNonPower2Texture = mDisplay->getNonPower2TextureSupport(); + mSupportsInstancing = mDisplay->getInstancingSupport(); mMaxTextureDimension = std::min(std::min((int)mDeviceCaps.MaxTextureWidth, (int)mDeviceCaps.MaxTextureHeight), (int)gl::IMPLEMENTATION_MAX_TEXTURE_SIZE); @@ -255,7 +287,7 @@ void Context::makeCurrent(egl::Display *display, egl::Surface *surface) for (int i = 0; i < sizeof(renderBufferFormats) / sizeof(D3DFORMAT); ++i) { bool *multisampleArray = new bool[D3DMULTISAMPLE_16_SAMPLES + 1]; - display->getMultiSampleSupport(renderBufferFormats[i], multisampleArray); + mDisplay->getMultiSampleSupport(renderBufferFormats[i], multisampleArray); mMultiSampleSupport[renderBufferFormats[i]] = multisampleArray; for (int j = D3DMULTISAMPLE_16_SAMPLES; j >= 0; --j) @@ -269,16 +301,34 @@ void Context::makeCurrent(egl::Display *display, egl::Surface *surface) mMaxSupportedSamples = max; - mSupportsEventQueries = display->getEventQuerySupport(); - mSupportsCompressedTextures = display->getCompressedTextureSupport(); - mSupportsFloatTextures = display->getFloatTextureSupport(&mSupportsFloatLinearFilter, &mSupportsFloatRenderableTextures); - mSupportsHalfFloatTextures = display->getHalfFloatTextureSupport(&mSupportsHalfFloatLinearFilter, &mSupportsHalfFloatRenderableTextures); - mSupportsLuminanceTextures = display->getLuminanceTextureSupport(); - mSupportsLuminanceAlphaTextures = display->getLuminanceAlphaTextureSupport(); + mSupportsEventQueries = mDisplay->getEventQuerySupport(); + mSupportsOcclusionQueries = mDisplay->getOcclusionQuerySupport(); + mSupportsDXT1Textures = mDisplay->getDXT1TextureSupport(); + mSupportsDXT3Textures = mDisplay->getDXT3TextureSupport(); + mSupportsDXT5Textures = mDisplay->getDXT5TextureSupport(); + mSupportsFloat32Textures = mDisplay->getFloat32TextureSupport(&mSupportsFloat32LinearFilter, &mSupportsFloat32RenderableTextures); + mSupportsFloat16Textures = mDisplay->getFloat16TextureSupport(&mSupportsFloat16LinearFilter, &mSupportsFloat16RenderableTextures); + mSupportsLuminanceTextures = mDisplay->getLuminanceTextureSupport(); + mSupportsLuminanceAlphaTextures = mDisplay->getLuminanceAlphaTextureSupport(); mSupports32bitIndices = mDeviceCaps.MaxVertexIndex >= (1 << 16); + mNumCompressedTextureFormats = 0; + if (supportsDXT1Textures()) + { + mNumCompressedTextureFormats += 2; + } + if (supportsDXT3Textures()) + { + mNumCompressedTextureFormats += 1; + } + if (supportsDXT5Textures()) + { + mNumCompressedTextureFormats += 1; + } + initExtensionString(); + initRendererString(); mState.viewportX = 0; mState.viewportY = 0; @@ -319,11 +369,26 @@ void Context::makeCurrent(egl::Display *display, egl::Surface *surface) // This function will set all of the state-related dirty flags, so that all state is set during next pre-draw. void Context::markAllStateDirty() { + for (int t = 0; t < MAX_TEXTURE_IMAGE_UNITS; t++) + { + mAppliedTextureSerialPS[t] = 0; + } + + for (int t = 0; t < MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF; t++) + { + mAppliedTextureSerialVS[t] = 0; + } + + mAppliedProgramSerial = 0; mAppliedRenderTargetSerial = 0; mAppliedDepthbufferSerial = 0; mAppliedStencilbufferSerial = 0; + mAppliedIBSerial = 0; mDepthStencilInitialized = false; - mAppliedProgram = 0; + mViewportInitialized = false; + mRenderTargetDescInitialized = false; + + mVertexDeclarationCache.markStateDirty(); mClearStateDirty = true; mCullStateDirty = true; @@ -336,6 +401,20 @@ void Context::markAllStateDirty() mSampleStateDirty = true; mDitherStateDirty = true; mFrontFaceDirty = true; + mDxUniformsDirty = true; + mCachedCurrentProgram = NULL; +} + +void Context::markContextLost() +{ + if (mResetStrategy == GL_LOSE_CONTEXT_ON_RESET_EXT) + mResetStatus = GL_UNKNOWN_CONTEXT_RESET_EXT; + mContextLost = true; +} + +bool Context::isContextLost() +{ + return mContextLost; } void Context::setClearColor(float red, float green, float blue, float alpha) @@ -710,7 +789,7 @@ void Context::setDepthMask(bool mask) } } -void Context::setActiveSampler(int active) +void Context::setActiveSampler(unsigned int active) { mState.activeSampler = active; } @@ -735,6 +814,32 @@ GLuint Context::getArrayBufferHandle() const return mState.arrayBuffer.id(); } +GLuint Context::getActiveQuery(GLenum target) 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); + } + + if (queryObject) + { + return queryObject->id(); + } + else + { + return 0; + } +} + void Context::setEnableVertexAttribArray(unsigned int attribNum, bool enabled) { mState.vertexAttribute[attribNum].mArrayEnabled = enabled; @@ -786,6 +891,16 @@ GLint Context::getUnpackAlignment() const return mState.unpackAlignment; } +void Context::setPackReverseRowOrder(bool reverseRowOrder) +{ + mState.packReverseRowOrder = reverseRowOrder; +} + +bool Context::getPackReverseRowOrder() const +{ + return mState.packReverseRowOrder; +} + GLuint Context::createBuffer() { return mResourceManager->createBuffer(); @@ -814,12 +929,7 @@ GLuint Context::createRenderbuffer() // Returns an unused framebuffer name GLuint Context::createFramebuffer() { - unsigned int handle = 1; - - while (mFramebufferMap.find(handle) != mFramebufferMap.end()) - { - handle++; - } + GLuint handle = mFramebufferHandleAllocator.allocate(); mFramebufferMap[handle] = NULL; @@ -828,14 +938,19 @@ GLuint Context::createFramebuffer() GLuint Context::createFence() { - unsigned int handle = 0; + GLuint handle = mFenceHandleAllocator.allocate(); - while (mFenceMap.find(handle) != mFenceMap.end()) - { - handle++; - } + mFenceMap[handle] = new Fence(mDisplay); - mFenceMap[handle] = new Fence; + return handle; +} + +// Returns an unused query name +GLuint Context::createQuery() +{ + GLuint handle = mQueryHandleAllocator.allocate(); + + mQueryMap[handle] = NULL; return handle; } @@ -858,6 +973,7 @@ void Context::deleteShader(GLuint shader) void Context::deleteProgram(GLuint program) { mResourceManager->deleteProgram(program); + mCachedCurrentProgram = NULL; } void Context::deleteTexture(GLuint texture) @@ -888,6 +1004,7 @@ void Context::deleteFramebuffer(GLuint framebuffer) { detachFramebuffer(framebuffer); + mFramebufferHandleAllocator.release(framebufferObject->first); delete framebufferObject->second; mFramebufferMap.erase(framebufferObject); } @@ -899,11 +1016,26 @@ void Context::deleteFence(GLuint 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); @@ -936,7 +1068,7 @@ Framebuffer *Context::getReadFramebuffer() Framebuffer *Context::getDrawFramebuffer() { - return getFramebuffer(mState.drawFramebuffer); + return mBoundDrawFramebuffer; } void Context::bindArrayBuffer(unsigned int buffer) @@ -955,16 +1087,16 @@ void Context::bindElementArrayBuffer(unsigned int buffer) void Context::bindTexture2D(GLuint texture) { - mResourceManager->checkTextureAllocation(texture, SAMPLER_2D); + mResourceManager->checkTextureAllocation(texture, TEXTURE_2D); - mState.samplerTexture[SAMPLER_2D][mState.activeSampler].set(getTexture(texture)); + mState.samplerTexture[TEXTURE_2D][mState.activeSampler].set(getTexture(texture)); } void Context::bindTextureCubeMap(GLuint texture) { - mResourceManager->checkTextureAllocation(texture, SAMPLER_CUBE); + mResourceManager->checkTextureAllocation(texture, TEXTURE_CUBE); - mState.samplerTexture[SAMPLER_CUBE][mState.activeSampler].set(getTexture(texture)); + mState.samplerTexture[TEXTURE_CUBE][mState.activeSampler].set(getTexture(texture)); } void Context::bindReadFramebuffer(GLuint framebuffer) @@ -985,6 +1117,8 @@ void Context::bindDrawFramebuffer(GLuint framebuffer) } mState.drawFramebuffer = framebuffer; + + mBoundDrawFramebuffer = getFramebuffer(framebuffer); } void Context::bindRenderbuffer(GLuint renderbuffer) @@ -1003,6 +1137,8 @@ void Context::useProgram(GLuint program) { Program *newProgram = mResourceManager->getProgram(program); Program *oldProgram = mResourceManager->getProgram(priorProgram); + mCachedCurrentProgram = NULL; + mDxUniformsDirty = true; if (newProgram) { @@ -1016,10 +1152,103 @@ void Context::useProgram(GLuint program) } } +void Context::beginQuery(GLenum target, GLuint query) +{ + // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id> + // of zero, if the active query object name for <target> 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 <id> is the name of an + // existing query object whose type does not match <target>, or if <id> 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 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; + } + + Query *queryObject = getQuery(query, true, target); + + // check that name was obtained with glGenQueries + if (!queryObject) + { + return error(GL_INVALID_OPERATION); + } + + // check for type mismatch + if (queryObject->getType() != target) + { + return error(GL_INVALID_OPERATION); + } + + // set query as active for specified target + mState.activeQuery[qType].set(queryObject); + + // begin query + queryObject->begin(); +} + +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 error(GL_INVALID_OPERATION); + } + + queryObject->end(); + + mState.activeQuery[qType].set(NULL); +} + void Context::setFramebufferZero(Framebuffer *buffer) { delete mFramebufferMap[0]; mFramebufferMap[0] = buffer; + if (mState.drawFramebuffer == 0) + { + mBoundDrawFramebuffer = buffer; + } } void Context::setRenderbufferStorage(RenderbufferStorage *renderbuffer) @@ -1056,6 +1285,25 @@ Fence *Context::getFence(unsigned int handle) } } +Query *Context::getQuery(unsigned int handle, bool create, GLenum type) +{ + QueryMap::iterator query = mQueryMap.find(handle); + + if (query == mQueryMap.end()) + { + return NULL; + } + else + { + if (!query->second && create) + { + query->second = new Query(handle, type); + query->second->addRef(); + } + return query->second; + } +} + Buffer *Context::getArrayBuffer() { return mState.arrayBuffer.get(); @@ -1068,20 +1316,24 @@ Buffer *Context::getElementArrayBuffer() Program *Context::getCurrentProgram() { - return mResourceManager->getProgram(mState.currentProgram); + if (!mCachedCurrentProgram) + { + mCachedCurrentProgram = mResourceManager->getProgram(mState.currentProgram); + } + return mCachedCurrentProgram; } Texture2D *Context::getTexture2D() { - return static_cast<Texture2D*>(getSamplerTexture(mState.activeSampler, SAMPLER_2D)); + return static_cast<Texture2D*>(getSamplerTexture(mState.activeSampler, TEXTURE_2D)); } TextureCubeMap *Context::getTextureCubeMap() { - return static_cast<TextureCubeMap*>(getSamplerTexture(mState.activeSampler, SAMPLER_CUBE)); + return static_cast<TextureCubeMap*>(getSamplerTexture(mState.activeSampler, TEXTURE_CUBE)); } -Texture *Context::getSamplerTexture(unsigned int sampler, SamplerType type) +Texture *Context::getSamplerTexture(unsigned int sampler, TextureType type) { GLuint texid = mState.samplerTexture[type][sampler].id(); @@ -1090,8 +1342,8 @@ Texture *Context::getSamplerTexture(unsigned int sampler, SamplerType type) switch (type) { default: UNREACHABLE(); - case SAMPLER_2D: return mTexture2DZero.get(); - case SAMPLER_CUBE: return mTextureCubeMapZero.get(); + case TEXTURE_2D: return mTexture2DZero.get(); + case TEXTURE_CUBE: return mTextureCubeMapZero.get(); } } @@ -1102,24 +1354,25 @@ bool 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.depthMask; break; + case GL_SHADER_COMPILER: *params = GL_TRUE; break; + case GL_SAMPLE_COVERAGE_INVERT: *params = mState.sampleCoverageInvert; break; + case GL_DEPTH_WRITEMASK: *params = mState.depthMask; break; case GL_COLOR_WRITEMASK: params[0] = mState.colorMaskRed; params[1] = mState.colorMaskGreen; params[2] = mState.colorMaskBlue; params[3] = mState.colorMaskAlpha; break; - case GL_CULL_FACE: *params = mState.cullFace; break; - case GL_POLYGON_OFFSET_FILL: *params = mState.polygonOffsetFill; break; - case GL_SAMPLE_ALPHA_TO_COVERAGE: *params = mState.sampleAlphaToCoverage; break; - case GL_SAMPLE_COVERAGE: *params = mState.sampleCoverage; break; - case GL_SCISSOR_TEST: *params = mState.scissorTest; break; - case GL_STENCIL_TEST: *params = mState.stencilTest; break; - case GL_DEPTH_TEST: *params = mState.depthTest; break; - case GL_BLEND: *params = mState.blend; break; - case GL_DITHER: *params = mState.dither; break; + case GL_CULL_FACE: *params = mState.cullFace; break; + case GL_POLYGON_OFFSET_FILL: *params = mState.polygonOffsetFill; break; + case GL_SAMPLE_ALPHA_TO_COVERAGE: *params = mState.sampleAlphaToCoverage; break; + case GL_SAMPLE_COVERAGE: *params = mState.sampleCoverage; break; + case GL_SCISSOR_TEST: *params = mState.scissorTest; break; + case GL_STENCIL_TEST: *params = mState.stencilTest; break; + case GL_DEPTH_TEST: *params = mState.depthTest; break; + case GL_BLEND: *params = mState.blend; break; + case GL_DITHER: *params = mState.dither; break; + case GL_CONTEXT_ROBUST_ACCESS_EXT: *params = mRobustAccess ? GL_TRUE : GL_FALSE; break; default: return false; } @@ -1183,8 +1436,8 @@ bool Context::getIntegerv(GLenum pname, GLint *params) case GL_MAX_VERTEX_ATTRIBS: *params = gl::MAX_VERTEX_ATTRIBS; break; case GL_MAX_VERTEX_UNIFORM_VECTORS: *params = gl::MAX_VERTEX_UNIFORM_VECTORS; break; case GL_MAX_VARYING_VECTORS: *params = getMaximumVaryingVectors(); break; - case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: *params = gl::MAX_COMBINED_TEXTURE_IMAGE_UNITS; break; - case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS: *params = gl::MAX_VERTEX_TEXTURE_IMAGE_UNITS; break; + case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: *params = getMaximumCombinedTextureImageUnits(); break; + case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS: *params = getMaximumVertexTextureImageUnits(); break; case GL_MAX_TEXTURE_IMAGE_UNITS: *params = gl::MAX_TEXTURE_IMAGE_UNITS; break; case GL_MAX_FRAGMENT_UNIFORM_VECTORS: *params = getMaximumFragmentUniformVectors(); break; case GL_MAX_RENDERBUFFER_SIZE: *params = getMaximumRenderbufferDimension(); break; @@ -1198,6 +1451,7 @@ bool Context::getIntegerv(GLenum pname, GLint *params) 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; @@ -1228,18 +1482,7 @@ bool Context::getIntegerv(GLenum pname, GLint *params) case GL_MAX_TEXTURE_SIZE: *params = getMaximumTextureDimension(); break; case GL_MAX_CUBE_MAP_TEXTURE_SIZE: *params = getMaximumCubeTextureDimension(); break; case GL_NUM_COMPRESSED_TEXTURE_FORMATS: - { - if (supportsCompressedTextures()) - { - // at current, only GL_COMPRESSED_RGB_S3TC_DXT1_EXT and - // GL_COMPRESSED_RGBA_S3TC_DXT1_EXT are supported - *params = 2; - } - else - { - *params = 0; - } - } + params[0] = mNumCompressedTextureFormats; break; case GL_MAX_SAMPLES_ANGLE: { @@ -1295,10 +1538,18 @@ bool Context::getIntegerv(GLenum pname, GLint *params) break; case GL_COMPRESSED_TEXTURE_FORMATS: { - if (supportsCompressedTextures()) + if (supportsDXT1Textures()) + { + *params++ = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; + *params++ = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; + } + if (supportsDXT3Textures()) + { + *params++ = GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE; + } + if (supportsDXT5Textures()) { - params[0] = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; - params[1] = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; + *params++ = GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE; } } break; @@ -1322,7 +1573,7 @@ bool Context::getIntegerv(GLenum pname, GLint *params) case GL_ALPHA_BITS: { gl::Framebuffer *framebuffer = getDrawFramebuffer(); - gl::Colorbuffer *colorbuffer = framebuffer->getColorbuffer(); + gl::Renderbuffer *colorbuffer = framebuffer->getColorbuffer(); if (colorbuffer) { @@ -1343,7 +1594,7 @@ bool Context::getIntegerv(GLenum pname, GLint *params) case GL_DEPTH_BITS: { gl::Framebuffer *framebuffer = getDrawFramebuffer(); - gl::DepthStencilbuffer *depthbuffer = framebuffer->getDepthbuffer(); + gl::Renderbuffer *depthbuffer = framebuffer->getDepthbuffer(); if (depthbuffer) { @@ -1358,7 +1609,7 @@ bool Context::getIntegerv(GLenum pname, GLint *params) case GL_STENCIL_BITS: { gl::Framebuffer *framebuffer = getDrawFramebuffer(); - gl::DepthStencilbuffer *stencilbuffer = framebuffer->getStencilbuffer(); + gl::Renderbuffer *stencilbuffer = framebuffer->getStencilbuffer(); if (stencilbuffer) { @@ -1372,26 +1623,29 @@ bool Context::getIntegerv(GLenum pname, GLint *params) break; case GL_TEXTURE_BINDING_2D: { - if (mState.activeSampler < 0 || mState.activeSampler > gl::MAX_TEXTURE_IMAGE_UNITS - 1) + if (mState.activeSampler < 0 || mState.activeSampler > getMaximumCombinedTextureImageUnits() - 1) { error(GL_INVALID_OPERATION); return false; } - *params = mState.samplerTexture[SAMPLER_2D][mState.activeSampler].id(); + *params = mState.samplerTexture[TEXTURE_2D][mState.activeSampler].id(); } break; case GL_TEXTURE_BINDING_CUBE_MAP: { - if (mState.activeSampler < 0 || mState.activeSampler > gl::MAX_TEXTURE_IMAGE_UNITS - 1) + if (mState.activeSampler < 0 || mState.activeSampler > getMaximumCombinedTextureImageUnits() - 1) { error(GL_INVALID_OPERATION); return false; } - *params = mState.samplerTexture[SAMPLER_CUBE][mState.activeSampler].id(); + *params = mState.samplerTexture[TEXTURE_CUBE][mState.activeSampler].id(); } break; + case GL_RESET_NOTIFICATION_STRATEGY_EXT: + *params = mResetStrategy; + break; default: return false; } @@ -1410,7 +1664,12 @@ bool Context::getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *nu // application. switch (pname) { - case GL_COMPRESSED_TEXTURE_FORMATS: /* no compressed texture formats are supported */ + case GL_COMPRESSED_TEXTURE_FORMATS: + { + *type = GL_INT; + *numParams = mNumCompressedTextureFormats; + } + break; case GL_SHADER_BINARY_FORMATS: { *type = GL_INT; @@ -1432,6 +1691,7 @@ bool Context::getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *nu case GL_RENDERBUFFER_BINDING: case GL_CURRENT_PROGRAM: case GL_PACK_ALIGNMENT: + case GL_PACK_REVERSE_ROW_ORDER_ANGLE: case GL_UNPACK_ALIGNMENT: case GL_GENERATE_MIPMAP_HINT: case GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES: @@ -1476,6 +1736,7 @@ bool Context::getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *nu case GL_IMPLEMENTATION_COLOR_READ_FORMAT: case GL_TEXTURE_BINDING_2D: case GL_TEXTURE_BINDING_CUBE_MAP: + case GL_RESET_NOTIFICATION_STRATEGY_EXT: { *type = GL_INT; *numParams = 1; @@ -1519,6 +1780,7 @@ bool Context::getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *nu case GL_DEPTH_TEST: case GL_BLEND: case GL_DITHER: + case GL_CONTEXT_ROBUST_ACCESS_EXT: { *type = GL_BOOL; *numParams = 1; @@ -1566,34 +1828,30 @@ bool Context::getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *nu // scissor rectangle to the Direct3D 9 device bool Context::applyRenderTarget(bool ignoreViewport) { - IDirect3DDevice9 *device = getDevice(); - Framebuffer *framebufferObject = getDrawFramebuffer(); if (!framebufferObject || framebufferObject->completeness() != GL_FRAMEBUFFER_COMPLETE) { - error(GL_INVALID_FRAMEBUFFER_OPERATION); - - return false; + return error(GL_INVALID_FRAMEBUFFER_OPERATION, false); } - IDirect3DSurface9 *renderTarget = framebufferObject->getRenderTarget(); - - if (!renderTarget) - { - return false; // Context must be lost - } - - IDirect3DSurface9 *depthStencil = NULL; - + bool renderTargetChanged = false; unsigned int renderTargetSerial = framebufferObject->getRenderTargetSerial(); if (renderTargetSerial != mAppliedRenderTargetSerial) { - device->SetRenderTarget(0, renderTarget); + IDirect3DSurface9 *renderTarget = framebufferObject->getRenderTarget(); + if (!renderTarget) + { + return false; // Context must be lost + } + mDevice->SetRenderTarget(0, renderTarget); mAppliedRenderTargetSerial = renderTargetSerial; mScissorStateDirty = true; // Scissor area must be clamped to render target's size-- this is different for different render targets. + renderTargetChanged = true; + renderTarget->Release(); } + IDirect3DSurface9 *depthStencil = NULL; unsigned int depthbufferSerial = 0; unsigned int stencilbufferSerial = 0; if (framebufferObject->getDepthbufferType() != GL_NONE) @@ -1623,15 +1881,25 @@ bool Context::applyRenderTarget(bool ignoreViewport) stencilbufferSerial != mAppliedStencilbufferSerial || !mDepthStencilInitialized) { - device->SetDepthStencilSurface(depthStencil); + mDevice->SetDepthStencilSurface(depthStencil); mAppliedDepthbufferSerial = depthbufferSerial; mAppliedStencilbufferSerial = stencilbufferSerial; mDepthStencilInitialized = true; } + if (!mRenderTargetDescInitialized || renderTargetChanged) + { + IDirect3DSurface9 *renderTarget = framebufferObject->getRenderTarget(); + if (!renderTarget) + { + return false; // Context must be lost + } + renderTarget->GetDesc(&mRenderTargetDesc); + mRenderTargetDescInitialized = true; + renderTarget->Release(); + } + D3DVIEWPORT9 viewport; - D3DSURFACE_DESC desc; - renderTarget->GetDesc(&desc); float zNear = clamp01(mState.zNear); float zFar = clamp01(mState.zFar); @@ -1640,17 +1908,18 @@ bool Context::applyRenderTarget(bool ignoreViewport) { viewport.X = 0; viewport.Y = 0; - viewport.Width = desc.Width; - viewport.Height = desc.Height; + viewport.Width = mRenderTargetDesc.Width; + viewport.Height = mRenderTargetDesc.Height; viewport.MinZ = 0.0f; viewport.MaxZ = 1.0f; } else { - viewport.X = std::max(mState.viewportX, 0); - viewport.Y = std::max(mState.viewportY, 0); - viewport.Width = std::min(mState.viewportWidth, (int)desc.Width - (int)viewport.X); - viewport.Height = std::min(mState.viewportHeight, (int)desc.Height - (int)viewport.Y); + RECT rect = transformPixelRect(mState.viewportX, mState.viewportY, mState.viewportWidth, mState.viewportHeight, mRenderTargetDesc.Height); + viewport.X = clamp(rect.left, 0L, static_cast<LONG>(mRenderTargetDesc.Width)); + viewport.Y = clamp(rect.top, 0L, static_cast<LONG>(mRenderTargetDesc.Height)); + viewport.Width = clamp(rect.right - rect.left, 0L, static_cast<LONG>(mRenderTargetDesc.Width) - static_cast<LONG>(viewport.X)); + viewport.Height = clamp(rect.bottom - rect.top, 0L, static_cast<LONG>(mRenderTargetDesc.Height) - static_cast<LONG>(viewport.Y)); viewport.MinZ = zNear; viewport.MaxZ = zFar; } @@ -1660,42 +1929,49 @@ bool Context::applyRenderTarget(bool ignoreViewport) return false; // Nothing to render } - device->SetViewport(&viewport); + if (renderTargetChanged || !mViewportInitialized || memcmp(&viewport, &mSetViewport, sizeof mSetViewport) != 0) + { + mDevice->SetViewport(&viewport); + mSetViewport = viewport; + mViewportInitialized = true; + mDxUniformsDirty = true; + } if (mScissorStateDirty) { if (mState.scissorTest) { - RECT rect = {mState.scissorX, - mState.scissorY, - mState.scissorX + mState.scissorWidth, - mState.scissorY + mState.scissorHeight}; - rect.right = std::min(static_cast<UINT>(rect.right), desc.Width); - rect.bottom = std::min(static_cast<UINT>(rect.bottom), desc.Height); - device->SetScissorRect(&rect); - device->SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE); + RECT rect = transformPixelRect(mState.scissorX, mState.scissorY, mState.scissorWidth, mState.scissorHeight, mRenderTargetDesc.Height); + rect.left = clamp(rect.left, 0L, static_cast<LONG>(mRenderTargetDesc.Width)); + rect.top = clamp(rect.top, 0L, static_cast<LONG>(mRenderTargetDesc.Height)); + rect.right = clamp(rect.right, 0L, static_cast<LONG>(mRenderTargetDesc.Width)); + rect.bottom = clamp(rect.bottom, 0L, static_cast<LONG>(mRenderTargetDesc.Height)); + mDevice->SetScissorRect(&rect); + mDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE); } else { - device->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE); + mDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE); } mScissorStateDirty = false; } - if (mState.currentProgram) + if (mState.currentProgram && mDxUniformsDirty) { Program *programObject = getCurrentProgram(); GLint halfPixelSize = programObject->getDxHalfPixelSizeLocation(); - GLfloat xy[2] = {1.0f / viewport.Width, 1.0f / viewport.Height}; + GLfloat xy[2] = {1.0f / viewport.Width, -1.0f / viewport.Height}; programObject->setUniform2fv(halfPixelSize, 1, xy); - GLint viewport = programObject->getDxViewportLocation(); - GLfloat whxy[4] = {mState.viewportWidth / 2.0f, mState.viewportHeight / 2.0f, + // These values are used for computing gl_FragCoord in Program::linkVaryings(). The approach depends on Shader Model 3.0 support. + GLint coord = programObject->getDxCoordLocation(); + float h = mSupportsShaderModel3 ? mRenderTargetDesc.Height : mState.viewportHeight / 2.0f; + GLfloat whxy[4] = {mState.viewportWidth / 2.0f, h, (float)mState.viewportX + mState.viewportWidth / 2.0f, (float)mState.viewportY + mState.viewportHeight / 2.0f}; - programObject->setUniform4fv(viewport, 1, whxy); + programObject->setUniform4fv(coord, 1, whxy); GLint depth = programObject->getDxDepthLocation(); GLfloat dz[2] = {(zFar - zNear) / 2.0f, (zNear + zFar) / 2.0f}; @@ -1704,6 +1980,7 @@ bool Context::applyRenderTarget(bool ignoreViewport) GLint depthRange = programObject->getDxDepthRangeLocation(); GLfloat nearFarDiff[3] = {zNear, zFar, zFar - zNear}; programObject->setUniform3fv(depthRange, 1, nearFarDiff); + mDxUniformsDirty = false; } return true; @@ -1712,28 +1989,37 @@ bool Context::applyRenderTarget(bool ignoreViewport) // Applies the fixed-function state (culling, depth test, alpha blending, stenciling, etc) to the Direct3D 9 device void Context::applyState(GLenum drawMode) { - IDirect3DDevice9 *device = getDevice(); Program *programObject = getCurrentProgram(); + Framebuffer *framebufferObject = getDrawFramebuffer(); + + GLenum adjustedFrontFace = adjustWinding(mState.frontFace); + GLint frontCCW = programObject->getDxFrontCCWLocation(); - GLint ccw = (mState.frontFace == GL_CCW); + GLint ccw = (adjustedFrontFace == GL_CCW); programObject->setUniform1iv(frontCCW, 1, &ccw); GLint pointsOrLines = programObject->getDxPointsOrLinesLocation(); GLint alwaysFront = !isTriangleMode(drawMode); programObject->setUniform1iv(pointsOrLines, 1, &alwaysFront); - Framebuffer *framebufferObject = getDrawFramebuffer(); + D3DADAPTER_IDENTIFIER9 *identifier = mDisplay->getAdapterIdentifier(); + bool zeroColorMaskAllowed = identifier->VendorId != 0x1002; + // Apparently some ATI cards have a bug where a draw with a zero color + // write mask can cause later draws to have incorrect results. Instead, + // set a nonzero color write mask but modify the blend state so that no + // drawing is done. + // http://code.google.com/p/angleproject/issues/detail?id=169 if (mCullStateDirty || mFrontFaceDirty) { if (mState.cullFace) { - device->SetRenderState(D3DRS_CULLMODE, es2dx::ConvertCullMode(mState.cullMode, mState.frontFace)); + mDevice->SetRenderState(D3DRS_CULLMODE, es2dx::ConvertCullMode(mState.cullMode, adjustedFrontFace)); } else { - device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + mDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); } mCullStateDirty = false; @@ -1741,61 +2027,66 @@ void Context::applyState(GLenum drawMode) if (mDepthStateDirty) { - if (mState.depthTest && framebufferObject->getDepthbufferType() != GL_NONE) + if (mState.depthTest) { - device->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE); - device->SetRenderState(D3DRS_ZFUNC, es2dx::ConvertComparison(mState.depthFunc)); + mDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE); + mDevice->SetRenderState(D3DRS_ZFUNC, es2dx::ConvertComparison(mState.depthFunc)); } else { - device->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE); + mDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE); } mDepthStateDirty = false; } + if (!zeroColorMaskAllowed && (mMaskStateDirty || mBlendStateDirty)) + { + mBlendStateDirty = true; + mMaskStateDirty = true; + } + if (mBlendStateDirty) { if (mState.blend) { - device->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); + mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); if (mState.sourceBlendRGB != GL_CONSTANT_ALPHA && mState.sourceBlendRGB != GL_ONE_MINUS_CONSTANT_ALPHA && mState.destBlendRGB != GL_CONSTANT_ALPHA && mState.destBlendRGB != GL_ONE_MINUS_CONSTANT_ALPHA) { - device->SetRenderState(D3DRS_BLENDFACTOR, es2dx::ConvertColor(mState.blendColor)); + mDevice->SetRenderState(D3DRS_BLENDFACTOR, es2dx::ConvertColor(mState.blendColor)); } else { - device->SetRenderState(D3DRS_BLENDFACTOR, D3DCOLOR_RGBA(unorm<8>(mState.blendColor.alpha), + mDevice->SetRenderState(D3DRS_BLENDFACTOR, D3DCOLOR_RGBA(unorm<8>(mState.blendColor.alpha), unorm<8>(mState.blendColor.alpha), unorm<8>(mState.blendColor.alpha), unorm<8>(mState.blendColor.alpha))); } - device->SetRenderState(D3DRS_SRCBLEND, es2dx::ConvertBlendFunc(mState.sourceBlendRGB)); - device->SetRenderState(D3DRS_DESTBLEND, es2dx::ConvertBlendFunc(mState.destBlendRGB)); - device->SetRenderState(D3DRS_BLENDOP, es2dx::ConvertBlendOp(mState.blendEquationRGB)); + mDevice->SetRenderState(D3DRS_SRCBLEND, es2dx::ConvertBlendFunc(mState.sourceBlendRGB)); + mDevice->SetRenderState(D3DRS_DESTBLEND, es2dx::ConvertBlendFunc(mState.destBlendRGB)); + mDevice->SetRenderState(D3DRS_BLENDOP, es2dx::ConvertBlendOp(mState.blendEquationRGB)); if (mState.sourceBlendRGB != mState.sourceBlendAlpha || mState.destBlendRGB != mState.destBlendAlpha || mState.blendEquationRGB != mState.blendEquationAlpha) { - device->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE); - - device->SetRenderState(D3DRS_SRCBLENDALPHA, es2dx::ConvertBlendFunc(mState.sourceBlendAlpha)); - device->SetRenderState(D3DRS_DESTBLENDALPHA, es2dx::ConvertBlendFunc(mState.destBlendAlpha)); - device->SetRenderState(D3DRS_BLENDOPALPHA, es2dx::ConvertBlendOp(mState.blendEquationAlpha)); + mDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE); + mDevice->SetRenderState(D3DRS_SRCBLENDALPHA, es2dx::ConvertBlendFunc(mState.sourceBlendAlpha)); + mDevice->SetRenderState(D3DRS_DESTBLENDALPHA, es2dx::ConvertBlendFunc(mState.destBlendAlpha)); + mDevice->SetRenderState(D3DRS_BLENDOPALPHA, es2dx::ConvertBlendOp(mState.blendEquationAlpha)); } else { - device->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, FALSE); + mDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, FALSE); } } else { - device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); } mBlendStateDirty = false; @@ -1805,8 +2096,8 @@ void Context::applyState(GLenum drawMode) { if (mState.stencilTest && framebufferObject->hasStencil()) { - device->SetRenderState(D3DRS_STENCILENABLE, TRUE); - device->SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, TRUE); + mDevice->SetRenderState(D3DRS_STENCILENABLE, TRUE); + mDevice->SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, TRUE); // FIXME: Unsupported by D3D9 const D3DRENDERSTATETYPE D3DRS_CCW_STENCILREF = D3DRS_STENCILREF; @@ -1821,50 +2112,65 @@ void Context::applyState(GLenum drawMode) } // get the maximum size of the stencil ref - gl::DepthStencilbuffer *stencilbuffer = framebufferObject->getStencilbuffer(); + gl::Renderbuffer *stencilbuffer = framebufferObject->getStencilbuffer(); GLuint maxStencil = (1 << stencilbuffer->getStencilSize()) - 1; - device->SetRenderState(mState.frontFace == GL_CCW ? D3DRS_STENCILWRITEMASK : D3DRS_CCW_STENCILWRITEMASK, mState.stencilWritemask); - device->SetRenderState(mState.frontFace == GL_CCW ? D3DRS_STENCILFUNC : D3DRS_CCW_STENCILFUNC, + mDevice->SetRenderState(adjustedFrontFace == GL_CCW ? D3DRS_STENCILWRITEMASK : D3DRS_CCW_STENCILWRITEMASK, mState.stencilWritemask); + mDevice->SetRenderState(adjustedFrontFace == GL_CCW ? D3DRS_STENCILFUNC : D3DRS_CCW_STENCILFUNC, es2dx::ConvertComparison(mState.stencilFunc)); - device->SetRenderState(mState.frontFace == GL_CCW ? D3DRS_STENCILREF : D3DRS_CCW_STENCILREF, (mState.stencilRef < (GLint)maxStencil) ? mState.stencilRef : maxStencil); - device->SetRenderState(mState.frontFace == GL_CCW ? D3DRS_STENCILMASK : D3DRS_CCW_STENCILMASK, mState.stencilMask); + mDevice->SetRenderState(adjustedFrontFace == GL_CCW ? D3DRS_STENCILREF : D3DRS_CCW_STENCILREF, (mState.stencilRef < (GLint)maxStencil) ? mState.stencilRef : maxStencil); + mDevice->SetRenderState(adjustedFrontFace == GL_CCW ? D3DRS_STENCILMASK : D3DRS_CCW_STENCILMASK, mState.stencilMask); - device->SetRenderState(mState.frontFace == GL_CCW ? D3DRS_STENCILFAIL : D3DRS_CCW_STENCILFAIL, + mDevice->SetRenderState(adjustedFrontFace == GL_CCW ? D3DRS_STENCILFAIL : D3DRS_CCW_STENCILFAIL, es2dx::ConvertStencilOp(mState.stencilFail)); - device->SetRenderState(mState.frontFace == GL_CCW ? D3DRS_STENCILZFAIL : D3DRS_CCW_STENCILZFAIL, + mDevice->SetRenderState(adjustedFrontFace == GL_CCW ? D3DRS_STENCILZFAIL : D3DRS_CCW_STENCILZFAIL, es2dx::ConvertStencilOp(mState.stencilPassDepthFail)); - device->SetRenderState(mState.frontFace == GL_CCW ? D3DRS_STENCILPASS : D3DRS_CCW_STENCILPASS, + mDevice->SetRenderState(adjustedFrontFace == GL_CCW ? D3DRS_STENCILPASS : D3DRS_CCW_STENCILPASS, es2dx::ConvertStencilOp(mState.stencilPassDepthPass)); - device->SetRenderState(mState.frontFace == GL_CW ? D3DRS_STENCILWRITEMASK : D3DRS_CCW_STENCILWRITEMASK, mState.stencilBackWritemask); - device->SetRenderState(mState.frontFace == GL_CW ? D3DRS_STENCILFUNC : D3DRS_CCW_STENCILFUNC, + mDevice->SetRenderState(adjustedFrontFace == GL_CW ? D3DRS_STENCILWRITEMASK : D3DRS_CCW_STENCILWRITEMASK, mState.stencilBackWritemask); + mDevice->SetRenderState(adjustedFrontFace == GL_CW ? D3DRS_STENCILFUNC : D3DRS_CCW_STENCILFUNC, es2dx::ConvertComparison(mState.stencilBackFunc)); - device->SetRenderState(mState.frontFace == GL_CW ? D3DRS_STENCILREF : D3DRS_CCW_STENCILREF, (mState.stencilBackRef < (GLint)maxStencil) ? mState.stencilBackRef : maxStencil); - device->SetRenderState(mState.frontFace == GL_CW ? D3DRS_STENCILMASK : D3DRS_CCW_STENCILMASK, mState.stencilBackMask); + mDevice->SetRenderState(adjustedFrontFace == GL_CW ? D3DRS_STENCILREF : D3DRS_CCW_STENCILREF, (mState.stencilBackRef < (GLint)maxStencil) ? mState.stencilBackRef : maxStencil); + mDevice->SetRenderState(adjustedFrontFace == GL_CW ? D3DRS_STENCILMASK : D3DRS_CCW_STENCILMASK, mState.stencilBackMask); - device->SetRenderState(mState.frontFace == GL_CW ? D3DRS_STENCILFAIL : D3DRS_CCW_STENCILFAIL, + mDevice->SetRenderState(adjustedFrontFace == GL_CW ? D3DRS_STENCILFAIL : D3DRS_CCW_STENCILFAIL, es2dx::ConvertStencilOp(mState.stencilBackFail)); - device->SetRenderState(mState.frontFace == GL_CW ? D3DRS_STENCILZFAIL : D3DRS_CCW_STENCILZFAIL, + mDevice->SetRenderState(adjustedFrontFace == GL_CW ? D3DRS_STENCILZFAIL : D3DRS_CCW_STENCILZFAIL, es2dx::ConvertStencilOp(mState.stencilBackPassDepthFail)); - device->SetRenderState(mState.frontFace == GL_CW ? D3DRS_STENCILPASS : D3DRS_CCW_STENCILPASS, + mDevice->SetRenderState(adjustedFrontFace == GL_CW ? D3DRS_STENCILPASS : D3DRS_CCW_STENCILPASS, es2dx::ConvertStencilOp(mState.stencilBackPassDepthPass)); } else { - device->SetRenderState(D3DRS_STENCILENABLE, FALSE); + mDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE); } mStencilStateDirty = false; + mFrontFaceDirty = false; } if (mMaskStateDirty) { - device->SetRenderState(D3DRS_COLORWRITEENABLE, es2dx::ConvertColorMask(mState.colorMaskRed, mState.colorMaskGreen, - mState.colorMaskBlue, mState.colorMaskAlpha)); - device->SetRenderState(D3DRS_ZWRITEENABLE, mState.depthMask ? TRUE : FALSE); + int colorMask = es2dx::ConvertColorMask(mState.colorMaskRed, mState.colorMaskGreen, + mState.colorMaskBlue, mState.colorMaskAlpha); + if (colorMask == 0 && !zeroColorMaskAllowed) + { + // Enable green channel, but set blending so nothing will be drawn. + mDevice->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_GREEN); + mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); + + mDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ZERO); + mDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE); + mDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD); + } + else + { + mDevice->SetRenderState(D3DRS_COLORWRITEENABLE, colorMask); + } + mDevice->SetRenderState(D3DRS_ZWRITEENABLE, mState.depthMask ? TRUE : FALSE); mMaskStateDirty = false; } @@ -1873,18 +2179,18 @@ void Context::applyState(GLenum drawMode) { if (mState.polygonOffsetFill) { - gl::DepthStencilbuffer *depthbuffer = framebufferObject->getDepthbuffer(); + gl::Renderbuffer *depthbuffer = framebufferObject->getDepthbuffer(); if (depthbuffer) { - device->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, *((DWORD*)&mState.polygonOffsetFactor)); + mDevice->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, *((DWORD*)&mState.polygonOffsetFactor)); float depthBias = ldexp(mState.polygonOffsetUnits, -(int)(depthbuffer->getDepthSize())); - device->SetRenderState(D3DRS_DEPTHBIAS, *((DWORD*)&depthBias)); + mDevice->SetRenderState(D3DRS_DEPTHBIAS, *((DWORD*)&depthBias)); } } else { - device->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, 0); - device->SetRenderState(D3DRS_DEPTHBIAS, 0); + mDevice->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, 0); + mDevice->SetRenderState(D3DRS_DEPTHBIAS, 0); } mPolygonOffsetStateDirty = false; @@ -1892,48 +2198,41 @@ void Context::applyState(GLenum drawMode) if (mSampleStateDirty) { - if (framebufferObject->isMultisample()) + if (mState.sampleAlphaToCoverage) { - if (mState.sampleAlphaToCoverage) - { - FIXME("Sample alpha to coverage is unimplemented."); - } + FIXME("Sample alpha to coverage is unimplemented."); + } - device->SetRenderState(D3DRS_MULTISAMPLEANTIALIAS, TRUE); - if (mState.sampleCoverage) + mDevice->SetRenderState(D3DRS_MULTISAMPLEANTIALIAS, TRUE); + if (mState.sampleCoverage) + { + unsigned int mask = 0; + if (mState.sampleCoverageValue != 0) { - unsigned int mask = 0; - if (mState.sampleCoverageValue != 0) + float threshold = 0.5f; + + for (int i = 0; i < framebufferObject->getSamples(); ++i) { - float threshold = 0.5f; + mask <<= 1; - for (int i = 0; i < framebufferObject->getSamples(); ++i) + if ((i + 1) * mState.sampleCoverageValue >= threshold) { - mask <<= 1; - - if ((i + 1) * mState.sampleCoverageValue >= threshold) - { - threshold += 1.0f; - mask |= 1; - } + threshold += 1.0f; + mask |= 1; } } - - if (mState.sampleCoverageInvert) - { - mask = ~mask; - } - - device->SetRenderState(D3DRS_MULTISAMPLEMASK, mask); } - else + + if (mState.sampleCoverageInvert) { - device->SetRenderState(D3DRS_MULTISAMPLEMASK, 0xFFFFFFFF); + mask = ~mask; } + + mDevice->SetRenderState(D3DRS_MULTISAMPLEMASK, mask); } else { - device->SetRenderState(D3DRS_MULTISAMPLEANTIALIAS, FALSE); + mDevice->SetRenderState(D3DRS_MULTISAMPLEMASK, 0xFFFFFFFF); } mSampleStateDirty = false; @@ -1941,52 +2240,37 @@ void Context::applyState(GLenum drawMode) if (mDitherStateDirty) { - device->SetRenderState(D3DRS_DITHERENABLE, mState.dither ? TRUE : FALSE); + mDevice->SetRenderState(D3DRS_DITHERENABLE, mState.dither ? TRUE : FALSE); mDitherStateDirty = false; } - - mFrontFaceDirty = false; } -// Fill in the semanticIndex field of the array of TranslatedAttributes based on the active GLSL program. -void Context::lookupAttributeMapping(TranslatedAttribute *attributes) +GLenum Context::applyVertexBuffer(GLint first, GLsizei count, GLsizei instances, GLsizei *repeatDraw) { - for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++) - { - if (attributes[i].active) - { - attributes[i].semanticIndex = getCurrentProgram()->getSemanticIndex(i); - } - } -} + TranslatedAttribute attributes[MAX_VERTEX_ATTRIBS]; -GLenum Context::applyVertexBuffer(GLint first, GLsizei count) -{ - TranslatedAttribute translated[MAX_VERTEX_ATTRIBS]; - - GLenum err = mVertexDataManager->prepareVertexData(first, count, translated); + GLenum err = mVertexDataManager->prepareVertexData(first, count, attributes, instances); if (err != GL_NO_ERROR) { return err; } - lookupAttributeMapping(translated); - - mVertexDataManager->setupAttributes(translated); - - return GL_NO_ERROR; + return mVertexDeclarationCache.applyDeclaration(mDevice, attributes, getCurrentProgram(), instances, repeatDraw); } // Applies the indices and element array bindings to the Direct3D 9 device -GLenum Context::applyIndexBuffer(const void *indices, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo) +GLenum Context::applyIndexBuffer(const GLvoid *indices, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo) { - IDirect3DDevice9 *device = getDevice(); GLenum err = mIndexDataManager->prepareIndexData(type, count, mState.elementArrayBuffer.get(), indices, indexInfo); if (err == GL_NO_ERROR) { - device->SetIndices(indexInfo->indexBuffer); + if (indexInfo->serial != mAppliedIBSerial) + { + mDevice->SetIndices(indexInfo->indexBuffer); + mAppliedIBSerial = indexInfo->serial; + } } return err; @@ -1995,19 +2279,16 @@ GLenum Context::applyIndexBuffer(const void *indices, GLsizei count, GLenum mode // Applies the shaders and shader constants to the Direct3D 9 device void Context::applyShaders() { - IDirect3DDevice9 *device = getDevice(); Program *programObject = getCurrentProgram(); - IDirect3DVertexShader9 *vertexShader = programObject->getVertexShader(); - IDirect3DPixelShader9 *pixelShader = programObject->getPixelShader(); - - device->SetVertexShader(vertexShader); - device->SetPixelShader(pixelShader); - - if (programObject->getSerial() != mAppliedProgram) + if (programObject->getSerial() != mAppliedProgramSerial) { + IDirect3DVertexShader9 *vertexShader = programObject->getVertexShader(); + IDirect3DPixelShader9 *pixelShader = programObject->getPixelShader(); + + mDevice->SetPixelShader(pixelShader); + mDevice->SetVertexShader(vertexShader); programObject->dirtyAllUniforms(); - programObject->dirtyAllSamplers(); - mAppliedProgram = programObject->getSerial(); + mAppliedProgramSerial = programObject->getSerial(); } programObject->applyUniforms(); @@ -2016,58 +2297,96 @@ void Context::applyShaders() // Applies the textures and sampler states to the Direct3D 9 device void Context::applyTextures() { - IDirect3DDevice9 *device = getDevice(); + applyTextures(SAMPLER_PIXEL); + + if (mSupportsVertexTexture) + { + applyTextures(SAMPLER_VERTEX); + } +} + +// For each Direct3D 9 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) +{ Program *programObject = getCurrentProgram(); - for (int sampler = 0; sampler < MAX_TEXTURE_IMAGE_UNITS; sampler++) + int samplerCount = (type == SAMPLER_PIXEL) ? MAX_TEXTURE_IMAGE_UNITS : MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF; // Range of Direct3D 9 samplers of given sampler type + unsigned int *appliedTextureSerial = (type == SAMPLER_PIXEL) ? mAppliedTextureSerialPS : mAppliedTextureSerialVS; + int d3dSamplerOffset = (type == SAMPLER_PIXEL) ? 0 : D3DVERTEXTEXTURESAMPLER0; + int samplerRange = programObject->getUsedSamplerRange(type); + + for (int samplerIndex = 0; samplerIndex < samplerRange; samplerIndex++) { - int textureUnit = programObject->getSamplerMapping(sampler); + int textureUnit = programObject->getSamplerMapping(type, samplerIndex); // OpenGL texture image unit index + int d3dSampler = samplerIndex + d3dSamplerOffset; + if (textureUnit != -1) { - SamplerType textureType = programObject->getSamplerType(sampler); + TextureType textureType = programObject->getSamplerTextureType(type, samplerIndex); Texture *texture = getSamplerTexture(textureUnit, textureType); - if (programObject->isSamplerDirty(sampler) || texture->isDirty()) + if (appliedTextureSerial[samplerIndex] != texture->getTextureSerial() || texture->hasDirtyParameters() || texture->hasDirtyImages()) { - if (texture->isComplete()) - { - GLenum wrapS = texture->getWrapS(); - GLenum wrapT = texture->getWrapT(); - GLenum minFilter = texture->getMinFilter(); - GLenum magFilter = texture->getMagFilter(); - - device->SetSamplerState(sampler, D3DSAMP_ADDRESSU, es2dx::ConvertTextureWrap(wrapS)); - device->SetSamplerState(sampler, D3DSAMP_ADDRESSV, es2dx::ConvertTextureWrap(wrapT)); + IDirect3DBaseTexture9 *d3dTexture = texture->getTexture(); - device->SetSamplerState(sampler, D3DSAMP_MAGFILTER, es2dx::ConvertMagFilter(magFilter)); - D3DTEXTUREFILTERTYPE d3dMinFilter, d3dMipFilter; - es2dx::ConvertMinFilter(minFilter, &d3dMinFilter, &d3dMipFilter); - device->SetSamplerState(sampler, D3DSAMP_MINFILTER, d3dMinFilter); - device->SetSamplerState(sampler, D3DSAMP_MIPFILTER, d3dMipFilter); + if (d3dTexture) + { + if (appliedTextureSerial[samplerIndex] != texture->getTextureSerial() || texture->hasDirtyParameters()) + { + GLenum wrapS = texture->getWrapS(); + GLenum wrapT = texture->getWrapT(); + GLenum minFilter = texture->getMinFilter(); + GLenum magFilter = texture->getMagFilter(); + + mDevice->SetSamplerState(d3dSampler, D3DSAMP_ADDRESSU, es2dx::ConvertTextureWrap(wrapS)); + mDevice->SetSamplerState(d3dSampler, D3DSAMP_ADDRESSV, es2dx::ConvertTextureWrap(wrapT)); + + mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAGFILTER, es2dx::ConvertMagFilter(magFilter)); + D3DTEXTUREFILTERTYPE d3dMinFilter, d3dMipFilter; + es2dx::ConvertMinFilter(minFilter, &d3dMinFilter, &d3dMipFilter); + mDevice->SetSamplerState(d3dSampler, D3DSAMP_MINFILTER, d3dMinFilter); + mDevice->SetSamplerState(d3dSampler, D3DSAMP_MIPFILTER, d3dMipFilter); + } - device->SetTexture(sampler, texture->getTexture()); + if (appliedTextureSerial[samplerIndex] != texture->getTextureSerial() || texture->hasDirtyImages()) + { + mDevice->SetTexture(d3dSampler, d3dTexture); + } } else { - device->SetTexture(sampler, getIncompleteTexture(textureType)->getTexture()); + mDevice->SetTexture(d3dSampler, getIncompleteTexture(textureType)->getTexture()); } - } - programObject->setSamplerDirty(sampler, false); + appliedTextureSerial[samplerIndex] = texture->getTextureSerial(); + texture->resetDirty(); + } } else { - if (programObject->isSamplerDirty(sampler)) + if (appliedTextureSerial[samplerIndex] != 0) { - device->SetTexture(sampler, NULL); - programObject->setSamplerDirty(sampler, false); + mDevice->SetTexture(d3dSampler, NULL); + appliedTextureSerial[samplerIndex] = 0; } - } + } + } + + for (int samplerIndex = samplerRange; samplerIndex < samplerCount; samplerIndex++) + { + if (appliedTextureSerial[samplerIndex] != 0) + { + mDevice->SetTexture(samplerIndex + d3dSamplerOffset, NULL); + appliedTextureSerial[samplerIndex] = 0; + } } } -void Context::readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels) +void Context::readPixels(GLint x, GLint y, GLsizei width, GLsizei height, + GLenum format, GLenum type, GLsizei *bufSize, void* pixels) { Framebuffer *framebuffer = getReadFramebuffer(); @@ -2081,55 +2400,93 @@ void Context::readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum return error(GL_INVALID_OPERATION); } - IDirect3DSurface9 *renderTarget = framebuffer->getRenderTarget(); + GLsizei outputPitch = ComputePitch(width, format, type, mState.packAlignment); + // sized query sanity check + if (bufSize) + { + int requiredSize = outputPitch * height; + if (requiredSize > *bufSize) + { + return error(GL_INVALID_OPERATION); + } + } + IDirect3DSurface9 *renderTarget = framebuffer->getRenderTarget(); if (!renderTarget) { return; // Context must be lost, return silently } - IDirect3DDevice9 *device = getDevice(); - D3DSURFACE_DESC desc; renderTarget->GetDesc(&desc); - IDirect3DSurface9 *systemSurface; - HRESULT result = device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &systemSurface, NULL); - - if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY) + if (desc.MultiSampleType != D3DMULTISAMPLE_NONE) { + UNIMPLEMENTED(); // FIXME: Requires resolve using StretchRect into non-multisampled render target + renderTarget->Release(); return error(GL_OUT_OF_MEMORY); } - ASSERT(SUCCEEDED(result)); + HRESULT result; + IDirect3DSurface9 *systemSurface = NULL; + bool directToPixels = getPackReverseRowOrder() && getPackAlignment() <= 4 && mDisplay->isD3d9ExDevice() && + x == 0 && y == 0 && UINT(width) == desc.Width && UINT(height) == desc.Height && + desc.Format == D3DFMT_A8R8G8B8 && format == GL_BGRA_EXT && type == GL_UNSIGNED_BYTE; + if (directToPixels) + { + // Use the pixels ptr as a shared handle to write directly into client's memory + result = mDevice->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, + D3DPOOL_SYSTEMMEM, &systemSurface, &pixels); + if (FAILED(result)) + { + // Try again without the shared handle + directToPixels = false; + } + } - if (desc.MultiSampleType != D3DMULTISAMPLE_NONE) + if (!directToPixels) { - UNIMPLEMENTED(); // FIXME: Requires resolve using StretchRect into non-multisampled render target + result = mDevice->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, + D3DPOOL_SYSTEMMEM, &systemSurface, NULL); + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + return error(GL_OUT_OF_MEMORY); + } } - result = device->GetRenderTargetData(renderTarget, systemSurface); + result = mDevice->GetRenderTargetData(renderTarget, systemSurface); + renderTarget->Release(); + renderTarget = NULL; if (FAILED(result)) { systemSurface->Release(); - switch (result) + // It turns out that D3D will sometimes produce more error + // codes than those documented. + if (checkDeviceLost(result)) + return error(GL_OUT_OF_MEMORY); + else { - case D3DERR_DRIVERINTERNALERROR: - case D3DERR_DEVICELOST: - return error(GL_OUT_OF_MEMORY); - default: - UNREACHABLE(); - return; // No sensible error to generate + UNREACHABLE(); + return; } + + } + + if (directToPixels) + { + systemSurface->Release(); + return; } D3DLOCKED_RECT lock; - RECT rect = {std::max(x, 0), - std::max(y, 0), - std::min(x + width, (int)desc.Width), - std::min(y + height, (int)desc.Height)}; + RECT rect = transformPixelRect(x, y, width, height, desc.Height); + rect.left = clamp(rect.left, 0L, static_cast<LONG>(desc.Width)); + rect.top = clamp(rect.top, 0L, static_cast<LONG>(desc.Height)); + rect.right = clamp(rect.right, 0L, static_cast<LONG>(desc.Width)); + rect.bottom = clamp(rect.bottom, 0L, static_cast<LONG>(desc.Height)); result = systemSurface->LockRect(&lock, &rect, D3DLOCK_READONLY); @@ -2141,11 +2498,21 @@ void Context::readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum return; // No sensible error to generate } - unsigned char *source = (unsigned char*)lock.pBits; unsigned char *dest = (unsigned char*)pixels; unsigned short *dest16 = (unsigned short*)pixels; - GLsizei outputPitch = ComputePitch(width, format, type, mState.packAlignment); + unsigned char *source; + int inputPitch; + if (getPackReverseRowOrder()) + { + source = (unsigned char*)lock.pBits; + inputPitch = lock.Pitch; + } + else + { + source = ((unsigned char*)lock.pBits) + lock.Pitch * (rect.bottom - rect.top - 1); + inputPitch = -lock.Pitch; + } for (int j = 0; j < rect.bottom - rect.top; j++) { @@ -2157,7 +2524,7 @@ void Context::readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum // an RGBA source buffer. Note that buffers with no // alpha go through the slow path below. memcpy(dest + j * outputPitch, - source + j * lock.Pitch, + source + j * inputPitch, (rect.right - rect.left) * 4); continue; } @@ -2173,7 +2540,7 @@ void Context::readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum { case D3DFMT_R5G6B5: { - unsigned short rgb = *(unsigned short*)(source + 2 * i + j * lock.Pitch); + unsigned short rgb = *(unsigned short*)(source + 2 * i + j * inputPitch); a = 1.0f; b = (rgb & 0x001F) * (1.0f / 0x001F); @@ -2183,7 +2550,7 @@ void Context::readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum break; case D3DFMT_A1R5G5B5: { - unsigned short argb = *(unsigned short*)(source + 2 * i + j * lock.Pitch); + unsigned short argb = *(unsigned short*)(source + 2 * i + j * inputPitch); a = (argb & 0x8000) ? 1.0f : 0.0f; b = (argb & 0x001F) * (1.0f / 0x001F); @@ -2193,7 +2560,7 @@ void Context::readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum break; case D3DFMT_A8R8G8B8: { - unsigned int argb = *(unsigned int*)(source + 4 * i + j * lock.Pitch); + unsigned int argb = *(unsigned int*)(source + 4 * i + j * inputPitch); a = (argb & 0xFF000000) * (1.0f / 0xFF000000); b = (argb & 0x000000FF) * (1.0f / 0x000000FF); @@ -2203,7 +2570,7 @@ void Context::readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum break; case D3DFMT_X8R8G8B8: { - unsigned int xrgb = *(unsigned int*)(source + 4 * i + j * lock.Pitch); + unsigned int xrgb = *(unsigned int*)(source + 4 * i + j * inputPitch); a = 1.0f; b = (xrgb & 0x000000FF) * (1.0f / 0x000000FF); @@ -2213,7 +2580,7 @@ void Context::readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum break; case D3DFMT_A2R10G10B10: { - unsigned int argb = *(unsigned int*)(source + 4 * i + j * lock.Pitch); + unsigned int argb = *(unsigned int*)(source + 4 * i + j * inputPitch); a = (argb & 0xC0000000) * (1.0f / 0xC0000000); b = (argb & 0x000003FF) * (1.0f / 0x000003FF); @@ -2224,10 +2591,10 @@ void Context::readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum case D3DFMT_A32B32G32R32F: { // float formats in D3D are stored rgba, rather than the other way round - r = *((float*)(source + 16 * i + j * lock.Pitch) + 0); - g = *((float*)(source + 16 * i + j * lock.Pitch) + 1); - b = *((float*)(source + 16 * i + j * lock.Pitch) + 2); - a = *((float*)(source + 16 * i + j * lock.Pitch) + 3); + r = *((float*)(source + 16 * i + j * inputPitch) + 0); + g = *((float*)(source + 16 * i + j * inputPitch) + 1); + b = *((float*)(source + 16 * i + j * inputPitch) + 2); + a = *((float*)(source + 16 * i + j * inputPitch) + 3); } break; case D3DFMT_A16B16G16R16F: @@ -2235,7 +2602,7 @@ void Context::readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum // float formats in D3D are stored rgba, rather than the other way round float abgr[4]; - D3DXFloat16To32Array(abgr, (D3DXFLOAT16*)(source + 8 * i + j * lock.Pitch), 4); + D3DXFloat16To32Array(abgr, (D3DXFLOAT16*)(source + 8 * i + j * inputPitch), 4); a = abgr[3]; b = abgr[2]; @@ -2246,6 +2613,7 @@ void Context::readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum default: UNIMPLEMENTED(); // FIXME UNREACHABLE(); + return; } switch (format) @@ -2330,13 +2698,9 @@ void Context::clear(GLbitfield mask) if (!framebufferObject || framebufferObject->completeness() != GL_FRAMEBUFFER_COMPLETE) { - error(GL_INVALID_FRAMEBUFFER_OPERATION); - - return; + return error(GL_INVALID_FRAMEBUFFER_OPERATION); } - egl::Display *display = getDisplay(); - IDirect3DDevice9 *device = getDevice(); DWORD flags = 0; if (mask & GL_COLOR_BUFFER_BIT) @@ -2375,7 +2739,7 @@ void Context::clear(GLbitfield mask) D3DSURFACE_DESC desc; depthStencil->GetDesc(&desc); - unsigned int stencilSize = es2dx::GetStencilSize(desc.Format); + unsigned int stencilSize = dx2es::GetStencilSize(desc.Format); stencilUnmasked = (0x1 << stencilSize) - 1; if (stencilUnmasked != 0x0) @@ -2396,23 +2760,13 @@ void Context::clear(GLbitfield mask) } D3DCOLOR color = D3DCOLOR_ARGB(unorm<8>(mState.colorClearValue.alpha), - unorm<8>(mState.colorClearValue.red), - unorm<8>(mState.colorClearValue.green), - unorm<8>(mState.colorClearValue.blue)); + unorm<8>(mState.colorClearValue.red), + unorm<8>(mState.colorClearValue.green), + unorm<8>(mState.colorClearValue.blue)); float depth = clamp01(mState.depthClearValue); int stencil = mState.stencilClearValue & 0x000000FF; - IDirect3DSurface9 *renderTarget = framebufferObject->getRenderTarget(); - - if (!renderTarget) - { - return; // Context must be lost, return silently - } - - D3DSURFACE_DESC desc; - renderTarget->GetDesc(&desc); - - bool alphaUnmasked = (es2dx::GetAlphaSize(desc.Format) == 0) || mState.colorMaskAlpha; + bool alphaUnmasked = (dx2es::GetAlphaSize(mRenderTargetDesc.Format) == 0) || mState.colorMaskAlpha; const bool needMaskedStencilClear = (flags & D3DCLEAR_STENCIL) && (mState.stencilWritemask & stencilUnmasked) != stencilUnmasked; @@ -2428,25 +2782,37 @@ void Context::clear(GLbitfield mask) HRESULT hr; if (mMaskedClearSavedState == NULL) { - hr = device->BeginStateBlock(); + hr = mDevice->BeginStateBlock(); ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY); - device->SetRenderState(D3DRS_ZWRITEENABLE, FALSE); - device->SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS); - device->SetRenderState(D3DRS_ZENABLE, FALSE); - device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); - device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID); - device->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); - device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); - device->SetRenderState(D3DRS_CLIPPLANEENABLE, 0); - device->SetRenderState(D3DRS_COLORWRITEENABLE, 0); - device->SetRenderState(D3DRS_STENCILENABLE, FALSE); - device->SetPixelShader(NULL); - device->SetVertexShader(NULL); - device->SetFVF(D3DFVF_XYZRHW | D3DFVF_DIFFUSE); - device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_DISABLE); - - hr = device->EndStateBlock(&mMaskedClearSavedState); + mDevice->SetRenderState(D3DRS_ZWRITEENABLE, FALSE); + mDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS); + mDevice->SetRenderState(D3DRS_ZENABLE, FALSE); + mDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + mDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID); + mDevice->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); + mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + mDevice->SetRenderState(D3DRS_CLIPPLANEENABLE, 0); + mDevice->SetRenderState(D3DRS_COLORWRITEENABLE, 0); + mDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE); + mDevice->SetPixelShader(NULL); + mDevice->SetVertexShader(NULL); + mDevice->SetFVF(D3DFVF_XYZRHW | D3DFVF_DIFFUSE); + mDevice->SetStreamSource(0, NULL, 0, 0); + mDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE); + mDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); + mDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TFACTOR); + mDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); + mDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TFACTOR); + mDevice->SetRenderState(D3DRS_TEXTUREFACTOR, color); + mDevice->SetRenderState(D3DRS_MULTISAMPLEMASK, 0xFFFFFFFF); + + for(int i = 0; i < MAX_VERTEX_ATTRIBS; i++) + { + mDevice->SetStreamSourceFreq(i, 1); + } + + hr = mDevice->EndStateBlock(&mMaskedClearSavedState); ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY); } @@ -2458,88 +2824,86 @@ void Context::clear(GLbitfield mask) ASSERT(SUCCEEDED(hr)); } - device->SetRenderState(D3DRS_ZWRITEENABLE, FALSE); - device->SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS); - device->SetRenderState(D3DRS_ZENABLE, FALSE); - device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); - device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID); - device->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); - device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); - device->SetRenderState(D3DRS_CLIPPLANEENABLE, 0); + mDevice->SetRenderState(D3DRS_ZWRITEENABLE, FALSE); + mDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS); + mDevice->SetRenderState(D3DRS_ZENABLE, FALSE); + mDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + mDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID); + mDevice->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); + mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + mDevice->SetRenderState(D3DRS_CLIPPLANEENABLE, 0); if (flags & D3DCLEAR_TARGET) { - device->SetRenderState(D3DRS_COLORWRITEENABLE, (mState.colorMaskRed ? D3DCOLORWRITEENABLE_RED : 0) | - (mState.colorMaskGreen ? D3DCOLORWRITEENABLE_GREEN : 0) | - (mState.colorMaskBlue ? D3DCOLORWRITEENABLE_BLUE : 0) | - (mState.colorMaskAlpha ? D3DCOLORWRITEENABLE_ALPHA : 0)); + mDevice->SetRenderState(D3DRS_COLORWRITEENABLE, es2dx::ConvertColorMask(mState.colorMaskRed, mState.colorMaskGreen, mState.colorMaskBlue, mState.colorMaskAlpha)); } else { - device->SetRenderState(D3DRS_COLORWRITEENABLE, 0); + mDevice->SetRenderState(D3DRS_COLORWRITEENABLE, 0); } if (stencilUnmasked != 0x0 && (flags & D3DCLEAR_STENCIL)) { - device->SetRenderState(D3DRS_STENCILENABLE, TRUE); - device->SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, FALSE); - device->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_ALWAYS); - device->SetRenderState(D3DRS_STENCILREF, stencil); - device->SetRenderState(D3DRS_STENCILWRITEMASK, mState.stencilWritemask); - device->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_REPLACE); - device->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_REPLACE); - device->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE); + mDevice->SetRenderState(D3DRS_STENCILENABLE, TRUE); + mDevice->SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, FALSE); + mDevice->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_ALWAYS); + mDevice->SetRenderState(D3DRS_STENCILREF, stencil); + mDevice->SetRenderState(D3DRS_STENCILWRITEMASK, mState.stencilWritemask); + mDevice->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_REPLACE); + mDevice->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_REPLACE); + mDevice->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE); mStencilStateDirty = true; } else { - device->SetRenderState(D3DRS_STENCILENABLE, FALSE); + mDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE); } - device->SetPixelShader(NULL); - device->SetVertexShader(NULL); - device->SetFVF(D3DFVF_XYZRHW | D3DFVF_DIFFUSE); - device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_DISABLE); - - struct Vertex + mDevice->SetPixelShader(NULL); + mDevice->SetVertexShader(NULL); + mDevice->SetFVF(D3DFVF_XYZRHW); + mDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE); + mDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); + mDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TFACTOR); + mDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); + mDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TFACTOR); + mDevice->SetRenderState(D3DRS_TEXTUREFACTOR, color); + mDevice->SetRenderState(D3DRS_MULTISAMPLEMASK, 0xFFFFFFFF); + + for(int i = 0; i < MAX_VERTEX_ATTRIBS; i++) { - float x, y, z, w; - D3DCOLOR diffuse; - }; + mDevice->SetStreamSourceFreq(i, 1); + } + + float quad[4][4]; // A quadrilateral covering the target, aligned to match the edges + quad[0][0] = -0.5f; + quad[0][1] = mRenderTargetDesc.Height - 0.5f; + quad[0][2] = 0.0f; + quad[0][3] = 1.0f; + + quad[1][0] = mRenderTargetDesc.Width - 0.5f; + quad[1][1] = mRenderTargetDesc.Height - 0.5f; + quad[1][2] = 0.0f; + quad[1][3] = 1.0f; + + quad[2][0] = -0.5f; + quad[2][1] = -0.5f; + quad[2][2] = 0.0f; + quad[2][3] = 1.0f; - Vertex quad[4]; - quad[0].x = 0.0f; - quad[0].y = (float)desc.Height; - quad[0].z = 0.0f; - quad[0].w = 1.0f; - quad[0].diffuse = color; - - quad[1].x = (float)desc.Width; - quad[1].y = (float)desc.Height; - quad[1].z = 0.0f; - quad[1].w = 1.0f; - quad[1].diffuse = color; - - quad[2].x = 0.0f; - quad[2].y = 0.0f; - quad[2].z = 0.0f; - quad[2].w = 1.0f; - quad[2].diffuse = color; - - quad[3].x = (float)desc.Width; - quad[3].y = 0.0f; - quad[3].z = 0.0f; - quad[3].w = 1.0f; - quad[3].diffuse = color; - - display->startScene(); - device->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, quad, sizeof(Vertex)); + quad[3][0] = mRenderTargetDesc.Width - 0.5f; + quad[3][1] = -0.5f; + quad[3][2] = 0.0f; + quad[3][3] = 1.0f; + + mDisplay->startScene(); + mDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, quad, sizeof(float[4])); if (flags & D3DCLEAR_ZBUFFER) { - device->SetRenderState(D3DRS_ZENABLE, TRUE); - device->SetRenderState(D3DRS_ZWRITEENABLE, TRUE); - device->Clear(0, NULL, D3DCLEAR_ZBUFFER, color, depth, stencil); + mDevice->SetRenderState(D3DRS_ZENABLE, TRUE); + mDevice->SetRenderState(D3DRS_ZWRITEENABLE, TRUE); + mDevice->Clear(0, NULL, D3DCLEAR_ZBUFFER, color, depth, stencil); } if (mMaskedClearSavedState != NULL) @@ -2549,19 +2913,17 @@ void Context::clear(GLbitfield mask) } else if (flags) { - device->Clear(0, NULL, flags, color, depth, stencil); + mDevice->Clear(0, NULL, flags, color, depth, stencil); } } -void Context::drawArrays(GLenum mode, GLint first, GLsizei count) +void Context::drawArrays(GLenum mode, GLint first, GLsizei count, GLsizei instances) { if (!mState.currentProgram) { return error(GL_INVALID_OPERATION); } - egl::Display *display = getDisplay(); - IDirect3DDevice9 *device = getDevice(); D3DPRIMITIVETYPE primitiveType; int primitiveCount; @@ -2580,7 +2942,8 @@ void Context::drawArrays(GLenum mode, GLint first, GLsizei count) applyState(mode); - GLenum err = applyVertexBuffer(first, count); + GLsizei repeatDraw = 1; + GLenum err = applyVertexBuffer(first, count, instances, &repeatDraw); if (err != GL_NO_ERROR) { return error(err); @@ -2589,25 +2952,49 @@ void Context::drawArrays(GLenum mode, GLint first, GLsizei count) applyShaders(); applyTextures(); - if (!getCurrentProgram()->validateSamplers()) + if (!getCurrentProgram()->validateSamplers(false)) { return error(GL_INVALID_OPERATION); } if (!cullSkipsDraw(mode)) { - display->startScene(); + mDisplay->startScene(); - device->DrawPrimitive(primitiveType, 0, primitiveCount); + if (mode == GL_LINE_LOOP) + { + drawLineLoop(count, GL_NONE, NULL, 0); + } + else if (instances > 0) + { + StaticIndexBuffer *countingIB = mIndexDataManager->getCountingIndices(count); + if (countingIB) + { + if (mAppliedIBSerial != countingIB->getSerial()) + { + mDevice->SetIndices(countingIB->getBuffer()); + mAppliedIBSerial = countingIB->getSerial(); + } - if (mode == GL_LINE_LOOP) // Draw the last segment separately + for (int i = 0; i < repeatDraw; i++) + { + mDevice->DrawIndexedPrimitive(primitiveType, 0, 0, count, 0, primitiveCount); + } + } + else + { + ERR("Could not create a counting index buffer for glDrawArraysInstanced."); + return error(GL_OUT_OF_MEMORY); + } + } + else // Regular case { - drawClosingLine(first, first + count - 1); + mDevice->DrawPrimitive(primitiveType, 0, primitiveCount); } } } -void Context::drawElements(GLenum mode, GLsizei count, GLenum type, const void *indices) +void Context::drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei instances) { if (!mState.currentProgram) { @@ -2619,8 +3006,6 @@ void Context::drawElements(GLenum mode, GLsizei count, GLenum type, const void * return error(GL_INVALID_OPERATION); } - egl::Display *display = getDisplay(); - IDirect3DDevice9 *device = getDevice(); D3DPRIMITIVETYPE primitiveType; int primitiveCount; @@ -2647,7 +3032,8 @@ void Context::drawElements(GLenum mode, GLsizei count, GLenum type, const void * } GLsizei vertexCount = indexInfo.maxIndex - indexInfo.minIndex + 1; - err = applyVertexBuffer(indexInfo.minIndex, vertexCount); + GLsizei repeatDraw = 1; + err = applyVertexBuffer(indexInfo.minIndex, vertexCount, instances, &repeatDraw); if (err != GL_NO_ERROR) { return error(err); @@ -2656,188 +3042,178 @@ void Context::drawElements(GLenum mode, GLsizei count, GLenum type, const void * applyShaders(); applyTextures(); - if (!getCurrentProgram()->validateSamplers()) + if (!getCurrentProgram()->validateSamplers(false)) { return error(GL_INVALID_OPERATION); } if (!cullSkipsDraw(mode)) { - display->startScene(); - - device->DrawIndexedPrimitive(primitiveType, -(INT)indexInfo.minIndex, indexInfo.minIndex, vertexCount, indexInfo.startIndex, primitiveCount); - - if (mode == GL_LINE_LOOP) // Draw the last segment separately - { - drawClosingLine(count, type, indices); - } - } -} - -void Context::finish() -{ - egl::Display *display = getDisplay(); - IDirect3DDevice9 *device = getDevice(); - IDirect3DQuery9 *occlusionQuery = NULL; - - HRESULT result = device->CreateQuery(D3DQUERYTYPE_OCCLUSION, &occlusionQuery); - - if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY) - { - return error(GL_OUT_OF_MEMORY); - } - - ASSERT(SUCCEEDED(result)); - - if (occlusionQuery) - { - IDirect3DStateBlock9 *savedState = NULL; - device->CreateStateBlock(D3DSBT_ALL, &savedState); - - HRESULT result = occlusionQuery->Issue(D3DISSUE_BEGIN); - ASSERT(SUCCEEDED(result)); - - // Render something outside the render target - device->SetPixelShader(NULL); - device->SetVertexShader(NULL); - device->SetFVF(D3DFVF_XYZRHW); - float data[4] = {-1.0f, -1.0f, -1.0f, 1.0f}; - display->startScene(); - device->DrawPrimitiveUP(D3DPT_POINTLIST, 1, data, sizeof(data)); - - result = occlusionQuery->Issue(D3DISSUE_END); - ASSERT(SUCCEEDED(result)); + mDisplay->startScene(); - while (occlusionQuery->GetData(NULL, 0, D3DGETDATA_FLUSH) == S_FALSE) + if (mode == GL_LINE_LOOP) { - // Keep polling, but allow other threads to do something useful first - Sleep(0); + drawLineLoop(count, type, indices, indexInfo.minIndex); } - - occlusionQuery->Release(); - - if (savedState) + else { - savedState->Apply(); - savedState->Release(); + for (int i = 0; i < repeatDraw; i++) + { + mDevice->DrawIndexedPrimitive(primitiveType, -(INT)indexInfo.minIndex, indexInfo.minIndex, vertexCount, indexInfo.startIndex, primitiveCount); + } } } } -void Context::flush() +// Implements glFlush when block is false, glFinish when block is true +void Context::sync(bool block) { - IDirect3DDevice9 *device = getDevice(); - IDirect3DQuery9 *eventQuery = NULL; - - HRESULT result = device->CreateQuery(D3DQUERYTYPE_EVENT, &eventQuery); + mDisplay->sync(block); +} - if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY) +void Context::drawLineLoop(GLsizei count, GLenum type, const GLvoid *indices, int minIndex) +{ + // Get the raw indices for an indexed draw + if (type != GL_NONE && mState.elementArrayBuffer.get()) { - return error(GL_OUT_OF_MEMORY); + Buffer *indexBuffer = mState.elementArrayBuffer.get(); + intptr_t offset = reinterpret_cast<intptr_t>(indices); + indices = static_cast<const GLubyte*>(indexBuffer->data()) + offset; } - ASSERT(SUCCEEDED(result)); + UINT startIndex = 0; + bool succeeded = false; - if (eventQuery) + if (supports32bitIndices()) { - HRESULT result = eventQuery->Issue(D3DISSUE_END); - ASSERT(SUCCEEDED(result)); + const int spaceNeeded = (count + 1) * sizeof(unsigned int); - result = eventQuery->GetData(NULL, 0, D3DGETDATA_FLUSH); - eventQuery->Release(); - - if (result == D3DERR_DEVICELOST) + if (!mLineLoopIB) { - error(GL_OUT_OF_MEMORY); + mLineLoopIB = new StreamingIndexBuffer(mDevice, INITIAL_INDEX_BUFFER_SIZE, D3DFMT_INDEX32); } - } -} - -void Context::drawClosingLine(unsigned int first, unsigned int last) -{ - IDirect3DDevice9 *device = getDevice(); - IDirect3DIndexBuffer9 *indexBuffer = NULL; - HRESULT result = D3DERR_INVALIDCALL; - - if (supports32bitIndices()) - { - result = device->CreateIndexBuffer(8, D3DUSAGE_WRITEONLY, D3DFMT_INDEX32, D3DPOOL_DEFAULT, &indexBuffer, 0); - if (SUCCEEDED(result)) + if (mLineLoopIB) { - unsigned int *data; - result = indexBuffer->Lock(0, 0, (void**)&data, 0); + mLineLoopIB->reserveSpace(spaceNeeded, GL_UNSIGNED_INT); - if (SUCCEEDED(result)) + UINT offset = 0; + unsigned int *data = static_cast<unsigned int*>(mLineLoopIB->map(spaceNeeded, &offset)); + startIndex = offset / 4; + + if (data) { - data[0] = last; - data[1] = first; + switch (type) + { + case GL_NONE: // Non-indexed draw + for (int i = 0; i < count; i++) + { + data[i] = i; + } + data[count] = 0; + break; + case GL_UNSIGNED_BYTE: + for (int i = 0; i < count; i++) + { + data[i] = static_cast<const GLubyte*>(indices)[i]; + } + data[count] = static_cast<const GLubyte*>(indices)[0]; + break; + case GL_UNSIGNED_SHORT: + for (int i = 0; i < count; i++) + { + data[i] = static_cast<const GLushort*>(indices)[i]; + } + data[count] = static_cast<const GLushort*>(indices)[0]; + break; + case GL_UNSIGNED_INT: + for (int i = 0; i < count; i++) + { + data[i] = static_cast<const GLuint*>(indices)[i]; + } + data[count] = static_cast<const GLuint*>(indices)[0]; + break; + default: UNREACHABLE(); + } + + mLineLoopIB->unmap(); + succeeded = true; } } } else { - result = device->CreateIndexBuffer(4, D3DUSAGE_WRITEONLY, D3DFMT_INDEX16, D3DPOOL_DEFAULT, &indexBuffer, 0); + const int spaceNeeded = (count + 1) * sizeof(unsigned short); - if (SUCCEEDED(result)) + if (!mLineLoopIB) { - unsigned short *data; - result = indexBuffer->Lock(0, 0, (void**)&data, 0); + mLineLoopIB = new StreamingIndexBuffer(mDevice, INITIAL_INDEX_BUFFER_SIZE, D3DFMT_INDEX16); + } - if (SUCCEEDED(result)) + if (mLineLoopIB) + { + mLineLoopIB->reserveSpace(spaceNeeded, GL_UNSIGNED_SHORT); + + UINT offset = 0; + unsigned short *data = static_cast<unsigned short*>(mLineLoopIB->map(spaceNeeded, &offset)); + startIndex = offset / 2; + + if (data) { - data[0] = last; - data[1] = first; + switch (type) + { + case GL_NONE: // Non-indexed draw + for (int i = 0; i < count; i++) + { + data[i] = i; + } + data[count] = 0; + break; + case GL_UNSIGNED_BYTE: + for (int i = 0; i < count; i++) + { + data[i] = static_cast<const GLubyte*>(indices)[i]; + } + data[count] = static_cast<const GLubyte*>(indices)[0]; + break; + case GL_UNSIGNED_SHORT: + for (int i = 0; i < count; i++) + { + data[i] = static_cast<const GLushort*>(indices)[i]; + } + data[count] = static_cast<const GLushort*>(indices)[0]; + break; + case GL_UNSIGNED_INT: + for (int i = 0; i < count; i++) + { + data[i] = static_cast<const GLuint*>(indices)[i]; + } + data[count] = static_cast<const GLuint*>(indices)[0]; + break; + default: UNREACHABLE(); + } + + mLineLoopIB->unmap(); + succeeded = true; } } } - if (SUCCEEDED(result)) + if (succeeded) { - indexBuffer->Unlock(); - device->SetIndices(indexBuffer); - - device->DrawIndexedPrimitive(D3DPT_LINELIST, 0, 0, 2, 0, 1); + if (mAppliedIBSerial != mLineLoopIB->getSerial()) + { + mDevice->SetIndices(mLineLoopIB->getBuffer()); + mAppliedIBSerial = mLineLoopIB->getSerial(); + } - indexBuffer->Release(); + mDevice->DrawIndexedPrimitive(D3DPT_LINESTRIP, -minIndex, minIndex, count, startIndex, count); } else { - ERR("Could not create an index buffer for closing a line loop."); - error(GL_OUT_OF_MEMORY); - } -} - -void Context::drawClosingLine(GLsizei count, GLenum type, const void *indices) -{ - unsigned int first = 0; - unsigned int last = 0; - - if (mState.elementArrayBuffer.get()) - { - Buffer *indexBuffer = mState.elementArrayBuffer.get(); - intptr_t offset = reinterpret_cast<intptr_t>(indices); - indices = static_cast<const GLubyte*>(indexBuffer->data()) + offset; - } - - switch (type) - { - case GL_UNSIGNED_BYTE: - first = static_cast<const GLubyte*>(indices)[0]; - last = static_cast<const GLubyte*>(indices)[count - 1]; - break; - case GL_UNSIGNED_SHORT: - first = static_cast<const GLushort*>(indices)[0]; - last = static_cast<const GLushort*>(indices)[count - 1]; - break; - case GL_UNSIGNED_INT: - first = static_cast<const GLuint*>(indices)[0]; - last = static_cast<const GLuint*>(indices)[count - 1]; - break; - default: UNREACHABLE(); + ERR("Could not create a looping index buffer for GL_LINE_LOOP."); + return error(GL_OUT_OF_MEMORY); } - - drawClosingLine(first, last); } void Context::recordInvalidEnum() @@ -2907,6 +3283,36 @@ GLenum Context::getError() return GL_NO_ERROR; } +GLenum Context::getResetStatus() +{ + if (mResetStatus == GL_NO_ERROR) + { + bool lost = mDisplay->testDeviceLost(); + + if (lost) + { + mDisplay->notifyDeviceLost(); // Sets mResetStatus + } + } + + GLenum status = mResetStatus; + + if (mResetStatus != GL_NO_ERROR) + { + if (mDisplay->testDeviceResettable()) + { + mResetStatus = GL_NO_ERROR; + } + } + + return status; +} + +bool Context::isResetNotificationEnabled() +{ + return (mResetStrategy == GL_LOSE_CONTEXT_ON_RESET_EXT); +} + bool Context::supportsShaderModel3() const { return mSupportsShaderModel3; @@ -2917,6 +3323,16 @@ int Context::getMaximumVaryingVectors() const return mSupportsShaderModel3 ? MAX_VARYING_VECTORS_SM3 : MAX_VARYING_VECTORS_SM2; } +unsigned int Context::getMaximumVertexTextureImageUnits() const +{ + return mSupportsVertexTexture ? MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF : 0; +} + +unsigned int Context::getMaximumCombinedTextureImageUnits() const +{ + return MAX_TEXTURE_IMAGE_UNITS + getMaximumVertexTextureImageUnits(); +} + int Context::getMaximumFragmentUniformVectors() const { return mSupportsShaderModel3 ? MAX_FRAGMENT_UNIFORM_VECTORS_SM3 : MAX_FRAGMENT_UNIFORM_VECTORS_SM2; @@ -2956,39 +3372,54 @@ bool Context::supportsEventQueries() const return mSupportsEventQueries; } -bool Context::supportsCompressedTextures() const +bool Context::supportsOcclusionQueries() const +{ + return mSupportsOcclusionQueries; +} + +bool Context::supportsDXT1Textures() const +{ + return mSupportsDXT1Textures; +} + +bool Context::supportsDXT3Textures() const +{ + return mSupportsDXT3Textures; +} + +bool Context::supportsDXT5Textures() const { - return mSupportsCompressedTextures; + return mSupportsDXT5Textures; } -bool Context::supportsFloatTextures() const +bool Context::supportsFloat32Textures() const { - return mSupportsFloatTextures; + return mSupportsFloat32Textures; } -bool Context::supportsFloatLinearFilter() const +bool Context::supportsFloat32LinearFilter() const { - return mSupportsFloatLinearFilter; + return mSupportsFloat32LinearFilter; } -bool Context::supportsFloatRenderableTextures() const +bool Context::supportsFloat32RenderableTextures() const { - return mSupportsFloatRenderableTextures; + return mSupportsFloat32RenderableTextures; } -bool Context::supportsHalfFloatTextures() const +bool Context::supportsFloat16Textures() const { - return mSupportsHalfFloatTextures; + return mSupportsFloat16Textures; } -bool Context::supportsHalfFloatLinearFilter() const +bool Context::supportsFloat16LinearFilter() const { - return mSupportsHalfFloatLinearFilter; + return mSupportsFloat16LinearFilter; } -bool Context::supportsHalfFloatRenderableTextures() const +bool Context::supportsFloat16RenderableTextures() const { - return mSupportsHalfFloatRenderableTextures; + return mSupportsFloat16RenderableTextures; } int Context::getMaximumRenderbufferDimension() const @@ -3026,6 +3457,16 @@ bool Context::supports32bitIndices() const return mSupports32bitIndices; } +bool Context::supportsNonPower2Texture() const +{ + return mSupportsNonPower2Texture; +} + +bool Context::supportsInstancing() const +{ + return mSupportsInstancing; +} + void Context::detachBuffer(GLuint buffer) { // [OpenGL ES 2.0.24] section 2.9 page 22: @@ -3057,9 +3498,9 @@ void Context::detachTexture(GLuint texture) // 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 < SAMPLER_TYPE_COUNT; type++) + for (int type = 0; type < TEXTURE_TYPE_COUNT; type++) { - for (int sampler = 0; sampler < MAX_TEXTURE_IMAGE_UNITS; sampler++) + for (int sampler = 0; sampler < MAX_COMBINED_TEXTURE_IMAGE_UNITS_VTF; sampler++) { if (mState.samplerTexture[type][sampler].id() == texture) { @@ -3134,7 +3575,7 @@ void Context::detachRenderbuffer(GLuint renderbuffer) } } -Texture *Context::getIncompleteTexture(SamplerType type) +Texture *Context::getIncompleteTexture(TextureType type) { Texture *t = mIncompleteTextures[type].get(); @@ -3146,26 +3587,26 @@ Texture *Context::getIncompleteTexture(SamplerType type) { default: UNREACHABLE(); - // default falls through to SAMPLER_2D + // default falls through to TEXTURE_2D - case SAMPLER_2D: + case TEXTURE_2D: { Texture2D *incomplete2d = new Texture2D(Texture::INCOMPLETE_TEXTURE_ID); - incomplete2d->setImage(0, GL_RGBA, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color); + incomplete2d->setImage(0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color); t = incomplete2d; } break; - case SAMPLER_CUBE: + case TEXTURE_CUBE: { TextureCubeMap *incompleteCube = new TextureCubeMap(Texture::INCOMPLETE_TEXTURE_ID); - incompleteCube->setImagePosX(0, GL_RGBA, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color); - incompleteCube->setImageNegX(0, GL_RGBA, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color); - incompleteCube->setImagePosY(0, GL_RGBA, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color); - incompleteCube->setImageNegY(0, GL_RGBA, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color); - incompleteCube->setImagePosZ(0, GL_RGBA, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color); - incompleteCube->setImageNegZ(0, GL_RGBA, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color); + 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); t = incompleteCube; } @@ -3214,53 +3655,100 @@ void Context::setVertexAttrib(GLuint index, const GLfloat *values) mVertexDataManager->dirtyCurrentValue(index); } +void Context::setVertexAttribDivisor(GLuint index, GLuint divisor) +{ + ASSERT(index < gl::MAX_VERTEX_ATTRIBS); + + mState.vertexAttribute[index].mDivisor = divisor; +} + +// keep list sorted in following order +// OES extensions +// EXT extensions +// Vendor extensions void Context::initExtensionString() { + mExtensionString = ""; + + // OES extensions + if (supports32bitIndices()) + { + mExtensionString += "GL_OES_element_index_uint "; + } + mExtensionString += "GL_OES_packed_depth_stencil "; - mExtensionString += "GL_EXT_texture_format_BGRA8888 "; - mExtensionString += "GL_EXT_read_format_bgra "; - mExtensionString += "GL_ANGLE_framebuffer_blit "; mExtensionString += "GL_OES_rgb8_rgba8 "; mExtensionString += "GL_OES_standard_derivatives "; - if (supportsEventQueries()) + if (supportsFloat16Textures()) { - mExtensionString += "GL_NV_fence "; + mExtensionString += "GL_OES_texture_half_float "; } - - if (supportsCompressedTextures()) + if (supportsFloat16LinearFilter()) { - mExtensionString += "GL_EXT_texture_compression_dxt1 "; + mExtensionString += "GL_OES_texture_half_float_linear "; } - - if (supportsFloatTextures()) + if (supportsFloat32Textures()) { mExtensionString += "GL_OES_texture_float "; } + if (supportsFloat32LinearFilter()) + { + mExtensionString += "GL_OES_texture_float_linear "; + } - if (supportsHalfFloatTextures()) + if (supportsNonPower2Texture()) { - mExtensionString += "GL_OES_texture_half_float "; + mExtensionString += "GL_OES_texture_npot "; } - if (supportsFloatLinearFilter()) + // Multi-vendor (EXT) extensions + if (supportsOcclusionQueries()) { - mExtensionString += "GL_OES_texture_float_linear "; + mExtensionString += "GL_EXT_occlusion_query_boolean "; } - if (supportsHalfFloatLinearFilter()) + mExtensionString += "GL_EXT_read_format_bgra "; + mExtensionString += "GL_EXT_robustness "; + + if (supportsDXT1Textures()) { - mExtensionString += "GL_OES_texture_half_float_linear "; + mExtensionString += "GL_EXT_texture_compression_dxt1 "; } + mExtensionString += "GL_EXT_texture_format_BGRA8888 "; + mExtensionString += "GL_EXT_texture_storage "; + + // ANGLE-specific extensions + mExtensionString += "GL_ANGLE_framebuffer_blit "; if (getMaxSupportedSamples() != 0) { mExtensionString += "GL_ANGLE_framebuffer_multisample "; } - if (supports32bitIndices()) + if (supportsInstancing()) { - mExtensionString += "GL_OES_element_index_uint "; + mExtensionString += "GL_ANGLE_instanced_arrays "; + } + + mExtensionString += "GL_ANGLE_pack_reverse_row_order "; + + if (supportsDXT3Textures()) + { + mExtensionString += "GL_ANGLE_texture_compression_dxt3 "; + } + if (supportsDXT5Textures()) + { + mExtensionString += "GL_ANGLE_texture_compression_dxt5 "; + } + + mExtensionString += "GL_ANGLE_texture_usage "; + mExtensionString += "GL_ANGLE_translated_shader_source "; + + // Other vendor-specific extensions + if (supportsEventQueries()) + { + mExtensionString += "GL_NV_fence "; } std::string::size_type end = mExtensionString.find_last_not_of(' '); @@ -3275,12 +3763,24 @@ const char *Context::getExtensionString() const return mExtensionString.c_str(); } +void Context::initRendererString() +{ + D3DADAPTER_IDENTIFIER9 *identifier = mDisplay->getAdapterIdentifier(); + + mRendererString = "ANGLE ("; + mRendererString += identifier->Description; + mRendererString += ")"; +} + +const char *Context::getRendererString() const +{ + return mRendererString.c_str(); +} + void Context::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask) { - IDirect3DDevice9 *device = getDevice(); - Framebuffer *readFramebuffer = getReadFramebuffer(); Framebuffer *drawFramebuffer = getDrawFramebuffer(); @@ -3295,6 +3795,11 @@ void Context::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1 return error(GL_INVALID_OPERATION); } + int readBufferWidth = readFramebuffer->getColorbuffer()->getWidth(); + int readBufferHeight = readFramebuffer->getColorbuffer()->getHeight(); + int drawBufferWidth = drawFramebuffer->getColorbuffer()->getWidth(); + int drawBufferHeight = drawFramebuffer->getColorbuffer()->getHeight(); + RECT sourceRect; RECT destRect; @@ -3313,21 +3818,19 @@ void Context::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1 destRect.right = dstX0; } - // Arguments to StretchRect must be in D3D-style (0-top) coordinates, so we must - // flip our Y-values here if (srcY0 < srcY1) { - sourceRect.bottom = srcY1; - destRect.bottom = dstY1; - sourceRect.top = srcY0; - destRect.top = dstY0; + sourceRect.top = readBufferHeight - srcY1; + destRect.top = drawBufferHeight - dstY1; + sourceRect.bottom = readBufferHeight - srcY0; + destRect.bottom = drawBufferHeight - dstY0; } else { - sourceRect.bottom = srcY0; - destRect.bottom = dstY0; - sourceRect.top = srcY1; - destRect.top = dstY1; + sourceRect.top = readBufferHeight - srcY0; + destRect.top = drawBufferHeight - dstY0; + sourceRect.bottom = readBufferHeight - srcY1; + destRect.bottom = drawBufferHeight - dstY1; } RECT sourceScissoredRect = sourceRect; @@ -3382,11 +3885,6 @@ void Context::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1 destTrimmedRect.left += xDiff; } - int readBufferWidth = readFramebuffer->getColorbuffer()->getWidth(); - int readBufferHeight = readFramebuffer->getColorbuffer()->getHeight(); - int drawBufferWidth = drawFramebuffer->getColorbuffer()->getWidth(); - int drawBufferHeight = drawFramebuffer->getColorbuffer()->getHeight(); - if (sourceTrimmedRect.right > readBufferWidth) { int xDiff = sourceTrimmedRect.right - readBufferWidth; @@ -3470,8 +3968,8 @@ void Context::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1 if (mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) { - DepthStencilbuffer *readDSBuffer = NULL; - DepthStencilbuffer *drawDSBuffer = NULL; + 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. @@ -3523,13 +4021,18 @@ void Context::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1 if (blitRenderTarget || blitDepthStencil) { - egl::Display *display = getDisplay(); - display->endScene(); + mDisplay->endScene(); if (blitRenderTarget) { - HRESULT result = device->StretchRect(readFramebuffer->getRenderTarget(), &sourceTrimmedRect, - drawFramebuffer->getRenderTarget(), &destTrimmedRect, D3DTEXF_NONE); + IDirect3DSurface9* readRenderTarget = readFramebuffer->getRenderTarget(); + IDirect3DSurface9* drawRenderTarget = drawFramebuffer->getRenderTarget(); + + HRESULT result = mDevice->StretchRect(readRenderTarget, &sourceTrimmedRect, + drawRenderTarget, &destTrimmedRect, D3DTEXF_NONE); + + readRenderTarget->Release(); + drawRenderTarget->Release(); if (FAILED(result)) { @@ -3540,7 +4043,7 @@ void Context::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1 if (blitDepthStencil) { - HRESULT result = device->StretchRect(readFramebuffer->getDepthStencil(), NULL, drawFramebuffer->getDepthStencil(), NULL, D3DTEXF_NONE); + HRESULT result = mDevice->StretchRect(readFramebuffer->getDepthStencil(), NULL, drawFramebuffer->getDepthStencil(), NULL, D3DTEXF_NONE); if (FAILED(result)) { @@ -3551,13 +4054,204 @@ void Context::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1 } } +VertexDeclarationCache::VertexDeclarationCache() : mMaxLru(0) +{ + for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++) + { + mVertexDeclCache[i].vertexDeclaration = NULL; + mVertexDeclCache[i].lruCount = 0; + } +} + +VertexDeclarationCache::~VertexDeclarationCache() +{ + for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++) + { + if (mVertexDeclCache[i].vertexDeclaration) + { + mVertexDeclCache[i].vertexDeclaration->Release(); + } + } +} + +GLenum VertexDeclarationCache::applyDeclaration(IDirect3DDevice9 *device, TranslatedAttribute attributes[], Program *program, GLsizei instances, GLsizei *repeatDraw) +{ + *repeatDraw = 1; + + int indexedAttribute = MAX_VERTEX_ATTRIBS; + int instancedAttribute = MAX_VERTEX_ATTRIBS; + + if (instances > 0) + { + // Find an indexed attribute to be mapped to D3D stream 0 + for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++) + { + if (attributes[i].active) + { + if (indexedAttribute == MAX_VERTEX_ATTRIBS) + { + if (attributes[i].divisor == 0) + { + indexedAttribute = i; + } + } + else if (instancedAttribute == MAX_VERTEX_ATTRIBS) + { + if (attributes[i].divisor != 0) + { + instancedAttribute = i; + } + } + else break; // Found both an indexed and instanced attribute + } + } + + if (indexedAttribute == MAX_VERTEX_ATTRIBS) + { + return GL_INVALID_OPERATION; + } + } + + D3DVERTEXELEMENT9 elements[MAX_VERTEX_ATTRIBS + 1]; + D3DVERTEXELEMENT9 *element = &elements[0]; + + for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++) + { + if (attributes[i].active) + { + int stream = i; + + if (instances > 0) + { + // Due to a bug on ATI cards we can't enable instancing when none of the attributes are instanced. + if (instancedAttribute == MAX_VERTEX_ATTRIBS) + { + *repeatDraw = instances; + } + else + { + if (i == indexedAttribute) + { + stream = 0; + } + else if (i == 0) + { + stream = indexedAttribute; + } + + UINT frequency = 1; + + if (attributes[i].divisor == 0) + { + frequency = D3DSTREAMSOURCE_INDEXEDDATA | instances; + } + else + { + frequency = D3DSTREAMSOURCE_INSTANCEDATA | attributes[i].divisor; + } + + device->SetStreamSourceFreq(stream, frequency); + mInstancingEnabled = true; + } + } + + if (mAppliedVBs[stream].serial != attributes[i].serial || + mAppliedVBs[stream].stride != attributes[i].stride || + mAppliedVBs[stream].offset != attributes[i].offset) + { + device->SetStreamSource(stream, attributes[i].vertexBuffer, attributes[i].offset, attributes[i].stride); + mAppliedVBs[stream].serial = attributes[i].serial; + mAppliedVBs[stream].stride = attributes[i].stride; + mAppliedVBs[stream].offset = attributes[i].offset; + } + + element->Stream = stream; + element->Offset = 0; + element->Type = attributes[i].type; + element->Method = D3DDECLMETHOD_DEFAULT; + element->Usage = D3DDECLUSAGE_TEXCOORD; + element->UsageIndex = program->getSemanticIndex(i); + element++; + } + } + + if (instances == 0 || instancedAttribute == MAX_VERTEX_ATTRIBS) + { + if (mInstancingEnabled) + { + for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++) + { + device->SetStreamSourceFreq(i, 1); + } + + mInstancingEnabled = false; + } + } + + static const D3DVERTEXELEMENT9 end = D3DDECL_END(); + *(element++) = end; + + for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++) + { + VertexDeclCacheEntry *entry = &mVertexDeclCache[i]; + if (memcmp(entry->cachedElements, elements, (element - elements) * sizeof(D3DVERTEXELEMENT9)) == 0 && entry->vertexDeclaration) + { + entry->lruCount = ++mMaxLru; + if(entry->vertexDeclaration != mLastSetVDecl) + { + device->SetVertexDeclaration(entry->vertexDeclaration); + mLastSetVDecl = entry->vertexDeclaration; + } + + return GL_NO_ERROR; + } + } + + VertexDeclCacheEntry *lastCache = mVertexDeclCache; + + for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++) + { + if (mVertexDeclCache[i].lruCount < lastCache->lruCount) + { + lastCache = &mVertexDeclCache[i]; + } + } + + if (lastCache->vertexDeclaration != NULL) + { + lastCache->vertexDeclaration->Release(); + lastCache->vertexDeclaration = NULL; + // mLastSetVDecl is set to the replacement, so we don't have to worry + // about it. + } + + memcpy(lastCache->cachedElements, elements, (element - elements) * sizeof(D3DVERTEXELEMENT9)); + device->CreateVertexDeclaration(elements, &lastCache->vertexDeclaration); + device->SetVertexDeclaration(lastCache->vertexDeclaration); + mLastSetVDecl = lastCache->vertexDeclaration; + lastCache->lruCount = ++mMaxLru; + + return GL_NO_ERROR; +} + +void VertexDeclarationCache::markStateDirty() +{ + for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++) + { + mAppliedVBs[i].serial = 0; + } + + mLastSetVDecl = NULL; + mInstancingEnabled = true; // Forces it to be disabled when not used +} + } extern "C" { -gl::Context *glCreateContext(const egl::Config *config, const gl::Context *shareContext) +gl::Context *glCreateContext(const egl::Config *config, const gl::Context *shareContext, bool notifyResets, bool robustAccess) { - return new gl::Context(config, shareContext); + return new gl::Context(config, shareContext, notifyResets, robustAccess); } void glDestroyContext(gl::Context *context) |