diff options
Diffstat (limited to 'ANGLE/src/libGLESv2/Context.cpp')
-rw-r--r-- | ANGLE/src/libGLESv2/Context.cpp | 1287 |
1 files changed, 808 insertions, 479 deletions
diff --git a/ANGLE/src/libGLESv2/Context.cpp b/ANGLE/src/libGLESv2/Context.cpp index 55a83ff..48ef8fc 100644 --- a/ANGLE/src/libGLESv2/Context.cpp +++ b/ANGLE/src/libGLESv2/Context.cpp @@ -17,6 +17,7 @@ #include "libGLESv2/mathutil.h" #include "libGLESv2/utilities.h" #include "libGLESv2/Blit.h" +#include "libGLESv2/ResourceManager.h" #include "libGLESv2/Buffer.h" #include "libGLESv2/FrameBuffer.h" #include "libGLESv2/Program.h" @@ -33,7 +34,7 @@ namespace gl { -Context::Context(const egl::Config *config) +Context::Context(const egl::Config *config, const gl::Context *shareContext) : mConfig(config) { setClearColor(0.0f, 0.0f, 0.0f, 0.0f); @@ -103,37 +104,39 @@ Context::Context(const egl::Config *config) mState.colorMaskAlpha = true; mState.depthMask = true; + if (shareContext != NULL) + { + mResourceManager = shareContext->mResourceManager; + mResourceManager->addRef(); + } + else + { + mResourceManager = new ResourceManager(); + } + // [OpenGL ES 2.0.24] section 3.7 page 83: // In the initial state, TEXTURE_2D and TEXTURE_CUBE_MAP have twodimensional // and cube map texture state vectors respectively associated with them. // In order that access to these initial textures not be lost, they are treated as texture // objects all of whose names are 0. - mTexture2DZero = new Texture2D(this); - mTextureCubeMapZero = new TextureCubeMap(this); + mTexture2DZero = new Texture2D(0); + mTextureCubeMapZero = new TextureCubeMap(0); mColorbufferZero = NULL; - mDepthbufferZero = NULL; - mStencilbufferZero = NULL; + mDepthStencilbufferZero = NULL; mState.activeSampler = 0; - mState.arrayBuffer = 0; - mState.elementArrayBuffer = 0; + bindArrayBuffer(0); + bindElementArrayBuffer(0); bindTextureCubeMap(0); bindTexture2D(0); - bindFramebuffer(0); + bindReadFramebuffer(0); + bindDrawFramebuffer(0); bindRenderbuffer(0); for (int type = 0; type < SAMPLER_TYPE_COUNT; type++) { - for (int sampler = 0; sampler < MAX_TEXTURE_IMAGE_UNITS; sampler++) - { - mState.samplerTexture[type][sampler] = 0; - } - } - - for (int type = 0; type < SAMPLER_TYPE_COUNT; type++) - { mIncompleteTextures[type] = NULL; } @@ -155,65 +158,72 @@ Context::Context(const egl::Config *config) mHasBeenCurrent = false; + mMaxSupportedSamples = 0; mMaskedClearSavedState = NULL; markAllStateDirty(); } Context::~Context() { - mState.currentProgram = 0; - - for (int type = 0; type < SAMPLER_TYPE_COUNT; type++) + if (mState.currentProgram != 0) { - delete mIncompleteTextures[type]; + Program *programObject = mResourceManager->getProgram(mState.currentProgram); + if (programObject) + { + programObject->release(); + } + mState.currentProgram = 0; } - delete mTexture2DZero; - delete mTextureCubeMapZero; - - delete mColorbufferZero; - delete mDepthbufferZero; - delete mStencilbufferZero; - - delete mBufferBackEnd; - delete mVertexDataManager; - delete mIndexDataManager; - delete mBlit; - - while (!mBufferMap.empty()) + while (!mFramebufferMap.empty()) { - deleteBuffer(mBufferMap.begin()->first); + deleteFramebuffer(mFramebufferMap.begin()->first); } - while (!mProgramMap.empty()) + while (!mMultiSampleSupport.empty()) { - deleteProgram(mProgramMap.begin()->first); + delete [] mMultiSampleSupport.begin()->second; + mMultiSampleSupport.erase(mMultiSampleSupport.begin()); } - while (!mShaderMap.empty()) + for (int type = 0; type < SAMPLER_TYPE_COUNT; type++) { - deleteShader(mShaderMap.begin()->first); + for (int sampler = 0; sampler < MAX_TEXTURE_IMAGE_UNITS; sampler++) + { + mState.samplerTexture[type][sampler].set(NULL); + } } - while (!mFramebufferMap.empty()) + for (int type = 0; type < SAMPLER_TYPE_COUNT; type++) { - deleteFramebuffer(mFramebufferMap.begin()->first); + delete mIncompleteTextures[type]; } - while (!mRenderbufferMap.empty()) + for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++) { - deleteRenderbuffer(mRenderbufferMap.begin()->first); + mState.vertexAttribute[i].mBoundBuffer.set(NULL); } - while (!mTextureMap.empty()) - { - deleteTexture(mTextureMap.begin()->first); - } + mState.arrayBuffer.set(NULL); + mState.elementArrayBuffer.set(NULL); + mState.texture2D.set(NULL); + mState.textureCubeMap.set(NULL); + mState.renderbuffer.set(NULL); + + delete mTexture2DZero; + delete mTextureCubeMapZero; + + delete mBufferBackEnd; + delete mVertexDataManager; + delete mIndexDataManager; + delete mBlit; if (mMaskedClearSavedState) { mMaskedClearSavedState->Release(); } + + mResourceManager->release(); } void Context::makeCurrent(egl::Display *display, egl::Surface *surface) @@ -229,6 +239,34 @@ void Context::makeCurrent(egl::Display *display, egl::Surface *surface) mIndexDataManager = new IndexDataManager(this, mBufferBackEnd); mBlit = new Blit(this); + const D3DFORMAT renderBufferFormats[] = + { + D3DFMT_A8R8G8B8, + D3DFMT_X8R8G8B8, + D3DFMT_R5G6B5, + D3DFMT_D24S8 + }; + + int max = 0; + for (int i = 0; i < sizeof(renderBufferFormats) / sizeof(D3DFORMAT); ++i) + { + bool *multisampleArray = new bool[D3DMULTISAMPLE_16_SAMPLES + 1]; + display->getMultiSampleSupport(renderBufferFormats[i], multisampleArray); + mMultiSampleSupport[renderBufferFormats[i]] = multisampleArray; + + for (int j = D3DMULTISAMPLE_16_SAMPLES; j >= 0; --j) + { + if (multisampleArray[j] && j != D3DMULTISAMPLE_NONMASKABLE && j > max) + { + max = j; + } + } + } + + mMaxSupportedSamples = max; + + mSupportsCompressedTextures = display->getCompressedTextureSupport(); + initExtensionString(); mState.viewportX = 0; @@ -248,19 +286,11 @@ void Context::makeCurrent(egl::Display *display, egl::Surface *surface) IDirect3DSurface9 *defaultRenderTarget = surface->getRenderTarget(); IDirect3DSurface9 *depthStencil = surface->getDepthStencil(); - Framebuffer *framebufferZero = new Framebuffer(); Colorbuffer *colorbufferZero = new Colorbuffer(defaultRenderTarget); - Depthbuffer *depthbufferZero = new Depthbuffer(depthStencil); - Stencilbuffer *stencilbufferZero = new Stencilbuffer(depthStencil); + DepthStencilbuffer *depthStencilbufferZero = new DepthStencilbuffer(depthStencil); + Framebuffer *framebufferZero = new DefaultFramebuffer(colorbufferZero, depthStencilbufferZero); setFramebufferZero(framebufferZero); - setColorbufferZero(colorbufferZero); - setDepthbufferZero(depthbufferZero); - setStencilbufferZero(stencilbufferZero); - - framebufferZero->setColorbuffer(GL_RENDERBUFFER, 0); - framebufferZero->setDepthbuffer(GL_RENDERBUFFER, 0); - framebufferZero->setStencilbuffer(GL_RENDERBUFFER, 0); defaultRenderTarget->Release(); @@ -269,16 +299,7 @@ void Context::makeCurrent(egl::Display *display, egl::Surface *surface) depthStencil->Release(); } - if (mDeviceCaps.PixelShaderVersion == D3DPS_VERSION(3, 0)) - { - mPsProfile = "ps_3_0"; - mVsProfile = "vs_3_0"; - } - else // egl::Display guarantees support for at least 2.0 - { - mPsProfile = "ps_2_0"; - mVsProfile = "vs_2_0"; - } + mSupportsShaderModel3 = mDeviceCaps.PixelShaderVersion == D3DPS_VERSION(3, 0); markAllStateDirty(); } @@ -300,6 +321,12 @@ void Context::markAllStateDirty() mScissorStateDirty = true; mSampleStateDirty = true; mDitherStateDirty = true; + mFrontFaceDirty = true; + + if (mBufferBackEnd != NULL) + { + mBufferBackEnd->invalidate(); + } } void Context::setClearColor(float red, float green, float blue, float alpha) @@ -671,19 +698,24 @@ void Context::setActiveSampler(int active) mState.activeSampler = active; } -GLuint Context::getFramebufferHandle() const +GLuint Context::getReadFramebufferHandle() const { - return mState.framebuffer; + return mState.readFramebuffer; +} + +GLuint Context::getDrawFramebufferHandle() const +{ + return mState.drawFramebuffer; } GLuint Context::getRenderbufferHandle() const { - return mState.renderbuffer; + return mState.renderbuffer.id(); } GLuint Context::getArrayBufferHandle() const { - return mState.arrayBuffer; + return mState.arrayBuffer.id(); } void Context::setVertexAttribEnabled(unsigned int attribNum, bool enabled) @@ -696,10 +728,10 @@ const AttributeState &Context::getVertexAttribState(unsigned int attribNum) return mState.vertexAttribute[attribNum]; } -void Context::setVertexAttribState(unsigned int attribNum, GLuint boundBuffer, GLint size, GLenum type, bool normalized, +void Context::setVertexAttribState(unsigned int attribNum, Buffer *boundBuffer, GLint size, GLenum type, bool normalized, GLsizei stride, const void *pointer) { - mState.vertexAttribute[attribNum].mBoundBuffer = boundBuffer; + mState.vertexAttribute[attribNum].mBoundBuffer.set(boundBuffer); mState.vertexAttribute[attribNum].mSize = size; mState.vertexAttribute[attribNum].mType = type; mState.vertexAttribute[attribNum].mNormalized = normalized; @@ -738,72 +770,29 @@ GLint Context::getUnpackAlignment() const return mState.unpackAlignment; } -// Returns an unused buffer name GLuint Context::createBuffer() { - unsigned int handle = 1; - - while (mBufferMap.find(handle) != mBufferMap.end()) - { - handle++; - } - - mBufferMap[handle] = NULL; - - return handle; + return mResourceManager->createBuffer(); } -// Returns an unused shader/program name -GLuint Context::createShader(GLenum type) +GLuint Context::createProgram() { - unsigned int handle = 1; - - while (mShaderMap.find(handle) != mShaderMap.end() || mProgramMap.find(handle) != mProgramMap.end()) // Shared name space - { - handle++; - } - - if (type == GL_VERTEX_SHADER) - { - mShaderMap[handle] = new VertexShader(this, handle); - } - else if (type == GL_FRAGMENT_SHADER) - { - mShaderMap[handle] = new FragmentShader(this, handle); - } - else UNREACHABLE(); - - return handle; + return mResourceManager->createProgram(); } -// Returns an unused program/shader name -GLuint Context::createProgram() +GLuint Context::createShader(GLenum type) { - unsigned int handle = 1; - - while (mProgramMap.find(handle) != mProgramMap.end() || mShaderMap.find(handle) != mShaderMap.end()) // Shared name space - { - handle++; - } - - mProgramMap[handle] = new Program(); - - return handle; + return mResourceManager->createShader(type); } -// Returns an unused texture name GLuint Context::createTexture() { - unsigned int handle = 1; - - while (mTextureMap.find(handle) != mTextureMap.end()) - { - handle++; - } - - mTextureMap[handle] = NULL; + return mResourceManager->createTexture(); +} - return handle; +GLuint Context::createRenderbuffer() +{ + return mResourceManager->createRenderbuffer(); } // Returns an unused framebuffer name @@ -821,85 +810,44 @@ GLuint Context::createFramebuffer() return handle; } -// Returns an unused renderbuffer name -GLuint Context::createRenderbuffer() -{ - unsigned int handle = 1; - - while (mRenderbufferMap.find(handle) != mRenderbufferMap.end()) - { - handle++; - } - - mRenderbufferMap[handle] = NULL; - - return handle; -} - void Context::deleteBuffer(GLuint buffer) { - BufferMap::iterator bufferObject = mBufferMap.find(buffer); - - if (bufferObject != mBufferMap.end()) + if (mResourceManager->getBuffer(buffer)) { detachBuffer(buffer); - - delete bufferObject->second; - mBufferMap.erase(bufferObject); } + + mResourceManager->deleteBuffer(buffer); } void Context::deleteShader(GLuint shader) { - ShaderMap::iterator shaderObject = mShaderMap.find(shader); - - if (shaderObject != mShaderMap.end()) - { - if (!shaderObject->second->isAttached()) - { - delete shaderObject->second; - mShaderMap.erase(shaderObject); - } - else - { - shaderObject->second->flagForDeletion(); - } - } + mResourceManager->deleteShader(shader); } void Context::deleteProgram(GLuint program) { - ProgramMap::iterator programObject = mProgramMap.find(program); - - if (programObject != mProgramMap.end()) - { - if (program != mState.currentProgram) - { - delete programObject->second; - mProgramMap.erase(programObject); - } - else - { - programObject->second->flagForDeletion(); - } - } + mResourceManager->deleteProgram(program); } void Context::deleteTexture(GLuint texture) { - TextureMap::iterator textureObject = mTextureMap.find(texture); - - if (textureObject != mTextureMap.end()) + if (mResourceManager->getTexture(texture)) { detachTexture(texture); + } - if (texture != 0) - { - delete textureObject->second; - } + mResourceManager->deleteTexture(texture); +} - mTextureMap.erase(textureObject); +void Context::deleteRenderbuffer(GLuint renderbuffer) +{ + if (mResourceManager->getRenderbuffer(renderbuffer)) + { + detachRenderbuffer(renderbuffer); } + + mResourceManager->deleteRenderbuffer(renderbuffer); } void Context::deleteFramebuffer(GLuint framebuffer) @@ -915,307 +863,186 @@ void Context::deleteFramebuffer(GLuint framebuffer) } } -void Context::deleteRenderbuffer(GLuint renderbuffer) +Buffer *Context::getBuffer(GLuint handle) { - RenderbufferMap::iterator renderbufferObject = mRenderbufferMap.find(renderbuffer); - - if (renderbufferObject != mRenderbufferMap.end()) - { - detachRenderbuffer(renderbuffer); - - delete renderbufferObject->second; - mRenderbufferMap.erase(renderbufferObject); - } + return mResourceManager->getBuffer(handle); } -void Context::bindArrayBuffer(unsigned int buffer) +Shader *Context::getShader(GLuint handle) { - if (buffer != 0 && !getBuffer(buffer)) - { - mBufferMap[buffer] = new Buffer(); - } - - mState.arrayBuffer = buffer; + return mResourceManager->getShader(handle); } -void Context::bindElementArrayBuffer(unsigned int buffer) +Program *Context::getProgram(GLuint handle) { - if (buffer != 0 && !getBuffer(buffer)) - { - mBufferMap[buffer] = new Buffer(); - } - - mState.elementArrayBuffer = buffer; + return mResourceManager->getProgram(handle); } -void Context::bindTexture2D(GLuint texture) +Texture *Context::getTexture(GLuint handle) { - if (!getTexture(texture) && texture != 0) - { - mTextureMap[texture] = new Texture2D(this); - } - - mState.texture2D = texture; - - mState.samplerTexture[SAMPLER_2D][mState.activeSampler] = texture; + return mResourceManager->getTexture(handle); } -void Context::bindTextureCubeMap(GLuint texture) +Renderbuffer *Context::getRenderbuffer(GLuint handle) { - if (!getTexture(texture) && texture != 0) - { - mTextureMap[texture] = new TextureCubeMap(this); - } - - mState.textureCubeMap = texture; - - mState.samplerTexture[SAMPLER_CUBE][mState.activeSampler] = texture; + return mResourceManager->getRenderbuffer(handle); } -void Context::bindFramebuffer(GLuint framebuffer) +Framebuffer *Context::getReadFramebuffer() { - if (!getFramebuffer(framebuffer)) - { - mFramebufferMap[framebuffer] = new Framebuffer(); - } - - mState.framebuffer = framebuffer; + return getFramebuffer(mState.readFramebuffer); } -void Context::bindRenderbuffer(GLuint renderbuffer) +Framebuffer *Context::getDrawFramebuffer() { - if (renderbuffer != 0 && !getRenderbuffer(renderbuffer)) - { - mRenderbufferMap[renderbuffer] = new Renderbuffer(); - } - - mState.renderbuffer = renderbuffer; + return getFramebuffer(mState.drawFramebuffer); } -void Context::useProgram(GLuint program) +void Context::bindArrayBuffer(unsigned int buffer) { - Program *programObject = getCurrentProgram(); - - GLuint priorProgram = mState.currentProgram; - mState.currentProgram = program; // Must switch before trying to delete, otherwise it only gets flagged. + mResourceManager->checkBufferAllocation(buffer); - if (programObject && programObject->isFlaggedForDeletion()) - { - deleteProgram(priorProgram); - } + mState.arrayBuffer.set(getBuffer(buffer)); } -void Context::setFramebufferZero(Framebuffer *buffer) +void Context::bindElementArrayBuffer(unsigned int buffer) { - delete mFramebufferMap[0]; - mFramebufferMap[0] = buffer; -} + mResourceManager->checkBufferAllocation(buffer); -void Context::setColorbufferZero(Colorbuffer *buffer) -{ - delete mColorbufferZero; - mColorbufferZero = buffer; + mState.elementArrayBuffer.set(getBuffer(buffer)); } -void Context::setDepthbufferZero(Depthbuffer *buffer) +void Context::bindTexture2D(GLuint texture) { - delete mDepthbufferZero; - mDepthbufferZero = buffer; -} + mResourceManager->checkTextureAllocation(texture, SAMPLER_2D); -void Context::setStencilbufferZero(Stencilbuffer *buffer) -{ - delete mStencilbufferZero; - mStencilbufferZero = buffer; -} + mState.texture2D.set(getTexture(texture)); -void Context::setRenderbuffer(Renderbuffer *buffer) -{ - delete mRenderbufferMap[mState.renderbuffer]; - mRenderbufferMap[mState.renderbuffer] = buffer; + mState.samplerTexture[SAMPLER_2D][mState.activeSampler].set(mState.texture2D.get()); } -Buffer *Context::getBuffer(unsigned int handle) +void Context::bindTextureCubeMap(GLuint texture) { - BufferMap::iterator buffer = mBufferMap.find(handle); + mResourceManager->checkTextureAllocation(texture, SAMPLER_CUBE); - if (buffer == mBufferMap.end()) - { - return NULL; - } - else - { - return buffer->second; - } -} + mState.textureCubeMap.set(getTexture(texture)); -Shader *Context::getShader(unsigned int handle) -{ - ShaderMap::iterator shader = mShaderMap.find(handle); - - if (shader == mShaderMap.end()) - { - return NULL; - } - else - { - return shader->second; - } + mState.samplerTexture[SAMPLER_CUBE][mState.activeSampler].set(mState.textureCubeMap.get()); } -Program *Context::getProgram(unsigned int handle) +void Context::bindReadFramebuffer(GLuint framebuffer) { - ProgramMap::iterator program = mProgramMap.find(handle); - - if (program == mProgramMap.end()) - { - return NULL; - } - else + if (!getFramebuffer(framebuffer)) { - return program->second; + mFramebufferMap[framebuffer] = new Framebuffer(); } -} - -Texture *Context::getTexture(unsigned int handle) -{ - if (handle == 0) return NULL; - - TextureMap::iterator texture = mTextureMap.find(handle); - if (texture == mTextureMap.end()) - { - return NULL; - } - else - { - return texture->second; - } + mState.readFramebuffer = framebuffer; } -Framebuffer *Context::getFramebuffer(unsigned int handle) +void Context::bindDrawFramebuffer(GLuint framebuffer) { - FramebufferMap::iterator framebuffer = mFramebufferMap.find(handle); - - if (framebuffer == mFramebufferMap.end()) - { - return NULL; - } - else + if (!getFramebuffer(framebuffer)) { - return framebuffer->second; + mFramebufferMap[framebuffer] = new Framebuffer(); } + + mState.drawFramebuffer = framebuffer; } -Renderbuffer *Context::getRenderbuffer(unsigned int handle) +void Context::bindRenderbuffer(GLuint renderbuffer) { - RenderbufferMap::iterator renderbuffer = mRenderbufferMap.find(handle); + mResourceManager->checkRenderbufferAllocation(renderbuffer); - if (renderbuffer == mRenderbufferMap.end()) - { - return NULL; - } - else - { - return renderbuffer->second; - } + mState.renderbuffer.set(getRenderbuffer(renderbuffer)); } -Colorbuffer *Context::getColorbuffer(GLuint handle) +void Context::useProgram(GLuint program) { - if (handle != 0) + GLuint priorProgram = mState.currentProgram; + mState.currentProgram = program; // Must switch before trying to delete, otherwise it only gets flagged. + + if (priorProgram != program) { - Renderbuffer *renderbuffer = getRenderbuffer(handle); + Program *newProgram = mResourceManager->getProgram(program); + Program *oldProgram = mResourceManager->getProgram(priorProgram); - if (renderbuffer && renderbuffer->isColorbuffer()) + if (newProgram) { - return static_cast<Colorbuffer*>(renderbuffer); + newProgram->addRef(); + } + + if (oldProgram) + { + oldProgram->release(); } } - else // Special case: 0 refers to different initial render targets based on the attachment type - { - return mColorbufferZero; - } - - return NULL; } -Depthbuffer *Context::getDepthbuffer(GLuint handle) +void Context::setFramebufferZero(Framebuffer *buffer) { - if (handle != 0) - { - Renderbuffer *renderbuffer = getRenderbuffer(handle); - - if (renderbuffer && renderbuffer->isDepthbuffer()) - { - return static_cast<Depthbuffer*>(renderbuffer); - } - } - else // Special case: 0 refers to different initial render targets based on the attachment type - { - return mDepthbufferZero; - } + delete mFramebufferMap[0]; + mFramebufferMap[0] = buffer; +} - return NULL; +void Context::setRenderbufferStorage(RenderbufferStorage *renderbuffer) +{ + Renderbuffer *renderbufferObject = mState.renderbuffer.get(); + renderbufferObject->setStorage(renderbuffer); } -Stencilbuffer *Context::getStencilbuffer(GLuint handle) +Framebuffer *Context::getFramebuffer(unsigned int handle) { - if (handle != 0) - { - Renderbuffer *renderbuffer = getRenderbuffer(handle); + FramebufferMap::iterator framebuffer = mFramebufferMap.find(handle); - if (renderbuffer && renderbuffer->isStencilbuffer()) - { - return static_cast<Stencilbuffer*>(renderbuffer); - } + if (framebuffer == mFramebufferMap.end()) + { + return NULL; } else { - return mStencilbufferZero; + return framebuffer->second; } - - return NULL; } Buffer *Context::getArrayBuffer() { - return getBuffer(mState.arrayBuffer); + return mState.arrayBuffer.get(); } Buffer *Context::getElementArrayBuffer() { - return getBuffer(mState.elementArrayBuffer); + return mState.elementArrayBuffer.get(); } Program *Context::getCurrentProgram() { - return getProgram(mState.currentProgram); + return mResourceManager->getProgram(mState.currentProgram); } Texture2D *Context::getTexture2D() { - if (mState.texture2D == 0) // Special case: 0 refers to different initial textures based on the target + if (mState.texture2D.id() == 0) // Special case: 0 refers to different initial textures based on the target { return mTexture2DZero; } - return (Texture2D*)getTexture(mState.texture2D); + return static_cast<Texture2D*>(mState.texture2D.get()); } TextureCubeMap *Context::getTextureCubeMap() { - if (mState.textureCubeMap == 0) // Special case: 0 refers to different initial textures based on the target + if (mState.textureCubeMap.id() == 0) // Special case: 0 refers to different initial textures based on the target { return mTextureCubeMapZero; } - return (TextureCubeMap*)getTexture(mState.textureCubeMap); + return static_cast<TextureCubeMap*>(mState.textureCubeMap.get()); } Texture *Context::getSamplerTexture(unsigned int sampler, SamplerType type) { - GLuint texid = mState.samplerTexture[type][sampler]; + GLuint texid = mState.samplerTexture[type][sampler].id(); if (texid == 0) { @@ -1227,12 +1054,7 @@ Texture *Context::getSamplerTexture(unsigned int sampler, SamplerType type) } } - return getTexture(texid); -} - -Framebuffer *Context::getFramebuffer() -{ - return getFramebuffer(mState.framebuffer); + return mState.samplerTexture[type][sampler].get(); } bool Context::getBooleanv(GLenum pname, GLboolean *params) @@ -1283,7 +1105,7 @@ bool Context::getFloatv(GLenum pname, GLfloat *params) break; case GL_ALIASED_POINT_SIZE_RANGE: params[0] = gl::ALIASED_POINT_SIZE_RANGE_MIN; - params[1] = gl::ALIASED_POINT_SIZE_RANGE_MAX; + params[1] = supportsShaderModel3() ? gl::ALIASED_POINT_SIZE_RANGE_MAX_SM3 : gl::ALIASED_POINT_SIZE_RANGE_MAX_SM2; break; case GL_DEPTH_RANGE: params[0] = mState.zNear; @@ -1326,13 +1148,13 @@ bool Context::getIntegerv(GLenum pname, GLint *params) case GL_MAX_FRAGMENT_UNIFORM_VECTORS: *params = gl::MAX_FRAGMENT_UNIFORM_VECTORS; break; case GL_MAX_RENDERBUFFER_SIZE: *params = gl::MAX_RENDERBUFFER_SIZE; break; case GL_NUM_SHADER_BINARY_FORMATS: *params = 0; break; - case GL_NUM_COMPRESSED_TEXTURE_FORMATS: *params = 0; break; - case GL_COMPRESSED_TEXTURE_FORMATS: /* no compressed texture formats are supported */ break; case GL_SHADER_BINARY_FORMATS: /* no shader binary formats are supported */ break; - case GL_ARRAY_BUFFER_BINDING: *params = mState.arrayBuffer; break; - case GL_ELEMENT_ARRAY_BUFFER_BINDING: *params = mState.elementArrayBuffer; break; - case GL_FRAMEBUFFER_BINDING: *params = mState.framebuffer; break; - case GL_RENDERBUFFER_BINDING: *params = mState.renderbuffer; break; + case GL_ARRAY_BUFFER_BINDING: *params = mState.arrayBuffer.id(); break; + case GL_ELEMENT_ARRAY_BUFFER_BINDING: *params = mState.elementArrayBuffer.id(); break; + //case GL_FRAMEBUFFER_BINDING: // now equivalent to GL_DRAW_FRAMEBUFFER_BINDING_ANGLE + case GL_DRAW_FRAMEBUFFER_BINDING_ANGLE: *params = mState.drawFramebuffer; break; + case GL_READ_FRAMEBUFFER_BINDING_ANGLE: *params = mState.readFramebuffer; break; + case GL_RENDERBUFFER_BINDING: *params = mState.renderbuffer.id(); break; case GL_CURRENT_PROGRAM: *params = mState.currentProgram; break; case GL_PACK_ALIGNMENT: *params = mState.packAlignment; break; case GL_UNPACK_ALIGNMENT: *params = mState.unpackAlignment; break; @@ -1363,8 +1185,63 @@ bool Context::getIntegerv(GLenum pname, GLint *params) case GL_SUBPIXEL_BITS: *params = 4; break; case GL_MAX_TEXTURE_SIZE: *params = gl::MAX_TEXTURE_SIZE; break; case GL_MAX_CUBE_MAP_TEXTURE_SIZE: *params = gl::MAX_CUBE_MAP_TEXTURE_SIZE; break; - case GL_SAMPLE_BUFFERS: *params = 0; break; - case GL_SAMPLES: *params = 0; 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; + } + } + break; + case GL_MAX_SAMPLES_ANGLE: + { + GLsizei maxSamples = getMaxSupportedSamples(); + if (maxSamples != 0) + { + *params = maxSamples; + } + else + { + return false; + } + + break; + } + case GL_SAMPLE_BUFFERS: + case GL_SAMPLES: + { + gl::Framebuffer *framebuffer = getDrawFramebuffer(); + if (framebuffer->completeness() == GL_FRAMEBUFFER_COMPLETE) + { + switch (pname) + { + case GL_SAMPLE_BUFFERS: + if (framebuffer->getSamples() != 0) + { + *params = 1; + } + else + { + *params = 0; + } + break; + case GL_SAMPLES: + *params = framebuffer->getSamples(); + break; + } + } + else + { + *params = 0; + } + } + break; case GL_IMPLEMENTATION_COLOR_READ_TYPE: *params = gl::IMPLEMENTATION_COLOR_READ_TYPE; break; case GL_IMPLEMENTATION_COLOR_READ_FORMAT: *params = gl::IMPLEMENTATION_COLOR_READ_FORMAT; break; case GL_MAX_VIEWPORT_DIMS: @@ -1374,6 +1251,15 @@ bool Context::getIntegerv(GLenum pname, GLint *params) params[1] = maxDimension; } break; + case GL_COMPRESSED_TEXTURE_FORMATS: + { + if (supportsCompressedTextures()) + { + params[0] = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; + params[1] = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; + } + } + break; case GL_VIEWPORT: params[0] = mState.viewportX; params[1] = mState.viewportY; @@ -1393,7 +1279,7 @@ bool Context::getIntegerv(GLenum pname, GLint *params) case GL_BLUE_BITS: case GL_ALPHA_BITS: { - gl::Framebuffer *framebuffer = getFramebuffer(); + gl::Framebuffer *framebuffer = getDrawFramebuffer(); gl::Colorbuffer *colorbuffer = framebuffer->getColorbuffer(); if (colorbuffer) @@ -1414,8 +1300,8 @@ bool Context::getIntegerv(GLenum pname, GLint *params) break; case GL_DEPTH_BITS: { - gl::Framebuffer *framebuffer = getFramebuffer(); - gl::Depthbuffer *depthbuffer = framebuffer->getDepthbuffer(); + gl::Framebuffer *framebuffer = getDrawFramebuffer(); + gl::DepthStencilbuffer *depthbuffer = framebuffer->getDepthbuffer(); if (depthbuffer) { @@ -1429,8 +1315,8 @@ bool Context::getIntegerv(GLenum pname, GLint *params) break; case GL_STENCIL_BITS: { - gl::Framebuffer *framebuffer = getFramebuffer(); - gl::Stencilbuffer *stencilbuffer = framebuffer->getStencilbuffer(); + gl::Framebuffer *framebuffer = getDrawFramebuffer(); + gl::DepthStencilbuffer *stencilbuffer = framebuffer->getStencilbuffer(); if (stencilbuffer) { @@ -1450,7 +1336,7 @@ bool Context::getIntegerv(GLenum pname, GLint *params) return false; } - *params = mState.samplerTexture[SAMPLER_2D][mState.activeSampler]; + *params = mState.samplerTexture[SAMPLER_2D][mState.activeSampler].id(); } break; case GL_TEXTURE_BINDING_CUBE_MAP: @@ -1461,7 +1347,7 @@ bool Context::getIntegerv(GLenum pname, GLint *params) return false; } - *params = mState.samplerTexture[SAMPLER_CUBE][mState.activeSampler]; + *params = mState.samplerTexture[SAMPLER_CUBE][mState.activeSampler].id(); } break; default: @@ -1552,6 +1438,19 @@ bool Context::getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *nu *numParams = 1; } break; + case GL_MAX_SAMPLES_ANGLE: + { + if (getMaxSupportedSamples() != 0) + { + *type = GL_INT; + *numParams = 1; + } + else + { + return false; + } + } + break; case GL_MAX_VIEWPORT_DIMS: { *type = GL_INT; @@ -1626,7 +1525,7 @@ bool Context::applyRenderTarget(bool ignoreViewport) { IDirect3DDevice9 *device = getDevice(); - Framebuffer *framebufferObject = getFramebuffer(); + Framebuffer *framebufferObject = getDrawFramebuffer(); if (!framebufferObject || framebufferObject->completeness() != GL_FRAMEBUFFER_COMPLETE) { @@ -1636,20 +1535,35 @@ bool Context::applyRenderTarget(bool ignoreViewport) } IDirect3DSurface9 *renderTarget = framebufferObject->getRenderTarget(); - IDirect3DSurface9 *depthStencil = framebufferObject->getDepthStencil(); + IDirect3DSurface9 *depthStencil = NULL; unsigned int renderTargetSerial = framebufferObject->getRenderTargetSerial(); if (renderTargetSerial != mAppliedRenderTargetSerial) { device->SetRenderTarget(0, renderTarget); mAppliedRenderTargetSerial = renderTargetSerial; + mScissorStateDirty = true; // Scissor area must be clamped to render target's size-- this is different for different render targets. } - unsigned int depthbufferSerial = framebufferObject->getDepthbufferSerial(); - if (depthbufferSerial != mAppliedDepthbufferSerial) + unsigned int depthbufferSerial = 0; + unsigned int stencilbufferSerial = 0; + if (framebufferObject->getDepthbufferType() != GL_NONE) + { + depthStencil = framebufferObject->getDepthbuffer()->getDepthStencil(); + depthbufferSerial = framebufferObject->getDepthbuffer()->getSerial(); + } + else if (framebufferObject->getStencilbufferType() != GL_NONE) + { + depthStencil = framebufferObject->getStencilbuffer()->getDepthStencil(); + stencilbufferSerial = framebufferObject->getStencilbuffer()->getSerial(); + } + + if (depthbufferSerial != mAppliedDepthbufferSerial || + stencilbufferSerial != mAppliedStencilbufferSerial) { device->SetDepthStencilSurface(depthStencil); mAppliedDepthbufferSerial = depthbufferSerial; + mAppliedStencilbufferSerial = stencilbufferSerial; } D3DVIEWPORT9 viewport; @@ -1690,7 +1604,8 @@ bool Context::applyRenderTarget(bool ignoreViewport) 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); } @@ -1698,7 +1613,7 @@ bool Context::applyRenderTarget(bool ignoreViewport) { device->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE); } - + mScissorStateDirty = false; } @@ -1710,7 +1625,7 @@ bool Context::applyRenderTarget(bool ignoreViewport) GLfloat xy[2] = {1.0f / viewport.Width, 1.0f / viewport.Height}; programObject->setUniform2fv(halfPixelSize, 1, (GLfloat*)&xy); - GLint window = programObject->getDxWindowLocation(); + GLint window = programObject->getDxViewportLocation(); GLfloat whxy[4] = {mState.viewportWidth / 2.0f, mState.viewportHeight / 2.0f, (float)mState.viewportX + mState.viewportWidth / 2.0f, (float)mState.viewportY + mState.viewportHeight / 2.0f}; @@ -1748,6 +1663,8 @@ void Context::applyState(GLenum drawMode) GLint alwaysFront = !isTriangleMode(drawMode); programObject->setUniform1iv(pointsOrLines, 1, &alwaysFront); + Framebuffer *framebufferObject = getDrawFramebuffer(); + if (mCullStateDirty || mFrontFaceDirty) { if (mState.cullFace) @@ -1764,7 +1681,7 @@ void Context::applyState(GLenum drawMode) if (mDepthStateDirty) { - if (mState.depthTest) + if (mState.depthTest && framebufferObject->getDepthbufferType() != GL_NONE) { device->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE); device->SetRenderState(D3DRS_ZFUNC, es2dx::ConvertComparison(mState.depthFunc)); @@ -1826,7 +1743,7 @@ void Context::applyState(GLenum drawMode) if (mStencilStateDirty || mFrontFaceDirty) { - if (mState.stencilTest && hasStencil()) + if (mState.stencilTest && framebufferObject->hasStencil()) { device->SetRenderState(D3DRS_STENCILENABLE, TRUE); device->SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, TRUE); @@ -1844,8 +1761,7 @@ void Context::applyState(GLenum drawMode) } // get the maximum size of the stencil ref - gl::Framebuffer *framebuffer = getFramebuffer(); - gl::Stencilbuffer *stencilbuffer = framebuffer->getStencilbuffer(); + gl::DepthStencilbuffer *stencilbuffer = framebufferObject->getStencilbuffer(); GLuint maxStencil = (1 << stencilbuffer->getStencilSize()) - 1; device->SetRenderState(mState.frontFace == GL_CCW ? D3DRS_STENCILWRITEMASK : D3DRS_CCW_STENCILWRITEMASK, mState.stencilWritemask); @@ -1897,7 +1813,7 @@ void Context::applyState(GLenum drawMode) { if (mState.polygonOffsetFill) { - gl::Depthbuffer *depthbuffer = getFramebuffer()->getDepthbuffer(); + gl::DepthStencilbuffer *depthbuffer = framebufferObject->getDepthbuffer(); if (depthbuffer) { device->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, *((DWORD*)&mState.polygonOffsetFactor)); @@ -1914,7 +1830,7 @@ void Context::applyState(GLenum drawMode) mPolygonOffsetStateDirty = false; } - if (mConfig->mMultiSample != 0 && mSampleStateDirty) + if (framebufferObject->isMultisample() && mSampleStateDirty) { if (mState.sampleAlphaToCoverage) { @@ -1923,7 +1839,34 @@ void Context::applyState(GLenum drawMode) if (mState.sampleCoverage) { - FIXME("Sample coverage is unimplemented."); + device->SetRenderState(D3DRS_MULTISAMPLEANTIALIAS, TRUE); + unsigned int mask = 0; + if (mState.sampleCoverageValue != 0) + { + float threshold = 0.5f; + + for (int i = 0; i < framebufferObject->getSamples(); ++i) + { + mask <<= 1; + + if ((i + 1) * mState.sampleCoverageValue >= threshold) + { + threshold += 1.0f; + mask |= 1; + } + } + } + + if (mState.sampleCoverageInvert) + { + mask = ~mask; + } + + device->SetRenderState(D3DRS_MULTISAMPLEMASK, mask); + } + else + { + device->SetRenderState(D3DRS_MULTISAMPLEANTIALIAS, FALSE); } mSampleStateDirty = false; @@ -2005,7 +1948,7 @@ GLenum Context::applyVertexBuffer(const TranslatedIndexData &indexInfo) // 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 err = mIndexDataManager->preRenderValidate(mode, type, count, getBuffer(mState.elementArrayBuffer), indices, indexInfo); + GLenum err = mIndexDataManager->preRenderValidate(mode, type, count, mState.elementArrayBuffer.get(), indices, indexInfo); if (err == GL_NO_ERROR) { @@ -2092,7 +2035,18 @@ void Context::applyTextures() void Context::readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels) { - Framebuffer *framebuffer = getFramebuffer(); + Framebuffer *framebuffer = getReadFramebuffer(); + + if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE) + { + return error(GL_INVALID_FRAMEBUFFER_OPERATION); + } + + if (getReadFramebufferHandle() != 0 && framebuffer->getSamples() != 0) + { + return error(GL_INVALID_OPERATION); + } + IDirect3DSurface9 *renderTarget = framebuffer->getRenderTarget(); IDirect3DDevice9 *device = getDevice(); @@ -2155,6 +2109,19 @@ void Context::readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum for (int j = 0; j < rect.bottom - rect.top; j++) { + if (desc.Format == D3DFMT_A8R8G8B8 && + format == GL_BGRA_EXT && + type == GL_UNSIGNED_BYTE) + { + // Fast path for EXT_read_format_bgra, given + // an RGBA source buffer. Note that buffers with no + // alpha go through the slow path below. + memcpy(dest + j * outputPitch, + source + j * lock.Pitch, + (rect.right - rect.left) * 4); + continue; + } + for (int i = 0; i < rect.right - rect.left; i++) { float r; @@ -2243,6 +2210,46 @@ void Context::readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum default: UNREACHABLE(); } break; + case GL_BGRA_EXT: + switch (type) + { + case GL_UNSIGNED_BYTE: + dest[4 * i + j * outputPitch + 0] = (unsigned char)(255 * b + 0.5f); + dest[4 * i + j * outputPitch + 1] = (unsigned char)(255 * g + 0.5f); + dest[4 * i + j * outputPitch + 2] = (unsigned char)(255 * r + 0.5f); + dest[4 * i + j * outputPitch + 3] = (unsigned char)(255 * a + 0.5f); + break; + case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT: + // According to the desktop GL spec in the "Transfer of Pixel Rectangles" section + // this type is packed as follows: + // 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 + // -------------------------------------------------------------------------------- + // | 4th | 3rd | 2nd | 1st component | + // -------------------------------------------------------------------------------- + // in the case of BGRA_EXT, B is the first component, G the second, and so forth. + dest16[i + j * outputPitch / sizeof(unsigned short)] = + ((unsigned short)(15 * a + 0.5f) << 12)| + ((unsigned short)(15 * r + 0.5f) << 8) | + ((unsigned short)(15 * g + 0.5f) << 4) | + ((unsigned short)(15 * b + 0.5f) << 0); + break; + case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT: + // According to the desktop GL spec in the "Transfer of Pixel Rectangles" section + // this type is packed as follows: + // 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 + // -------------------------------------------------------------------------------- + // | 4th | 3rd | 2nd | 1st component | + // -------------------------------------------------------------------------------- + // in the case of BGRA_EXT, B is the first component, G the second, and so forth. + dest16[i + j * outputPitch / sizeof(unsigned short)] = + ((unsigned short)( a + 0.5f) << 15) | + ((unsigned short)(31 * r + 0.5f) << 10) | + ((unsigned short)(31 * g + 0.5f) << 5) | + ((unsigned short)(31 * b + 0.5f) << 0); + break; + default: UNREACHABLE(); + } + break; case GL_RGB: // IMPLEMENTATION_COLOR_READ_FORMAT switch (type) { @@ -2267,7 +2274,7 @@ void Context::readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum void Context::clear(GLbitfield mask) { - Framebuffer *framebufferObject = getFramebuffer(); + Framebuffer *framebufferObject = getDrawFramebuffer(); if (!framebufferObject || framebufferObject->completeness() != GL_FRAMEBUFFER_COMPLETE) { @@ -2299,22 +2306,24 @@ void Context::clear(GLbitfield mask) } } - IDirect3DSurface9 *depthStencil = framebufferObject->getDepthStencil(); - GLuint stencilUnmasked = 0x0; - if ((mask & GL_STENCIL_BUFFER_BIT) && depthStencil) + if (mask & GL_STENCIL_BUFFER_BIT) { - D3DSURFACE_DESC desc; - depthStencil->GetDesc(&desc); - mask &= ~GL_STENCIL_BUFFER_BIT; - unsigned int stencilSize = es2dx::GetStencilSize(desc.Format); - stencilUnmasked = (0x1 << stencilSize) - 1; - - if (stencilUnmasked != 0x0) + if (framebufferObject->getStencilbufferType() != GL_NONE) { - flags |= D3DCLEAR_STENCIL; + IDirect3DSurface9 *depthStencil = framebufferObject->getStencilbuffer()->getDepthStencil(); + D3DSURFACE_DESC desc; + depthStencil->GetDesc(&desc); + + unsigned int stencilSize = es2dx::GetStencilSize(desc.Format); + stencilUnmasked = (0x1 << stencilSize) - 1; + + if (stencilUnmasked != 0x0) + { + flags |= D3DCLEAR_STENCIL; + } } } @@ -2618,7 +2627,8 @@ void Context::finish() IDirect3DStateBlock9 *savedState = NULL; device->CreateStateBlock(D3DSBT_ALL, &savedState); - occlusionQuery->Issue(D3DISSUE_BEGIN); + HRESULT result = occlusionQuery->Issue(D3DISSUE_BEGIN); + ASSERT(SUCCEEDED(result)); // Render something outside the render target device->SetStreamSourceFreq(0, 1); @@ -2629,7 +2639,8 @@ void Context::finish() display->startScene(); device->DrawPrimitiveUP(D3DPT_POINTLIST, 1, data, sizeof(data)); - occlusionQuery->Issue(D3DISSUE_END); + result = occlusionQuery->Issue(D3DISSUE_END); + ASSERT(SUCCEEDED(result)); while (occlusionQuery->GetData(NULL, 0, D3DGETDATA_FLUSH) == S_FALSE) { @@ -2663,15 +2674,16 @@ void Context::flush() if (eventQuery) { - eventQuery->Issue(D3DISSUE_END); + HRESULT result = eventQuery->Issue(D3DISSUE_END); + ASSERT(SUCCEEDED(result)); - while (eventQuery->GetData(NULL, 0, D3DGETDATA_FLUSH) == S_FALSE) + result = eventQuery->GetData(NULL, 0, D3DGETDATA_FLUSH); + eventQuery->Release(); + + if (result == D3DERR_DEVICELOST) { - // Keep polling, but allow other threads to do something useful first - Sleep(0); + error(GL_OUT_OF_MEMORY); } - - eventQuery->Release(); } } @@ -2742,14 +2754,43 @@ GLenum Context::getError() return GL_NO_ERROR; } -const char *Context::getPixelShaderProfile() +bool Context::supportsShaderModel3() const { - return mPsProfile; + return mSupportsShaderModel3; } -const char *Context::getVertexShaderProfile() +int Context::getMaxSupportedSamples() const { - return mVsProfile; + return mMaxSupportedSamples; +} + +int Context::getNearestSupportedSamples(D3DFORMAT format, int requested) const +{ + if (requested == 0) + { + return requested; + } + + std::map<D3DFORMAT, bool *>::const_iterator itr = mMultiSampleSupport.find(format); + if (itr == mMultiSampleSupport.end()) + { + return -1; + } + + for (int i = requested; i <= D3DMULTISAMPLE_16_SAMPLES; ++i) + { + if (itr->second[i] && i != D3DMULTISAMPLE_NONMASKABLE) + { + return i; + } + } + + return -1; +} + +bool Context::supportsCompressedTextures() const +{ + return mSupportsCompressedTextures; } void Context::detachBuffer(GLuint buffer) @@ -2758,21 +2799,21 @@ void Context::detachBuffer(GLuint buffer) // If a buffer object is deleted while it is bound, all bindings to that object in the current context // (i.e. in the thread that called Delete-Buffers) are reset to zero. - if (mState.arrayBuffer == buffer) + if (mState.arrayBuffer.id() == buffer) { - mState.arrayBuffer = 0; + mState.arrayBuffer.set(NULL); } - if (mState.elementArrayBuffer == buffer) + if (mState.elementArrayBuffer.id() == buffer) { - mState.elementArrayBuffer = 0; + mState.elementArrayBuffer.set(NULL); } for (int attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++) { - if (mState.vertexAttribute[attribute].mBoundBuffer == buffer) + if (mState.vertexAttribute[attribute].mBoundBuffer.id() == buffer) { - mState.vertexAttribute[attribute].mBoundBuffer = 0; + mState.vertexAttribute[attribute].mBoundBuffer.set(NULL); } } } @@ -2787,9 +2828,9 @@ void Context::detachTexture(GLuint texture) { for (int sampler = 0; sampler < MAX_TEXTURE_IMAGE_UNITS; sampler++) { - if (mState.samplerTexture[type][sampler] == texture) + if (mState.samplerTexture[type][sampler].id() == texture) { - mState.samplerTexture[type][sampler] = 0; + mState.samplerTexture[type][sampler].set(NULL); } } } @@ -2799,11 +2840,17 @@ void Context::detachTexture(GLuint texture) // as if FramebufferTexture2D had been called, with a texture of 0, for each attachment point to which this // image was attached in the currently bound framebuffer. - Framebuffer *framebuffer = getFramebuffer(); + Framebuffer *readFramebuffer = getReadFramebuffer(); + Framebuffer *drawFramebuffer = getDrawFramebuffer(); - if (framebuffer) + if (readFramebuffer) { - framebuffer->detachTexture(texture); + readFramebuffer->detachTexture(texture); + } + + if (drawFramebuffer && drawFramebuffer != readFramebuffer) + { + drawFramebuffer->detachTexture(texture); } } @@ -2813,9 +2860,14 @@ void Context::detachFramebuffer(GLuint framebuffer) // If a framebuffer that is currently bound to the target FRAMEBUFFER is deleted, it is as though // BindFramebuffer had been executed with the target of FRAMEBUFFER and framebuffer of zero. - if (mState.framebuffer == framebuffer) + if (mState.readFramebuffer == framebuffer) + { + bindReadFramebuffer(0); + } + + if (mState.drawFramebuffer == framebuffer) { - bindFramebuffer(0); + bindDrawFramebuffer(0); } } @@ -2825,7 +2877,7 @@ void Context::detachRenderbuffer(GLuint renderbuffer) // If a renderbuffer that is currently bound to RENDERBUFFER is deleted, it is as though BindRenderbuffer // had been executed with the target RENDERBUFFER and name of zero. - if (mState.renderbuffer == renderbuffer) + if (mState.renderbuffer.id() == renderbuffer) { bindRenderbuffer(0); } @@ -2835,11 +2887,17 @@ void Context::detachRenderbuffer(GLuint renderbuffer) // then it is as if FramebufferRenderbuffer had been called, with a renderbuffer of 0, for each attachment // point to which this image was attached in the currently bound framebuffer. - Framebuffer *framebuffer = getFramebuffer(); + Framebuffer *readFramebuffer = getReadFramebuffer(); + Framebuffer *drawFramebuffer = getDrawFramebuffer(); + + if (readFramebuffer) + { + readFramebuffer->detachRenderbuffer(renderbuffer); + } - if (framebuffer) + if (drawFramebuffer && drawFramebuffer != readFramebuffer) { - framebuffer->detachRenderbuffer(renderbuffer); + drawFramebuffer->detachRenderbuffer(renderbuffer); } } @@ -2859,7 +2917,7 @@ Texture *Context::getIncompleteTexture(SamplerType type) case SAMPLER_2D: { - Texture2D *incomplete2d = new Texture2D(this); + Texture2D *incomplete2d = new Texture2D(Texture::INCOMPLETE_TEXTURE_ID); incomplete2d->setImage(0, GL_RGBA, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color); t = incomplete2d; } @@ -2867,7 +2925,7 @@ Texture *Context::getIncompleteTexture(SamplerType type) case SAMPLER_CUBE: { - TextureCubeMap *incompleteCube = new TextureCubeMap(this); + 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); @@ -2911,23 +2969,6 @@ bool Context::isTriangleMode(GLenum drawMode) return false; } -bool Context::hasStencil() -{ - Framebuffer *framebufferObject = getFramebuffer(); - - if (framebufferObject) - { - Stencilbuffer *stencilbufferObject = framebufferObject->getStencilbuffer(); - - if (stencilbufferObject) - { - return stencilbufferObject->getStencilSize() > 0; - } - } - - return false; -} - void Context::setVertexAttrib(GLuint index, const GLfloat *values) { ASSERT(index < gl::MAX_VERTEX_ATTRIBS); @@ -2942,6 +2983,22 @@ void Context::setVertexAttrib(GLuint index, const GLfloat *values) void Context::initExtensionString() { + 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 "; + + if (supportsCompressedTextures()) + { + mExtensionString += "GL_EXT_texture_compression_dxt1 "; + } + + if (getMaxSupportedSamples() != 0) + { + mExtensionString += "GL_ANGLE_framebuffer_multisample "; + } + if (mBufferBackEnd->supportIntIndices()) { mExtensionString += "GL_OES_element_index_uint "; @@ -2959,13 +3016,285 @@ const char *Context::getExtensionString() const return mExtensionString.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(); + + if (!readFramebuffer || readFramebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE || + !drawFramebuffer || drawFramebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE) + { + return error(GL_INVALID_FRAMEBUFFER_OPERATION); + } + + if (drawFramebuffer->getSamples() != 0) + { + return error(GL_INVALID_OPERATION); + } + + RECT sourceRect; + RECT destRect; + + if (srcX0 < srcX1) + { + sourceRect.left = srcX0; + sourceRect.right = srcX1; + destRect.left = dstX0; + destRect.right = dstX1; + } + else + { + sourceRect.left = srcX1; + destRect.left = dstX1; + sourceRect.right = srcX0; + 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; + } + else + { + sourceRect.bottom = srcY0; + destRect.bottom = dstY0; + sourceRect.top = srcY1; + destRect.top = dstY1; + } + + RECT sourceScissoredRect = sourceRect; + RECT destScissoredRect = destRect; + + if (mState.scissorTest) + { + // Only write to parts of the destination framebuffer which pass the scissor test + // Please note: the destRect is now in D3D-style coordinates, so the *top* of the + // rect will be checked against scissorY, rather than the bottom. + if (destRect.left < mState.scissorX) + { + int xDiff = mState.scissorX - destRect.left; + destScissoredRect.left = mState.scissorX; + sourceScissoredRect.left += xDiff; + } + + if (destRect.right > mState.scissorX + mState.scissorWidth) + { + int xDiff = destRect.right - (mState.scissorX + mState.scissorWidth); + destScissoredRect.right = mState.scissorX + mState.scissorWidth; + sourceScissoredRect.right -= xDiff; + } + + if (destRect.top < mState.scissorY) + { + int yDiff = mState.scissorY - destRect.top; + destScissoredRect.top = mState.scissorY; + sourceScissoredRect.top += yDiff; + } + + if (destRect.bottom > mState.scissorY + mState.scissorHeight) + { + int yDiff = destRect.bottom - (mState.scissorY + mState.scissorHeight); + destScissoredRect.bottom = mState.scissorY + mState.scissorHeight; + sourceScissoredRect.bottom -= yDiff; + } + } + + bool blitRenderTarget = false; + bool blitDepthStencil = false; + + RECT sourceTrimmedRect = sourceScissoredRect; + RECT destTrimmedRect = destScissoredRect; + + // The source & destination rectangles also may need to be trimmed if they fall out of the bounds of + // the actual draw and read surfaces. + if (sourceTrimmedRect.left < 0) + { + int xDiff = 0 - sourceTrimmedRect.left; + sourceTrimmedRect.left = 0; + 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; + sourceTrimmedRect.right = readBufferWidth; + destTrimmedRect.right -= xDiff; + } + + if (sourceTrimmedRect.top < 0) + { + int yDiff = 0 - sourceTrimmedRect.top; + sourceTrimmedRect.top = 0; + destTrimmedRect.top += yDiff; + } + + if (sourceTrimmedRect.bottom > readBufferHeight) + { + int yDiff = sourceTrimmedRect.bottom - readBufferHeight; + sourceTrimmedRect.bottom = readBufferHeight; + destTrimmedRect.bottom -= yDiff; + } + + if (destTrimmedRect.left < 0) + { + int xDiff = 0 - destTrimmedRect.left; + destTrimmedRect.left = 0; + sourceTrimmedRect.left += xDiff; + } + + if (destTrimmedRect.right > drawBufferWidth) + { + int xDiff = destTrimmedRect.right - drawBufferWidth; + destTrimmedRect.right = drawBufferWidth; + sourceTrimmedRect.right -= xDiff; + } + + if (destTrimmedRect.top < 0) + { + int yDiff = 0 - destTrimmedRect.top; + destTrimmedRect.top = 0; + sourceTrimmedRect.top += yDiff; + } + + if (destTrimmedRect.bottom > drawBufferHeight) + { + int yDiff = destTrimmedRect.bottom - drawBufferHeight; + destTrimmedRect.bottom = drawBufferHeight; + sourceTrimmedRect.bottom -= yDiff; + } + + bool partialBufferCopy = false; + if (sourceTrimmedRect.bottom - sourceTrimmedRect.top < readFramebuffer->getColorbuffer()->getHeight() || + sourceTrimmedRect.right - sourceTrimmedRect.left < readFramebuffer->getColorbuffer()->getWidth() || + destTrimmedRect.bottom - destTrimmedRect.top < drawFramebuffer->getColorbuffer()->getHeight() || + destTrimmedRect.right - destTrimmedRect.left < drawFramebuffer->getColorbuffer()->getWidth() || + sourceTrimmedRect.top != 0 || destTrimmedRect.top != 0 || sourceTrimmedRect.left != 0 || destTrimmedRect.left != 0) + { + partialBufferCopy = true; + } + + if (mask & GL_COLOR_BUFFER_BIT) + { + if (readFramebuffer->getColorbufferType() != drawFramebuffer->getColorbufferType() || + readFramebuffer->getColorbuffer()->getD3DFormat() != drawFramebuffer->getColorbuffer()->getD3DFormat()) + { + ERR("Color buffer format conversion in BlitFramebufferANGLE not supported by this implementation"); + return error(GL_INVALID_OPERATION); + } + + if (partialBufferCopy && readFramebuffer->getSamples() != 0) + { + return error(GL_INVALID_OPERATION); + } + + blitRenderTarget = true; + + } + + if (mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) + { + DepthStencilbuffer *readDSBuffer = NULL; + DepthStencilbuffer *drawDSBuffer = NULL; + + // We support OES_packed_depth_stencil, and do not support a separately attached depth and stencil buffer, so if we have + // both a depth and stencil buffer, it will be the same buffer. + + if (mask & GL_DEPTH_BUFFER_BIT) + { + if (readFramebuffer->getDepthbuffer() && drawFramebuffer->getDepthbuffer()) + { + if (readFramebuffer->getDepthbufferType() != drawFramebuffer->getDepthbufferType() || + readFramebuffer->getDepthbuffer()->getD3DFormat() != drawFramebuffer->getDepthbuffer()->getD3DFormat()) + { + return error(GL_INVALID_OPERATION); + } + + blitDepthStencil = true; + readDSBuffer = readFramebuffer->getDepthbuffer(); + drawDSBuffer = drawFramebuffer->getDepthbuffer(); + } + } + + if (mask & GL_STENCIL_BUFFER_BIT) + { + if (readFramebuffer->getStencilbuffer() && drawFramebuffer->getStencilbuffer()) + { + if (readFramebuffer->getStencilbufferType() != drawFramebuffer->getStencilbufferType() || + readFramebuffer->getStencilbuffer()->getD3DFormat() != drawFramebuffer->getStencilbuffer()->getD3DFormat()) + { + return error(GL_INVALID_OPERATION); + } + + blitDepthStencil = true; + readDSBuffer = readFramebuffer->getStencilbuffer(); + drawDSBuffer = drawFramebuffer->getStencilbuffer(); + } + } + + if (partialBufferCopy) + { + ERR("Only whole-buffer depth and stencil blits are supported by this implementation."); + return error(GL_INVALID_OPERATION); // only whole-buffer copies are permitted + } + + if ((drawDSBuffer && drawDSBuffer->getSamples() != 0) || + (readDSBuffer && readDSBuffer->getSamples() != 0)) + { + return error(GL_INVALID_OPERATION); + } + } + + if (blitRenderTarget || blitDepthStencil) + { + egl::Display *display = getDisplay(); + display->endScene(); + + if (blitRenderTarget) + { + HRESULT result = device->StretchRect(readFramebuffer->getRenderTarget(), &sourceTrimmedRect, + drawFramebuffer->getRenderTarget(), &destTrimmedRect, D3DTEXF_NONE); + + if (FAILED(result)) + { + ERR("BlitFramebufferANGLE failed: StretchRect returned %x.", result); + return; + } + } + + if (blitDepthStencil) + { + HRESULT result = device->StretchRect(readFramebuffer->getDepthStencil(), NULL, drawFramebuffer->getDepthStencil(), NULL, D3DTEXF_NONE); + + if (FAILED(result)) + { + ERR("BlitFramebufferANGLE failed: StretchRect returned %x.", result); + return; + } + } + } +} + } extern "C" { -gl::Context *glCreateContext(const egl::Config *config) +gl::Context *glCreateContext(const egl::Config *config, const gl::Context *shareContext) { - return new gl::Context(config); + return new gl::Context(config, shareContext); } void glDestroyContext(gl::Context *context) |