diff options
Diffstat (limited to 'Source/ThirdParty/ANGLE/src/libGLESv2')
39 files changed, 9161 insertions, 3962 deletions
diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/Blit.cpp b/Source/ThirdParty/ANGLE/src/libGLESv2/Blit.cpp index 43ed8a0..a248d69 100644 --- a/Source/ThirdParty/ANGLE/src/libGLESv2/Blit.cpp +++ b/Source/ThirdParty/ANGLE/src/libGLESv2/Blit.cpp @@ -155,16 +155,23 @@ void Blit::initGeometry() IDirect3DDevice9 *device = getDevice(); - HRESULT hr = device->CreateVertexBuffer(sizeof(quad), D3DUSAGE_WRITEONLY, 0, D3DPOOL_DEFAULT, &mQuadVertexBuffer, NULL); + HRESULT result = device->CreateVertexBuffer(sizeof(quad), D3DUSAGE_WRITEONLY, 0, D3DPOOL_DEFAULT, &mQuadVertexBuffer, NULL); - if (FAILED(hr)) + if (FAILED(result)) { - ASSERT(hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY); + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + return error(GL_OUT_OF_MEMORY); + } + + void *lockPtr = NULL; + result = mQuadVertexBuffer->Lock(0, 0, &lockPtr, 0); + + if (FAILED(result) || lockPtr == NULL) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); return error(GL_OUT_OF_MEMORY); } - void *lockPtr; - mQuadVertexBuffer->Lock(0, 0, &lockPtr, 0); memcpy(lockPtr, quad, sizeof(quad)); mQuadVertexBuffer->Unlock(); @@ -174,10 +181,11 @@ void Blit::initGeometry() D3DDECL_END() }; - hr = device->CreateVertexDeclaration(elements, &mQuadVertexDeclaration); - if (FAILED(hr)) + result = device->CreateVertexDeclaration(elements, &mQuadVertexDeclaration); + + if (FAILED(result)) { - ASSERT(hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY); + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); return error(GL_OUT_OF_MEMORY); } } @@ -287,6 +295,34 @@ bool Blit::boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *dest) return true; } +bool Blit::copy(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, IDirect3DSurface9 *dest) +{ + IDirect3DDevice9 *device = getDevice(); + + D3DSURFACE_DESC sourceDesc; + D3DSURFACE_DESC destDesc; + source->GetDesc(&sourceDesc); + dest->GetDesc(&destDesc); + + if (sourceDesc.Format == destDesc.Format && destDesc.Usage & D3DUSAGE_RENDERTARGET) // Can use StretchRect + { + RECT destRect = {xoffset, yoffset, xoffset + (sourceRect.right - sourceRect.left), yoffset + (sourceRect.bottom - sourceRect.top)}; + HRESULT result = device->StretchRect(source, &sourceRect, dest, &destRect, D3DTEXF_POINT); + + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + return error(GL_OUT_OF_MEMORY, false); + } + } + else + { + return formatConvert(source, sourceRect, destFormat, xoffset, yoffset, dest); + } + + return true; +} + bool Blit::formatConvert(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, IDirect3DSurface9 *dest) { IDirect3DTexture9 *texture = copySurfaceToTexture(source, sourceRect); @@ -468,6 +504,11 @@ void Blit::setCommonBlitState() RECT scissorRect = {0}; // Scissoring is disabled for flipping, but we need this to capture and restore the old rectangle device->SetScissorRect(&scissorRect); + + for(int i = 0; i < MAX_VERTEX_ATTRIBS; i++) + { + device->SetStreamSourceFreq(i, 1); + } } void Blit::render() diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/Blit.h b/Source/ThirdParty/ANGLE/src/libGLESv2/Blit.h index a83aac3..8928ecd 100644 --- a/Source/ThirdParty/ANGLE/src/libGLESv2/Blit.h +++ b/Source/ThirdParty/ANGLE/src/libGLESv2/Blit.h @@ -30,6 +30,10 @@ class Blit // Copy from source surface to dest surface. // sourceRect, xoffset, yoffset are in D3D coordinates (0,0 in upper-left) + bool copy(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, IDirect3DSurface9 *dest); + + // Copy from source surface to dest surface. + // sourceRect, xoffset, yoffset are in D3D coordinates (0,0 in upper-left) // source is interpreted as RGBA and destFormat specifies the desired result format. For example, if destFormat = GL_RGB, the alpha channel will be forced to 0. bool formatConvert(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, IDirect3DSurface9 *dest); diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/Buffer.cpp b/Source/ThirdParty/ANGLE/src/libGLESv2/Buffer.cpp index 17cea6c..dd12e3c 100644 --- a/Source/ThirdParty/ANGLE/src/libGLESv2/Buffer.cpp +++ b/Source/ThirdParty/ANGLE/src/libGLESv2/Buffer.cpp @@ -11,8 +11,8 @@ #include "libGLESv2/Buffer.h" #include "libGLESv2/main.h" -#include "libGLESv2/geometry/VertexDataManager.h" -#include "libGLESv2/geometry/IndexDataManager.h" +#include "libGLESv2/VertexDataManager.h" +#include "libGLESv2/IndexDataManager.h" namespace gl { @@ -23,15 +23,16 @@ Buffer::Buffer(GLuint id) : RefCountObject(id) mSize = 0; mUsage = GL_DYNAMIC_DRAW; - mVertexBuffer = NULL; - mIndexBuffer = NULL; + mStaticVertexBuffer = NULL; + mStaticIndexBuffer = NULL; + mUnmodifiedDataUse = 0; } Buffer::~Buffer() { delete[] mContents; - delete mVertexBuffer; - delete mIndexBuffer; + delete mStaticVertexBuffer; + delete mStaticIndexBuffer; } void Buffer::bufferData(const void *data, GLsizeiptr size, GLenum usage) @@ -60,47 +61,57 @@ void Buffer::bufferData(const void *data, GLsizeiptr size, GLenum usage) if (usage == GL_STATIC_DRAW) { - mVertexBuffer = new StaticVertexBuffer(getDevice()); - mIndexBuffer = new StaticIndexBuffer(getDevice()); + mStaticVertexBuffer = new StaticVertexBuffer(getDevice()); + mStaticIndexBuffer = new StaticIndexBuffer(getDevice()); } } void Buffer::bufferSubData(const void *data, GLsizeiptr size, GLintptr offset) { memcpy(mContents + offset, data, size); - - if ((mVertexBuffer && mVertexBuffer->size() != 0) || (mIndexBuffer && mIndexBuffer->size() != 0)) + + if ((mStaticVertexBuffer && mStaticVertexBuffer->size() != 0) || (mStaticIndexBuffer && mStaticIndexBuffer->size() != 0)) { invalidateStaticData(); - - if (mUsage == GL_STATIC_DRAW) - { - // If applications update the buffer data after it has already been used in a draw call, - // it most likely isn't used as a static buffer so we should fall back to streaming usage - // for best performance. So ignore the usage hint and don't create new static buffers. - // mVertexBuffer = new StaticVertexBuffer(getDevice()); - // mIndexBuffer = new StaticIndexBuffer(getDevice()); - } } + + mUnmodifiedDataUse = 0; } -StaticVertexBuffer *Buffer::getVertexBuffer() +StaticVertexBuffer *Buffer::getStaticVertexBuffer() { - return mVertexBuffer; + return mStaticVertexBuffer; } -StaticIndexBuffer *Buffer::getIndexBuffer() +StaticIndexBuffer *Buffer::getStaticIndexBuffer() { - return mIndexBuffer; + return mStaticIndexBuffer; } void Buffer::invalidateStaticData() { - delete mVertexBuffer; - mVertexBuffer = NULL; + delete mStaticVertexBuffer; + mStaticVertexBuffer = NULL; + + delete mStaticIndexBuffer; + mStaticIndexBuffer = NULL; + + mUnmodifiedDataUse = 0; +} + +// Creates static buffers if sufficient used data has been left unmodified +void Buffer::promoteStaticUsage(int dataSize) +{ + if (!mStaticVertexBuffer && !mStaticIndexBuffer) + { + mUnmodifiedDataUse += dataSize; - delete mIndexBuffer; - mIndexBuffer = NULL; + if (mUnmodifiedDataUse > 3 * mSize) + { + mStaticVertexBuffer = new StaticVertexBuffer(getDevice()); + mStaticIndexBuffer = new StaticIndexBuffer(getDevice()); + } + } } } diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/Buffer.h b/Source/ThirdParty/ANGLE/src/libGLESv2/Buffer.h index c2ed60f..7019c4e 100644 --- a/Source/ThirdParty/ANGLE/src/libGLESv2/Buffer.h +++ b/Source/ThirdParty/ANGLE/src/libGLESv2/Buffer.h @@ -18,7 +18,7 @@ #include <GLES2/gl2.h> #include "common/angleutils.h" -#include "libGLESv2/RefCountObject.h" +#include "common/RefCountObject.h" namespace gl { @@ -39,19 +39,21 @@ class Buffer : public RefCountObject size_t size() const { return mSize; } GLenum usage() const { return mUsage; } - StaticVertexBuffer *getVertexBuffer(); - StaticIndexBuffer *getIndexBuffer(); + StaticVertexBuffer *getStaticVertexBuffer(); + StaticIndexBuffer *getStaticIndexBuffer(); void invalidateStaticData(); + void promoteStaticUsage(int dataSize); private: DISALLOW_COPY_AND_ASSIGN(Buffer); GLubyte *mContents; - size_t mSize; + GLsizeiptr mSize; GLenum mUsage; - StaticVertexBuffer *mVertexBuffer; - StaticIndexBuffer *mIndexBuffer; + StaticVertexBuffer *mStaticVertexBuffer; + StaticIndexBuffer *mStaticIndexBuffer; + GLsizeiptr mUnmodifiedDataUse; }; } 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) diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/Context.h b/Source/ThirdParty/ANGLE/src/libGLESv2/Context.h index 2906664..8dccf0f 100644 --- a/Source/ThirdParty/ANGLE/src/libGLESv2/Context.h +++ b/Source/ThirdParty/ANGLE/src/libGLESv2/Context.h @@ -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. // @@ -18,10 +18,12 @@ #include <d3d9.h> #include <map> +#include <hash_map> #include "common/angleutils.h" +#include "common/RefCountObject.h" #include "libGLESv2/ResourceManager.h" -#include "libGLESv2/RefCountObject.h" +#include "libGLESv2/HandleAllocator.h" namespace egl { @@ -46,23 +48,29 @@ class Renderbuffer; class RenderbufferStorage; class Colorbuffer; class Depthbuffer; +class StreamingIndexBuffer; class Stencilbuffer; class DepthStencilbuffer; class VertexDataManager; class IndexDataManager; class Blit; class Fence; +class Query; enum { + D3D9_MAX_FLOAT_CONSTANTS = 256, + D3D9_MAX_BOOL_CONSTANTS = 16, + D3D9_MAX_INT_CONSTANTS = 16, + MAX_VERTEX_ATTRIBS = 16, - MAX_VERTEX_UNIFORM_VECTORS = 256 - 2, // 256 is the minimum for SM2, and in practice the maximum for DX9. Reserve space for dx_HalfPixelSize and dx_DepthRange. + MAX_VERTEX_UNIFORM_VECTORS = D3D9_MAX_FLOAT_CONSTANTS - 2, // Reserve space for dx_HalfPixelSize and dx_DepthRange. MAX_VARYING_VECTORS_SM2 = 8, MAX_VARYING_VECTORS_SM3 = 10, - MAX_COMBINED_TEXTURE_IMAGE_UNITS = 16, - MAX_VERTEX_TEXTURE_IMAGE_UNITS = 0, MAX_TEXTURE_IMAGE_UNITS = 16, - MAX_FRAGMENT_UNIFORM_VECTORS_SM2 = 32 - 3, // Reserve space for dx_Viewport, dx_Depth, and dx_DepthRange. dx_PointOrLines and dx_FrontCCW use separate bool registers. + MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF = 4, // For devices supporting vertex texture fetch + MAX_COMBINED_TEXTURE_IMAGE_UNITS_VTF = MAX_TEXTURE_IMAGE_UNITS + MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF, + MAX_FRAGMENT_UNIFORM_VECTORS_SM2 = 32 - 3, // Reserve space for dx_Coord, dx_Depth, and dx_DepthRange. dx_PointOrLines and dx_FrontCCW use separate bool registers. MAX_FRAGMENT_UNIFORM_VECTORS_SM3 = 224 - 3, MAX_DRAW_BUFFERS = 1, @@ -70,6 +78,14 @@ enum IMPLEMENTATION_COLOR_READ_TYPE = GL_UNSIGNED_SHORT_5_6_5 }; +enum QueryType +{ + QUERY_ANY_SAMPLES_PASSED, + QUERY_ANY_SAMPLES_PASSED_CONSERVATIVE, + + QUERY_TYPE_COUNT +}; + const float ALIASED_LINE_WIDTH_RANGE_MIN = 1.0f; const float ALIASED_LINE_WIDTH_RANGE_MAX = 1.0f; const float ALIASED_POINT_SIZE_RANGE_MIN = 1.0f; @@ -88,7 +104,7 @@ struct Color class VertexAttribute { public: - VertexAttribute() : mType(GL_FLOAT), mSize(0), mNormalized(false), mStride(0), mPointer(NULL), mArrayEnabled(false) + VertexAttribute() : mType(GL_FLOAT), mSize(0), mNormalized(false), mStride(0), mPointer(NULL), mArrayEnabled(false), mDivisor(0) { mCurrentValue[0] = 0.0f; mCurrentValue[1] = 0.0f; @@ -131,6 +147,7 @@ class VertexAttribute bool mArrayEnabled; // From glEnable/DisableVertexAttribArray float mCurrentValue[4]; // From glVertexAttrib + unsigned int mDivisor; }; typedef VertexAttribute VertexAttributeArray[MAX_VERTEX_ATTRIBS]; @@ -203,7 +220,7 @@ struct State bool colorMaskAlpha; bool depthMask; - int activeSampler; // Active texture unit selector - GL_TEXTURE0 + unsigned int activeSampler; // Active texture unit selector - GL_TEXTURE0 BindingPointer<Buffer> arrayBuffer; BindingPointer<Buffer> elementArrayBuffer; GLuint readFramebuffer; @@ -212,16 +229,53 @@ struct State GLuint currentProgram; VertexAttribute vertexAttribute[MAX_VERTEX_ATTRIBS]; - BindingPointer<Texture> samplerTexture[SAMPLER_TYPE_COUNT][MAX_TEXTURE_IMAGE_UNITS]; + BindingPointer<Texture> samplerTexture[TEXTURE_TYPE_COUNT][MAX_COMBINED_TEXTURE_IMAGE_UNITS_VTF]; + BindingPointer<Query> activeQuery[QUERY_TYPE_COUNT]; GLint unpackAlignment; GLint packAlignment; + bool packReverseRowOrder; +}; + +// Helper class to construct and cache vertex declarations +class VertexDeclarationCache +{ + public: + VertexDeclarationCache(); + ~VertexDeclarationCache(); + + GLenum applyDeclaration(IDirect3DDevice9 *device, TranslatedAttribute attributes[], Program *program, GLsizei instances, GLsizei *repeatDraw); + + void markStateDirty(); + + private: + UINT mMaxLru; + + enum { NUM_VERTEX_DECL_CACHE_ENTRIES = 16 }; + + struct VBData + { + unsigned int serial; + unsigned int stride; + unsigned int offset; + }; + + VBData mAppliedVBs[MAX_VERTEX_ATTRIBS]; + IDirect3DVertexDeclaration9 *mLastSetVDecl; + bool mInstancingEnabled; + + struct VertexDeclCacheEntry + { + D3DVERTEXELEMENT9 cachedElements[MAX_VERTEX_ATTRIBS + 1]; + UINT lruCount; + IDirect3DVertexDeclaration9 *vertexDeclaration; + } mVertexDeclCache[NUM_VERTEX_DECL_CACHE_ENTRIES]; }; class Context { public: - Context(const egl::Config *config, const gl::Context *shareContext); + Context(const egl::Config *config, const gl::Context *shareContext, bool notifyResets, bool robustAccess); ~Context(); @@ -229,6 +283,9 @@ class Context void markAllStateDirty(); + virtual void markContextLost(); + bool isContextLost(); + // State manipulation void setClearColor(float red, float green, float blue, float alpha); @@ -298,7 +355,7 @@ class Context void setColorMask(bool red, bool green, bool blue, bool alpha); void setDepthMask(bool mask); - void setActiveSampler(int active); + void setActiveSampler(unsigned int active); GLuint getReadFramebufferHandle() const; GLuint getDrawFramebufferHandle() const; @@ -306,6 +363,8 @@ class Context GLuint getArrayBufferHandle() const; + GLuint getActiveQuery(GLenum target) const; + void setEnableVertexAttribArray(unsigned int attribNum, bool enabled); const VertexAttribute &getVertexAttribState(unsigned int attribNum); void setVertexAttribState(unsigned int attribNum, Buffer *boundBuffer, GLint size, GLenum type, @@ -320,6 +379,9 @@ class Context void setPackAlignment(GLint alignment); GLint getPackAlignment() const; + void setPackReverseRowOrder(bool reverseRowOrder); + bool getPackReverseRowOrder() const; + // These create and destroy methods are merely pass-throughs to // ResourceManager, which owns these object types GLuint createBuffer(); @@ -341,6 +403,10 @@ class Context // Fences are owned by the Context. GLuint createFence(); void deleteFence(GLuint fence); + + // Queries are owned by the Context; + GLuint createQuery(); + void deleteQuery(GLuint query); void bindArrayBuffer(GLuint buffer); void bindElementArrayBuffer(GLuint buffer); @@ -351,11 +417,15 @@ class Context void bindRenderbuffer(GLuint renderbuffer); void useProgram(GLuint program); + void beginQuery(GLenum target, GLuint query); + void endQuery(GLenum target); + void setFramebufferZero(Framebuffer *framebuffer); void setRenderbufferStorage(RenderbufferStorage *renderbuffer); void setVertexAttrib(GLuint index, const GLfloat *values); + void setVertexAttribDivisor(GLuint index, GLuint divisor); Buffer *getBuffer(GLuint handle); Fence *getFence(GLuint handle); @@ -364,13 +434,14 @@ class Context Texture *getTexture(GLuint handle); Framebuffer *getFramebuffer(GLuint handle); Renderbuffer *getRenderbuffer(GLuint handle); + Query *getQuery(GLuint handle, bool create, GLenum type); Buffer *getArrayBuffer(); Buffer *getElementArrayBuffer(); Program *getCurrentProgram(); Texture2D *getTexture2D(); TextureCubeMap *getTextureCubeMap(); - Texture *getSamplerTexture(unsigned int sampler, SamplerType type); + Texture *getSamplerTexture(unsigned int sampler, TextureType type); Framebuffer *getReadFramebuffer(); Framebuffer *getDrawFramebuffer(); @@ -380,23 +451,13 @@ class Context bool getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *numParams); - bool applyRenderTarget(bool ignoreViewport); - void applyState(GLenum drawMode); - GLenum applyVertexBuffer(GLint first, GLsizei count); - GLenum applyIndexBuffer(const void *indices, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo); - void applyShaders(); - void applyTextures(); - - void readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels); + void readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei *bufSize, void* pixels); void clear(GLbitfield mask); - void drawArrays(GLenum mode, GLint first, GLsizei count); - void drawElements(GLenum mode, GLsizei count, GLenum type, const void *indices); - void finish(); - void flush(); + void drawArrays(GLenum mode, GLint first, GLsizei count, GLsizei instances); + void drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei instances); + void sync(bool block); // flush/finish - // Draw the last segment of a line loop - void drawClosingLine(unsigned int first, unsigned int last); - void drawClosingLine(GLsizei count, GLenum type, const void *indices); + void drawLineLoop(GLsizei count, GLenum type, const GLvoid *indices, int minIndex); void recordInvalidEnum(); void recordInvalidValue(); @@ -405,9 +466,13 @@ class Context void recordInvalidFramebufferOperation(); GLenum getError(); + GLenum getResetStatus(); + virtual bool isResetNotificationEnabled(); bool supportsShaderModel3() const; int getMaximumVaryingVectors() const; + unsigned int getMaximumVertexTextureImageUnits() const; + unsigned int getMaximumCombinedTextureImageUnits() const; int getMaximumFragmentUniformVectors() const; int getMaximumRenderbufferDimension() const; int getMaximumTextureDimension() const; @@ -416,17 +481,23 @@ class Context GLsizei getMaxSupportedSamples() const; int getNearestSupportedSamples(D3DFORMAT format, int requested) const; const char *getExtensionString() const; + const char *getRendererString() const; bool supportsEventQueries() const; - bool supportsCompressedTextures() const; - bool supportsFloatTextures() const; - bool supportsFloatLinearFilter() const; - bool supportsFloatRenderableTextures() const; - bool supportsHalfFloatTextures() const; - bool supportsHalfFloatLinearFilter() const; - bool supportsHalfFloatRenderableTextures() const; + bool supportsOcclusionQueries() const; + bool supportsDXT1Textures() const; + bool supportsDXT3Textures() const; + bool supportsDXT5Textures() const; + bool supportsFloat32Textures() const; + bool supportsFloat32LinearFilter() const; + bool supportsFloat32RenderableTextures() const; + bool supportsFloat16Textures() const; + bool supportsFloat16LinearFilter() const; + bool supportsFloat16RenderableTextures() const; bool supportsLuminanceTextures() const; bool supportsLuminanceAlphaTextures() const; bool supports32bitIndices() const; + bool supportsNonPower2Texture() const; + bool supportsInstancing() const; void blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, @@ -439,40 +510,59 @@ class Context private: DISALLOW_COPY_AND_ASSIGN(Context); - void lookupAttributeMapping(TranslatedAttribute *attributes); + bool applyRenderTarget(bool ignoreViewport); + void applyState(GLenum drawMode); + GLenum applyVertexBuffer(GLint first, GLsizei count, GLsizei instances, GLsizei *repeatDraw); + GLenum applyIndexBuffer(const GLvoid *indices, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo); + void applyShaders(); + void applyTextures(); + void applyTextures(SamplerType type); void detachBuffer(GLuint buffer); void detachTexture(GLuint texture); void detachFramebuffer(GLuint framebuffer); void detachRenderbuffer(GLuint renderbuffer); - Texture *getIncompleteTexture(SamplerType type); + Texture *getIncompleteTexture(TextureType type); bool cullSkipsDraw(GLenum drawMode); bool isTriangleMode(GLenum drawMode); + void initExtensionString(); + void initRendererString(); + const egl::Config *const mConfig; + egl::Display *mDisplay; + IDirect3DDevice9 *mDevice; - State mState; + State mState; BindingPointer<Texture2D> mTexture2DZero; BindingPointer<TextureCubeMap> mTextureCubeMapZero; - typedef std::map<GLuint, Framebuffer*> FramebufferMap; + typedef stdext::hash_map<GLuint, Framebuffer*> FramebufferMap; FramebufferMap mFramebufferMap; + HandleAllocator mFramebufferHandleAllocator; - typedef std::map<GLuint, Fence*> FenceMap; + typedef stdext::hash_map<GLuint, Fence*> FenceMap; FenceMap mFenceMap; + HandleAllocator mFenceHandleAllocator; + + typedef stdext::hash_map<GLuint, Query*> QueryMap; + QueryMap mQueryMap; + HandleAllocator mQueryHandleAllocator; - void initExtensionString(); std::string mExtensionString; + std::string mRendererString; VertexDataManager *mVertexDataManager; IndexDataManager *mIndexDataManager; Blit *mBlit; + + StreamingIndexBuffer *mLineLoopIB; - BindingPointer<Texture> mIncompleteTextures[SAMPLER_TYPE_COUNT]; + BindingPointer<Texture> mIncompleteTextures[TEXTURE_TYPE_COUNT]; // Recorded errors bool mInvalidEnum; @@ -481,15 +571,33 @@ class Context bool mOutOfMemory; bool mInvalidFramebufferOperation; + // Current/lost context flags bool mHasBeenCurrent; - - unsigned int mAppliedProgram; + bool mContextLost; + GLenum mResetStatus; + GLenum mResetStrategy; + bool mRobustAccess; + + unsigned int mAppliedTextureSerialPS[MAX_TEXTURE_IMAGE_UNITS]; + unsigned int mAppliedTextureSerialVS[MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF]; + unsigned int mAppliedProgramSerial; unsigned int mAppliedRenderTargetSerial; unsigned int mAppliedDepthbufferSerial; unsigned int mAppliedStencilbufferSerial; + unsigned int mAppliedIBSerial; bool mDepthStencilInitialized; + bool mViewportInitialized; + D3DVIEWPORT9 mSetViewport; + bool mRenderTargetDescInitialized; + D3DSURFACE_DESC mRenderTargetDesc; + bool mDxUniformsDirty; + Program *mCachedCurrentProgram; + Framebuffer *mBoundDrawFramebuffer; bool mSupportsShaderModel3; + bool mSupportsVertexTexture; + bool mSupportsNonPower2Texture; + bool mSupportsInstancing; int mMaxRenderbufferDimension; int mMaxTextureDimension; int mMaxCubeTextureDimension; @@ -497,16 +605,20 @@ class Context std::map<D3DFORMAT, bool *> mMultiSampleSupport; GLsizei mMaxSupportedSamples; bool mSupportsEventQueries; - bool mSupportsCompressedTextures; - bool mSupportsFloatTextures; - bool mSupportsFloatLinearFilter; - bool mSupportsFloatRenderableTextures; - bool mSupportsHalfFloatTextures; - bool mSupportsHalfFloatLinearFilter; - bool mSupportsHalfFloatRenderableTextures; + bool mSupportsOcclusionQueries; + bool mSupportsDXT1Textures; + bool mSupportsDXT3Textures; + bool mSupportsDXT5Textures; + bool mSupportsFloat32Textures; + bool mSupportsFloat32LinearFilter; + bool mSupportsFloat32RenderableTextures; + bool mSupportsFloat16Textures; + bool mSupportsFloat16LinearFilter; + bool mSupportsFloat16RenderableTextures; bool mSupportsLuminanceTextures; bool mSupportsLuminanceAlphaTextures; bool mSupports32bitIndices; + int mNumCompressedTextureFormats; // state caching flags bool mClearStateDirty; @@ -527,17 +639,20 @@ class Context D3DCAPS9 mDeviceCaps; ResourceManager *mResourceManager; + + VertexDeclarationCache mVertexDeclarationCache; }; } extern "C" { // Exported functions for use by EGL -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); void glDestroyContext(gl::Context *context); void glMakeCurrent(gl::Context *context, egl::Display *display, egl::Surface *surface); gl::Context *glGetCurrentContext(); __eglMustCastToProperFunctionPointerType __stdcall glGetProcAddress(const char *procname); +bool __stdcall glBindTexImage(egl::Surface *surface); } #endif // INCLUDE_CONTEXT_H_ diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/Fence.cpp b/Source/ThirdParty/ANGLE/src/libGLESv2/Fence.cpp index 7fbcb6a..14d1239 100644 --- a/Source/ThirdParty/ANGLE/src/libGLESv2/Fence.cpp +++ b/Source/ThirdParty/ANGLE/src/libGLESv2/Fence.cpp @@ -13,8 +13,9 @@ namespace gl { -Fence::Fence() -{ +Fence::Fence(egl::Display* display) +{ + mDisplay = display; mQuery = NULL; mCondition = GL_NONE; mStatus = GL_FALSE; @@ -24,8 +25,7 @@ Fence::~Fence() { if (mQuery != NULL) { - mQuery->Release(); - mQuery = NULL; + mDisplay->freeEventQuery(mQuery); } } @@ -38,15 +38,13 @@ GLboolean Fence::isFence() void Fence::setFence(GLenum condition) { - if (mQuery != NULL) + if (!mQuery) { - mQuery->Release(); - mQuery = NULL; - } - - if (FAILED(getDevice()->CreateQuery(D3DQUERYTYPE_EVENT, &mQuery))) - { - return error(GL_OUT_OF_MEMORY); + mQuery = mDisplay->allocateEventQuery(); + if (!mQuery) + { + return error(GL_OUT_OF_MEMORY); + } } HRESULT result = mQuery->Issue(D3DISSUE_END); @@ -65,7 +63,7 @@ GLboolean Fence::testFence() HRESULT result = mQuery->GetData(NULL, 0, D3DGETDATA_FLUSH); - if (result == D3DERR_DEVICELOST) + if (checkDeviceLost(result)) { return error(GL_OUT_OF_MEMORY, GL_TRUE); } @@ -110,7 +108,7 @@ void Fence::getFenceiv(GLenum pname, GLint *params) HRESULT result = mQuery->GetData(NULL, 0, 0); - if (result == D3DERR_DEVICELOST) + if (checkDeviceLost(result)) { params[0] = GL_TRUE; return error(GL_OUT_OF_MEMORY); diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/Fence.h b/Source/ThirdParty/ANGLE/src/libGLESv2/Fence.h index 17bad78..9626cb0 100644 --- a/Source/ThirdParty/ANGLE/src/libGLESv2/Fence.h +++ b/Source/ThirdParty/ANGLE/src/libGLESv2/Fence.h @@ -15,13 +15,18 @@ #include "common/angleutils.h" +namespace egl +{ +class Display; +} + namespace gl { class Fence { public: - Fence(); + explicit Fence(egl::Display* display); virtual ~Fence(); GLboolean isFence(); @@ -33,6 +38,7 @@ class Fence private: DISALLOW_COPY_AND_ASSIGN(Fence); + egl::Display* mDisplay; IDirect3DQuery9* mQuery; GLenum mCondition; GLboolean mStatus; diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/Framebuffer.cpp b/Source/ThirdParty/ANGLE/src/libGLESv2/Framebuffer.cpp index 5fe01e0..730fffc 100644 --- a/Source/ThirdParty/ANGLE/src/libGLESv2/Framebuffer.cpp +++ b/Source/ThirdParty/ANGLE/src/libGLESv2/Framebuffer.cpp @@ -44,9 +44,9 @@ Renderbuffer *Framebuffer::lookupRenderbuffer(GLenum type, GLuint handle) const { buffer = context->getRenderbuffer(handle); } - else if (IsTextureTarget(type)) + else if (IsInternalTextureTarget(type)) { - buffer = context->getTexture(handle)->getColorbuffer(type); + buffer = context->getTexture(handle)->getRenderbuffer(type); } else { @@ -58,37 +58,37 @@ Renderbuffer *Framebuffer::lookupRenderbuffer(GLenum type, GLuint handle) const void Framebuffer::setColorbuffer(GLenum type, GLuint colorbuffer) { - mColorbufferType = type; + mColorbufferType = (colorbuffer != 0) ? type : GL_NONE; mColorbufferPointer.set(lookupRenderbuffer(type, colorbuffer)); } void Framebuffer::setDepthbuffer(GLenum type, GLuint depthbuffer) { - mDepthbufferType = type; + mDepthbufferType = (depthbuffer != 0) ? type : GL_NONE; mDepthbufferPointer.set(lookupRenderbuffer(type, depthbuffer)); } void Framebuffer::setStencilbuffer(GLenum type, GLuint stencilbuffer) { - mStencilbufferType = type; + mStencilbufferType = (stencilbuffer != 0) ? type : GL_NONE; mStencilbufferPointer.set(lookupRenderbuffer(type, stencilbuffer)); } void Framebuffer::detachTexture(GLuint texture) { - if (mColorbufferPointer.id() == texture && IsTextureTarget(mColorbufferType)) + if (mColorbufferPointer.id() == texture && IsInternalTextureTarget(mColorbufferType)) { mColorbufferType = GL_NONE; mColorbufferPointer.set(NULL); } - if (mDepthbufferPointer.id() == texture && IsTextureTarget(mDepthbufferType)) + if (mDepthbufferPointer.id() == texture && IsInternalTextureTarget(mDepthbufferType)) { mDepthbufferType = GL_NONE; mDepthbufferPointer.set(NULL); } - if (mStencilbufferPointer.id() == texture && IsTextureTarget(mStencilbufferType)) + if (mStencilbufferPointer.id() == texture && IsInternalTextureTarget(mStencilbufferType)) { mStencilbufferType = GL_NONE; mStencilbufferPointer.set(NULL); @@ -181,46 +181,19 @@ unsigned int Framebuffer::getStencilbufferSerial() return 0; } -Colorbuffer *Framebuffer::getColorbuffer() +Renderbuffer *Framebuffer::getColorbuffer() { - Renderbuffer *rb = mColorbufferPointer.get(); - - if (rb != NULL && rb->isColorbuffer()) - { - return static_cast<Colorbuffer*>(rb->getStorage()); - } - else - { - return NULL; - } + return mColorbufferPointer.get(); } -DepthStencilbuffer *Framebuffer::getDepthbuffer() +Renderbuffer *Framebuffer::getDepthbuffer() { - Renderbuffer *rb = mDepthbufferPointer.get(); - - if (rb != NULL && rb->isDepthbuffer()) - { - return static_cast<DepthStencilbuffer*>(rb->getStorage()); - } - else - { - return NULL; - } + return mDepthbufferPointer.get(); } -DepthStencilbuffer *Framebuffer::getStencilbuffer() +Renderbuffer *Framebuffer::getStencilbuffer() { - Renderbuffer *rb = mStencilbufferPointer.get(); - - if (rb != NULL && rb->isStencilbuffer()) - { - return static_cast<DepthStencilbuffer*>(rb->getStorage()); - } - else - { - return NULL; - } + return mStencilbufferPointer.get(); } GLenum Framebuffer::getColorbufferType() @@ -257,7 +230,7 @@ bool Framebuffer::hasStencil() { if (mStencilbufferType != GL_NONE) { - DepthStencilbuffer *stencilbufferObject = getStencilbuffer(); + Renderbuffer *stencilbufferObject = getStencilbuffer(); if (stencilbufferObject) { @@ -268,23 +241,6 @@ bool Framebuffer::hasStencil() return false; } -bool Framebuffer::isMultisample() -{ - // If the framebuffer is not complete, attachment samples may be mismatched, and it - // cannot be used as a multisample framebuffer. If it is complete, it is required to - // have a color attachment, and all its attachments must have the same number of samples, - // so the number of samples for the colorbuffer will indicate whether the framebuffer is - // multisampled. - if (completeness() == GL_FRAMEBUFFER_COMPLETE && getColorbuffer()->getSamples() > 0) - { - return true; - } - else - { - return false; - } -} - GLenum Framebuffer::completeness() { int width = 0; @@ -293,7 +249,7 @@ GLenum Framebuffer::completeness() if (mColorbufferType != GL_NONE) { - Colorbuffer *colorbuffer = getColorbuffer(); + Renderbuffer *colorbuffer = getColorbuffer(); if (!colorbuffer) { @@ -307,25 +263,25 @@ GLenum Framebuffer::completeness() if (mColorbufferType == GL_RENDERBUFFER) { - if (!gl::IsColorRenderable(colorbuffer->getFormat())) + if (!gl::IsColorRenderable(colorbuffer->getInternalFormat())) { return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; } } - else if (IsTextureTarget(mColorbufferType)) + else if (IsInternalTextureTarget(mColorbufferType)) { - if (IsCompressed(colorbuffer->getFormat())) + if (IsCompressed(colorbuffer->getInternalFormat())) { return GL_FRAMEBUFFER_UNSUPPORTED; } - if (colorbuffer->isFloatingPoint() && (!getContext()->supportsFloatRenderableTextures() || - !getContext()->supportsHalfFloatRenderableTextures())) + if ((dx2es::IsFloat32Format(colorbuffer->getD3DFormat()) && !getContext()->supportsFloat32RenderableTextures()) || + (dx2es::IsFloat16Format(colorbuffer->getD3DFormat()) && !getContext()->supportsFloat16RenderableTextures())) { return GL_FRAMEBUFFER_UNSUPPORTED; } - if (colorbuffer->getFormat() == GL_LUMINANCE || colorbuffer->getFormat() == GL_LUMINANCE_ALPHA) + if (colorbuffer->getInternalFormat() == GL_LUMINANCE || colorbuffer->getInternalFormat() == GL_LUMINANCE_ALPHA) { return GL_FRAMEBUFFER_UNSUPPORTED; } @@ -341,8 +297,8 @@ GLenum Framebuffer::completeness() return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT; } - DepthStencilbuffer *depthbuffer = NULL; - DepthStencilbuffer *stencilbuffer = NULL; + Renderbuffer *depthbuffer = NULL; + Renderbuffer *stencilbuffer = NULL; if (mDepthbufferType != GL_NONE) { @@ -424,8 +380,8 @@ GLenum Framebuffer::completeness() if (mDepthbufferType == GL_RENDERBUFFER && mStencilbufferType == GL_RENDERBUFFER) { - if (depthbuffer->getFormat() != GL_DEPTH24_STENCIL8_OES || - stencilbuffer->getFormat() != GL_DEPTH24_STENCIL8_OES || + if (depthbuffer->getInternalFormat() != GL_DEPTH24_STENCIL8_OES || + stencilbuffer->getInternalFormat() != GL_DEPTH24_STENCIL8_OES || depthbuffer->getSerial() != stencilbuffer->getSerial()) { return GL_FRAMEBUFFER_UNSUPPORTED; @@ -435,17 +391,17 @@ GLenum Framebuffer::completeness() return GL_FRAMEBUFFER_COMPLETE; } -DefaultFramebuffer::DefaultFramebuffer(Colorbuffer *color, DepthStencilbuffer *depthStencil) +DefaultFramebuffer::DefaultFramebuffer(Colorbuffer *colorbuffer, DepthStencilbuffer *depthStencil) { - mColorbufferType = GL_RENDERBUFFER; - mDepthbufferType = (depthStencil->getDepthSize() != 0) ? GL_RENDERBUFFER : GL_NONE; - mStencilbufferType = (depthStencil->getStencilSize() != 0) ? GL_RENDERBUFFER : GL_NONE; - - mColorbufferPointer.set(new Renderbuffer(0, color)); + mColorbufferPointer.set(new Renderbuffer(0, colorbuffer)); Renderbuffer *depthStencilRenderbuffer = new Renderbuffer(0, depthStencil); mDepthbufferPointer.set(depthStencilRenderbuffer); mStencilbufferPointer.set(depthStencilRenderbuffer); + + mColorbufferType = GL_RENDERBUFFER; + mDepthbufferType = (depthStencilRenderbuffer->getDepthSize() != 0) ? GL_RENDERBUFFER : GL_NONE; + mStencilbufferType = (depthStencilRenderbuffer->getStencilSize() != 0) ? GL_RENDERBUFFER : GL_NONE; } int Framebuffer::getSamples() diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/Framebuffer.h b/Source/ThirdParty/ANGLE/src/libGLESv2/Framebuffer.h index 0995145..b73f9a0 100644 --- a/Source/ThirdParty/ANGLE/src/libGLESv2/Framebuffer.h +++ b/Source/ThirdParty/ANGLE/src/libGLESv2/Framebuffer.h @@ -15,7 +15,7 @@ #include <d3d9.h> #include "common/angleutils.h" -#include "libGLESv2/RefCountObject.h" +#include "common/RefCountObject.h" namespace gl { @@ -46,9 +46,9 @@ class Framebuffer unsigned int getDepthbufferSerial(); unsigned int getStencilbufferSerial(); - Colorbuffer *getColorbuffer(); - DepthStencilbuffer *getDepthbuffer(); - DepthStencilbuffer *getStencilbuffer(); + Renderbuffer *getColorbuffer(); + Renderbuffer *getDepthbuffer(); + Renderbuffer *getStencilbuffer(); GLenum getColorbufferType(); GLenum getDepthbufferType(); @@ -59,7 +59,6 @@ class Framebuffer GLuint getStencilbufferHandle(); bool hasStencil(); - bool isMultisample(); int getSamples(); virtual GLenum completeness(); @@ -83,7 +82,7 @@ class Framebuffer class DefaultFramebuffer : public Framebuffer { public: - DefaultFramebuffer(Colorbuffer *color, DepthStencilbuffer *depthStencil); + DefaultFramebuffer(Colorbuffer *colorbuffer, DepthStencilbuffer *depthStencil); virtual GLenum completeness(); diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/HandleAllocator.cpp b/Source/ThirdParty/ANGLE/src/libGLESv2/HandleAllocator.cpp new file mode 100644 index 0000000..c498f8a --- /dev/null +++ b/Source/ThirdParty/ANGLE/src/libGLESv2/HandleAllocator.cpp @@ -0,0 +1,63 @@ +// +// Copyright (c) 2002-2011 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. +// + +// HandleAllocator.cpp: Implements the gl::HandleAllocator class, which is used +// to allocate GL handles. + +#include "libGLESv2/HandleAllocator.h" + +#include "libGLESv2/main.h" + +namespace gl +{ + +HandleAllocator::HandleAllocator() : mBaseValue(1), mNextValue(1) +{ +} + +HandleAllocator::~HandleAllocator() +{ +} + +void HandleAllocator::setBaseHandle(GLuint value) +{ + ASSERT(mBaseValue == mNextValue); + mBaseValue = value; + mNextValue = value; +} + +GLuint HandleAllocator::allocate() +{ + if (mFreeValues.size()) + { + GLuint handle = mFreeValues.back(); + mFreeValues.pop_back(); + return handle; + } + return mNextValue++; +} + +void HandleAllocator::release(GLuint handle) +{ + if (handle == mNextValue - 1) + { + // Don't drop below base value + if(mNextValue > mBaseValue) + { + mNextValue--; + } + } + else + { + // Only free handles that we own - don't drop below the base value + if (handle >= mBaseValue) + { + mFreeValues.push_back(handle); + } + } +} + +} diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/HandleAllocator.h b/Source/ThirdParty/ANGLE/src/libGLESv2/HandleAllocator.h new file mode 100644 index 0000000..a92e168 --- /dev/null +++ b/Source/ThirdParty/ANGLE/src/libGLESv2/HandleAllocator.h @@ -0,0 +1,45 @@ +// +// Copyright (c) 2002-2011 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. +// + +// HandleAllocator.h: Defines the gl::HandleAllocator class, which is used to +// allocate GL handles. + +#ifndef LIBGLESV2_HANDLEALLOCATOR_H_ +#define LIBGLESV2_HANDLEALLOCATOR_H_ + +#define GL_APICALL +#include <GLES2/gl2.h> + +#include <vector> + +#include "common/angleutils.h" + +namespace gl +{ + +class HandleAllocator +{ + public: + HandleAllocator(); + virtual ~HandleAllocator(); + + void setBaseHandle(GLuint value); + + GLuint allocate(); + void release(GLuint handle); + + private: + DISALLOW_COPY_AND_ASSIGN(HandleAllocator); + + GLuint mBaseValue; + GLuint mNextValue; + typedef std::vector<GLuint> HandleList; + HandleList mFreeValues; +}; + +} + +#endif // LIBGLESV2_HANDLEALLOCATOR_H_ diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/IndexDataManager.cpp b/Source/ThirdParty/ANGLE/src/libGLESv2/IndexDataManager.cpp new file mode 100644 index 0000000..3dc0aef --- /dev/null +++ b/Source/ThirdParty/ANGLE/src/libGLESv2/IndexDataManager.cpp @@ -0,0 +1,473 @@ +// +// 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. +// + +// IndexDataManager.cpp: Defines the IndexDataManager, a class that +// runs the Buffer translation process for index buffers. + +#include "libGLESv2/IndexDataManager.h" + +#include "common/debug.h" + +#include "libGLESv2/Buffer.h" +#include "libGLESv2/mathutil.h" +#include "libGLESv2/main.h" + +namespace gl +{ +unsigned int IndexBuffer::mCurrentSerial = 1; + +IndexDataManager::IndexDataManager(Context *context, IDirect3DDevice9 *device) : mDevice(device) +{ + mStreamingBufferShort = new StreamingIndexBuffer(mDevice, INITIAL_INDEX_BUFFER_SIZE, D3DFMT_INDEX16); + + if (context->supports32bitIndices()) + { + mStreamingBufferInt = new StreamingIndexBuffer(mDevice, INITIAL_INDEX_BUFFER_SIZE, D3DFMT_INDEX32); + + if (!mStreamingBufferInt) + { + // Don't leave it in a half-initialized state + delete mStreamingBufferShort; + mStreamingBufferShort = NULL; + } + } + else + { + mStreamingBufferInt = NULL; + } + + if (!mStreamingBufferShort) + { + ERR("Failed to allocate the streaming index buffer(s)."); + } + + mCountingBuffer = NULL; +} + +IndexDataManager::~IndexDataManager() +{ + delete mStreamingBufferShort; + delete mStreamingBufferInt; + delete mCountingBuffer; +} + +void convertIndices(GLenum type, const void *input, GLsizei count, void *output) +{ + if (type == GL_UNSIGNED_BYTE) + { + const GLubyte *in = static_cast<const GLubyte*>(input); + GLushort *out = static_cast<GLushort*>(output); + + for (GLsizei i = 0; i < count; i++) + { + out[i] = in[i]; + } + } + else if (type == GL_UNSIGNED_INT) + { + memcpy(output, input, count * sizeof(GLuint)); + } + else if (type == GL_UNSIGNED_SHORT) + { + memcpy(output, input, count * sizeof(GLushort)); + } + else UNREACHABLE(); +} + +template <class IndexType> +void computeRange(const IndexType *indices, GLsizei count, GLuint *minIndex, GLuint *maxIndex) +{ + *minIndex = indices[0]; + *maxIndex = indices[0]; + + for (GLsizei i = 0; i < count; i++) + { + if (*minIndex > indices[i]) *minIndex = indices[i]; + if (*maxIndex < indices[i]) *maxIndex = indices[i]; + } +} + +void computeRange(GLenum type, const GLvoid *indices, GLsizei count, GLuint *minIndex, GLuint *maxIndex) +{ + if (type == GL_UNSIGNED_BYTE) + { + computeRange(static_cast<const GLubyte*>(indices), count, minIndex, maxIndex); + } + else if (type == GL_UNSIGNED_INT) + { + computeRange(static_cast<const GLuint*>(indices), count, minIndex, maxIndex); + } + else if (type == GL_UNSIGNED_SHORT) + { + computeRange(static_cast<const GLushort*>(indices), count, minIndex, maxIndex); + } + else UNREACHABLE(); +} + +GLenum IndexDataManager::prepareIndexData(GLenum type, GLsizei count, Buffer *buffer, const GLvoid *indices, TranslatedIndexData *translated) +{ + if (!mStreamingBufferShort) + { + return GL_OUT_OF_MEMORY; + } + + D3DFORMAT format = (type == GL_UNSIGNED_INT) ? D3DFMT_INDEX32 : D3DFMT_INDEX16; + intptr_t offset = reinterpret_cast<intptr_t>(indices); + bool alignedOffset = false; + + if (buffer != NULL) + { + switch (type) + { + case GL_UNSIGNED_BYTE: alignedOffset = (offset % sizeof(GLubyte) == 0); break; + case GL_UNSIGNED_SHORT: alignedOffset = (offset % sizeof(GLushort) == 0); break; + case GL_UNSIGNED_INT: alignedOffset = (offset % sizeof(GLuint) == 0); break; + default: UNREACHABLE(); alignedOffset = false; + } + + if (typeSize(type) * count + offset > static_cast<std::size_t>(buffer->size())) + { + return GL_INVALID_OPERATION; + } + + indices = static_cast<const GLubyte*>(buffer->data()) + offset; + } + + StreamingIndexBuffer *streamingBuffer = (type == GL_UNSIGNED_INT) ? mStreamingBufferInt : mStreamingBufferShort; + + StaticIndexBuffer *staticBuffer = buffer ? buffer->getStaticIndexBuffer() : NULL; + IndexBuffer *indexBuffer = streamingBuffer; + UINT streamOffset = 0; + + if (staticBuffer && staticBuffer->lookupType(type) && alignedOffset) + { + indexBuffer = staticBuffer; + streamOffset = staticBuffer->lookupRange(offset, count, &translated->minIndex, &translated->maxIndex); + + if (streamOffset == -1) + { + streamOffset = (offset / typeSize(type)) * indexSize(format); + computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex); + staticBuffer->addRange(offset, count, translated->minIndex, translated->maxIndex, streamOffset); + } + } + else + { + int convertCount = count; + + if (staticBuffer) + { + if (staticBuffer->size() == 0 && alignedOffset) + { + indexBuffer = staticBuffer; + convertCount = buffer->size() / typeSize(type); + } + else + { + buffer->invalidateStaticData(); + staticBuffer = NULL; + } + } + + void *output = NULL; + + if (indexBuffer) + { + indexBuffer->reserveSpace(convertCount * indexSize(format), type); + output = indexBuffer->map(indexSize(format) * convertCount, &streamOffset); + } + + if (output == NULL) + { + ERR("Failed to map index buffer."); + return GL_OUT_OF_MEMORY; + } + + convertIndices(type, staticBuffer ? buffer->data() : indices, convertCount, output); + indexBuffer->unmap(); + + computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex); + + if (staticBuffer) + { + streamOffset = (offset / typeSize(type)) * indexSize(format); + staticBuffer->addRange(offset, count, translated->minIndex, translated->maxIndex, streamOffset); + } + } + + translated->indexBuffer = indexBuffer->getBuffer(); + translated->serial = indexBuffer->getSerial(); + translated->startIndex = streamOffset / indexSize(format); + + if (buffer) + { + buffer->promoteStaticUsage(count * typeSize(type)); + } + + return GL_NO_ERROR; +} + +std::size_t IndexDataManager::indexSize(D3DFORMAT format) const +{ + return (format == D3DFMT_INDEX32) ? sizeof(unsigned int) : sizeof(unsigned short); +} + +std::size_t IndexDataManager::typeSize(GLenum type) const +{ + switch (type) + { + case GL_UNSIGNED_INT: return sizeof(GLuint); + case GL_UNSIGNED_SHORT: return sizeof(GLushort); + case GL_UNSIGNED_BYTE: return sizeof(GLubyte); + default: UNREACHABLE(); return sizeof(GLushort); + } +} + +StaticIndexBuffer *IndexDataManager::getCountingIndices(GLsizei count) +{ + if (count <= 65536) // 16-bit indices + { + const unsigned int spaceNeeded = count * sizeof(unsigned short); + + if (!mCountingBuffer || mCountingBuffer->size() < spaceNeeded) + { + delete mCountingBuffer; + mCountingBuffer = new StaticIndexBuffer(mDevice); + mCountingBuffer->reserveSpace(spaceNeeded, GL_UNSIGNED_SHORT); + + UINT offset; + unsigned short *data = static_cast<unsigned short*>(mCountingBuffer->map(spaceNeeded, &offset)); + + if (data) + { + for(int i = 0; i < count; i++) + { + data[i] = i; + } + + mCountingBuffer->unmap(); + } + } + } + else if (mStreamingBufferInt) // 32-bit indices supported + { + const unsigned int spaceNeeded = count * sizeof(unsigned int); + + if (!mCountingBuffer || mCountingBuffer->size() < spaceNeeded) + { + delete mCountingBuffer; + mCountingBuffer = new StaticIndexBuffer(mDevice); + mCountingBuffer->reserveSpace(spaceNeeded, GL_UNSIGNED_INT); + + UINT offset; + unsigned int *data = static_cast<unsigned int*>(mCountingBuffer->map(spaceNeeded, &offset)); + + if (data) + { + for(int i = 0; i < count; i++) + { + data[i] = i; + } + + mCountingBuffer->unmap(); + } + } + } + else return NULL; + + return mCountingBuffer; +} + +IndexBuffer::IndexBuffer(IDirect3DDevice9 *device, UINT size, D3DFORMAT format) : mDevice(device), mBufferSize(size), mIndexBuffer(NULL) +{ + if (size > 0) + { + D3DPOOL pool = getDisplay()->getBufferPool(D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY); + HRESULT result = device->CreateIndexBuffer(size, D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, format, pool, &mIndexBuffer, NULL); + mSerial = issueSerial(); + + if (FAILED(result)) + { + ERR("Out of memory allocating an index buffer of size %lu.", size); + } + } +} + +IndexBuffer::~IndexBuffer() +{ + if (mIndexBuffer) + { + mIndexBuffer->Release(); + } +} + +IDirect3DIndexBuffer9 *IndexBuffer::getBuffer() const +{ + return mIndexBuffer; +} + +unsigned int IndexBuffer::getSerial() const +{ + return mSerial; +} + +unsigned int IndexBuffer::issueSerial() +{ + return mCurrentSerial++; +} + +void IndexBuffer::unmap() +{ + if (mIndexBuffer) + { + mIndexBuffer->Unlock(); + } +} + +StreamingIndexBuffer::StreamingIndexBuffer(IDirect3DDevice9 *device, UINT initialSize, D3DFORMAT format) : IndexBuffer(device, initialSize, format) +{ + mWritePosition = 0; +} + +StreamingIndexBuffer::~StreamingIndexBuffer() +{ +} + +void *StreamingIndexBuffer::map(UINT requiredSpace, UINT *offset) +{ + void *mapPtr = NULL; + + if (mIndexBuffer) + { + HRESULT result = mIndexBuffer->Lock(mWritePosition, requiredSpace, &mapPtr, D3DLOCK_NOOVERWRITE); + + if (FAILED(result)) + { + ERR(" Lock failed with error 0x%08x", result); + return NULL; + } + + *offset = mWritePosition; + mWritePosition += requiredSpace; + } + + return mapPtr; +} + +void StreamingIndexBuffer::reserveSpace(UINT requiredSpace, GLenum type) +{ + if (requiredSpace > mBufferSize) + { + if (mIndexBuffer) + { + mIndexBuffer->Release(); + mIndexBuffer = NULL; + } + + mBufferSize = std::max(requiredSpace, 2 * mBufferSize); + + D3DPOOL pool = getDisplay()->getBufferPool(D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY); + HRESULT result = mDevice->CreateIndexBuffer(mBufferSize, D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, type == GL_UNSIGNED_INT ? D3DFMT_INDEX32 : D3DFMT_INDEX16, pool, &mIndexBuffer, NULL); + mSerial = issueSerial(); + + if (FAILED(result)) + { + ERR("Out of memory allocating a vertex buffer of size %lu.", mBufferSize); + } + + mWritePosition = 0; + } + else if (mWritePosition + requiredSpace > mBufferSize) // Recycle + { + void *dummy; + mIndexBuffer->Lock(0, 1, &dummy, D3DLOCK_DISCARD); + mIndexBuffer->Unlock(); + + mWritePosition = 0; + } +} + +StaticIndexBuffer::StaticIndexBuffer(IDirect3DDevice9 *device) : IndexBuffer(device, 0, D3DFMT_UNKNOWN) +{ + mCacheType = GL_NONE; +} + +StaticIndexBuffer::~StaticIndexBuffer() +{ +} + +void *StaticIndexBuffer::map(UINT requiredSpace, UINT *offset) +{ + void *mapPtr = NULL; + + if (mIndexBuffer) + { + HRESULT result = mIndexBuffer->Lock(0, requiredSpace, &mapPtr, 0); + + if (FAILED(result)) + { + ERR(" Lock failed with error 0x%08x", result); + return NULL; + } + + *offset = 0; + } + + return mapPtr; +} + +void StaticIndexBuffer::reserveSpace(UINT requiredSpace, GLenum type) +{ + if (!mIndexBuffer && mBufferSize == 0) + { + D3DPOOL pool = getDisplay()->getBufferPool(D3DUSAGE_WRITEONLY); + HRESULT result = mDevice->CreateIndexBuffer(requiredSpace, D3DUSAGE_WRITEONLY, type == GL_UNSIGNED_INT ? D3DFMT_INDEX32 : D3DFMT_INDEX16, pool, &mIndexBuffer, NULL); + mSerial = issueSerial(); + + if (FAILED(result)) + { + ERR("Out of memory allocating a vertex buffer of size %lu.", mBufferSize); + } + + mBufferSize = requiredSpace; + mCacheType = type; + } + else if (mIndexBuffer && mBufferSize >= requiredSpace && mCacheType == type) + { + // Already allocated + } + else UNREACHABLE(); // Static index buffers can't be resized +} + +bool StaticIndexBuffer::lookupType(GLenum type) +{ + return mCacheType == type; +} + +UINT StaticIndexBuffer::lookupRange(intptr_t offset, GLsizei count, UINT *minIndex, UINT *maxIndex) +{ + IndexRange range = {offset, count}; + + std::map<IndexRange, IndexResult>::iterator res = mCache.find(range); + + if (res == mCache.end()) + { + return -1; + } + + *minIndex = res->second.minIndex; + *maxIndex = res->second.maxIndex; + return res->second.streamOffset; +} + +void StaticIndexBuffer::addRange(intptr_t offset, GLsizei count, UINT minIndex, UINT maxIndex, UINT streamOffset) +{ + IndexRange indexRange = {offset, count}; + IndexResult indexResult = {minIndex, maxIndex, streamOffset}; + mCache[indexRange] = indexResult; +} + +} diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/IndexDataManager.h b/Source/ThirdParty/ANGLE/src/libGLESv2/IndexDataManager.h new file mode 100644 index 0000000..c1d4168 --- /dev/null +++ b/Source/ThirdParty/ANGLE/src/libGLESv2/IndexDataManager.h @@ -0,0 +1,149 @@ +// +// 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. +// + +// IndexDataManager.h: Defines the IndexDataManager, a class that +// runs the Buffer translation process for index buffers. + +#ifndef LIBGLESV2_INDEXDATAMANAGER_H_ +#define LIBGLESV2_INDEXDATAMANAGER_H_ + +#include <vector> +#include <cstddef> + +#define GL_APICALL +#include <GLES2/gl2.h> + +#include "libGLESv2/Context.h" + +namespace +{ + enum { INITIAL_INDEX_BUFFER_SIZE = 4096 * sizeof(GLuint) }; +} + +namespace gl +{ + +struct TranslatedIndexData +{ + UINT minIndex; + UINT maxIndex; + UINT startIndex; + + IDirect3DIndexBuffer9 *indexBuffer; + unsigned int serial; +}; + +class IndexBuffer +{ + public: + IndexBuffer(IDirect3DDevice9 *device, UINT size, D3DFORMAT format); + virtual ~IndexBuffer(); + + UINT size() const { return mBufferSize; } + virtual void *map(UINT requiredSpace, UINT *offset) = 0; + void unmap(); + virtual void reserveSpace(UINT requiredSpace, GLenum type) = 0; + + IDirect3DIndexBuffer9 *getBuffer() const; + unsigned int getSerial() const; + + protected: + IDirect3DDevice9 *const mDevice; + + IDirect3DIndexBuffer9 *mIndexBuffer; + UINT mBufferSize; + + unsigned int mSerial; + static unsigned int issueSerial(); + static unsigned int mCurrentSerial; + + private: + DISALLOW_COPY_AND_ASSIGN(IndexBuffer); +}; + +class StreamingIndexBuffer : public IndexBuffer +{ + public: + StreamingIndexBuffer(IDirect3DDevice9 *device, UINT initialSize, D3DFORMAT format); + ~StreamingIndexBuffer(); + + virtual void *map(UINT requiredSpace, UINT *offset); + virtual void reserveSpace(UINT requiredSpace, GLenum type); + + private: + UINT mWritePosition; +}; + +class StaticIndexBuffer : public IndexBuffer +{ + public: + explicit StaticIndexBuffer(IDirect3DDevice9 *device); + ~StaticIndexBuffer(); + + virtual void *map(UINT requiredSpace, UINT *offset); + virtual void reserveSpace(UINT requiredSpace, GLenum type); + + bool lookupType(GLenum type); + UINT lookupRange(intptr_t offset, GLsizei count, UINT *minIndex, UINT *maxIndex); // Returns the offset into the index buffer, or -1 if not found + void addRange(intptr_t offset, GLsizei count, UINT minIndex, UINT maxIndex, UINT streamOffset); + + private: + GLenum mCacheType; + + struct IndexRange + { + intptr_t offset; + GLsizei count; + + bool operator<(const IndexRange& rhs) const + { + if (offset != rhs.offset) + { + return offset < rhs.offset; + } + if (count != rhs.count) + { + return count < rhs.count; + } + return false; + } + }; + + struct IndexResult + { + UINT minIndex; + UINT maxIndex; + UINT streamOffset; + }; + + std::map<IndexRange, IndexResult> mCache; +}; + +class IndexDataManager +{ + public: + IndexDataManager(Context *context, IDirect3DDevice9 *evice); + virtual ~IndexDataManager(); + + GLenum prepareIndexData(GLenum type, GLsizei count, Buffer *arrayElementBuffer, const GLvoid *indices, TranslatedIndexData *translated); + StaticIndexBuffer *getCountingIndices(GLsizei count); + + private: + DISALLOW_COPY_AND_ASSIGN(IndexDataManager); + + std::size_t typeSize(GLenum type) const; + std::size_t indexSize(D3DFORMAT format) const; + + IDirect3DDevice9 *const mDevice; + + StreamingIndexBuffer *mStreamingBufferShort; + StreamingIndexBuffer *mStreamingBufferInt; + StaticIndexBuffer *mCountingBuffer; +}; + +} + +#endif // LIBGLESV2_INDEXDATAMANAGER_H_ diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/Program.cpp b/Source/ThirdParty/ANGLE/src/libGLESv2/Program.cpp index 780c3e3..a5e38bf 100644 --- a/Source/ThirdParty/ANGLE/src/libGLESv2/Program.cpp +++ b/Source/ThirdParty/ANGLE/src/libGLESv2/Program.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. // @@ -15,9 +15,16 @@ #include "libGLESv2/Shader.h" #include "libGLESv2/utilities.h" +#include <string> + +#if !defined(ANGLE_COMPILE_OPTIMIZATION_LEVEL) +#define ANGLE_COMPILE_OPTIMIZATION_LEVEL D3DCOMPILE_OPTIMIZATION_LEVEL3 +#endif + namespace gl { unsigned int Program::mCurrentSerial = 1; +const char *fakepath = "C:\\fakepath"; std::string str(int i) { @@ -26,13 +33,13 @@ std::string str(int i) return buffer; } -Uniform::Uniform(GLenum type, const std::string &name, unsigned int arraySize) : type(type), name(name), arraySize(arraySize) +Uniform::Uniform(GLenum type, const std::string &_name, unsigned int arraySize) + : type(type), _name(_name), name(Program::undecorateUniform(_name)), arraySize(arraySize) { - int bytes = UniformTypeSize(type) * arraySize; + int bytes = UniformInternalSize(type) * arraySize; data = new unsigned char[bytes]; memset(data, 0, bytes); dirty = true; - handlesSet = false; } Uniform::~Uniform() @@ -40,13 +47,19 @@ Uniform::~Uniform() delete[] data; } -UniformLocation::UniformLocation(const std::string &name, unsigned int element, unsigned int index) - : name(name), element(element), index(index) +bool Uniform::isArray() +{ + return _name.compare(0, 3, "ar_") == 0; +} + +UniformLocation::UniformLocation(const std::string &_name, unsigned int element, unsigned int index) + : name(Program::undecorateUniform(_name)), element(element), index(index) { } Program::Program(ResourceManager *manager, GLuint handle) : mResourceManager(manager), mHandle(handle), mSerial(issueSerial()) { + mDevice = getDevice(); mFragmentShader = NULL; mVertexShader = NULL; @@ -131,8 +144,6 @@ bool Program::detachShader(Shader *shader) } else UNREACHABLE(); - unlink(); - return true; } @@ -182,28 +193,54 @@ GLuint Program::getAttributeLocation(const char *name) int Program::getSemanticIndex(int attributeIndex) { - if (attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS) + ASSERT(attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS); + + return mSemanticIndex[attributeIndex]; +} + +// Returns one more than the highest sampler index used. +GLint Program::getUsedSamplerRange(SamplerType type) +{ + switch (type) { - return mSemanticIndex[attributeIndex]; + case SAMPLER_PIXEL: + return mUsedPixelSamplerRange; + case SAMPLER_VERTEX: + return mUsedVertexSamplerRange; + default: + UNREACHABLE(); + return 0; } - - return -1; } -// Returns the index of the texture unit corresponding to a Direct3D 9 sampler -// index referenced in the compiled HLSL shader -GLint Program::getSamplerMapping(unsigned int samplerIndex) +// Returns the index of the texture image unit (0-19) corresponding to a Direct3D 9 sampler +// index (0-15 for the pixel shader and 0-3 for the vertex shader). +GLint Program::getSamplerMapping(SamplerType type, unsigned int samplerIndex) { - assert(samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0])); - GLint logicalTextureUnit = -1; - if (mSamplers[samplerIndex].active) + switch (type) { - logicalTextureUnit = mSamplers[samplerIndex].logicalTextureUnit; + case SAMPLER_PIXEL: + ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0])); + + if (mSamplersPS[samplerIndex].active) + { + logicalTextureUnit = mSamplersPS[samplerIndex].logicalTextureUnit; + } + break; + case SAMPLER_VERTEX: + ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0])); + + if (mSamplersVS[samplerIndex].active) + { + logicalTextureUnit = mSamplersVS[samplerIndex].logicalTextureUnit; + } + break; + default: UNREACHABLE(); } - if (logicalTextureUnit >= 0 && logicalTextureUnit < MAX_TEXTURE_IMAGE_UNITS) + if (logicalTextureUnit >= 0 && logicalTextureUnit < (GLint)getContext()->getMaximumCombinedTextureImageUnits()) { return logicalTextureUnit; } @@ -211,52 +248,43 @@ GLint Program::getSamplerMapping(unsigned int samplerIndex) return -1; } -SamplerType Program::getSamplerType(unsigned int samplerIndex) +// Returns the texture type for a given Direct3D 9 sampler type and +// index (0-15 for the pixel shader and 0-3 for the vertex shader). +TextureType Program::getSamplerTextureType(SamplerType type, unsigned int samplerIndex) { - assert(samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0])); - assert(mSamplers[samplerIndex].active); - - return mSamplers[samplerIndex].type; -} - -bool Program::isSamplerDirty(unsigned int samplerIndex) const -{ - if (samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0])) + switch (type) { - return mSamplers[samplerIndex].dirty; + case SAMPLER_PIXEL: + ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0])); + ASSERT(mSamplersPS[samplerIndex].active); + return mSamplersPS[samplerIndex].textureType; + case SAMPLER_VERTEX: + ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0])); + ASSERT(mSamplersVS[samplerIndex].active); + return mSamplersVS[samplerIndex].textureType; + default: UNREACHABLE(); } - else UNREACHABLE(); - - return false; -} -void Program::setSamplerDirty(unsigned int samplerIndex, bool dirty) -{ - if (samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0])) - { - mSamplers[samplerIndex].dirty = dirty; - } - else UNREACHABLE(); + return TEXTURE_2D; } -GLint Program::getUniformLocation(const char *name, bool decorated) +GLint Program::getUniformLocation(std::string name) { - std::string _name = decorated ? name : decorate(name); - int subscript = 0; + unsigned int subscript = 0; // Strip any trailing array operator and retrieve the subscript - size_t open = _name.find_last_of('['); - size_t close = _name.find_last_of(']'); - if (open != std::string::npos && close == _name.length() - 1) + size_t open = name.find_last_of('['); + size_t close = name.find_last_of(']'); + if (open != std::string::npos && close == name.length() - 1) { - subscript = atoi(_name.substr(open + 1).c_str()); - _name.erase(open); + subscript = atoi(name.substr(open + 1).c_str()); + name.erase(open); } unsigned int numUniforms = mUniformIndex.size(); for (unsigned int location = 0; location < numUniforms; location++) { - if (mUniformIndex[location].name == _name && + if (mUniformIndex[location].name == name && mUniformIndex[location].element == subscript) { return location; @@ -285,8 +313,17 @@ bool Program::setUniform1fv(GLint location, GLsizei count, const GLfloat* v) count = std::min(arraySize - (int)mUniformIndex[location].element, count); - memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat), - v, sizeof(GLfloat) * count); + GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4; + + for (int i = 0; i < count; i++) + { + target[0] = v[0]; + target[1] = 0; + target[2] = 0; + target[3] = 0; + target += 4; + v += 1; + } } else if (targetUniform->type == GL_BOOL) { @@ -296,7 +333,7 @@ bool Program::setUniform1fv(GLint location, GLsizei count, const GLfloat* v) return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION count = std::min(arraySize - (int)mUniformIndex[location].element, count); - GLboolean *boolParams = new GLboolean[count]; + GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element; for (int i = 0; i < count; ++i) { @@ -309,11 +346,6 @@ bool Program::setUniform1fv(GLint location, GLsizei count, const GLfloat* v) boolParams[i] = GL_TRUE; } } - - memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean), - boolParams, sizeof(GLboolean) * count); - - delete [] boolParams; } else { @@ -342,8 +374,17 @@ bool Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v) count = std::min(arraySize - (int)mUniformIndex[location].element, count); - memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 2, - v, 2 * sizeof(GLfloat) * count); + GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4; + + for (int i = 0; i < count; i++) + { + target[0] = v[0]; + target[1] = v[1]; + target[2] = 0; + target[3] = 0; + target += 4; + v += 2; + } } else if (targetUniform->type == GL_BOOL_VEC2) { @@ -354,7 +395,7 @@ bool Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v) count = std::min(arraySize - (int)mUniformIndex[location].element, count); - GLboolean *boolParams = new GLboolean[count * 2]; + GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 2; for (int i = 0; i < count * 2; ++i) { @@ -367,11 +408,6 @@ bool Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v) boolParams[i] = GL_TRUE; } } - - memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 2, - boolParams, 2 * sizeof(GLboolean) * count); - - delete [] boolParams; } else { @@ -400,8 +436,17 @@ bool Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v) count = std::min(arraySize - (int)mUniformIndex[location].element, count); - memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 3, - v, 3 * sizeof(GLfloat) * count); + GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4; + + for (int i = 0; i < count; i++) + { + target[0] = v[0]; + target[1] = v[1]; + target[2] = v[2]; + target[3] = 0; + target += 4; + v += 3; + } } else if (targetUniform->type == GL_BOOL_VEC3) { @@ -411,7 +456,7 @@ bool Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v) return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION count = std::min(arraySize - (int)mUniformIndex[location].element, count); - GLboolean *boolParams = new GLboolean[count * 3]; + GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 3; for (int i = 0; i < count * 3; ++i) { @@ -424,11 +469,6 @@ bool Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v) boolParams[i] = GL_TRUE; } } - - memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 3, - boolParams, 3 * sizeof(GLboolean) * count); - - delete [] boolParams; } else { @@ -468,7 +508,7 @@ bool Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v) return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION count = std::min(arraySize - (int)mUniformIndex[location].element, count); - GLboolean *boolParams = new GLboolean[count * 4]; + GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 4; for (int i = 0; i < count * 4; ++i) { @@ -481,11 +521,6 @@ bool Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v) boolParams[i] = GL_TRUE; } } - - memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 4, - boolParams, 4 * sizeof(GLboolean) * count); - - delete [] boolParams; } else { @@ -495,6 +530,37 @@ bool Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v) return true; } +template<typename T, int targetWidth, int targetHeight, int srcWidth, int srcHeight> +void transposeMatrix(T *target, const GLfloat *value) +{ + int copyWidth = std::min(targetWidth, srcWidth); + int copyHeight = std::min(targetHeight, srcHeight); + + for (int x = 0; x < copyWidth; x++) + { + for (int y = 0; y < copyHeight; y++) + { + target[x * targetWidth + y] = (T)value[y * srcWidth + x]; + } + } + // clear unfilled right side + for (int y = 0; y < copyHeight; y++) + { + for (int x = srcWidth; x < targetWidth; x++) + { + target[y * targetWidth + x] = (T)0; + } + } + // clear unfilled bottom. + for (int y = srcHeight; y < targetHeight; y++) + { + for (int x = 0; x < targetWidth; x++) + { + target[y * targetWidth + x] = (T)0; + } + } +} + bool Program::setUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value) { if (location < 0 || location >= (int)mUniformIndex.size()) @@ -517,8 +583,13 @@ bool Program::setUniformMatrix2fv(GLint location, GLsizei count, const GLfloat * count = std::min(arraySize - (int)mUniformIndex[location].element, count); - memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 4, - value, 4 * sizeof(GLfloat) * count); + GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8; + for (int i = 0; i < count; i++) + { + transposeMatrix<GLfloat,4,2,2,2>(target, value); + target += 8; + value += 4; + } return true; } @@ -545,12 +616,18 @@ bool Program::setUniformMatrix3fv(GLint location, GLsizei count, const GLfloat * count = std::min(arraySize - (int)mUniformIndex[location].element, count); - memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 9, - value, 9 * sizeof(GLfloat) * count); + GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12; + for (int i = 0; i < count; i++) + { + transposeMatrix<GLfloat,4,3,3,3>(target, value); + target += 12; + value += 9; + } return true; } + bool Program::setUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value) { if (location < 0 || location >= (int)mUniformIndex.size()) @@ -573,8 +650,13 @@ bool Program::setUniformMatrix4fv(GLint location, GLsizei count, const GLfloat * count = std::min(arraySize - (int)mUniformIndex[location].element, count); - memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 16, - value, 16 * sizeof(GLfloat) * count); + GLfloat *target = (GLfloat*)(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 16); + for (int i = 0; i < count; i++) + { + transposeMatrix<GLfloat,4,4,4,4>(target, value); + target += 16; + value += 16; + } return true; } @@ -611,7 +693,7 @@ bool Program::setUniform1iv(GLint location, GLsizei count, const GLint *v) return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION count = std::min(arraySize - (int)mUniformIndex[location].element, count); - GLboolean *boolParams = new GLboolean[count]; + GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element; for (int i = 0; i < count; ++i) { @@ -624,11 +706,6 @@ bool Program::setUniform1iv(GLint location, GLsizei count, const GLint *v) boolParams[i] = GL_TRUE; } } - - memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean), - boolParams, sizeof(GLboolean) * count); - - delete [] boolParams; } else { @@ -668,7 +745,7 @@ bool Program::setUniform2iv(GLint location, GLsizei count, const GLint *v) return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION count = std::min(arraySize - (int)mUniformIndex[location].element, count); - GLboolean *boolParams = new GLboolean[count * 2]; + GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 2; for (int i = 0; i < count * 2; ++i) { @@ -681,11 +758,6 @@ bool Program::setUniform2iv(GLint location, GLsizei count, const GLint *v) boolParams[i] = GL_TRUE; } } - - memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 2, - boolParams, 2 * sizeof(GLboolean) * count); - - delete [] boolParams; } else { @@ -725,7 +797,7 @@ bool Program::setUniform3iv(GLint location, GLsizei count, const GLint *v) return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION count = std::min(arraySize - (int)mUniformIndex[location].element, count); - GLboolean *boolParams = new GLboolean[count * 3]; + GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 3; for (int i = 0; i < count * 3; ++i) { @@ -738,11 +810,6 @@ bool Program::setUniform3iv(GLint location, GLsizei count, const GLint *v) boolParams[i] = GL_TRUE; } } - - memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 3, - boolParams, 3 * sizeof(GLboolean) * count); - - delete [] boolParams; } else { @@ -782,7 +849,7 @@ bool Program::setUniform4iv(GLint location, GLsizei count, const GLint *v) return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION count = std::min(arraySize - (int)mUniformIndex[location].element, count); - GLboolean *boolParams = new GLboolean[count * 4]; + GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 4; for (int i = 0; i < count * 4; ++i) { @@ -795,11 +862,6 @@ bool Program::setUniform4iv(GLint location, GLsizei count, const GLint *v) boolParams[i] = GL_TRUE; } } - - memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 4, - boolParams, 4 * sizeof(GLboolean) * count); - - delete [] boolParams; } else { @@ -809,7 +871,7 @@ bool Program::setUniform4iv(GLint location, GLsizei count, const GLint *v) return true; } -bool Program::getUniformfv(GLint location, GLfloat *params) +bool Program::getUniformfv(GLint location, GLsizei *bufSize, GLfloat *params) { if (location < 0 || location >= (int)mUniformIndex.size()) { @@ -818,41 +880,67 @@ bool Program::getUniformfv(GLint location, GLfloat *params) Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; - unsigned int count = UniformComponentCount(targetUniform->type); - - switch (UniformComponentType(targetUniform->type)) + // sized queries -- ensure the provided buffer is large enough + if (bufSize) { - case GL_BOOL: + int requiredBytes = UniformExternalSize(targetUniform->type); + if (*bufSize < requiredBytes) { - GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * count; - - for (unsigned int i = 0; i < count; ++i) - { - params[i] = (boolParams[i] == GL_FALSE) ? 0.0f : 1.0f; - } + return false; } + } + + switch (targetUniform->type) + { + case GL_FLOAT_MAT2: + transposeMatrix<GLfloat,2,2,4,2>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8); + break; + case GL_FLOAT_MAT3: + transposeMatrix<GLfloat,3,3,4,3>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12); break; - case GL_FLOAT: - memcpy(params, targetUniform->data + mUniformIndex[location].element * count * sizeof(GLfloat), - count * sizeof(GLfloat)); + case GL_FLOAT_MAT4: + transposeMatrix<GLfloat,4,4,4,4>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 16); break; - case GL_INT: + default: { - GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * count; + unsigned int count = UniformExternalComponentCount(targetUniform->type); + unsigned int internalCount = UniformInternalComponentCount(targetUniform->type); - for (unsigned int i = 0; i < count; ++i) + switch (UniformComponentType(targetUniform->type)) { - params[i] = (float)intParams[i]; + case GL_BOOL: + { + GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * internalCount; + + for (unsigned int i = 0; i < count; ++i) + { + params[i] = (boolParams[i] == GL_FALSE) ? 0.0f : 1.0f; + } + } + break; + case GL_FLOAT: + memcpy(params, targetUniform->data + mUniformIndex[location].element * internalCount * sizeof(GLfloat), + count * sizeof(GLfloat)); + break; + case GL_INT: + { + GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * internalCount; + + for (unsigned int i = 0; i < count; ++i) + { + params[i] = (float)intParams[i]; + } + } + break; + default: UNREACHABLE(); } } - break; - default: UNREACHABLE(); } return true; } -bool Program::getUniformiv(GLint location, GLint *params) +bool Program::getUniformiv(GLint location, GLsizei *bufSize, GLint *params) { if (location < 0 || location >= (int)mUniformIndex.size()) { @@ -861,35 +949,67 @@ bool Program::getUniformiv(GLint location, GLint *params) Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; - unsigned int count = UniformComponentCount(targetUniform->type); - - switch (UniformComponentType(targetUniform->type)) + // sized queries -- ensure the provided buffer is large enough + if (bufSize) { - case GL_BOOL: + int requiredBytes = UniformExternalSize(targetUniform->type); + if (*bufSize < requiredBytes) { - GLboolean *boolParams = targetUniform->data + mUniformIndex[location].element * count; + return false; + } + } - for (unsigned int i = 0; i < count; ++i) - { - params[i] = (GLint)boolParams[i]; - } + switch (targetUniform->type) + { + case GL_FLOAT_MAT2: + { + transposeMatrix<GLint,2,2,4,2>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8); + } + break; + case GL_FLOAT_MAT3: + { + transposeMatrix<GLint,3,3,4,3>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12); } break; - case GL_FLOAT: + case GL_FLOAT_MAT4: + { + transposeMatrix<GLint,4,4,4,4>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 16); + } + break; + default: { - GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * count; + unsigned int count = UniformExternalComponentCount(targetUniform->type); + unsigned int internalCount = UniformInternalComponentCount(targetUniform->type); - for (unsigned int i = 0; i < count; ++i) + switch (UniformComponentType(targetUniform->type)) { - params[i] = (GLint)floatParams[i]; + case GL_BOOL: + { + GLboolean *boolParams = targetUniform->data + mUniformIndex[location].element * internalCount; + + for (unsigned int i = 0; i < count; ++i) + { + params[i] = (GLint)boolParams[i]; + } + } + break; + case GL_FLOAT: + { + GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * internalCount; + + for (unsigned int i = 0; i < count; ++i) + { + params[i] = (GLint)floatParams[i]; + } + } + break; + case GL_INT: + memcpy(params, targetUniform->data + mUniformIndex[location].element * internalCount * sizeof(GLint), + count * sizeof(GLint)); + break; + default: UNREACHABLE(); } } - break; - case GL_INT: - memcpy(params, targetUniform->data + mUniformIndex[location].element * count * sizeof(GLint), - count * sizeof(GLint)); - break; - default: UNREACHABLE(); } return true; @@ -904,26 +1024,11 @@ void Program::dirtyAllUniforms() } } -void Program::dirtyAllSamplers() -{ - for (unsigned int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; ++index) - { - mSamplers[index].dirty = true; - } -} - // Applies all the uniforms set for this program object to the Direct3D 9 device void Program::applyUniforms() { - unsigned int numUniforms = mUniformIndex.size(); - for (unsigned int location = 0; location < numUniforms; location++) - { - if (mUniformIndex[location].element != 0) - { - continue; - } - - Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; + for (std::vector<Uniform*>::iterator ub = mUniforms.begin(), ue = mUniforms.end(); ub != ue; ++ub) { + Uniform *targetUniform = *ub; if (targetUniform->dirty) { @@ -934,23 +1039,23 @@ void Program::applyUniforms() switch (targetUniform->type) { - case GL_BOOL: applyUniform1bv(location, arraySize, b); break; - case GL_BOOL_VEC2: applyUniform2bv(location, arraySize, b); break; - case GL_BOOL_VEC3: applyUniform3bv(location, arraySize, b); break; - case GL_BOOL_VEC4: applyUniform4bv(location, arraySize, b); break; - case GL_FLOAT: applyUniform1fv(location, arraySize, f); break; - case GL_FLOAT_VEC2: applyUniform2fv(location, arraySize, f); break; - case GL_FLOAT_VEC3: applyUniform3fv(location, arraySize, f); break; - case GL_FLOAT_VEC4: applyUniform4fv(location, arraySize, f); break; - case GL_FLOAT_MAT2: applyUniformMatrix2fv(location, arraySize, f); break; - case GL_FLOAT_MAT3: applyUniformMatrix3fv(location, arraySize, f); break; - case GL_FLOAT_MAT4: applyUniformMatrix4fv(location, arraySize, f); break; + case GL_BOOL: applyUniformnbv(targetUniform, arraySize, 1, b); break; + case GL_BOOL_VEC2: applyUniformnbv(targetUniform, arraySize, 2, b); break; + case GL_BOOL_VEC3: applyUniformnbv(targetUniform, arraySize, 3, b); break; + case GL_BOOL_VEC4: applyUniformnbv(targetUniform, arraySize, 4, b); break; + case GL_FLOAT: + case GL_FLOAT_VEC2: + case GL_FLOAT_VEC3: + case GL_FLOAT_VEC4: + case GL_FLOAT_MAT2: + case GL_FLOAT_MAT3: + case GL_FLOAT_MAT4: applyUniformnfv(targetUniform, f); break; case GL_SAMPLER_2D: case GL_SAMPLER_CUBE: - case GL_INT: applyUniform1iv(location, arraySize, i); break; - case GL_INT_VEC2: applyUniform2iv(location, arraySize, i); break; - case GL_INT_VEC3: applyUniform3iv(location, arraySize, i); break; - case GL_INT_VEC4: applyUniform4iv(location, arraySize, i); break; + case GL_INT: applyUniform1iv(targetUniform, arraySize, i); break; + case GL_INT_VEC2: applyUniform2iv(targetUniform, arraySize, i); break; + case GL_INT_VEC3: applyUniform3iv(targetUniform, arraySize, i); break; + case GL_INT_VEC4: applyUniform4iv(targetUniform, arraySize, i); break; default: UNREACHABLE(); } @@ -961,38 +1066,76 @@ void Program::applyUniforms() } // Compiles the HLSL code of the attached shaders into executable binaries -ID3DXBuffer *Program::compileToBinary(const char *hlsl, const char *profile, ID3DXConstantTable **constantTable) +ID3D10Blob *Program::compileToBinary(const char *hlsl, const char *profile, ID3DXConstantTable **constantTable) { if (!hlsl) { return NULL; } - ID3DXBuffer *binary = NULL; - ID3DXBuffer *errorMessage = NULL; - - HRESULT result = D3DXCompileShader(hlsl, (UINT)strlen(hlsl), NULL, NULL, "main", profile, 0, &binary, &errorMessage, constantTable); - - if (SUCCEEDED(result)) + DWORD result; + UINT flags = 0; + std::string sourceText; + if (perfActive()) { - return binary; - } + flags |= D3DCOMPILE_DEBUG; +#ifdef NDEBUG + flags |= ANGLE_COMPILE_OPTIMIZATION_LEVEL; +#else + flags |= D3DCOMPILE_SKIP_OPTIMIZATION; +#endif - if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY) + std::string sourcePath = getTempPath(); + sourceText = std::string("#line 2 \"") + sourcePath + std::string("\"\n\n") + std::string(hlsl); + writeFile(sourcePath.c_str(), sourceText.c_str(), sourceText.size()); + } + else { - return error(GL_OUT_OF_MEMORY, (ID3DXBuffer*)NULL); + flags |= ANGLE_COMPILE_OPTIMIZATION_LEVEL; + sourceText = hlsl; } + ID3D10Blob *binary = NULL; + ID3D10Blob *errorMessage = NULL; + result = D3DCompile(hlsl, strlen(hlsl), fakepath, NULL, NULL, "main", profile, flags, 0, &binary, &errorMessage); + if (errorMessage) { const char *message = (const char*)errorMessage->GetBufferPointer(); - appendToInfoLog("%s\n", message); + appendToInfoLogSanitized(message); TRACE("\n%s", hlsl); TRACE("\n%s", message); + + errorMessage->Release(); + errorMessage = NULL; + } + + if (FAILED(result)) + { + if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY) + { + error(GL_OUT_OF_MEMORY); + } + + return NULL; + } + + result = D3DXGetShaderConstantTable(static_cast<const DWORD*>(binary->GetBufferPointer()), constantTable); + + if (FAILED(result)) + { + if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY) + { + error(GL_OUT_OF_MEMORY); + } + + binary->Release(); + + return NULL; } - return NULL; + return binary; } // Packs varyings into generic varying registers, using the algorithm from [OpenGL ES Shading Language 1.00 rev. 17] appendix A section 7 page 111 @@ -1002,7 +1145,7 @@ int Program::packVaryings(const Varying *packing[][4]) Context *context = getContext(); const int maxVaryingVectors = context->getMaximumVaryingVectors(); - for (VaryingList::iterator varying = mFragmentShader->varyings.begin(); varying != mFragmentShader->varyings.end(); varying++) + for (VaryingList::iterator varying = mFragmentShader->mVaryings.begin(); varying != mFragmentShader->mVaryings.end(); varying++) { int n = VariableRowCount(varying->type) * varying->size; int m = VariableColumnCount(varying->type); @@ -1093,13 +1236,13 @@ int Program::packVaryings(const Varying *packing[][4]) for (int x = 0; x < 4; x++) { - if (space[x] > n && space[x] < space[column]) + if (space[x] >= n && space[x] < space[column]) { column = x; } } - if (space[column] > n) + if (space[column] >= n) { for (int r = 0; r < maxVaryingVectors; r++) { @@ -1152,6 +1295,20 @@ bool Program::linkVaryings() return false; } + // Reset the varying register assignments + for (VaryingList::iterator fragVar = mFragmentShader->mVaryings.begin(); fragVar != mFragmentShader->mVaryings.end(); fragVar++) + { + fragVar->reg = -1; + fragVar->col = -1; + } + + for (VaryingList::iterator vtxVar = mVertexShader->mVaryings.begin(); vtxVar != mVertexShader->mVaryings.end(); vtxVar++) + { + vtxVar->reg = -1; + vtxVar->col = -1; + } + + // Map the varyings to the register file const Varying *packing[MAX_VARYING_VECTORS_SM3][4] = {NULL}; int registers = packVaryings(packing); @@ -1160,6 +1317,7 @@ bool Program::linkVaryings() return false; } + // Write the HLSL input/output declarations Context *context = getContext(); const bool sm3 = context->supportsShaderModel3(); const int maxVaryingVectors = context->getMaximumVaryingVectors(); @@ -1171,11 +1329,11 @@ bool Program::linkVaryings() return false; } - for (VaryingList::iterator input = mFragmentShader->varyings.begin(); input != mFragmentShader->varyings.end(); input++) + for (VaryingList::iterator input = mFragmentShader->mVaryings.begin(); input != mFragmentShader->mVaryings.end(); input++) { bool matched = false; - for (VaryingList::iterator output = mVertexShader->varyings.begin(); output != mVertexShader->varyings.end(); output++) + for (VaryingList::iterator output = mVertexShader->mVaryings.begin(); output != mVertexShader->mVaryings.end(); output++) { if (output->name == input->name) { @@ -1196,7 +1354,7 @@ bool Program::linkVaryings() if (!matched) { - appendToInfoLog("Fragment varying varying %s does not match any vertex varying", input->name.c_str()); + appendToInfoLog("Fragment varying %s does not match any vertex varying", input->name.c_str()); return false; } @@ -1222,7 +1380,7 @@ bool Program::linkVaryings() default: UNREACHABLE(); } - mVertexHLSL += decorate(attribute->name) + " : TEXCOORD" + str(semanticIndex) + ";\n"; + mVertexHLSL += decorateAttribute(attribute->name) + " : TEXCOORD" + str(semanticIndex) + ";\n"; semanticIndex += VariableRowCount(attribute->type); } @@ -1257,14 +1415,14 @@ bool Program::linkVaryings() for (AttributeArray::iterator attribute = mVertexShader->mAttributes.begin(); attribute != mVertexShader->mAttributes.end(); attribute++) { - mVertexHLSL += " " + decorate(attribute->name) + " = "; + mVertexHLSL += " " + decorateAttribute(attribute->name) + " = "; if (VariableRowCount(attribute->type) > 1) // Matrix { mVertexHLSL += "transpose"; } - mVertexHLSL += "(input." + decorate(attribute->name) + ");\n"; + mVertexHLSL += "(input." + decorateAttribute(attribute->name) + ");\n"; } mVertexHLSL += "\n" @@ -1272,7 +1430,7 @@ bool Program::linkVaryings() "\n" " VS_OUTPUT output;\n" " output.gl_Position.x = gl_Position.x - dx_HalfPixelSize.x * gl_Position.w;\n" - " output.gl_Position.y = -(gl_Position.y - dx_HalfPixelSize.y * gl_Position.w);\n" + " output.gl_Position.y = gl_Position.y - dx_HalfPixelSize.y * gl_Position.w;\n" " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n" " output.gl_Position.w = gl_Position.w;\n"; @@ -1286,7 +1444,7 @@ bool Program::linkVaryings() mVertexHLSL += " output.gl_FragCoord = gl_Position;\n"; } - for (VaryingList::iterator varying = mVertexShader->varyings.begin(); varying != mVertexShader->varyings.end(); varying++) + for (VaryingList::iterator varying = mVertexShader->mVaryings.begin(); varying != mVertexShader->mVaryings.end(); varying++) { if (varying->reg >= 0) { @@ -1354,7 +1512,7 @@ bool Program::linkVaryings() mPixelHLSL += "struct PS_INPUT\n" "{\n"; - for (VaryingList::iterator varying = mFragmentShader->varyings.begin(); varying != mFragmentShader->varyings.end(); varying++) + for (VaryingList::iterator varying = mFragmentShader->mVaryings.begin(); varying != mFragmentShader->mVaryings.end(); varying++) { if (varying->reg >= 0) { @@ -1402,20 +1560,27 @@ bool Program::linkVaryings() if (mFragmentShader->mUsesFragCoord) { mPixelHLSL += " float rhw = 1.0 / input.gl_FragCoord.w;\n"; - if (sm3) { - mPixelHLSL += " gl_FragCoord.x = input.dx_VPos.x;\n" - " gl_FragCoord.y = input.dx_VPos.y;\n"; - } else { - mPixelHLSL += " gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * dx_Viewport.x + dx_Viewport.z;\n" - " gl_FragCoord.y = (input.gl_FragCoord.y * rhw) * dx_Viewport.y + dx_Viewport.w;\n"; + + if (sm3) + { + // dx_Coord.y contains the render target height. See Context::applyRenderTarget() + mPixelHLSL += " gl_FragCoord.x = input.dx_VPos.x + 0.5;\n" + " gl_FragCoord.y = dx_Coord.y - input.dx_VPos.y - 0.5;\n"; } + else + { + // dx_Coord contains the viewport width/2, height/2, center.x and center.y. See Context::applyRenderTarget() + mPixelHLSL += " gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * dx_Coord.x + dx_Coord.z;\n" + " gl_FragCoord.y = -(input.gl_FragCoord.y * rhw) * dx_Coord.y + dx_Coord.w;\n"; + } + mPixelHLSL += " gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * dx_Depth.x + dx_Depth.y;\n" " gl_FragCoord.w = rhw;\n"; } if (mFragmentShader->mUsesPointCoord && sm3) { - mPixelHLSL += " gl_PointCoord = float2(input.gl_PointCoord.x, 1.0 - input.gl_PointCoord.y);\n"; + mPixelHLSL += " gl_PointCoord = input.gl_PointCoord;\n"; } if (mFragmentShader->mUsesFrontFacing) @@ -1423,7 +1588,7 @@ bool Program::linkVaryings() mPixelHLSL += " gl_FrontFacing = dx_PointsOrLines || (dx_FrontCCW ? (input.vFace >= 0.0) : (input.vFace <= 0.0));\n"; } - for (VaryingList::iterator varying = mFragmentShader->varyings.begin(); varying != mFragmentShader->varyings.end(); varying++) + for (VaryingList::iterator varying = mFragmentShader->mVaryings.begin(); varying != mFragmentShader->mVaryings.end(); varying++) { if (varying->reg >= 0) { @@ -1461,9 +1626,6 @@ bool Program::linkVaryings() " return output;\n" "}\n"; - TRACE("\n%s", mPixelHLSL.c_str()); - TRACE("\n%s", mVertexHLSL.c_str()); - return true; } @@ -1496,14 +1658,13 @@ void Program::link() const char *vertexProfile = context->supportsShaderModel3() ? "vs_3_0" : "vs_2_0"; const char *pixelProfile = context->supportsShaderModel3() ? "ps_3_0" : "ps_2_0"; - ID3DXBuffer *vertexBinary = compileToBinary(mVertexHLSL.c_str(), vertexProfile, &mConstantTableVS); - ID3DXBuffer *pixelBinary = compileToBinary(mPixelHLSL.c_str(), pixelProfile, &mConstantTablePS); + ID3D10Blob *vertexBinary = compileToBinary(mVertexHLSL.c_str(), vertexProfile, &mConstantTableVS); + ID3D10Blob *pixelBinary = compileToBinary(mPixelHLSL.c_str(), pixelProfile, &mConstantTablePS); if (vertexBinary && pixelBinary) { - IDirect3DDevice9 *device = getDevice(); - HRESULT vertexResult = device->CreateVertexShader((DWORD*)vertexBinary->GetBufferPointer(), &mVertexExecutable); - HRESULT pixelResult = device->CreatePixelShader((DWORD*)pixelBinary->GetBufferPointer(), &mPixelExecutable); + HRESULT vertexResult = mDevice->CreateVertexShader((DWORD*)vertexBinary->GetBufferPointer(), &mVertexExecutable); + HRESULT pixelResult = mDevice->CreatePixelShader((DWORD*)pixelBinary->GetBufferPointer(), &mPixelExecutable); if (vertexResult == D3DERR_OUTOFVIDEOMEMORY || vertexResult == E_OUTOFMEMORY || pixelResult == D3DERR_OUTOFVIDEOMEMORY || pixelResult == E_OUTOFMEMORY) { @@ -1536,12 +1697,12 @@ void Program::link() // these uniforms are searched as already-decorated because gl_ and dx_ // are reserved prefixes, and do not receive additional decoration - mDxDepthRangeLocation = getUniformLocation("dx_DepthRange", true); - mDxDepthLocation = getUniformLocation("dx_Depth", true); - mDxViewportLocation = getUniformLocation("dx_Viewport", true); - mDxHalfPixelSizeLocation = getUniformLocation("dx_HalfPixelSize", true); - mDxFrontCCWLocation = getUniformLocation("dx_FrontCCW", true); - mDxPointsOrLinesLocation = getUniformLocation("dx_PointsOrLines", true); + mDxDepthRangeLocation = getUniformLocation("dx_DepthRange"); + mDxDepthLocation = getUniformLocation("dx_Depth"); + mDxCoordLocation = getUniformLocation("dx_Coord"); + mDxHalfPixelSizeLocation = getUniformLocation("dx_HalfPixelSize"); + mDxFrontCCWLocation = getUniformLocation("dx_FrontCCW"); + mDxPointsOrLinesLocation = getUniformLocation("dx_PointsOrLines"); mLinked = true; // Success } @@ -1642,7 +1803,8 @@ bool Program::linkUniforms(ID3DXConstantTable *constantTable) for (unsigned int constantIndex = 0; constantIndex < constantTableDescription.Constants; constantIndex++) { D3DXHANDLE constantHandle = constantTable->GetConstant(0, constantIndex); - constantTable->GetConstantDesc(constantHandle, &constantDescription, &descriptionCount); + HRESULT result = constantTable->GetConstantDesc(constantHandle, &constantDescription, &descriptionCount); + ASSERT(SUCCEEDED(result)); if (!defineUniform(constantHandle, constantDescription)) { @@ -1659,14 +1821,46 @@ bool Program::defineUniform(const D3DXHANDLE &constantHandle, const D3DXCONSTANT { if (constantDescription.RegisterSet == D3DXRS_SAMPLER) { - for (unsigned int samplerIndex = constantDescription.RegisterIndex; samplerIndex < constantDescription.RegisterIndex + constantDescription.RegisterCount; samplerIndex++) + for (unsigned int i = 0; i < constantDescription.RegisterCount; i++) { - ASSERT(samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0])); + D3DXHANDLE psConstant = mConstantTablePS->GetConstantByName(NULL, constantDescription.Name); + D3DXHANDLE vsConstant = mConstantTableVS->GetConstantByName(NULL, constantDescription.Name); - mSamplers[samplerIndex].active = true; - mSamplers[samplerIndex].type = (constantDescription.Type == D3DXPT_SAMPLERCUBE) ? SAMPLER_CUBE : SAMPLER_2D; - mSamplers[samplerIndex].logicalTextureUnit = 0; - mSamplers[samplerIndex].dirty = true; + if (psConstant) + { + unsigned int samplerIndex = mConstantTablePS->GetSamplerIndex(psConstant) + i; + + if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS) + { + mSamplersPS[samplerIndex].active = true; + mSamplersPS[samplerIndex].textureType = (constantDescription.Type == D3DXPT_SAMPLERCUBE) ? TEXTURE_CUBE : TEXTURE_2D; + mSamplersPS[samplerIndex].logicalTextureUnit = 0; + mUsedPixelSamplerRange = std::max(samplerIndex + 1, mUsedPixelSamplerRange); + } + else + { + appendToInfoLog("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", MAX_TEXTURE_IMAGE_UNITS); + return false; + } + } + + if (vsConstant) + { + unsigned int samplerIndex = mConstantTableVS->GetSamplerIndex(vsConstant) + i; + + if (samplerIndex < getContext()->getMaximumVertexTextureImageUnits()) + { + mSamplersVS[samplerIndex].active = true; + mSamplersVS[samplerIndex].textureType = (constantDescription.Type == D3DXPT_SAMPLERCUBE) ? TEXTURE_CUBE : TEXTURE_2D; + mSamplersVS[samplerIndex].logicalTextureUnit = 0; + mUsedVertexSamplerRange = std::max(samplerIndex + 1, mUsedVertexSamplerRange); + } + else + { + appendToInfoLog("Vertex shader sampler count exceeds MAX_VERTEX_TEXTURE_IMAGE_UNITS (%d).", getContext()->getMaximumVertexTextureImageUnits()); + return false; + } + } } } @@ -1683,7 +1877,8 @@ bool Program::defineUniform(const D3DXHANDLE &constantHandle, const D3DXCONSTANT D3DXCONSTANT_DESC fieldDescription; UINT descriptionCount = 1; - mConstantTablePS->GetConstantDesc(fieldHandle, &fieldDescription, &descriptionCount); + HRESULT result = mConstantTablePS->GetConstantDesc(fieldHandle, &fieldDescription, &descriptionCount); + ASSERT(SUCCEEDED(result)); std::string structIndex = (constantDescription.Elements > 1) ? ("[" + str(arrayIndex) + "]") : ""; @@ -1707,9 +1902,9 @@ bool Program::defineUniform(const D3DXHANDLE &constantHandle, const D3DXCONSTANT } } -bool Program::defineUniform(const D3DXCONSTANT_DESC &constantDescription, std::string &name) +bool Program::defineUniform(const D3DXCONSTANT_DESC &constantDescription, const std::string &_name) { - Uniform *uniform = createUniform(constantDescription, name); + Uniform *uniform = createUniform(constantDescription, _name); if(!uniform) { @@ -1717,7 +1912,7 @@ bool Program::defineUniform(const D3DXCONSTANT_DESC &constantDescription, std::s } // Check if already defined - GLint location = getUniformLocation(name.c_str(), true); + GLint location = getUniformLocation(uniform->name); GLenum type = uniform->type; if (location >= 0) @@ -1734,18 +1929,21 @@ bool Program::defineUniform(const D3DXCONSTANT_DESC &constantDescription, std::s } } + initializeConstantHandles(uniform, &uniform->ps, mConstantTablePS); + initializeConstantHandles(uniform, &uniform->vs, mConstantTableVS); + mUniforms.push_back(uniform); unsigned int uniformIndex = mUniforms.size() - 1; for (unsigned int i = 0; i < uniform->arraySize; ++i) { - mUniformIndex.push_back(UniformLocation(name, i, uniformIndex)); + mUniformIndex.push_back(UniformLocation(_name, i, uniformIndex)); } return true; } -Uniform *Program::createUniform(const D3DXCONSTANT_DESC &constantDescription, std::string &name) +Uniform *Program::createUniform(const D3DXCONSTANT_DESC &constantDescription, const std::string &_name) { if (constantDescription.Rows == 1) // Vectors and scalars { @@ -1754,44 +1952,44 @@ Uniform *Program::createUniform(const D3DXCONSTANT_DESC &constantDescription, st case D3DXPT_SAMPLER2D: switch (constantDescription.Columns) { - case 1: return new Uniform(GL_SAMPLER_2D, name, constantDescription.Elements); + case 1: return new Uniform(GL_SAMPLER_2D, _name, constantDescription.Elements); default: UNREACHABLE(); } break; case D3DXPT_SAMPLERCUBE: switch (constantDescription.Columns) { - case 1: return new Uniform(GL_SAMPLER_CUBE, name, constantDescription.Elements); + case 1: return new Uniform(GL_SAMPLER_CUBE, _name, constantDescription.Elements); default: UNREACHABLE(); } break; case D3DXPT_BOOL: switch (constantDescription.Columns) { - case 1: return new Uniform(GL_BOOL, name, constantDescription.Elements); - case 2: return new Uniform(GL_BOOL_VEC2, name, constantDescription.Elements); - case 3: return new Uniform(GL_BOOL_VEC3, name, constantDescription.Elements); - case 4: return new Uniform(GL_BOOL_VEC4, name, constantDescription.Elements); + case 1: return new Uniform(GL_BOOL, _name, constantDescription.Elements); + case 2: return new Uniform(GL_BOOL_VEC2, _name, constantDescription.Elements); + case 3: return new Uniform(GL_BOOL_VEC3, _name, constantDescription.Elements); + case 4: return new Uniform(GL_BOOL_VEC4, _name, constantDescription.Elements); default: UNREACHABLE(); } break; case D3DXPT_INT: switch (constantDescription.Columns) { - case 1: return new Uniform(GL_INT, name, constantDescription.Elements); - case 2: return new Uniform(GL_INT_VEC2, name, constantDescription.Elements); - case 3: return new Uniform(GL_INT_VEC3, name, constantDescription.Elements); - case 4: return new Uniform(GL_INT_VEC4, name, constantDescription.Elements); + case 1: return new Uniform(GL_INT, _name, constantDescription.Elements); + case 2: return new Uniform(GL_INT_VEC2, _name, constantDescription.Elements); + case 3: return new Uniform(GL_INT_VEC3, _name, constantDescription.Elements); + case 4: return new Uniform(GL_INT_VEC4, _name, constantDescription.Elements); default: UNREACHABLE(); } break; case D3DXPT_FLOAT: switch (constantDescription.Columns) { - case 1: return new Uniform(GL_FLOAT, name, constantDescription.Elements); - case 2: return new Uniform(GL_FLOAT_VEC2, name, constantDescription.Elements); - case 3: return new Uniform(GL_FLOAT_VEC3, name, constantDescription.Elements); - case 4: return new Uniform(GL_FLOAT_VEC4, name, constantDescription.Elements); + case 1: return new Uniform(GL_FLOAT, _name, constantDescription.Elements); + case 2: return new Uniform(GL_FLOAT_VEC2, _name, constantDescription.Elements); + case 3: return new Uniform(GL_FLOAT_VEC3, _name, constantDescription.Elements); + case 4: return new Uniform(GL_FLOAT_VEC4, _name, constantDescription.Elements); default: UNREACHABLE(); } break; @@ -1806,9 +2004,9 @@ Uniform *Program::createUniform(const D3DXCONSTANT_DESC &constantDescription, st case D3DXPT_FLOAT: switch (constantDescription.Rows) { - case 2: return new Uniform(GL_FLOAT_MAT2, name, constantDescription.Elements); - case 3: return new Uniform(GL_FLOAT_MAT3, name, constantDescription.Elements); - case 4: return new Uniform(GL_FLOAT_MAT4, name, constantDescription.Elements); + case 2: return new Uniform(GL_FLOAT_MAT2, _name, constantDescription.Elements); + case 3: return new Uniform(GL_FLOAT_MAT3, _name, constantDescription.Elements); + case 4: return new Uniform(GL_FLOAT_MAT4, _name, constantDescription.Elements); default: UNREACHABLE(); } break; @@ -1821,410 +2019,125 @@ Uniform *Program::createUniform(const D3DXCONSTANT_DESC &constantDescription, st } // This method needs to match OutputHLSL::decorate -std::string Program::decorate(const std::string &string) -{ - if (string.substr(0, 3) != "gl_" && string.substr(0, 3) != "dx_") - { - return "_" + string; - } - else - { - return string; - } -} - -std::string Program::undecorate(const std::string &string) +std::string Program::decorateAttribute(const std::string &name) { - if (string.substr(0, 1) == "_") + if (name.compare(0, 3, "gl_") != 0 && name.compare(0, 3, "dx_") != 0) { - return string.substr(1); + return "_" + name; } - else - { - return string; - } -} - -bool Program::applyUniform1bv(GLint location, GLsizei count, const GLboolean *v) -{ - BOOL *vector = new BOOL[count]; - for (int i = 0; i < count; i++) - { - if (v[i] == GL_FALSE) - vector[i] = 0; - else - vector[i] = 1; - } - - Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; - - D3DXHANDLE constantPS; - D3DXHANDLE constantVS; - getConstantHandles(targetUniform, &constantPS, &constantVS); - - IDirect3DDevice9 *device = getDevice(); - - if (constantPS) - { - mConstantTablePS->SetBoolArray(device, constantPS, vector, count); - } - - if (constantVS) - { - mConstantTableVS->SetBoolArray(device, constantVS, vector, count); - } - - delete [] vector; - - return true; -} - -bool Program::applyUniform2bv(GLint location, GLsizei count, const GLboolean *v) -{ - D3DXVECTOR4 *vector = new D3DXVECTOR4[count]; - - for (int i = 0; i < count; i++) - { - vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f), - (v[1] == GL_FALSE ? 0.0f : 1.0f), 0, 0); - - v += 2; - } - - Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; - - D3DXHANDLE constantPS; - D3DXHANDLE constantVS; - getConstantHandles(targetUniform, &constantPS, &constantVS); - IDirect3DDevice9 *device = getDevice(); - - if (constantPS) - { - mConstantTablePS->SetVectorArray(device, constantPS, vector, count); - } - - if (constantVS) - { - mConstantTableVS->SetVectorArray(device, constantVS, vector, count); - } - - delete[] vector; - - return true; -} - -bool Program::applyUniform3bv(GLint location, GLsizei count, const GLboolean *v) -{ - D3DXVECTOR4 *vector = new D3DXVECTOR4[count]; - - for (int i = 0; i < count; i++) - { - vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f), - (v[1] == GL_FALSE ? 0.0f : 1.0f), - (v[2] == GL_FALSE ? 0.0f : 1.0f), 0); - - v += 3; - } - - Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; - - D3DXHANDLE constantPS; - D3DXHANDLE constantVS; - getConstantHandles(targetUniform, &constantPS, &constantVS); - IDirect3DDevice9 *device = getDevice(); - - if (constantPS) - { - mConstantTablePS->SetVectorArray(device, constantPS, vector, count); - } - - if (constantVS) - { - mConstantTableVS->SetVectorArray(device, constantVS, vector, count); - } - - delete[] vector; - - return true; -} - -bool Program::applyUniform4bv(GLint location, GLsizei count, const GLboolean *v) -{ - D3DXVECTOR4 *vector = new D3DXVECTOR4[count]; - - for (int i = 0; i < count; i++) - { - vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f), - (v[1] == GL_FALSE ? 0.0f : 1.0f), - (v[2] == GL_FALSE ? 0.0f : 1.0f), - (v[3] == GL_FALSE ? 0.0f : 1.0f)); - - v += 3; - } - - Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; - - D3DXHANDLE constantPS; - D3DXHANDLE constantVS; - getConstantHandles(targetUniform, &constantPS, &constantVS); - IDirect3DDevice9 *device = getDevice(); - - if (constantPS) - { - mConstantTablePS->SetVectorArray(device, constantPS, vector, count); - } - - if (constantVS) - { - mConstantTableVS->SetVectorArray(device, constantVS, vector, count); - } - - delete [] vector; - - return true; -} - -bool Program::applyUniform1fv(GLint location, GLsizei count, const GLfloat *v) -{ - Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; - - D3DXHANDLE constantPS; - D3DXHANDLE constantVS; - getConstantHandles(targetUniform, &constantPS, &constantVS); - IDirect3DDevice9 *device = getDevice(); - - if (constantPS) - { - mConstantTablePS->SetFloatArray(device, constantPS, v, count); - } - - if (constantVS) - { - mConstantTableVS->SetFloatArray(device, constantVS, v, count); - } - - return true; + + return name; } -bool Program::applyUniform2fv(GLint location, GLsizei count, const GLfloat *v) +std::string Program::undecorateUniform(const std::string &_name) { - D3DXVECTOR4 *vector = new D3DXVECTOR4[count]; - - for (int i = 0; i < count; i++) + if (_name[0] == '_') { - vector[i] = D3DXVECTOR4(v[0], v[1], 0, 0); - - v += 2; + return _name.substr(1); } - - Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; - - D3DXHANDLE constantPS; - D3DXHANDLE constantVS; - getConstantHandles(targetUniform, &constantPS, &constantVS); - IDirect3DDevice9 *device = getDevice(); - - if (constantPS) - { - mConstantTablePS->SetVectorArray(device, constantPS, vector, count); - } - - if (constantVS) + else if (_name.compare(0, 3, "ar_") == 0) { - mConstantTableVS->SetVectorArray(device, constantVS, vector, count); + return _name.substr(3); } - - delete[] vector; - - return true; + + return _name; } -bool Program::applyUniform3fv(GLint location, GLsizei count, const GLfloat *v) +void Program::applyUniformnbv(Uniform *targetUniform, GLsizei count, int width, const GLboolean *v) { - D3DXVECTOR4 *vector = new D3DXVECTOR4[count]; + float vector[D3D9_MAX_FLOAT_CONSTANTS * 4]; + BOOL boolVector[D3D9_MAX_BOOL_CONSTANTS]; - for (int i = 0; i < count; i++) + if (targetUniform->ps.registerCount && targetUniform->ps.registerSet == D3DXRS_FLOAT4 || + targetUniform->vs.registerCount && targetUniform->vs.registerSet == D3DXRS_FLOAT4) { - vector[i] = D3DXVECTOR4(v[0], v[1], v[2], 0); - - v += 3; - } - - Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; - - D3DXHANDLE constantPS; - D3DXHANDLE constantVS; - getConstantHandles(targetUniform, &constantPS, &constantVS); - IDirect3DDevice9 *device = getDevice(); - - if (constantPS) - { - mConstantTablePS->SetVectorArray(device, constantPS, vector, count); + ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS); + for (int i = 0; i < count; i++) + { + for (int j = 0; j < 4; j++) + { + if (j < width) + { + vector[i * 4 + j] = (v[i * width + j] == GL_FALSE) ? 0.0f : 1.0f; + } + else + { + vector[i * 4 + j] = 0.0f; + } + } + } } - if (constantVS) + if (targetUniform->ps.registerCount && targetUniform->ps.registerSet == D3DXRS_BOOL || + targetUniform->vs.registerCount && targetUniform->vs.registerSet == D3DXRS_BOOL) { - mConstantTableVS->SetVectorArray(device, constantVS, vector, count); + int psCount = targetUniform->ps.registerSet == D3DXRS_BOOL ? targetUniform->ps.registerCount : 0; + int vsCount = targetUniform->vs.registerSet == D3DXRS_BOOL ? targetUniform->vs.registerCount : 0; + int copyCount = std::min(count * width, std::max(psCount, vsCount)); + ASSERT(copyCount <= D3D9_MAX_BOOL_CONSTANTS); + for (int i = 0; i < copyCount; i++) + { + boolVector[i] = v[i] != GL_FALSE; + } } - delete[] vector; - - return true; -} - -bool Program::applyUniform4fv(GLint location, GLsizei count, const GLfloat *v) -{ - Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; - - D3DXHANDLE constantPS; - D3DXHANDLE constantVS; - getConstantHandles(targetUniform, &constantPS, &constantVS); - IDirect3DDevice9 *device = getDevice(); - - if (constantPS) + if (targetUniform->ps.registerCount) { - mConstantTablePS->SetVectorArray(device, constantPS, (D3DXVECTOR4*)v, count); + if (targetUniform->ps.registerSet == D3DXRS_FLOAT4) + { + mDevice->SetPixelShaderConstantF(targetUniform->ps.registerIndex, vector, targetUniform->ps.registerCount); + } + else if (targetUniform->ps.registerSet == D3DXRS_BOOL) + { + mDevice->SetPixelShaderConstantB(targetUniform->ps.registerIndex, boolVector, targetUniform->ps.registerCount); + } + else UNREACHABLE(); } - if (constantVS) + if (targetUniform->vs.registerCount) { - mConstantTableVS->SetVectorArray(device, constantVS, (D3DXVECTOR4*)v, count); + if (targetUniform->vs.registerSet == D3DXRS_FLOAT4) + { + mDevice->SetVertexShaderConstantF(targetUniform->vs.registerIndex, vector, targetUniform->vs.registerCount); + } + else if (targetUniform->vs.registerSet == D3DXRS_BOOL) + { + mDevice->SetVertexShaderConstantB(targetUniform->vs.registerIndex, boolVector, targetUniform->vs.registerCount); + } + else UNREACHABLE(); } - - return true; } -bool Program::applyUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value) +bool Program::applyUniformnfv(Uniform *targetUniform, const GLfloat *v) { - D3DXMATRIX *matrix = new D3DXMATRIX[count]; - - for (int i = 0; i < count; i++) + if (targetUniform->ps.registerCount) { - matrix[i] = D3DXMATRIX(value[0], value[2], 0, 0, - value[1], value[3], 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1); - - value += 4; - } - - Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; - - D3DXHANDLE constantPS; - D3DXHANDLE constantVS; - getConstantHandles(targetUniform, &constantPS, &constantVS); - IDirect3DDevice9 *device = getDevice(); - - if (constantPS) - { - mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count); + mDevice->SetPixelShaderConstantF(targetUniform->ps.registerIndex, v, targetUniform->ps.registerCount); } - if (constantVS) + if (targetUniform->vs.registerCount) { - mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count); + mDevice->SetVertexShaderConstantF(targetUniform->vs.registerIndex, v, targetUniform->vs.registerCount); } - delete[] matrix; - return true; } -bool Program::applyUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value) +bool Program::applyUniform1iv(Uniform *targetUniform, GLsizei count, const GLint *v) { - D3DXMATRIX *matrix = new D3DXMATRIX[count]; + ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS); + D3DXVECTOR4 vector[D3D9_MAX_FLOAT_CONSTANTS]; for (int i = 0; i < count; i++) { - matrix[i] = D3DXMATRIX(value[0], value[3], value[6], 0, - value[1], value[4], value[7], 0, - value[2], value[5], value[8], 0, - 0, 0, 0, 1); - - value += 9; - } - - Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; - - D3DXHANDLE constantPS; - D3DXHANDLE constantVS; - getConstantHandles(targetUniform, &constantPS, &constantVS); - IDirect3DDevice9 *device = getDevice(); - - if (constantPS) - { - mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count); + vector[i] = D3DXVECTOR4((float)v[i], 0, 0, 0); } - if (constantVS) + if (targetUniform->ps.registerCount) { - mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count); - } - - delete[] matrix; - - return true; -} - -bool Program::applyUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value) -{ - D3DXMATRIX *matrix = new D3DXMATRIX[count]; - - for (int i = 0; i < count; i++) - { - matrix[i] = D3DXMATRIX(value[0], value[4], value[8], value[12], - value[1], value[5], value[9], value[13], - value[2], value[6], value[10], value[14], - value[3], value[7], value[11], value[15]); - - value += 16; - } - - Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; - - D3DXHANDLE constantPS; - D3DXHANDLE constantVS; - getConstantHandles(targetUniform, &constantPS, &constantVS); - IDirect3DDevice9 *device = getDevice(); - - if (constantPS) - { - mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count); - } - - if (constantVS) - { - mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count); - } - - delete[] matrix; - - return true; -} - -bool Program::applyUniform1iv(GLint location, GLsizei count, const GLint *v) -{ - Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; - - D3DXHANDLE constantPS; - D3DXHANDLE constantVS; - getConstantHandles(targetUniform, &constantPS, &constantVS); - IDirect3DDevice9 *device = getDevice(); - - if (constantPS) - { - D3DXCONSTANT_DESC constantDescription; - UINT descriptionCount = 1; - HRESULT result = mConstantTablePS->GetConstantDesc(constantPS, &constantDescription, &descriptionCount); - - if (FAILED(result)) - { - return false; - } - - if (constantDescription.RegisterSet == D3DXRS_SAMPLER) + if (targetUniform->ps.registerSet == D3DXRS_SAMPLER) { - unsigned int firstIndex = mConstantTablePS->GetSamplerIndex(constantPS); + unsigned int firstIndex = targetUniform->ps.registerIndex; for (int i = 0; i < count; i++) { @@ -2232,32 +2145,49 @@ bool Program::applyUniform1iv(GLint location, GLsizei count, const GLint *v) if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS) { - ASSERT(mSamplers[samplerIndex].active); - mSamplers[samplerIndex].logicalTextureUnit = v[i]; - mSamplers[samplerIndex].dirty = true; + ASSERT(mSamplersPS[samplerIndex].active); + mSamplersPS[samplerIndex].logicalTextureUnit = v[i]; } } - - return true; + } + else + { + ASSERT(targetUniform->ps.registerSet == D3DXRS_FLOAT4); + mDevice->SetPixelShaderConstantF(targetUniform->ps.registerIndex, (const float*)vector, targetUniform->ps.registerCount); } } - if (constantPS) + if (targetUniform->vs.registerCount) { - mConstantTablePS->SetIntArray(device, constantPS, v, count); - } + if (targetUniform->vs.registerSet == D3DXRS_SAMPLER) + { + unsigned int firstIndex = targetUniform->vs.registerIndex; - if (constantVS) - { - mConstantTableVS->SetIntArray(device, constantVS, v, count); + for (int i = 0; i < count; i++) + { + unsigned int samplerIndex = firstIndex + i; + + if (samplerIndex < MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF) + { + ASSERT(mSamplersVS[samplerIndex].active); + mSamplersVS[samplerIndex].logicalTextureUnit = v[i]; + } + } + } + else + { + ASSERT(targetUniform->vs.registerSet == D3DXRS_FLOAT4); + mDevice->SetVertexShaderConstantF(targetUniform->vs.registerIndex, (const float *)vector, targetUniform->vs.registerCount); + } } return true; } -bool Program::applyUniform2iv(GLint location, GLsizei count, const GLint *v) +bool Program::applyUniform2iv(Uniform *targetUniform, GLsizei count, const GLint *v) { - D3DXVECTOR4 *vector = new D3DXVECTOR4[count]; + ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS); + D3DXVECTOR4 vector[D3D9_MAX_FLOAT_CONSTANTS]; for (int i = 0; i < count; i++) { @@ -2266,31 +2196,15 @@ bool Program::applyUniform2iv(GLint location, GLsizei count, const GLint *v) v += 2; } - Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; - - D3DXHANDLE constantPS; - D3DXHANDLE constantVS; - getConstantHandles(targetUniform, &constantPS, &constantVS); - IDirect3DDevice9 *device = getDevice(); - - if (constantPS) - { - mConstantTablePS->SetVectorArray(device, constantPS, vector, count); - } - - if (constantVS) - { - mConstantTableVS->SetVectorArray(device, constantVS, vector, count); - } - - delete[] vector; + applyUniformniv(targetUniform, count, vector); return true; } -bool Program::applyUniform3iv(GLint location, GLsizei count, const GLint *v) +bool Program::applyUniform3iv(Uniform *targetUniform, GLsizei count, const GLint *v) { - D3DXVECTOR4 *vector = new D3DXVECTOR4[count]; + ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS); + D3DXVECTOR4 vector[D3D9_MAX_FLOAT_CONSTANTS]; for (int i = 0; i < count; i++) { @@ -2299,31 +2213,15 @@ bool Program::applyUniform3iv(GLint location, GLsizei count, const GLint *v) v += 3; } - Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; - - D3DXHANDLE constantPS; - D3DXHANDLE constantVS; - getConstantHandles(targetUniform, &constantPS, &constantVS); - IDirect3DDevice9 *device = getDevice(); - - if (constantPS) - { - mConstantTablePS->SetVectorArray(device, constantPS, vector, count); - } - - if (constantVS) - { - mConstantTableVS->SetVectorArray(device, constantVS, vector, count); - } - - delete[] vector; + applyUniformniv(targetUniform, count, vector); return true; } -bool Program::applyUniform4iv(GLint location, GLsizei count, const GLint *v) +bool Program::applyUniform4iv(Uniform *targetUniform, GLsizei count, const GLint *v) { - D3DXVECTOR4 *vector = new D3DXVECTOR4[count]; + ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS); + D3DXVECTOR4 vector[D3D9_MAX_FLOAT_CONSTANTS]; for (int i = 0; i < count; i++) { @@ -2332,26 +2230,45 @@ bool Program::applyUniform4iv(GLint location, GLsizei count, const GLint *v) v += 4; } - Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; + applyUniformniv(targetUniform, count, vector); - D3DXHANDLE constantPS; - D3DXHANDLE constantVS; - getConstantHandles(targetUniform, &constantPS, &constantVS); - IDirect3DDevice9 *device = getDevice(); + return true; +} - if (constantPS) +void Program::applyUniformniv(Uniform *targetUniform, GLsizei count, const D3DXVECTOR4 *vector) +{ + if (targetUniform->ps.registerCount) { - mConstantTablePS->SetVectorArray(device, constantPS, vector, count); + ASSERT(targetUniform->ps.registerSet == D3DXRS_FLOAT4); + mDevice->SetPixelShaderConstantF(targetUniform->ps.registerIndex, (const float *)vector, targetUniform->ps.registerCount); } - if (constantVS) + if (targetUniform->vs.registerCount) { - mConstantTableVS->SetVectorArray(device, constantVS, vector, count); + ASSERT(targetUniform->vs.registerSet == D3DXRS_FLOAT4); + mDevice->SetVertexShaderConstantF(targetUniform->vs.registerIndex, (const float *)vector, targetUniform->vs.registerCount); } +} - delete [] vector; +// append a santized message to the program info log. +// The D3D compiler includes a fake file path in some of the warning or error +// messages, so lets remove all occurrences of this fake file path from the log. +void Program::appendToInfoLogSanitized(const char *message) +{ + std::string msg(message); - return true; + size_t found; + do + { + found = msg.find(fakepath); + if (found != std::string::npos) + { + msg.erase(found, strlen(fakepath)); + } + } + while (found != std::string::npos); + + appendToInfoLog("%s\n", msg.c_str()); } void Program::appendToInfoLog(const char *format, ...) @@ -2396,7 +2313,7 @@ void Program::resetInfoLog() } } -// Returns the program object to an unlinked state, after detaching a shader, before re-linking, or at destruction +// Returns the program object to an unlinked state, before re-linking, or at destruction void Program::unlink(bool destroy) { if (destroy) // Object being destructed @@ -2446,10 +2363,17 @@ void Program::unlink(bool destroy) for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++) { - mSamplers[index].active = false; - mSamplers[index].dirty = true; + mSamplersPS[index].active = false; } + for (int index = 0; index < MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF; index++) + { + mSamplersVS[index].active = false; + } + + mUsedVertexSamplerRange = 0; + mUsedPixelSamplerRange = 0; + while (!mUniforms.empty()) { delete mUniforms.back(); @@ -2458,7 +2382,7 @@ void Program::unlink(bool destroy) mDxDepthRangeLocation = -1; mDxDepthLocation = -1; - mDxViewportLocation = -1; + mDxCoordLocation = -1; mDxHalfPixelSizeLocation = -1; mDxFrontCCWLocation = -1; mDxPointsOrLinesLocation = -1; @@ -2532,11 +2456,8 @@ void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) if (mInfoLog) { - while (index < bufSize - 1 && index < (int)strlen(mInfoLog)) - { - infoLog[index] = mInfoLog[index]; - index++; - } + index = std::min(bufSize - 1, (int)strlen(mInfoLog)); + memcpy(infoLog, mInfoLog, index); } if (bufSize) @@ -2655,7 +2576,7 @@ void Program::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, G unsigned int uniform; for (uniform = 0; uniform < mUniforms.size(); uniform++) { - if (mUniforms[uniform]->name.substr(0, 3) == "dx_") + if (mUniforms[uniform]->name.compare(0, 3, "dx_") == 0) { continue; } @@ -2672,9 +2593,9 @@ void Program::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, G if (bufsize > 0) { - std::string string = undecorate(mUniforms[uniform]->name); + std::string string = mUniforms[uniform]->name; - if (mUniforms[uniform]->arraySize != 1) + if (mUniforms[uniform]->isArray()) { string += "[0]"; } @@ -2700,7 +2621,7 @@ GLint Program::getActiveUniformCount() unsigned int numUniforms = mUniforms.size(); for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++) { - if (mUniforms[uniformIndex]->name.substr(0, 3) != "dx_") + if (mUniforms[uniformIndex]->name.compare(0, 3, "dx_") != 0) { count++; } @@ -2716,9 +2637,14 @@ GLint Program::getActiveUniformMaxLength() unsigned int numUniforms = mUniforms.size(); for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++) { - if (!mUniforms[uniformIndex]->name.empty() && mUniforms[uniformIndex]->name.substr(0, 3) != "dx_") + if (!mUniforms[uniformIndex]->name.empty() && mUniforms[uniformIndex]->name.compare(0, 3, "dx_") != 0) { - maxLength = std::max((int)(undecorate(mUniforms[uniformIndex]->name).length() + 1), maxLength); + int length = (int)(mUniforms[uniformIndex]->name.length() + 1); + if (mUniforms[uniformIndex]->isArray()) + { + length += 3; // Counting in "[0]". + } + maxLength = std::max(length, maxLength); } } @@ -2747,9 +2673,8 @@ void Program::validate() else { applyUniforms(); - if (!validateSamplers()) + if (!validateSamplers(true)) { - appendToInfoLog("Samplers of conflicting types refer to the same texture image unit."); mValidated = false; } else @@ -2759,24 +2684,86 @@ void Program::validate() } } -bool Program::validateSamplers() const +bool Program::validateSamplers(bool logErrors) { // if any two active samplers in a program are of different types, but refer to the same // texture image unit, and this is the current program, then ValidateProgram will fail, and // DrawArrays and DrawElements will issue the INVALID_OPERATION error. - std::map<int, SamplerType> samplerMap; - for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i) + + const unsigned int maxCombinedTextureImageUnits = getContext()->getMaximumCombinedTextureImageUnits(); + TextureType textureUnitType[MAX_COMBINED_TEXTURE_IMAGE_UNITS_VTF]; + + for (unsigned int i = 0; i < MAX_COMBINED_TEXTURE_IMAGE_UNITS_VTF; ++i) + { + textureUnitType[i] = TEXTURE_UNKNOWN; + } + + for (unsigned int i = 0; i < mUsedPixelSamplerRange; ++i) { - if (mSamplers[i].active) + if (mSamplersPS[i].active) { - if (samplerMap.find(mSamplers[i].logicalTextureUnit) != samplerMap.end()) + unsigned int unit = mSamplersPS[i].logicalTextureUnit; + + if (unit >= maxCombinedTextureImageUnits) { - if (mSamplers[i].type != samplerMap[mSamplers[i].logicalTextureUnit]) + if (logErrors) + { + appendToInfoLog("Sampler uniform (%d) exceeds MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits); + } + + return false; + } + + if (textureUnitType[unit] != TEXTURE_UNKNOWN) + { + if (mSamplersPS[i].textureType != textureUnitType[unit]) + { + if (logErrors) + { + appendToInfoLog("Samplers of conflicting types refer to the same texture image unit (%d).", unit); + } + return false; + } } else { - samplerMap[mSamplers[i].logicalTextureUnit] = mSamplers[i].type; + textureUnitType[unit] = mSamplersPS[i].textureType; + } + } + } + + for (unsigned int i = 0; i < mUsedVertexSamplerRange; ++i) + { + if (mSamplersVS[i].active) + { + unsigned int unit = mSamplersVS[i].logicalTextureUnit; + + if (unit >= maxCombinedTextureImageUnits) + { + if (logErrors) + { + appendToInfoLog("Sampler uniform (%d) exceeds MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits); + } + + return false; + } + + if (textureUnitType[unit] != TEXTURE_UNKNOWN) + { + if (mSamplersVS[i].textureType != textureUnitType[unit]) + { + if (logErrors) + { + appendToInfoLog("Samplers of conflicting types refer to the same texture image unit (%d).", unit); + } + + return false; + } + } + else + { + textureUnitType[unit] = mSamplersVS[i].textureType; } } } @@ -2784,17 +2771,23 @@ bool Program::validateSamplers() const return true; } -void Program::getConstantHandles(Uniform *targetUniform, D3DXHANDLE *constantPS, D3DXHANDLE *constantVS) +void Program::initializeConstantHandles(Uniform *targetUniform, Uniform::RegisterInfo *ri, ID3DXConstantTable *constantTable) { - if (!targetUniform->handlesSet) + D3DXHANDLE handle = constantTable->GetConstantByName(0, targetUniform->_name.c_str()); + if (handle) + { + UINT descriptionCount = 1; + D3DXCONSTANT_DESC constantDescription; + HRESULT result = constantTable->GetConstantDesc(handle, &constantDescription, &descriptionCount); + ASSERT(SUCCEEDED(result)); + ri->registerIndex = constantDescription.RegisterIndex; + ri->registerCount = constantDescription.RegisterCount; + ri->registerSet = constantDescription.RegisterSet; + } + else { - targetUniform->psHandle = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str()); - targetUniform->vsHandle = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str()); - targetUniform->handlesSet = true; + ri->registerCount = 0; } - - *constantPS = targetUniform->psHandle; - *constantVS = targetUniform->vsHandle; } GLint Program::getDxDepthRangeLocation() const @@ -2807,9 +2800,9 @@ GLint Program::getDxDepthLocation() const return mDxDepthLocation; } -GLint Program::getDxViewportLocation() const +GLint Program::getDxCoordLocation() const { - return mDxViewportLocation; + return mDxCoordLocation; } GLint Program::getDxHalfPixelSizeLocation() const diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/Program.h b/Source/ThirdParty/ANGLE/src/libGLESv2/Program.h index e9c149e..61830c6 100644 --- a/Source/ThirdParty/ANGLE/src/libGLESv2/Program.h +++ b/Source/ThirdParty/ANGLE/src/libGLESv2/Program.h @@ -1,5 +1,5 @@ // -// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // @@ -11,6 +11,7 @@ #define LIBGLESV2_PROGRAM_H_ #include <d3dx9.h> +#include <d3dcompiler.h> #include <string> #include <vector> #include <set> @@ -27,26 +28,35 @@ class VertexShader; // Helper struct representing a single shader uniform struct Uniform { - Uniform(GLenum type, const std::string &name, unsigned int arraySize); + Uniform(GLenum type, const std::string &_name, unsigned int arraySize); ~Uniform(); + bool isArray(); + const GLenum type; - const std::string name; + const std::string _name; // Decorated name + const std::string name; // Undecorated name const unsigned int arraySize; unsigned char *data; bool dirty; - D3DXHANDLE vsHandle; - D3DXHANDLE psHandle; - bool handlesSet; + struct RegisterInfo + { + int registerSet; + int registerIndex; + int registerCount; + }; + + RegisterInfo ps; + RegisterInfo vs; }; // Struct used for correlating uniforms/elements of uniform arrays to handles struct UniformLocation { - UniformLocation(const std::string &name, unsigned int element, unsigned int index); + UniformLocation(const std::string &_name, unsigned int element, unsigned int index); std::string name; unsigned int element; @@ -71,14 +81,11 @@ class Program GLuint getAttributeLocation(const char *name); int getSemanticIndex(int attributeIndex); - void dirtyAllSamplers(); + GLint getSamplerMapping(SamplerType type, unsigned int samplerIndex); + TextureType getSamplerTextureType(SamplerType type, unsigned int samplerIndex); + GLint getUsedSamplerRange(SamplerType type); - GLint getSamplerMapping(unsigned int samplerIndex); - SamplerType getSamplerType(unsigned int samplerIndex); - bool isSamplerDirty(unsigned int samplerIndex) const; - void setSamplerDirty(unsigned int samplerIndex, bool dirty); - - GLint getUniformLocation(const char *name, bool decorated); + GLint getUniformLocation(std::string name); bool setUniform1fv(GLint location, GLsizei count, const GLfloat *v); bool setUniform2fv(GLint location, GLsizei count, const GLfloat *v); bool setUniform3fv(GLint location, GLsizei count, const GLfloat *v); @@ -91,12 +98,12 @@ class Program bool setUniform3iv(GLint location, GLsizei count, const GLint *v); bool setUniform4iv(GLint location, GLsizei count, const GLint *v); - bool getUniformfv(GLint location, GLfloat *params); - bool getUniformiv(GLint location, GLint *params); + bool getUniformfv(GLint location, GLsizei *bufSize, GLfloat *params); + bool getUniformiv(GLint location, GLsizei *bufSize, GLint *params); GLint getDxDepthRangeLocation() const; GLint getDxDepthLocation() const; - GLint getDxViewportLocation() const; + GLint getDxCoordLocation() const; GLint getDxHalfPixelSizeLocation() const; GLint getDxFrontCCWLocation() const; GLint getDxPointsOrLinesLocation() const; @@ -125,15 +132,18 @@ class Program bool isFlaggedForDeletion() const; void validate(); - bool validateSamplers() const; + bool validateSamplers(bool logErrors); bool isValidated() const; unsigned int getSerial() const; + static std::string decorateAttribute(const std::string &name); // Prepend an underscore + static std::string undecorateUniform(const std::string &_name); // Remove leading underscore + private: DISALLOW_COPY_AND_ASSIGN(Program); - ID3DXBuffer *compileToBinary(const char *hlsl, const char *profile, ID3DXConstantTable **constantTable); + ID3D10Blob *compileToBinary(const char *hlsl, const char *profile, ID3DXConstantTable **constantTable); void unlink(bool destroy = false); int packVaryings(const Varying *packing[][4]); @@ -144,34 +154,25 @@ class Program bool linkUniforms(ID3DXConstantTable *constantTable); bool defineUniform(const D3DXHANDLE &constantHandle, const D3DXCONSTANT_DESC &constantDescription, std::string name = ""); - bool defineUniform(const D3DXCONSTANT_DESC &constantDescription, std::string &name); - Uniform *createUniform(const D3DXCONSTANT_DESC &constantDescription, std::string &name); - bool applyUniform1bv(GLint location, GLsizei count, const GLboolean *v); - bool applyUniform2bv(GLint location, GLsizei count, const GLboolean *v); - bool applyUniform3bv(GLint location, GLsizei count, const GLboolean *v); - bool applyUniform4bv(GLint location, GLsizei count, const GLboolean *v); - bool applyUniform1fv(GLint location, GLsizei count, const GLfloat *v); - bool applyUniform2fv(GLint location, GLsizei count, const GLfloat *v); - bool applyUniform3fv(GLint location, GLsizei count, const GLfloat *v); - bool applyUniform4fv(GLint location, GLsizei count, const GLfloat *v); - bool applyUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value); - bool applyUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value); - bool applyUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value); - bool applyUniform1iv(GLint location, GLsizei count, const GLint *v); - bool applyUniform2iv(GLint location, GLsizei count, const GLint *v); - bool applyUniform3iv(GLint location, GLsizei count, const GLint *v); - bool applyUniform4iv(GLint location, GLsizei count, const GLint *v); - - void getConstantHandles(Uniform *targetUniform, D3DXHANDLE *constantPS, D3DXHANDLE *constantVS); - + bool defineUniform(const D3DXCONSTANT_DESC &constantDescription, const std::string &name); + Uniform *createUniform(const D3DXCONSTANT_DESC &constantDescription, const std::string &name); + bool applyUniformnfv(Uniform *targetUniform, const GLfloat *v); + bool applyUniform1iv(Uniform *targetUniform, GLsizei count, const GLint *v); + bool applyUniform2iv(Uniform *targetUniform, GLsizei count, const GLint *v); + bool applyUniform3iv(Uniform *targetUniform, GLsizei count, const GLint *v); + bool applyUniform4iv(Uniform *targetUniform, GLsizei count, const GLint *v); + void applyUniformniv(Uniform *targetUniform, GLsizei count, const D3DXVECTOR4 *vector); + void applyUniformnbv(Uniform *targetUniform, GLsizei count, int width, const GLboolean *v); + + void initializeConstantHandles(Uniform *targetUniform, Uniform::RegisterInfo *rs, ID3DXConstantTable *constantTable); + + void appendToInfoLogSanitized(const char *message); void appendToInfoLog(const char *info, ...); void resetInfoLog(); - static std::string decorate(const std::string &string); // Prepend an underscore - static std::string undecorate(const std::string &string); // Remove leading underscore - static unsigned int issueSerial(); + IDirect3DDevice9 *mDevice; FragmentShader *mFragmentShader; VertexShader *mVertexShader; @@ -191,11 +192,13 @@ class Program { bool active; GLint logicalTextureUnit; - SamplerType type; - bool dirty; + TextureType textureType; }; - Sampler mSamplers[MAX_TEXTURE_IMAGE_UNITS]; + Sampler mSamplersPS[MAX_TEXTURE_IMAGE_UNITS]; + Sampler mSamplersVS[MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF]; + GLuint mUsedVertexSamplerRange; + GLuint mUsedPixelSamplerRange; typedef std::vector<Uniform*> UniformArray; UniformArray mUniforms; @@ -204,7 +207,7 @@ class Program GLint mDxDepthRangeLocation; GLint mDxDepthLocation; - GLint mDxViewportLocation; + GLint mDxCoordLocation; GLint mDxHalfPixelSizeLocation; GLint mDxFrontCCWLocation; GLint mDxPointsOrLinesLocation; diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/Query.cpp b/Source/ThirdParty/ANGLE/src/libGLESv2/Query.cpp new file mode 100644 index 0000000..10edda5 --- /dev/null +++ b/Source/ThirdParty/ANGLE/src/libGLESv2/Query.cpp @@ -0,0 +1,128 @@ +// +// Copyright (c) 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. +// + +// Query.cpp: Implements the gl::Query class + +#include "libGLESv2/Query.h" + +#include "libGLESv2/main.h" + +namespace gl +{ + +Query::Query(GLuint id, GLenum type) : RefCountObject(id) +{ + mQuery = NULL; + mStatus = GL_FALSE; + mResult = GL_FALSE; + mType = type; +} + +Query::~Query() +{ + if (mQuery != NULL) + { + mQuery->Release(); + mQuery = NULL; + } +} + +void Query::begin() +{ + if (mQuery == NULL) + { + if (FAILED(getDevice()->CreateQuery(D3DQUERYTYPE_OCCLUSION, &mQuery))) + { + return error(GL_OUT_OF_MEMORY); + } + } + + HRESULT result = mQuery->Issue(D3DISSUE_BEGIN); + ASSERT(SUCCEEDED(result)); +} + +void Query::end() +{ + if (mQuery == NULL) + { + return error(GL_INVALID_OPERATION); + } + + HRESULT result = mQuery->Issue(D3DISSUE_END); + ASSERT(SUCCEEDED(result)); + + mStatus = GL_FALSE; + mResult = GL_FALSE; +} + +GLuint Query::getResult() +{ + if (mQuery != NULL) + { + while (!testQuery()) + { + Sleep(0); + // explicitly check for device loss + // some drivers seem to return S_FALSE even if the device is lost + // instead of D3DERR_DEVICELOST like they should + if (gl::getDisplay()->testDeviceLost()) + { + gl::getDisplay()->notifyDeviceLost(); + return error(GL_OUT_OF_MEMORY, 0); + } + } + } + + return (GLuint)mResult; +} + +GLboolean Query::isResultAvailable() +{ + if (mQuery != NULL) + { + testQuery(); + } + + return mStatus; +} + +GLenum Query::getType() const +{ + return mType; +} + +GLboolean Query::testQuery() +{ + if (mQuery != NULL && mStatus != GL_TRUE) + { + DWORD numPixels = 0; + + HRESULT hres = mQuery->GetData(&numPixels, sizeof(DWORD), D3DGETDATA_FLUSH); + if (hres == S_OK) + { + mStatus = GL_TRUE; + + switch (mType) + { + case GL_ANY_SAMPLES_PASSED_EXT: + case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT: + mResult = (numPixels > 0) ? GL_TRUE : GL_FALSE; + break; + default: + ASSERT(false); + } + } + else if (checkDeviceLost(hres)) + { + return error(GL_OUT_OF_MEMORY, GL_TRUE); + } + + return mStatus; + } + + return GL_TRUE; // prevent blocking when query is null +} +} diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/Query.h b/Source/ThirdParty/ANGLE/src/libGLESv2/Query.h new file mode 100644 index 0000000..79357a0 --- /dev/null +++ b/Source/ThirdParty/ANGLE/src/libGLESv2/Query.h @@ -0,0 +1,48 @@ +// +// Copyright (c) 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. +// + +// Query.h: Defines the gl::Query class + +#ifndef LIBGLESV2_QUERY_H_ +#define LIBGLESV2_QUERY_H_ + +#define GL_APICALL +#include <GLES2/gl2.h> +#include <d3d9.h> + +#include "common/angleutils.h" +#include "common/RefCountObject.h" + +namespace gl +{ + +class Query : public RefCountObject +{ + public: + Query(GLuint id, GLenum type); + virtual ~Query(); + + void begin(); + void end(); + GLuint getResult(); + GLboolean isResultAvailable(); + + GLenum getType() const; + + private: + DISALLOW_COPY_AND_ASSIGN(Query); + + GLboolean testQuery(); + + IDirect3DQuery9* mQuery; + GLenum mType; + GLboolean mStatus; + GLint mResult; +}; + +} + +#endif // LIBGLESV2_QUERY_H_ diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/Renderbuffer.cpp b/Source/ThirdParty/ANGLE/src/libGLESv2/Renderbuffer.cpp index 6e4494b..6004255 100644 --- a/Source/ThirdParty/ANGLE/src/libGLESv2/Renderbuffer.cpp +++ b/Source/ThirdParty/ANGLE/src/libGLESv2/Renderbuffer.cpp @@ -18,137 +18,254 @@ namespace gl { unsigned int RenderbufferStorage::mCurrentSerial = 1; -Renderbuffer::Renderbuffer(GLuint id, RenderbufferStorage *storage) : RefCountObject(id) +RenderbufferInterface::RenderbufferInterface() { - ASSERT(storage != NULL); - mStorage = storage; } -Renderbuffer::~Renderbuffer() +// The default case for classes inherited from RenderbufferInterface is not to +// need to do anything upon the reference count to the parent Renderbuffer incrementing +// or decrementing. +void RenderbufferInterface::addProxyRef(const Renderbuffer *proxy) +{ +} + +void RenderbufferInterface::releaseProxy(const Renderbuffer *proxy) +{ +} + +GLuint RenderbufferInterface::getRedSize() const +{ + return dx2es::GetRedSize(getD3DFormat()); +} + +GLuint RenderbufferInterface::getGreenSize() const +{ + return dx2es::GetGreenSize(getD3DFormat()); +} + +GLuint RenderbufferInterface::getBlueSize() const +{ + return dx2es::GetBlueSize(getD3DFormat()); +} + +GLuint RenderbufferInterface::getAlphaSize() const +{ + return dx2es::GetAlphaSize(getD3DFormat()); +} + +GLuint RenderbufferInterface::getDepthSize() const +{ + return dx2es::GetDepthSize(getD3DFormat()); +} + +GLuint RenderbufferInterface::getStencilSize() const +{ + return dx2es::GetStencilSize(getD3DFormat()); +} + +RenderbufferTexture::RenderbufferTexture(Texture *texture, GLenum target) : mTarget(target) +{ + mTexture.set(texture); +} + +RenderbufferTexture::~RenderbufferTexture() +{ + mTexture.set(NULL); +} + +// Textures need to maintain their own reference count for references via +// Renderbuffers acting as proxies. Here, we notify the texture of a reference. +void RenderbufferTexture::addProxyRef(const Renderbuffer *proxy) +{ + mTexture->addProxyRef(proxy); +} + +void RenderbufferTexture::releaseProxy(const Renderbuffer *proxy) +{ + mTexture->releaseProxy(proxy); +} + +IDirect3DSurface9 *RenderbufferTexture::getRenderTarget() +{ + return mTexture->getRenderTarget(mTarget); +} + +IDirect3DSurface9 *RenderbufferTexture::getDepthStencil() +{ + return NULL; +} + +GLsizei RenderbufferTexture::getWidth() const +{ + return mTexture->getWidth(0); +} + +GLsizei RenderbufferTexture::getHeight() const +{ + return mTexture->getHeight(0); +} + +GLenum RenderbufferTexture::getInternalFormat() const +{ + return mTexture->getInternalFormat(); +} + +D3DFORMAT RenderbufferTexture::getD3DFormat() const +{ + return mTexture->getD3DFormat(); +} + +GLsizei RenderbufferTexture::getSamples() const +{ + return 0; +} + +unsigned int RenderbufferTexture::getSerial() const +{ + return mTexture->getRenderTargetSerial(mTarget); +} + +Renderbuffer::Renderbuffer(GLuint id, RenderbufferInterface *instance) : RefCountObject(id) { - delete mStorage; + ASSERT(instance != NULL); + mInstance = instance; } -bool Renderbuffer::isColorbuffer() const +Renderbuffer::~Renderbuffer() { - return mStorage->isColorbuffer(); + delete mInstance; } -bool Renderbuffer::isDepthbuffer() const +// The RenderbufferInterface contained in this Renderbuffer may need to maintain +// its own reference count, so we pass it on here. +void Renderbuffer::addRef() const { - return mStorage->isDepthbuffer(); + mInstance->addProxyRef(this); + + RefCountObject::addRef(); } -bool Renderbuffer::isStencilbuffer() const +void Renderbuffer::release() const { - return mStorage->isStencilbuffer(); + mInstance->releaseProxy(this); + + RefCountObject::release(); } IDirect3DSurface9 *Renderbuffer::getRenderTarget() { - return mStorage->getRenderTarget(); + return mInstance->getRenderTarget(); } IDirect3DSurface9 *Renderbuffer::getDepthStencil() { - return mStorage->getDepthStencil(); + return mInstance->getDepthStencil(); } -int Renderbuffer::getWidth() const +GLsizei Renderbuffer::getWidth() const { - return mStorage->getWidth(); + return mInstance->getWidth(); } -int Renderbuffer::getHeight() const +GLsizei Renderbuffer::getHeight() const { - return mStorage->getHeight(); + return mInstance->getHeight(); } -GLenum Renderbuffer::getFormat() const +GLenum Renderbuffer::getInternalFormat() const { - return mStorage->getFormat(); + return mInstance->getInternalFormat(); } D3DFORMAT Renderbuffer::getD3DFormat() const { - return mStorage->getD3DFormat(); + return mInstance->getD3DFormat(); } -unsigned int Renderbuffer::getSerial() const +GLuint Renderbuffer::getRedSize() const { - return mStorage->getSerial(); + return mInstance->getRedSize(); } -void Renderbuffer::setStorage(RenderbufferStorage *newStorage) +GLuint Renderbuffer::getGreenSize() const { - ASSERT(newStorage != NULL); + return mInstance->getGreenSize(); +} - delete mStorage; - mStorage = newStorage; +GLuint Renderbuffer::getBlueSize() const +{ + return mInstance->getBlueSize(); } -RenderbufferStorage::RenderbufferStorage() : mSerial(issueSerial()) +GLuint Renderbuffer::getAlphaSize() const { - mWidth = 0; - mHeight = 0; - mFormat = GL_RGBA4; - mD3DFormat = D3DFMT_A8R8G8B8; - mSamples = 0; + return mInstance->getAlphaSize(); } -RenderbufferStorage::~RenderbufferStorage() +GLuint Renderbuffer::getDepthSize() const { + return mInstance->getDepthSize(); } -bool RenderbufferStorage::isColorbuffer() const +GLuint Renderbuffer::getStencilSize() const { - return false; + return mInstance->getStencilSize(); } -bool RenderbufferStorage::isDepthbuffer() const +GLsizei Renderbuffer::getSamples() const { - return false; + return mInstance->getSamples(); } -bool RenderbufferStorage::isStencilbuffer() const +unsigned int Renderbuffer::getSerial() const { - return false; + return mInstance->getSerial(); } -IDirect3DSurface9 *RenderbufferStorage::getRenderTarget() +void Renderbuffer::setStorage(RenderbufferStorage *newStorage) { - return NULL; + ASSERT(newStorage != NULL); + + delete mInstance; + mInstance = newStorage; } -IDirect3DSurface9 *RenderbufferStorage::getDepthStencil() +RenderbufferStorage::RenderbufferStorage() : mSerial(issueSerial()) { - return NULL; + mWidth = 0; + mHeight = 0; + mInternalFormat = GL_RGBA4; + mD3DFormat = D3DFMT_A8R8G8B8; + mSamples = 0; } -int RenderbufferStorage::getWidth() const +RenderbufferStorage::~RenderbufferStorage() { - return mWidth; } -int RenderbufferStorage::getHeight() const +IDirect3DSurface9 *RenderbufferStorage::getRenderTarget() { - return mHeight; + return NULL; } -void RenderbufferStorage::setSize(int width, int height) +IDirect3DSurface9 *RenderbufferStorage::getDepthStencil() { - mWidth = width; - mHeight = height; + return NULL; } -GLenum RenderbufferStorage::getFormat() const +GLsizei RenderbufferStorage::getWidth() const { - return mFormat; + return mWidth; } -bool RenderbufferStorage::isFloatingPoint() const +GLsizei RenderbufferStorage::getHeight() const { - return false; // no floating point renderbuffers + return mHeight; +} + +GLenum RenderbufferStorage::getInternalFormat() const +{ + return mInternalFormat; } D3DFORMAT RenderbufferStorage::getD3DFormat() const @@ -171,6 +288,13 @@ unsigned int RenderbufferStorage::issueSerial() return mCurrentSerial++; } +unsigned int RenderbufferStorage::issueCubeSerials() +{ + unsigned int firstSerial = mCurrentSerial; + mCurrentSerial += 6; + return firstSerial; +} + Colorbuffer::Colorbuffer(IDirect3DSurface9 *renderTarget) : mRenderTarget(renderTarget) { if (renderTarget) @@ -180,25 +304,18 @@ Colorbuffer::Colorbuffer(IDirect3DSurface9 *renderTarget) : mRenderTarget(render D3DSURFACE_DESC description; renderTarget->GetDesc(&description); - setSize(description.Width, description.Height); - mFormat = dx2es::ConvertBackBufferFormat(description.Format); + mWidth = description.Width; + mHeight = description.Height; + mInternalFormat = dx2es::ConvertBackBufferFormat(description.Format); mD3DFormat = description.Format; - mSamples = es2dx::GetSamplesFromMultisampleType(description.MultiSampleType); + mSamples = dx2es::GetSamplesFromMultisampleType(description.MultiSampleType); } } -Colorbuffer::Colorbuffer(const Texture* texture) : mRenderTarget(NULL) -{ - setSize(texture->getWidth(), texture->getHeight()); - mD3DFormat = texture->getD3DFormat(); - mSamples = 0; -} - -Colorbuffer::Colorbuffer(int width, int height, GLenum format, GLsizei samples) +Colorbuffer::Colorbuffer(int width, int height, GLenum format, GLsizei samples) : mRenderTarget(NULL) { IDirect3DDevice9 *device = getDevice(); - mRenderTarget = NULL; D3DFORMAT requestedFormat = es2dx::ConvertRenderbufferFormat(format); int supportedSamples = getContext()->getNearestSupportedSamples(requestedFormat, samples); @@ -224,13 +341,11 @@ Colorbuffer::Colorbuffer(int width, int height, GLenum format, GLsizei samples) ASSERT(SUCCEEDED(result)); } - if (mRenderTarget) - { - setSize(width, height); - mFormat = format; - mD3DFormat = requestedFormat; - mSamples = supportedSamples; - } + mWidth = width; + mHeight = height; + mInternalFormat = format; + mD3DFormat = requestedFormat; + mSamples = supportedSamples; } Colorbuffer::~Colorbuffer() @@ -241,65 +356,13 @@ Colorbuffer::~Colorbuffer() } } -bool Colorbuffer::isColorbuffer() const -{ - return true; -} - -GLuint Colorbuffer::getRedSize() const -{ - if (mRenderTarget) - { - D3DSURFACE_DESC description; - mRenderTarget->GetDesc(&description); - - return es2dx::GetRedSize(description.Format); - } - - return 0; -} - -GLuint Colorbuffer::getGreenSize() const -{ - if (mRenderTarget) - { - D3DSURFACE_DESC description; - mRenderTarget->GetDesc(&description); - - return es2dx::GetGreenSize(description.Format); - } - - return 0; -} - -GLuint Colorbuffer::getBlueSize() const -{ - if (mRenderTarget) - { - D3DSURFACE_DESC description; - mRenderTarget->GetDesc(&description); - - return es2dx::GetBlueSize(description.Format); - } - - return 0; -} - -GLuint Colorbuffer::getAlphaSize() const +IDirect3DSurface9 *Colorbuffer::getRenderTarget() { if (mRenderTarget) { - D3DSURFACE_DESC description; - mRenderTarget->GetDesc(&description); - - return es2dx::GetAlphaSize(description.Format); + mRenderTarget->AddRef(); } - return 0; -} - -IDirect3DSurface9 *Colorbuffer::getRenderTarget() -{ return mRenderTarget; } @@ -312,9 +375,10 @@ DepthStencilbuffer::DepthStencilbuffer(IDirect3DSurface9 *depthStencil) : mDepth D3DSURFACE_DESC description; depthStencil->GetDesc(&description); - setSize(description.Width, description.Height); - mFormat = dx2es::ConvertDepthStencilFormat(description.Format); - mSamples = es2dx::GetSamplesFromMultisampleType(description.MultiSampleType); + mWidth = description.Width; + mHeight = description.Height; + mInternalFormat = dx2es::ConvertDepthStencilFormat(description.Format); + mSamples = dx2es::GetSamplesFromMultisampleType(description.MultiSampleType); mD3DFormat = description.Format; } } @@ -334,25 +398,26 @@ DepthStencilbuffer::DepthStencilbuffer(int width, int height, GLsizei samples) return; } - HRESULT result = device->CreateDepthStencilSurface(width, height, D3DFMT_D24S8, es2dx::GetMultisampleTypeFromSamples(supportedSamples), - 0, FALSE, &mDepthStencil, 0); - - if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY) + if (width > 0 && height > 0) { - error(GL_OUT_OF_MEMORY); + HRESULT result = device->CreateDepthStencilSurface(width, height, D3DFMT_D24S8, es2dx::GetMultisampleTypeFromSamples(supportedSamples), + 0, FALSE, &mDepthStencil, 0); - return; - } + if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY) + { + error(GL_OUT_OF_MEMORY); - ASSERT(SUCCEEDED(result)); + return; + } - if (mDepthStencil) - { - setSize(width, height); - mFormat = GL_DEPTH24_STENCIL8_OES; - mD3DFormat = D3DFMT_D24S8; - mSamples = supportedSamples; + ASSERT(SUCCEEDED(result)); } + + mWidth = width; + mHeight = height; + mInternalFormat = GL_DEPTH24_STENCIL8_OES; + mD3DFormat = D3DFMT_D24S8; + mSamples = supportedSamples; } DepthStencilbuffer::~DepthStencilbuffer() @@ -363,42 +428,6 @@ DepthStencilbuffer::~DepthStencilbuffer() } } -bool DepthStencilbuffer::isDepthbuffer() const -{ - return true; -} - -bool DepthStencilbuffer::isStencilbuffer() const -{ - return true; -} - -GLuint DepthStencilbuffer::getDepthSize() const -{ - if (mDepthStencil) - { - D3DSURFACE_DESC description; - mDepthStencil->GetDesc(&description); - - return es2dx::GetDepthSize(description.Format); - } - - return 0; -} - -GLuint DepthStencilbuffer::getStencilSize() const -{ - if (mDepthStencil) - { - D3DSURFACE_DESC description; - mDepthStencil->GetDesc(&description); - - return es2dx::GetStencilSize(description.Format); - } - - return 0; -} - IDirect3DSurface9 *DepthStencilbuffer::getDepthStencil() { return mDepthStencil; @@ -408,19 +437,19 @@ Depthbuffer::Depthbuffer(IDirect3DSurface9 *depthStencil) : DepthStencilbuffer(d { if (depthStencil) { - mFormat = GL_DEPTH_COMPONENT16; // If the renderbuffer parameters are queried, the calling function - // will expect one of the valid renderbuffer formats for use in - // glRenderbufferStorage + mInternalFormat = GL_DEPTH_COMPONENT16; // If the renderbuffer parameters are queried, the calling function + // will expect one of the valid renderbuffer formats for use in + // glRenderbufferStorage } } Depthbuffer::Depthbuffer(int width, int height, GLsizei samples) : DepthStencilbuffer(width, height, samples) { - if (getDepthStencil()) + if (mDepthStencil) { - mFormat = GL_DEPTH_COMPONENT16; // If the renderbuffer parameters are queried, the calling function - // will expect one of the valid renderbuffer formats for use in - // glRenderbufferStorage + mInternalFormat = GL_DEPTH_COMPONENT16; // If the renderbuffer parameters are queried, the calling function + // will expect one of the valid renderbuffer formats for use in + // glRenderbufferStorage } } @@ -428,37 +457,23 @@ Depthbuffer::~Depthbuffer() { } -bool Depthbuffer::isDepthbuffer() const -{ - return true; -} - -bool Depthbuffer::isStencilbuffer() const -{ - return false; -} - Stencilbuffer::Stencilbuffer(IDirect3DSurface9 *depthStencil) : DepthStencilbuffer(depthStencil) { if (depthStencil) { - mFormat = GL_STENCIL_INDEX8; // If the renderbuffer parameters are queried, the calling function - // will expect one of the valid renderbuffer formats for use in - // glRenderbufferStorage - } - else - { - mFormat = GL_RGBA4; //default format + mInternalFormat = GL_STENCIL_INDEX8; // If the renderbuffer parameters are queried, the calling function + // will expect one of the valid renderbuffer formats for use in + // glRenderbufferStorage } } Stencilbuffer::Stencilbuffer(int width, int height, GLsizei samples) : DepthStencilbuffer(width, height, samples) { - if (getDepthStencil()) + if (mDepthStencil) { - mFormat = GL_STENCIL_INDEX8; // If the renderbuffer parameters are queried, the calling function - // will expect one of the valid renderbuffer formats for use in - // glRenderbufferStorage + mInternalFormat = GL_STENCIL_INDEX8; // If the renderbuffer parameters are queried, the calling function + // will expect one of the valid renderbuffer formats for use in + // glRenderbufferStorage } } @@ -466,13 +481,4 @@ Stencilbuffer::~Stencilbuffer() { } -bool Stencilbuffer::isDepthbuffer() const -{ - return false; -} - -bool Stencilbuffer::isStencilbuffer() const -{ - return true; -} } diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/Renderbuffer.h b/Source/ThirdParty/ANGLE/src/libGLESv2/Renderbuffer.h index 98510c2..60ec058 100644 --- a/Source/ThirdParty/ANGLE/src/libGLESv2/Renderbuffer.h +++ b/Source/ThirdParty/ANGLE/src/libGLESv2/Renderbuffer.h @@ -17,143 +17,196 @@ #include <d3d9.h> #include "common/angleutils.h" -#include "libGLESv2/RefCountObject.h" +#include "common/RefCountObject.h" namespace gl { - class Texture; +class Texture; +class Renderbuffer; +class Colorbuffer; +class DepthStencilbuffer; + +class RenderbufferInterface +{ + public: + RenderbufferInterface(); + + virtual ~RenderbufferInterface() {}; + + virtual void addProxyRef(const Renderbuffer *proxy); + virtual void releaseProxy(const Renderbuffer *proxy); + + virtual IDirect3DSurface9 *getRenderTarget() = 0; + virtual IDirect3DSurface9 *getDepthStencil() = 0; + + virtual GLsizei getWidth() const = 0; + virtual GLsizei getHeight() const = 0; + virtual GLenum getInternalFormat() const = 0; + virtual D3DFORMAT getD3DFormat() const = 0; + virtual GLsizei getSamples() const = 0; + + GLuint getRedSize() const; + GLuint getGreenSize() const; + GLuint getBlueSize() const; + GLuint getAlphaSize() const; + GLuint getDepthSize() const; + GLuint getStencilSize() const; + + virtual unsigned int getSerial() const = 0; + + private: + DISALLOW_COPY_AND_ASSIGN(RenderbufferInterface); +}; + +class RenderbufferTexture : public RenderbufferInterface +{ + public: + RenderbufferTexture(Texture *texture, GLenum target); + + virtual ~RenderbufferTexture(); + + void addProxyRef(const Renderbuffer *proxy); + void releaseProxy(const Renderbuffer *proxy); + + IDirect3DSurface9 *getRenderTarget(); + IDirect3DSurface9 *getDepthStencil(); + + virtual GLsizei getWidth() const; + virtual GLsizei getHeight() const; + virtual GLenum getInternalFormat() const; + virtual D3DFORMAT getD3DFormat() const; + virtual GLsizei getSamples() const; + + virtual unsigned int getSerial() const; + + private: + DISALLOW_COPY_AND_ASSIGN(RenderbufferTexture); + + BindingPointer <Texture> mTexture; + GLenum mTarget; +}; // A class derived from RenderbufferStorage is created whenever glRenderbufferStorage // is called. The specific concrete type depends on whether the internal format is // colour depth, stencil or packed depth/stencil. -class RenderbufferStorage +class RenderbufferStorage : public RenderbufferInterface { public: RenderbufferStorage(); virtual ~RenderbufferStorage() = 0; - virtual bool isColorbuffer() const; - virtual bool isDepthbuffer() const; - virtual bool isStencilbuffer() const; - virtual IDirect3DSurface9 *getRenderTarget(); virtual IDirect3DSurface9 *getDepthStencil(); - virtual int getWidth() const; - virtual int getHeight() const; - virtual GLenum getFormat() const; - virtual bool isFloatingPoint() const; - D3DFORMAT getD3DFormat() const; - GLsizei getSamples() const; - unsigned int getSerial() const; + virtual GLsizei getWidth() const; + virtual GLsizei getHeight() const; + virtual GLenum getInternalFormat() const; + virtual D3DFORMAT getD3DFormat() const; + virtual GLsizei getSamples() const; + + virtual unsigned int getSerial() const; static unsigned int issueSerial(); + static unsigned int issueCubeSerials(); protected: - void setSize(int width, int height); - GLenum mFormat; + GLsizei mWidth; + GLsizei mHeight; + GLenum mInternalFormat; D3DFORMAT mD3DFormat; GLsizei mSamples; - const unsigned int mSerial; private: DISALLOW_COPY_AND_ASSIGN(RenderbufferStorage); - static unsigned int mCurrentSerial; + const unsigned int mSerial; - int mWidth; - int mHeight; + static unsigned int mCurrentSerial; }; // Renderbuffer implements the GL renderbuffer object. -// It's only a wrapper for a RenderbufferStorage, but the internal object +// It's only a proxy for a RenderbufferInterface instance; the internal object // can change whenever glRenderbufferStorage is called. class Renderbuffer : public RefCountObject { public: - Renderbuffer(GLuint id, RenderbufferStorage *storage); + Renderbuffer(GLuint id, RenderbufferInterface *storage); - ~Renderbuffer(); + virtual ~Renderbuffer(); - bool isColorbuffer() const; - bool isDepthbuffer() const; - bool isStencilbuffer() const; + // These functions from RefCountObject are overloaded here because + // Textures need to maintain their own count of references to them via + // Renderbuffers/RenderbufferTextures. These functions invoke those + // reference counting functions on the RenderbufferInterface. + void addRef() const; + void release() const; IDirect3DSurface9 *getRenderTarget(); IDirect3DSurface9 *getDepthStencil(); - int getWidth() const; - int getHeight() const; - GLenum getFormat() const; + GLsizei getWidth() const; + GLsizei getHeight() const; + GLenum getInternalFormat() const; D3DFORMAT getD3DFormat() const; + GLuint getRedSize() const; + GLuint getGreenSize() const; + GLuint getBlueSize() const; + GLuint getAlphaSize() const; + GLuint getDepthSize() const; + GLuint getStencilSize() const; + GLsizei getSamples() const; + unsigned int getSerial() const; void setStorage(RenderbufferStorage *newStorage); - RenderbufferStorage *getStorage() { return mStorage; } private: DISALLOW_COPY_AND_ASSIGN(Renderbuffer); - RenderbufferStorage *mStorage; + RenderbufferInterface *mInstance; }; class Colorbuffer : public RenderbufferStorage { public: explicit Colorbuffer(IDirect3DSurface9 *renderTarget); - explicit Colorbuffer(const Texture* texture); - Colorbuffer(int width, int height, GLenum format, GLsizei samples); - - ~Colorbuffer(); - - bool isColorbuffer() const; - - GLuint getRedSize() const; - GLuint getGreenSize() const; - GLuint getBlueSize() const; - GLuint getAlphaSize() const; + Colorbuffer(GLsizei width, GLsizei height, GLenum format, GLsizei samples); - IDirect3DSurface9 *getRenderTarget(); + virtual ~Colorbuffer(); - protected: - IDirect3DSurface9 *mRenderTarget; + virtual IDirect3DSurface9 *getRenderTarget(); private: DISALLOW_COPY_AND_ASSIGN(Colorbuffer); + + IDirect3DSurface9 *mRenderTarget; }; class DepthStencilbuffer : public RenderbufferStorage { public: explicit DepthStencilbuffer(IDirect3DSurface9 *depthStencil); - DepthStencilbuffer(int width, int height, GLsizei samples); + DepthStencilbuffer(GLsizei width, GLsizei height, GLsizei samples); ~DepthStencilbuffer(); - virtual bool isDepthbuffer() const; - virtual bool isStencilbuffer() const; - - GLuint getDepthSize() const; - GLuint getStencilSize() const; + virtual IDirect3DSurface9 *getDepthStencil(); - IDirect3DSurface9 *getDepthStencil(); + protected: + IDirect3DSurface9 *mDepthStencil; private: DISALLOW_COPY_AND_ASSIGN(DepthStencilbuffer); - IDirect3DSurface9 *mDepthStencil; }; class Depthbuffer : public DepthStencilbuffer { public: explicit Depthbuffer(IDirect3DSurface9 *depthStencil); - Depthbuffer(int width, int height, GLsizei samples); + Depthbuffer(GLsizei width, GLsizei height, GLsizei samples); - ~Depthbuffer(); - - bool isDepthbuffer() const; - bool isStencilbuffer() const; + virtual ~Depthbuffer(); private: DISALLOW_COPY_AND_ASSIGN(Depthbuffer); @@ -163,12 +216,9 @@ class Stencilbuffer : public DepthStencilbuffer { public: explicit Stencilbuffer(IDirect3DSurface9 *depthStencil); - Stencilbuffer(int width, int height, GLsizei samples); - - ~Stencilbuffer(); + Stencilbuffer(GLsizei width, GLsizei height, GLsizei samples); - bool isDepthbuffer() const; - bool isStencilbuffer() const; + virtual ~Stencilbuffer(); private: DISALLOW_COPY_AND_ASSIGN(Stencilbuffer); diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/ResourceManager.cpp b/Source/ThirdParty/ANGLE/src/libGLESv2/ResourceManager.cpp index 12a86c1..ae26352 100644 --- a/Source/ThirdParty/ANGLE/src/libGLESv2/ResourceManager.cpp +++ b/Source/ThirdParty/ANGLE/src/libGLESv2/ResourceManager.cpp @@ -66,12 +66,7 @@ void ResourceManager::release() // Returns an unused buffer name GLuint ResourceManager::createBuffer() { - unsigned int handle = 1; - - while (mBufferMap.find(handle) != mBufferMap.end()) - { - handle++; - } + GLuint handle = mBufferHandleAllocator.allocate(); mBufferMap[handle] = NULL; @@ -81,12 +76,7 @@ GLuint ResourceManager::createBuffer() // Returns an unused shader/program name GLuint ResourceManager::createShader(GLenum type) { - unsigned int handle = 1; - - while (mShaderMap.find(handle) != mShaderMap.end() || mProgramMap.find(handle) != mProgramMap.end()) // Shared name space - { - handle++; - } + GLuint handle = mProgramShaderHandleAllocator.allocate(); if (type == GL_VERTEX_SHADER) { @@ -104,12 +94,7 @@ GLuint ResourceManager::createShader(GLenum type) // Returns an unused program/shader name GLuint ResourceManager::createProgram() { - unsigned int handle = 1; - - while (mProgramMap.find(handle) != mProgramMap.end() || mShaderMap.find(handle) != mShaderMap.end()) // Shared name space - { - handle++; - } + GLuint handle = mProgramShaderHandleAllocator.allocate(); mProgramMap[handle] = new Program(this, handle); @@ -119,12 +104,7 @@ GLuint ResourceManager::createProgram() // Returns an unused texture name GLuint ResourceManager::createTexture() { - unsigned int handle = 1; - - while (mTextureMap.find(handle) != mTextureMap.end()) - { - handle++; - } + GLuint handle = mTextureHandleAllocator.allocate(); mTextureMap[handle] = NULL; @@ -134,12 +114,7 @@ GLuint ResourceManager::createTexture() // Returns an unused renderbuffer name GLuint ResourceManager::createRenderbuffer() { - unsigned int handle = 1; - - while (mRenderbufferMap.find(handle) != mRenderbufferMap.end()) - { - handle++; - } + GLuint handle = mRenderbufferHandleAllocator.allocate(); mRenderbufferMap[handle] = NULL; @@ -152,6 +127,7 @@ void ResourceManager::deleteBuffer(GLuint buffer) if (bufferObject != mBufferMap.end()) { + mBufferHandleAllocator.release(bufferObject->first); if (bufferObject->second) bufferObject->second->release(); mBufferMap.erase(bufferObject); } @@ -165,6 +141,7 @@ void ResourceManager::deleteShader(GLuint shader) { if (shaderObject->second->getRefCount() == 0) { + mProgramShaderHandleAllocator.release(shaderObject->first); delete shaderObject->second; mShaderMap.erase(shaderObject); } @@ -183,6 +160,7 @@ void ResourceManager::deleteProgram(GLuint program) { if (programObject->second->getRefCount() == 0) { + mProgramShaderHandleAllocator.release(programObject->first); delete programObject->second; mProgramMap.erase(programObject); } @@ -199,6 +177,7 @@ void ResourceManager::deleteTexture(GLuint texture) if (textureObject != mTextureMap.end()) { + mTextureHandleAllocator.release(textureObject->first); if (textureObject->second) textureObject->second->release(); mTextureMap.erase(textureObject); } @@ -210,6 +189,7 @@ void ResourceManager::deleteRenderbuffer(GLuint renderbuffer) if (renderbufferObject != mRenderbufferMap.end()) { + mRenderbufferHandleAllocator.release(renderbufferObject->first); if (renderbufferObject->second) renderbufferObject->second->release(); mRenderbufferMap.erase(renderbufferObject); } @@ -302,17 +282,17 @@ void ResourceManager::checkBufferAllocation(unsigned int buffer) } } -void ResourceManager::checkTextureAllocation(GLuint texture, SamplerType type) +void ResourceManager::checkTextureAllocation(GLuint texture, TextureType type) { if (!getTexture(texture) && texture != 0) { Texture *textureObject; - if (type == SAMPLER_2D) + if (type == TEXTURE_2D) { textureObject = new Texture2D(texture); } - else if (type == SAMPLER_CUBE) + else if (type == TEXTURE_CUBE) { textureObject = new TextureCubeMap(texture); } diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/ResourceManager.h b/Source/ThirdParty/ANGLE/src/libGLESv2/ResourceManager.h index 346e51f..5185fc9 100644 --- a/Source/ThirdParty/ANGLE/src/libGLESv2/ResourceManager.h +++ b/Source/ThirdParty/ANGLE/src/libGLESv2/ResourceManager.h @@ -13,9 +13,10 @@ #define GL_APICALL #include <GLES2/gl2.h> -#include <map> +#include <hash_map> #include "common/angleutils.h" +#include "libGLESv2/HandleAllocator.h" namespace gl { @@ -25,12 +26,19 @@ class Program; class Texture; class Renderbuffer; -enum SamplerType +enum TextureType { - SAMPLER_2D, - SAMPLER_CUBE, + TEXTURE_2D, + TEXTURE_CUBE, + + TEXTURE_TYPE_COUNT, + TEXTURE_UNKNOWN +}; - SAMPLER_TYPE_COUNT +enum SamplerType +{ + SAMPLER_PIXEL, + SAMPLER_VERTEX }; class ResourceManager @@ -63,7 +71,7 @@ class ResourceManager void setRenderbuffer(GLuint handle, Renderbuffer *renderbuffer); void checkBufferAllocation(unsigned int buffer); - void checkTextureAllocation(GLuint texture, SamplerType type); + void checkTextureAllocation(GLuint texture, TextureType type); void checkRenderbufferAllocation(GLuint renderbuffer); private: @@ -71,20 +79,24 @@ class ResourceManager std::size_t mRefCount; - typedef std::map<GLuint, Buffer*> BufferMap; + typedef stdext::hash_map<GLuint, Buffer*> BufferMap; BufferMap mBufferMap; + HandleAllocator mBufferHandleAllocator; - typedef std::map<GLuint, Shader*> ShaderMap; + typedef stdext::hash_map<GLuint, Shader*> ShaderMap; ShaderMap mShaderMap; - typedef std::map<GLuint, Program*> ProgramMap; + typedef stdext::hash_map<GLuint, Program*> ProgramMap; ProgramMap mProgramMap; + HandleAllocator mProgramShaderHandleAllocator; - typedef std::map<GLuint, Texture*> TextureMap; + typedef stdext::hash_map<GLuint, Texture*> TextureMap; TextureMap mTextureMap; + HandleAllocator mTextureHandleAllocator; - typedef std::map<GLuint, Renderbuffer*> RenderbufferMap; + typedef stdext::hash_map<GLuint, Renderbuffer*> RenderbufferMap; RenderbufferMap mRenderbufferMap; + HandleAllocator mRenderbufferHandleAllocator; }; } diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/Shader.cpp b/Source/ThirdParty/ANGLE/src/libGLESv2/Shader.cpp index 4c969d6..ac58abe 100644 --- a/Source/ThirdParty/ANGLE/src/libGLESv2/Shader.cpp +++ b/Source/ThirdParty/ANGLE/src/libGLESv2/Shader.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. // @@ -27,31 +27,8 @@ Shader::Shader(ResourceManager *manager, GLuint handle) : mHandle(handle), mReso mHlsl = NULL; mInfoLog = NULL; - // Perform a one-time initialization of the shader compiler (or after being destructed by releaseCompiler) - if (!mFragmentCompiler) - { - int result = ShInitialize(); - - if (result) - { - ShBuiltInResources resources; - ShInitBuiltInResources(&resources); - Context *context = getContext(); - - resources.MaxVertexAttribs = MAX_VERTEX_ATTRIBS; - resources.MaxVertexUniformVectors = MAX_VERTEX_UNIFORM_VECTORS; - resources.MaxVaryingVectors = context->getMaximumVaryingVectors(); - resources.MaxVertexTextureImageUnits = MAX_VERTEX_TEXTURE_IMAGE_UNITS; - resources.MaxCombinedTextureImageUnits = MAX_COMBINED_TEXTURE_IMAGE_UNITS; - resources.MaxTextureImageUnits = MAX_TEXTURE_IMAGE_UNITS; - resources.MaxFragmentUniformVectors = context->getMaximumFragmentUniformVectors(); - resources.MaxDrawBuffers = MAX_DRAW_BUFFERS; - resources.OES_standard_derivatives = 1; - - mFragmentCompiler = ShConstructCompiler(SH_FRAGMENT_SHADER, SH_GLES2_SPEC, &resources); - mVertexCompiler = ShConstructCompiler(SH_VERTEX_SHADER, SH_GLES2_SPEC, &resources); - } - } + uncompile(); + initializeCompiler(); mRefCount = 0; mDeleteStatus = false; @@ -127,11 +104,8 @@ void Shader::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) if (mInfoLog) { - while (index < bufSize - 1 && index < (int)strlen(mInfoLog)) - { - infoLog[index] = mInfoLog[index]; - index++; - } + index = std::min(bufSize - 1, (int)strlen(mInfoLog)); + memcpy(infoLog, mInfoLog, index); } if (bufSize) @@ -157,22 +131,31 @@ int Shader::getSourceLength() const } } -void Shader::getSource(GLsizei bufSize, GLsizei *length, char *source) +int Shader::getTranslatedSourceLength() const +{ + if (!mHlsl) + { + return 0; + } + else + { + return strlen(mHlsl) + 1; + } +} + +void Shader::getSourceImpl(char *source, GLsizei bufSize, GLsizei *length, char *buffer) { int index = 0; - if (mSource) + if (source) { - while (index < bufSize - 1 && index < (int)strlen(mSource)) - { - source[index] = mSource[index]; - index++; - } + index = std::min(bufSize - 1, (int)strlen(source)); + memcpy(buffer, source, index); } if (bufSize) { - source[index] = '\0'; + buffer[index] = '\0'; } if (length) @@ -181,6 +164,16 @@ void Shader::getSource(GLsizei bufSize, GLsizei *length, char *source) } } +void Shader::getSource(GLsizei bufSize, GLsizei *length, char *buffer) +{ + getSourceImpl(mSource, bufSize, length, buffer); +} + +void Shader::getTranslatedSource(GLsizei bufSize, GLsizei *length, char *buffer) +{ + getSourceImpl(mHlsl, bufSize, length, buffer); +} + bool Shader::isCompiled() { return mHlsl != NULL; @@ -221,6 +214,36 @@ void Shader::flagForDeletion() mDeleteStatus = true; } +// Perform a one-time initialization of the shader compiler (or after being destructed by releaseCompiler) +void Shader::initializeCompiler() +{ + if (!mFragmentCompiler) + { + int result = ShInitialize(); + + if (result) + { + ShBuiltInResources resources; + ShInitBuiltInResources(&resources); + Context *context = getContext(); + + resources.MaxVertexAttribs = MAX_VERTEX_ATTRIBS; + resources.MaxVertexUniformVectors = MAX_VERTEX_UNIFORM_VECTORS; + resources.MaxVaryingVectors = context->getMaximumVaryingVectors(); + resources.MaxVertexTextureImageUnits = context->getMaximumVertexTextureImageUnits(); + resources.MaxCombinedTextureImageUnits = context->getMaximumCombinedTextureImageUnits(); + resources.MaxTextureImageUnits = MAX_TEXTURE_IMAGE_UNITS; + resources.MaxFragmentUniformVectors = context->getMaximumFragmentUniformVectors(); + resources.MaxDrawBuffers = MAX_DRAW_BUFFERS; + resources.OES_standard_derivatives = 1; + // resources.OES_EGL_image_external = getDisplay()->isD3d9ExDevice() ? 1 : 0; // TODO: commented out until the extension is actually supported. + + mFragmentCompiler = ShConstructCompiler(SH_FRAGMENT_SHADER, SH_GLES2_SPEC, SH_HLSL_OUTPUT, &resources); + mVertexCompiler = ShConstructCompiler(SH_VERTEX_SHADER, SH_GLES2_SPEC, SH_HLSL_OUTPUT, &resources); + } + } +} + void Shader::releaseCompiler() { ShDestruct(mFragmentCompiler); @@ -259,7 +282,7 @@ void Shader::parseVaryings() *array = '\0'; } - varyings.push_back(Varying(parseType(varyingType), varyingName, size, array != NULL)); + mVaryings.push_back(Varying(parseType(varyingType), varyingName, size, array != NULL)); input = strstr(input, ";") + 2; } @@ -271,19 +294,60 @@ void Shader::parseVaryings() } } +// initialize/clean up previous state +void Shader::uncompile() +{ + // set by compileToHLSL + delete[] mHlsl; + mHlsl = NULL; + delete[] mInfoLog; + mInfoLog = NULL; + + // set by parseVaryings + mVaryings.clear(); + + mUsesFragCoord = false; + mUsesFrontFacing = false; + mUsesPointSize = false; + mUsesPointCoord = false; +} + void Shader::compileToHLSL(void *compiler) { - if (isCompiled() || !mSource) + // ensure we don't pass a NULL source to the compiler + char *source = "\0"; + if (mSource) { - return; + source = mSource; } - TRACE("\n%s", mSource); + // ensure the compiler is loaded + initializeCompiler(); - delete[] mInfoLog; - mInfoLog = NULL; + int compileOptions = SH_OBJECT_CODE; + std::string sourcePath; + if (perfActive()) + { + sourcePath = getTempPath(); + writeFile(sourcePath.c_str(), source, strlen(source)); + compileOptions |= SH_LINE_DIRECTIVES; + } + + int result; + if (sourcePath.empty()) + { + result = ShCompile(compiler, &source, 1, compileOptions); + } + else + { + const char* sourceStrings[2] = + { + sourcePath.c_str(), + source + }; - int result = ShCompile(compiler, &mSource, 1, SH_OBJECT_CODE); + result = ShCompile(compiler, sourceStrings, 2, compileOptions | SH_SOURCE_PATH); + } if (result) { @@ -291,8 +355,6 @@ void Shader::compileToHLSL(void *compiler) ShGetInfo(compiler, SH_OBJECT_CODE_LENGTH, &objCodeLen); mHlsl = new char[objCodeLen]; ShGetObjectCode(compiler, mHlsl); - - TRACE("\n%s", mHlsl); } else { @@ -436,8 +498,18 @@ GLenum VertexShader::getType() return GL_VERTEX_SHADER; } +void VertexShader::uncompile() +{ + Shader::uncompile(); + + // set by ParseAttributes + mAttributes.clear(); +}; + void VertexShader::compile() { + uncompile(); + compileToHLSL(mVertexCompiler); parseAttributes(); parseVaryings(); @@ -464,9 +536,10 @@ int VertexShader::getSemanticIndex(const std::string &attributeName) void VertexShader::parseAttributes() { - if (mHlsl) + const char *hlsl = getHLSL(); + if (hlsl) { - const char *input = strstr(mHlsl, "// Attributes") + 14; + const char *input = strstr(hlsl, "// Attributes") + 14; while(true) { @@ -502,8 +575,10 @@ GLenum FragmentShader::getType() void FragmentShader::compile() { + uncompile(); + compileToHLSL(mFragmentCompiler); parseVaryings(); - varyings.sort(compareVarying); + mVaryings.sort(compareVarying); } } diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/Shader.h b/Source/ThirdParty/ANGLE/src/libGLESv2/Shader.h index 5eaa053..9c7c0df 100644 --- a/Source/ThirdParty/ANGLE/src/libGLESv2/Shader.h +++ b/Source/ThirdParty/ANGLE/src/libGLESv2/Shader.h @@ -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. // @@ -57,9 +57,12 @@ class Shader int getInfoLogLength() const; void getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog); int getSourceLength() const; - void getSource(GLsizei bufSize, GLsizei *length, char *source); + void getSource(GLsizei bufSize, GLsizei *length, char *buffer); + int getTranslatedSourceLength() const; + void getTranslatedSource(GLsizei bufSize, GLsizei *length, char *buffer); virtual void compile() = 0; + virtual void uncompile(); bool isCompiled(); const char *getHLSL(); @@ -72,15 +75,30 @@ class Shader static void releaseCompiler(); protected: - DISALLOW_COPY_AND_ASSIGN(Shader); - void parseVaryings(); void compileToHLSL(void *compiler); + void getSourceImpl(char *source, GLsizei bufSize, GLsizei *length, char *buffer); + static GLenum parseType(const std::string &type); static bool compareVarying(const Varying &x, const Varying &y); + VaryingList mVaryings; + + bool mUsesFragCoord; + bool mUsesFrontFacing; + bool mUsesPointSize; + bool mUsesPointCoord; + + static void *mFragmentCompiler; + static void *mVertexCompiler; + + private: + DISALLOW_COPY_AND_ASSIGN(Shader); + + void initializeCompiler(); + const GLuint mHandle; unsigned int mRefCount; // Number of program objects this shader is attached to bool mDeleteStatus; // Flag to indicate that the shader can be deleted when no longer in use @@ -89,17 +107,7 @@ class Shader char *mHlsl; char *mInfoLog; - VaryingList varyings; - - bool mUsesFragCoord; - bool mUsesFrontFacing; - bool mUsesPointSize; - bool mUsesPointCoord; - ResourceManager *mResourceManager; - - static void *mFragmentCompiler; - static void *mVertexCompiler; }; struct Attribute @@ -127,8 +135,9 @@ class VertexShader : public Shader ~VertexShader(); - GLenum getType(); - void compile(); + virtual GLenum getType(); + virtual void compile(); + virtual void uncompile(); int getSemanticIndex(const std::string &attributeName); private: @@ -146,8 +155,8 @@ class FragmentShader : public Shader ~FragmentShader(); - GLenum getType(); - void compile(); + virtual GLenum getType(); + virtual void compile(); private: DISALLOW_COPY_AND_ASSIGN(FragmentShader); diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/Texture.cpp b/Source/ThirdParty/ANGLE/src/libGLESv2/Texture.cpp index 7c040f8..29177d2 100644 --- a/Source/ThirdParty/ANGLE/src/libGLESv2/Texture.cpp +++ b/Source/ThirdParty/ANGLE/src/libGLESv2/Texture.cpp @@ -13,334 +13,384 @@ #include <d3dx9tex.h> #include <algorithm> +#include <intrin.h> #include "common/debug.h" +#include "libEGL/Display.h" + #include "libGLESv2/main.h" #include "libGLESv2/mathutil.h" #include "libGLESv2/utilities.h" #include "libGLESv2/Blit.h" +#include "libGLESv2/Framebuffer.h" namespace gl { +unsigned int TextureStorage::mCurrentTextureSerial = 1; -Texture::Image::Image() - : width(0), height(0), dirty(false), surface(NULL), format(GL_NONE) +static D3DFORMAT ConvertTextureFormatType(GLenum format, GLenum type) { + if (format == GL_COMPRESSED_RGB_S3TC_DXT1_EXT || + format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) + { + return D3DFMT_DXT1; + } + else if (format == GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE) + { + return D3DFMT_DXT3; + } + else if (format == GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE) + { + return D3DFMT_DXT5; + } + else if (type == GL_FLOAT) + { + return D3DFMT_A32B32G32R32F; + } + else if (type == GL_HALF_FLOAT_OES) + { + return D3DFMT_A16B16G16R16F; + } + else if (type == GL_UNSIGNED_BYTE) + { + if (format == GL_LUMINANCE && getContext()->supportsLuminanceTextures()) + { + return D3DFMT_L8; + } + else if (format == GL_LUMINANCE_ALPHA && getContext()->supportsLuminanceAlphaTextures()) + { + return D3DFMT_A8L8; + } + else if (format == GL_RGB) + { + return D3DFMT_X8R8G8B8; + } + + return D3DFMT_A8R8G8B8; + } + + return D3DFMT_A8R8G8B8; } -Texture::Image::~Image() +static bool IsTextureFormatRenderable(D3DFORMAT format) { - if (surface) surface->Release(); + switch(format) + { + case D3DFMT_L8: + case D3DFMT_A8L8: + case D3DFMT_DXT1: + case D3DFMT_DXT3: + case D3DFMT_DXT5: + return false; + case D3DFMT_A8R8G8B8: + case D3DFMT_X8R8G8B8: + case D3DFMT_A16B16G16R16F: + case D3DFMT_A32B32G32R32F: + return true; + default: + UNREACHABLE(); + } + + return false; } -Texture::Texture(GLuint id) : RefCountObject(id) +Image::Image() { - mMinFilter = GL_NEAREST_MIPMAP_LINEAR; - mMagFilter = GL_LINEAR; - mWrapS = GL_REPEAT; - mWrapT = GL_REPEAT; - - mWidth = 0; + mWidth = 0; mHeight = 0; - - mDirtyMetaData = true; - mDirty = true; - mIsRenderable = false; + mFormat = GL_NONE; mType = GL_UNSIGNED_BYTE; - mBaseTexture = NULL; -} -Texture::~Texture() -{ -} + mSurface = NULL; -Blit *Texture::getBlitter() -{ - Context *context = getContext(); - return context->getBlitter(); + mDirty = false; + + mD3DPool = D3DPOOL_SYSTEMMEM; + mD3DFormat = D3DFMT_UNKNOWN; } -// Returns true on successful filter state update (valid enum parameter) -bool Texture::setMinFilter(GLenum filter) +Image::~Image() { - switch (filter) + if (mSurface) { - case GL_NEAREST: - case GL_LINEAR: - case GL_NEAREST_MIPMAP_NEAREST: - case GL_LINEAR_MIPMAP_NEAREST: - case GL_NEAREST_MIPMAP_LINEAR: - case GL_LINEAR_MIPMAP_LINEAR: - { - if (mMinFilter != filter) - { - mMinFilter = filter; - mDirty = true; - } - return true; - } - default: - return false; + mSurface->Release(); } } -// Returns true on successful filter state update (valid enum parameter) -bool Texture::setMagFilter(GLenum filter) +bool Image::redefine(GLenum format, GLsizei width, GLsizei height, GLenum type, bool forceRelease) { - switch (filter) + if (mWidth != width || + mHeight != height || + mFormat != format || + mType != type || + forceRelease) { - case GL_NEAREST: - case GL_LINEAR: + mWidth = width; + mHeight = height; + mFormat = format; + mType = type; + // compute the d3d format that will be used + mD3DFormat = ConvertTextureFormatType(mFormat, mType); + + if (mSurface) { - if (mMagFilter != filter) - { - mMagFilter = filter; - mDirty = true; - } - return true; + mSurface->Release(); + mSurface = NULL; } - default: - return false; + + return true; } + + return false; } -// Returns true on successful wrap state update (valid enum parameter) -bool Texture::setWrapS(GLenum wrap) +void Image::createSurface() { - switch (wrap) + if(mSurface) { - case GL_REPEAT: - case GL_CLAMP_TO_EDGE: - case GL_MIRRORED_REPEAT: - { - if (mWrapS != wrap) - { - mWrapS = wrap; - mDirty = true; - } - return true; - } - default: - return false; + return; } -} -// Returns true on successful wrap state update (valid enum parameter) -bool Texture::setWrapT(GLenum wrap) -{ - switch (wrap) + IDirect3DTexture9 *newTexture = NULL; + IDirect3DSurface9 *newSurface = NULL; + const D3DPOOL poolToUse = D3DPOOL_SYSTEMMEM; + + if (mWidth != 0 && mHeight != 0) { - case GL_REPEAT: - case GL_CLAMP_TO_EDGE: - case GL_MIRRORED_REPEAT: + int levelToFetch = 0; + GLsizei requestWidth = mWidth; + GLsizei requestHeight = mHeight; + if (IsCompressed(mFormat) && (mWidth % 4 != 0 || mHeight % 4 != 0)) { - if (mWrapT != wrap) + bool isMult4 = false; + int upsampleCount = 0; + while (!isMult4) { - mWrapT = wrap; - mDirty = true; + requestWidth <<= 1; + requestHeight <<= 1; + upsampleCount++; + if (requestWidth % 4 == 0 && requestHeight % 4 == 0) + { + isMult4 = true; + } } - return true; + levelToFetch = upsampleCount; } - default: - return false; + + HRESULT result = getDevice()->CreateTexture(requestWidth, requestHeight, levelToFetch + 1, NULL, getD3DFormat(), + poolToUse, &newTexture, NULL); + + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + ERR("Creating image surface failed."); + return error(GL_OUT_OF_MEMORY); + } + + newTexture->GetSurfaceLevel(levelToFetch, &newSurface); + newTexture->Release(); } -} -GLenum Texture::getMinFilter() const -{ - return mMinFilter; + mSurface = newSurface; + mDirty = false; + mD3DPool = poolToUse; } -GLenum Texture::getMagFilter() const +HRESULT Image::lock(D3DLOCKED_RECT *lockedRect, const RECT *rect) { - return mMagFilter; -} + createSurface(); -GLenum Texture::getWrapS() const -{ - return mWrapS; + HRESULT result = D3DERR_INVALIDCALL; + + if (mSurface) + { + result = mSurface->LockRect(lockedRect, rect, 0); + ASSERT(SUCCEEDED(result)); + + mDirty = true; + } + + return result; } -GLenum Texture::getWrapT() const +void Image::unlock() { - return mWrapT; + if (mSurface) + { + HRESULT result = mSurface->UnlockRect(); + ASSERT(SUCCEEDED(result)); + } } -GLuint Texture::getWidth() const -{ - return mWidth; +bool Image::isRenderableFormat() const +{ + return IsTextureFormatRenderable(getD3DFormat()); } -GLuint Texture::getHeight() const +D3DFORMAT Image::getD3DFormat() const { - return mHeight; + // this should only happen if the image hasn't been redefined first + // which would be a bug by the caller + ASSERT(mD3DFormat != D3DFMT_UNKNOWN); + + return mD3DFormat; } -bool Texture::isFloatingPoint() const +IDirect3DSurface9 *Image::getSurface() { - return (mType == GL_FLOAT || mType == GL_HALF_FLOAT_OES); + createSurface(); + + return mSurface; } -bool Texture::isRenderableFormat() const +void Image::setManagedSurface(IDirect3DSurface9 *surface) { - D3DFORMAT format = getD3DFormat(); - - switch(format) + if (mSurface) { - case D3DFMT_L8: - case D3DFMT_A8L8: - case D3DFMT_DXT1: - return false; - case D3DFMT_A8R8G8B8: - case D3DFMT_X8R8G8B8: - case D3DFMT_A16B16G16R16F: - case D3DFMT_A32B32G32R32F: - return true; - default: - UNREACHABLE(); + D3DXLoadSurfaceFromSurface(surface, NULL, NULL, mSurface, NULL, NULL, D3DX_FILTER_BOX, 0); + mSurface->Release(); } - return false; + D3DSURFACE_DESC desc; + surface->GetDesc(&desc); + ASSERT(desc.Pool == D3DPOOL_MANAGED); + + mSurface = surface; + mD3DPool = desc.Pool; } -// Selects an internal Direct3D 9 format for storing an Image -D3DFORMAT Texture::selectFormat(GLenum format, GLenum type) +void Image::updateSurface(IDirect3DSurface9 *destSurface, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) { - if (format == GL_COMPRESSED_RGB_S3TC_DXT1_EXT || - format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) - { - return D3DFMT_DXT1; - } - else if (type == GL_FLOAT) - { - return D3DFMT_A32B32G32R32F; - } - else if (type == GL_HALF_FLOAT_OES) - { - return D3DFMT_A16B16G16R16F; - } - else if (type == GL_UNSIGNED_BYTE) + IDirect3DSurface9 *sourceSurface = getSurface(); + + if (sourceSurface != destSurface) { - if (format == GL_LUMINANCE && getContext()->supportsLuminanceTextures()) - { - return D3DFMT_L8; - } - else if (format == GL_LUMINANCE_ALPHA && getContext()->supportsLuminanceAlphaTextures()) + RECT rect = transformPixelRect(xoffset, yoffset, width, height, mHeight); + + if (mD3DPool == D3DPOOL_MANAGED) { - return D3DFMT_A8L8; + HRESULT result = D3DXLoadSurfaceFromSurface(destSurface, NULL, &rect, sourceSurface, NULL, &rect, D3DX_FILTER_BOX, 0); + ASSERT(SUCCEEDED(result)); } - else if (format == GL_RGB) + else { - return D3DFMT_X8R8G8B8; + // UpdateSurface: source must be SYSTEMMEM, dest must be DEFAULT pools + POINT point = {rect.left, rect.top}; + HRESULT result = getDevice()->UpdateSurface(sourceSurface, &rect, destSurface, &point); + ASSERT(SUCCEEDED(result)); } - - return D3DFMT_A8R8G8B8; } - - return D3DFMT_A8R8G8B8; } // Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input // into the target pixel rectangle at output with outputPitch bytes in between each line. -void Texture::loadImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, - GLint unpackAlignment, const void *input, size_t outputPitch, void *output, D3DSURFACE_DESC *description) const +void Image::loadData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum type, + GLint unpackAlignment, const void *input, size_t outputPitch, void *output) const { - GLsizei inputPitch = ComputePitch(width, format, type, unpackAlignment); + GLsizei inputPitch = -ComputePitch(width, mFormat, type, unpackAlignment); + input = ((char*)input) - inputPitch * (height - 1); switch (type) { case GL_UNSIGNED_BYTE: - switch (format) + switch (mFormat) { case GL_ALPHA: - loadAlphaImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); + loadAlphaData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); break; case GL_LUMINANCE: - loadLuminanceImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output, description->Format == D3DFMT_L8); + loadLuminanceData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output, getD3DFormat() == D3DFMT_L8); break; case GL_LUMINANCE_ALPHA: - loadLuminanceAlphaImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output, description->Format == D3DFMT_A8L8); + loadLuminanceAlphaData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output, getD3DFormat() == D3DFMT_A8L8); break; case GL_RGB: - loadRGBUByteImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); + loadRGBUByteData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); break; case GL_RGBA: - loadRGBAUByteImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); + if (supportsSSE2()) + { + loadRGBAUByteDataSSE2(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); + } + else + { + loadRGBAUByteData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); + } break; case GL_BGRA_EXT: - loadBGRAImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); + loadBGRAData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); break; default: UNREACHABLE(); } break; case GL_UNSIGNED_SHORT_5_6_5: - switch (format) + switch (mFormat) { case GL_RGB: - loadRGB565ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); + loadRGB565Data(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); break; default: UNREACHABLE(); } break; case GL_UNSIGNED_SHORT_4_4_4_4: - switch (format) + switch (mFormat) { case GL_RGBA: - loadRGBA4444ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); + loadRGBA4444Data(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); break; default: UNREACHABLE(); } break; case GL_UNSIGNED_SHORT_5_5_5_1: - switch (format) + switch (mFormat) { case GL_RGBA: - loadRGBA5551ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); + loadRGBA5551Data(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); break; default: UNREACHABLE(); } break; case GL_FLOAT: - switch (format) + switch (mFormat) { // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D case GL_ALPHA: - loadAlphaFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); + loadAlphaFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); break; case GL_LUMINANCE: - loadLuminanceFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); + loadLuminanceFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); break; case GL_LUMINANCE_ALPHA: - loadLuminanceAlphaFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); + loadLuminanceAlphaFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); break; case GL_RGB: - loadRGBFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); + loadRGBFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); break; case GL_RGBA: - loadRGBAFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); + loadRGBAFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); break; default: UNREACHABLE(); } break; case GL_HALF_FLOAT_OES: - switch (format) + switch (mFormat) { // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D case GL_ALPHA: - loadAlphaHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); + loadAlphaHalfFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); break; case GL_LUMINANCE: - loadLuminanceHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); + loadLuminanceHalfFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); break; case GL_LUMINANCE_ALPHA: - loadLuminanceAlphaHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); + loadLuminanceAlphaHalfFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); break; case GL_RGB: - loadRGBHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); + loadRGBHalfFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); break; case GL_RGBA: - loadRGBAHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); + loadRGBAHalfFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); break; default: UNREACHABLE(); } @@ -349,8 +399,8 @@ void Texture::loadImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei } } -void Texture::loadAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - size_t inputPitch, const void *input, size_t outputPitch, void *output) const +void Image::loadAlphaData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const { const unsigned char *source = NULL; unsigned char *dest = NULL; @@ -369,8 +419,8 @@ void Texture::loadAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GL } } -void Texture::loadAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - size_t inputPitch, const void *input, size_t outputPitch, void *output) const +void Image::loadAlphaFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const { const float *source = NULL; float *dest = NULL; @@ -389,8 +439,8 @@ void Texture::loadAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei widt } } -void Texture::loadAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - size_t inputPitch, const void *input, size_t outputPitch, void *output) const +void Image::loadAlphaHalfFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const { const unsigned short *source = NULL; unsigned short *dest = NULL; @@ -409,8 +459,8 @@ void Texture::loadAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei } } -void Texture::loadLuminanceImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - size_t inputPitch, const void *input, size_t outputPitch, void *output, bool native) const +void Image::loadLuminanceData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const { const int destBytesPerPixel = native? 1: 4; const unsigned char *source = NULL; @@ -438,8 +488,8 @@ void Texture::loadLuminanceImageData(GLint xoffset, GLint yoffset, GLsizei width } } -void Texture::loadLuminanceFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - size_t inputPitch, const void *input, size_t outputPitch, void *output) const +void Image::loadLuminanceFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const { const float *source = NULL; float *dest = NULL; @@ -458,8 +508,8 @@ void Texture::loadLuminanceFloatImageData(GLint xoffset, GLint yoffset, GLsizei } } -void Texture::loadLuminanceHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - size_t inputPitch, const void *input, size_t outputPitch, void *output) const +void Image::loadLuminanceHalfFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const { const unsigned short *source = NULL; unsigned short *dest = NULL; @@ -478,8 +528,8 @@ void Texture::loadLuminanceHalfFloatImageData(GLint xoffset, GLint yoffset, GLsi } } -void Texture::loadLuminanceAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - size_t inputPitch, const void *input, size_t outputPitch, void *output, bool native) const +void Image::loadLuminanceAlphaData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const { const int destBytesPerPixel = native? 2: 4; const unsigned char *source = NULL; @@ -507,8 +557,8 @@ void Texture::loadLuminanceAlphaImageData(GLint xoffset, GLint yoffset, GLsizei } } -void Texture::loadLuminanceAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - size_t inputPitch, const void *input, size_t outputPitch, void *output) const +void Image::loadLuminanceAlphaFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const { const float *source = NULL; float *dest = NULL; @@ -527,8 +577,8 @@ void Texture::loadLuminanceAlphaFloatImageData(GLint xoffset, GLint yoffset, GLs } } -void Texture::loadLuminanceAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - size_t inputPitch, const void *input, size_t outputPitch, void *output) const +void Image::loadLuminanceAlphaHalfFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const { const unsigned short *source = NULL; unsigned short *dest = NULL; @@ -547,8 +597,8 @@ void Texture::loadLuminanceAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, } } -void Texture::loadRGBUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - size_t inputPitch, const void *input, size_t outputPitch, void *output) const +void Image::loadRGBUByteData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const { const unsigned char *source = NULL; unsigned char *dest = NULL; @@ -567,8 +617,8 @@ void Texture::loadRGBUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, } } -void Texture::loadRGB565ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - size_t inputPitch, const void *input, size_t outputPitch, void *output) const +void Image::loadRGB565Data(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const { const unsigned short *source = NULL; unsigned char *dest = NULL; @@ -588,8 +638,8 @@ void Texture::loadRGB565ImageData(GLint xoffset, GLint yoffset, GLsizei width, G } } -void Texture::loadRGBFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - size_t inputPitch, const void *input, size_t outputPitch, void *output) const +void Image::loadRGBFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const { const float *source = NULL; float *dest = NULL; @@ -608,8 +658,8 @@ void Texture::loadRGBFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, } } -void Texture::loadRGBHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - size_t inputPitch, const void *input, size_t outputPitch, void *output) const +void Image::loadRGBHalfFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const { const unsigned short *source = NULL; unsigned short *dest = NULL; @@ -628,28 +678,68 @@ void Texture::loadRGBHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei wi } } -void Texture::loadRGBAUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - size_t inputPitch, const void *input, size_t outputPitch, void *output) const +void Image::loadRGBAUByteDataSSE2(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const { - const unsigned char *source = NULL; - unsigned char *dest = NULL; + const unsigned int *source = NULL; + unsigned int *dest = NULL; + __m128i brMask = _mm_set1_epi32(0x00ff00ff); for (int y = 0; y < height; y++) { - source = static_cast<const unsigned char*>(input) + y * inputPitch; - dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4; + source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch); + dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4); + int x = 0; + + // Make output writes aligned + for (x = 0; ((reinterpret_cast<intptr_t>(&dest[x]) & 15) != 0) && x < width; x++) + { + unsigned int rgba = source[x]; + dest[x] = (_rotl(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00); + } + + for (; x + 3 < width; x += 4) + { + __m128i sourceData = _mm_loadu_si128(reinterpret_cast<const __m128i*>(&source[x])); + // Mask out g and a, which don't change + __m128i gaComponents = _mm_andnot_si128(brMask, sourceData); + // Mask out b and r + __m128i brComponents = _mm_and_si128(sourceData, brMask); + // Swap b and r + __m128i brSwapped = _mm_shufflehi_epi16(_mm_shufflelo_epi16(brComponents, _MM_SHUFFLE(2, 3, 0, 1)), _MM_SHUFFLE(2, 3, 0, 1)); + __m128i result = _mm_or_si128(gaComponents, brSwapped); + _mm_store_si128(reinterpret_cast<__m128i*>(&dest[x]), result); + } + + // Perform leftover writes + for (; x < width; x++) + { + unsigned int rgba = source[x]; + dest[x] = (_rotl(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00); + } + } +} + +void Image::loadRGBAUByteData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const +{ + const unsigned int *source = NULL; + unsigned int *dest = NULL; + for (int y = 0; y < height; y++) + { + source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch); + dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4); + for (int x = 0; x < width; x++) { - dest[4 * x + 0] = source[x * 4 + 2]; - dest[4 * x + 1] = source[x * 4 + 1]; - dest[4 * x + 2] = source[x * 4 + 0]; - dest[4 * x + 3] = source[x * 4 + 3]; + unsigned int rgba = source[x]; + dest[x] = (_rotl(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00); } } } -void Texture::loadRGBA4444ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - size_t inputPitch, const void *input, size_t outputPitch, void *output) const +void Image::loadRGBA4444Data(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const { const unsigned short *source = NULL; unsigned char *dest = NULL; @@ -669,8 +759,8 @@ void Texture::loadRGBA4444ImageData(GLint xoffset, GLint yoffset, GLsizei width, } } -void Texture::loadRGBA5551ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - size_t inputPitch, const void *input, size_t outputPitch, void *output) const +void Image::loadRGBA5551Data(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const { const unsigned short *source = NULL; unsigned char *dest = NULL; @@ -690,8 +780,8 @@ void Texture::loadRGBA5551ImageData(GLint xoffset, GLint yoffset, GLsizei width, } } -void Texture::loadRGBAFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - size_t inputPitch, const void *input, size_t outputPitch, void *output) const +void Image::loadRGBAFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const { const float *source = NULL; float *dest = NULL; @@ -704,8 +794,8 @@ void Texture::loadRGBAFloatImageData(GLint xoffset, GLint yoffset, GLsizei width } } -void Texture::loadRGBAHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - size_t inputPitch, const void *input, size_t outputPitch, void *output) const +void Image::loadRGBAHalfFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const { const unsigned char *source = NULL; unsigned char *dest = NULL; @@ -718,8 +808,8 @@ void Texture::loadRGBAHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei w } } -void Texture::loadBGRAImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - size_t inputPitch, const void *input, size_t outputPitch, void *output) const +void Image::loadBGRAData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const { const unsigned char *source = NULL; unsigned char *dest = NULL; @@ -732,158 +822,718 @@ void Texture::loadBGRAImageData(GLint xoffset, GLint yoffset, GLsizei width, GLs } } -void Texture::createSurface(GLsizei width, GLsizei height, GLenum format, GLenum type, Image *img) +void Image::loadCompressedData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const { + switch (getD3DFormat()) + { + case D3DFMT_DXT1: + loadDXT1Data(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); + break; + case D3DFMT_DXT3: + loadDXT3Data(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); + break; + case D3DFMT_DXT5: + loadDXT5Data(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); + break; + } +} + +static void FlipCopyDXT1BlockFull(const unsigned int* source, unsigned int* dest) { + // A DXT1 block layout is: + // [0-1] color0. + // [2-3] color1. + // [4-7] color bitmap, 2 bits per pixel. + // So each of the 4-7 bytes represents one line, flipping a block is just + // flipping those bytes. + + // First 32-bits is two RGB565 colors shared by tile and does not need to be modified. + dest[0] = source[0]; + + // Second 32-bits contains 4 rows of 4 2-bit interpolants between the colors. All rows should be flipped. + dest[1] = (source[1] >> 24) | + ((source[1] << 8) & 0x00FF0000) | + ((source[1] >> 8) & 0x0000FF00) | + (source[1] << 24); +} + +// Flips the first 2 lines of a DXT1 block in the y direction. +static void FlipCopyDXT1BlockHalf(const unsigned int* source, unsigned int* dest) { + // See layout above. + dest[0] = source[0]; + dest[1] = ((source[1] << 8) & 0x0000FF00) | + ((source[1] >> 8) & 0x000000FF); +} + +// Flips a full DXT3 block in the y direction. +static void FlipCopyDXT3BlockFull(const unsigned int* source, unsigned int* dest) { + // A DXT3 block layout is: + // [0-7] alpha bitmap, 4 bits per pixel. + // [8-15] a DXT1 block. + + // First and Second 32 bits are 4bit per pixel alpha and need to be flipped. + dest[0] = (source[1] >> 16) | (source[1] << 16); + dest[1] = (source[0] >> 16) | (source[0] << 16); + + // And flip the DXT1 block using the above function. + FlipCopyDXT1BlockFull(source + 2, dest + 2); +} + +// Flips the first 2 lines of a DXT3 block in the y direction. +static void FlipCopyDXT3BlockHalf(const unsigned int* source, unsigned int* dest) { + // See layout above. + dest[0] = (source[1] >> 16) | (source[1] << 16); + FlipCopyDXT1BlockHalf(source + 2, dest + 2); +} + +// Flips a full DXT5 block in the y direction. +static void FlipCopyDXT5BlockFull(const unsigned int* source, unsigned int* dest) { + // A DXT5 block layout is: + // [0] alpha0. + // [1] alpha1. + // [2-7] alpha bitmap, 3 bits per pixel. + // [8-15] a DXT1 block. + + // The alpha bitmap doesn't easily map lines to bytes, so we have to + // interpret it correctly. Extracted from + // http://www.opengl.org/registry/specs/EXT/texture_compression_s3tc.txt : + // + // The 6 "bits" bytes of the block are decoded into one 48-bit integer: + // + // bits = bits_0 + 256 * (bits_1 + 256 * (bits_2 + 256 * (bits_3 + + // 256 * (bits_4 + 256 * bits_5)))) + // + // bits is a 48-bit unsigned integer, from which a three-bit control code + // is extracted for a texel at location (x,y) in the block using: + // + // code(x,y) = bits[3*(4*y+x)+1..3*(4*y+x)+0] + // + // where bit 47 is the most significant and bit 0 is the least + // significant bit. + const unsigned char* sourceBytes = static_cast<const unsigned char*>(static_cast<const void*>(source)); + unsigned char* destBytes = static_cast<unsigned char*>(static_cast<void*>(dest)); + unsigned int line_0_1 = sourceBytes[2] + 256 * (sourceBytes[3] + 256 * sourceBytes[4]); + unsigned int line_2_3 = sourceBytes[5] + 256 * (sourceBytes[6] + 256 * sourceBytes[7]); + // swap lines 0 and 1 in line_0_1. + unsigned int line_1_0 = ((line_0_1 & 0x000fff) << 12) | + ((line_0_1 & 0xfff000) >> 12); + // swap lines 2 and 3 in line_2_3. + unsigned int line_3_2 = ((line_2_3 & 0x000fff) << 12) | + ((line_2_3 & 0xfff000) >> 12); + destBytes[0] = sourceBytes[0]; + destBytes[1] = sourceBytes[1]; + destBytes[2] = line_3_2 & 0xff; + destBytes[3] = (line_3_2 & 0xff00) >> 8; + destBytes[4] = (line_3_2 & 0xff0000) >> 16; + destBytes[5] = line_1_0 & 0xff; + destBytes[6] = (line_1_0 & 0xff00) >> 8; + destBytes[7] = (line_1_0 & 0xff0000) >> 16; + + // And flip the DXT1 block using the above function. + FlipCopyDXT1BlockFull(source + 2, dest + 2); +} + +// Flips the first 2 lines of a DXT5 block in the y direction. +static void FlipCopyDXT5BlockHalf(const unsigned int* source, unsigned int* dest) { + // See layout above. + const unsigned char* sourceBytes = static_cast<const unsigned char*>(static_cast<const void*>(source)); + unsigned char* destBytes = static_cast<unsigned char*>(static_cast<void*>(dest)); + unsigned int line_0_1 = sourceBytes[2] + 256 * (sourceBytes[3] + 256 * sourceBytes[4]); + unsigned int line_1_0 = ((line_0_1 & 0x000fff) << 12) | + ((line_0_1 & 0xfff000) >> 12); + destBytes[0] = sourceBytes[0]; + destBytes[1] = sourceBytes[1]; + destBytes[2] = line_1_0 & 0xff; + destBytes[3] = (line_1_0 & 0xff00) >> 8; + destBytes[4] = (line_1_0 & 0xff0000) >> 16; + FlipCopyDXT1BlockHalf(source + 2, dest + 2); +} + +void Image::loadDXT1Data(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const +{ + ASSERT(xoffset % 4 == 0); + ASSERT(yoffset % 4 == 0); + ASSERT(width % 4 == 0 || width == 2 || width == 1); + ASSERT(inputPitch % 8 == 0); + ASSERT(outputPitch % 8 == 0); + + const unsigned int *source = reinterpret_cast<const unsigned int*>(input); + unsigned int *dest = reinterpret_cast<unsigned int*>(output); + + // Round width up in case it is less than 4. + int blocksAcross = (width + 3) / 4; + int intsAcross = blocksAcross * 2; + + switch (height) + { + case 1: + for (int x = 0; x < intsAcross; x += 2) + { + // just copy the block + dest[x] = source[x]; + dest[x + 1] = source[x + 1]; + } + break; + case 2: + for (int x = 0; x < intsAcross; x += 2) + { + FlipCopyDXT1BlockHalf(source + x, dest + x); + } + break; + default: + ASSERT(height % 4 == 0); + for (int y = 0; y < height / 4; ++y) + { + const unsigned int *source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch); + unsigned int *dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8); + + for (int x = 0; x < intsAcross; x += 2) + { + FlipCopyDXT1BlockFull(source + x, dest + x); + } + } + break; + } +} + +void Image::loadDXT3Data(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const { - IDirect3DTexture9 *newTexture = NULL; - IDirect3DSurface9 *newSurface = NULL; + ASSERT(xoffset % 4 == 0); + ASSERT(yoffset % 4 == 0); + ASSERT(width % 4 == 0 || width == 2 || width == 1); + ASSERT(inputPitch % 16 == 0); + ASSERT(outputPitch % 16 == 0); + + const unsigned int *source = reinterpret_cast<const unsigned int*>(input); + unsigned int *dest = reinterpret_cast<unsigned int*>(output); + + // Round width up in case it is less than 4. + int blocksAcross = (width + 3) / 4; + int intsAcross = blocksAcross * 4; - if (width != 0 && height != 0) + switch (height) { - int levelToFetch = 0; - GLsizei requestWidth = width; - GLsizei requestHeight = height; - if (IsCompressed(format) && (width % 4 != 0 || height % 4 != 0)) - { - bool isMult4 = false; - int upsampleCount = 0; - while (!isMult4) + case 1: + for (int x = 0; x < intsAcross; x += 4) { - requestWidth <<= 1; - requestHeight <<= 1; - upsampleCount++; - if (requestWidth % 4 == 0 && requestHeight % 4 == 0) + // just copy the block + dest[x] = source[x]; + dest[x + 1] = source[x + 1]; + dest[x + 2] = source[x + 2]; + dest[x + 3] = source[x + 3]; + } + break; + case 2: + for (int x = 0; x < intsAcross; x += 4) + { + FlipCopyDXT3BlockHalf(source + x, dest + x); + } + break; + default: + ASSERT(height % 4 == 0); + for (int y = 0; y < height / 4; ++y) + { + const unsigned int *source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch); + unsigned int *dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16); + + for (int x = 0; x < intsAcross; x += 4) { - isMult4 = true; + FlipCopyDXT3BlockFull(source + x, dest + x); } } - levelToFetch = upsampleCount; + break; + } +} + +void Image::loadDXT5Data(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const +{ + ASSERT(xoffset % 4 == 0); + ASSERT(yoffset % 4 == 0); + ASSERT(width % 4 == 0 || width == 2 || width == 1); + ASSERT(inputPitch % 16 == 0); + ASSERT(outputPitch % 16 == 0); + + const unsigned int *source = reinterpret_cast<const unsigned int*>(input); + unsigned int *dest = reinterpret_cast<unsigned int*>(output); + + // Round width up in case it is less than 4. + int blocksAcross = (width + 3) / 4; + int intsAcross = blocksAcross * 4; + + switch (height) + { + case 1: + for (int x = 0; x < intsAcross; x += 4) + { + // just copy the block + dest[x] = source[x]; + dest[x + 1] = source[x + 1]; + dest[x + 2] = source[x + 2]; + dest[x + 3] = source[x + 3]; + } + break; + case 2: + for (int x = 0; x < intsAcross; x += 4) + { + FlipCopyDXT5BlockHalf(source + x, dest + x); + } + break; + default: + ASSERT(height % 4 == 0); + for (int y = 0; y < height / 4; ++y) + { + const unsigned int *source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch); + unsigned int *dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16); + + for (int x = 0; x < intsAcross; x += 4) + { + FlipCopyDXT5BlockFull(source + x, dest + x); + } + } + break; + } +} + +// This implements glCopyTex[Sub]Image2D for non-renderable internal texture formats and incomplete textures +void Image::copy(GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, IDirect3DSurface9 *renderTarget) +{ + IDirect3DDevice9 *device = getDevice(); + IDirect3DSurface9 *renderTargetData = NULL; + D3DSURFACE_DESC description; + renderTarget->GetDesc(&description); + + HRESULT result = device->CreateOffscreenPlainSurface(description.Width, description.Height, description.Format, D3DPOOL_SYSTEMMEM, &renderTargetData, NULL); + + if (FAILED(result)) + { + ERR("Could not create matching destination surface."); + return error(GL_OUT_OF_MEMORY); + } + + result = device->GetRenderTargetData(renderTarget, renderTargetData); + + if (FAILED(result)) + { + ERR("GetRenderTargetData unexpectedly failed."); + renderTargetData->Release(); + return error(GL_OUT_OF_MEMORY); + } + + RECT sourceRect = transformPixelRect(x, y, width, height, description.Height); + int destYOffset = transformPixelYOffset(yoffset, height, mHeight); + RECT destRect = {xoffset, destYOffset, xoffset + width, destYOffset + height}; + + if (isRenderableFormat()) + { + result = D3DXLoadSurfaceFromSurface(getSurface(), NULL, &destRect, renderTargetData, NULL, &sourceRect, D3DX_FILTER_BOX, 0); + + if (FAILED(result)) + { + ERR("Copying surfaces unexpectedly failed."); + renderTargetData->Release(); + return error(GL_OUT_OF_MEMORY); } + } + else + { + D3DLOCKED_RECT sourceLock = {0}; + result = renderTargetData->LockRect(&sourceLock, &sourceRect, 0); - HRESULT result = getDevice()->CreateTexture(requestWidth, requestHeight, levelToFetch + 1, NULL, selectFormat(format, type), - D3DPOOL_SYSTEMMEM, &newTexture, NULL); + if (FAILED(result)) + { + ERR("Failed to lock the source surface (rectangle might be invalid)."); + renderTargetData->Release(); + return error(GL_OUT_OF_MEMORY); + } + D3DLOCKED_RECT destLock = {0}; + result = lock(&destLock, &destRect); + if (FAILED(result)) { - ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + ERR("Failed to lock the destination surface (rectangle might be invalid)."); + renderTargetData->UnlockRect(); + renderTargetData->Release(); return error(GL_OUT_OF_MEMORY); } - newTexture->GetSurfaceLevel(levelToFetch, &newSurface); - newTexture->Release(); + if (destLock.pBits && sourceLock.pBits) + { + unsigned char *source = (unsigned char*)sourceLock.pBits; + unsigned char *dest = (unsigned char*)destLock.pBits; + + switch (description.Format) + { + case D3DFMT_X8R8G8B8: + case D3DFMT_A8R8G8B8: + switch(getD3DFormat()) + { + case D3DFMT_L8: + for(int y = 0; y < height; y++) + { + for(int x = 0; x < width; x++) + { + dest[x] = source[x * 4 + 2]; + } + + source += sourceLock.Pitch; + dest += destLock.Pitch; + } + break; + case D3DFMT_A8L8: + for(int y = 0; y < height; y++) + { + for(int x = 0; x < width; x++) + { + dest[x * 2 + 0] = source[x * 4 + 2]; + dest[x * 2 + 1] = source[x * 4 + 3]; + } + + source += sourceLock.Pitch; + dest += destLock.Pitch; + } + break; + default: + UNREACHABLE(); + } + break; + case D3DFMT_R5G6B5: + switch(getD3DFormat()) + { + case D3DFMT_L8: + for(int y = 0; y < height; y++) + { + for(int x = 0; x < width; x++) + { + unsigned char red = source[x * 2 + 1] & 0xF8; + dest[x] = red | (red >> 5); + } + + source += sourceLock.Pitch; + dest += destLock.Pitch; + } + break; + default: + UNREACHABLE(); + } + break; + case D3DFMT_A1R5G5B5: + switch(getD3DFormat()) + { + case D3DFMT_L8: + for(int y = 0; y < height; y++) + { + for(int x = 0; x < width; x++) + { + unsigned char red = source[x * 2 + 1] & 0x7C; + dest[x] = (red << 1) | (red >> 4); + } + + source += sourceLock.Pitch; + dest += destLock.Pitch; + } + break; + case D3DFMT_A8L8: + for(int y = 0; y < height; y++) + { + for(int x = 0; x < width; x++) + { + unsigned char red = source[x * 2 + 1] & 0x7C; + dest[x * 2 + 0] = (red << 1) | (red >> 4); + dest[x * 2 + 1] = (signed char)source[x * 2 + 1] >> 7; + } + + source += sourceLock.Pitch; + dest += destLock.Pitch; + } + break; + default: + UNREACHABLE(); + } + break; + default: + UNREACHABLE(); + } + } + + unlock(); + renderTargetData->UnlockRect(); } - if (img->surface) img->surface->Release(); - img->surface = newSurface; + renderTargetData->Release(); + + mDirty = true; +} + +TextureStorage::TextureStorage(bool renderTarget) + : mRenderTarget(renderTarget), + mD3DPool(getDisplay()->getTexturePool(mRenderTarget)), + mTextureSerial(issueTextureSerial()) +{ +} + +TextureStorage::~TextureStorage() +{ +} + +bool TextureStorage::isRenderTarget() const +{ + return mRenderTarget; +} + +bool TextureStorage::isManaged() const +{ + return (mD3DPool == D3DPOOL_MANAGED); +} + +D3DPOOL TextureStorage::getPool() const +{ + return mD3DPool; +} - img->width = width; - img->height = height; - img->format = format; +unsigned int TextureStorage::getTextureSerial() const +{ + return mTextureSerial; } -void Texture::setImage(GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *img) +unsigned int TextureStorage::issueTextureSerial() { - createSurface(width, height, format, type, img); + return mCurrentTextureSerial++; +} - if (pixels != NULL && img->surface != NULL) +Texture::Texture(GLuint id) : RefCountObject(id) +{ + mMinFilter = GL_NEAREST_MIPMAP_LINEAR; + mMagFilter = GL_LINEAR; + mWrapS = GL_REPEAT; + mWrapT = GL_REPEAT; + mDirtyParameters = true; + mUsage = GL_NONE; + + mDirtyImages = true; + + mImmutable = false; +} + +Texture::~Texture() +{ +} + +// Returns true on successful filter state update (valid enum parameter) +bool Texture::setMinFilter(GLenum filter) +{ + switch (filter) { - D3DSURFACE_DESC description; - img->surface->GetDesc(&description); + case GL_NEAREST: + case GL_LINEAR: + case GL_NEAREST_MIPMAP_NEAREST: + case GL_LINEAR_MIPMAP_NEAREST: + case GL_NEAREST_MIPMAP_LINEAR: + case GL_LINEAR_MIPMAP_LINEAR: + { + if (mMinFilter != filter) + { + mMinFilter = filter; + mDirtyParameters = true; + } + return true; + } + default: + return false; + } +} - D3DLOCKED_RECT locked; - HRESULT result = img->surface->LockRect(&locked, NULL, 0); +// Returns true on successful filter state update (valid enum parameter) +bool Texture::setMagFilter(GLenum filter) +{ + switch (filter) + { + case GL_NEAREST: + case GL_LINEAR: + { + if (mMagFilter != filter) + { + mMagFilter = filter; + mDirtyParameters = true; + } + return true; + } + default: + return false; + } +} - ASSERT(SUCCEEDED(result)); +// Returns true on successful wrap state update (valid enum parameter) +bool Texture::setWrapS(GLenum wrap) +{ + switch (wrap) + { + case GL_REPEAT: + case GL_CLAMP_TO_EDGE: + case GL_MIRRORED_REPEAT: + { + if (mWrapS != wrap) + { + mWrapS = wrap; + mDirtyParameters = true; + } + return true; + } + default: + return false; + } +} - if (SUCCEEDED(result)) +// Returns true on successful wrap state update (valid enum parameter) +bool Texture::setWrapT(GLenum wrap) +{ + switch (wrap) + { + case GL_REPEAT: + case GL_CLAMP_TO_EDGE: + case GL_MIRRORED_REPEAT: { - loadImageData(0, 0, width, height, format, type, unpackAlignment, pixels, locked.Pitch, locked.pBits, &description); - img->surface->UnlockRect(); + if (mWrapT != wrap) + { + mWrapT = wrap; + mDirtyParameters = true; + } + return true; } + default: + return false; + } +} - img->dirty = true; +// Returns true on successful usage state update (valid enum parameter) +bool Texture::setUsage(GLenum usage) +{ + switch (usage) + { + case GL_NONE: + case GL_FRAMEBUFFER_ATTACHMENT_ANGLE: + mUsage = usage; + return true; + default: + return false; } +} - mDirtyMetaData = true; +GLenum Texture::getMinFilter() const +{ + return mMinFilter; } -void Texture::setCompressedImage(GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *img) +GLenum Texture::getMagFilter() const +{ + return mMagFilter; +} + +GLenum Texture::getWrapS() const { - createSurface(width, height, format, GL_UNSIGNED_BYTE, img); + return mWrapS; +} - if (pixels != NULL && img->surface != NULL) +GLenum Texture::getWrapT() const +{ + return mWrapT; +} + +GLenum Texture::getUsage() const +{ + return mUsage; +} + +void Texture::setImage(GLint unpackAlignment, const void *pixels, Image *image) +{ + if (pixels != NULL) { D3DLOCKED_RECT locked; - HRESULT result = img->surface->LockRect(&locked, NULL, 0); - - ASSERT(SUCCEEDED(result)); + HRESULT result = image->lock(&locked, NULL); if (SUCCEEDED(result)) { - memcpy(locked.pBits, pixels, imageSize); - img->surface->UnlockRect(); + image->loadData(0, 0, image->getWidth(), image->getHeight(), image->getType(), unpackAlignment, pixels, locked.Pitch, locked.pBits); + image->unlock(); } - img->dirty = true; + mDirtyImages = true; } +} + +void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, Image *image) +{ + if (pixels != NULL) + { + D3DLOCKED_RECT locked; + HRESULT result = image->lock(&locked, NULL); - mDirtyMetaData = true; + if (SUCCEEDED(result)) + { + int inputPitch = ComputeCompressedPitch(image->getWidth(), image->getFormat()); + int inputSize = ComputeCompressedSize(image->getWidth(), image->getHeight(), image->getFormat()); + image->loadCompressedData(0, 0, image->getWidth(), image->getHeight(), -inputPitch, static_cast<const char*>(pixels) + inputSize - inputPitch, locked.Pitch, locked.pBits); + image->unlock(); + } + + mDirtyImages = true; + } } -bool Texture::subImage(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *img) +bool Texture::subImage(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *image) { - if (width + xoffset > img->width || height + yoffset > img->height) + if (width + xoffset > image->getWidth() || height + yoffset > image->getHeight()) { error(GL_INVALID_VALUE); return false; } - if (!img->surface) + if (IsCompressed(image->getFormat())) { - createSurface(img->width, img->height, format, type, img); + error(GL_INVALID_OPERATION); + return false; } - if (pixels != NULL && img->surface != NULL) + if (format != image->getFormat()) { - D3DSURFACE_DESC description; - img->surface->GetDesc(&description); + error(GL_INVALID_OPERATION); + return false; + } + if (pixels != NULL) + { D3DLOCKED_RECT locked; - HRESULT result = img->surface->LockRect(&locked, NULL, 0); - - ASSERT(SUCCEEDED(result)); + HRESULT result = image->lock(&locked, NULL); if (SUCCEEDED(result)) { - loadImageData(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, locked.Pitch, locked.pBits, &description); - img->surface->UnlockRect(); + image->loadData(xoffset, transformPixelYOffset(yoffset, height, image->getHeight()), width, height, type, unpackAlignment, pixels, locked.Pitch, locked.pBits); + image->unlock(); } - img->dirty = true; + mDirtyImages = true; } return true; } -bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *img) +bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *image) { - if (width + xoffset > img->width || height + yoffset > img->height) + if (width + xoffset > image->getWidth() || height + yoffset > image->getHeight()) { error(GL_INVALID_VALUE); return false; } - if (format != getFormat()) + if (format != getInternalFormat()) { error(GL_INVALID_OPERATION); return false; } - if (!img->surface) - { - createSurface(img->width, img->height, format, GL_UNSIGNED_BYTE, img); - } - - if (pixels != NULL && img->surface != NULL) + if (pixels != NULL) { RECT updateRegion; updateRegion.left = xoffset; @@ -892,419 +1542,354 @@ bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GL updateRegion.top = yoffset; D3DLOCKED_RECT locked; - HRESULT result = img->surface->LockRect(&locked, &updateRegion, 0); - - ASSERT(SUCCEEDED(result)); + HRESULT result = image->lock(&locked, &updateRegion); if (SUCCEEDED(result)) { - GLsizei inputPitch = ComputeCompressedPitch(width, format); - int rows = imageSize / inputPitch; - for (int i = 0; i < rows; ++i) - { - memcpy((void*)((BYTE*)locked.pBits + i * locked.Pitch), (void*)((BYTE*)pixels + i * inputPitch), inputPitch); - } - img->surface->UnlockRect(); + int inputPitch = ComputeCompressedPitch(width, format); + int inputSize = ComputeCompressedSize(width, height, format); + image->loadCompressedData(xoffset, transformPixelYOffset(yoffset, height, image->getHeight()), width, height, -inputPitch, static_cast<const char*>(pixels) + inputSize - inputPitch, locked.Pitch, locked.pBits); + image->unlock(); } - img->dirty = true; + mDirtyImages = true; } return true; } -// This implements glCopyTex[Sub]Image2D for non-renderable internal texture formats -void Texture::copyNonRenderable(Image *image, GLenum internalFormat, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, IDirect3DSurface9 *renderTarget) +IDirect3DBaseTexture9 *Texture::getTexture() { - IDirect3DDevice9 *device = getDevice(); - IDirect3DSurface9 *surface = NULL; - D3DSURFACE_DESC description; - renderTarget->GetDesc(&description); - - HRESULT result = device->CreateOffscreenPlainSurface(description.Width, description.Height, description.Format, D3DPOOL_SYSTEMMEM, &surface, NULL); - - if (!SUCCEEDED(result)) + if (!isSamplerComplete()) { - ERR("Could not create matching destination surface."); - return error(GL_OUT_OF_MEMORY); + return NULL; } - result = device->GetRenderTargetData(renderTarget, surface); - - if (!SUCCEEDED(result)) + // ensure the underlying texture is created + if (getStorage(false) == NULL) { - ERR("GetRenderTargetData unexpectedly failed."); - surface->Release(); - return error(GL_OUT_OF_MEMORY); + return NULL; } - D3DLOCKED_RECT sourceLock = {0}; - RECT sourceRect = {x, y, x + width, y + height}; - result = surface->LockRect(&sourceLock, &sourceRect, 0); + updateTexture(); - if (FAILED(result)) - { - ERR("Failed to lock the source surface (rectangle might be invalid)."); - surface->UnlockRect(); - surface->Release(); - return error(GL_OUT_OF_MEMORY); - } + return getBaseTexture(); +} - if (!image->surface) - { - createSurface(width, height, internalFormat, mType, image); - } +bool Texture::hasDirtyParameters() const +{ + return mDirtyParameters; +} - if (image->surface == NULL) - { - ERR("Failed to create an image surface."); - surface->UnlockRect(); - surface->Release(); - return error(GL_OUT_OF_MEMORY); - } +bool Texture::hasDirtyImages() const +{ + return mDirtyImages; +} - D3DLOCKED_RECT destLock = {0}; - RECT destRect = {xoffset, yoffset, xoffset + width, yoffset + height}; - result = image->surface->LockRect(&destLock, &destRect, 0); - - if (FAILED(result)) +void Texture::resetDirty() +{ + mDirtyParameters = false; + mDirtyImages = false; +} + +unsigned int Texture::getTextureSerial() +{ + TextureStorage *texture = getStorage(false); + return texture ? texture->getTextureSerial() : 0; +} + +unsigned int Texture::getRenderTargetSerial(GLenum target) +{ + TextureStorage *texture = getStorage(true); + return texture ? texture->getRenderTargetSerial(target) : 0; +} + +bool Texture::isImmutable() const +{ + return mImmutable; +} + +GLint Texture::creationLevels(GLsizei width, GLsizei height) const +{ + if ((isPow2(width) && isPow2(height)) || getContext()->supportsNonPower2Texture()) { - ERR("Failed to lock the destination surface (rectangle might be invalid)."); - surface->UnlockRect(); - surface->Release(); - return error(GL_OUT_OF_MEMORY); + return 0; // Maximum number of levels } - - if (destLock.pBits && sourceLock.pBits) + else { - unsigned char *source = (unsigned char*)sourceLock.pBits; - unsigned char *dest = (unsigned char*)destLock.pBits; + // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps. + return 1; + } +} - switch (description.Format) - { - case D3DFMT_X8R8G8B8: - case D3DFMT_A8R8G8B8: - switch(getD3DFormat()) - { - case D3DFMT_L8: - for(int y = 0; y < height; y++) - { - for(int x = 0; x < width; x++) - { - dest[x] = source[x * 4 + 2]; - } +GLint Texture::creationLevels(GLsizei size) const +{ + return creationLevels(size, size); +} - source += sourceLock.Pitch; - dest += destLock.Pitch; - } - break; - case D3DFMT_A8L8: - for(int y = 0; y < height; y++) - { - for(int x = 0; x < width; x++) - { - dest[x * 2 + 0] = source[x * 4 + 2]; - dest[x * 2 + 1] = source[x * 4 + 3]; - } +int Texture::levelCount() const +{ + return getBaseTexture() ? getBaseTexture()->GetLevelCount() : 0; +} - source += sourceLock.Pitch; - dest += destLock.Pitch; - } - break; - default: - UNREACHABLE(); - } - break; - case D3DFMT_R5G6B5: - switch(getD3DFormat()) - { - case D3DFMT_L8: - for(int y = 0; y < height; y++) - { - for(int x = 0; x < width; x++) - { - unsigned char red = source[x * 2 + 1] & 0xF8; - dest[x] = red | (red >> 5); - } +Blit *Texture::getBlitter() +{ + Context *context = getContext(); + return context->getBlitter(); +} - source += sourceLock.Pitch; - dest += destLock.Pitch; - } - break; - default: - UNREACHABLE(); - } - break; - case D3DFMT_A1R5G5B5: - switch(getD3DFormat()) - { - case D3DFMT_L8: - for(int y = 0; y < height; y++) - { - for(int x = 0; x < width; x++) - { - unsigned char red = source[x * 2 + 1] & 0x7C; - dest[x] = (red << 1) | (red >> 4); - } +bool Texture::copyToRenderTarget(IDirect3DSurface9 *dest, IDirect3DSurface9 *source, bool fromManaged) +{ + if (source && dest) + { + HRESULT result; - source += sourceLock.Pitch; - dest += destLock.Pitch; - } - break; - case D3DFMT_A8L8: - for(int y = 0; y < height; y++) - { - for(int x = 0; x < width; x++) - { - unsigned char red = source[x * 2 + 1] & 0x7C; - dest[x * 2 + 0] = (red << 1) | (red >> 4); - dest[x * 2 + 1] = (signed char)source[x * 2 + 1] >> 7; - } + if (fromManaged) + { + result = D3DXLoadSurfaceFromSurface(dest, NULL, NULL, source, NULL, NULL, D3DX_FILTER_BOX, 0); + } + else + { + egl::Display *display = getDisplay(); + IDirect3DDevice9 *device = display->getDevice(); - source += sourceLock.Pitch; - dest += destLock.Pitch; - } - break; - default: - UNREACHABLE(); - } - break; - default: - UNREACHABLE(); + display->endScene(); + result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE); } - image->dirty = true; - mDirtyMetaData = true; + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + return false; + } } - image->surface->UnlockRect(); - surface->UnlockRect(); - surface->Release(); + return true; } -D3DFORMAT Texture::getD3DFormat() const +TextureStorage2D::TextureStorage2D(IDirect3DTexture9 *surfaceTexture) : TextureStorage(true), mRenderTargetSerial(RenderbufferStorage::issueSerial()) { - return selectFormat(getFormat(), mType); + mTexture = surfaceTexture; } -IDirect3DBaseTexture9 *Texture::getTexture() +TextureStorage2D::TextureStorage2D(int levels, D3DFORMAT format, int width, int height, bool renderTarget) + : TextureStorage(renderTarget), mRenderTargetSerial(RenderbufferStorage::issueSerial()) { - if (!isComplete()) + IDirect3DDevice9 *device = getDevice(); + + mTexture = NULL; + HRESULT result = device->CreateTexture(width, height, levels, isRenderTarget() ? D3DUSAGE_RENDERTARGET : 0, format, getPool(), &mTexture, NULL); + + if (FAILED(result)) { - return NULL; + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + error(GL_OUT_OF_MEMORY); } +} - if (mDirtyMetaData) +TextureStorage2D::~TextureStorage2D() +{ + if (mTexture) { - mBaseTexture = createTexture(); - mIsRenderable = false; + mTexture->Release(); } +} + +IDirect3DSurface9 *TextureStorage2D::getSurfaceLevel(int level) +{ + IDirect3DSurface9 *surface = NULL; - if (mDirtyMetaData || dirtyImageData()) + if (mTexture) { - updateTexture(); + HRESULT result = mTexture->GetSurfaceLevel(level, &surface); + ASSERT(SUCCEEDED(result)); } - mDirtyMetaData = false; - ASSERT(!dirtyImageData()); + return surface; +} - return mBaseTexture; +IDirect3DBaseTexture9 *TextureStorage2D::getBaseTexture() const +{ + return mTexture; } -bool Texture::isDirty() const +unsigned int TextureStorage2D::getRenderTargetSerial(GLenum target) const { - return (mDirty || mDirtyMetaData || dirtyImageData()); + return mRenderTargetSerial; } -// Returns the top-level texture surface as a render target -void Texture::needRenderTarget() +Texture2D::Texture2D(GLuint id) : Texture(id) { - if (!mIsRenderable) - { - mBaseTexture = convertToRenderTarget(); - mIsRenderable = true; - } + mTexStorage = NULL; + mSurface = NULL; + mColorbufferProxy = NULL; + mProxyRefs = 0; +} - if (dirtyImageData()) +Texture2D::~Texture2D() +{ + mColorbufferProxy = NULL; + + delete mTexStorage; + mTexStorage = NULL; + + if (mSurface) { - updateTexture(); + mSurface->setBoundTexture(NULL); + mSurface = NULL; } +} - mDirtyMetaData = false; +// We need to maintain a count of references to renderbuffers acting as +// proxies for this texture, so that we do not attempt to use a pointer +// to a renderbuffer proxy which has been deleted. +void Texture2D::addProxyRef(const Renderbuffer *proxy) +{ + mProxyRefs++; } -void Texture::dropTexture() +void Texture2D::releaseProxy(const Renderbuffer *proxy) { - if (mBaseTexture) - { - mBaseTexture = NULL; - } + if (mProxyRefs > 0) + mProxyRefs--; - mIsRenderable = false; + if (mProxyRefs == 0) + mColorbufferProxy = NULL; } -void Texture::pushTexture(IDirect3DBaseTexture9 *newTexture, bool renderable) +GLenum Texture2D::getTarget() const { - mBaseTexture = newTexture; - mDirtyMetaData = false; - mIsRenderable = renderable; - mDirty = true; + return GL_TEXTURE_2D; } - -GLint Texture::creationLevels(GLsizei width, GLsizei height, GLint maxlevel) const +GLsizei Texture2D::getWidth(GLint level) const { - if (isPow2(width) && isPow2(height)) - { - return maxlevel; - } + if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) + return mImageArray[level].getWidth(); else - { - // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps. - return 1; - } + return 0; } -GLint Texture::creationLevels(GLsizei size, GLint maxlevel) const +GLsizei Texture2D::getHeight(GLint level) const { - return creationLevels(size, size, maxlevel); + if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) + return mImageArray[level].getHeight(); + else + return 0; } -int Texture::levelCount() const +GLenum Texture2D::getInternalFormat() const { - return mBaseTexture ? mBaseTexture->GetLevelCount() : 0; + return mImageArray[0].getFormat(); } -bool Texture::isRenderable() const +GLenum Texture2D::getType() const { - return mIsRenderable; + return mImageArray[0].getType(); } -Texture2D::Texture2D(GLuint id) : Texture(id) +D3DFORMAT Texture2D::getD3DFormat() const { - mTexture = NULL; + return mImageArray[0].getD3DFormat(); } -Texture2D::~Texture2D() +void Texture2D::redefineImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type) { - mColorbufferProxy.set(NULL); + releaseTexImage(); - if (mTexture) + bool redefined = mImageArray[level].redefine(format, width, height, type, false); + + if (mTexStorage && redefined) { - mTexture->Release(); - mTexture = NULL; + for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) + { + mImageArray[i].markDirty(); + } + + delete mTexStorage; + mTexStorage = NULL; + mDirtyImages = true; } } -GLenum Texture2D::getTarget() const +void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) { - return GL_TEXTURE_2D; -} + redefineImage(level, format, width, height, type); -GLenum Texture2D::getFormat() const -{ - return mImageArray[0].format; + Texture::setImage(unpackAlignment, pixels, &mImageArray[level]); } -// While OpenGL doesn't check texture consistency until draw-time, D3D9 requires a complete texture -// for render-to-texture (such as CopyTexImage). We have no way of keeping individual inconsistent levels. -// Call this when a particular level of the texture must be defined with a specific format, width and height. -// -// Returns true if the existing texture was unsuitable and had to be destroyed. If so, it will also set -// a new height and width for the texture by working backwards from the given width and height. -bool Texture2D::redefineTexture(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum type) +void Texture2D::bindTexImage(egl::Surface *surface) { - bool widthOkay = (mWidth >> level == width); - bool heightOkay = (mHeight >> level == height); + releaseTexImage(); - bool sizeOkay = ((widthOkay && heightOkay) - || (widthOkay && mHeight >> level == 0 && height == 1) - || (heightOkay && mWidth >> level == 0 && width == 1)); + GLenum format; - bool typeOkay = (type == mType); + switch(surface->getFormat()) + { + case D3DFMT_A8R8G8B8: + format = GL_RGBA; + break; + case D3DFMT_X8R8G8B8: + format = GL_RGB; + break; + default: + UNIMPLEMENTED(); + return; + } - bool textureOkay = (sizeOkay && typeOkay && internalFormat == mImageArray[0].format); + mImageArray[0].redefine(format, surface->getWidth(), surface->getHeight(), GL_UNSIGNED_BYTE, true); - if (!textureOkay) - { - TRACE("Redefining 2D texture (%d, 0x%04X, %d, %d => 0x%04X, %d, %d).", level, - mImageArray[0].format, mWidth, mHeight, - internalFormat, width, height); + delete mTexStorage; + mTexStorage = new TextureStorage2D(surface->getOffscreenTexture()); - // Purge all the levels and the texture. + mDirtyImages = true; + mSurface = surface; + mSurface->setBoundTexture(this); +} - for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) - { - if (mImageArray[i].surface != NULL) - { - mImageArray[i].dirty = false; +void Texture2D::releaseTexImage() +{ + if (mSurface) + { + mSurface->setBoundTexture(NULL); + mSurface = NULL; - mImageArray[i].surface->Release(); - mImageArray[i].surface = NULL; - } + if (mTexStorage) + { + delete mTexStorage; + mTexStorage = NULL; } - if (mTexture != NULL) + for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) { - mTexture->Release(); - mTexture = NULL; - dropTexture(); + mImageArray[i].redefine(GL_RGBA, 0, 0, GL_UNSIGNED_BYTE, true); } - - mWidth = width << level; - mHeight = height << level; - mImageArray[0].format = internalFormat; - mType = type; } - - return !textureOkay; } -void Texture2D::setImage(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) +void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels) { - redefineTexture(level, internalFormat, width, height, type); + redefineImage(level, format, width, height, GL_UNSIGNED_BYTE); - Texture::setImage(width, height, format, type, unpackAlignment, pixels, &mImageArray[level]); -} - -void Texture2D::setCompressedImage(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels) -{ - redefineTexture(level, internalFormat, width, height, GL_UNSIGNED_BYTE); - - Texture::setCompressedImage(width, height, internalFormat, imageSize, pixels, &mImageArray[level]); + Texture::setCompressedImage(imageSize, pixels, &mImageArray[level]); } void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) { - ASSERT(mImageArray[level].surface != NULL); + ASSERT(mImageArray[level].getSurface() != NULL); if (level < levelCount()) { - IDirect3DSurface9 *destLevel = NULL; - HRESULT result = mTexture->GetSurfaceLevel(level, &destLevel); + IDirect3DSurface9 *destLevel = mTexStorage->getSurfaceLevel(level); - ASSERT(SUCCEEDED(result)); - - if (SUCCEEDED(result)) + if (destLevel) { - Image *img = &mImageArray[level]; - - RECT sourceRect; - sourceRect.left = xoffset; - sourceRect.top = yoffset; - sourceRect.right = xoffset + width; - sourceRect.bottom = yoffset + height; - - POINT destPoint; - destPoint.x = xoffset; - destPoint.y = yoffset; - - result = getDevice()->UpdateSurface(img->surface, &sourceRect, destLevel, &destPoint); - ASSERT(SUCCEEDED(result)); + Image *image = &mImageArray[level]; + image->updateSurface(destLevel, xoffset, yoffset, width, height); destLevel->Release(); - - img->dirty = false; + image->markClean(); } } } @@ -1325,7 +1910,7 @@ void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GL } } -void Texture2D::copyImage(GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, RenderbufferStorage *source) +void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) { IDirect3DSurface9 *renderTarget = source->getRenderTarget(); @@ -1335,48 +1920,48 @@ void Texture2D::copyImage(GLint level, GLenum internalFormat, GLint x, GLint y, return error(GL_OUT_OF_MEMORY); } - bool redefined = redefineTexture(level, internalFormat, width, height, mType); + redefineImage(level, format, width, height, GL_UNSIGNED_BYTE); - if (!isRenderableFormat()) + if (!mImageArray[level].isRenderableFormat()) { - copyNonRenderable(&mImageArray[level], internalFormat, 0, 0, x, y, width, height, renderTarget); + mImageArray[level].copy(0, 0, x, y, width, height, renderTarget); + mDirtyImages = true; } else { - if (redefined) + if (!mTexStorage || !mTexStorage->isRenderTarget()) { convertToRenderTarget(); - pushTexture(mTexture, true); - } - else - { - needRenderTarget(); } + + mImageArray[level].markClean(); if (width != 0 && height != 0 && level < levelCount()) { - RECT sourceRect; - sourceRect.left = x; - sourceRect.right = x + width; - sourceRect.top = y; - sourceRect.bottom = y + height; + RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight()); + sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth()); + sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight()); + sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth()); + sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight()); - IDirect3DSurface9 *dest; - HRESULT hr = mTexture->GetSurfaceLevel(level, &dest); + GLint destYOffset = transformPixelYOffset(0, height, mImageArray[level].getHeight()); + + IDirect3DSurface9 *dest = mTexStorage->getSurfaceLevel(level); - getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, internalFormat, 0, 0, dest); - dest->Release(); + if (dest) + { + getBlitter()->copy(renderTarget, sourceRect, format, 0, destYOffset, dest); + dest->Release(); + } } } - mImageArray[level].width = width; - mImageArray[level].height = height; - mImageArray[level].format = internalFormat; + renderTarget->Release(); } -void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, RenderbufferStorage *source) +void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) { - if (xoffset + width > mImageArray[level].width || yoffset + height > mImageArray[level].height) + if (xoffset + width > mImageArray[level].getWidth() || yoffset + height > mImageArray[level].getHeight()) { return error(GL_INVALID_VALUE); } @@ -1389,46 +1974,83 @@ void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yo return error(GL_OUT_OF_MEMORY); } - bool redefined = redefineTexture(0, mImageArray[0].format, mImageArray[0].width, mImageArray[0].height, mType); - - if (!isRenderableFormat()) + if (!mImageArray[level].isRenderableFormat() || (!mTexStorage && !isSamplerComplete())) { - copyNonRenderable(&mImageArray[level], getFormat(), xoffset, yoffset, x, y, width, height, renderTarget); + mImageArray[level].copy(xoffset, yoffset, x, y, width, height, renderTarget); + mDirtyImages = true; } else { - if (redefined) + if (!mTexStorage || !mTexStorage->isRenderTarget()) { convertToRenderTarget(); - pushTexture(mTexture, true); - } - else - { - needRenderTarget(); } + + updateTexture(); if (level < levelCount()) { - RECT sourceRect; - sourceRect.left = x; - sourceRect.right = x + width; - sourceRect.top = y; - sourceRect.bottom = y + height; + RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight()); + sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth()); + sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight()); + sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth()); + sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight()); + + GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[level].getHeight()); - IDirect3DSurface9 *dest; - HRESULT hr = mTexture->GetSurfaceLevel(level, &dest); + IDirect3DSurface9 *dest = mTexStorage->getSurfaceLevel(level); - getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0].format, xoffset, yoffset, dest); - dest->Release(); + if (dest) + { + getBlitter()->copy(renderTarget, sourceRect, mImageArray[0].getFormat(), xoffset, destYOffset, dest); + dest->Release(); + } } } + + renderTarget->Release(); } -// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81. -bool Texture2D::isComplete() const +void Texture2D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) { - GLsizei width = mImageArray[0].width; - GLsizei height = mImageArray[0].height; + GLenum format = gl::ExtractFormat(internalformat); + GLenum type = gl::ExtractType(internalformat); + D3DFORMAT d3dfmt = ConvertTextureFormatType(format, type); + const bool renderTarget = IsTextureFormatRenderable(d3dfmt) && (mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE); + + delete mTexStorage; + mTexStorage = new TextureStorage2D(levels, d3dfmt, width, height, renderTarget); + mImmutable = true; + + for (int level = 0; level < levels; level++) + { + mImageArray[level].redefine(format, width, height, type, true); + width = std::max(1, width >> 1); + height = std::max(1, height >> 1); + } + + for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) + { + mImageArray[level].redefine(GL_NONE, 0, 0, GL_UNSIGNED_BYTE, true); + } + + if (mTexStorage->isManaged()) + { + int levels = levelCount(); + + for (int level = 0; level < levels; level++) + { + IDirect3DSurface9 *surface = mTexStorage->getSurfaceLevel(level); + mImageArray[level].setManagedSurface(surface); + } + } +} + +// Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85. +bool Texture2D::isSamplerComplete() const +{ + GLsizei width = mImageArray[0].getWidth(); + GLsizei height = mImageArray[0].getHeight(); if (width <= 0 || height <= 0) { @@ -1449,11 +2071,11 @@ bool Texture2D::isComplete() const case GL_LINEAR_MIPMAP_LINEAR: mipmapping = true; break; - default: UNREACHABLE(); + default: UNREACHABLE(); } - if ((getFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) || - (getFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter())) + if ((getInternalFormat() == GL_FLOAT && !getContext()->supportsFloat32LinearFilter()) || + (getInternalFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsFloat16LinearFilter())) { if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST)) { @@ -1461,38 +2083,74 @@ bool Texture2D::isComplete() const } } + bool npotSupport = getContext()->supportsNonPower2Texture(); - if ((getWrapS() != GL_CLAMP_TO_EDGE && !isPow2(width)) - || (getWrapT() != GL_CLAMP_TO_EDGE && !isPow2(height))) + if (!npotSupport) { - return false; + if ((getWrapS() != GL_CLAMP_TO_EDGE && !isPow2(width)) || + (getWrapT() != GL_CLAMP_TO_EDGE && !isPow2(height))) + { + return false; + } } if (mipmapping) { - if (!isPow2(width) || !isPow2(height)) + if (!npotSupport) + { + if (!isPow2(width) || !isPow2(height)) + { + return false; + } + } + + if (!isMipmapComplete()) { return false; } + } - int q = log2(std::max(width, height)); + return true; +} - for (int level = 1; level <= q; level++) +// Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81. +bool Texture2D::isMipmapComplete() const +{ + if (isImmutable()) + { + return true; + } + + GLsizei width = mImageArray[0].getWidth(); + GLsizei height = mImageArray[0].getHeight(); + + if (width <= 0 || height <= 0) + { + return false; + } + + int q = log2(std::max(width, height)); + + for (int level = 1; level <= q; level++) + { + if (mImageArray[level].getFormat() != mImageArray[0].getFormat()) { - if (mImageArray[level].format != mImageArray[0].format) - { - return false; - } + return false; + } - if (mImageArray[level].width != std::max(1, width >> level)) - { - return false; - } + if (mImageArray[level].getType() != mImageArray[0].getType()) + { + return false; + } - if (mImageArray[level].height != std::max(1, height >> level)) - { - return false; - } + if (mImageArray[level].getWidth() != std::max(1, width >> level)) + { + return false; + } + + if (mImageArray[level].getHeight() != std::max(1, height >> level)) + { + return false; } } @@ -1501,186 +2159,122 @@ bool Texture2D::isComplete() const bool Texture2D::isCompressed() const { - return IsCompressed(getFormat()); + return IsCompressed(getInternalFormat()); } -// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one -IDirect3DBaseTexture9 *Texture2D::createTexture() +IDirect3DBaseTexture9 *Texture2D::getBaseTexture() const { - IDirect3DTexture9 *texture; - - IDirect3DDevice9 *device = getDevice(); - D3DFORMAT format = selectFormat(mImageArray[0].format, mType); + return mTexStorage ? mTexStorage->getBaseTexture() : NULL; +} - HRESULT result = device->CreateTexture(mWidth, mHeight, creationLevels(mWidth, mHeight, 0), 0, format, D3DPOOL_DEFAULT, &texture, NULL); +// Constructs a Direct3D 9 texture resource from the texture images +void Texture2D::createTexture() +{ + GLsizei width = mImageArray[0].getWidth(); + GLsizei height = mImageArray[0].getHeight(); + GLint levels = creationLevels(width, height); + D3DFORMAT format = mImageArray[0].getD3DFormat(); + const bool renderTarget = IsTextureFormatRenderable(format) && (mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE); - if (FAILED(result)) + delete mTexStorage; + mTexStorage = new TextureStorage2D(levels, format, width, height, renderTarget); + + if (mTexStorage->isManaged()) { - ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL); + int levels = levelCount(); + + for (int level = 0; level < levels; level++) + { + IDirect3DSurface9 *surface = mTexStorage->getSurfaceLevel(level); + mImageArray[level].setManagedSurface(surface); + } } - if (mTexture) mTexture->Release(); - mTexture = texture; - return texture; + mDirtyImages = true; } void Texture2D::updateTexture() { - IDirect3DDevice9 *device = getDevice(); - int levels = levelCount(); for (int level = 0; level < levels; level++) { - if (mImageArray[level].dirty) - { - IDirect3DSurface9 *levelSurface = NULL; - HRESULT result = mTexture->GetSurfaceLevel(level, &levelSurface); - - ASSERT(SUCCEEDED(result)); - - if (SUCCEEDED(result)) - { - result = device->UpdateSurface(mImageArray[level].surface, NULL, levelSurface, NULL); - ASSERT(SUCCEEDED(result)); + Image *image = &mImageArray[level]; - levelSurface->Release(); - - mImageArray[level].dirty = false; - } + if (image->isDirty()) + { + commitRect(level, 0, 0, mImageArray[level].getWidth(), mImageArray[level].getHeight()); } } } -IDirect3DBaseTexture9 *Texture2D::convertToRenderTarget() +void Texture2D::convertToRenderTarget() { - IDirect3DTexture9 *texture = NULL; + TextureStorage2D *newTexStorage = NULL; - if (mWidth != 0 && mHeight != 0) + if (mImageArray[0].getWidth() != 0 && mImageArray[0].getHeight() != 0) { - egl::Display *display = getDisplay(); - IDirect3DDevice9 *device = getDevice(); - D3DFORMAT format = selectFormat(mImageArray[0].format, mType); - - HRESULT result = device->CreateTexture(mWidth, mHeight, creationLevels(mWidth, mHeight, 0), D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL); + GLsizei width = mImageArray[0].getWidth(); + GLsizei height = mImageArray[0].getHeight(); + GLint levels = creationLevels(width, height); + D3DFORMAT format = mImageArray[0].getD3DFormat(); - if (FAILED(result)) - { - ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL); - } + newTexStorage = new TextureStorage2D(levels, format, width, height, true); - if (mTexture != NULL) + if (mTexStorage != NULL) { int levels = levelCount(); for (int i = 0; i < levels; i++) { - IDirect3DSurface9 *source; - result = mTexture->GetSurfaceLevel(i, &source); - - if (FAILED(result)) - { - ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - - texture->Release(); - - return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL); - } - - IDirect3DSurface9 *dest; - result = texture->GetSurfaceLevel(i, &dest); - - if (FAILED(result)) - { - ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - - texture->Release(); - source->Release(); - - return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL); + IDirect3DSurface9 *source = mTexStorage->getSurfaceLevel(i); + IDirect3DSurface9 *dest = newTexStorage->getSurfaceLevel(i); + + if (!copyToRenderTarget(dest, source, mTexStorage->isManaged())) + { + delete newTexStorage; + source->Release(); + dest->Release(); + return error(GL_OUT_OF_MEMORY); } - display->endScene(); - result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE); - - if (FAILED(result)) - { - ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - - texture->Release(); - source->Release(); - dest->Release(); - - return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL); - } - - source->Release(); - dest->Release(); + if (source) source->Release(); + if (dest) dest->Release(); } } } - if (mTexture != NULL) - { - mTexture->Release(); - } - - mTexture = texture; - return mTexture; -} - -bool Texture2D::dirtyImageData() const -{ - int q = log2(std::max(mWidth, mHeight)); + delete mTexStorage; + mTexStorage = newTexStorage; - for (int i = 0; i <= q; i++) - { - if (mImageArray[i].dirty) return true; - } - - return false; + mDirtyImages = true; } void Texture2D::generateMipmaps() { - if (!isPow2(mImageArray[0].width) || !isPow2(mImageArray[0].height)) + if (!getContext()->supportsNonPower2Texture()) { - return error(GL_INVALID_OPERATION); + if (!isPow2(mImageArray[0].getWidth()) || !isPow2(mImageArray[0].getHeight())) + { + return error(GL_INVALID_OPERATION); + } } // Purge array levels 1 through q and reset them to represent the generated mipmap levels. - unsigned int q = log2(std::max(mWidth, mHeight)); + unsigned int q = log2(std::max(mImageArray[0].getWidth(), mImageArray[0].getHeight())); for (unsigned int i = 1; i <= q; i++) { - if (mImageArray[i].surface != NULL) - { - mImageArray[i].surface->Release(); - mImageArray[i].surface = NULL; - } - - mImageArray[i].dirty = false; - - mImageArray[i].format = mImageArray[0].format; - mImageArray[i].width = std::max(mImageArray[0].width >> i, 1); - mImageArray[i].height = std::max(mImageArray[0].height >> i, 1); + redefineImage(i, mImageArray[0].getFormat(), + std::max(mImageArray[0].getWidth() >> i, 1), + std::max(mImageArray[0].getHeight() >> i, 1), + mImageArray[0].getType()); } - if (isRenderable()) + if (mTexStorage && mTexStorage->isRenderTarget()) { - if (mTexture == NULL) - { - ERR(" failed because mTexture was null."); - return; - } - for (unsigned int i = 1; i <= q; i++) { - IDirect3DSurface9 *upper = NULL; - IDirect3DSurface9 *lower = NULL; - - mTexture->GetSurfaceLevel(i-1, &upper); - mTexture->GetSurfaceLevel(i, &lower); + IDirect3DSurface9 *upper = mTexStorage->getSurfaceLevel(i - 1); + IDirect3DSurface9 *lower = mTexStorage->getSurfaceLevel(i); if (upper != NULL && lower != NULL) { @@ -1689,78 +2283,169 @@ void Texture2D::generateMipmaps() if (upper != NULL) upper->Release(); if (lower != NULL) lower->Release(); + + mImageArray[i].markClean(); } } else { for (unsigned int i = 1; i <= q; i++) { - createSurface(mImageArray[i].width, mImageArray[i].height, mImageArray[i].format, mType, &mImageArray[i]); - if (mImageArray[i].surface == NULL) + if (mImageArray[i].getSurface() == NULL) { return error(GL_OUT_OF_MEMORY); } - if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[i].surface, NULL, NULL, mImageArray[i - 1].surface, NULL, NULL, D3DX_FILTER_BOX, 0))) + if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[i].getSurface(), NULL, NULL, mImageArray[i - 1].getSurface(), NULL, NULL, D3DX_FILTER_BOX, 0))) { ERR(" failed to load filter %d to %d.", i - 1, i); } - mImageArray[i].dirty = true; + mImageArray[i].markDirty(); } - - mDirtyMetaData = true; } } -Renderbuffer *Texture2D::getColorbuffer(GLenum target) +Renderbuffer *Texture2D::getRenderbuffer(GLenum target) { if (target != GL_TEXTURE_2D) { return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL); } - if (mColorbufferProxy.get() == NULL) + if (mColorbufferProxy == NULL) { - mColorbufferProxy.set(new Renderbuffer(id(), new TextureColorbufferProxy(this, target))); + mColorbufferProxy = new Renderbuffer(id(), new RenderbufferTexture(this, target)); } - return mColorbufferProxy.get(); + return mColorbufferProxy; } IDirect3DSurface9 *Texture2D::getRenderTarget(GLenum target) { ASSERT(target == GL_TEXTURE_2D); - needRenderTarget(); - - if (mTexture == NULL) + // ensure the underlying texture is created + if (getStorage(true) == NULL) { return NULL; } + + updateTexture(); - IDirect3DSurface9 *renderTarget = NULL; - mTexture->GetSurfaceLevel(0, &renderTarget); + return mTexStorage->getSurfaceLevel(0); +} - return renderTarget; +TextureStorage *Texture2D::getStorage(bool renderTarget) +{ + if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget())) + { + if (renderTarget) + { + convertToRenderTarget(); + } + else + { + createTexture(); + } + } + + return mTexStorage; } -TextureCubeMap::TextureCubeMap(GLuint id) : Texture(id) +TextureStorageCubeMap::TextureStorageCubeMap(int levels, D3DFORMAT format, int size, bool renderTarget) + : TextureStorage(renderTarget), mFirstRenderTargetSerial(RenderbufferStorage::issueCubeSerials()) { + IDirect3DDevice9 *device = getDevice(); + mTexture = NULL; + HRESULT result = device->CreateCubeTexture(size, levels, isRenderTarget() ? D3DUSAGE_RENDERTARGET : 0, format, getPool(), &mTexture, NULL); + + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + error(GL_OUT_OF_MEMORY); + } +} + +TextureStorageCubeMap::~TextureStorageCubeMap() +{ + if (mTexture) + { + mTexture->Release(); + } +} + +IDirect3DSurface9 *TextureStorageCubeMap::getCubeMapSurface(GLenum faceTarget, int level) +{ + IDirect3DSurface9 *surface = NULL; + + if (mTexture) + { + HRESULT result = mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(faceTarget), level, &surface); + ASSERT(SUCCEEDED(result)); + } + + return surface; +} + +IDirect3DBaseTexture9 *TextureStorageCubeMap::getBaseTexture() const +{ + return mTexture; +} + +unsigned int TextureStorageCubeMap::getRenderTargetSerial(GLenum target) const +{ + return mFirstRenderTargetSerial + TextureCubeMap::faceIndex(target); +} + +TextureCubeMap::TextureCubeMap(GLuint id) : Texture(id) +{ + mTexStorage = NULL; + for (int i = 0; i < 6; i++) + { + mFaceProxies[i] = NULL; + mFaceProxyRefs[i] = 0; + } } TextureCubeMap::~TextureCubeMap() { for (int i = 0; i < 6; i++) { - mFaceProxies[i].set(NULL); + mFaceProxies[i] = NULL; } - if (mTexture) + delete mTexStorage; + mTexStorage = NULL; +} + +// We need to maintain a count of references to renderbuffers acting as +// proxies for this texture, so that the texture is not deleted while +// proxy references still exist. If the reference count drops to zero, +// we set our proxy pointer NULL, so that a new attempt at referencing +// will cause recreation. +void TextureCubeMap::addProxyRef(const Renderbuffer *proxy) +{ + for (int i = 0; i < 6; i++) { - mTexture->Release(); - mTexture = NULL; + if (mFaceProxies[i] == proxy) + mFaceProxyRefs[i]++; + } +} + +void TextureCubeMap::releaseProxy(const Renderbuffer *proxy) +{ + for (int i = 0; i < 6; i++) + { + if (mFaceProxies[i] == proxy) + { + if (mFaceProxyRefs[i] > 0) + mFaceProxyRefs[i]--; + + if (mFaceProxyRefs[i] == 0) + mFaceProxies[i] = NULL; + } } } @@ -1769,79 +2454,90 @@ GLenum TextureCubeMap::getTarget() const return GL_TEXTURE_CUBE_MAP; } -GLenum TextureCubeMap::getFormat() const +GLsizei TextureCubeMap::getWidth(GLint level) const +{ + if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) + return mImageArray[0][level].getWidth(); + else + return 0; +} + +GLsizei TextureCubeMap::getHeight(GLint level) const +{ + if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) + return mImageArray[0][level].getHeight(); + else + return 0; +} + +GLenum TextureCubeMap::getInternalFormat() const { - return mImageArray[0][0].format; + return mImageArray[0][0].getFormat(); } -void TextureCubeMap::setImagePosX(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) +GLenum TextureCubeMap::getType() const { - setImage(0, level, internalFormat, width, height, format, type, unpackAlignment, pixels); + return mImageArray[0][0].getType(); } -void TextureCubeMap::setImageNegX(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) +D3DFORMAT TextureCubeMap::getD3DFormat() const { - setImage(1, level, internalFormat, width, height, format, type, unpackAlignment, pixels); + return mImageArray[0][0].getD3DFormat(); } -void TextureCubeMap::setImagePosY(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) +void TextureCubeMap::setImagePosX(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) { - setImage(2, level, internalFormat, width, height, format, type, unpackAlignment, pixels); + setImage(0, level, width, height, format, type, unpackAlignment, pixels); } -void TextureCubeMap::setImageNegY(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) +void TextureCubeMap::setImageNegX(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) { - setImage(3, level, internalFormat, width, height, format, type, unpackAlignment, pixels); + setImage(1, level, width, height, format, type, unpackAlignment, pixels); } -void TextureCubeMap::setImagePosZ(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) +void TextureCubeMap::setImagePosY(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) { - setImage(4, level, internalFormat, width, height, format, type, unpackAlignment, pixels); + setImage(2, level, width, height, format, type, unpackAlignment, pixels); } -void TextureCubeMap::setImageNegZ(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) +void TextureCubeMap::setImageNegY(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) { - setImage(5, level, internalFormat, width, height, format, type, unpackAlignment, pixels); + setImage(3, level, width, height, format, type, unpackAlignment, pixels); } -void TextureCubeMap::setCompressedImage(GLenum face, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels) +void TextureCubeMap::setImagePosZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) { - redefineTexture(level, internalFormat, width); + setImage(4, level, width, height, format, type, unpackAlignment, pixels); +} - Texture::setCompressedImage(width, height, internalFormat, imageSize, pixels, &mImageArray[faceIndex(face)][level]); +void TextureCubeMap::setImageNegZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) +{ + setImage(5, level, width, height, format, type, unpackAlignment, pixels); } -void TextureCubeMap::commitRect(GLenum faceTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) +void TextureCubeMap::setCompressedImage(GLenum face, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels) { - int face = faceIndex(faceTarget); + redefineImage(faceIndex(face), level, format, width, height, GL_UNSIGNED_BYTE); + + Texture::setCompressedImage(imageSize, pixels, &mImageArray[faceIndex(face)][level]); +} - ASSERT(mImageArray[face][level].surface != NULL); +void TextureCubeMap::commitRect(int face, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) +{ + ASSERT(mImageArray[face][level].getSurface() != NULL); if (level < levelCount()) { - IDirect3DSurface9 *destLevel = getCubeMapSurface(face, level); + IDirect3DSurface9 *destLevel = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level); ASSERT(destLevel != NULL); if (destLevel != NULL) { - Image *img = &mImageArray[face][level]; - - RECT sourceRect; - sourceRect.left = xoffset; - sourceRect.top = yoffset; - sourceRect.right = xoffset + width; - sourceRect.bottom = yoffset + height; - - POINT destPoint; - destPoint.x = xoffset; - destPoint.y = yoffset; - - HRESULT result = getDevice()->UpdateSurface(img->surface, &sourceRect, destLevel, &destPoint); - ASSERT(SUCCEEDED(result)); + Image *image = &mImageArray[face][level]; + image->updateSurface(destLevel, xoffset, yoffset, width, height); destLevel->Release(); - - img->dirty = false; + image->markClean(); } } } @@ -1850,7 +2546,7 @@ void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint y { if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[faceIndex(target)][level])) { - commitRect(target, level, xoffset, yoffset, width, height); + commitRect(faceIndex(target), level, xoffset, yoffset, width, height); } } @@ -1858,19 +2554,14 @@ void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffse { if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[faceIndex(target)][level])) { - commitRect(target, level, xoffset, yoffset, width, height); + commitRect(faceIndex(target), level, xoffset, yoffset, width, height); } } -// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81. -bool TextureCubeMap::isComplete() const +// Tests for cube map sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 86. +bool TextureCubeMap::isSamplerComplete() const { - int size = mImageArray[0][0].width; - - if (size <= 0) - { - return false; - } + int size = mImageArray[0][0].getWidth(); bool mipmapping; @@ -1886,50 +2577,101 @@ bool TextureCubeMap::isComplete() const case GL_LINEAR_MIPMAP_LINEAR: mipmapping = true; break; - default: UNREACHABLE(); + default: + UNREACHABLE(); + return false; } - for (int face = 0; face < 6; face++) + if ((getInternalFormat() == GL_FLOAT && !getContext()->supportsFloat32LinearFilter()) || + (getInternalFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsFloat16LinearFilter())) { - if (mImageArray[face][0].width != size || mImageArray[face][0].height != size) + if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST)) { return false; } } - if ((getFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) || - (getFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter())) + if (!isPow2(size) && !getContext()->supportsNonPower2Texture()) { - if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST)) + if (getWrapS() != GL_CLAMP_TO_EDGE || getWrapT() != GL_CLAMP_TO_EDGE || mipmapping) { return false; } } - if (mipmapping) + if (!mipmapping) + { + if (!isCubeComplete()) + { + return false; + } + } + else { - if (!isPow2(size) && (getWrapS() != GL_CLAMP_TO_EDGE || getWrapT() != GL_CLAMP_TO_EDGE)) + if (!isMipmapCubeComplete()) // Also tests for isCubeComplete() { return false; } + } - int q = log2(size); + return true; +} - for (int face = 0; face < 6; face++) +// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81. +bool TextureCubeMap::isCubeComplete() const +{ + if (mImageArray[0][0].getWidth() <= 0 || mImageArray[0][0].getHeight() != mImageArray[0][0].getWidth()) + { + return false; + } + + for (unsigned int face = 1; face < 6; face++) + { + if (mImageArray[face][0].getWidth() != mImageArray[0][0].getWidth() || + mImageArray[face][0].getWidth() != mImageArray[0][0].getHeight() || + mImageArray[face][0].getFormat() != mImageArray[0][0].getFormat() || + mImageArray[face][0].getType() != mImageArray[0][0].getType()) { - for (int level = 1; level <= q; level++) + return false; + } + } + + return true; +} + +bool TextureCubeMap::isMipmapCubeComplete() const +{ + if (isImmutable()) + { + return true; + } + + if (!isCubeComplete()) + { + return false; + } + + GLsizei size = mImageArray[0][0].getWidth(); + + int q = log2(size); + + for (int face = 0; face < 6; face++) + { + for (int level = 1; level <= q; level++) + { + if (mImageArray[face][level].getFormat() != mImageArray[0][0].getFormat()) { - if (mImageArray[face][level].format != mImageArray[0][0].format) - { - return false; - } + return false; + } - if (mImageArray[face][level].width != std::max(1, size >> level)) - { - return false; - } + if (mImageArray[face][level].getType() != mImageArray[0][0].getType()) + { + return false; + } - ASSERT(mImageArray[face][level].height == mImageArray[face][level].width); + if (mImageArray[face][level].getWidth() != std::max(1, size >> level)) + { + return false; } } } @@ -1939,143 +2681,107 @@ bool TextureCubeMap::isComplete() const bool TextureCubeMap::isCompressed() const { - return IsCompressed(getFormat()); + return IsCompressed(getInternalFormat()); } -// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one -IDirect3DBaseTexture9 *TextureCubeMap::createTexture() +IDirect3DBaseTexture9 *TextureCubeMap::getBaseTexture() const { - IDirect3DDevice9 *device = getDevice(); - D3DFORMAT format = selectFormat(mImageArray[0][0].format, mType); + return mTexStorage ? mTexStorage->getBaseTexture() : NULL; +} - IDirect3DCubeTexture9 *texture; +// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one +void TextureCubeMap::createTexture() +{ + GLsizei size = mImageArray[0][0].getWidth(); + GLint levels = creationLevels(size, 0); + D3DFORMAT format = mImageArray[0][0].getD3DFormat(); + const bool renderTarget = IsTextureFormatRenderable(format) && (mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE); - HRESULT result = device->CreateCubeTexture(mWidth, creationLevels(mWidth, 0), 0, format, D3DPOOL_DEFAULT, &texture, NULL); + delete mTexStorage; + mTexStorage = new TextureStorageCubeMap(levels, format, size, renderTarget); - if (FAILED(result)) + if (mTexStorage->isManaged()) { - ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL); - } + int levels = levelCount(); - if (mTexture) mTexture->Release(); + for (int face = 0; face < 6; face++) + { + for (int level = 0; level < levels; level++) + { + IDirect3DSurface9 *surface = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level); + mImageArray[face][level].setManagedSurface(surface); + } + } + } - mTexture = texture; - return mTexture; + mDirtyImages = true; } void TextureCubeMap::updateTexture() { - IDirect3DDevice9 *device = getDevice(); - for (int face = 0; face < 6; face++) { int levels = levelCount(); for (int level = 0; level < levels; level++) { - Image *img = &mImageArray[face][level]; + Image *image = &mImageArray[face][level]; - if (img->dirty) + if (image->isDirty()) { - IDirect3DSurface9 *levelSurface = getCubeMapSurface(face, level); - ASSERT(levelSurface != NULL); - - if (levelSurface != NULL) - { - HRESULT result = device->UpdateSurface(img->surface, NULL, levelSurface, NULL); - ASSERT(SUCCEEDED(result)); - - levelSurface->Release(); - - img->dirty = false; - } + commitRect(face, level, 0, 0, image->getWidth(), image->getHeight()); } } } } -IDirect3DBaseTexture9 *TextureCubeMap::convertToRenderTarget() +void TextureCubeMap::convertToRenderTarget() { - IDirect3DCubeTexture9 *texture = NULL; + TextureStorageCubeMap *newTexStorage = NULL; - if (mWidth != 0) + if (mImageArray[0][0].getWidth() != 0) { - egl::Display *display = getDisplay(); - IDirect3DDevice9 *device = getDevice(); - D3DFORMAT format = selectFormat(mImageArray[0][0].format, mType); - - HRESULT result = device->CreateCubeTexture(mWidth, creationLevels(mWidth, 0), D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL); + GLsizei size = mImageArray[0][0].getWidth(); + GLint levels = creationLevels(size, 0); + D3DFORMAT format = mImageArray[0][0].getD3DFormat(); - if (FAILED(result)) - { - ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL); - } + newTexStorage = new TextureStorageCubeMap(levels, format, size, true); - if (mTexture != NULL) + if (mTexStorage != NULL) { int levels = levelCount(); for (int f = 0; f < 6; f++) { for (int i = 0; i < levels; i++) { - IDirect3DSurface9 *source; - result = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &source); - - if (FAILED(result)) - { - ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - - texture->Release(); - - return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL); - } - - IDirect3DSurface9 *dest; - result = texture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &dest); + IDirect3DSurface9 *source = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i); + IDirect3DSurface9 *dest = newTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i); - if (FAILED(result)) + if (!copyToRenderTarget(dest, source, mTexStorage->isManaged())) { - ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - - texture->Release(); - source->Release(); - - return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL); + delete newTexStorage; + source->Release(); + dest->Release(); + return error(GL_OUT_OF_MEMORY); } - display->endScene(); - result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE); - - if (FAILED(result)) - { - ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - - texture->Release(); - source->Release(); - dest->Release(); - - return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL); - } + if (source) source->Release(); + if (dest) dest->Release(); } } } } - if (mTexture != NULL) - { - mTexture->Release(); - } + delete mTexStorage; + mTexStorage = newTexStorage; - mTexture = texture; - return mTexture; + mDirtyImages = true; } -void TextureCubeMap::setImage(int face, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) +void TextureCubeMap::setImage(int faceIndex, GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) { - redefineTexture(level, internalFormat, width); + redefineImage(faceIndex, level, format, width, height, type); - Texture::setImage(width, height, format, type, unpackAlignment, pixels, &mImageArray[face][level]); + Texture::setImage(unpackAlignment, pixels, &mImageArray[faceIndex][level]); } unsigned int TextureCubeMap::faceIndex(GLenum face) @@ -2089,74 +2795,28 @@ unsigned int TextureCubeMap::faceIndex(GLenum face) return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X; } -bool TextureCubeMap::dirtyImageData() const +void TextureCubeMap::redefineImage(int face, GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type) { - int q = log2(mWidth); + bool redefined = mImageArray[face][level].redefine(format, width, height, type, false); - for (int f = 0; f < 6; f++) + if (mTexStorage && redefined) { - for (int i = 0; i <= q; i++) - { - if (mImageArray[f][i].dirty) return true; - } - } - - return false; -} - -// While OpenGL doesn't check texture consistency until draw-time, D3D9 requires a complete texture -// for render-to-texture (such as CopyTexImage). We have no way of keeping individual inconsistent levels & faces. -// Call this when a particular level of the texture must be defined with a specific format, width and height. -// -// Returns true if the existing texture was unsuitable had to be destroyed. If so, it will also set -// a new size for the texture by working backwards from the given size. -bool TextureCubeMap::redefineTexture(GLint level, GLenum internalFormat, GLsizei width) -{ - // Are these settings compatible with level 0? - bool sizeOkay = (mImageArray[0][0].width >> level == width); - - bool textureOkay = (sizeOkay && internalFormat == mImageArray[0][0].format); - - if (!textureOkay) - { - TRACE("Redefining cube texture (%d, 0x%04X, %d => 0x%04X, %d).", level, - mImageArray[0][0].format, mImageArray[0][0].width, - internalFormat, width); - - // Purge all the levels and the texture. for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) { for (int f = 0; f < 6; f++) { - if (mImageArray[f][i].surface != NULL) - { - mImageArray[f][i].dirty = false; - - mImageArray[f][i].surface->Release(); - mImageArray[f][i].surface = NULL; - } + mImageArray[f][i].markDirty(); } } - if (mTexture != NULL) - { - mTexture->Release(); - mTexture = NULL; - dropTexture(); - } - - mWidth = width << level; - mImageArray[0][0].width = width << level; - mHeight = width << level; - mImageArray[0][0].height = width << level; + delete mTexStorage; + mTexStorage = NULL; - mImageArray[0][0].format = internalFormat; + mDirtyImages = true; } - - return !textureOkay; } -void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, RenderbufferStorage *source) +void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) { IDirect3DSurface9 *renderTarget = source->getRenderTarget(); @@ -2167,80 +2827,50 @@ void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum internalFormat } unsigned int faceindex = faceIndex(target); - bool redefined = redefineTexture(level, internalFormat, width); + redefineImage(faceindex, level, format, width, height, GL_UNSIGNED_BYTE); - if (!isRenderableFormat()) + if (!mImageArray[faceindex][level].isRenderableFormat()) { - copyNonRenderable(&mImageArray[faceindex][level], internalFormat, 0, 0, x, y, width, height, renderTarget); + mImageArray[faceindex][level].copy(0, 0, x, y, width, height, renderTarget); + mDirtyImages = true; } else { - if (redefined) + if (!mTexStorage || !mTexStorage->isRenderTarget()) { convertToRenderTarget(); - pushTexture(mTexture, true); - } - else - { - needRenderTarget(); } + + mImageArray[faceindex][level].markClean(); ASSERT(width == height); if (width > 0 && level < levelCount()) { - RECT sourceRect; - sourceRect.left = x; - sourceRect.right = x + width; - sourceRect.top = y; - sourceRect.bottom = y + height; + RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight()); + sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth()); + sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight()); + sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth()); + sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight()); - IDirect3DSurface9 *dest = getCubeMapSurface(target, level); + GLint destYOffset = transformPixelYOffset(0, height, mImageArray[faceindex][level].getWidth()); - getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, internalFormat, 0, 0, dest); - dest->Release(); - } - } - - mImageArray[faceindex][level].width = width; - mImageArray[faceindex][level].height = height; - mImageArray[faceindex][level].format = internalFormat; -} - -IDirect3DSurface9 *TextureCubeMap::getCubeMapSurface(unsigned int faceIdentifier, unsigned int level) -{ - unsigned int faceIndex; - - if (faceIdentifier < 6) - { - faceIndex = faceIdentifier; - } - else if (faceIdentifier >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && faceIdentifier <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z) - { - faceIndex = faceIdentifier - GL_TEXTURE_CUBE_MAP_POSITIVE_X; - } - else - { - UNREACHABLE(); - faceIndex = 0; - } + IDirect3DSurface9 *dest = mTexStorage->getCubeMapSurface(target, level); - if (mTexture == NULL) - { - UNREACHABLE(); - return NULL; + if (dest) + { + getBlitter()->copy(renderTarget, sourceRect, format, 0, destYOffset, dest); + dest->Release(); + } + } } - IDirect3DSurface9 *surface = NULL; - - HRESULT hr = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(faceIndex), level, &surface); - - return (SUCCEEDED(hr)) ? surface : NULL; + renderTarget->Release(); } -void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, RenderbufferStorage *source) +void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) { - GLsizei size = mImageArray[faceIndex(target)][level].width; + GLsizei size = mImageArray[faceIndex(target)][level].getWidth(); if (xoffset + width > size || yoffset + height > size) { @@ -2256,99 +2886,123 @@ void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLi } unsigned int faceindex = faceIndex(target); - bool redefined = redefineTexture(0, mImageArray[0][0].format, mImageArray[0][0].width); - - if (!isRenderableFormat()) + + if (!mImageArray[faceindex][level].isRenderableFormat() || (!mTexStorage && !isSamplerComplete())) { - copyNonRenderable(&mImageArray[faceindex][level], getFormat(), 0, 0, x, y, width, height, renderTarget); + mImageArray[faceindex][level].copy(0, 0, x, y, width, height, renderTarget); + mDirtyImages = true; } else { - if (redefined) + if (!mTexStorage || !mTexStorage->isRenderTarget()) { convertToRenderTarget(); - pushTexture(mTexture, true); - } - else - { - needRenderTarget(); } + + updateTexture(); if (level < levelCount()) { - RECT sourceRect; - sourceRect.left = x; - sourceRect.right = x + width; - sourceRect.top = y; - sourceRect.bottom = y + height; + RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight()); + sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth()); + sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight()); + sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth()); + sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight()); + + GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[faceindex][level].getWidth()); - IDirect3DSurface9 *dest = getCubeMapSurface(target, level); + IDirect3DSurface9 *dest = mTexStorage->getCubeMapSurface(target, level); - getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0][0].format, xoffset, yoffset, dest); - dest->Release(); + if (dest) + { + getBlitter()->copy(renderTarget, sourceRect, mImageArray[0][0].getFormat(), xoffset, destYOffset, dest); + dest->Release(); + } } } + + renderTarget->Release(); } -bool TextureCubeMap::isCubeComplete() const +void TextureCubeMap::storage(GLsizei levels, GLenum internalformat, GLsizei size) { - if (mImageArray[0][0].width == 0) + GLenum format = gl::ExtractFormat(internalformat); + GLenum type = gl::ExtractType(internalformat); + D3DFORMAT d3dfmt = ConvertTextureFormatType(format, type); + const bool renderTarget = IsTextureFormatRenderable(d3dfmt) && (mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE); + + delete mTexStorage; + mTexStorage = new TextureStorageCubeMap(levels, d3dfmt, size, renderTarget); + mImmutable = true; + + for (int level = 0; level < levels; level++) { - return false; + for (int face = 0; face < 6; face++) + { + mImageArray[face][level].redefine(format, size, size, type, true); + size = std::max(1, size >> 1); + } } - for (unsigned int f = 1; f < 6; f++) + for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) { - if (mImageArray[f][0].width != mImageArray[0][0].width - || mImageArray[f][0].format != mImageArray[0][0].format) + for (int face = 0; face < 6; face++) { - return false; + mImageArray[face][level].redefine(GL_NONE, 0, 0, GL_UNSIGNED_BYTE, true); } } - return true; + if (mTexStorage->isManaged()) + { + int levels = levelCount(); + + for (int face = 0; face < 6; face++) + { + for (int level = 0; level < levels; level++) + { + IDirect3DSurface9 *surface = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level); + mImageArray[face][level].setManagedSurface(surface); + } + } + } } void TextureCubeMap::generateMipmaps() { - if (!isPow2(mImageArray[0][0].width) || !isCubeComplete()) + if (!isCubeComplete()) { return error(GL_INVALID_OPERATION); } - // Purge array levels 1 through q and reset them to represent the generated mipmap levels. - unsigned int q = log2(mImageArray[0][0].width); - for (unsigned int f = 0; f < 6; f++) + if (!getContext()->supportsNonPower2Texture()) { - for (unsigned int i = 1; i <= q; i++) + if (!isPow2(mImageArray[0][0].getWidth())) { - if (mImageArray[f][i].surface != NULL) - { - mImageArray[f][i].surface->Release(); - mImageArray[f][i].surface = NULL; - } - - mImageArray[f][i].dirty = false; - - mImageArray[f][i].format = mImageArray[f][0].format; - mImageArray[f][i].width = std::max(mImageArray[f][0].width >> i, 1); - mImageArray[f][i].height = mImageArray[f][i].width; + return error(GL_INVALID_OPERATION); } } - if (isRenderable()) + // Purge array levels 1 through q and reset them to represent the generated mipmap levels. + unsigned int q = log2(mImageArray[0][0].getWidth()); + for (unsigned int f = 0; f < 6; f++) { - if (mTexture == NULL) + for (unsigned int i = 1; i <= q; i++) { - return; + redefineImage(f, i, mImageArray[f][0].getFormat(), + std::max(mImageArray[f][0].getWidth() >> i, 1), + std::max(mImageArray[f][0].getWidth() >> i, 1), + mImageArray[f][0].getType()); } + } + if (mTexStorage && mTexStorage->isRenderTarget()) + { for (unsigned int f = 0; f < 6; f++) { for (unsigned int i = 1; i <= q; i++) { - IDirect3DSurface9 *upper = getCubeMapSurface(f, i-1); - IDirect3DSurface9 *lower = getCubeMapSurface(f, i); + IDirect3DSurface9 *upper = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i-1); + IDirect3DSurface9 *lower = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i); if (upper != NULL && lower != NULL) { @@ -2357,6 +3011,8 @@ void TextureCubeMap::generateMipmaps() if (upper != NULL) upper->Release(); if (lower != NULL) lower->Release(); + + mImageArray[f][i].markClean(); } } } @@ -2366,26 +3022,23 @@ void TextureCubeMap::generateMipmaps() { for (unsigned int i = 1; i <= q; i++) { - createSurface(mImageArray[f][i].width, mImageArray[f][i].height, mImageArray[f][i].format, mType, &mImageArray[f][i]); - if (mImageArray[f][i].surface == NULL) + if (mImageArray[f][i].getSurface() == NULL) { return error(GL_OUT_OF_MEMORY); } - if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[f][i].surface, NULL, NULL, mImageArray[f][i - 1].surface, NULL, NULL, D3DX_FILTER_BOX, 0))) + if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[f][i].getSurface(), NULL, NULL, mImageArray[f][i - 1].getSurface(), NULL, NULL, D3DX_FILTER_BOX, 0))) { ERR(" failed to load filter %d to %d.", i - 1, i); } - mImageArray[f][i].dirty = true; + mImageArray[f][i].markDirty(); } } - - mDirtyMetaData = true; } } -Renderbuffer *TextureCubeMap::getColorbuffer(GLenum target) +Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target) { if (!IsCubemapTextureTarget(target)) { @@ -2394,74 +3047,44 @@ Renderbuffer *TextureCubeMap::getColorbuffer(GLenum target) unsigned int face = faceIndex(target); - if (mFaceProxies[face].get() == NULL) + if (mFaceProxies[face] == NULL) { - mFaceProxies[face].set(new Renderbuffer(id(), new TextureColorbufferProxy(this, target))); + mFaceProxies[face] = new Renderbuffer(id(), new RenderbufferTexture(this, target)); } - return mFaceProxies[face].get(); + return mFaceProxies[face]; } IDirect3DSurface9 *TextureCubeMap::getRenderTarget(GLenum target) { ASSERT(IsCubemapTextureTarget(target)); - needRenderTarget(); - - if (mTexture == NULL) + // ensure the underlying texture is created + if (getStorage(true) == NULL) { return NULL; } - - IDirect3DSurface9 *renderTarget = NULL; - mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(faceIndex(target)), 0, &renderTarget); - - return renderTarget; -} - -Texture::TextureColorbufferProxy::TextureColorbufferProxy(Texture *texture, GLenum target) - : Colorbuffer(texture), mTexture(texture), mTarget(target) -{ - ASSERT(IsTextureTarget(target)); -} - -void Texture::TextureColorbufferProxy::addRef() const -{ - mTexture->addRef(); -} - -void Texture::TextureColorbufferProxy::release() const -{ - mTexture->release(); -} - -IDirect3DSurface9 *Texture::TextureColorbufferProxy::getRenderTarget() -{ - if (mRenderTarget) mRenderTarget->Release(); - - mRenderTarget = mTexture->getRenderTarget(mTarget); - return mRenderTarget; -} - -int Texture::TextureColorbufferProxy::getWidth() const -{ - return mTexture->getWidth(); -} - -int Texture::TextureColorbufferProxy::getHeight() const -{ - return mTexture->getHeight(); + updateTexture(); + + return mTexStorage->getCubeMapSurface(target, 0); } -GLenum Texture::TextureColorbufferProxy::getFormat() const +TextureStorage *TextureCubeMap::getStorage(bool renderTarget) { - return mTexture->getFormat(); -} + if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget())) + { + if (renderTarget) + { + convertToRenderTarget(); + } + else + { + createTexture(); + } + } -bool Texture::TextureColorbufferProxy::isFloatingPoint() const -{ - return mTexture->isFloatingPoint(); + return mTexStorage; } -} +}
\ No newline at end of file diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/Texture.h b/Source/ThirdParty/ANGLE/src/libGLESv2/Texture.h index ca7aec7..19a6eb5 100644 --- a/Source/ThirdParty/ANGLE/src/libGLESv2/Texture.h +++ b/Source/ThirdParty/ANGLE/src/libGLESv2/Texture.h @@ -17,14 +17,20 @@ #include <GLES2/gl2.h> #include <d3d9.h> +#include "common/debug.h" +#include "common/RefCountObject.h" #include "libGLESv2/Renderbuffer.h" -#include "libGLESv2/RefCountObject.h" #include "libGLESv2/utilities.h" -#include "common/debug.h" + +namespace egl +{ +class Surface; +} namespace gl { class Blit; +class Framebuffer; enum { @@ -37,6 +43,129 @@ enum IMPLEMENTATION_MAX_TEXTURE_LEVELS = 15 // 1+log2 of MAX_TEXTURE_SIZE }; +class Image +{ + public: + Image(); + ~Image(); + + bool redefine(GLenum format, GLsizei width, GLsizei height, GLenum type, bool forceRelease); + void markDirty() {mDirty = true;} + void markClean() {mDirty = false;} + + HRESULT lock(D3DLOCKED_RECT *lockedRect, const RECT *rect); + void unlock(); + + bool isRenderableFormat() const; + D3DFORMAT getD3DFormat() const; + + GLsizei getWidth() const {return mWidth;} + GLsizei getHeight() const {return mHeight;} + GLenum getFormat() const {return mFormat;} + GLenum getType() const {return mType;} + bool isDirty() const {return mSurface && mDirty;} + IDirect3DSurface9 *getSurface(); + + void setManagedSurface(IDirect3DSurface9 *surface); + void updateSurface(IDirect3DSurface9 *dest, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height); + + void loadData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum type, + GLint unpackAlignment, const void *input, std::size_t outputPitch, void *output) const; + + void loadAlphaData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadAlphaFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadAlphaHalfFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadLuminanceData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const; + void loadLuminanceFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadLuminanceHalfFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadLuminanceAlphaData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const; + void loadLuminanceAlphaFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadLuminanceAlphaHalfFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadRGBUByteData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadRGB565Data(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadRGBFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadRGBHalfFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadRGBAUByteDataSSE2(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadRGBAUByteData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadRGBA4444Data(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadRGBA5551Data(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadRGBAFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadRGBAHalfFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadBGRAData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadCompressedData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadDXT1Data(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadDXT3Data(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadDXT5Data(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + + void copy(GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, IDirect3DSurface9 *renderTarget); + + private: + DISALLOW_COPY_AND_ASSIGN(Image); + + void createSurface(); + + GLsizei mWidth; + GLsizei mHeight; + GLenum mFormat; + GLenum mType; + + bool mDirty; + + D3DPOOL mD3DPool; // can only be D3DPOOL_SYSTEMMEM or D3DPOOL_MANAGED since it needs to be lockable. + D3DFORMAT mD3DFormat; + + IDirect3DSurface9 *mSurface; +}; + +class TextureStorage +{ + public: + explicit TextureStorage(bool renderTarget); + + virtual ~TextureStorage(); + + bool isRenderTarget() const; + bool isManaged() const; + D3DPOOL getPool() const; + unsigned int getTextureSerial() const; + virtual unsigned int getRenderTargetSerial(GLenum target) const = 0; + + private: + DISALLOW_COPY_AND_ASSIGN(TextureStorage); + + const bool mRenderTarget; + const D3DPOOL mD3DPool; + + const unsigned int mTextureSerial; + static unsigned int issueTextureSerial(); + + static unsigned int mCurrentTextureSerial; +}; + class Texture : public RefCountObject { public: @@ -44,167 +173,105 @@ class Texture : public RefCountObject virtual ~Texture(); + virtual void addProxyRef(const Renderbuffer *proxy) = 0; + virtual void releaseProxy(const Renderbuffer *proxy) = 0; + virtual GLenum getTarget() const = 0; bool setMinFilter(GLenum filter); bool setMagFilter(GLenum filter); bool setWrapS(GLenum wrap); bool setWrapT(GLenum wrap); + bool setUsage(GLenum usage); GLenum getMinFilter() const; GLenum getMagFilter() const; GLenum getWrapS() const; GLenum getWrapT() const; + GLenum getUsage() const; - GLuint getWidth() const; - GLuint getHeight() const; + virtual GLsizei getWidth(GLint level) const = 0; + virtual GLsizei getHeight(GLint level) const = 0; + virtual GLenum getInternalFormat() const = 0; + virtual GLenum getType() const = 0; + virtual D3DFORMAT getD3DFormat() const = 0; - virtual GLenum getFormat() const = 0; - virtual bool isComplete() const = 0; + virtual bool isSamplerComplete() const = 0; virtual bool isCompressed() const = 0; - bool isFloatingPoint() const; - bool isRenderableFormat() const; - D3DFORMAT getD3DFormat() const; IDirect3DBaseTexture9 *getTexture(); - virtual Renderbuffer *getColorbuffer(GLenum target) = 0; + virtual Renderbuffer *getRenderbuffer(GLenum target) = 0; virtual void generateMipmaps() = 0; - virtual void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, RenderbufferStorage *source) = 0; - - bool isDirty() const; - - static const GLuint INCOMPLETE_TEXTURE_ID = static_cast<GLuint>(-1); // Every texture takes an id at creation time. The value is arbitrary because it is never registered with the resource manager. - - protected: - class TextureColorbufferProxy; - friend class TextureColorbufferProxy; - class TextureColorbufferProxy : public Colorbuffer - { - public: - TextureColorbufferProxy(Texture *texture, GLenum target); - // target is a 2D-like texture target (GL_TEXTURE_2D or one of the cube face targets) - - virtual void addRef() const; - virtual void release() const; - - virtual IDirect3DSurface9 *getRenderTarget(); + virtual void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) = 0; - virtual int getWidth() const; - virtual int getHeight() const; - virtual GLenum getFormat() const; - virtual bool isFloatingPoint() const; + bool hasDirtyParameters() const; + bool hasDirtyImages() const; + void resetDirty(); + unsigned int getTextureSerial(); + unsigned int getRenderTargetSerial(GLenum target); - private: - Texture *mTexture; - GLenum mTarget; - }; + bool isImmutable() const; - // Helper structure representing a single image layer - struct Image - { - Image(); - ~Image(); + static const GLuint INCOMPLETE_TEXTURE_ID = static_cast<GLuint>(-1); // Every texture takes an id at creation time. The value is arbitrary because it is never registered with the resource manager. - GLsizei width; - GLsizei height; - GLenum format; - - bool dirty; - - IDirect3DSurface9 *surface; - }; - - static D3DFORMAT selectFormat(GLenum format, GLenum type); - - void setImage(GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *img); - bool subImage(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *img); - void setCompressedImage(GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *img); - bool subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *img); - void copyNonRenderable(Image *image, GLenum internalFormat, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, IDirect3DSurface9 *renderTarget); + protected: + friend class RenderbufferTexture; - void needRenderTarget(); + void setImage(GLint unpackAlignment, const void *pixels, Image *image); + bool subImage(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *image); + void setCompressedImage(GLsizei imageSize, const void *pixels, Image *image); + bool subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *image); - GLint creationLevels(GLsizei width, GLsizei height, GLint maxlevel) const; - GLint creationLevels(GLsizei size, GLint maxlevel) const; + GLint creationLevels(GLsizei width, GLsizei height) const; + GLint creationLevels(GLsizei size) const; - // The pointer returned is weak and it is assumed the derived class will keep a strong pointer until the next createTexture() call. - virtual IDirect3DBaseTexture9 *createTexture() = 0; + virtual IDirect3DBaseTexture9 *getBaseTexture() const = 0; + virtual void createTexture() = 0; virtual void updateTexture() = 0; - virtual IDirect3DBaseTexture9 *convertToRenderTarget() = 0; + virtual void convertToRenderTarget() = 0; virtual IDirect3DSurface9 *getRenderTarget(GLenum target) = 0; - virtual bool dirtyImageData() const = 0; - - void dropTexture(); - void pushTexture(IDirect3DBaseTexture9 *newTexture, bool renderable); - void createSurface(GLsizei width, GLsizei height, GLenum format, GLenum type, Image *img); - - Blit *getBlitter(); - int levelCount() const; - bool isRenderable() const; + static Blit *getBlitter(); + static bool copyToRenderTarget(IDirect3DSurface9 *dest, IDirect3DSurface9 *source, bool fromManaged); - unsigned int mWidth; - unsigned int mHeight; GLenum mMinFilter; GLenum mMagFilter; GLenum mWrapS; GLenum mWrapT; - GLenum mType; + bool mDirtyParameters; + GLenum mUsage; - bool mDirtyMetaData; + bool mDirtyImages; + + bool mImmutable; private: DISALLOW_COPY_AND_ASSIGN(Texture); - void loadImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, - GLint unpackAlignment, const void *input, std::size_t outputPitch, void *output, D3DSURFACE_DESC *description) const; - - void loadAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - size_t inputPitch, const void *input, size_t outputPitch, void *output) const; - void loadAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - size_t inputPitch, const void *input, size_t outputPitch, void *output) const; - void loadAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - size_t inputPitch, const void *input, size_t outputPitch, void *output) const; - void loadLuminanceImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - size_t inputPitch, const void *input, size_t outputPitch, void *output, bool native) const; - void loadLuminanceFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - size_t inputPitch, const void *input, size_t outputPitch, void *output) const; - void loadLuminanceHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - size_t inputPitch, const void *input, size_t outputPitch, void *output) const; - void loadLuminanceAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - size_t inputPitch, const void *input, size_t outputPitch, void *output, bool native) const; - void loadLuminanceAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - size_t inputPitch, const void *input, size_t outputPitch, void *output) const; - void loadLuminanceAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - size_t inputPitch, const void *input, size_t outputPitch, void *output) const; - void loadRGBUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - size_t inputPitch, const void *input, size_t outputPitch, void *output) const; - void loadRGB565ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - size_t inputPitch, const void *input, size_t outputPitch, void *output) const; - void loadRGBFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - size_t inputPitch, const void *input, size_t outputPitch, void *output) const; - void loadRGBHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - size_t inputPitch, const void *input, size_t outputPitch, void *output) const; - void loadRGBAUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - size_t inputPitch, const void *input, size_t outputPitch, void *output) const; - void loadRGBA4444ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - size_t inputPitch, const void *input, size_t outputPitch, void *output) const; - void loadRGBA5551ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - size_t inputPitch, const void *input, size_t outputPitch, void *output) const; - void loadRGBAFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - size_t inputPitch, const void *input, size_t outputPitch, void *output) const; - void loadRGBAHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - size_t inputPitch, const void *input, size_t outputPitch, void *output) const; - void loadBGRAImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - size_t inputPitch, const void *input, size_t outputPitch, void *output) const; - - IDirect3DBaseTexture9 *mBaseTexture; // This is a weak pointer. The derived class is assumed to own a strong pointer. + virtual TextureStorage *getStorage(bool renderTarget) = 0; +}; + +class TextureStorage2D : public TextureStorage +{ + public: + explicit TextureStorage2D(IDirect3DTexture9 *surfaceTexture); + TextureStorage2D(int levels, D3DFORMAT format, int width, int height, bool renderTarget); + + virtual ~TextureStorage2D(); - bool mDirty; - bool mIsRenderable; + IDirect3DSurface9 *getSurfaceLevel(int level); + IDirect3DBaseTexture9 *getBaseTexture() const; + + virtual unsigned int getRenderTargetSerial(GLenum target) const; + + private: + DISALLOW_COPY_AND_ASSIGN(TextureStorage2D); + + IDirect3DTexture9 *mTexture; + const unsigned int mRenderTargetSerial; }; class Texture2D : public Texture @@ -214,41 +281,80 @@ class Texture2D : public Texture ~Texture2D(); - GLenum getTarget() const; - GLenum getFormat() const; + void addProxyRef(const Renderbuffer *proxy); + void releaseProxy(const Renderbuffer *proxy); + + virtual GLenum getTarget() const; - void setImage(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels); - void setCompressedImage(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels); + virtual GLsizei getWidth(GLint level) const; + virtual GLsizei getHeight(GLint level) const; + virtual GLenum getInternalFormat() const; + virtual GLenum getType() const; + virtual D3DFORMAT getD3DFormat() const; + + void setImage(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels); + void setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels); void subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels); void subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels); - void copyImage(GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, RenderbufferStorage *source); - void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, RenderbufferStorage *source); + void copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source); + virtual void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source); + void storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); - bool isComplete() const; - bool isCompressed() const; + virtual bool isSamplerComplete() const; + virtual bool isCompressed() const; + virtual void bindTexImage(egl::Surface *surface); + virtual void releaseTexImage(); virtual void generateMipmaps(); - virtual Renderbuffer *getColorbuffer(GLenum target); + virtual Renderbuffer *getRenderbuffer(GLenum target); private: DISALLOW_COPY_AND_ASSIGN(Texture2D); - virtual IDirect3DBaseTexture9 *createTexture(); + virtual IDirect3DBaseTexture9 *getBaseTexture() const; + virtual void createTexture(); virtual void updateTexture(); - virtual IDirect3DBaseTexture9 *convertToRenderTarget(); + virtual void convertToRenderTarget(); virtual IDirect3DSurface9 *getRenderTarget(GLenum target); + virtual TextureStorage *getStorage(bool renderTarget); - virtual bool dirtyImageData() const; + bool isMipmapComplete() const; - bool redefineTexture(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum type); + void redefineImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type); void commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height); Image mImageArray[IMPLEMENTATION_MAX_TEXTURE_LEVELS]; - IDirect3DTexture9 *mTexture; + TextureStorage2D *mTexStorage; + egl::Surface *mSurface; - BindingPointer<Renderbuffer> mColorbufferProxy; + // A specific internal reference count is kept for colorbuffer proxy references, + // because, as the renderbuffer acting as proxy will maintain a binding pointer + // back to this texture, there would be a circular reference if we used a binding + // pointer here. This reference count will cause the pointer to be set to NULL if + // the count drops to zero, but will not cause deletion of the Renderbuffer. + Renderbuffer *mColorbufferProxy; + unsigned int mProxyRefs; +}; + +class TextureStorageCubeMap : public TextureStorage +{ + public: + TextureStorageCubeMap(int levels, D3DFORMAT format, int size, bool renderTarget); + + virtual ~TextureStorageCubeMap(); + + IDirect3DSurface9 *getCubeMapSurface(GLenum faceTarget, int level); + IDirect3DBaseTexture9 *getBaseTexture() const; + + virtual unsigned int getRenderTargetSerial(GLenum target) const; + + private: + DISALLOW_COPY_AND_ASSIGN(TextureStorageCubeMap); + + IDirect3DCubeTexture9 *mTexture; + const unsigned int mFirstRenderTargetSerial; }; class TextureCubeMap : public Texture @@ -258,58 +364,70 @@ class TextureCubeMap : public Texture ~TextureCubeMap(); - GLenum getTarget() const; - GLenum getFormat() const; + void addProxyRef(const Renderbuffer *proxy); + void releaseProxy(const Renderbuffer *proxy); + + virtual GLenum getTarget() const; + + virtual GLsizei getWidth(GLint level) const; + virtual GLsizei getHeight(GLint level) const; + virtual GLenum getInternalFormat() const; + virtual GLenum getType() const; + virtual D3DFORMAT getD3DFormat() const; - void setImagePosX(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels); - void setImageNegX(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels); - void setImagePosY(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels); - void setImageNegY(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels); - void setImagePosZ(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels); - void setImageNegZ(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels); + void setImagePosX(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels); + void setImageNegX(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels); + void setImagePosY(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels); + void setImageNegY(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels); + void setImagePosZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels); + void setImageNegZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels); - void setCompressedImage(GLenum face, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels); + void setCompressedImage(GLenum face, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels); void subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels); void subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels); - void copyImage(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, RenderbufferStorage *source); - void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, RenderbufferStorage *source); + void copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source); + virtual void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source); + void storage(GLsizei levels, GLenum internalformat, GLsizei size); - bool isComplete() const; - bool isCompressed() const; + virtual bool isSamplerComplete() const; + virtual bool isCompressed() const; virtual void generateMipmaps(); - virtual Renderbuffer *getColorbuffer(GLenum target); + virtual Renderbuffer *getRenderbuffer(GLenum target); + + static unsigned int faceIndex(GLenum face); private: DISALLOW_COPY_AND_ASSIGN(TextureCubeMap); - virtual IDirect3DBaseTexture9 *createTexture(); + virtual IDirect3DBaseTexture9 *getBaseTexture() const; + virtual void createTexture(); virtual void updateTexture(); - virtual IDirect3DBaseTexture9 *convertToRenderTarget(); + virtual void convertToRenderTarget(); virtual IDirect3DSurface9 *getRenderTarget(GLenum target); - - virtual bool dirtyImageData() const; - - // faceIdentifier is 0-5 or one of the GL_TEXTURE_CUBE_MAP_* enumerants. - // Returns NULL if the call underlying Direct3D call fails. - IDirect3DSurface9 *getCubeMapSurface(unsigned int faceIdentifier, unsigned int level); - - static unsigned int faceIndex(GLenum face); + virtual TextureStorage *getStorage(bool renderTarget); bool isCubeComplete() const; + bool isMipmapCubeComplete() const; - void setImage(int face, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels); - void commitRect(GLenum faceTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height); - bool redefineTexture(GLint level, GLenum internalFormat, GLsizei width); + void setImage(int faceIndex, GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels); + void commitRect(int faceIndex, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height); + void redefineImage(int faceIndex, GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type); Image mImageArray[6][IMPLEMENTATION_MAX_TEXTURE_LEVELS]; - IDirect3DCubeTexture9 *mTexture; + TextureStorageCubeMap *mTexStorage; - BindingPointer<Renderbuffer> mFaceProxies[6]; + // A specific internal reference count is kept for colorbuffer proxy references, + // because, as the renderbuffer acting as proxy will maintain a binding pointer + // back to this texture, there would be a circular reference if we used a binding + // pointer here. This reference count will cause the pointer to be set to NULL if + // the count drops to zero, but will not cause deletion of the Renderbuffer. + Renderbuffer *mFaceProxies[6]; + unsigned int *mFaceProxyRefs[6]; }; } -#endif // LIBGLESV2_TEXTURE_H_ +#endif // LIBGLESV2_TEXTURE_H_
\ No newline at end of file diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/VertexDataManager.cpp b/Source/ThirdParty/ANGLE/src/libGLESv2/VertexDataManager.cpp new file mode 100644 index 0000000..95bc3fb --- /dev/null +++ b/Source/ThirdParty/ANGLE/src/libGLESv2/VertexDataManager.cpp @@ -0,0 +1,782 @@ +// +// 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. +// + +// VertexDataManager.h: Defines the VertexDataManager, a class that +// runs the Buffer translation process. + +#include "libGLESv2/VertexDataManager.h" + +#include "common/debug.h" + +#include "libGLESv2/Buffer.h" +#include "libGLESv2/Program.h" +#include "libGLESv2/main.h" + +#include "libGLESv2/vertexconversion.h" +#include "libGLESv2/IndexDataManager.h" + +namespace +{ + enum { INITIAL_STREAM_BUFFER_SIZE = 1024*1024 }; + // This has to be at least 4k or else it fails on ATI cards. + enum { CONSTANT_VERTEX_BUFFER_SIZE = 4096 }; +} + +namespace gl +{ +unsigned int VertexBuffer::mCurrentSerial = 1; + +int elementsInBuffer(const VertexAttribute &attribute, int size) +{ + int stride = attribute.stride(); + return (size - attribute.mOffset % stride + (stride - attribute.typeSize())) / stride; +} + +VertexDataManager::VertexDataManager(Context *context, IDirect3DDevice9 *device) : mContext(context), mDevice(device) +{ + for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++) + { + mDirtyCurrentValue[i] = true; + mCurrentValueBuffer[i] = NULL; + mCurrentValueOffsets[i] = 0; + } + + const D3DCAPS9 &caps = context->getDeviceCaps(); + checkVertexCaps(caps.DeclTypes); + + mStreamingBuffer = new StreamingVertexBuffer(mDevice, INITIAL_STREAM_BUFFER_SIZE); + + if (!mStreamingBuffer) + { + ERR("Failed to allocate the streaming vertex buffer."); + } +} + +VertexDataManager::~VertexDataManager() +{ + delete mStreamingBuffer; + + for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++) + { + delete mCurrentValueBuffer[i]; + } +} + +std::size_t VertexDataManager::writeAttributeData(ArrayVertexBuffer *vertexBuffer, GLint start, GLsizei count, const VertexAttribute &attribute, GLsizei instances) +{ + Buffer *buffer = attribute.mBoundBuffer.get(); + + int inputStride = attribute.stride(); + int elementSize = attribute.typeSize(); + const FormatConverter &converter = formatConverter(attribute); + std::size_t streamOffset = 0; + + void *output = NULL; + + if (vertexBuffer) + { + output = vertexBuffer->map(attribute, spaceRequired(attribute, count, instances), &streamOffset); + } + + if (output == NULL) + { + ERR("Failed to map vertex buffer."); + return -1; + } + + const char *input = NULL; + + if (buffer) + { + int offset = attribute.mOffset; + + input = static_cast<const char*>(buffer->data()) + offset; + } + else + { + input = static_cast<const char*>(attribute.mPointer); + } + + if (instances == 0 || attribute.mDivisor == 0) + { + input += inputStride * start; + } + + if (converter.identity && inputStride == elementSize) + { + memcpy(output, input, count * inputStride); + } + else + { + converter.convertArray(input, inputStride, count, output); + } + + vertexBuffer->unmap(); + + return streamOffset; +} + +GLenum VertexDataManager::prepareVertexData(GLint start, GLsizei count, TranslatedAttribute *translated, GLsizei instances) +{ + if (!mStreamingBuffer) + { + return GL_OUT_OF_MEMORY; + } + + const VertexAttributeArray &attribs = mContext->getVertexAttributes(); + Program *program = mContext->getCurrentProgram(); + + for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++) + { + translated[attributeIndex].active = (program->getSemanticIndex(attributeIndex) != -1); + } + + // Determine the required storage size per used buffer, and invalidate static buffers that don't contain matching attributes + for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++) + { + if (translated[i].active && attribs[i].mArrayEnabled) + { + Buffer *buffer = attribs[i].mBoundBuffer.get(); + StaticVertexBuffer *staticBuffer = buffer ? buffer->getStaticVertexBuffer() : NULL; + + if (staticBuffer) + { + if (staticBuffer->size() == 0) + { + int totalCount = elementsInBuffer(attribs[i], buffer->size()); + staticBuffer->addRequiredSpace(spaceRequired(attribs[i], totalCount, 0)); + } + else if (staticBuffer->lookupAttribute(attribs[i]) == -1) + { + // This static buffer doesn't have matching attributes, so fall back to using the streaming buffer + // Add the space of all previous attributes belonging to the invalidated static buffer to the streaming buffer + for (int previous = 0; previous < i; previous++) + { + if (translated[previous].active && attribs[previous].mArrayEnabled) + { + Buffer *previousBuffer = attribs[previous].mBoundBuffer.get(); + StaticVertexBuffer *previousStaticBuffer = previousBuffer ? previousBuffer->getStaticVertexBuffer() : NULL; + + if (staticBuffer == previousStaticBuffer) + { + mStreamingBuffer->addRequiredSpace(spaceRequired(attribs[previous], count, instances)); + } + } + } + + mStreamingBuffer->addRequiredSpace(spaceRequired(attribs[i], count, instances)); + + buffer->invalidateStaticData(); + } + } + else + { + mStreamingBuffer->addRequiredSpace(spaceRequired(attribs[i], count, instances)); + } + } + } + + // Reserve the required space per used buffer + for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++) + { + if (translated[i].active && attribs[i].mArrayEnabled) + { + Buffer *buffer = attribs[i].mBoundBuffer.get(); + ArrayVertexBuffer *staticBuffer = buffer ? buffer->getStaticVertexBuffer() : NULL; + ArrayVertexBuffer *vertexBuffer = staticBuffer ? staticBuffer : mStreamingBuffer; + + if (vertexBuffer) + { + vertexBuffer->reserveRequiredSpace(); + } + } + } + + // Perform the vertex data translations + for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++) + { + if (translated[i].active) + { + if (attribs[i].mArrayEnabled) + { + Buffer *buffer = attribs[i].mBoundBuffer.get(); + + if (!buffer && attribs[i].mPointer == NULL) + { + // This is an application error that would normally result in a crash, but we catch it and return an error + ERR("An enabled vertex array has no buffer and no pointer."); + return GL_INVALID_OPERATION; + } + + const FormatConverter &converter = formatConverter(attribs[i]); + + StaticVertexBuffer *staticBuffer = buffer ? buffer->getStaticVertexBuffer() : NULL; + ArrayVertexBuffer *vertexBuffer = staticBuffer ? staticBuffer : static_cast<ArrayVertexBuffer*>(mStreamingBuffer); + + std::size_t streamOffset = -1; + + if (staticBuffer) + { + streamOffset = staticBuffer->lookupAttribute(attribs[i]); + + if (streamOffset == -1) + { + // Convert the entire buffer + int totalCount = elementsInBuffer(attribs[i], buffer->size()); + int startIndex = attribs[i].mOffset / attribs[i].stride(); + + streamOffset = writeAttributeData(staticBuffer, -startIndex, totalCount, attribs[i], 0); + } + + if (streamOffset != -1) + { + streamOffset += (attribs[i].mOffset / attribs[i].stride()) * converter.outputElementSize; + + if (instances == 0 || attribs[i].mDivisor == 0) + { + streamOffset += start * converter.outputElementSize; + } + } + } + else + { + streamOffset = writeAttributeData(mStreamingBuffer, start, count, attribs[i], instances); + } + + if (streamOffset == -1) + { + return GL_OUT_OF_MEMORY; + } + + translated[i].vertexBuffer = vertexBuffer->getBuffer(); + translated[i].serial = vertexBuffer->getSerial(); + translated[i].divisor = attribs[i].mDivisor; + + translated[i].type = converter.d3dDeclType; + translated[i].stride = converter.outputElementSize; + translated[i].offset = streamOffset; + } + else + { + if (!mCurrentValueBuffer[i]) + { + mCurrentValueBuffer[i] = new StreamingVertexBuffer(mDevice, CONSTANT_VERTEX_BUFFER_SIZE); + } + + StreamingVertexBuffer *buffer = mCurrentValueBuffer[i]; + + if (mDirtyCurrentValue[i]) + { + const int requiredSpace = 4 * sizeof(float); + buffer->addRequiredSpace(requiredSpace); + buffer->reserveRequiredSpace(); + float *data = static_cast<float*>(buffer->map(VertexAttribute(), requiredSpace, &mCurrentValueOffsets[i])); + if (data) + { + data[0] = attribs[i].mCurrentValue[0]; + data[1] = attribs[i].mCurrentValue[1]; + data[2] = attribs[i].mCurrentValue[2]; + data[3] = attribs[i].mCurrentValue[3]; + buffer->unmap(); + mDirtyCurrentValue[i] = false; + } + } + + translated[i].vertexBuffer = mCurrentValueBuffer[i]->getBuffer(); + translated[i].serial = mCurrentValueBuffer[i]->getSerial(); + translated[i].divisor = 0; + + translated[i].type = D3DDECLTYPE_FLOAT4; + translated[i].stride = 0; + translated[i].offset = mCurrentValueOffsets[i]; + } + } + } + + for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++) + { + if (translated[i].active && attribs[i].mArrayEnabled) + { + Buffer *buffer = attribs[i].mBoundBuffer.get(); + + if (buffer) + { + buffer->promoteStaticUsage(count * attribs[i].typeSize()); + } + } + } + + return GL_NO_ERROR; +} + +std::size_t VertexDataManager::spaceRequired(const VertexAttribute &attrib, std::size_t count, GLsizei instances) const +{ + size_t elementSize = formatConverter(attrib).outputElementSize; + + if (instances == 0 || attrib.mDivisor == 0) + { + return elementSize * count; + } + else + { + return elementSize * ((instances + attrib.mDivisor - 1) / attrib.mDivisor); + } +} + +// Mapping from OpenGL-ES vertex attrib type to D3D decl type: +// +// BYTE SHORT (Cast) +// BYTE-norm FLOAT (Normalize) (can't be exactly represented as SHORT-norm) +// UNSIGNED_BYTE UBYTE4 (Identity) or SHORT (Cast) +// UNSIGNED_BYTE-norm UBYTE4N (Identity) or FLOAT (Normalize) +// SHORT SHORT (Identity) +// SHORT-norm SHORT-norm (Identity) or FLOAT (Normalize) +// UNSIGNED_SHORT FLOAT (Cast) +// UNSIGNED_SHORT-norm USHORT-norm (Identity) or FLOAT (Normalize) +// FIXED (not in WebGL) FLOAT (FixedToFloat) +// FLOAT FLOAT (Identity) + +// GLToCType maps from GL type (as GLenum) to the C typedef. +template <GLenum GLType> struct GLToCType { }; + +template <> struct GLToCType<GL_BYTE> { typedef GLbyte type; }; +template <> struct GLToCType<GL_UNSIGNED_BYTE> { typedef GLubyte type; }; +template <> struct GLToCType<GL_SHORT> { typedef GLshort type; }; +template <> struct GLToCType<GL_UNSIGNED_SHORT> { typedef GLushort type; }; +template <> struct GLToCType<GL_FIXED> { typedef GLuint type; }; +template <> struct GLToCType<GL_FLOAT> { typedef GLfloat type; }; + +// This differs from D3DDECLTYPE in that it is unsized. (Size expansion is applied last.) +enum D3DVertexType +{ + D3DVT_FLOAT, + D3DVT_SHORT, + D3DVT_SHORT_NORM, + D3DVT_UBYTE, + D3DVT_UBYTE_NORM, + D3DVT_USHORT_NORM +}; + +// D3DToCType maps from D3D vertex type (as enum D3DVertexType) to the corresponding C type. +template <unsigned int D3DType> struct D3DToCType { }; + +template <> struct D3DToCType<D3DVT_FLOAT> { typedef float type; }; +template <> struct D3DToCType<D3DVT_SHORT> { typedef short type; }; +template <> struct D3DToCType<D3DVT_SHORT_NORM> { typedef short type; }; +template <> struct D3DToCType<D3DVT_UBYTE> { typedef unsigned char type; }; +template <> struct D3DToCType<D3DVT_UBYTE_NORM> { typedef unsigned char type; }; +template <> struct D3DToCType<D3DVT_USHORT_NORM> { typedef unsigned short type; }; + +// Encode the type/size combinations that D3D permits. For each type/size it expands to a widener that will provide the appropriate final size. +template <unsigned int type, int size> +struct WidenRule +{ +}; + +template <int size> struct WidenRule<D3DVT_FLOAT, size> : gl::NoWiden<size> { }; +template <int size> struct WidenRule<D3DVT_SHORT, size> : gl::WidenToEven<size> { }; +template <int size> struct WidenRule<D3DVT_SHORT_NORM, size> : gl::WidenToEven<size> { }; +template <int size> struct WidenRule<D3DVT_UBYTE, size> : gl::WidenToFour<size> { }; +template <int size> struct WidenRule<D3DVT_UBYTE_NORM, size> : gl::WidenToFour<size> { }; +template <int size> struct WidenRule<D3DVT_USHORT_NORM, size> : gl::WidenToEven<size> { }; + +// VertexTypeFlags encodes the D3DCAPS9::DeclType flag and vertex declaration flag for each D3D vertex type & size combination. +template <unsigned int d3dtype, int size> +struct VertexTypeFlags +{ +}; + +template <unsigned int capflag, unsigned int declflag> +struct VertexTypeFlagsHelper +{ + enum { capflag = capflag }; + enum { declflag = declflag }; +}; + +template <> struct VertexTypeFlags<D3DVT_FLOAT, 1> : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT1> { }; +template <> struct VertexTypeFlags<D3DVT_FLOAT, 2> : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT2> { }; +template <> struct VertexTypeFlags<D3DVT_FLOAT, 3> : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT3> { }; +template <> struct VertexTypeFlags<D3DVT_FLOAT, 4> : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT4> { }; +template <> struct VertexTypeFlags<D3DVT_SHORT, 2> : VertexTypeFlagsHelper<0, D3DDECLTYPE_SHORT2> { }; +template <> struct VertexTypeFlags<D3DVT_SHORT, 4> : VertexTypeFlagsHelper<0, D3DDECLTYPE_SHORT4> { }; +template <> struct VertexTypeFlags<D3DVT_SHORT_NORM, 2> : VertexTypeFlagsHelper<D3DDTCAPS_SHORT2N, D3DDECLTYPE_SHORT2N> { }; +template <> struct VertexTypeFlags<D3DVT_SHORT_NORM, 4> : VertexTypeFlagsHelper<D3DDTCAPS_SHORT4N, D3DDECLTYPE_SHORT4N> { }; +template <> struct VertexTypeFlags<D3DVT_UBYTE, 4> : VertexTypeFlagsHelper<D3DDTCAPS_UBYTE4, D3DDECLTYPE_UBYTE4> { }; +template <> struct VertexTypeFlags<D3DVT_UBYTE_NORM, 4> : VertexTypeFlagsHelper<D3DDTCAPS_UBYTE4N, D3DDECLTYPE_UBYTE4N> { }; +template <> struct VertexTypeFlags<D3DVT_USHORT_NORM, 2> : VertexTypeFlagsHelper<D3DDTCAPS_USHORT2N, D3DDECLTYPE_USHORT2N> { }; +template <> struct VertexTypeFlags<D3DVT_USHORT_NORM, 4> : VertexTypeFlagsHelper<D3DDTCAPS_USHORT4N, D3DDECLTYPE_USHORT4N> { }; + + +// VertexTypeMapping maps GL type & normalized flag to preferred and fallback D3D vertex types (as D3DVertexType enums). +template <GLenum GLtype, bool normalized> +struct VertexTypeMapping +{ +}; + +template <D3DVertexType Preferred, D3DVertexType Fallback = Preferred> +struct VertexTypeMappingBase +{ + enum { preferred = Preferred }; + enum { fallback = Fallback }; +}; + +template <> struct VertexTypeMapping<GL_BYTE, false> : VertexTypeMappingBase<D3DVT_SHORT> { }; // Cast +template <> struct VertexTypeMapping<GL_BYTE, true> : VertexTypeMappingBase<D3DVT_FLOAT> { }; // Normalize +template <> struct VertexTypeMapping<GL_UNSIGNED_BYTE, false> : VertexTypeMappingBase<D3DVT_UBYTE, D3DVT_FLOAT> { }; // Identity, Cast +template <> struct VertexTypeMapping<GL_UNSIGNED_BYTE, true> : VertexTypeMappingBase<D3DVT_UBYTE_NORM, D3DVT_FLOAT> { }; // Identity, Normalize +template <> struct VertexTypeMapping<GL_SHORT, false> : VertexTypeMappingBase<D3DVT_SHORT> { }; // Identity +template <> struct VertexTypeMapping<GL_SHORT, true> : VertexTypeMappingBase<D3DVT_SHORT_NORM, D3DVT_FLOAT> { }; // Cast, Normalize +template <> struct VertexTypeMapping<GL_UNSIGNED_SHORT, false> : VertexTypeMappingBase<D3DVT_FLOAT> { }; // Cast +template <> struct VertexTypeMapping<GL_UNSIGNED_SHORT, true> : VertexTypeMappingBase<D3DVT_USHORT_NORM, D3DVT_FLOAT> { }; // Cast, Normalize +template <bool normalized> struct VertexTypeMapping<GL_FIXED, normalized> : VertexTypeMappingBase<D3DVT_FLOAT> { }; // FixedToFloat +template <bool normalized> struct VertexTypeMapping<GL_FLOAT, normalized> : VertexTypeMappingBase<D3DVT_FLOAT> { }; // Identity + + +// Given a GL type & norm flag and a D3D type, ConversionRule provides the type conversion rule (Cast, Normalize, Identity, FixedToFloat). +// The conversion rules themselves are defined in vertexconversion.h. + +// Almost all cases are covered by Cast (including those that are actually Identity since Cast<T,T> knows it's an identity mapping). +template <GLenum fromType, bool normalized, unsigned int toType> +struct ConversionRule : gl::Cast<typename GLToCType<fromType>::type, typename D3DToCType<toType>::type> +{ +}; + +// All conversions from normalized types to float use the Normalize operator. +template <GLenum fromType> struct ConversionRule<fromType, true, D3DVT_FLOAT> : gl::Normalize<typename GLToCType<fromType>::type> { }; + +// Use a full specialisation for this so that it preferentially matches ahead of the generic normalize-to-float rules. +template <> struct ConversionRule<GL_FIXED, true, D3DVT_FLOAT> : gl::FixedToFloat<GLuint, 16> { }; +template <> struct ConversionRule<GL_FIXED, false, D3DVT_FLOAT> : gl::FixedToFloat<GLuint, 16> { }; + +// A 2-stage construction is used for DefaultVertexValues because float must use SimpleDefaultValues (i.e. 0/1) +// whether it is normalized or not. +template <class T, bool normalized> +struct DefaultVertexValuesStage2 +{ +}; + +template <class T> struct DefaultVertexValuesStage2<T, true> : gl::NormalizedDefaultValues<T> { }; +template <class T> struct DefaultVertexValuesStage2<T, false> : gl::SimpleDefaultValues<T> { }; + +// Work out the default value rule for a D3D type (expressed as the C type) and +template <class T, bool normalized> +struct DefaultVertexValues : DefaultVertexValuesStage2<T, normalized> +{ +}; + +template <bool normalized> struct DefaultVertexValues<float, normalized> : gl::SimpleDefaultValues<float> { }; + +// Policy rules for use with Converter, to choose whether to use the preferred or fallback conversion. +// The fallback conversion produces an output that all D3D9 devices must support. +template <class T> struct UsePreferred { enum { type = T::preferred }; }; +template <class T> struct UseFallback { enum { type = T::fallback }; }; + +// Converter ties it all together. Given an OpenGL type/norm/size and choice of preferred/fallback conversion, +// it provides all the members of the appropriate VertexDataConverter, the D3DCAPS9::DeclTypes flag in cap flag +// and the D3DDECLTYPE member needed for the vertex declaration in declflag. +template <GLenum fromType, bool normalized, int size, template <class T> class PreferenceRule> +struct Converter + : gl::VertexDataConverter<typename GLToCType<fromType>::type, + WidenRule<PreferenceRule< VertexTypeMapping<fromType, normalized> >::type, size>, + ConversionRule<fromType, + normalized, + PreferenceRule< VertexTypeMapping<fromType, normalized> >::type>, + DefaultVertexValues<typename D3DToCType<PreferenceRule< VertexTypeMapping<fromType, normalized> >::type>::type, normalized > > +{ +private: + enum { d3dtype = PreferenceRule< VertexTypeMapping<fromType, normalized> >::type }; + enum { d3dsize = WidenRule<d3dtype, size>::finalWidth }; + +public: + enum { capflag = VertexTypeFlags<d3dtype, d3dsize>::capflag }; + enum { declflag = VertexTypeFlags<d3dtype, d3dsize>::declflag }; +}; + +// Initialise a TranslationInfo +#define TRANSLATION(type, norm, size, preferred) \ + { \ + Converter<type, norm, size, preferred>::identity, \ + Converter<type, norm, size, preferred>::finalSize, \ + Converter<type, norm, size, preferred>::convertArray, \ + static_cast<D3DDECLTYPE>(Converter<type, norm, size, preferred>::declflag) \ + } + +#define TRANSLATION_FOR_TYPE_NORM_SIZE(type, norm, size) \ + { \ + Converter<type, norm, size, UsePreferred>::capflag, \ + TRANSLATION(type, norm, size, UsePreferred), \ + TRANSLATION(type, norm, size, UseFallback) \ + } + +#define TRANSLATIONS_FOR_TYPE(type) \ + { \ + { TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 1), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 2), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 3), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 4) }, \ + { TRANSLATION_FOR_TYPE_NORM_SIZE(type, true, 1), TRANSLATION_FOR_TYPE_NORM_SIZE(type, true, 2), TRANSLATION_FOR_TYPE_NORM_SIZE(type, true, 3), TRANSLATION_FOR_TYPE_NORM_SIZE(type, true, 4) }, \ + } + +#define TRANSLATIONS_FOR_TYPE_NO_NORM(type) \ + { \ + { TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 1), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 2), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 3), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 4) }, \ + { TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 1), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 2), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 3), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 4) }, \ + } + +const VertexDataManager::TranslationDescription VertexDataManager::mPossibleTranslations[NUM_GL_VERTEX_ATTRIB_TYPES][2][4] = // [GL types as enumerated by typeIndex()][normalized][size-1] +{ + TRANSLATIONS_FOR_TYPE(GL_BYTE), + TRANSLATIONS_FOR_TYPE(GL_UNSIGNED_BYTE), + TRANSLATIONS_FOR_TYPE(GL_SHORT), + TRANSLATIONS_FOR_TYPE(GL_UNSIGNED_SHORT), + TRANSLATIONS_FOR_TYPE_NO_NORM(GL_FIXED), + TRANSLATIONS_FOR_TYPE_NO_NORM(GL_FLOAT) +}; + +void VertexDataManager::checkVertexCaps(DWORD declTypes) +{ + for (unsigned int i = 0; i < NUM_GL_VERTEX_ATTRIB_TYPES; i++) + { + for (unsigned int j = 0; j < 2; j++) + { + for (unsigned int k = 0; k < 4; k++) + { + if (mPossibleTranslations[i][j][k].capsFlag == 0 || (declTypes & mPossibleTranslations[i][j][k].capsFlag) != 0) + { + mAttributeTypes[i][j][k] = mPossibleTranslations[i][j][k].preferredConversion; + } + else + { + mAttributeTypes[i][j][k] = mPossibleTranslations[i][j][k].fallbackConversion; + } + } + } + } +} + +// This is used to index mAttributeTypes and mPossibleTranslations. +unsigned int VertexDataManager::typeIndex(GLenum type) const +{ + switch (type) + { + case GL_BYTE: return 0; + case GL_UNSIGNED_BYTE: return 1; + case GL_SHORT: return 2; + case GL_UNSIGNED_SHORT: return 3; + case GL_FIXED: return 4; + case GL_FLOAT: return 5; + + default: UNREACHABLE(); return 5; + } +} + +VertexBuffer::VertexBuffer(IDirect3DDevice9 *device, std::size_t size, DWORD usageFlags) : mDevice(device), mVertexBuffer(NULL) +{ + if (size > 0) + { + D3DPOOL pool = getDisplay()->getBufferPool(usageFlags); + HRESULT result = device->CreateVertexBuffer(size, usageFlags, 0, pool, &mVertexBuffer, NULL); + mSerial = issueSerial(); + + if (FAILED(result)) + { + ERR("Out of memory allocating a vertex buffer of size %lu.", size); + } + } +} + +VertexBuffer::~VertexBuffer() +{ + if (mVertexBuffer) + { + mVertexBuffer->Release(); + } +} + +void VertexBuffer::unmap() +{ + if (mVertexBuffer) + { + mVertexBuffer->Unlock(); + } +} + +IDirect3DVertexBuffer9 *VertexBuffer::getBuffer() const +{ + return mVertexBuffer; +} + +unsigned int VertexBuffer::getSerial() const +{ + return mSerial; +} + +unsigned int VertexBuffer::issueSerial() +{ + return mCurrentSerial++; +} + +ArrayVertexBuffer::ArrayVertexBuffer(IDirect3DDevice9 *device, std::size_t size, DWORD usageFlags) : VertexBuffer(device, size, usageFlags) +{ + mBufferSize = size; + mWritePosition = 0; + mRequiredSpace = 0; +} + +ArrayVertexBuffer::~ArrayVertexBuffer() +{ +} + +void ArrayVertexBuffer::addRequiredSpace(UINT requiredSpace) +{ + mRequiredSpace += requiredSpace; +} + +StreamingVertexBuffer::StreamingVertexBuffer(IDirect3DDevice9 *device, std::size_t initialSize) : ArrayVertexBuffer(device, initialSize, D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY) +{ +} + +StreamingVertexBuffer::~StreamingVertexBuffer() +{ +} + +void *StreamingVertexBuffer::map(const VertexAttribute &attribute, std::size_t requiredSpace, std::size_t *offset) +{ + void *mapPtr = NULL; + + if (mVertexBuffer) + { + HRESULT result = mVertexBuffer->Lock(mWritePosition, requiredSpace, &mapPtr, D3DLOCK_NOOVERWRITE); + + if (FAILED(result)) + { + ERR("Lock failed with error 0x%08x", result); + return NULL; + } + + *offset = mWritePosition; + mWritePosition += requiredSpace; + } + + return mapPtr; +} + +void StreamingVertexBuffer::reserveRequiredSpace() +{ + if (mRequiredSpace > mBufferSize) + { + if (mVertexBuffer) + { + mVertexBuffer->Release(); + mVertexBuffer = NULL; + } + + mBufferSize = std::max(mRequiredSpace, 3 * mBufferSize / 2); // 1.5 x mBufferSize is arbitrary and should be checked to see we don't have too many reallocations. + + D3DPOOL pool = getDisplay()->getBufferPool(D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY); + HRESULT result = mDevice->CreateVertexBuffer(mBufferSize, D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, 0, pool, &mVertexBuffer, NULL); + mSerial = issueSerial(); + + if (FAILED(result)) + { + ERR("Out of memory allocating a vertex buffer of size %lu.", mBufferSize); + } + + mWritePosition = 0; + } + else if (mWritePosition + mRequiredSpace > mBufferSize) // Recycle + { + if (mVertexBuffer) + { + void *dummy; + mVertexBuffer->Lock(0, 1, &dummy, D3DLOCK_DISCARD); + mVertexBuffer->Unlock(); + } + + mWritePosition = 0; + } + + mRequiredSpace = 0; +} + +StaticVertexBuffer::StaticVertexBuffer(IDirect3DDevice9 *device) : ArrayVertexBuffer(device, 0, D3DUSAGE_WRITEONLY) +{ +} + +StaticVertexBuffer::~StaticVertexBuffer() +{ +} + +void *StaticVertexBuffer::map(const VertexAttribute &attribute, std::size_t requiredSpace, std::size_t *streamOffset) +{ + void *mapPtr = NULL; + + if (mVertexBuffer) + { + HRESULT result = mVertexBuffer->Lock(mWritePosition, requiredSpace, &mapPtr, 0); + + if (FAILED(result)) + { + ERR("Lock failed with error 0x%08x", result); + return NULL; + } + + int attributeOffset = attribute.mOffset % attribute.stride(); + VertexElement element = {attribute.mType, attribute.mSize, attribute.stride(), attribute.mNormalized, attributeOffset, mWritePosition}; + mCache.push_back(element); + + *streamOffset = mWritePosition; + mWritePosition += requiredSpace; + } + + return mapPtr; +} + +void StaticVertexBuffer::reserveRequiredSpace() +{ + if (!mVertexBuffer && mBufferSize == 0) + { + D3DPOOL pool = getDisplay()->getBufferPool(D3DUSAGE_WRITEONLY); + HRESULT result = mDevice->CreateVertexBuffer(mRequiredSpace, D3DUSAGE_WRITEONLY, 0, pool, &mVertexBuffer, NULL); + mSerial = issueSerial(); + + if (FAILED(result)) + { + ERR("Out of memory allocating a vertex buffer of size %lu.", mRequiredSpace); + } + + mBufferSize = mRequiredSpace; + } + else if (mVertexBuffer && mBufferSize >= mRequiredSpace) + { + // Already allocated + } + else UNREACHABLE(); // Static vertex buffers can't be resized + + mRequiredSpace = 0; +} + +std::size_t StaticVertexBuffer::lookupAttribute(const VertexAttribute &attribute) +{ + for (unsigned int element = 0; element < mCache.size(); element++) + { + if (mCache[element].type == attribute.mType && + mCache[element].size == attribute.mSize && + mCache[element].stride == attribute.stride() && + mCache[element].normalized == attribute.mNormalized) + { + if (mCache[element].attributeOffset == attribute.mOffset % attribute.stride()) + { + return mCache[element].streamOffset; + } + } + } + + return -1; +} + +const VertexDataManager::FormatConverter &VertexDataManager::formatConverter(const VertexAttribute &attribute) const +{ + return mAttributeTypes[typeIndex(attribute.mType)][attribute.mNormalized][attribute.mSize - 1]; +} +} diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/VertexDataManager.h b/Source/ThirdParty/ANGLE/src/libGLESv2/VertexDataManager.h new file mode 100644 index 0000000..857591a --- /dev/null +++ b/Source/ThirdParty/ANGLE/src/libGLESv2/VertexDataManager.h @@ -0,0 +1,169 @@ +// +// 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. +// + +// VertexDataManager.h: Defines the VertexDataManager, a class that +// runs the Buffer translation process. + +#ifndef LIBGLESV2_VERTEXDATAMANAGER_H_ +#define LIBGLESV2_VERTEXDATAMANAGER_H_ + +#include <vector> +#include <cstddef> + +#define GL_APICALL +#include <GLES2/gl2.h> + +#include "libGLESv2/Context.h" + +namespace gl +{ + +struct TranslatedAttribute +{ + bool active; + + D3DDECLTYPE type; + UINT offset; + UINT stride; // 0 means not to advance the read pointer at all + + IDirect3DVertexBuffer9 *vertexBuffer; + unsigned int serial; + unsigned int divisor; +}; + +class VertexBuffer +{ + public: + VertexBuffer(IDirect3DDevice9 *device, std::size_t size, DWORD usageFlags); + virtual ~VertexBuffer(); + + void unmap(); + + IDirect3DVertexBuffer9 *getBuffer() const; + unsigned int getSerial() const; + + protected: + IDirect3DDevice9 *const mDevice; + IDirect3DVertexBuffer9 *mVertexBuffer; + + unsigned int mSerial; + static unsigned int issueSerial(); + static unsigned int mCurrentSerial; + + private: + DISALLOW_COPY_AND_ASSIGN(VertexBuffer); +}; + +class ArrayVertexBuffer : public VertexBuffer +{ + public: + ArrayVertexBuffer(IDirect3DDevice9 *device, std::size_t size, DWORD usageFlags); + ~ArrayVertexBuffer(); + + std::size_t size() const { return mBufferSize; } + virtual void *map(const VertexAttribute &attribute, std::size_t requiredSpace, std::size_t *streamOffset) = 0; + virtual void reserveRequiredSpace() = 0; + void addRequiredSpace(UINT requiredSpace); + + protected: + std::size_t mBufferSize; + std::size_t mWritePosition; + std::size_t mRequiredSpace; +}; + +class StreamingVertexBuffer : public ArrayVertexBuffer +{ + public: + StreamingVertexBuffer(IDirect3DDevice9 *device, std::size_t initialSize); + ~StreamingVertexBuffer(); + + void *map(const VertexAttribute &attribute, std::size_t requiredSpace, std::size_t *streamOffset); + void reserveRequiredSpace(); +}; + +class StaticVertexBuffer : public ArrayVertexBuffer +{ + public: + explicit StaticVertexBuffer(IDirect3DDevice9 *device); + ~StaticVertexBuffer(); + + void *map(const VertexAttribute &attribute, std::size_t requiredSpace, std::size_t *streamOffset); + void reserveRequiredSpace(); + + std::size_t lookupAttribute(const VertexAttribute &attribute); // Returns the offset into the vertex buffer, or -1 if not found + + private: + struct VertexElement + { + GLenum type; + GLint size; + GLsizei stride; + bool normalized; + int attributeOffset; + + std::size_t streamOffset; + }; + + std::vector<VertexElement> mCache; +}; + +class VertexDataManager +{ + public: + VertexDataManager(Context *context, IDirect3DDevice9 *backend); + virtual ~VertexDataManager(); + + void dirtyCurrentValue(int index) { mDirtyCurrentValue[index] = true; } + + GLenum prepareVertexData(GLint start, GLsizei count, TranslatedAttribute *outAttribs, GLsizei instances); + + private: + DISALLOW_COPY_AND_ASSIGN(VertexDataManager); + + std::size_t spaceRequired(const VertexAttribute &attrib, std::size_t count, GLsizei instances) const; + std::size_t writeAttributeData(ArrayVertexBuffer *vertexBuffer, GLint start, GLsizei count, const VertexAttribute &attribute, GLsizei instances); + + Context *const mContext; + IDirect3DDevice9 *const mDevice; + + StreamingVertexBuffer *mStreamingBuffer; + + bool mDirtyCurrentValue[MAX_VERTEX_ATTRIBS]; + StreamingVertexBuffer *mCurrentValueBuffer[MAX_VERTEX_ATTRIBS]; + std::size_t mCurrentValueOffsets[MAX_VERTEX_ATTRIBS]; + + // Attribute format conversion + struct FormatConverter + { + bool identity; + std::size_t outputElementSize; + void (*convertArray)(const void *in, std::size_t stride, std::size_t n, void *out); + D3DDECLTYPE d3dDeclType; + }; + + enum { NUM_GL_VERTEX_ATTRIB_TYPES = 6 }; + + FormatConverter mAttributeTypes[NUM_GL_VERTEX_ATTRIB_TYPES][2][4]; // [GL types as enumerated by typeIndex()][normalized][size - 1] + + struct TranslationDescription + { + DWORD capsFlag; + FormatConverter preferredConversion; + FormatConverter fallbackConversion; + }; + + // This table is used to generate mAttributeTypes. + static const TranslationDescription mPossibleTranslations[NUM_GL_VERTEX_ATTRIB_TYPES][2][4]; // [GL types as enumerated by typeIndex()][normalized][size - 1] + + void checkVertexCaps(DWORD declTypes); + + unsigned int typeIndex(GLenum type) const; + const FormatConverter &formatConverter(const VertexAttribute &attribute) const; +}; + +} + +#endif // LIBGLESV2_VERTEXDATAMANAGER_H_ diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/libGLESv2.cpp b/Source/ThirdParty/ANGLE/src/libGLESv2/libGLESv2.cpp index 543c0d2..ee8eca9 100644 --- a/Source/ThirdParty/ANGLE/src/libGLESv2/libGLESv2.cpp +++ b/Source/ThirdParty/ANGLE/src/libGLESv2/libGLESv2.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. // @@ -14,6 +14,7 @@ #include <limits> #include "common/debug.h" +#include "common/version.h" #include "libGLESv2/main.h" #include "libGLESv2/mathutil.h" @@ -26,25 +27,126 @@ #include "libGLESv2/Renderbuffer.h" #include "libGLESv2/Shader.h" #include "libGLESv2/Texture.h" +#include "libGLESv2/Query.h" -extern "C" +bool validImageSize(GLint level, GLsizei width, GLsizei height) { + if (level < 0 || width < 0 || height < 0) + { + return false; + } -void __stdcall glActiveTexture(GLenum texture) + if (gl::getContext() && gl::getContext()->supportsNonPower2Texture()) + { + return true; + } + + if (level == 0) + { + return true; + } + + if (gl::isPow2(width) && gl::isPow2(height)) + { + return true; + } + + return false; +} + +bool validateSubImageParams(bool compressed, GLsizei width, GLsizei height, GLint xoffset, GLint yoffset, GLint level, GLenum format, gl::Texture *texture) { - TRACE("(GLenum texture = 0x%X)", texture); + if (!texture) + { + return error(GL_INVALID_OPERATION, false); + } - try + if (compressed != texture->isCompressed()) { - if (texture < GL_TEXTURE0 || texture > GL_TEXTURE0 + gl::MAX_TEXTURE_IMAGE_UNITS - 1) + return error(GL_INVALID_OPERATION, false); + } + + if (format != GL_NONE && format != texture->getInternalFormat()) + { + return error(GL_INVALID_OPERATION, false); + } + + if (compressed) + { + if ((width % 4 != 0 && width != texture->getWidth(0)) || + (height % 4 != 0 && height != texture->getHeight(0))) { - return error(GL_INVALID_ENUM); + return error(GL_INVALID_OPERATION, false); } + } - gl::Context *context = gl::getContext(); + if (xoffset + width > texture->getWidth(level) || + yoffset + height > texture->getHeight(level)) + { + return error(GL_INVALID_VALUE, false); + } + + return true; +} + +// check for combinations of format and type that are valid for ReadPixels +bool validReadFormatType(GLenum format, GLenum type) +{ + switch (format) + { + case GL_RGBA: + switch (type) + { + case GL_UNSIGNED_BYTE: + break; + default: + return false; + } + break; + case GL_BGRA_EXT: + switch (type) + { + case GL_UNSIGNED_BYTE: + case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT: + case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT: + break; + default: + return false; + } + break; + case gl::IMPLEMENTATION_COLOR_READ_FORMAT: + switch (type) + { + case gl::IMPLEMENTATION_COLOR_READ_TYPE: + break; + default: + return false; + } + break; + default: + return false; + } + return true; +} + +extern "C" +{ + +void __stdcall glActiveTexture(GLenum texture) +{ + EVENT("(GLenum texture = 0x%X)", texture); + + try + { + gl::Context *context = gl::getNonLostContext(); if (context) { + if (texture < GL_TEXTURE0 || texture > GL_TEXTURE0 + context->getMaximumCombinedTextureImageUnits() - 1) + { + return error(GL_INVALID_ENUM); + } + context->setActiveSampler(texture - GL_TEXTURE0); } } @@ -56,11 +158,11 @@ void __stdcall glActiveTexture(GLenum texture) void __stdcall glAttachShader(GLuint program, GLuint shader) { - TRACE("(GLuint program = %d, GLuint shader = %d)", program, shader); + EVENT("(GLuint program = %d, GLuint shader = %d)", program, shader); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -103,9 +205,42 @@ void __stdcall glAttachShader(GLuint program, GLuint shader) } } +void __stdcall glBeginQueryEXT(GLenum target, GLuint id) +{ + EVENT("(GLenum target = 0x%X, GLuint %d)", target, id); + + try + { + switch (target) + { + case GL_ANY_SAMPLES_PASSED_EXT: + case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT: + break; + default: + return error(GL_INVALID_ENUM); + } + + if (id == 0) + { + return error(GL_INVALID_OPERATION); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + context->beginQuery(target, id); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + void __stdcall glBindAttribLocation(GLuint program, GLuint index, const GLchar* name) { - TRACE("(GLuint program = %d, GLuint index = %d, const GLchar* name = 0x%0.8p)", program, index, name); + EVENT("(GLuint program = %d, GLuint index = %d, const GLchar* name = 0x%0.8p)", program, index, name); try { @@ -114,7 +249,7 @@ void __stdcall glBindAttribLocation(GLuint program, GLuint index, const GLchar* return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -148,11 +283,11 @@ void __stdcall glBindAttribLocation(GLuint program, GLuint index, const GLchar* void __stdcall glBindBuffer(GLenum target, GLuint buffer) { - TRACE("(GLenum target = 0x%X, GLuint buffer = %d)", target, buffer); + EVENT("(GLenum target = 0x%X, GLuint buffer = %d)", target, buffer); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -177,7 +312,7 @@ void __stdcall glBindBuffer(GLenum target, GLuint buffer) void __stdcall glBindFramebuffer(GLenum target, GLuint framebuffer) { - TRACE("(GLenum target = 0x%X, GLuint framebuffer = %d)", target, framebuffer); + EVENT("(GLenum target = 0x%X, GLuint framebuffer = %d)", target, framebuffer); try { @@ -186,7 +321,7 @@ void __stdcall glBindFramebuffer(GLenum target, GLuint framebuffer) return error(GL_INVALID_ENUM); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -209,7 +344,7 @@ void __stdcall glBindFramebuffer(GLenum target, GLuint framebuffer) void __stdcall glBindRenderbuffer(GLenum target, GLuint renderbuffer) { - TRACE("(GLenum target = 0x%X, GLuint renderbuffer = %d)", target, renderbuffer); + EVENT("(GLenum target = 0x%X, GLuint renderbuffer = %d)", target, renderbuffer); try { @@ -218,7 +353,7 @@ void __stdcall glBindRenderbuffer(GLenum target, GLuint renderbuffer) return error(GL_INVALID_ENUM); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -233,11 +368,11 @@ void __stdcall glBindRenderbuffer(GLenum target, GLuint renderbuffer) void __stdcall glBindTexture(GLenum target, GLuint texture) { - TRACE("(GLenum target = 0x%X, GLuint texture = %d)", target, texture); + EVENT("(GLenum target = 0x%X, GLuint texture = %d)", target, texture); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -269,12 +404,12 @@ void __stdcall glBindTexture(GLenum target, GLuint texture) void __stdcall glBlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) { - TRACE("(GLclampf red = %f, GLclampf green = %f, GLclampf blue = %f, GLclampf alpha = %f)", + EVENT("(GLclampf red = %f, GLclampf green = %f, GLclampf blue = %f, GLclampf alpha = %f)", red, green, blue, alpha); try { - gl::Context* context = gl::getContext(); + gl::Context* context = gl::getNonLostContext(); if (context) { @@ -294,7 +429,7 @@ void __stdcall glBlendEquation(GLenum mode) void __stdcall glBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha) { - TRACE("(GLenum modeRGB = 0x%X, GLenum modeAlpha = 0x%X)", modeRGB, modeAlpha); + EVENT("(GLenum modeRGB = 0x%X, GLenum modeAlpha = 0x%X)", modeRGB, modeAlpha); try { @@ -318,7 +453,7 @@ void __stdcall glBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha) return error(GL_INVALID_ENUM); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -338,7 +473,7 @@ void __stdcall glBlendFunc(GLenum sfactor, GLenum dfactor) void __stdcall glBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) { - TRACE("(GLenum srcRGB = 0x%X, GLenum dstRGB = 0x%X, GLenum srcAlpha = 0x%X, GLenum dstAlpha = 0x%X)", + EVENT("(GLenum srcRGB = 0x%X, GLenum dstRGB = 0x%X, GLenum srcAlpha = 0x%X, GLenum dstAlpha = 0x%X)", srcRGB, dstRGB, srcAlpha, dstAlpha); try @@ -441,7 +576,7 @@ void __stdcall glBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha return error(GL_INVALID_OPERATION); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -456,7 +591,7 @@ void __stdcall glBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha void __stdcall glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage) { - TRACE("(GLenum target = 0x%X, GLsizeiptr size = %d, const GLvoid* data = 0x%0.8p, GLenum usage = %d)", + EVENT("(GLenum target = 0x%X, GLsizeiptr size = %d, const GLvoid* data = 0x%0.8p, GLenum usage = %d)", target, size, data, usage); try @@ -476,7 +611,7 @@ void __stdcall glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, return error(GL_INVALID_ENUM); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -510,7 +645,7 @@ void __stdcall glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, void __stdcall glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data) { - TRACE("(GLenum target = 0x%X, GLintptr offset = %d, GLsizeiptr size = %d, const GLvoid* data = 0x%0.8p)", + EVENT("(GLenum target = 0x%X, GLintptr offset = %d, GLsizeiptr size = %d, const GLvoid* data = 0x%0.8p)", target, offset, size, data); try @@ -525,7 +660,7 @@ void __stdcall glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, return; } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -564,7 +699,7 @@ void __stdcall glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, GLenum __stdcall glCheckFramebufferStatus(GLenum target) { - TRACE("(GLenum target = 0x%X)", target); + EVENT("(GLenum target = 0x%X)", target); try { @@ -573,7 +708,7 @@ GLenum __stdcall glCheckFramebufferStatus(GLenum target) return error(GL_INVALID_ENUM, 0); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -600,11 +735,11 @@ GLenum __stdcall glCheckFramebufferStatus(GLenum target) void __stdcall glClear(GLbitfield mask) { - TRACE("(GLbitfield mask = %X)", mask); + EVENT("(GLbitfield mask = %X)", mask); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -619,12 +754,12 @@ void __stdcall glClear(GLbitfield mask) void __stdcall glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) { - TRACE("(GLclampf red = %f, GLclampf green = %f, GLclampf blue = %f, GLclampf alpha = %f)", + EVENT("(GLclampf red = %f, GLclampf green = %f, GLclampf blue = %f, GLclampf alpha = %f)", red, green, blue, alpha); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -639,11 +774,11 @@ void __stdcall glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclamp void __stdcall glClearDepthf(GLclampf depth) { - TRACE("(GLclampf depth = %f)", depth); + EVENT("(GLclampf depth = %f)", depth); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -658,11 +793,11 @@ void __stdcall glClearDepthf(GLclampf depth) void __stdcall glClearStencil(GLint s) { - TRACE("(GLint s = %d)", s); + EVENT("(GLint s = %d)", s); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -677,12 +812,12 @@ void __stdcall glClearStencil(GLint s) void __stdcall glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) { - TRACE("(GLboolean red = %d, GLboolean green = %d, GLboolean blue = %d, GLboolean alpha = %d)", + EVENT("(GLboolean red = %d, GLboolean green = %d, GLboolean blue = %d, GLboolean alpha = %d)", red, green, blue, alpha); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -697,11 +832,11 @@ void __stdcall glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboo void __stdcall glCompileShader(GLuint shader) { - TRACE("(GLuint shader = %d)", shader); + EVENT("(GLuint shader = %d)", shader); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -731,18 +866,13 @@ void __stdcall glCompileShader(GLuint shader) void __stdcall glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid* data) { - TRACE("(GLenum target = 0x%X, GLint level = %d, GLenum internalformat = 0x%X, GLsizei width = %d, " + EVENT("(GLenum target = 0x%X, GLint level = %d, GLenum internalformat = 0x%X, GLsizei width = %d, " "GLsizei height = %d, GLint border = %d, GLsizei imageSize = %d, const GLvoid* data = 0x%0.8p)", target, level, internalformat, width, height, border, imageSize, data); try { - if (level < 0) - { - return error(GL_INVALID_VALUE); - } - - if (width < 0 || height < 0 || (level > 0 && !gl::isPow2(width)) || (level > 0 && !gl::isPow2(height)) || border != 0 || imageSize < 0) + if (!validImageSize(level, width, height) || border != 0 || imageSize < 0) { return error(GL_INVALID_VALUE); } @@ -751,6 +881,8 @@ void __stdcall glCompressedTexImage2D(GLenum target, GLint level, GLenum interna { case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: + case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: break; default: return error(GL_INVALID_ENUM); @@ -761,7 +893,7 @@ void __stdcall glCompressedTexImage2D(GLenum target, GLint level, GLenum interna return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -800,9 +932,27 @@ void __stdcall glCompressedTexImage2D(GLenum target, GLint level, GLenum interna return error(GL_INVALID_ENUM); } - if (!context->supportsCompressedTextures()) - { - return error(GL_INVALID_ENUM); // in this case, it's as though the internal format switch failed + switch (internalformat) { + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + if (!context->supportsDXT1Textures()) + { + return error(GL_INVALID_ENUM); // in this case, it's as though the internal format switch failed + } + break; + case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: + if (!context->supportsDXT3Textures()) + { + return error(GL_INVALID_ENUM); // in this case, it's as though the internal format switch failed + } + break; + case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: + if (!context->supportsDXT5Textures()) + { + return error(GL_INVALID_ENUM); // in this case, it's as though the internal format switch failed + } + break; + default: UNREACHABLE(); } if (imageSize != gl::ComputeCompressedSize(width, height, internalformat)) @@ -819,6 +969,11 @@ void __stdcall glCompressedTexImage2D(GLenum target, GLint level, GLenum interna return error(GL_INVALID_OPERATION); } + if (texture->isImmutable()) + { + return error(GL_INVALID_OPERATION); + } + texture->setCompressedImage(level, internalformat, width, height, imageSize, data); } else @@ -830,6 +985,11 @@ void __stdcall glCompressedTexImage2D(GLenum target, GLint level, GLenum interna return error(GL_INVALID_OPERATION); } + if (texture->isImmutable()) + { + return error(GL_INVALID_OPERATION); + } + switch (target) { case GL_TEXTURE_CUBE_MAP_POSITIVE_X: @@ -855,25 +1015,19 @@ void __stdcall glCompressedTexImage2D(GLenum target, GLint level, GLenum interna void __stdcall glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid* data) { - TRACE("(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, " + EVENT("(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, " "GLsizei width = %d, GLsizei height = %d, GLenum format = 0x%X, " "GLsizei imageSize = %d, const GLvoid* data = 0x%0.8p)", target, level, xoffset, yoffset, width, height, format, imageSize, data); try { - if (!gl::IsTextureTarget(target)) + if (!gl::IsInternalTextureTarget(target)) { return error(GL_INVALID_ENUM); } - if (level < 0) - { - return error(GL_INVALID_VALUE); - } - - if (xoffset < 0 || yoffset < 0 || width < 0 || height < 0 || - (level > 0 && !gl::isPow2(width)) || (level > 0 && !gl::isPow2(height)) || imageSize < 0) + if (xoffset < 0 || yoffset < 0 || !validImageSize(level, width, height) || imageSize < 0) { return error(GL_INVALID_VALUE); } @@ -882,6 +1036,8 @@ void __stdcall glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffs { case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: + case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: break; default: return error(GL_INVALID_ENUM); @@ -892,7 +1048,7 @@ void __stdcall glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffs return; } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -901,9 +1057,27 @@ void __stdcall glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffs return error(GL_INVALID_VALUE); } - if (!context->supportsCompressedTextures()) - { - return error(GL_INVALID_ENUM); // in this case, it's as though the format switch has failed. + switch (format) { + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + if (!context->supportsDXT1Textures()) + { + return error(GL_INVALID_ENUM); // in this case, it's as though the internal format switch failed + } + break; + case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: + if (!context->supportsDXT3Textures()) + { + return error(GL_INVALID_ENUM); // in this case, it's as though the internal format switch failed + } + break; + case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: + if (!context->supportsDXT5Textures()) + { + return error(GL_INVALID_ENUM); // in this case, it's as though the internal format switch failed + } + break; + default: UNREACHABLE(); } if (imageSize != gl::ComputeCompressedSize(width, height, format)) @@ -914,52 +1088,24 @@ void __stdcall glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffs if (xoffset % 4 != 0 || yoffset % 4 != 0) { return error(GL_INVALID_OPERATION); // we wait to check the offsets until this point, because the multiple-of-four restriction - // does not exist unless DXT1 textures are supported. + // does not exist unless DXT textures are supported. } if (target == GL_TEXTURE_2D) { gl::Texture2D *texture = context->getTexture2D(); - - if (!texture) - { - return error(GL_INVALID_OPERATION); - } - - if (!texture->isCompressed()) + if (validateSubImageParams(true, width, height, xoffset, yoffset, level, GL_NONE, texture)) { - return error(GL_INVALID_OPERATION); + texture->subImageCompressed(level, xoffset, yoffset, width, height, format, imageSize, data); } - - if ((width % 4 != 0 && width != texture->getWidth()) || - (height % 4 != 0 && height != texture->getHeight())) - { - return error(GL_INVALID_OPERATION); - } - - texture->subImageCompressed(level, xoffset, yoffset, width, height, format, imageSize, data); } else if (gl::IsCubemapTextureTarget(target)) { gl::TextureCubeMap *texture = context->getTextureCubeMap(); - - if (!texture) - { - return error(GL_INVALID_OPERATION); - } - - if (!texture->isCompressed()) - { - return error(GL_INVALID_OPERATION); - } - - if ((width % 4 != 0 && width != texture->getWidth()) || - (height % 4 != 0 && height != texture->getHeight())) + if (validateSubImageParams(true, width, height, xoffset, yoffset, level, GL_NONE, texture)) { - return error(GL_INVALID_OPERATION); + texture->subImageCompressed(target, level, xoffset, yoffset, width, height, format, imageSize, data); } - - texture->subImageCompressed(target, level, xoffset, yoffset, width, height, format, imageSize, data); } else { @@ -975,18 +1121,13 @@ void __stdcall glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffs void __stdcall glCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) { - TRACE("(GLenum target = 0x%X, GLint level = %d, GLenum internalformat = 0x%X, " + EVENT("(GLenum target = 0x%X, GLint level = %d, GLenum internalformat = 0x%X, " "GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d, GLint border = %d)", target, level, internalformat, x, y, width, height, border); try { - if (level < 0 || width < 0 || height < 0) - { - return error(GL_INVALID_VALUE); - } - - if (level > 0 && (!gl::isPow2(width) || !gl::isPow2(height))) + if (!validImageSize(level, width, height)) { return error(GL_INVALID_VALUE); } @@ -996,10 +1137,15 @@ void __stdcall glCopyTexImage2D(GLenum target, GLint level, GLenum internalforma return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { + if (level > context->getMaximumTextureLevel()) + { + return error(GL_INVALID_VALUE); + } + switch (target) { case GL_TEXTURE_2D: @@ -1042,8 +1188,8 @@ void __stdcall glCopyTexImage2D(GLenum target, GLint level, GLenum internalforma return error(GL_INVALID_OPERATION); } - gl::Colorbuffer *source = framebuffer->getColorbuffer(); - GLenum colorbufferFormat = source->getFormat(); + gl::Renderbuffer *source = framebuffer->getColorbuffer(); + GLenum colorbufferFormat = source->getInternalFormat(); // [OpenGL ES 2.0.24] table 3.9 switch (internalformat) @@ -1083,7 +1229,27 @@ void __stdcall glCopyTexImage2D(GLenum target, GLint level, GLenum internalforma break; case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: - if (context->supportsCompressedTextures()) + if (context->supportsDXT1Textures()) + { + return error(GL_INVALID_OPERATION); + } + else + { + return error(GL_INVALID_ENUM); + } + break; + case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: + if (context->supportsDXT3Textures()) + { + return error(GL_INVALID_OPERATION); + } + else + { + return error(GL_INVALID_ENUM); + } + break; + case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: + if (context->supportsDXT5Textures()) { return error(GL_INVALID_OPERATION); } @@ -1105,7 +1271,12 @@ void __stdcall glCopyTexImage2D(GLenum target, GLint level, GLenum internalforma return error(GL_INVALID_OPERATION); } - texture->copyImage(level, internalformat, x, y, width, height, source); + if (texture->isImmutable()) + { + return error(GL_INVALID_OPERATION); + } + + texture->copyImage(level, internalformat, x, y, width, height, framebuffer); } else if (gl::IsCubemapTextureTarget(target)) { @@ -1116,7 +1287,12 @@ void __stdcall glCopyTexImage2D(GLenum target, GLint level, GLenum internalforma return error(GL_INVALID_OPERATION); } - texture->copyImage(target, level, internalformat, x, y, width, height, source); + if (texture->isImmutable()) + { + return error(GL_INVALID_OPERATION); + } + + texture->copyImage(target, level, internalformat, x, y, width, height, framebuffer); } else UNREACHABLE(); } @@ -1129,13 +1305,13 @@ void __stdcall glCopyTexImage2D(GLenum target, GLint level, GLenum internalforma void __stdcall glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) { - TRACE("(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, " + EVENT("(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, " "GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d)", target, level, xoffset, yoffset, x, y, width, height); try { - if (!gl::IsTextureTarget(target)) + if (!gl::IsInternalTextureTarget(target)) { return error(GL_INVALID_ENUM); } @@ -1155,7 +1331,7 @@ void __stdcall glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GL return; } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -1176,8 +1352,8 @@ void __stdcall glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GL return error(GL_INVALID_OPERATION); } - gl::Colorbuffer *source = framebuffer->getColorbuffer(); - GLenum colorbufferFormat = source->getFormat(); + gl::Renderbuffer *source = framebuffer->getColorbuffer(); + GLenum colorbufferFormat = source->getInternalFormat(); gl::Texture *texture = NULL; if (target == GL_TEXTURE_2D) @@ -1190,12 +1366,12 @@ void __stdcall glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GL } else UNREACHABLE(); - if (!texture) + if (!validateSubImageParams(false, width, height, xoffset, yoffset, level, GL_NONE, texture)) { - return error(GL_INVALID_OPERATION); + return; // error already registered by validateSubImageParams } - GLenum textureFormat = texture->getFormat(); + GLenum textureFormat = texture->getInternalFormat(); // [OpenGL ES 2.0.24] table 3.9 switch (textureFormat) @@ -1235,12 +1411,14 @@ void __stdcall glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GL break; case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: + case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: return error(GL_INVALID_OPERATION); default: return error(GL_INVALID_OPERATION); } - texture->copySubImage(target, level, xoffset, yoffset, x, y, width, height, source); + texture->copySubImage(target, level, xoffset, yoffset, x, y, width, height, framebuffer); } } @@ -1252,11 +1430,11 @@ void __stdcall glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GL GLuint __stdcall glCreateProgram(void) { - TRACE("()"); + EVENT("()"); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -1273,11 +1451,11 @@ GLuint __stdcall glCreateProgram(void) GLuint __stdcall glCreateShader(GLenum type) { - TRACE("(GLenum type = 0x%X)", type); + EVENT("(GLenum type = 0x%X)", type); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -1301,7 +1479,7 @@ GLuint __stdcall glCreateShader(GLenum type) void __stdcall glCullFace(GLenum mode) { - TRACE("(GLenum mode = 0x%X)", mode); + EVENT("(GLenum mode = 0x%X)", mode); try { @@ -1311,7 +1489,7 @@ void __stdcall glCullFace(GLenum mode) case GL_BACK: case GL_FRONT_AND_BACK: { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -1331,7 +1509,7 @@ void __stdcall glCullFace(GLenum mode) void __stdcall glDeleteBuffers(GLsizei n, const GLuint* buffers) { - TRACE("(GLsizei n = %d, const GLuint* buffers = 0x%0.8p)", n, buffers); + EVENT("(GLsizei n = %d, const GLuint* buffers = 0x%0.8p)", n, buffers); try { @@ -1340,7 +1518,7 @@ void __stdcall glDeleteBuffers(GLsizei n, const GLuint* buffers) return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -1358,7 +1536,7 @@ void __stdcall glDeleteBuffers(GLsizei n, const GLuint* buffers) void __stdcall glDeleteFencesNV(GLsizei n, const GLuint* fences) { - TRACE("(GLsizei n = %d, const GLuint* fences = 0x%0.8p)", n, fences); + EVENT("(GLsizei n = %d, const GLuint* fences = 0x%0.8p)", n, fences); try { @@ -1367,7 +1545,7 @@ void __stdcall glDeleteFencesNV(GLsizei n, const GLuint* fences) return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -1385,7 +1563,7 @@ void __stdcall glDeleteFencesNV(GLsizei n, const GLuint* fences) void __stdcall glDeleteFramebuffers(GLsizei n, const GLuint* framebuffers) { - TRACE("(GLsizei n = %d, const GLuint* framebuffers = 0x%0.8p)", n, framebuffers); + EVENT("(GLsizei n = %d, const GLuint* framebuffers = 0x%0.8p)", n, framebuffers); try { @@ -1394,7 +1572,7 @@ void __stdcall glDeleteFramebuffers(GLsizei n, const GLuint* framebuffers) return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -1415,7 +1593,7 @@ void __stdcall glDeleteFramebuffers(GLsizei n, const GLuint* framebuffers) void __stdcall glDeleteProgram(GLuint program) { - TRACE("(GLuint program = %d)", program); + EVENT("(GLuint program = %d)", program); try { @@ -1424,7 +1602,7 @@ void __stdcall glDeleteProgram(GLuint program) return; } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -1449,9 +1627,36 @@ void __stdcall glDeleteProgram(GLuint program) } } +void __stdcall glDeleteQueriesEXT(GLsizei n, const GLuint *ids) +{ + EVENT("(GLsizei n = %d, const GLuint *ids = 0x%0.8p)", n, ids); + + try + { + if (n < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + for (int i = 0; i < n; i++) + { + context->deleteQuery(ids[i]); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + void __stdcall glDeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers) { - TRACE("(GLsizei n = %d, const GLuint* renderbuffers = 0x%0.8p)", n, renderbuffers); + EVENT("(GLsizei n = %d, const GLuint* renderbuffers = 0x%0.8p)", n, renderbuffers); try { @@ -1460,7 +1665,7 @@ void __stdcall glDeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers) return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -1478,7 +1683,7 @@ void __stdcall glDeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers) void __stdcall glDeleteShader(GLuint shader) { - TRACE("(GLuint shader = %d)", shader); + EVENT("(GLuint shader = %d)", shader); try { @@ -1487,7 +1692,7 @@ void __stdcall glDeleteShader(GLuint shader) return; } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -1514,7 +1719,7 @@ void __stdcall glDeleteShader(GLuint shader) void __stdcall glDeleteTextures(GLsizei n, const GLuint* textures) { - TRACE("(GLsizei n = %d, const GLuint* textures = 0x%0.8p)", n, textures); + EVENT("(GLsizei n = %d, const GLuint* textures = 0x%0.8p)", n, textures); try { @@ -1523,7 +1728,7 @@ void __stdcall glDeleteTextures(GLsizei n, const GLuint* textures) return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -1544,7 +1749,7 @@ void __stdcall glDeleteTextures(GLsizei n, const GLuint* textures) void __stdcall glDepthFunc(GLenum func) { - TRACE("(GLenum func = 0x%X)", func); + EVENT("(GLenum func = 0x%X)", func); try { @@ -1563,7 +1768,7 @@ void __stdcall glDepthFunc(GLenum func) return error(GL_INVALID_ENUM); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -1578,11 +1783,11 @@ void __stdcall glDepthFunc(GLenum func) void __stdcall glDepthMask(GLboolean flag) { - TRACE("(GLboolean flag = %d)", flag); + EVENT("(GLboolean flag = %d)", flag); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -1597,11 +1802,11 @@ void __stdcall glDepthMask(GLboolean flag) void __stdcall glDepthRangef(GLclampf zNear, GLclampf zFar) { - TRACE("(GLclampf zNear = %f, GLclampf zFar = %f)", zNear, zFar); + EVENT("(GLclampf zNear = %f, GLclampf zFar = %f)", zNear, zFar); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -1616,11 +1821,11 @@ void __stdcall glDepthRangef(GLclampf zNear, GLclampf zFar) void __stdcall glDetachShader(GLuint program, GLuint shader) { - TRACE("(GLuint program = %d, GLuint shader = %d)", program, shader); + EVENT("(GLuint program = %d, GLuint shader = %d)", program, shader); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -1669,11 +1874,11 @@ void __stdcall glDetachShader(GLuint program, GLuint shader) void __stdcall glDisable(GLenum cap) { - TRACE("(GLenum cap = 0x%X)", cap); + EVENT("(GLenum cap = 0x%X)", cap); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -1701,7 +1906,7 @@ void __stdcall glDisable(GLenum cap) void __stdcall glDisableVertexAttribArray(GLuint index) { - TRACE("(GLuint index = %d)", index); + EVENT("(GLuint index = %d)", index); try { @@ -1710,7 +1915,7 @@ void __stdcall glDisableVertexAttribArray(GLuint index) return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -1725,7 +1930,7 @@ void __stdcall glDisableVertexAttribArray(GLuint index) void __stdcall glDrawArrays(GLenum mode, GLint first, GLsizei count) { - TRACE("(GLenum mode = 0x%X, GLint first = %d, GLsizei count = %d)", mode, first, count); + EVENT("(GLenum mode = 0x%X, GLint first = %d, GLsizei count = %d)", mode, first, count); try { @@ -1734,11 +1939,38 @@ void __stdcall glDrawArrays(GLenum mode, GLint first, GLsizei count) return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { - context->drawArrays(mode, first, count); + context->drawArrays(mode, first, count, 0); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glDrawArraysInstancedANGLE(GLenum mode, GLint first, GLsizei count, GLsizei primcount) +{ + EVENT("(GLenum mode = 0x%X, GLint first = %d, GLsizei count = %d, GLsizei primcount = %d)", mode, first, count, primcount); + + try + { + if (count < 0 || first < 0 || primcount < 0) + { + return error(GL_INVALID_VALUE); + } + + if (primcount > 0) + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + context->drawArrays(mode, first, count, primcount); + } } } catch(std::bad_alloc&) @@ -1749,7 +1981,7 @@ void __stdcall glDrawArrays(GLenum mode, GLint first, GLsizei count) void __stdcall glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices) { - TRACE("(GLenum mode = 0x%X, GLsizei count = %d, GLenum type = 0x%X, const GLvoid* indices = 0x%0.8p)", + EVENT("(GLenum mode = 0x%X, GLsizei count = %d, GLenum type = 0x%X, const GLvoid* indices = 0x%0.8p)", mode, count, type, indices); try @@ -1759,7 +1991,7 @@ void __stdcall glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLv return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -1778,7 +2010,50 @@ void __stdcall glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLv return error(GL_INVALID_ENUM); } - context->drawElements(mode, count, type, indices); + context->drawElements(mode, count, type, indices, 0); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glDrawElementsInstancedANGLE(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount) +{ + EVENT("(GLenum mode = 0x%X, GLsizei count = %d, GLenum type = 0x%X, const GLvoid* indices = 0x%0.8p, GLsizei primcount = %d)", + mode, count, type, indices, primcount); + + try + { + if (count < 0 || primcount < 0) + { + return error(GL_INVALID_VALUE); + } + + if (primcount > 0) + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + switch (type) + { + case GL_UNSIGNED_BYTE: + case GL_UNSIGNED_SHORT: + break; + case GL_UNSIGNED_INT: + if (!context->supports32bitIndices()) + { + return error(GL_INVALID_ENUM); + } + break; + default: + return error(GL_INVALID_ENUM); + } + + context->drawElements(mode, count, type, indices, primcount); + } } } catch(std::bad_alloc&) @@ -1789,11 +2064,11 @@ void __stdcall glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLv void __stdcall glEnable(GLenum cap) { - TRACE("(GLenum cap = 0x%X)", cap); + EVENT("(GLenum cap = 0x%X)", cap); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -1821,7 +2096,7 @@ void __stdcall glEnable(GLenum cap) void __stdcall glEnableVertexAttribArray(GLuint index) { - TRACE("(GLuint index = %d)", index); + EVENT("(GLuint index = %d)", index); try { @@ -1830,7 +2105,7 @@ void __stdcall glEnableVertexAttribArray(GLuint index) return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -1843,13 +2118,41 @@ void __stdcall glEnableVertexAttribArray(GLuint index) } } +void __stdcall glEndQueryEXT(GLenum target) +{ + EVENT("GLenum target = 0x%X)", target); + + try + { + switch (target) + { + case GL_ANY_SAMPLES_PASSED_EXT: + case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT: + break; + default: + return error(GL_INVALID_ENUM); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + context->endQuery(target); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + void __stdcall glFinishFenceNV(GLuint fence) { - TRACE("(GLuint fence = %d)", fence); + EVENT("(GLuint fence = %d)", fence); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -1871,15 +2174,15 @@ void __stdcall glFinishFenceNV(GLuint fence) void __stdcall glFinish(void) { - TRACE("()"); + EVENT("()"); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { - context->finish(); + context->sync(true); } } catch(std::bad_alloc&) @@ -1890,15 +2193,15 @@ void __stdcall glFinish(void) void __stdcall glFlush(void) { - TRACE("()"); + EVENT("()"); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { - context->flush(); + context->sync(false); } } catch(std::bad_alloc&) @@ -1909,18 +2212,18 @@ void __stdcall glFlush(void) void __stdcall glFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) { - TRACE("(GLenum target = 0x%X, GLenum attachment = 0x%X, GLenum renderbuffertarget = 0x%X, " + EVENT("(GLenum target = 0x%X, GLenum attachment = 0x%X, GLenum renderbuffertarget = 0x%X, " "GLuint renderbuffer = %d)", target, attachment, renderbuffertarget, renderbuffer); try { if ((target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER_ANGLE && target != GL_READ_FRAMEBUFFER_ANGLE) - || renderbuffertarget != GL_RENDERBUFFER) + || (renderbuffertarget != GL_RENDERBUFFER && renderbuffer != 0)) { return error(GL_INVALID_ENUM); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -1931,13 +2234,13 @@ void __stdcall glFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenu framebuffer = context->getReadFramebuffer(); framebufferHandle = context->getReadFramebufferHandle(); } - else + else { framebuffer = context->getDrawFramebuffer(); framebufferHandle = context->getDrawFramebufferHandle(); } - if (framebufferHandle == 0 || !framebuffer) + if (!framebuffer || (framebufferHandle == 0 && renderbuffer != 0)) { return error(GL_INVALID_OPERATION); } @@ -1966,7 +2269,7 @@ void __stdcall glFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenu void __stdcall glFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) { - TRACE("(GLenum target = 0x%X, GLenum attachment = 0x%X, GLenum textarget = 0x%X, " + EVENT("(GLenum target = 0x%X, GLenum attachment = 0x%X, GLenum textarget = 0x%X, " "GLuint texture = %d, GLint level = %d)", target, attachment, textarget, texture, level); try @@ -1986,7 +2289,7 @@ void __stdcall glFramebufferTexture2D(GLenum target, GLenum attachment, GLenum t return error(GL_INVALID_ENUM); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -2073,7 +2376,7 @@ void __stdcall glFramebufferTexture2D(GLenum target, GLenum attachment, GLenum t void __stdcall glFrontFace(GLenum mode) { - TRACE("(GLenum mode = 0x%X)", mode); + EVENT("(GLenum mode = 0x%X)", mode); try { @@ -2082,7 +2385,7 @@ void __stdcall glFrontFace(GLenum mode) case GL_CW: case GL_CCW: { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -2102,7 +2405,7 @@ void __stdcall glFrontFace(GLenum mode) void __stdcall glGenBuffers(GLsizei n, GLuint* buffers) { - TRACE("(GLsizei n = %d, GLuint* buffers = 0x%0.8p)", n, buffers); + EVENT("(GLsizei n = %d, GLuint* buffers = 0x%0.8p)", n, buffers); try { @@ -2111,7 +2414,7 @@ void __stdcall glGenBuffers(GLsizei n, GLuint* buffers) return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -2129,11 +2432,11 @@ void __stdcall glGenBuffers(GLsizei n, GLuint* buffers) void __stdcall glGenerateMipmap(GLenum target) { - TRACE("(GLenum target = 0x%X)", target); + EVENT("(GLenum target = 0x%X)", target); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -2169,7 +2472,7 @@ void __stdcall glGenerateMipmap(GLenum target) void __stdcall glGenFencesNV(GLsizei n, GLuint* fences) { - TRACE("(GLsizei n = %d, GLuint* fences = 0x%0.8p)", n, fences); + EVENT("(GLsizei n = %d, GLuint* fences = 0x%0.8p)", n, fences); try { @@ -2178,7 +2481,7 @@ void __stdcall glGenFencesNV(GLsizei n, GLuint* fences) return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -2196,7 +2499,7 @@ void __stdcall glGenFencesNV(GLsizei n, GLuint* fences) void __stdcall glGenFramebuffers(GLsizei n, GLuint* framebuffers) { - TRACE("(GLsizei n = %d, GLuint* framebuffers = 0x%0.8p)", n, framebuffers); + EVENT("(GLsizei n = %d, GLuint* framebuffers = 0x%0.8p)", n, framebuffers); try { @@ -2205,7 +2508,7 @@ void __stdcall glGenFramebuffers(GLsizei n, GLuint* framebuffers) return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -2221,9 +2524,36 @@ void __stdcall glGenFramebuffers(GLsizei n, GLuint* framebuffers) } } +void __stdcall glGenQueriesEXT(GLsizei n, GLuint* ids) +{ + EVENT("(GLsizei n = %d, GLuint* ids = 0x%0.8p)", n, ids); + + try + { + if (n < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + for (int i = 0; i < n; i++) + { + ids[i] = context->createQuery(); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + void __stdcall glGenRenderbuffers(GLsizei n, GLuint* renderbuffers) { - TRACE("(GLsizei n = %d, GLuint* renderbuffers = 0x%0.8p)", n, renderbuffers); + EVENT("(GLsizei n = %d, GLuint* renderbuffers = 0x%0.8p)", n, renderbuffers); try { @@ -2232,7 +2562,7 @@ void __stdcall glGenRenderbuffers(GLsizei n, GLuint* renderbuffers) return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -2250,7 +2580,7 @@ void __stdcall glGenRenderbuffers(GLsizei n, GLuint* renderbuffers) void __stdcall glGenTextures(GLsizei n, GLuint* textures) { - TRACE("(GLsizei n = %d, GLuint* textures = 0x%0.8p)", n, textures); + EVENT("(GLsizei n = %d, GLuint* textures = 0x%0.8p)", n, textures); try { @@ -2259,7 +2589,7 @@ void __stdcall glGenTextures(GLsizei n, GLuint* textures) return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -2277,7 +2607,7 @@ void __stdcall glGenTextures(GLsizei n, GLuint* textures) void __stdcall glGetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) { - TRACE("(GLuint program = %d, GLuint index = %d, GLsizei bufsize = %d, GLsizei *length = 0x%0.8p, " + EVENT("(GLuint program = %d, GLuint index = %d, GLsizei bufsize = %d, GLsizei *length = 0x%0.8p, " "GLint *size = 0x%0.8p, GLenum *type = %0.8p, GLchar *name = %0.8p)", program, index, bufsize, length, size, type, name); @@ -2288,7 +2618,7 @@ void __stdcall glGetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize, return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -2322,7 +2652,7 @@ void __stdcall glGetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize, void __stdcall glGetActiveUniform(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name) { - TRACE("(GLuint program = %d, GLuint index = %d, GLsizei bufsize = %d, " + EVENT("(GLuint program = %d, GLuint index = %d, GLsizei bufsize = %d, " "GLsizei* length = 0x%0.8p, GLint* size = 0x%0.8p, GLenum* type = 0x%0.8p, GLchar* name = 0x%0.8p)", program, index, bufsize, length, size, type, name); @@ -2333,7 +2663,7 @@ void __stdcall glGetActiveUniform(GLuint program, GLuint index, GLsizei bufsize, return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -2367,7 +2697,7 @@ void __stdcall glGetActiveUniform(GLuint program, GLuint index, GLsizei bufsize, void __stdcall glGetAttachedShaders(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders) { - TRACE("(GLuint program = %d, GLsizei maxcount = %d, GLsizei* count = 0x%0.8p, GLuint* shaders = 0x%0.8p)", + EVENT("(GLuint program = %d, GLsizei maxcount = %d, GLsizei* count = 0x%0.8p, GLuint* shaders = 0x%0.8p)", program, maxcount, count, shaders); try @@ -2377,7 +2707,7 @@ void __stdcall glGetAttachedShaders(GLuint program, GLsizei maxcount, GLsizei* c return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -2406,11 +2736,11 @@ void __stdcall glGetAttachedShaders(GLuint program, GLsizei maxcount, GLsizei* c int __stdcall glGetAttribLocation(GLuint program, const GLchar* name) { - TRACE("(GLuint program = %d, const GLchar* name = %s)", program, name); + EVENT("(GLuint program = %d, const GLchar* name = %s)", program, name); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -2447,11 +2777,11 @@ int __stdcall glGetAttribLocation(GLuint program, const GLchar* name) void __stdcall glGetBooleanv(GLenum pname, GLboolean* params) { - TRACE("(GLenum pname = 0x%X, GLboolean* params = 0x%0.8p)", pname, params); + EVENT("(GLenum pname = 0x%X, GLboolean* params = 0x%0.8p)", pname, params); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -2510,11 +2840,11 @@ void __stdcall glGetBooleanv(GLenum pname, GLboolean* params) void __stdcall glGetBufferParameteriv(GLenum target, GLenum pname, GLint* params) { - TRACE("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", target, pname, params); + EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", target, pname, params); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -2557,7 +2887,7 @@ void __stdcall glGetBufferParameteriv(GLenum target, GLenum pname, GLint* params GLenum __stdcall glGetError(void) { - TRACE("()"); + EVENT("()"); gl::Context *context = gl::getContext(); @@ -2571,12 +2901,12 @@ GLenum __stdcall glGetError(void) void __stdcall glGetFenceivNV(GLuint fence, GLenum pname, GLint *params) { - TRACE("(GLuint fence = %d, GLenum pname = 0x%X, GLint *params = 0x%0.8p)", fence, pname, params); + EVENT("(GLuint fence = %d, GLenum pname = 0x%X, GLint *params = 0x%0.8p)", fence, pname, params); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -2598,11 +2928,11 @@ void __stdcall glGetFenceivNV(GLuint fence, GLenum pname, GLint *params) void __stdcall glGetFloatv(GLenum pname, GLfloat* params) { - TRACE("(GLenum pname = 0x%X, GLfloat* params = 0x%0.8p)", pname, params); + EVENT("(GLenum pname = 0x%X, GLfloat* params = 0x%0.8p)", pname, params); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -2658,12 +2988,12 @@ void __stdcall glGetFloatv(GLenum pname, GLfloat* params) void __stdcall glGetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint* params) { - TRACE("(GLenum target = 0x%X, GLenum attachment = 0x%X, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", + EVENT("(GLenum target = 0x%X, GLenum attachment = 0x%X, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", target, attachment, pname, params); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -2716,11 +3046,15 @@ void __stdcall glGetFramebufferAttachmentParameteriv(GLenum target, GLenum attac { attachmentObjectType = attachmentType; } - else if (gl::IsTextureTarget(attachmentType)) + else if (gl::IsInternalTextureTarget(attachmentType)) { attachmentObjectType = GL_TEXTURE; } - else UNREACHABLE(); + else + { + UNREACHABLE(); + return; + } switch (pname) { @@ -2775,9 +3109,9 @@ void __stdcall glGetFramebufferAttachmentParameteriv(GLenum target, GLenum attac } } -void __stdcall glGetIntegerv(GLenum pname, GLint* params) +GLenum __stdcall glGetGraphicsResetStatusEXT(void) { - TRACE("(GLenum pname = 0x%X, GLint* params = 0x%0.8p)", pname, params); + EVENT("()"); try { @@ -2785,6 +3119,27 @@ void __stdcall glGetIntegerv(GLenum pname, GLint* params) if (context) { + return context->getResetStatus(); + } + + return GL_NO_ERROR; + } + catch(std::bad_alloc&) + { + return GL_OUT_OF_MEMORY; + } +} + +void __stdcall glGetIntegerv(GLenum pname, GLint* params) +{ + EVENT("(GLenum pname = 0x%X, GLint* params = 0x%0.8p)", pname, params); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { if (!(context->getIntegerv(pname, params))) { GLenum nativeType; @@ -2842,11 +3197,11 @@ void __stdcall glGetIntegerv(GLenum pname, GLint* params) void __stdcall glGetProgramiv(GLuint program, GLenum pname, GLint* params) { - TRACE("(GLuint program = %d, GLenum pname = %d, GLint* params = 0x%0.8p)", program, pname, params); + EVENT("(GLuint program = %d, GLenum pname = %d, GLint* params = 0x%0.8p)", program, pname, params); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -2899,7 +3254,7 @@ void __stdcall glGetProgramiv(GLuint program, GLenum pname, GLint* params) void __stdcall glGetProgramInfoLog(GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog) { - TRACE("(GLuint program = %d, GLsizei bufsize = %d, GLsizei* length = 0x%0.8p, GLchar* infolog = 0x%0.8p)", + EVENT("(GLuint program = %d, GLsizei bufsize = %d, GLsizei* length = 0x%0.8p, GLchar* infolog = 0x%0.8p)", program, bufsize, length, infolog); try @@ -2909,7 +3264,7 @@ void __stdcall glGetProgramInfoLog(GLuint program, GLsizei bufsize, GLsizei* len return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -2929,13 +3284,89 @@ void __stdcall glGetProgramInfoLog(GLuint program, GLsizei bufsize, GLsizei* len } } +void __stdcall glGetQueryivEXT(GLenum target, GLenum pname, GLint *params) +{ + EVENT("GLenum target = 0x%X, GLenum pname = 0x%X, GLint *params = 0x%0.8p)", target, pname, params); + + try + { + switch (pname) + { + case GL_CURRENT_QUERY_EXT: + break; + default: + return error(GL_INVALID_ENUM); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + params[0] = context->getActiveQuery(target); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGetQueryObjectuivEXT(GLuint id, GLenum pname, GLuint *params) +{ + EVENT("(GLuint id = %d, GLenum pname = 0x%X, GLuint *params = 0x%0.8p)", id, pname, params); + + try + { + switch (pname) + { + case GL_QUERY_RESULT_EXT: + case GL_QUERY_RESULT_AVAILABLE_EXT: + break; + default: + return error(GL_INVALID_ENUM); + } + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::Query *queryObject = context->getQuery(id, false, GL_NONE); + + if (!queryObject) + { + return error(GL_INVALID_OPERATION); + } + + if (context->getActiveQuery(queryObject->getType()) == id) + { + return error(GL_INVALID_OPERATION); + } + + switch(pname) + { + case GL_QUERY_RESULT_EXT: + params[0] = queryObject->getResult(); + break; + case GL_QUERY_RESULT_AVAILABLE_EXT: + params[0] = queryObject->isResultAvailable(); + break; + default: + ASSERT(false); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + void __stdcall glGetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params) { - TRACE("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", target, pname, params); + EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", target, pname, params); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -2953,85 +3384,23 @@ void __stdcall glGetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* switch (pname) { - case GL_RENDERBUFFER_WIDTH: - *params = renderbuffer->getWidth(); - break; - case GL_RENDERBUFFER_HEIGHT: - *params = renderbuffer->getHeight(); - break; - case GL_RENDERBUFFER_INTERNAL_FORMAT: - *params = renderbuffer->getFormat(); - break; - case GL_RENDERBUFFER_RED_SIZE: - if (renderbuffer->isColorbuffer()) - { - *params = static_cast<gl::Colorbuffer*>(renderbuffer->getStorage())->getRedSize(); - } - else - { - *params = 0; - } - break; - case GL_RENDERBUFFER_GREEN_SIZE: - if (renderbuffer->isColorbuffer()) - { - *params = static_cast<gl::Colorbuffer*>(renderbuffer->getStorage())->getGreenSize(); - } - else - { - *params = 0; - } - break; - case GL_RENDERBUFFER_BLUE_SIZE: - if (renderbuffer->isColorbuffer()) - { - *params = static_cast<gl::Colorbuffer*>(renderbuffer->getStorage())->getBlueSize(); - } - else - { - *params = 0; - } - break; - case GL_RENDERBUFFER_ALPHA_SIZE: - if (renderbuffer->isColorbuffer()) - { - *params = static_cast<gl::Colorbuffer*>(renderbuffer->getStorage())->getAlphaSize(); - } - else - { - *params = 0; - } - break; - case GL_RENDERBUFFER_DEPTH_SIZE: - if (renderbuffer->isDepthbuffer()) - { - *params = static_cast<gl::Depthbuffer*>(renderbuffer->getStorage())->getDepthSize(); - } - else - { - *params = 0; - } - break; - case GL_RENDERBUFFER_STENCIL_SIZE: - if (renderbuffer->isStencilbuffer()) + case GL_RENDERBUFFER_WIDTH: *params = renderbuffer->getWidth(); break; + case GL_RENDERBUFFER_HEIGHT: *params = renderbuffer->getHeight(); break; + case GL_RENDERBUFFER_INTERNAL_FORMAT: *params = renderbuffer->getInternalFormat(); break; + case GL_RENDERBUFFER_RED_SIZE: *params = renderbuffer->getRedSize(); break; + case GL_RENDERBUFFER_GREEN_SIZE: *params = renderbuffer->getGreenSize(); break; + case GL_RENDERBUFFER_BLUE_SIZE: *params = renderbuffer->getBlueSize(); break; + case GL_RENDERBUFFER_ALPHA_SIZE: *params = renderbuffer->getAlphaSize(); break; + case GL_RENDERBUFFER_DEPTH_SIZE: *params = renderbuffer->getDepthSize(); break; + case GL_RENDERBUFFER_STENCIL_SIZE: *params = renderbuffer->getStencilSize(); break; + case GL_RENDERBUFFER_SAMPLES_ANGLE: + if (context->getMaxSupportedSamples() != 0) { - *params = static_cast<gl::Stencilbuffer*>(renderbuffer->getStorage())->getStencilSize(); + *params = renderbuffer->getSamples(); } else { - *params = 0; - } - break; - case GL_RENDERBUFFER_SAMPLES_ANGLE: - { - if (context->getMaxSupportedSamples() != 0) - { - *params = renderbuffer->getStorage()->getSamples(); - } - else - { - return error(GL_INVALID_ENUM); - } + return error(GL_INVALID_ENUM); } break; default: @@ -3047,11 +3416,11 @@ void __stdcall glGetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* void __stdcall glGetShaderiv(GLuint shader, GLenum pname, GLint* params) { - TRACE("(GLuint shader = %d, GLenum pname = %d, GLint* params = 0x%0.8p)", shader, pname, params); + EVENT("(GLuint shader = %d, GLenum pname = %d, GLint* params = 0x%0.8p)", shader, pname, params); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -3079,6 +3448,9 @@ void __stdcall glGetShaderiv(GLuint shader, GLenum pname, GLint* params) case GL_SHADER_SOURCE_LENGTH: *params = shaderObject->getSourceLength(); return; + case GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE: + *params = shaderObject->getTranslatedSourceLength(); + return; default: return error(GL_INVALID_ENUM); } @@ -3092,7 +3464,7 @@ void __stdcall glGetShaderiv(GLuint shader, GLenum pname, GLint* params) void __stdcall glGetShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog) { - TRACE("(GLuint shader = %d, GLsizei bufsize = %d, GLsizei* length = 0x%0.8p, GLchar* infolog = 0x%0.8p)", + EVENT("(GLuint shader = %d, GLsizei bufsize = %d, GLsizei* length = 0x%0.8p, GLchar* infolog = 0x%0.8p)", shader, bufsize, length, infolog); try @@ -3102,7 +3474,7 @@ void __stdcall glGetShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei* lengt return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -3124,7 +3496,7 @@ void __stdcall glGetShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei* lengt void __stdcall glGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) { - TRACE("(GLenum shadertype = 0x%X, GLenum precisiontype = 0x%X, GLint* range = 0x%0.8p, GLint* precision = 0x%0.8p)", + EVENT("(GLenum shadertype = 0x%X, GLenum precisiontype = 0x%X, GLint* range = 0x%0.8p, GLint* precision = 0x%0.8p)", shadertype, precisiontype, range, precision); try @@ -3169,7 +3541,7 @@ void __stdcall glGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontyp void __stdcall glGetShaderSource(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source) { - TRACE("(GLuint shader = %d, GLsizei bufsize = %d, GLsizei* length = 0x%0.8p, GLchar* source = 0x%0.8p)", + EVENT("(GLuint shader = %d, GLsizei bufsize = %d, GLsizei* length = 0x%0.8p, GLchar* source = 0x%0.8p)", shader, bufsize, length, source); try @@ -3179,7 +3551,7 @@ void __stdcall glGetShaderSource(GLuint shader, GLsizei bufsize, GLsizei* length return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -3199,24 +3571,56 @@ void __stdcall glGetShaderSource(GLuint shader, GLsizei bufsize, GLsizei* length } } +void __stdcall glGetTranslatedShaderSourceANGLE(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source) +{ + EVENT("(GLuint shader = %d, GLsizei bufsize = %d, GLsizei* length = 0x%0.8p, GLchar* source = 0x%0.8p)", + shader, bufsize, length, source); + + try + { + if (bufsize < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::Shader *shaderObject = context->getShader(shader); + + if (!shaderObject) + { + return error(GL_INVALID_OPERATION); + } + + shaderObject->getTranslatedSource(bufsize, length, source); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + const GLubyte* __stdcall glGetString(GLenum name) { - TRACE("(GLenum name = 0x%X)", name); + EVENT("(GLenum name = 0x%X)", name); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); switch (name) { case GL_VENDOR: - return (GLubyte*)"TransGaming Inc."; + return (GLubyte*)"Google Inc."; case GL_RENDERER: - return (GLubyte*)"ANGLE"; + return (GLubyte*)((context != NULL) ? context->getRendererString() : "ANGLE"); case GL_VERSION: - return (GLubyte*)"OpenGL ES 2.0 (git-devel "__DATE__ " " __TIME__")"; + return (GLubyte*)"OpenGL ES 2.0 (ANGLE "VERSION_STRING")"; case GL_SHADING_LANGUAGE_VERSION: - return (GLubyte*)"OpenGL ES GLSL ES 1.00 (git-devel "__DATE__ " " __TIME__")"; + return (GLubyte*)"OpenGL ES GLSL ES 1.00 (ANGLE "VERSION_STRING")"; case GL_EXTENSIONS: return (GLubyte*)((context != NULL) ? context->getExtensionString() : ""); default: @@ -3227,17 +3631,15 @@ const GLubyte* __stdcall glGetString(GLenum name) { return error(GL_OUT_OF_MEMORY, (GLubyte*)NULL); } - - return NULL; } void __stdcall glGetTexParameterfv(GLenum target, GLenum pname, GLfloat* params) { - TRACE("(GLenum target = 0x%X, GLenum pname = 0x%X, GLfloat* params = 0x%0.8p)", target, pname, params); + EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLfloat* params = 0x%0.8p)", target, pname, params); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -3269,6 +3671,12 @@ void __stdcall glGetTexParameterfv(GLenum target, GLenum pname, GLfloat* params) case GL_TEXTURE_WRAP_T: *params = (GLfloat)texture->getWrapT(); break; + case GL_TEXTURE_IMMUTABLE_FORMAT_EXT: + *params = (GLfloat)(texture->isImmutable() ? GL_TRUE : GL_FALSE); + break; + case GL_TEXTURE_USAGE_ANGLE: + *params = (GLfloat)texture->getUsage(); + break; default: return error(GL_INVALID_ENUM); } @@ -3282,11 +3690,11 @@ void __stdcall glGetTexParameterfv(GLenum target, GLenum pname, GLfloat* params) void __stdcall glGetTexParameteriv(GLenum target, GLenum pname, GLint* params) { - TRACE("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", target, pname, params); + EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", target, pname, params); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -3318,6 +3726,12 @@ void __stdcall glGetTexParameteriv(GLenum target, GLenum pname, GLint* params) case GL_TEXTURE_WRAP_T: *params = texture->getWrapT(); break; + case GL_TEXTURE_IMMUTABLE_FORMAT_EXT: + *params = texture->isImmutable() ? GL_TRUE : GL_FALSE; + break; + case GL_TEXTURE_USAGE_ANGLE: + *params = texture->getUsage(); + break; default: return error(GL_INVALID_ENUM); } @@ -3329,13 +3743,93 @@ void __stdcall glGetTexParameteriv(GLenum target, GLenum pname, GLint* params) } } +void __stdcall glGetnUniformfvEXT(GLuint program, GLint location, GLsizei bufSize, GLfloat* params) +{ + EVENT("(GLuint program = %d, GLint location = %d, GLsizei bufSize = %d, GLfloat* params = 0x%0.8p)", + program, location, bufSize, params); + + try + { + if (bufSize < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (program == 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Program *programObject = context->getProgram(program); + + if (!programObject || !programObject->isLinked()) + { + return error(GL_INVALID_OPERATION); + } + + if (!programObject->getUniformfv(location, &bufSize, params)) + { + return error(GL_INVALID_OPERATION); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + void __stdcall glGetUniformfv(GLuint program, GLint location, GLfloat* params) { - TRACE("(GLuint program = %d, GLint location = %d, GLfloat* params = 0x%0.8p)", program, location, params); + EVENT("(GLuint program = %d, GLint location = %d, GLfloat* params = 0x%0.8p)", program, location, params); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (program == 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Program *programObject = context->getProgram(program); + + if (!programObject || !programObject->isLinked()) + { + return error(GL_INVALID_OPERATION); + } + + if (!programObject->getUniformfv(location, NULL, params)) + { + return error(GL_INVALID_OPERATION); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGetnUniformivEXT(GLuint program, GLint location, GLsizei bufSize, GLint* params) +{ + EVENT("(GLuint program = %d, GLint location = %d, GLsizei bufSize = %d, GLint* params = 0x%0.8p)", + program, location, bufSize, params); + + try + { + if (bufSize < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -3351,7 +3845,12 @@ void __stdcall glGetUniformfv(GLuint program, GLint location, GLfloat* params) return error(GL_INVALID_OPERATION); } - if (!programObject->getUniformfv(location, params)) + if (!programObject) + { + return error(GL_INVALID_OPERATION); + } + + if (!programObject->getUniformiv(location, &bufSize, params)) { return error(GL_INVALID_OPERATION); } @@ -3365,11 +3864,11 @@ void __stdcall glGetUniformfv(GLuint program, GLint location, GLfloat* params) void __stdcall glGetUniformiv(GLuint program, GLint location, GLint* params) { - TRACE("(GLuint program = %d, GLint location = %d, GLint* params = 0x%0.8p)", program, location, params); + EVENT("(GLuint program = %d, GLint location = %d, GLint* params = 0x%0.8p)", program, location, params); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -3390,7 +3889,7 @@ void __stdcall glGetUniformiv(GLuint program, GLint location, GLint* params) return error(GL_INVALID_OPERATION); } - if (!programObject->getUniformiv(location, params)) + if (!programObject->getUniformiv(location, NULL, params)) { return error(GL_INVALID_OPERATION); } @@ -3404,11 +3903,11 @@ void __stdcall glGetUniformiv(GLuint program, GLint location, GLint* params) int __stdcall glGetUniformLocation(GLuint program, const GLchar* name) { - TRACE("(GLuint program = %d, const GLchar* name = 0x%0.8p)", program, name); + EVENT("(GLuint program = %d, const GLchar* name = 0x%0.8p)", program, name); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (strstr(name, "gl_") == name) { @@ -3436,7 +3935,7 @@ int __stdcall glGetUniformLocation(GLuint program, const GLchar* name) return error(GL_INVALID_OPERATION, -1); } - return programObject->getUniformLocation(name, false); + return programObject->getUniformLocation(name); } } catch(std::bad_alloc&) @@ -3449,11 +3948,11 @@ int __stdcall glGetUniformLocation(GLuint program, const GLchar* name) void __stdcall glGetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params) { - TRACE("(GLuint index = %d, GLenum pname = 0x%X, GLfloat* params = 0x%0.8p)", index, pname, params); + EVENT("(GLuint index = %d, GLenum pname = 0x%X, GLfloat* params = 0x%0.8p)", index, pname, params); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -3490,6 +3989,9 @@ void __stdcall glGetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params) params[i] = attribState.mCurrentValue[i]; } break; + case GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE: + *params = (GLfloat)attribState.mDivisor; + break; default: return error(GL_INVALID_ENUM); } } @@ -3502,11 +4004,11 @@ void __stdcall glGetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params) void __stdcall glGetVertexAttribiv(GLuint index, GLenum pname, GLint* params) { - TRACE("(GLuint index = %d, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", index, pname, params); + EVENT("(GLuint index = %d, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", index, pname, params); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -3544,6 +4046,9 @@ void __stdcall glGetVertexAttribiv(GLuint index, GLenum pname, GLint* params) params[i] = (GLint)(currentValue > 0.0f ? floor(currentValue + 0.5f) : ceil(currentValue - 0.5f)); } break; + case GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE: + *params = (GLint)attribState.mDivisor; + break; default: return error(GL_INVALID_ENUM); } } @@ -3556,11 +4061,11 @@ void __stdcall glGetVertexAttribiv(GLuint index, GLenum pname, GLint* params) void __stdcall glGetVertexAttribPointerv(GLuint index, GLenum pname, GLvoid** pointer) { - TRACE("(GLuint index = %d, GLenum pname = 0x%X, GLvoid** pointer = 0x%0.8p)", index, pname, pointer); + EVENT("(GLuint index = %d, GLenum pname = 0x%X, GLvoid** pointer = 0x%0.8p)", index, pname, pointer); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -3585,7 +4090,7 @@ void __stdcall glGetVertexAttribPointerv(GLuint index, GLenum pname, GLvoid** po void __stdcall glHint(GLenum target, GLenum mode) { - TRACE("(GLenum target = 0x%X, GLenum mode = 0x%X)", target, mode); + EVENT("(GLenum target = 0x%X, GLenum mode = 0x%X)", target, mode); try { @@ -3599,7 +4104,7 @@ void __stdcall glHint(GLenum target, GLenum mode) return error(GL_INVALID_ENUM); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); switch (target) { case GL_GENERATE_MIPMAP_HINT: @@ -3620,11 +4125,11 @@ void __stdcall glHint(GLenum target, GLenum mode) GLboolean __stdcall glIsBuffer(GLuint buffer) { - TRACE("(GLuint buffer = %d)", buffer); + EVENT("(GLuint buffer = %d)", buffer); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context && buffer) { @@ -3646,11 +4151,11 @@ GLboolean __stdcall glIsBuffer(GLuint buffer) GLboolean __stdcall glIsEnabled(GLenum cap) { - TRACE("(GLenum cap = 0x%X)", cap); + EVENT("(GLenum cap = 0x%X)", cap); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -3680,11 +4185,11 @@ GLboolean __stdcall glIsEnabled(GLenum cap) GLboolean __stdcall glIsFenceNV(GLuint fence) { - TRACE("(GLuint fence = %d)", fence); + EVENT("(GLuint fence = %d)", fence); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -3708,11 +4213,11 @@ GLboolean __stdcall glIsFenceNV(GLuint fence) GLboolean __stdcall glIsFramebuffer(GLuint framebuffer) { - TRACE("(GLuint framebuffer = %d)", framebuffer); + EVENT("(GLuint framebuffer = %d)", framebuffer); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context && framebuffer) { @@ -3734,11 +4239,11 @@ GLboolean __stdcall glIsFramebuffer(GLuint framebuffer) GLboolean __stdcall glIsProgram(GLuint program) { - TRACE("(GLuint program = %d)", program); + EVENT("(GLuint program = %d)", program); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context && program) { @@ -3758,13 +4263,44 @@ GLboolean __stdcall glIsProgram(GLuint program) return GL_FALSE; } +GLboolean __stdcall glIsQueryEXT(GLuint id) +{ + EVENT("(GLuint id = %d)", id); + + try + { + if (id == 0) + { + return GL_FALSE; + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::Query *queryObject = context->getQuery(id, false, GL_NONE); + + if (queryObject) + { + return GL_TRUE; + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY, GL_FALSE); + } + + return GL_FALSE; +} + GLboolean __stdcall glIsRenderbuffer(GLuint renderbuffer) { - TRACE("(GLuint renderbuffer = %d)", renderbuffer); + EVENT("(GLuint renderbuffer = %d)", renderbuffer); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context && renderbuffer) { @@ -3786,11 +4322,11 @@ GLboolean __stdcall glIsRenderbuffer(GLuint renderbuffer) GLboolean __stdcall glIsShader(GLuint shader) { - TRACE("(GLuint shader = %d)", shader); + EVENT("(GLuint shader = %d)", shader); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context && shader) { @@ -3812,11 +4348,11 @@ GLboolean __stdcall glIsShader(GLuint shader) GLboolean __stdcall glIsTexture(GLuint texture) { - TRACE("(GLuint texture = %d)", texture); + EVENT("(GLuint texture = %d)", texture); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context && texture) { @@ -3838,7 +4374,7 @@ GLboolean __stdcall glIsTexture(GLuint texture) void __stdcall glLineWidth(GLfloat width) { - TRACE("(GLfloat width = %f)", width); + EVENT("(GLfloat width = %f)", width); try { @@ -3847,7 +4383,7 @@ void __stdcall glLineWidth(GLfloat width) return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -3862,11 +4398,11 @@ void __stdcall glLineWidth(GLfloat width) void __stdcall glLinkProgram(GLuint program) { - TRACE("(GLuint program = %d)", program); + EVENT("(GLuint program = %d)", program); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -3895,11 +4431,11 @@ void __stdcall glLinkProgram(GLuint program) void __stdcall glPixelStorei(GLenum pname, GLint param) { - TRACE("(GLenum pname = 0x%X, GLint param = %d)", pname, param); + EVENT("(GLenum pname = 0x%X, GLint param = %d)", pname, param); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -3923,6 +4459,10 @@ void __stdcall glPixelStorei(GLenum pname, GLint param) context->setPackAlignment(param); break; + case GL_PACK_REVERSE_ROW_ORDER_ANGLE: + context->setPackReverseRowOrder(param != 0); + break; + default: return error(GL_INVALID_ENUM); } @@ -3936,11 +4476,11 @@ void __stdcall glPixelStorei(GLenum pname, GLint param) void __stdcall glPolygonOffset(GLfloat factor, GLfloat units) { - TRACE("(GLfloat factor = %f, GLfloat units = %f)", factor, units); + EVENT("(GLfloat factor = %f, GLfloat units = %f)", factor, units); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -3953,9 +4493,43 @@ void __stdcall glPolygonOffset(GLfloat factor, GLfloat units) } } -void __stdcall glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels) +void __stdcall glReadnPixelsEXT(GLint x, GLint y, GLsizei width, GLsizei height, + GLenum format, GLenum type, GLsizei bufSize, + GLvoid *data) +{ + EVENT("(GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d, " + "GLenum format = 0x%X, GLenum type = 0x%X, GLsizei bufSize = 0x%d, GLvoid *data = 0x%0.8p)", + x, y, width, height, format, type, bufSize, data); + + try + { + if (width < 0 || height < 0 || bufSize < 0) + { + return error(GL_INVALID_VALUE); + } + + if (!validReadFormatType(format, type)) + { + return error(GL_INVALID_OPERATION); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + context->readPixels(x, y, width, height, format, type, &bufSize, data); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, + GLenum format, GLenum type, GLvoid* pixels) { - TRACE("(GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d, " + EVENT("(GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d, " "GLenum format = 0x%X, GLenum type = 0x%X, GLvoid* pixels = 0x%0.8p)", x, y, width, height, format, type, pixels); @@ -3966,46 +4540,16 @@ void __stdcall glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLe return error(GL_INVALID_VALUE); } - switch (format) + if (!validReadFormatType(format, type)) { - case GL_RGBA: - switch (type) - { - case GL_UNSIGNED_BYTE: - break; - default: - return error(GL_INVALID_OPERATION); - } - break; - case GL_BGRA_EXT: - switch (type) - { - case GL_UNSIGNED_BYTE: - case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT: - case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT: - break; - default: - return error(GL_INVALID_OPERATION); - } - break; - case gl::IMPLEMENTATION_COLOR_READ_FORMAT: - switch (type) - { - case gl::IMPLEMENTATION_COLOR_READ_TYPE: - break; - default: - return error(GL_INVALID_OPERATION); - } - break; - default: return error(GL_INVALID_OPERATION); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { - context->readPixels(x, y, width, height, format, type, pixels); + context->readPixels(x, y, width, height, format, type, NULL, pixels); } } catch(std::bad_alloc&) @@ -4016,7 +4560,7 @@ void __stdcall glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLe void __stdcall glReleaseShaderCompiler(void) { - TRACE("()"); + EVENT("()"); try { @@ -4030,7 +4574,7 @@ void __stdcall glReleaseShaderCompiler(void) void __stdcall glRenderbufferStorageMultisampleANGLE(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) { - TRACE("(GLenum target = 0x%X, GLsizei samples = %d, GLenum internalformat = 0x%X, GLsizei width = %d, GLsizei height = %d)", + EVENT("(GLenum target = 0x%X, GLsizei samples = %d, GLenum internalformat = 0x%X, GLsizei width = %d, GLsizei height = %d)", target, samples, internalformat, width, height); try @@ -4053,7 +4597,7 @@ void __stdcall glRenderbufferStorageMultisampleANGLE(GLenum target, GLsizei samp return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -4106,11 +4650,11 @@ void __stdcall glRenderbufferStorage(GLenum target, GLenum internalformat, GLsiz void __stdcall glSampleCoverage(GLclampf value, GLboolean invert) { - TRACE("(GLclampf value = %f, GLboolean invert = %d)", value, invert); + EVENT("(GLclampf value = %f, GLboolean invert = %d)", value, invert); try { - gl::Context* context = gl::getContext(); + gl::Context* context = gl::getNonLostContext(); if (context) { @@ -4125,7 +4669,7 @@ void __stdcall glSampleCoverage(GLclampf value, GLboolean invert) void __stdcall glSetFenceNV(GLuint fence, GLenum condition) { - TRACE("(GLuint fence = %d, GLenum condition = 0x%X)", fence, condition); + EVENT("(GLuint fence = %d, GLenum condition = 0x%X)", fence, condition); try { @@ -4134,7 +4678,7 @@ void __stdcall glSetFenceNV(GLuint fence, GLenum condition) return error(GL_INVALID_ENUM); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -4156,7 +4700,7 @@ void __stdcall glSetFenceNV(GLuint fence, GLenum condition) void __stdcall glScissor(GLint x, GLint y, GLsizei width, GLsizei height) { - TRACE("(GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d)", x, y, width, height); + EVENT("(GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d)", x, y, width, height); try { @@ -4165,7 +4709,7 @@ void __stdcall glScissor(GLint x, GLint y, GLsizei width, GLsizei height) return error(GL_INVALID_VALUE); } - gl::Context* context = gl::getContext(); + gl::Context* context = gl::getNonLostContext(); if (context) { @@ -4180,7 +4724,7 @@ void __stdcall glScissor(GLint x, GLint y, GLsizei width, GLsizei height) void __stdcall glShaderBinary(GLsizei n, const GLuint* shaders, GLenum binaryformat, const GLvoid* binary, GLsizei length) { - TRACE("(GLsizei n = %d, const GLuint* shaders = 0x%0.8p, GLenum binaryformat = 0x%X, " + EVENT("(GLsizei n = %d, const GLuint* shaders = 0x%0.8p, GLenum binaryformat = 0x%X, " "const GLvoid* binary = 0x%0.8p, GLsizei length = %d)", n, shaders, binaryformat, binary, length); @@ -4197,7 +4741,7 @@ void __stdcall glShaderBinary(GLsizei n, const GLuint* shaders, GLenum binaryfor void __stdcall glShaderSource(GLuint shader, GLsizei count, const GLchar** string, const GLint* length) { - TRACE("(GLuint shader = %d, GLsizei count = %d, const GLchar** string = 0x%0.8p, const GLint* length = 0x%0.8p)", + EVENT("(GLuint shader = %d, GLsizei count = %d, const GLchar** string = 0x%0.8p, const GLint* length = 0x%0.8p)", shader, count, string, length); try @@ -4207,7 +4751,7 @@ void __stdcall glShaderSource(GLuint shader, GLsizei count, const GLchar** strin return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -4241,7 +4785,7 @@ void __stdcall glStencilFunc(GLenum func, GLint ref, GLuint mask) void __stdcall glStencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask) { - TRACE("(GLenum face = 0x%X, GLenum func = 0x%X, GLint ref = %d, GLuint mask = %d)", face, func, ref, mask); + EVENT("(GLenum face = 0x%X, GLenum func = 0x%X, GLint ref = %d, GLuint mask = %d)", face, func, ref, mask); try { @@ -4270,7 +4814,7 @@ void __stdcall glStencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint return error(GL_INVALID_ENUM); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -4298,7 +4842,7 @@ void __stdcall glStencilMask(GLuint mask) void __stdcall glStencilMaskSeparate(GLenum face, GLuint mask) { - TRACE("(GLenum face = 0x%X, GLuint mask = %d)", face, mask); + EVENT("(GLenum face = 0x%X, GLuint mask = %d)", face, mask); try { @@ -4312,7 +4856,7 @@ void __stdcall glStencilMaskSeparate(GLenum face, GLuint mask) return error(GL_INVALID_ENUM); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -4340,7 +4884,7 @@ void __stdcall glStencilOp(GLenum fail, GLenum zfail, GLenum zpass) void __stdcall glStencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass) { - TRACE("(GLenum face = 0x%X, GLenum fail = 0x%X, GLenum zfail = 0x%X, GLenum zpas = 0x%Xs)", + EVENT("(GLenum face = 0x%X, GLenum fail = 0x%X, GLenum zfail = 0x%X, GLenum zpas = 0x%Xs)", face, fail, zfail, zpass); try @@ -4400,7 +4944,7 @@ void __stdcall glStencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenu return error(GL_INVALID_ENUM); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -4423,11 +4967,11 @@ void __stdcall glStencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenu GLboolean __stdcall glTestFenceNV(GLuint fence) { - TRACE("(GLuint fence = %d)", fence); + EVENT("(GLuint fence = %d)", fence); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -4452,28 +4996,23 @@ GLboolean __stdcall glTestFenceNV(GLuint fence) void __stdcall glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels) { - TRACE("(GLenum target = 0x%X, GLint level = %d, GLint internalformat = %d, GLsizei width = %d, GLsizei height = %d, " + EVENT("(GLenum target = 0x%X, GLint level = %d, GLint internalformat = %d, GLsizei width = %d, GLsizei height = %d, " "GLint border = %d, GLenum format = 0x%X, GLenum type = 0x%X, const GLvoid* pixels = 0x%0.8p)", target, level, internalformat, width, height, border, format, type, pixels); try { - if (level < 0 || width < 0 || height < 0) - { - return error(GL_INVALID_VALUE); - } - - if (level > 0 && (!gl::isPow2(width) || !gl::isPow2(height))) + if (!validImageSize(level, width, height)) { return error(GL_INVALID_VALUE); } - if (internalformat != format) + if (internalformat != GLint(format)) { return error(GL_INVALID_OPERATION); } - switch (internalformat) + switch (format) { case GL_ALPHA: case GL_LUMINANCE: @@ -4524,6 +5063,8 @@ void __stdcall glTexImage2D(GLenum target, GLint level, GLint internalformat, GL break; case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: // error cases for compressed textures are handled below case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: + case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: break; default: return error(GL_INVALID_VALUE); @@ -4534,10 +5075,15 @@ void __stdcall glTexImage2D(GLenum target, GLint level, GLint internalformat, GL return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { + if (level > context->getMaximumTextureLevel()) + { + return error(GL_INVALID_VALUE); + } + switch (target) { case GL_TEXTURE_2D: @@ -4568,10 +5114,30 @@ void __stdcall glTexImage2D(GLenum target, GLint level, GLint internalformat, GL return error(GL_INVALID_ENUM); } - if (internalformat == GL_COMPRESSED_RGB_S3TC_DXT1_EXT || - internalformat == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) - { - if (context->supportsCompressedTextures()) + switch (format) { + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + if (context->supportsDXT1Textures()) + { + return error(GL_INVALID_OPERATION); + } + else + { + return error(GL_INVALID_ENUM); + } + break; + case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: + if (context->supportsDXT3Textures()) + { + return error(GL_INVALID_OPERATION); + } + else + { + return error(GL_INVALID_ENUM); + } + break; + case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: + if (context->supportsDXT5Textures()) { return error(GL_INVALID_OPERATION); } @@ -4579,18 +5145,21 @@ void __stdcall glTexImage2D(GLenum target, GLint level, GLint internalformat, GL { return error(GL_INVALID_ENUM); } + break; + default: + break; } if (type == GL_FLOAT) { - if (!context->supportsFloatTextures()) + if (!context->supportsFloat32Textures()) { return error(GL_INVALID_ENUM); } } else if (type == GL_HALF_FLOAT_OES) { - if (!context->supportsHalfFloatTextures()) + if (!context->supportsFloat16Textures()) { return error(GL_INVALID_ENUM); } @@ -4605,7 +5174,12 @@ void __stdcall glTexImage2D(GLenum target, GLint level, GLint internalformat, GL return error(GL_INVALID_OPERATION); } - texture->setImage(level, internalformat, width, height, format, type, context->getUnpackAlignment(), pixels); + if (texture->isImmutable()) + { + return error(GL_INVALID_OPERATION); + } + + texture->setImage(level, width, height, format, type, context->getUnpackAlignment(), pixels); } else { @@ -4616,25 +5190,30 @@ void __stdcall glTexImage2D(GLenum target, GLint level, GLint internalformat, GL return error(GL_INVALID_OPERATION); } + if (texture->isImmutable()) + { + return error(GL_INVALID_OPERATION); + } + switch (target) { case GL_TEXTURE_CUBE_MAP_POSITIVE_X: - texture->setImagePosX(level, internalformat, width, height, format, type, context->getUnpackAlignment(), pixels); + texture->setImagePosX(level, width, height, format, type, context->getUnpackAlignment(), pixels); break; case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: - texture->setImageNegX(level, internalformat, width, height, format, type, context->getUnpackAlignment(), pixels); + texture->setImageNegX(level, width, height, format, type, context->getUnpackAlignment(), pixels); break; case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: - texture->setImagePosY(level, internalformat, width, height, format, type, context->getUnpackAlignment(), pixels); + texture->setImagePosY(level, width, height, format, type, context->getUnpackAlignment(), pixels); break; case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: - texture->setImageNegY(level, internalformat, width, height, format, type, context->getUnpackAlignment(), pixels); + texture->setImageNegY(level, width, height, format, type, context->getUnpackAlignment(), pixels); break; case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: - texture->setImagePosZ(level, internalformat, width, height, format, type, context->getUnpackAlignment(), pixels); + texture->setImagePosZ(level, width, height, format, type, context->getUnpackAlignment(), pixels); break; case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: - texture->setImageNegZ(level, internalformat, width, height, format, type, context->getUnpackAlignment(), pixels); + texture->setImageNegZ(level, width, height, format, type, context->getUnpackAlignment(), pixels); break; default: UNREACHABLE(); } @@ -4659,11 +5238,11 @@ void __stdcall glTexParameterfv(GLenum target, GLenum pname, const GLfloat* para void __stdcall glTexParameteri(GLenum target, GLenum pname, GLint param) { - TRACE("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint param = %d)", target, pname, param); + EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint param = %d)", target, pname, param); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -4707,6 +5286,12 @@ void __stdcall glTexParameteri(GLenum target, GLenum pname, GLint param) return error(GL_INVALID_ENUM); } break; + case GL_TEXTURE_USAGE_ANGLE: + if (!texture->setUsage((GLenum)param)) + { + return error(GL_INVALID_ENUM); + } + break; default: return error(GL_INVALID_ENUM); } @@ -4723,106 +5308,231 @@ void __stdcall glTexParameteriv(GLenum target, GLenum pname, const GLint* params glTexParameteri(target, pname, *params); } -void __stdcall glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - GLenum format, GLenum type, const GLvoid* pixels) +void __stdcall glTexStorage2DEXT(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) { - TRACE("(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, " - "GLsizei width = %d, GLsizei height = %d, GLenum format = 0x%X, GLenum type = 0x%X, " - "const GLvoid* pixels = 0x%0.8p)", - target, level, xoffset, yoffset, width, height, format, type, pixels); + EVENT("(GLenum target = 0x%X, GLsizei levels = %d, GLenum internalformat = 0x%X, GLsizei width = %d, GLsizei height = %d)", + target, levels, internalformat, width, height); try { - if (!gl::IsTextureTarget(target)) + if (target != GL_TEXTURE_2D && target != GL_TEXTURE_CUBE_MAP) { return error(GL_INVALID_ENUM); } - if (level < 0 || xoffset < 0 || yoffset < 0 || width < 0 || height < 0) + if (width < 1 || height < 1 || levels < 1) { return error(GL_INVALID_VALUE); } - if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height) + if (target == GL_TEXTURE_CUBE_MAP && width != height) { return error(GL_INVALID_VALUE); } - if (!gl::CheckTextureFormatType(format, type)) + if (levels != 1 && levels != gl::log2(std::max(width, height)) + 1) { - return error(GL_INVALID_ENUM); + return error(GL_INVALID_OPERATION); } - if (width == 0 || height == 0 || pixels == NULL) + GLenum format = gl::ExtractFormat(internalformat); + GLenum type = gl::ExtractType(internalformat); + + if (format == GL_NONE || type == GL_NONE) { - return; + return error(GL_INVALID_ENUM); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { - if (level > context->getMaximumTextureLevel()) + switch (target) { - return error(GL_INVALID_VALUE); + case GL_TEXTURE_2D: + if (width > context->getMaximumTextureDimension() || + height > context->getMaximumTextureDimension()) + { + return error(GL_INVALID_VALUE); + } + break; + case GL_TEXTURE_CUBE_MAP: + if (width > context->getMaximumCubeTextureDimension() || + height > context->getMaximumCubeTextureDimension()) + { + return error(GL_INVALID_VALUE); + } + break; + default: + return error(GL_INVALID_ENUM); } - if (format == GL_FLOAT) + if (levels != 1 && !context->supportsNonPower2Texture()) { - if (!context->supportsFloatTextures()) + if (!gl::isPow2(width) || !gl::isPow2(height)) { - return error(GL_INVALID_ENUM); + return error(GL_INVALID_OPERATION); } } - else if (format == GL_HALF_FLOAT_OES) + + switch (internalformat) { - if (!context->supportsHalfFloatTextures()) + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + if (!context->supportsDXT1Textures()) + { + return error(GL_INVALID_ENUM); + } + break; + case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: + if (!context->supportsDXT3Textures()) + { + return error(GL_INVALID_ENUM); + } + break; + case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: + if (!context->supportsDXT5Textures()) + { + return error(GL_INVALID_ENUM); + } + break; + case GL_RGBA32F_EXT: + case GL_RGB32F_EXT: + case GL_ALPHA32F_EXT: + case GL_LUMINANCE32F_EXT: + case GL_LUMINANCE_ALPHA32F_EXT: + if (!context->supportsFloat32Textures()) + { + return error(GL_INVALID_ENUM); + } + break; + case GL_RGBA16F_EXT: + case GL_RGB16F_EXT: + case GL_ALPHA16F_EXT: + case GL_LUMINANCE16F_EXT: + case GL_LUMINANCE_ALPHA16F_EXT: + if (!context->supportsFloat16Textures()) { return error(GL_INVALID_ENUM); } + break; } if (target == GL_TEXTURE_2D) { gl::Texture2D *texture = context->getTexture2D(); - if (!texture) - { - return error(GL_INVALID_OPERATION); - } - - if (texture->isCompressed()) + if (!texture || texture->id() == 0) { return error(GL_INVALID_OPERATION); } - if (format != texture->getFormat()) + if (texture->isImmutable()) { return error(GL_INVALID_OPERATION); } - texture->subImage(level, xoffset, yoffset, width, height, format, type, context->getUnpackAlignment(), pixels); + texture->storage(levels, internalformat, width, height); } - else if (gl::IsCubemapTextureTarget(target)) + else if (target == GL_TEXTURE_CUBE_MAP) { gl::TextureCubeMap *texture = context->getTextureCubeMap(); - if (!texture) + if (!texture || texture->id() == 0) { return error(GL_INVALID_OPERATION); } - if (texture->isCompressed()) + if (texture->isImmutable()) { return error(GL_INVALID_OPERATION); } - if (format != texture->getFormat()) + texture->storage(levels, internalformat, width); + } + else UNREACHABLE(); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + GLenum format, GLenum type, const GLvoid* pixels) +{ + EVENT("(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, " + "GLsizei width = %d, GLsizei height = %d, GLenum format = 0x%X, GLenum type = 0x%X, " + "const GLvoid* pixels = 0x%0.8p)", + target, level, xoffset, yoffset, width, height, format, type, pixels); + + try + { + if (!gl::IsInternalTextureTarget(target)) + { + return error(GL_INVALID_ENUM); + } + + if (level < 0 || xoffset < 0 || yoffset < 0 || width < 0 || height < 0) + { + return error(GL_INVALID_VALUE); + } + + if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height) + { + return error(GL_INVALID_VALUE); + } + + if (!gl::CheckTextureFormatType(format, type)) + { + return error(GL_INVALID_ENUM); + } + + if (width == 0 || height == 0 || pixels == NULL) + { + return; + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (level > context->getMaximumTextureLevel()) + { + return error(GL_INVALID_VALUE); + } + + if (format == GL_FLOAT) + { + if (!context->supportsFloat32Textures()) { - return error(GL_INVALID_OPERATION); + return error(GL_INVALID_ENUM); } + } + else if (format == GL_HALF_FLOAT_OES) + { + if (!context->supportsFloat16Textures()) + { + return error(GL_INVALID_ENUM); + } + } - texture->subImage(target, level, xoffset, yoffset, width, height, format, type, context->getUnpackAlignment(), pixels); + if (target == GL_TEXTURE_2D) + { + gl::Texture2D *texture = context->getTexture2D(); + if (validateSubImageParams(false, width, height, xoffset, yoffset, level, format, texture)) + { + texture->subImage(level, xoffset, yoffset, width, height, format, type, context->getUnpackAlignment(), pixels); + } + } + else if (gl::IsCubemapTextureTarget(target)) + { + gl::TextureCubeMap *texture = context->getTextureCubeMap(); + if (validateSubImageParams(false, width, height, xoffset, yoffset, level, format, texture)) + { + texture->subImage(target, level, xoffset, yoffset, width, height, format, type, context->getUnpackAlignment(), pixels); + } } else { @@ -4843,7 +5553,7 @@ void __stdcall glUniform1f(GLint location, GLfloat x) void __stdcall glUniform1fv(GLint location, GLsizei count, const GLfloat* v) { - TRACE("(GLint location = %d, GLsizei count = %d, const GLfloat* v = 0x%0.8p)", location, count, v); + EVENT("(GLint location = %d, GLsizei count = %d, const GLfloat* v = 0x%0.8p)", location, count, v); try { @@ -4857,7 +5567,7 @@ void __stdcall glUniform1fv(GLint location, GLsizei count, const GLfloat* v) return; } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -4887,7 +5597,7 @@ void __stdcall glUniform1i(GLint location, GLint x) void __stdcall glUniform1iv(GLint location, GLsizei count, const GLint* v) { - TRACE("(GLint location = %d, GLsizei count = %d, const GLint* v = 0x%0.8p)", location, count, v); + EVENT("(GLint location = %d, GLsizei count = %d, const GLint* v = 0x%0.8p)", location, count, v); try { @@ -4901,7 +5611,7 @@ void __stdcall glUniform1iv(GLint location, GLsizei count, const GLint* v) return; } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -4933,7 +5643,7 @@ void __stdcall glUniform2f(GLint location, GLfloat x, GLfloat y) void __stdcall glUniform2fv(GLint location, GLsizei count, const GLfloat* v) { - TRACE("(GLint location = %d, GLsizei count = %d, const GLfloat* v = 0x%0.8p)", location, count, v); + EVENT("(GLint location = %d, GLsizei count = %d, const GLfloat* v = 0x%0.8p)", location, count, v); try { @@ -4947,7 +5657,7 @@ void __stdcall glUniform2fv(GLint location, GLsizei count, const GLfloat* v) return; } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -4979,7 +5689,7 @@ void __stdcall glUniform2i(GLint location, GLint x, GLint y) void __stdcall glUniform2iv(GLint location, GLsizei count, const GLint* v) { - TRACE("(GLint location = %d, GLsizei count = %d, const GLint* v = 0x%0.8p)", location, count, v); + EVENT("(GLint location = %d, GLsizei count = %d, const GLint* v = 0x%0.8p)", location, count, v); try { @@ -4993,7 +5703,7 @@ void __stdcall glUniform2iv(GLint location, GLsizei count, const GLint* v) return; } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -5025,7 +5735,7 @@ void __stdcall glUniform3f(GLint location, GLfloat x, GLfloat y, GLfloat z) void __stdcall glUniform3fv(GLint location, GLsizei count, const GLfloat* v) { - TRACE("(GLint location = %d, GLsizei count = %d, const GLfloat* v = 0x%0.8p)", location, count, v); + EVENT("(GLint location = %d, GLsizei count = %d, const GLfloat* v = 0x%0.8p)", location, count, v); try { @@ -5039,7 +5749,7 @@ void __stdcall glUniform3fv(GLint location, GLsizei count, const GLfloat* v) return; } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -5071,7 +5781,7 @@ void __stdcall glUniform3i(GLint location, GLint x, GLint y, GLint z) void __stdcall glUniform3iv(GLint location, GLsizei count, const GLint* v) { - TRACE("(GLint location = %d, GLsizei count = %d, const GLint* v = 0x%0.8p)", location, count, v); + EVENT("(GLint location = %d, GLsizei count = %d, const GLint* v = 0x%0.8p)", location, count, v); try { @@ -5085,7 +5795,7 @@ void __stdcall glUniform3iv(GLint location, GLsizei count, const GLint* v) return; } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -5117,7 +5827,7 @@ void __stdcall glUniform4f(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfl void __stdcall glUniform4fv(GLint location, GLsizei count, const GLfloat* v) { - TRACE("(GLint location = %d, GLsizei count = %d, const GLfloat* v = 0x%0.8p)", location, count, v); + EVENT("(GLint location = %d, GLsizei count = %d, const GLfloat* v = 0x%0.8p)", location, count, v); try { @@ -5131,7 +5841,7 @@ void __stdcall glUniform4fv(GLint location, GLsizei count, const GLfloat* v) return; } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -5163,7 +5873,7 @@ void __stdcall glUniform4i(GLint location, GLint x, GLint y, GLint z, GLint w) void __stdcall glUniform4iv(GLint location, GLsizei count, const GLint* v) { - TRACE("(GLint location = %d, GLsizei count = %d, const GLint* v = 0x%0.8p)", location, count, v); + EVENT("(GLint location = %d, GLsizei count = %d, const GLint* v = 0x%0.8p)", location, count, v); try { @@ -5177,7 +5887,7 @@ void __stdcall glUniform4iv(GLint location, GLsizei count, const GLint* v) return; } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -5202,7 +5912,7 @@ void __stdcall glUniform4iv(GLint location, GLsizei count, const GLint* v) void __stdcall glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) { - TRACE("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %d, const GLfloat* value = 0x%0.8p)", + EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %d, const GLfloat* value = 0x%0.8p)", location, count, transpose, value); try @@ -5217,7 +5927,7 @@ void __stdcall glUniformMatrix2fv(GLint location, GLsizei count, GLboolean trans return; } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -5242,7 +5952,7 @@ void __stdcall glUniformMatrix2fv(GLint location, GLsizei count, GLboolean trans void __stdcall glUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) { - TRACE("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %d, const GLfloat* value = 0x%0.8p)", + EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %d, const GLfloat* value = 0x%0.8p)", location, count, transpose, value); try @@ -5257,7 +5967,7 @@ void __stdcall glUniformMatrix3fv(GLint location, GLsizei count, GLboolean trans return; } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -5282,7 +5992,7 @@ void __stdcall glUniformMatrix3fv(GLint location, GLsizei count, GLboolean trans void __stdcall glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) { - TRACE("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %d, const GLfloat* value = 0x%0.8p)", + EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %d, const GLfloat* value = 0x%0.8p)", location, count, transpose, value); try @@ -5297,7 +6007,7 @@ void __stdcall glUniformMatrix4fv(GLint location, GLsizei count, GLboolean trans return; } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -5322,11 +6032,11 @@ void __stdcall glUniformMatrix4fv(GLint location, GLsizei count, GLboolean trans void __stdcall glUseProgram(GLuint program) { - TRACE("(GLuint program = %d)", program); + EVENT("(GLuint program = %d)", program); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -5360,11 +6070,11 @@ void __stdcall glUseProgram(GLuint program) void __stdcall glValidateProgram(GLuint program) { - TRACE("(GLuint program = %d)", program); + EVENT("(GLuint program = %d)", program); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -5393,7 +6103,7 @@ void __stdcall glValidateProgram(GLuint program) void __stdcall glVertexAttrib1f(GLuint index, GLfloat x) { - TRACE("(GLuint index = %d, GLfloat x = %f)", index, x); + EVENT("(GLuint index = %d, GLfloat x = %f)", index, x); try { @@ -5402,7 +6112,7 @@ void __stdcall glVertexAttrib1f(GLuint index, GLfloat x) return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -5418,7 +6128,7 @@ void __stdcall glVertexAttrib1f(GLuint index, GLfloat x) void __stdcall glVertexAttrib1fv(GLuint index, const GLfloat* values) { - TRACE("(GLuint index = %d, const GLfloat* values = 0x%0.8p)", index, values); + EVENT("(GLuint index = %d, const GLfloat* values = 0x%0.8p)", index, values); try { @@ -5427,7 +6137,7 @@ void __stdcall glVertexAttrib1fv(GLuint index, const GLfloat* values) return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -5443,7 +6153,7 @@ void __stdcall glVertexAttrib1fv(GLuint index, const GLfloat* values) void __stdcall glVertexAttrib2f(GLuint index, GLfloat x, GLfloat y) { - TRACE("(GLuint index = %d, GLfloat x = %f, GLfloat y = %f)", index, x, y); + EVENT("(GLuint index = %d, GLfloat x = %f, GLfloat y = %f)", index, x, y); try { @@ -5452,7 +6162,7 @@ void __stdcall glVertexAttrib2f(GLuint index, GLfloat x, GLfloat y) return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -5468,7 +6178,7 @@ void __stdcall glVertexAttrib2f(GLuint index, GLfloat x, GLfloat y) void __stdcall glVertexAttrib2fv(GLuint index, const GLfloat* values) { - TRACE("(GLuint index = %d, const GLfloat* values = 0x%0.8p)", index, values); + EVENT("(GLuint index = %d, const GLfloat* values = 0x%0.8p)", index, values); try { @@ -5477,7 +6187,7 @@ void __stdcall glVertexAttrib2fv(GLuint index, const GLfloat* values) return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -5493,7 +6203,7 @@ void __stdcall glVertexAttrib2fv(GLuint index, const GLfloat* values) void __stdcall glVertexAttrib3f(GLuint index, GLfloat x, GLfloat y, GLfloat z) { - TRACE("(GLuint index = %d, GLfloat x = %f, GLfloat y = %f, GLfloat z = %f)", index, x, y, z); + EVENT("(GLuint index = %d, GLfloat x = %f, GLfloat y = %f, GLfloat z = %f)", index, x, y, z); try { @@ -5502,7 +6212,7 @@ void __stdcall glVertexAttrib3f(GLuint index, GLfloat x, GLfloat y, GLfloat z) return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -5518,7 +6228,7 @@ void __stdcall glVertexAttrib3f(GLuint index, GLfloat x, GLfloat y, GLfloat z) void __stdcall glVertexAttrib3fv(GLuint index, const GLfloat* values) { - TRACE("(GLuint index = %d, const GLfloat* values = 0x%0.8p)", index, values); + EVENT("(GLuint index = %d, const GLfloat* values = 0x%0.8p)", index, values); try { @@ -5527,7 +6237,7 @@ void __stdcall glVertexAttrib3fv(GLuint index, const GLfloat* values) return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -5543,7 +6253,7 @@ void __stdcall glVertexAttrib3fv(GLuint index, const GLfloat* values) void __stdcall glVertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) { - TRACE("(GLuint index = %d, GLfloat x = %f, GLfloat y = %f, GLfloat z = %f, GLfloat w = %f)", index, x, y, z, w); + EVENT("(GLuint index = %d, GLfloat x = %f, GLfloat y = %f, GLfloat z = %f, GLfloat w = %f)", index, x, y, z, w); try { @@ -5552,7 +6262,7 @@ void __stdcall glVertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, G return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -5568,7 +6278,7 @@ void __stdcall glVertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, G void __stdcall glVertexAttrib4fv(GLuint index, const GLfloat* values) { - TRACE("(GLuint index = %d, const GLfloat* values = 0x%0.8p)", index, values); + EVENT("(GLuint index = %d, const GLfloat* values = 0x%0.8p)", index, values); try { @@ -5577,7 +6287,7 @@ void __stdcall glVertexAttrib4fv(GLuint index, const GLfloat* values) return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -5590,9 +6300,33 @@ void __stdcall glVertexAttrib4fv(GLuint index, const GLfloat* values) } } +void __stdcall glVertexAttribDivisorANGLE(GLuint index, GLuint divisor) +{ + EVENT("(GLuint index = %d, GLuint divisor = %d)", index, divisor); + + try + { + if (index >= gl::MAX_VERTEX_ATTRIBS) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + context->setVertexAttribDivisor(index, divisor); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + void __stdcall glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr) { - TRACE("(GLuint index = %d, GLint size = %d, GLenum type = 0x%X, " + EVENT("(GLuint index = %d, GLint size = %d, GLenum type = 0x%X, " "GLboolean normalized = %d, GLsizei stride = %d, const GLvoid* ptr = 0x%0.8p)", index, size, type, normalized, stride, ptr); @@ -5626,7 +6360,7 @@ void __stdcall glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLbo return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -5641,7 +6375,7 @@ void __stdcall glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLbo void __stdcall glViewport(GLint x, GLint y, GLsizei width, GLsizei height) { - TRACE("(GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d)", x, y, width, height); + EVENT("(GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d)", x, y, width, height); try { @@ -5650,7 +6384,7 @@ void __stdcall glViewport(GLint x, GLint y, GLsizei width, GLsizei height) return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -5666,7 +6400,7 @@ void __stdcall glViewport(GLint x, GLint y, GLsizei width, GLsizei height) void __stdcall glBlitFramebufferANGLE(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) { - TRACE("(GLint srcX0 = %d, GLint srcY0 = %d, GLint srcX1 = %d, GLint srcY1 = %d, " + EVENT("(GLint srcX0 = %d, GLint srcY0 = %d, GLint srcX1 = %d, GLint srcY1 = %d, " "GLint dstX0 = %d, GLint dstY0 = %d, GLint dstX1 = %d, GLint dstY1 = %d, " "GLbitfield mask = 0x%X, GLenum filter = 0x%X)", srcX0, srcY0, srcX1, srcX1, dstX0, dstY0, dstX1, dstY1, mask, filter); @@ -5692,7 +6426,7 @@ void __stdcall glBlitFramebufferANGLE(GLint srcX0, GLint srcY0, GLint srcX1, GLi return error(GL_INVALID_OPERATION); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -5714,7 +6448,7 @@ void __stdcall glBlitFramebufferANGLE(GLint srcX0, GLint srcY0, GLint srcX1, GLi void __stdcall glTexImage3DOES(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid* pixels) { - TRACE("(GLenum target = 0x%X, GLint level = %d, GLenum internalformat = 0x%X, " + EVENT("(GLenum target = 0x%X, GLint level = %d, GLenum internalformat = 0x%X, " "GLsizei width = %d, GLsizei height = %d, GLsizei depth = %d, GLint border = %d, " "GLenum format = 0x%X, GLenum type = 0x%x, const GLvoid* pixels = 0x%0.8p)", target, level, internalformat, width, height, depth, border, format, type, pixels); @@ -5749,6 +6483,22 @@ __eglMustCastToProperFunctionPointerType __stdcall glGetProcAddress(const char * {"glGetFenceivNV", (__eglMustCastToProperFunctionPointerType)glGetFenceivNV}, {"glFinishFenceNV", (__eglMustCastToProperFunctionPointerType)glFinishFenceNV}, {"glSetFenceNV", (__eglMustCastToProperFunctionPointerType)glSetFenceNV}, + {"glGetTranslatedShaderSourceANGLE", (__eglMustCastToProperFunctionPointerType)glGetTranslatedShaderSourceANGLE}, + {"glTexStorage2DEXT", (__eglMustCastToProperFunctionPointerType)glTexStorage2DEXT}, + {"glGetGraphicsResetStatusEXT", (__eglMustCastToProperFunctionPointerType)glGetGraphicsResetStatusEXT}, + {"glReadnPixelsEXT", (__eglMustCastToProperFunctionPointerType)glReadnPixelsEXT}, + {"glGetnUniformfvEXT", (__eglMustCastToProperFunctionPointerType)glGetnUniformfvEXT}, + {"glGetnUniformivEXT", (__eglMustCastToProperFunctionPointerType)glGetnUniformivEXT}, + {"glGenQueriesEXT", (__eglMustCastToProperFunctionPointerType)glGenQueriesEXT}, + {"glDeleteQueriesEXT", (__eglMustCastToProperFunctionPointerType)glDeleteQueriesEXT}, + {"glIsQueryEXT", (__eglMustCastToProperFunctionPointerType)glIsQueryEXT}, + {"glBeginQueryEXT", (__eglMustCastToProperFunctionPointerType)glBeginQueryEXT}, + {"glEndQueryEXT", (__eglMustCastToProperFunctionPointerType)glEndQueryEXT}, + {"glGetQueryivEXT", (__eglMustCastToProperFunctionPointerType)glGetQueryivEXT}, + {"glGetQueryObjectuivEXT", (__eglMustCastToProperFunctionPointerType)glGetQueryObjectuivEXT}, + {"glVertexAttribDivisorANGLE", (__eglMustCastToProperFunctionPointerType)glVertexAttribDivisorANGLE}, + {"glDrawArraysInstancedANGLE", (__eglMustCastToProperFunctionPointerType)glDrawArraysInstancedANGLE}, + {"glDrawElementsInstancedANGLE", (__eglMustCastToProperFunctionPointerType)glDrawElementsInstancedANGLE}, }; for (int ext = 0; ext < sizeof(glExtensions) / sizeof(Extension); ext++) @@ -5762,4 +6512,38 @@ __eglMustCastToProperFunctionPointerType __stdcall glGetProcAddress(const char * return NULL; } +// Non-public functions used by EGL + +bool __stdcall glBindTexImage(egl::Surface *surface) +{ + EVENT("(egl::Surface* surface = 0x%0.8p)", + surface); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::Texture2D *textureObject = context->getTexture2D(); + + if (textureObject->isImmutable()) + { + return false; + } + + if (textureObject) + { + textureObject->bindTexImage(surface); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY, false); + } + + return true; +} + } diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/libGLESv2.def b/Source/ThirdParty/ANGLE/src/libGLESv2/libGLESv2.def index b2dc23c..ea7769b 100644 --- a/Source/ThirdParty/ANGLE/src/libGLESv2/libGLESv2.def +++ b/Source/ThirdParty/ANGLE/src/libGLESv2/libGLESv2.def @@ -154,10 +154,27 @@ EXPORTS glIsFenceNV @155 glSetFenceNV @156 glTestFenceNV @157 + glGetTranslatedShaderSourceANGLE @159 + glTexStorage2DEXT @160 + glGetGraphicsResetStatusEXT @161 + glReadnPixelsEXT @162 + glGetnUniformfvEXT @163 + glGetnUniformivEXT @164 + glGenQueriesEXT @165 + glDeleteQueriesEXT @166 + glIsQueryEXT @167 + glBeginQueryEXT @168 + glEndQueryEXT @169 + glGetQueryivEXT @170 + glGetQueryObjectuivEXT @171 + glVertexAttribDivisorANGLE @172 + glDrawArraysInstancedANGLE @173 + glDrawElementsInstancedANGLE @174 ; EGL dependencies glCreateContext @144 NONAME glDestroyContext @145 NONAME glMakeCurrent @146 NONAME glGetCurrentContext @147 NONAME - glGetProcAddress @148 NONAME
\ No newline at end of file + glGetProcAddress @148 NONAME + glBindTexImage @158 NONAME diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/libGLESv2.rc b/Source/ThirdParty/ANGLE/src/libGLESv2/libGLESv2.rc new file mode 100644 index 0000000..0ad21e4 --- /dev/null +++ b/Source/ThirdParty/ANGLE/src/libGLESv2/libGLESv2.rc @@ -0,0 +1,102 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include <windows.h> +#include "../common/version.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "#include ""../common/version.h""\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION MAJOR_VERSION,MINOR_VERSION,BUILD_VERSION,BUILD_REVISION + PRODUCTVERSION MAJOR_VERSION,MINOR_VERSION,BUILD_VERSION,BUILD_REVISION + FILEFLAGSMASK 0x17L +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "FileDescription", "ANGLE libGLESv2 Dynamic Link Library" + VALUE "FileVersion", VERSION_STRING + VALUE "InternalName", "libGLESv2" + VALUE "LegalCopyright", "Copyright (C) 2011 Google Inc." + VALUE "OriginalFilename", "libGLESv2.dll" + VALUE "PrivateBuild", VERSION_STRING + VALUE "ProductName", "ANGLE libGLESv2 Dynamic Link Library" + VALUE "ProductVersion", VERSION_STRING + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/libGLESv2.vcproj b/Source/ThirdParty/ANGLE/src/libGLESv2/libGLESv2.vcproj index 0d95080..7d2b649 100644 --- a/Source/ThirdParty/ANGLE/src/libGLESv2/libGLESv2.vcproj +++ b/Source/ThirdParty/ANGLE/src/libGLESv2/libGLESv2.vcproj @@ -12,6 +12,9 @@ <Platform Name="Win32" /> + <Platform + Name="x64" + /> </Platforms> <ToolFiles> </ToolFiles> @@ -47,9 +50,11 @@ BasicRuntimeChecks="3" RuntimeLibrary="1" UsePrecompiledHeader="0" - WarningLevel="3" + WarningLevel="4" + DisableSpecificWarnings="4100;4127;4189;4239;4244;4245;4512;4702" Detect64BitPortabilityProblems="false" DebugInformationFormat="4" + WarnAsError="true" /> <Tool Name="VCManagedResourceCompilerTool" @@ -62,7 +67,7 @@ /> <Tool Name="VCLinkerTool" - AdditionalDependencies="D3dx9.lib" + AdditionalDependencies="d3d9.lib D3dx9.lib d3dcompiler.lib" LinkIncremental="2" ModuleDefinitionFile="libGLESv2.def" GenerateDebugInformation="true" @@ -125,9 +130,11 @@ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBGLESV2_EXPORTS;_CRT_SECURE_NO_DEPRECATE;NOMINMAX;_SECURE_SCL=0" RuntimeLibrary="0" UsePrecompiledHeader="0" - WarningLevel="3" + WarningLevel="4" + DisableSpecificWarnings="4100;4127;4189;4239;4244;4245;4512;4702;4718" Detect64BitPortabilityProblems="false" DebugInformationFormat="3" + WarnAsError="true" /> <Tool Name="VCManagedResourceCompilerTool" @@ -140,7 +147,7 @@ /> <Tool Name="VCLinkerTool" - AdditionalDependencies="D3dx9.lib" + AdditionalDependencies="d3d9.lib D3dx9.lib d3dcompiler.lib" LinkIncremental="1" IgnoreAllDefaultLibraries="false" ModuleDefinitionFile="libGLESv2.def" @@ -175,6 +182,171 @@ CommandLine="@echo on
mkdir "$(ProjectDir)..\..\lib\$(ConfigurationName)\"
copy "$(OutDir)\libGLESv2.dll" "$(ProjectDir)..\..\lib\$(ConfigurationName)\"
copy "$(OutDir)\libGLESv2.lib" "$(ProjectDir)..\..\lib\$(ConfigurationName)\"
@echo off
" /> </Configuration> + <Configuration + Name="Debug|x64" + OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(PlatformName)\$(ConfigurationName)" + ConfigurationType="2" + CharacterSet="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + TargetEnvironment="3" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories="$(ProjectDir)/..; $(ProjectDir)/../../include" + PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBGLESV2_EXPORTS;_CRT_SECURE_NO_DEPRECATE;NOMINMAX" + MinimalRebuild="true" + BasicRuntimeChecks="3" + RuntimeLibrary="1" + UsePrecompiledHeader="0" + WarningLevel="4" + DisableSpecificWarnings="4100;4127;4189;4239;4244;4245;4512;4702;4718" + Detect64BitPortabilityProblems="false" + DebugInformationFormat="3" + WarnAsError="true" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="d3d9.lib D3dx9.lib d3dcompiler.lib" + LinkIncremental="2" + ModuleDefinitionFile="libGLESv2.def" + GenerateDebugInformation="true" + SubSystem="2" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + TargetMachine="17" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + CommandLine="@echo on
mkdir "$(ProjectDir)..\..\lib\$(ConfigurationName)\"
copy "$(OutDir)\libGLESv2.dll" "$(ProjectDir)..\..\lib\$(ConfigurationName)\"
copy "$(OutDir)\libGLESv2.lib" "$(ProjectDir)..\..\lib\$(ConfigurationName)\"
@echo off
" + /> + </Configuration> + <Configuration + Name="Release|x64" + OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(PlatformName)\$(ConfigurationName)" + ConfigurationType="2" + CharacterSet="1" + WholeProgramOptimization="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + TargetEnvironment="3" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + InlineFunctionExpansion="2" + AdditionalIncludeDirectories="$(ProjectDir)/..; $(ProjectDir)/../../include" + PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBGLESV2_EXPORTS;_CRT_SECURE_NO_DEPRECATE;NOMINMAX;_SECURE_SCL=0" + RuntimeLibrary="0" + UsePrecompiledHeader="0" + WarningLevel="4" + DisableSpecificWarnings="4100;4127;4189;4239;4244;4245;4512;4702;4718" + Detect64BitPortabilityProblems="false" + DebugInformationFormat="3" + WarnAsError="true" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="d3d9.lib D3dx9.lib d3dcompiler.lib" + LinkIncremental="1" + IgnoreAllDefaultLibraries="false" + ModuleDefinitionFile="libGLESv2.def" + GenerateDebugInformation="true" + SubSystem="2" + OptimizeReferences="2" + EnableCOMDATFolding="2" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + TargetMachine="17" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + CommandLine="@echo on
mkdir "$(ProjectDir)..\..\lib\$(ConfigurationName)\"
copy "$(OutDir)\libGLESv2.dll" "$(ProjectDir)..\..\lib\$(ConfigurationName)\"
copy "$(OutDir)\libGLESv2.lib" "$(ProjectDir)..\..\lib\$(ConfigurationName)\"
@echo off
" + /> + </Configuration> </Configurations> <References> </References> @@ -209,6 +381,14 @@ > </File> <File + RelativePath=".\HandleAllocator.cpp" + > + </File> + <File + RelativePath=".\IndexDataManager.cpp" + > + </File> + <File RelativePath=".\libGLESv2.cpp" > </File> @@ -221,7 +401,11 @@ > </File> <File - RelativePath=".\RefCountObject.cpp" + RelativePath=".\Query.cpp" + > + </File> + <File + RelativePath="..\common\RefCountObject.cpp" > </File> <File @@ -244,18 +428,10 @@ RelativePath=".\utilities.cpp" > </File> - <Filter - Name="Geometry" + <File + RelativePath=".\VertexDataManager.cpp" > - <File - RelativePath=".\geometry\IndexDataManager.cpp" - > - </File> - <File - RelativePath=".\geometry\VertexDataManager.cpp" - > - </File> - </Filter> + </File> </Filter> <Filter Name="Header Files" @@ -295,6 +471,14 @@ > </File> <File + RelativePath=".\HandleAllocator.h" + > + </File> + <File + RelativePath=".\IndexDataManager.h" + > + </File> + <File RelativePath=".\main.h" > </File> @@ -307,7 +491,11 @@ > </File> <File - RelativePath=".\RefCountObject.h" + RelativePath=".\Query.h" + > + </File> + <File + RelativePath="..\common\RefCountObject.h" > </File> <File @@ -315,6 +503,10 @@ > </File> <File + RelativePath=".\resource.h" + > + </File> + <File RelativePath=".\ResourceManager.h" > </File> @@ -330,27 +522,27 @@ RelativePath=".\utilities.h" > </File> - <Filter - Name="Geometry" - > - <File - RelativePath=".\geometry\IndexDataManager.h" - > - </File> - <File - RelativePath=".\geometry\vertexconversion.h" - > - </File> - <File - RelativePath=".\geometry\VertexDataManager.h" - > - </File> - </Filter> + <File + RelativePath="..\common\version.h" + > + </File> + <File + RelativePath=".\vertexconversion.h" + > + </File> + <File + RelativePath=".\VertexDataManager.h" + > + </File> </Filter> <File RelativePath=".\libGLESv2.def" > </File> + <File + RelativePath=".\libGLESv2.rc" + > + </File> </Files> <Globals> </Globals> diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/main.cpp b/Source/ThirdParty/ANGLE/src/libGLESv2/main.cpp index a99ec44..154d277 100644 --- a/Source/ThirdParty/ANGLE/src/libGLESv2/main.cpp +++ b/Source/ThirdParty/ANGLE/src/libGLESv2/main.cpp @@ -7,6 +7,7 @@ // main.cpp: DLL entry point and management of thread-local data. #include "libGLESv2/main.h" +#include "libGLESv2/utilities.h" #include "common/debug.h" #include "libEGL/Surface.h" @@ -93,6 +94,25 @@ Context *getContext() return current->context; } +Context *getNonLostContext() +{ + Context *context = getContext(); + + if (context) + { + if (context->isContextLost()) + { + error(GL_OUT_OF_MEMORY); + return NULL; + } + else + { + return context; + } + } + return NULL; +} + egl::Display *getDisplay() { Current *current = (Current*)TlsGetValue(currentTLS); @@ -106,6 +126,19 @@ IDirect3DDevice9 *getDevice() return display->getDevice(); } + +bool checkDeviceLost(HRESULT errorCode) +{ + egl::Display *display = NULL; + + if (isDeviceLostError(errorCode)) + { + display = gl::getDisplay(); + display->notifyDeviceLost(); + return true; + } + return false; +} } // Records an error code @@ -119,23 +152,23 @@ void error(GLenum errorCode) { case GL_INVALID_ENUM: context->recordInvalidEnum(); - gl::trace("\t! Error generated: invalid enum\n"); + TRACE("\t! Error generated: invalid enum\n"); break; case GL_INVALID_VALUE: context->recordInvalidValue(); - gl::trace("\t! Error generated: invalid value\n"); + TRACE("\t! Error generated: invalid value\n"); break; case GL_INVALID_OPERATION: context->recordInvalidOperation(); - gl::trace("\t! Error generated: invalid operation\n"); + TRACE("\t! Error generated: invalid operation\n"); break; case GL_OUT_OF_MEMORY: context->recordOutOfMemory(); - gl::trace("\t! Error generated: out of memory\n"); + TRACE("\t! Error generated: out of memory\n"); break; case GL_INVALID_FRAMEBUFFER_OPERATION: context->recordInvalidFramebufferOperation(); - gl::trace("\t! Error generated: invalid framebuffer operation\n"); + TRACE("\t! Error generated: invalid framebuffer operation\n"); break; default: UNREACHABLE(); } diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/main.h b/Source/ThirdParty/ANGLE/src/libGLESv2/main.h index 7f9c880..504848a 100644 --- a/Source/ThirdParty/ANGLE/src/libGLESv2/main.h +++ b/Source/ThirdParty/ANGLE/src/libGLESv2/main.h @@ -29,9 +29,12 @@ struct Current void makeCurrent(Context *context, egl::Display *display, egl::Surface *surface); Context *getContext(); +Context *getNonLostContext(); egl::Display *getDisplay(); IDirect3DDevice9 *getDevice(); + +bool checkDeviceLost(HRESULT errorCode); } void error(GLenum errorCode); diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/mathutil.h b/Source/ThirdParty/ANGLE/src/libGLESv2/mathutil.h index 31fa16f..7ca2d9f 100644 --- a/Source/ThirdParty/ANGLE/src/libGLESv2/mathutil.h +++ b/Source/ThirdParty/ANGLE/src/libGLESv2/mathutil.h @@ -9,7 +9,9 @@ #ifndef LIBGLESV2_MATHUTIL_H_ #define LIBGLESV2_MATHUTIL_H_ +#include <intrin.h> #include <math.h> +#include <windows.h> namespace gl { @@ -38,9 +40,15 @@ inline unsigned int ceilPow2(unsigned int x) return x; } +template<typename T, typename MIN, typename MAX> +inline T clamp(T x, MIN min, MAX max) +{ + return x < min ? min : (x > max ? max : x); +} + inline float clamp01(float x) { - return x < 0 ? 0 : (x > 1 ? 1 : x); + return clamp(x, 0.0f, 1.0f); } template<const int n> @@ -61,6 +69,51 @@ inline unsigned int unorm(float x) return (unsigned int)(max * x + 0.5f); } } + +inline RECT transformPixelRect(GLint x, GLint y, GLint w, GLint h, GLint surfaceHeight) +{ + RECT rect = {x, + surfaceHeight - y - h, + x + w, + surfaceHeight - y}; + return rect; +} + +inline int transformPixelYOffset(GLint yoffset, GLint h, GLint surfaceHeight) +{ + return surfaceHeight - yoffset - h; +} + +inline GLenum adjustWinding(GLenum winding) +{ + ASSERT(winding == GL_CW || winding == GL_CCW); + return winding == GL_CW ? GL_CCW : GL_CW; +} + +inline bool supportsSSE2() +{ + static bool checked = false; + static bool supports = false; + + if (checked) + { + return supports; + } + + int info[4]; + __cpuid(info, 0); + + if (info[0] >= 1) + { + __cpuid(info, 1); + + supports = (info[3] >> 26) & 1; + } + + checked = true; + + return supports; +} } #endif // LIBGLESV2_MATHUTIL_H_ diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/resource.h b/Source/ThirdParty/ANGLE/src/libGLESv2/resource.h new file mode 100644 index 0000000..39adaad --- /dev/null +++ b/Source/ThirdParty/ANGLE/src/libGLESv2/resource.h @@ -0,0 +1,14 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by libGLESv2.rc + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/utilities.cpp b/Source/ThirdParty/ANGLE/src/libGLESv2/utilities.cpp index a3f5243..6589eb1 100644 --- a/Source/ThirdParty/ANGLE/src/libGLESv2/utilities.cpp +++ b/Source/ThirdParty/ANGLE/src/libGLESv2/utilities.cpp @@ -9,6 +9,8 @@ #include "libGLESv2/utilities.h" #include <limits> +#include <stdio.h> +#include <windows.h> #include "common/debug.h" @@ -18,7 +20,8 @@ namespace gl { -int UniformComponentCount(GLenum type) +// This is how much data the application expects for a uniform +int UniformExternalComponentCount(GLenum type) { switch (type) { @@ -52,6 +55,42 @@ int UniformComponentCount(GLenum type) return 0; } +// This is how much data we actually store for a uniform +int UniformInternalComponentCount(GLenum type) +{ + switch (type) + { + case GL_BOOL: + case GL_INT: + case GL_SAMPLER_2D: + case GL_SAMPLER_CUBE: + return 1; + case GL_BOOL_VEC2: + case GL_INT_VEC2: + return 2; + case GL_INT_VEC3: + case GL_BOOL_VEC3: + return 3; + case GL_FLOAT: + case GL_FLOAT_VEC2: + case GL_FLOAT_VEC3: + case GL_BOOL_VEC4: + case GL_FLOAT_VEC4: + case GL_INT_VEC4: + return 4; + case GL_FLOAT_MAT2: + return 8; + case GL_FLOAT_MAT3: + return 12; + case GL_FLOAT_MAT4: + return 16; + default: + UNREACHABLE(); + } + + return 0; +} + GLenum UniformComponentType(GLenum type) { switch(type) @@ -83,16 +122,27 @@ GLenum UniformComponentType(GLenum type) return GL_NONE; } -size_t UniformTypeSize(GLenum type) +size_t UniformComponentSize(GLenum type) { switch(type) { - case GL_BOOL: return sizeof(GLboolean); + case GL_BOOL: return sizeof(GLint); case GL_FLOAT: return sizeof(GLfloat); case GL_INT: return sizeof(GLint); + default: UNREACHABLE(); } - return UniformTypeSize(UniformComponentType(type)) * UniformComponentCount(type); + return 0; +} + +size_t UniformInternalSize(GLenum type) +{ + return UniformComponentSize(UniformComponentType(type)) * UniformInternalComponentCount(type); +} + +size_t UniformExternalSize(GLenum type) +{ + return UniformComponentSize(UniformComponentType(type)) * UniformExternalComponentCount(type); } int VariableRowCount(GLenum type) @@ -189,18 +239,7 @@ GLsizei ComputePitch(GLsizei width, GLenum format, GLenum type, GLint alignment) GLsizei ComputeCompressedPitch(GLsizei width, GLenum format) { - switch (format) - { - case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: - case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: - break; - default: - return 0; - } - - ASSERT(width % 4 == 0); - - return 8 * width / 4; + return ComputeCompressedSize(width, 1, format); } GLsizei ComputeCompressedSize(GLsizei width, GLsizei height, GLenum format) @@ -209,18 +248,23 @@ GLsizei ComputeCompressedSize(GLsizei width, GLsizei height, GLenum format) { case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + return 8 * (GLsizei)ceil((float)width / 4.0f) * (GLsizei)ceil((float)height / 4.0f); break; + case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: + case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: + return 16 * (GLsizei)ceil((float)width / 4.0f) * (GLsizei)ceil((float)height / 4.0f); default: return 0; } - return 8 * (GLsizei)ceil((float)width / 4.0f) * (GLsizei)ceil((float)height / 4.0f); } bool IsCompressed(GLenum format) { if(format == GL_COMPRESSED_RGB_S3TC_DXT1_EXT || - format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) + format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT || + format == GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE || + format == GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE) { return true; } @@ -284,7 +328,7 @@ bool IsCubemapTextureTarget(GLenum target) return (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z); } -bool IsTextureTarget(GLenum target) +bool IsInternalTextureTarget(GLenum target) { return target == GL_TEXTURE_2D || IsCubemapTextureTarget(target); } @@ -336,6 +380,68 @@ bool CheckTextureFormatType(GLenum format, GLenum type) } } +GLenum ExtractFormat(GLenum internalformat) +{ + switch (internalformat) + { + case GL_RGB565: return GL_RGB; + case GL_RGBA4: return GL_RGBA; + case GL_RGB5_A1: return GL_RGBA; + case GL_RGB8_OES: return GL_RGB; + case GL_RGBA8_OES: return GL_RGBA; + case GL_LUMINANCE8_ALPHA8_EXT: return GL_LUMINANCE_ALPHA; + case GL_LUMINANCE8_EXT: return GL_LUMINANCE; + case GL_ALPHA8_EXT: return GL_ALPHA; + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: return GL_COMPRESSED_RGB_S3TC_DXT1_EXT; + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: return GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; + case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: return GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE; + case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: return GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE; + case GL_RGBA32F_EXT: return GL_RGBA; + case GL_RGB32F_EXT: return GL_RGB; + case GL_ALPHA32F_EXT: return GL_ALPHA; + case GL_LUMINANCE32F_EXT: return GL_LUMINANCE; + case GL_LUMINANCE_ALPHA32F_EXT: return GL_LUMINANCE_ALPHA; + case GL_RGBA16F_EXT: return GL_RGBA; + case GL_RGB16F_EXT: return GL_RGB; + case GL_ALPHA16F_EXT: return GL_ALPHA; + case GL_LUMINANCE16F_EXT: return GL_LUMINANCE; + case GL_LUMINANCE_ALPHA16F_EXT: return GL_LUMINANCE_ALPHA; + case GL_BGRA8_EXT: return GL_BGRA_EXT; + default: return GL_NONE; // Unsupported + } +} + +GLenum ExtractType(GLenum internalformat) +{ + switch (internalformat) + { + case GL_RGB565: return GL_UNSIGNED_SHORT_5_6_5; + case GL_RGBA4: return GL_UNSIGNED_SHORT_4_4_4_4; + case GL_RGB5_A1: return GL_UNSIGNED_SHORT_5_5_5_1; + case GL_RGB8_OES: return GL_UNSIGNED_BYTE; + case GL_RGBA8_OES: return GL_UNSIGNED_BYTE; + case GL_LUMINANCE8_ALPHA8_EXT: return GL_UNSIGNED_BYTE; + case GL_LUMINANCE8_EXT: return GL_UNSIGNED_BYTE; + case GL_ALPHA8_EXT: return GL_UNSIGNED_BYTE; + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: return GL_UNSIGNED_BYTE; + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: return GL_UNSIGNED_BYTE; + case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: return GL_UNSIGNED_BYTE; + case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: return GL_UNSIGNED_BYTE; + case GL_RGBA32F_EXT: return GL_FLOAT; + case GL_RGB32F_EXT: return GL_FLOAT; + case GL_ALPHA32F_EXT: return GL_FLOAT; + case GL_LUMINANCE32F_EXT: return GL_FLOAT; + case GL_LUMINANCE_ALPHA32F_EXT: return GL_FLOAT; + case GL_RGBA16F_EXT: return GL_HALF_FLOAT_OES; + case GL_RGB16F_EXT: return GL_HALF_FLOAT_OES; + case GL_ALPHA16F_EXT: return GL_HALF_FLOAT_OES; + case GL_LUMINANCE16F_EXT: return GL_HALF_FLOAT_OES; + case GL_LUMINANCE_ALPHA16F_EXT: return GL_HALF_FLOAT_OES; + case GL_BGRA8_EXT: return GL_UNSIGNED_BYTE; + default: return GL_NONE; // Unsupported + } +} + bool IsColorRenderable(GLenum internalformat) { switch (internalformat) @@ -528,6 +634,39 @@ D3DCULL ConvertCullMode(GLenum cullFace, GLenum frontFace) return cull; } +D3DCUBEMAP_FACES ConvertCubeFace(GLenum cubeFace) +{ + D3DCUBEMAP_FACES face = D3DCUBEMAP_FACE_POSITIVE_X; + + // Map a cube map texture target to the corresponding D3D surface index. Note that the + // Y faces are swapped because the Y coordinate to the texture lookup intrinsic functions + // are negated in the pixel shader. + switch (cubeFace) + { + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + face = D3DCUBEMAP_FACE_POSITIVE_X; + break; + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + face = D3DCUBEMAP_FACE_NEGATIVE_X; + break; + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + face = D3DCUBEMAP_FACE_NEGATIVE_Y; + break; + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + face = D3DCUBEMAP_FACE_POSITIVE_Y; + break; + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + face = D3DCUBEMAP_FACE_POSITIVE_Z; + break; + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + face = D3DCUBEMAP_FACE_NEGATIVE_Z; + break; + default: UNREACHABLE(); + } + + return face; +} + DWORD ConvertColorMask(bool red, bool green, bool blue, bool alpha) { return (red ? D3DCOLORWRITEENABLE_RED : 0) | @@ -584,6 +723,75 @@ void ConvertMinFilter(GLenum minFilter, D3DTEXTUREFILTERTYPE *d3dMinFilter, D3DT } } +bool ConvertPrimitiveType(GLenum primitiveType, GLsizei elementCount, + D3DPRIMITIVETYPE *d3dPrimitiveType, int *d3dPrimitiveCount) +{ + switch (primitiveType) + { + case GL_POINTS: + *d3dPrimitiveType = D3DPT_POINTLIST; + *d3dPrimitiveCount = elementCount; + break; + case GL_LINES: + *d3dPrimitiveType = D3DPT_LINELIST; + *d3dPrimitiveCount = elementCount / 2; + break; + case GL_LINE_LOOP: + *d3dPrimitiveType = D3DPT_LINESTRIP; + *d3dPrimitiveCount = elementCount - 1; // D3D doesn't support line loops, so we draw the last line separately + break; + case GL_LINE_STRIP: + *d3dPrimitiveType = D3DPT_LINESTRIP; + *d3dPrimitiveCount = elementCount - 1; + break; + case GL_TRIANGLES: + *d3dPrimitiveType = D3DPT_TRIANGLELIST; + *d3dPrimitiveCount = elementCount / 3; + break; + case GL_TRIANGLE_STRIP: + *d3dPrimitiveType = D3DPT_TRIANGLESTRIP; + *d3dPrimitiveCount = elementCount - 2; + break; + case GL_TRIANGLE_FAN: + *d3dPrimitiveType = D3DPT_TRIANGLEFAN; + *d3dPrimitiveCount = elementCount - 2; + break; + default: + return false; + } + + return true; +} + +D3DFORMAT ConvertRenderbufferFormat(GLenum format) +{ + switch (format) + { + case GL_RGBA4: + case GL_RGB5_A1: + case GL_RGBA8_OES: return D3DFMT_A8R8G8B8; + case GL_RGB565: return D3DFMT_R5G6B5; + case GL_RGB8_OES: return D3DFMT_X8R8G8B8; + case GL_DEPTH_COMPONENT16: + case GL_STENCIL_INDEX8: + case GL_DEPTH24_STENCIL8_OES: return D3DFMT_D24S8; + default: UNREACHABLE(); return D3DFMT_A8R8G8B8; + } +} + +D3DMULTISAMPLE_TYPE GetMultisampleTypeFromSamples(GLsizei samples) +{ + if (samples <= 1) + return D3DMULTISAMPLE_NONE; + else + return (D3DMULTISAMPLE_TYPE)samples; +} + +} + +namespace dx2es +{ + unsigned int GetStencilSize(D3DFORMAT stencilFormat) { switch(stencilFormat) @@ -601,11 +809,11 @@ unsigned int GetStencilSize(D3DFORMAT stencilFormat) case D3DFMT_D32F_LOCKABLE: case D3DFMT_D16: return 0; -// case D3DFMT_D32_LOCKABLE: return 0; // DirectX 9Ex only -// case D3DFMT_S8_LOCKABLE: return 8; // DirectX 9Ex only - default: UNREACHABLE(); + //case D3DFMT_D32_LOCKABLE: return 0; // DirectX 9Ex only + //case D3DFMT_S8_LOCKABLE: return 8; // DirectX 9Ex only + default: + return 0; } - return 0; } unsigned int GetAlphaSize(D3DFORMAT colorFormat) @@ -625,9 +833,9 @@ unsigned int GetAlphaSize(D3DFORMAT colorFormat) case D3DFMT_X8R8G8B8: case D3DFMT_R5G6B5: return 0; - default: UNREACHABLE(); + default: + return 0; } - return 0; } unsigned int GetRedSize(D3DFORMAT colorFormat) @@ -646,9 +854,9 @@ unsigned int GetRedSize(D3DFORMAT colorFormat) case D3DFMT_A1R5G5B5: case D3DFMT_R5G6B5: return 5; - default: UNREACHABLE(); + default: + return 0; } - return 0; } unsigned int GetGreenSize(D3DFORMAT colorFormat) @@ -668,9 +876,9 @@ unsigned int GetGreenSize(D3DFORMAT colorFormat) return 5; case D3DFMT_R5G6B5: return 6; - default: UNREACHABLE(); + default: + return 0; } - return 0; } unsigned int GetBlueSize(D3DFORMAT colorFormat) @@ -689,9 +897,9 @@ unsigned int GetBlueSize(D3DFORMAT colorFormat) case D3DFMT_A1R5G5B5: case D3DFMT_R5G6B5: return 5; - default: UNREACHABLE(); + default: + return 0; } - return 0; } unsigned int GetDepthSize(D3DFORMAT depthFormat) @@ -709,66 +917,52 @@ unsigned int GetDepthSize(D3DFORMAT depthFormat) case D3DFMT_D24FS8: return 24; //case D3DFMT_D32_LOCKABLE: return 32; // D3D9Ex only //case D3DFMT_S8_LOCKABLE: return 0; // D3D9Ex only - default: - UNREACHABLE(); + default: return 0; } - return 0; } -bool ConvertPrimitiveType(GLenum primitiveType, GLsizei elementCount, - D3DPRIMITIVETYPE *d3dPrimitiveType, int *d3dPrimitiveCount) +bool IsFloat32Format(D3DFORMAT surfaceFormat) { - switch (primitiveType) + switch(surfaceFormat) { - case GL_POINTS: - *d3dPrimitiveType = D3DPT_POINTLIST; - *d3dPrimitiveCount = elementCount; - break; - case GL_LINES: - *d3dPrimitiveType = D3DPT_LINELIST; - *d3dPrimitiveCount = elementCount / 2; - break; - case GL_LINE_LOOP: - *d3dPrimitiveType = D3DPT_LINESTRIP; - *d3dPrimitiveCount = elementCount - 1; // D3D doesn't support line loops, so we draw the last line separately - break; - case GL_LINE_STRIP: - *d3dPrimitiveType = D3DPT_LINESTRIP; - *d3dPrimitiveCount = elementCount - 1; - break; - case GL_TRIANGLES: - *d3dPrimitiveType = D3DPT_TRIANGLELIST; - *d3dPrimitiveCount = elementCount / 3; - break; - case GL_TRIANGLE_STRIP: - *d3dPrimitiveType = D3DPT_TRIANGLESTRIP; - *d3dPrimitiveCount = elementCount - 2; - break; - case GL_TRIANGLE_FAN: - *d3dPrimitiveType = D3DPT_TRIANGLEFAN; - *d3dPrimitiveCount = elementCount - 2; - break; - default: + case D3DFMT_R16F: + case D3DFMT_G16R16F: + case D3DFMT_A16B16G16R16F: + return false; + case D3DFMT_R32F: + case D3DFMT_G32R32F: + case D3DFMT_A32B32G32R32F: + return true; + case D3DFMT_A8R8G8B8: + case D3DFMT_X8R8G8B8: + case D3DFMT_A1R5G5B5: + case D3DFMT_R5G6B5: return false; + default: UNREACHABLE(); } - - return true; + return false; } -D3DFORMAT ConvertRenderbufferFormat(GLenum format) +bool IsFloat16Format(D3DFORMAT surfaceFormat) { - switch (format) + switch(surfaceFormat) { - case GL_RGBA4: - case GL_RGB5_A1: - case GL_RGBA8_OES: return D3DFMT_A8R8G8B8; - case GL_RGB565: return D3DFMT_R5G6B5; - case GL_RGB8_OES: return D3DFMT_X8R8G8B8; - case GL_DEPTH_COMPONENT16: - case GL_STENCIL_INDEX8: - case GL_DEPTH24_STENCIL8_OES: return D3DFMT_D24S8; - default: UNREACHABLE(); return D3DFMT_A8R8G8B8; + case D3DFMT_R16F: + case D3DFMT_G16R16F: + case D3DFMT_A16B16G16R16F: + return true; + case D3DFMT_R32F: + case D3DFMT_G32R32F: + case D3DFMT_A32B32G32R32F: + return false; + case D3DFMT_A8R8G8B8: + case D3DFMT_X8R8G8B8: + case D3DFMT_A1R5G5B5: + case D3DFMT_R5G6B5: + return false; + default: UNREACHABLE(); } + return false; } GLsizei GetSamplesFromMultisampleType(D3DMULTISAMPLE_TYPE type) @@ -779,19 +973,6 @@ GLsizei GetSamplesFromMultisampleType(D3DMULTISAMPLE_TYPE type) return type; } -D3DMULTISAMPLE_TYPE GetMultisampleTypeFromSamples(GLsizei samples) -{ - if (samples <= 1) - return D3DMULTISAMPLE_NONE; - else - return (D3DMULTISAMPLE_TYPE)samples; -} - -} - -namespace dx2es -{ - GLenum ConvertBackBufferFormat(D3DFORMAT format) { switch (format) @@ -825,3 +1006,36 @@ GLenum ConvertDepthStencilFormat(D3DFORMAT format) } } + +std::string getTempPath() +{ + char path[MAX_PATH]; + DWORD pathLen = GetTempPathA(sizeof(path) / sizeof(path[0]), path); + if (pathLen == 0) + { + UNREACHABLE(); + return std::string(); + } + + UINT unique = GetTempFileNameA(path, "sh", 0, path); + if (unique == 0) + { + UNREACHABLE(); + return std::string(); + } + + return path; +} + +void writeFile(const char* path, const void* content, size_t size) +{ + FILE* file = fopen(path, "w"); + if (!file) + { + UNREACHABLE(); + return; + } + + fwrite(content, sizeof(char), size, file); + fclose(file); +} diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/utilities.h b/Source/ThirdParty/ANGLE/src/libGLESv2/utilities.h index 85e8f26..88238dc 100644 --- a/Source/ThirdParty/ANGLE/src/libGLESv2/utilities.h +++ b/Source/ThirdParty/ANGLE/src/libGLESv2/utilities.h @@ -14,14 +14,18 @@ #include <GLES2/gl2ext.h> #include <d3d9.h> +#include <string> + namespace gl { struct Color; -int UniformComponentCount(GLenum type); +int UniformExternalComponentCount(GLenum type); +int UniformInternalComponentCount(GLenum type); GLenum UniformComponentType(GLenum type); -size_t UniformTypeSize(GLenum type); +size_t UniformInternalSize(GLenum type); +size_t UniformExternalSize(GLenum type); int VariableRowCount(GLenum type); int VariableColumnCount(GLenum type); @@ -33,8 +37,10 @@ GLsizei ComputeCompressedPitch(GLsizei width, GLenum format); GLsizei ComputeCompressedSize(GLsizei width, GLsizei height, GLenum format); bool IsCompressed(GLenum format); bool IsCubemapTextureTarget(GLenum target); -bool IsTextureTarget(GLenum target); +bool IsInternalTextureTarget(GLenum target); bool CheckTextureFormatType(GLenum format, GLenum type); +GLenum ExtractFormat(GLenum internalformat); +GLenum ExtractType(GLenum internalformat); bool IsColorRenderable(GLenum internalformat); bool IsDepthRenderable(GLenum internalformat); @@ -52,29 +58,50 @@ D3DBLENDOP ConvertBlendOp(GLenum blendOp); D3DSTENCILOP ConvertStencilOp(GLenum stencilOp); D3DTEXTUREADDRESS ConvertTextureWrap(GLenum wrap); D3DCULL ConvertCullMode(GLenum cullFace, GLenum frontFace); +D3DCUBEMAP_FACES ConvertCubeFace(GLenum cubeFace); DWORD ConvertColorMask(bool red, bool green, bool blue, bool alpha); D3DTEXTUREFILTERTYPE ConvertMagFilter(GLenum magFilter); void ConvertMinFilter(GLenum minFilter, D3DTEXTUREFILTERTYPE *d3dMinFilter, D3DTEXTUREFILTERTYPE *d3dMipFilter); -unsigned int GetAlphaSize(D3DFORMAT colorFormat); -unsigned int GetRedSize(D3DFORMAT colorFormat); -unsigned int GetGreenSize(D3DFORMAT colorFormat); -unsigned int GetBlueSize(D3DFORMAT colorFormat); -unsigned int GetDepthSize(D3DFORMAT depthFormat); -unsigned int GetStencilSize(D3DFORMAT stencilFormat); bool ConvertPrimitiveType(GLenum primitiveType, GLsizei elementCount, D3DPRIMITIVETYPE *d3dPrimitiveType, int *d3dPrimitiveCount); D3DFORMAT ConvertRenderbufferFormat(GLenum format); D3DMULTISAMPLE_TYPE GetMultisampleTypeFromSamples(GLsizei samples); -GLsizei GetSamplesFromMultisampleType(D3DMULTISAMPLE_TYPE type); } namespace dx2es { +GLuint GetAlphaSize(D3DFORMAT colorFormat); +GLuint GetRedSize(D3DFORMAT colorFormat); +GLuint GetGreenSize(D3DFORMAT colorFormat); +GLuint GetBlueSize(D3DFORMAT colorFormat); +GLuint GetDepthSize(D3DFORMAT depthFormat); +GLuint GetStencilSize(D3DFORMAT stencilFormat); +bool IsFloat32Format(D3DFORMAT surfaceFormat); +bool IsFloat16Format(D3DFORMAT surfaceFormat); + +GLsizei GetSamplesFromMultisampleType(D3DMULTISAMPLE_TYPE type); GLenum ConvertBackBufferFormat(D3DFORMAT format); GLenum ConvertDepthStencilFormat(D3DFORMAT format); } +std::string getTempPath(); +void writeFile(const char* path, const void* data, size_t size); + +inline bool isDeviceLostError(HRESULT errorCode) +{ + switch (errorCode) + { + case D3DERR_DRIVERINTERNALERROR: + case D3DERR_DEVICELOST: + case D3DERR_DEVICEHUNG: + case D3DERR_DEVICEREMOVED: + return true; + default: + return false; + } +}; + #endif // LIBGLESV2_UTILITIES_H diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/vertexconversion.h b/Source/ThirdParty/ANGLE/src/libGLESv2/vertexconversion.h new file mode 100644 index 0000000..5bb8b89 --- /dev/null +++ b/Source/ThirdParty/ANGLE/src/libGLESv2/vertexconversion.h @@ -0,0 +1,208 @@ +// +// Copyright (c) 2002-2010 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. +// + +// vertexconversion.h: A library of vertex conversion classes that can be used to build +// the FormatConverter objects used by the buffer conversion system. + +#ifndef LIBGLESV2_VERTEXCONVERSION_H_ +#define LIBGLESV2_VERTEXCONVERSION_H_ + +#include <cstddef> +#include <limits> + +#include "libGLESv2/Context.h" // Defines Index + +namespace gl +{ + +// Conversion types: +// static const bool identity: true if this is an identity transform, false otherwise +// static U convert(T): convert a single element from the input type to the output type +// typedef ... OutputType: the type produced by this conversion + +template <class T> +struct Identity +{ + static const bool identity = true; + + typedef T OutputType; + + static T convert(T x) + { + return x; + } +}; + +template <class FromT, class ToT> +struct Cast +{ + static const bool identity = false; + + typedef ToT OutputType; + + static ToT convert(FromT x) + { + return static_cast<ToT>(x); + } +}; + +template <class T> +struct Cast<T, T> +{ + static const bool identity = true; + + typedef T OutputType; + + static T convert(T x) + { + return static_cast<T>(x); + } +}; + +template <class T> +struct Normalize +{ + static const bool identity = false; + + typedef float OutputType; + + static float convert(T x) + { + typedef std::numeric_limits<T> NL; + float f = static_cast<float>(x); + + if (NL::is_signed) + { + // const float => VC2008 computes it at compile time + // static const float => VC2008 computes it the first time we get here, stores it to memory with static guard and all that. + const float divisor = 1.0f/(2*static_cast<float>(NL::max())+1); + return (2*f+1)*divisor; + } + else + { + return f/NL::max(); + } + } +}; + +template <class FromType, std::size_t ScaleBits> +struct FixedToFloat +{ + static const bool identity = false; + + typedef float OutputType; + + static float convert(FromType x) + { + const float divisor = 1.0f / static_cast<float>(static_cast<FromType>(1) << ScaleBits); + return static_cast<float>(x) * divisor; + } +}; + +// Widen types: +// static const unsigned int initialWidth: number of components before conversion +// static const unsigned int finalWidth: number of components after conversion + +// Float is supported at any size. +template <std::size_t N> +struct NoWiden +{ + static const std::size_t initialWidth = N; + static const std::size_t finalWidth = N; +}; + +// SHORT, norm-SHORT, norm-UNSIGNED_SHORT are supported but only with 2 or 4 components +template <std::size_t N> +struct WidenToEven +{ + static const std::size_t initialWidth = N; + static const std::size_t finalWidth = N+(N&1); +}; + +template <std::size_t N> +struct WidenToFour +{ + static const std::size_t initialWidth = N; + static const std::size_t finalWidth = 4; +}; + +// Most types have 0 and 1 that are just that. +template <class T> +struct SimpleDefaultValues +{ + static T zero() { return static_cast<T>(0); } + static T one() { return static_cast<T>(1); } +}; + +// But normalised types only store [0,1] or [-1,1] so 1.0 is represented by the max value. +template <class T> +struct NormalizedDefaultValues +{ + static T zero() { return static_cast<T>(0); } + static T one() { return std::numeric_limits<T>::max(); } +}; + +// Converter: +// static const bool identity: true if this is an identity transform (with no widening) +// static const std::size_t finalSize: number of bytes per output vertex +// static void convertArray(const void *in, std::size_t stride, std::size_t n, void *out): convert an array of vertices. Input may be strided, but output will be unstrided. + +template <class InT, class WidenRule, class Converter, class DefaultValueRule = SimpleDefaultValues<InT> > +struct VertexDataConverter +{ + typedef typename Converter::OutputType OutputType; + typedef InT InputType; + + static const bool identity = (WidenRule::initialWidth == WidenRule::finalWidth) && Converter::identity; + static const std::size_t finalSize = WidenRule::finalWidth * sizeof(OutputType); + + static void convertArray(const InputType *in, std::size_t stride, std::size_t n, OutputType *out) + { + for (std::size_t i = 0; i < n; i++) + { + const InputType *ein = pointerAddBytes(in, i * stride); + + copyComponent(out, ein, 0, static_cast<OutputType>(DefaultValueRule::zero())); + copyComponent(out, ein, 1, static_cast<OutputType>(DefaultValueRule::zero())); + copyComponent(out, ein, 2, static_cast<OutputType>(DefaultValueRule::zero())); + copyComponent(out, ein, 3, static_cast<OutputType>(DefaultValueRule::one())); + + out += WidenRule::finalWidth; + } + } + + static void convertArray(const void *in, std::size_t stride, std::size_t n, void *out) + { + return convertArray(static_cast<const InputType*>(in), stride, n, static_cast<OutputType*>(out)); + } + + private: + // Advance the given pointer by a number of bytes (not pointed-to elements). + template <class T> + static T *pointerAddBytes(T *basePtr, std::size_t numBytes) + { + return reinterpret_cast<T *>(reinterpret_cast<uintptr_t>(basePtr) + numBytes); + } + + static void copyComponent(OutputType *out, const InputType *in, std::size_t elementindex, OutputType defaultvalue) + { + if (WidenRule::finalWidth > elementindex) + { + if (WidenRule::initialWidth > elementindex) + { + out[elementindex] = Converter::convert(in[elementindex]); + } + else + { + out[elementindex] = defaultvalue; + } + } + } +}; + +} + +#endif // LIBGLESV2_VERTEXCONVERSION_H_ |