diff options
Diffstat (limited to 'src/3rdparty/angle/src/libGLESv2')
48 files changed, 30067 insertions, 0 deletions
diff --git a/src/3rdparty/angle/src/libGLESv2/BinaryStream.h b/src/3rdparty/angle/src/libGLESv2/BinaryStream.h new file mode 100644 index 0000000000..5f7213b8da --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/BinaryStream.h @@ -0,0 +1,167 @@ +// +// 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. +// + +// BinaryStream.h: Provides binary serialization of simple types. + +#ifndef LIBGLESV2_BINARYSTREAM_H_ +#define LIBGLESV2_BINARYSTREAM_H_ + +#include <string> +#include <vector> + +#include "common/angleutils.h" + +namespace gl +{ + +class BinaryInputStream +{ + public: + BinaryInputStream(const void *data, size_t length) + { + mError = false; + mOffset = 0; + mData = static_cast<const char*>(data); + mLength = length; + } + + template <typename T> + void read(T *v, size_t num) + { + union + { + T dummy; // Compilation error for non-trivial types + } dummy; + (void) dummy; + + if (mError) + { + return; + } + + size_t length = num * sizeof(T); + + if (mOffset + length > mLength) + { + mError = true; + return; + } + + memcpy(v, mData + mOffset, length); + mOffset += length; + } + + template <typename T> + void read(T * v) + { + read(v, 1); + } + + void read(std::string *v) + { + size_t length; + read(&length); + + if (mError) + { + return; + } + + if (mOffset + length > mLength) + { + mError = true; + return; + } + + v->assign(mData + mOffset, length); + mOffset += length; + } + + void skip(size_t length) + { + if (mOffset + length > mLength) + { + mError = true; + return; + } + + mOffset += length; + } + + size_t offset() const + { + return mOffset; + } + + bool error() const + { + return mError; + } + + bool endOfStream() const + { + return mOffset == mLength; + } + + private: + DISALLOW_COPY_AND_ASSIGN(BinaryInputStream); + bool mError; + size_t mOffset; + const char *mData; + size_t mLength; +}; + +class BinaryOutputStream +{ + public: + BinaryOutputStream() + { + } + + template <typename T> + void write(const T *v, size_t num) + { + union + { + T dummy; // Compilation error for non-trivial types + } dummy; + (void) dummy; + + const char *asBytes = reinterpret_cast<const char*>(v); + mData.insert(mData.end(), asBytes, asBytes + num * sizeof(T)); + } + + template <typename T> + void write(const T &v) + { + write(&v, 1); + } + + void write(const std::string &v) + { + size_t length = v.length(); + write(length); + + write(v.c_str(), length); + } + + size_t length() const + { + return mData.size(); + } + + const void* data() const + { + return mData.size() ? &mData[0] : NULL; + } + + private: + DISALLOW_COPY_AND_ASSIGN(BinaryOutputStream); + std::vector<char> mData; +}; +} + +#endif // LIBGLESV2_BINARYSTREAM_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/Blit.cpp b/src/3rdparty/angle/src/libGLESv2/Blit.cpp new file mode 100644 index 0000000000..28f3fbffbb --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/Blit.cpp @@ -0,0 +1,518 @@ +// +// 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. +// + +// Blit.cpp: Surface copy utility class. + +#include "libGLESv2/Blit.h" + +#include "common/debug.h" + +#include "libGLESv2/main.h" +#include "libGLESv2/utilities.h" + +namespace +{ +#include "libGLESv2/shaders/standardvs.h" +#include "libGLESv2/shaders/flipyvs.h" +#include "libGLESv2/shaders/passthroughps.h" +#include "libGLESv2/shaders/luminanceps.h" +#include "libGLESv2/shaders/componentmaskps.h" + +const BYTE* const g_shaderCode[] = +{ + g_vs20_standardvs, + g_vs20_flipyvs, + g_ps20_passthroughps, + g_ps20_luminanceps, + g_ps20_componentmaskps +}; + +const size_t g_shaderSize[] = +{ + sizeof(g_vs20_standardvs), + sizeof(g_vs20_flipyvs), + sizeof(g_ps20_passthroughps), + sizeof(g_ps20_luminanceps), + sizeof(g_ps20_componentmaskps) +}; +} + +namespace gl +{ +Blit::Blit(Context *context) + : mContext(context), mQuadVertexBuffer(NULL), mQuadVertexDeclaration(NULL), mSavedRenderTarget(NULL), mSavedDepthStencil(NULL), mSavedStateBlock(NULL) +{ + initGeometry(); + memset(mCompiledShaders, 0, sizeof(mCompiledShaders)); +} + +Blit::~Blit() +{ + if (mSavedStateBlock) mSavedStateBlock->Release(); + if (mQuadVertexBuffer) mQuadVertexBuffer->Release(); + if (mQuadVertexDeclaration) mQuadVertexDeclaration->Release(); + + for (int i = 0; i < SHADER_COUNT; i++) + { + if (mCompiledShaders[i]) + { + mCompiledShaders[i]->Release(); + } + } +} + +void Blit::initGeometry() +{ + static const float quad[] = + { + -1, -1, + -1, 1, + 1, -1, + 1, 1 + }; + + IDirect3DDevice9 *device = getDevice(); + + HRESULT result = device->CreateVertexBuffer(sizeof(quad), D3DUSAGE_WRITEONLY, 0, D3DPOOL_DEFAULT, &mQuadVertexBuffer, NULL); + + if (FAILED(result)) + { + 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); + } + + memcpy(lockPtr, quad, sizeof(quad)); + mQuadVertexBuffer->Unlock(); + + static const D3DVERTEXELEMENT9 elements[] = + { + { 0, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 }, + D3DDECL_END() + }; + + result = device->CreateVertexDeclaration(elements, &mQuadVertexDeclaration); + + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + return error(GL_OUT_OF_MEMORY); + } +} + +template <class D3DShaderType> +bool Blit::setShader(ShaderId source, const char *profile, + D3DShaderType *(egl::Display::*createShader)(const DWORD *, size_t length), + HRESULT (WINAPI IDirect3DDevice9::*setShader)(D3DShaderType*)) +{ + egl::Display *display = getDisplay(); + IDirect3DDevice9 *device = display->getDevice(); + + D3DShaderType *shader; + + if (mCompiledShaders[source] != NULL) + { + shader = static_cast<D3DShaderType*>(mCompiledShaders[source]); + } + else + { + const BYTE* shaderCode = g_shaderCode[source]; + size_t shaderSize = g_shaderSize[source]; + + shader = (display->*createShader)(reinterpret_cast<const DWORD*>(shaderCode), shaderSize); + if (!shader) + { + ERR("Failed to create shader for blit operation"); + return false; + } + + mCompiledShaders[source] = shader; + } + + HRESULT hr = (device->*setShader)(shader); + + if (FAILED(hr)) + { + ERR("Failed to set shader for blit operation"); + return false; + } + + return true; +} + +bool Blit::setVertexShader(ShaderId shader) +{ + return setShader<IDirect3DVertexShader9>(shader, "vs_2_0", &egl::Display::createVertexShader, &IDirect3DDevice9::SetVertexShader); +} + +bool Blit::setPixelShader(ShaderId shader) +{ + return setShader<IDirect3DPixelShader9>(shader, "ps_2_0", &egl::Display::createPixelShader, &IDirect3DDevice9::SetPixelShader); +} + +RECT Blit::getSurfaceRect(IDirect3DSurface9 *surface) const +{ + D3DSURFACE_DESC desc; + surface->GetDesc(&desc); + + RECT rect; + rect.left = 0; + rect.top = 0; + rect.right = desc.Width; + rect.bottom = desc.Height; + + return rect; +} + +bool Blit::boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *dest) +{ + IDirect3DTexture9 *texture = copySurfaceToTexture(source, getSurfaceRect(source)); + if (!texture) + { + return false; + } + + IDirect3DDevice9 *device = getDevice(); + + saveState(); + + device->SetTexture(0, texture); + device->SetRenderTarget(0, dest); + + setVertexShader(SHADER_VS_STANDARD); + setPixelShader(SHADER_PS_PASSTHROUGH); + + setCommonBlitState(); + device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + + setViewport(getSurfaceRect(dest), 0, 0); + + render(); + + texture->Release(); + + restoreState(); + + 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 && + dx2es::IsFormatChannelEquivalent(destDesc.Format, destFormat)) // 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); + if (!texture) + { + return false; + } + + IDirect3DDevice9 *device = getDevice(); + + saveState(); + + device->SetTexture(0, texture); + device->SetRenderTarget(0, dest); + + setViewport(sourceRect, xoffset, yoffset); + + setCommonBlitState(); + if (setFormatConvertShaders(destFormat)) + { + render(); + } + + texture->Release(); + + restoreState(); + + return true; +} + +bool Blit::setFormatConvertShaders(GLenum destFormat) +{ + bool okay = setVertexShader(SHADER_VS_STANDARD); + + switch (destFormat) + { + default: UNREACHABLE(); + case GL_RGBA: + case GL_BGRA_EXT: + case GL_RGB: + case GL_ALPHA: + okay = okay && setPixelShader(SHADER_PS_COMPONENTMASK); + break; + + case GL_LUMINANCE: + case GL_LUMINANCE_ALPHA: + okay = okay && setPixelShader(SHADER_PS_LUMINANCE); + break; + } + + if (!okay) + { + return false; + } + + enum { X = 0, Y = 1, Z = 2, W = 3 }; + + // The meaning of this constant depends on the shader that was selected. + // See the shader assembly code above for details. + float psConst0[4] = { 0, 0, 0, 0 }; + + switch (destFormat) + { + default: UNREACHABLE(); + case GL_RGBA: + case GL_BGRA_EXT: + psConst0[X] = 1; + psConst0[Z] = 1; + break; + + case GL_RGB: + psConst0[X] = 1; + psConst0[W] = 1; + break; + + case GL_ALPHA: + psConst0[Z] = 1; + break; + + case GL_LUMINANCE: + psConst0[Y] = 1; + break; + + case GL_LUMINANCE_ALPHA: + psConst0[X] = 1; + break; + } + + getDevice()->SetPixelShaderConstantF(0, psConst0, 1); + + return true; +} + +IDirect3DTexture9 *Blit::copySurfaceToTexture(IDirect3DSurface9 *surface, const RECT &sourceRect) +{ + if (!surface) + { + return NULL; + } + + egl::Display *display = getDisplay(); + IDirect3DDevice9 *device = getDevice(); + + D3DSURFACE_DESC sourceDesc; + surface->GetDesc(&sourceDesc); + + // Copy the render target into a texture + IDirect3DTexture9 *texture; + HRESULT result = device->CreateTexture(sourceRect.right - sourceRect.left, sourceRect.bottom - sourceRect.top, 1, D3DUSAGE_RENDERTARGET, sourceDesc.Format, D3DPOOL_DEFAULT, &texture, NULL); + + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + return error(GL_OUT_OF_MEMORY, (IDirect3DTexture9*)NULL); + } + + IDirect3DSurface9 *textureSurface; + result = texture->GetSurfaceLevel(0, &textureSurface); + + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + texture->Release(); + return error(GL_OUT_OF_MEMORY, (IDirect3DTexture9*)NULL); + } + + display->endScene(); + result = device->StretchRect(surface, &sourceRect, textureSurface, NULL, D3DTEXF_NONE); + + textureSurface->Release(); + + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + texture->Release(); + return error(GL_OUT_OF_MEMORY, (IDirect3DTexture9*)NULL); + } + + return texture; +} + +void Blit::setViewport(const RECT &sourceRect, GLint xoffset, GLint yoffset) +{ + IDirect3DDevice9 *device = getDevice(); + + D3DVIEWPORT9 vp; + vp.X = xoffset; + vp.Y = yoffset; + vp.Width = sourceRect.right - sourceRect.left; + vp.Height = sourceRect.bottom - sourceRect.top; + vp.MinZ = 0.0f; + vp.MaxZ = 1.0f; + device->SetViewport(&vp); + + float halfPixelAdjust[4] = { -1.0f/vp.Width, 1.0f/vp.Height, 0, 0 }; + device->SetVertexShaderConstantF(0, halfPixelAdjust, 1); +} + +void Blit::setCommonBlitState() +{ + IDirect3DDevice9 *device = getDevice(); + + device->SetDepthStencilSurface(NULL); + + device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID); + device->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); + device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + device->SetRenderState(D3DRS_CLIPPLANEENABLE, 0); + device->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA | D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_RED); + device->SetRenderState(D3DRS_SRGBWRITEENABLE, FALSE); + device->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE); + + device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); + device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); + device->SetSamplerState(0, D3DSAMP_SRGBTEXTURE, FALSE); + device->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); + device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); + + 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() +{ + egl::Display *display = getDisplay(); + IDirect3DDevice9 *device = getDevice(); + + HRESULT hr = device->SetStreamSource(0, mQuadVertexBuffer, 0, 2 * sizeof(float)); + hr = device->SetVertexDeclaration(mQuadVertexDeclaration); + + display->startScene(); + hr = device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); +} + +void Blit::saveState() +{ + IDirect3DDevice9 *device = getDevice(); + + HRESULT hr; + + device->GetDepthStencilSurface(&mSavedDepthStencil); + device->GetRenderTarget(0, &mSavedRenderTarget); + + if (mSavedStateBlock == NULL) + { + hr = device->BeginStateBlock(); + ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY); + + setCommonBlitState(); + + static const float dummyConst[4] = { 0, 0, 0, 0 }; + + device->SetVertexShader(NULL); + device->SetVertexShaderConstantF(0, dummyConst, 1); + device->SetPixelShader(NULL); + device->SetPixelShaderConstantF(0, dummyConst, 1); + + D3DVIEWPORT9 dummyVp; + dummyVp.X = 0; + dummyVp.Y = 0; + dummyVp.Width = 1; + dummyVp.Height = 1; + dummyVp.MinZ = 0; + dummyVp.MaxZ = 1; + + device->SetViewport(&dummyVp); + + device->SetTexture(0, NULL); + + device->SetStreamSource(0, mQuadVertexBuffer, 0, 0); + + device->SetVertexDeclaration(mQuadVertexDeclaration); + + hr = device->EndStateBlock(&mSavedStateBlock); + ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY); + } + + ASSERT(mSavedStateBlock != NULL); + + if (mSavedStateBlock != NULL) + { + hr = mSavedStateBlock->Capture(); + ASSERT(SUCCEEDED(hr)); + } +} + +void Blit::restoreState() +{ + IDirect3DDevice9 *device = getDevice(); + + device->SetDepthStencilSurface(mSavedDepthStencil); + if (mSavedDepthStencil != NULL) + { + mSavedDepthStencil->Release(); + mSavedDepthStencil = NULL; + } + + device->SetRenderTarget(0, mSavedRenderTarget); + if (mSavedRenderTarget != NULL) + { + mSavedRenderTarget->Release(); + mSavedRenderTarget = NULL; + } + + ASSERT(mSavedStateBlock != NULL); + + if (mSavedStateBlock != NULL) + { + mSavedStateBlock->Apply(); + } +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/Blit.h b/src/3rdparty/angle/src/libGLESv2/Blit.h new file mode 100644 index 0000000000..a9bb4956eb --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/Blit.h @@ -0,0 +1,94 @@ +// +// 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. +// + +// Blit.cpp: Surface copy utility class. + +#ifndef LIBGLESV2_BLIT_H_ +#define LIBGLESV2_BLIT_H_ + +#include <map> + +#define GL_APICALL +#include <GLES2/gl2.h> + +#include <d3d9.h> + +#include "common/angleutils.h" + +#include "libEGL/Display.h" + +namespace gl +{ +class Context; + +class Blit +{ + public: + explicit Blit(Context *context); + ~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); + + // 2x2 box filter sample from source to dest. + // Requires that source is RGB(A) and dest has the same format as source. + bool boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *dest); + + private: + Context *mContext; + + IDirect3DVertexBuffer9 *mQuadVertexBuffer; + IDirect3DVertexDeclaration9 *mQuadVertexDeclaration; + + void initGeometry(); + + bool setFormatConvertShaders(GLenum destFormat); + + IDirect3DTexture9 *copySurfaceToTexture(IDirect3DSurface9 *surface, const RECT &sourceRect); + void setViewport(const RECT &sourceRect, GLint xoffset, GLint yoffset); + void setCommonBlitState(); + RECT getSurfaceRect(IDirect3DSurface9 *surface) const; + + // This enum is used to index mCompiledShaders and mShaderSource. + enum ShaderId + { + SHADER_VS_STANDARD, + SHADER_VS_FLIPY, + SHADER_PS_PASSTHROUGH, + SHADER_PS_LUMINANCE, + SHADER_PS_COMPONENTMASK, + SHADER_COUNT + }; + + // This actually contains IDirect3DVertexShader9 or IDirect3DPixelShader9 casted to IUnknown. + IUnknown *mCompiledShaders[SHADER_COUNT]; + + template <class D3DShaderType> + bool setShader(ShaderId source, const char *profile, + D3DShaderType *(egl::Display::*createShader)(const DWORD *, size_t length), + HRESULT (WINAPI IDirect3DDevice9::*setShader)(D3DShaderType*)); + + bool setVertexShader(ShaderId shader); + bool setPixelShader(ShaderId shader); + void render(); + + void saveState(); + void restoreState(); + IDirect3DStateBlock9 *mSavedStateBlock; + IDirect3DSurface9 *mSavedRenderTarget; + IDirect3DSurface9 *mSavedDepthStencil; + + DISALLOW_COPY_AND_ASSIGN(Blit); +}; +} + +#endif // LIBGLESV2_BLIT_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/Buffer.cpp b/src/3rdparty/angle/src/libGLESv2/Buffer.cpp new file mode 100644 index 0000000000..dd12e3c077 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/Buffer.cpp @@ -0,0 +1,117 @@ +// +// 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. +// + +// Buffer.cpp: Implements the gl::Buffer class, representing storage of vertex and/or +// index data. Implements GL buffer objects and related functionality. +// [OpenGL ES 2.0.24] section 2.9 page 21. + +#include "libGLESv2/Buffer.h" + +#include "libGLESv2/main.h" +#include "libGLESv2/VertexDataManager.h" +#include "libGLESv2/IndexDataManager.h" + +namespace gl +{ + +Buffer::Buffer(GLuint id) : RefCountObject(id) +{ + mContents = NULL; + mSize = 0; + mUsage = GL_DYNAMIC_DRAW; + + mStaticVertexBuffer = NULL; + mStaticIndexBuffer = NULL; + mUnmodifiedDataUse = 0; +} + +Buffer::~Buffer() +{ + delete[] mContents; + delete mStaticVertexBuffer; + delete mStaticIndexBuffer; +} + +void Buffer::bufferData(const void *data, GLsizeiptr size, GLenum usage) +{ + if (size == 0) + { + delete[] mContents; + mContents = NULL; + } + else if (size != mSize) + { + delete[] mContents; + mContents = new GLubyte[size]; + memset(mContents, 0, size); + } + + if (data != NULL && size > 0) + { + memcpy(mContents, data, size); + } + + mSize = size; + mUsage = usage; + + invalidateStaticData(); + + if (usage == GL_STATIC_DRAW) + { + mStaticVertexBuffer = new StaticVertexBuffer(getDevice()); + mStaticIndexBuffer = new StaticIndexBuffer(getDevice()); + } +} + +void Buffer::bufferSubData(const void *data, GLsizeiptr size, GLintptr offset) +{ + memcpy(mContents + offset, data, size); + + if ((mStaticVertexBuffer && mStaticVertexBuffer->size() != 0) || (mStaticIndexBuffer && mStaticIndexBuffer->size() != 0)) + { + invalidateStaticData(); + } + + mUnmodifiedDataUse = 0; +} + +StaticVertexBuffer *Buffer::getStaticVertexBuffer() +{ + return mStaticVertexBuffer; +} + +StaticIndexBuffer *Buffer::getStaticIndexBuffer() +{ + return mStaticIndexBuffer; +} + +void Buffer::invalidateStaticData() +{ + 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; + + if (mUnmodifiedDataUse > 3 * mSize) + { + mStaticVertexBuffer = new StaticVertexBuffer(getDevice()); + mStaticIndexBuffer = new StaticIndexBuffer(getDevice()); + } + } +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/Buffer.h b/src/3rdparty/angle/src/libGLESv2/Buffer.h new file mode 100644 index 0000000000..7019c4e160 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/Buffer.h @@ -0,0 +1,61 @@ +// +// 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. +// + +// Buffer.h: Defines the gl::Buffer class, representing storage of vertex and/or +// index data. Implements GL buffer objects and related functionality. +// [OpenGL ES 2.0.24] section 2.9 page 21. + +#ifndef LIBGLESV2_BUFFER_H_ +#define LIBGLESV2_BUFFER_H_ + +#include <cstddef> +#include <vector> + +#define GL_APICALL +#include <GLES2/gl2.h> + +#include "common/angleutils.h" +#include "common/RefCountObject.h" + +namespace gl +{ +class StaticVertexBuffer; +class StaticIndexBuffer; + +class Buffer : public RefCountObject +{ + public: + explicit Buffer(GLuint id); + + virtual ~Buffer(); + + void bufferData(const void *data, GLsizeiptr size, GLenum usage); + void bufferSubData(const void *data, GLsizeiptr size, GLintptr offset); + + void *data() { return mContents; } + size_t size() const { return mSize; } + GLenum usage() const { return mUsage; } + + StaticVertexBuffer *getStaticVertexBuffer(); + StaticIndexBuffer *getStaticIndexBuffer(); + void invalidateStaticData(); + void promoteStaticUsage(int dataSize); + + private: + DISALLOW_COPY_AND_ASSIGN(Buffer); + + GLubyte *mContents; + GLsizeiptr mSize; + GLenum mUsage; + + StaticVertexBuffer *mStaticVertexBuffer; + StaticIndexBuffer *mStaticIndexBuffer; + GLsizeiptr mUnmodifiedDataUse; +}; + +} + +#endif // LIBGLESV2_BUFFER_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/Context.cpp b/src/3rdparty/angle/src/libGLESv2/Context.cpp new file mode 100644 index 0000000000..414bfa968d --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/Context.cpp @@ -0,0 +1,4501 @@ +// +// 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. +// + +// Context.cpp: Implements the gl::Context class, managing all GL state and performing +// rendering operations. It is the GLES2 specific implementation of EGLContext. + +#include "libGLESv2/Context.h" + +#include <algorithm> + +#include "libEGL/Display.h" + +#include "libGLESv2/main.h" +#include "libGLESv2/mathutil.h" +#include "libGLESv2/utilities.h" +#include "libGLESv2/Blit.h" +#include "libGLESv2/ResourceManager.h" +#include "libGLESv2/Buffer.h" +#include "libGLESv2/Fence.h" +#include "libGLESv2/Framebuffer.h" +#include "libGLESv2/Program.h" +#include "libGLESv2/ProgramBinary.h" +#include "libGLESv2/Query.h" +#include "libGLESv2/Renderbuffer.h" +#include "libGLESv2/Shader.h" +#include "libGLESv2/Texture.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, 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; + mState.stencilClearValue = 0; + + mState.cullFace = false; + mState.cullMode = GL_BACK; + mState.frontFace = GL_CCW; + mState.depthTest = false; + mState.depthFunc = GL_LESS; + mState.blend = false; + mState.sourceBlendRGB = GL_ONE; + mState.sourceBlendAlpha = GL_ONE; + mState.destBlendRGB = GL_ZERO; + mState.destBlendAlpha = GL_ZERO; + mState.blendEquationRGB = GL_FUNC_ADD; + mState.blendEquationAlpha = GL_FUNC_ADD; + mState.blendColor.red = 0; + mState.blendColor.green = 0; + mState.blendColor.blue = 0; + mState.blendColor.alpha = 0; + mState.stencilTest = false; + mState.stencilFunc = GL_ALWAYS; + mState.stencilRef = 0; + mState.stencilMask = -1; + mState.stencilWritemask = -1; + mState.stencilBackFunc = GL_ALWAYS; + mState.stencilBackRef = 0; + mState.stencilBackMask = - 1; + mState.stencilBackWritemask = -1; + mState.stencilFail = GL_KEEP; + mState.stencilPassDepthFail = GL_KEEP; + mState.stencilPassDepthPass = GL_KEEP; + mState.stencilBackFail = GL_KEEP; + mState.stencilBackPassDepthFail = GL_KEEP; + mState.stencilBackPassDepthPass = GL_KEEP; + mState.polygonOffsetFill = false; + mState.polygonOffsetFactor = 0.0f; + mState.polygonOffsetUnits = 0.0f; + mState.sampleAlphaToCoverage = false; + mState.sampleCoverage = false; + mState.sampleCoverageValue = 1.0f; + mState.sampleCoverageInvert = false; + mState.scissorTest = false; + mState.dither = true; + mState.generateMipmapHint = GL_DONT_CARE; + mState.fragmentShaderDerivativeHint = GL_DONT_CARE; + + mState.lineWidth = 1.0f; + + mState.viewportX = 0; + mState.viewportY = 0; + mState.viewportWidth = config->mDisplayMode.Width; + mState.viewportHeight = config->mDisplayMode.Height; + mState.zNear = 0.0f; + mState.zFar = 1.0f; + + mState.scissorX = 0; + mState.scissorY = 0; + mState.scissorWidth = config->mDisplayMode.Width; + mState.scissorHeight = config->mDisplayMode.Height; + + mState.colorMaskRed = true; + mState.colorMaskGreen = true; + mState.colorMaskBlue = true; + mState.colorMaskAlpha = true; + mState.depthMask = true; + + if (shareContext != NULL) + { + mResourceManager = shareContext->mResourceManager; + mResourceManager->addRef(); + } + else + { + mResourceManager = new ResourceManager(); + } + + // [OpenGL ES 2.0.24] section 3.7 page 83: + // In the initial state, TEXTURE_2D and TEXTURE_CUBE_MAP have twodimensional + // and cube map texture state vectors respectively associated with them. + // In order that access to these initial textures not be lost, they are treated as texture + // objects all of whose names are 0. + + mTexture2DZero.set(new Texture2D(0)); + mTextureCubeMapZero.set(new TextureCubeMap(0)); + + mState.activeSampler = 0; + bindArrayBuffer(0); + bindElementArrayBuffer(0); + bindTextureCubeMap(0); + bindTexture2D(0); + bindReadFramebuffer(0); + bindDrawFramebuffer(0); + bindRenderbuffer(0); + + mState.currentProgram = 0; + mCurrentProgramBinary.set(NULL); + + mState.packAlignment = 4; + mState.unpackAlignment = 4; + mState.packReverseRowOrder = false; + + mVertexDataManager = NULL; + mIndexDataManager = NULL; + mBlit = NULL; + mLineLoopIB = NULL; + + mInvalidEnum = false; + mInvalidValue = false; + mInvalidOperation = false; + mOutOfMemory = false; + mInvalidFramebufferOperation = false; + + mHasBeenCurrent = 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(); +} + +Context::~Context() +{ + if (mState.currentProgram != 0) + { + Program *programObject = mResourceManager->getProgram(mState.currentProgram); + if (programObject) + { + programObject->release(); + } + mState.currentProgram = 0; + } + mCurrentProgramBinary.set(NULL); + + while (!mFramebufferMap.empty()) + { + deleteFramebuffer(mFramebufferMap.begin()->first); + } + + while (!mFenceMap.empty()) + { + 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 < TEXTURE_TYPE_COUNT; type++) + { + for (int sampler = 0; sampler < MAX_COMBINED_TEXTURE_IMAGE_UNITS_VTF; sampler++) + { + mState.samplerTexture[type][sampler].set(NULL); + } + } + + for (int type = 0; type < TEXTURE_TYPE_COUNT; type++) + { + mIncompleteTextures[type].set(NULL); + } + + for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++) + { + 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); + + mTexture2DZero.set(NULL); + mTextureCubeMapZero.set(NULL); + + delete mVertexDataManager; + delete mIndexDataManager; + delete mBlit; + delete mLineLoopIB; + + if (mMaskedClearSavedState) + { + mMaskedClearSavedState->Release(); + } + + mResourceManager->release(); +} + +void Context::makeCurrent(egl::Display *display, egl::Surface *surface) +{ + mDisplay = display; + mDevice = mDisplay->getDevice(); + + if (!mHasBeenCurrent) + { + mDeviceCaps = mDisplay->getDeviceCaps(); + + mVertexDataManager = new VertexDataManager(this, mDevice); + mIndexDataManager = new IndexDataManager(this, mDevice); + mBlit = new Blit(this); + + mSupportsShaderModel3 = mDeviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0); + mMaximumPointSize = mDeviceCaps.MaxPointSize; + 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); + mMaxCubeTextureDimension = std::min(mMaxTextureDimension, (int)gl::IMPLEMENTATION_MAX_CUBE_MAP_TEXTURE_SIZE); + mMaxRenderbufferDimension = mMaxTextureDimension; + mMaxTextureLevel = log2(mMaxTextureDimension) + 1; + mMaxTextureAnisotropy = mDisplay->getTextureFilterAnisotropySupport(); + TRACE("MaxTextureDimension=%d, MaxCubeTextureDimension=%d, MaxRenderbufferDimension=%d, MaxTextureLevel=%d, MaxTextureAnisotropy=%f", + mMaxTextureDimension, mMaxCubeTextureDimension, mMaxRenderbufferDimension, mMaxTextureLevel, mMaxTextureAnisotropy); + + const D3DFORMAT renderBufferFormats[] = + { + D3DFMT_A8R8G8B8, + D3DFMT_X8R8G8B8, + D3DFMT_R5G6B5, + D3DFMT_D24S8 + }; + + int max = 0; + for (int i = 0; i < sizeof(renderBufferFormats) / sizeof(D3DFORMAT); ++i) + { + bool *multisampleArray = new bool[D3DMULTISAMPLE_16_SAMPLES + 1]; + mDisplay->getMultiSampleSupport(renderBufferFormats[i], multisampleArray); + mMultiSampleSupport[renderBufferFormats[i]] = multisampleArray; + + for (int j = D3DMULTISAMPLE_16_SAMPLES; j >= 0; --j) + { + if (multisampleArray[j] && j != D3DMULTISAMPLE_NONMASKABLE && j > max) + { + max = j; + } + } + } + + mMaxSupportedSamples = max; + + 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(); + mSupportsDepthTextures = mDisplay->getDepthTextureSupport(); + mSupportsTextureFilterAnisotropy = mMaxTextureAnisotropy >= 2.0f; + + 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; + mState.viewportWidth = surface->getWidth(); + mState.viewportHeight = surface->getHeight(); + + mState.scissorX = 0; + mState.scissorY = 0; + mState.scissorWidth = surface->getWidth(); + mState.scissorHeight = surface->getHeight(); + + mHasBeenCurrent = true; + } + + // Wrap the existing Direct3D 9 resources into GL objects and assign them to the '0' names + IDirect3DSurface9 *defaultRenderTarget = surface->getRenderTarget(); + IDirect3DSurface9 *depthStencil = surface->getDepthStencil(); + + Colorbuffer *colorbufferZero = new Colorbuffer(defaultRenderTarget); + DepthStencilbuffer *depthStencilbufferZero = new DepthStencilbuffer(depthStencil); + Framebuffer *framebufferZero = new DefaultFramebuffer(colorbufferZero, depthStencilbufferZero); + + setFramebufferZero(framebufferZero); + + if (defaultRenderTarget) + { + defaultRenderTarget->Release(); + } + + if (depthStencil) + { + depthStencil->Release(); + } + + // Reset pixel shader to null to work around a bug that only happens with Intel GPUs. + // http://crbug.com/110343 + mDevice->SetPixelShader(NULL); + + markAllStateDirty(); +} + +// 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; + } + + mAppliedProgramBinarySerial = 0; + mAppliedRenderTargetSerial = 0; + mAppliedDepthbufferSerial = 0; + mAppliedStencilbufferSerial = 0; + mAppliedIBSerial = 0; + mDepthStencilInitialized = false; + mViewportInitialized = false; + mRenderTargetDescInitialized = false; + + mVertexDeclarationCache.markStateDirty(); + + mClearStateDirty = true; + mCullStateDirty = true; + mDepthStateDirty = true; + mMaskStateDirty = true; + mBlendStateDirty = true; + mStencilStateDirty = true; + mPolygonOffsetStateDirty = true; + mScissorStateDirty = true; + mSampleStateDirty = true; + mDitherStateDirty = true; + mFrontFaceDirty = true; + mDxUniformsDirty = true; +} + +void Context::markDxUniformsDirty() +{ + mDxUniformsDirty = true; +} + +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) +{ + mState.colorClearValue.red = red; + mState.colorClearValue.green = green; + mState.colorClearValue.blue = blue; + mState.colorClearValue.alpha = alpha; +} + +void Context::setClearDepth(float depth) +{ + mState.depthClearValue = depth; +} + +void Context::setClearStencil(int stencil) +{ + mState.stencilClearValue = stencil; +} + +void Context::setCullFace(bool enabled) +{ + if (mState.cullFace != enabled) + { + mState.cullFace = enabled; + mCullStateDirty = true; + } +} + +bool Context::isCullFaceEnabled() const +{ + return mState.cullFace; +} + +void Context::setCullMode(GLenum mode) +{ + if (mState.cullMode != mode) + { + mState.cullMode = mode; + mCullStateDirty = true; + } +} + +void Context::setFrontFace(GLenum front) +{ + if (mState.frontFace != front) + { + mState.frontFace = front; + mFrontFaceDirty = true; + } +} + +void Context::setDepthTest(bool enabled) +{ + if (mState.depthTest != enabled) + { + mState.depthTest = enabled; + mDepthStateDirty = true; + } +} + +bool Context::isDepthTestEnabled() const +{ + return mState.depthTest; +} + +void Context::setDepthFunc(GLenum depthFunc) +{ + if (mState.depthFunc != depthFunc) + { + mState.depthFunc = depthFunc; + mDepthStateDirty = true; + } +} + +void Context::setDepthRange(float zNear, float zFar) +{ + mState.zNear = zNear; + mState.zFar = zFar; +} + +void Context::setBlend(bool enabled) +{ + if (mState.blend != enabled) + { + mState.blend = enabled; + mBlendStateDirty = true; + } +} + +bool Context::isBlendEnabled() const +{ + return mState.blend; +} + +void Context::setBlendFactors(GLenum sourceRGB, GLenum destRGB, GLenum sourceAlpha, GLenum destAlpha) +{ + if (mState.sourceBlendRGB != sourceRGB || + mState.sourceBlendAlpha != sourceAlpha || + mState.destBlendRGB != destRGB || + mState.destBlendAlpha != destAlpha) + { + mState.sourceBlendRGB = sourceRGB; + mState.destBlendRGB = destRGB; + mState.sourceBlendAlpha = sourceAlpha; + mState.destBlendAlpha = destAlpha; + mBlendStateDirty = true; + } +} + +void Context::setBlendColor(float red, float green, float blue, float alpha) +{ + if (mState.blendColor.red != red || + mState.blendColor.green != green || + mState.blendColor.blue != blue || + mState.blendColor.alpha != alpha) + { + mState.blendColor.red = red; + mState.blendColor.green = green; + mState.blendColor.blue = blue; + mState.blendColor.alpha = alpha; + mBlendStateDirty = true; + } +} + +void Context::setBlendEquation(GLenum rgbEquation, GLenum alphaEquation) +{ + if (mState.blendEquationRGB != rgbEquation || + mState.blendEquationAlpha != alphaEquation) + { + mState.blendEquationRGB = rgbEquation; + mState.blendEquationAlpha = alphaEquation; + mBlendStateDirty = true; + } +} + +void Context::setStencilTest(bool enabled) +{ + if (mState.stencilTest != enabled) + { + mState.stencilTest = enabled; + mStencilStateDirty = true; + } +} + +bool Context::isStencilTestEnabled() const +{ + return mState.stencilTest; +} + +void Context::setStencilParams(GLenum stencilFunc, GLint stencilRef, GLuint stencilMask) +{ + if (mState.stencilFunc != stencilFunc || + mState.stencilRef != stencilRef || + mState.stencilMask != stencilMask) + { + mState.stencilFunc = stencilFunc; + mState.stencilRef = (stencilRef > 0) ? stencilRef : 0; + mState.stencilMask = stencilMask; + mStencilStateDirty = true; + } +} + +void Context::setStencilBackParams(GLenum stencilBackFunc, GLint stencilBackRef, GLuint stencilBackMask) +{ + if (mState.stencilBackFunc != stencilBackFunc || + mState.stencilBackRef != stencilBackRef || + mState.stencilBackMask != stencilBackMask) + { + mState.stencilBackFunc = stencilBackFunc; + mState.stencilBackRef = (stencilBackRef > 0) ? stencilBackRef : 0; + mState.stencilBackMask = stencilBackMask; + mStencilStateDirty = true; + } +} + +void Context::setStencilWritemask(GLuint stencilWritemask) +{ + if (mState.stencilWritemask != stencilWritemask) + { + mState.stencilWritemask = stencilWritemask; + mStencilStateDirty = true; + } +} + +void Context::setStencilBackWritemask(GLuint stencilBackWritemask) +{ + if (mState.stencilBackWritemask != stencilBackWritemask) + { + mState.stencilBackWritemask = stencilBackWritemask; + mStencilStateDirty = true; + } +} + +void Context::setStencilOperations(GLenum stencilFail, GLenum stencilPassDepthFail, GLenum stencilPassDepthPass) +{ + if (mState.stencilFail != stencilFail || + mState.stencilPassDepthFail != stencilPassDepthFail || + mState.stencilPassDepthPass != stencilPassDepthPass) + { + mState.stencilFail = stencilFail; + mState.stencilPassDepthFail = stencilPassDepthFail; + mState.stencilPassDepthPass = stencilPassDepthPass; + mStencilStateDirty = true; + } +} + +void Context::setStencilBackOperations(GLenum stencilBackFail, GLenum stencilBackPassDepthFail, GLenum stencilBackPassDepthPass) +{ + if (mState.stencilBackFail != stencilBackFail || + mState.stencilBackPassDepthFail != stencilBackPassDepthFail || + mState.stencilBackPassDepthPass != stencilBackPassDepthPass) + { + mState.stencilBackFail = stencilBackFail; + mState.stencilBackPassDepthFail = stencilBackPassDepthFail; + mState.stencilBackPassDepthPass = stencilBackPassDepthPass; + mStencilStateDirty = true; + } +} + +void Context::setPolygonOffsetFill(bool enabled) +{ + if (mState.polygonOffsetFill != enabled) + { + mState.polygonOffsetFill = enabled; + mPolygonOffsetStateDirty = true; + } +} + +bool Context::isPolygonOffsetFillEnabled() const +{ + return mState.polygonOffsetFill; + +} + +void Context::setPolygonOffsetParams(GLfloat factor, GLfloat units) +{ + if (mState.polygonOffsetFactor != factor || + mState.polygonOffsetUnits != units) + { + mState.polygonOffsetFactor = factor; + mState.polygonOffsetUnits = units; + mPolygonOffsetStateDirty = true; + } +} + +void Context::setSampleAlphaToCoverage(bool enabled) +{ + if (mState.sampleAlphaToCoverage != enabled) + { + mState.sampleAlphaToCoverage = enabled; + mSampleStateDirty = true; + } +} + +bool Context::isSampleAlphaToCoverageEnabled() const +{ + return mState.sampleAlphaToCoverage; +} + +void Context::setSampleCoverage(bool enabled) +{ + if (mState.sampleCoverage != enabled) + { + mState.sampleCoverage = enabled; + mSampleStateDirty = true; + } +} + +bool Context::isSampleCoverageEnabled() const +{ + return mState.sampleCoverage; +} + +void Context::setSampleCoverageParams(GLclampf value, bool invert) +{ + if (mState.sampleCoverageValue != value || + mState.sampleCoverageInvert != invert) + { + mState.sampleCoverageValue = value; + mState.sampleCoverageInvert = invert; + mSampleStateDirty = true; + } +} + +void Context::setScissorTest(bool enabled) +{ + if (mState.scissorTest != enabled) + { + mState.scissorTest = enabled; + mScissorStateDirty = true; + } +} + +bool Context::isScissorTestEnabled() const +{ + return mState.scissorTest; +} + +void Context::setDither(bool enabled) +{ + if (mState.dither != enabled) + { + mState.dither = enabled; + mDitherStateDirty = true; + } +} + +bool Context::isDitherEnabled() const +{ + return mState.dither; +} + +void Context::setLineWidth(GLfloat width) +{ + mState.lineWidth = width; +} + +void Context::setGenerateMipmapHint(GLenum hint) +{ + mState.generateMipmapHint = hint; +} + +void Context::setFragmentShaderDerivativeHint(GLenum hint) +{ + mState.fragmentShaderDerivativeHint = hint; + // TODO: Propagate the hint to shader translator so we can write + // ddx, ddx_coarse, or ddx_fine depending on the hint. + // Ignore for now. It is valid for implementations to ignore hint. +} + +void Context::setViewportParams(GLint x, GLint y, GLsizei width, GLsizei height) +{ + mState.viewportX = x; + mState.viewportY = y; + mState.viewportWidth = width; + mState.viewportHeight = height; +} + +void Context::setScissorParams(GLint x, GLint y, GLsizei width, GLsizei height) +{ + if (mState.scissorX != x || mState.scissorY != y || + mState.scissorWidth != width || mState.scissorHeight != height) + { + mState.scissorX = x; + mState.scissorY = y; + mState.scissorWidth = width; + mState.scissorHeight = height; + mScissorStateDirty = true; + } +} + +void Context::setColorMask(bool red, bool green, bool blue, bool alpha) +{ + if (mState.colorMaskRed != red || mState.colorMaskGreen != green || + mState.colorMaskBlue != blue || mState.colorMaskAlpha != alpha) + { + mState.colorMaskRed = red; + mState.colorMaskGreen = green; + mState.colorMaskBlue = blue; + mState.colorMaskAlpha = alpha; + mMaskStateDirty = true; + } +} + +void Context::setDepthMask(bool mask) +{ + if (mState.depthMask != mask) + { + mState.depthMask = mask; + mMaskStateDirty = true; + } +} + +void Context::setActiveSampler(unsigned int active) +{ + mState.activeSampler = active; +} + +GLuint Context::getReadFramebufferHandle() const +{ + return mState.readFramebuffer; +} + +GLuint Context::getDrawFramebufferHandle() const +{ + return mState.drawFramebuffer; +} + +GLuint Context::getRenderbufferHandle() const +{ + return mState.renderbuffer.id(); +} + +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; +} + +const VertexAttribute &Context::getVertexAttribState(unsigned int attribNum) +{ + return mState.vertexAttribute[attribNum]; +} + +void Context::setVertexAttribState(unsigned int attribNum, Buffer *boundBuffer, GLint size, GLenum type, bool normalized, + GLsizei stride, const void *pointer) +{ + mState.vertexAttribute[attribNum].mBoundBuffer.set(boundBuffer); + mState.vertexAttribute[attribNum].mSize = size; + mState.vertexAttribute[attribNum].mType = type; + mState.vertexAttribute[attribNum].mNormalized = normalized; + mState.vertexAttribute[attribNum].mStride = stride; + mState.vertexAttribute[attribNum].mPointer = pointer; +} + +const void *Context::getVertexAttribPointer(unsigned int attribNum) const +{ + return mState.vertexAttribute[attribNum].mPointer; +} + +const VertexAttributeArray &Context::getVertexAttributes() +{ + return mState.vertexAttribute; +} + +void Context::setPackAlignment(GLint alignment) +{ + mState.packAlignment = alignment; +} + +GLint Context::getPackAlignment() const +{ + return mState.packAlignment; +} + +void Context::setUnpackAlignment(GLint alignment) +{ + mState.unpackAlignment = alignment; +} + +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(); +} + +GLuint Context::createProgram() +{ + return mResourceManager->createProgram(); +} + +GLuint Context::createShader(GLenum type) +{ + return mResourceManager->createShader(type); +} + +GLuint Context::createTexture() +{ + return mResourceManager->createTexture(); +} + +GLuint Context::createRenderbuffer() +{ + return mResourceManager->createRenderbuffer(); +} + +// Returns an unused framebuffer name +GLuint Context::createFramebuffer() +{ + GLuint handle = mFramebufferHandleAllocator.allocate(); + + mFramebufferMap[handle] = NULL; + + return handle; +} + +GLuint Context::createFence() +{ + GLuint handle = mFenceHandleAllocator.allocate(); + + mFenceMap[handle] = new Fence(mDisplay); + + return handle; +} + +// Returns an unused query name +GLuint Context::createQuery() +{ + GLuint handle = mQueryHandleAllocator.allocate(); + + mQueryMap[handle] = NULL; + + return handle; +} + +void Context::deleteBuffer(GLuint buffer) +{ + if (mResourceManager->getBuffer(buffer)) + { + detachBuffer(buffer); + } + + mResourceManager->deleteBuffer(buffer); +} + +void Context::deleteShader(GLuint shader) +{ + mResourceManager->deleteShader(shader); +} + +void Context::deleteProgram(GLuint program) +{ + mResourceManager->deleteProgram(program); +} + +void Context::deleteTexture(GLuint texture) +{ + if (mResourceManager->getTexture(texture)) + { + detachTexture(texture); + } + + mResourceManager->deleteTexture(texture); +} + +void Context::deleteRenderbuffer(GLuint renderbuffer) +{ + if (mResourceManager->getRenderbuffer(renderbuffer)) + { + detachRenderbuffer(renderbuffer); + } + + mResourceManager->deleteRenderbuffer(renderbuffer); +} + +void Context::deleteFramebuffer(GLuint framebuffer) +{ + FramebufferMap::iterator framebufferObject = mFramebufferMap.find(framebuffer); + + if (framebufferObject != mFramebufferMap.end()) + { + detachFramebuffer(framebuffer); + + mFramebufferHandleAllocator.release(framebufferObject->first); + delete framebufferObject->second; + mFramebufferMap.erase(framebufferObject); + } +} + +void Context::deleteFence(GLuint fence) +{ + FenceMap::iterator fenceObject = mFenceMap.find(fence); + + if (fenceObject != mFenceMap.end()) + { + mFenceHandleAllocator.release(fenceObject->first); + delete fenceObject->second; + mFenceMap.erase(fenceObject); + } +} + +void Context::deleteQuery(GLuint query) +{ + QueryMap::iterator queryObject = mQueryMap.find(query); + if (queryObject != mQueryMap.end()) + { + mQueryHandleAllocator.release(queryObject->first); + if (queryObject->second) + { + queryObject->second->release(); + } + mQueryMap.erase(queryObject); + } +} + +Buffer *Context::getBuffer(GLuint handle) +{ + return mResourceManager->getBuffer(handle); +} + +Shader *Context::getShader(GLuint handle) +{ + return mResourceManager->getShader(handle); +} + +Program *Context::getProgram(GLuint handle) +{ + return mResourceManager->getProgram(handle); +} + +Texture *Context::getTexture(GLuint handle) +{ + return mResourceManager->getTexture(handle); +} + +Renderbuffer *Context::getRenderbuffer(GLuint handle) +{ + return mResourceManager->getRenderbuffer(handle); +} + +Framebuffer *Context::getReadFramebuffer() +{ + return getFramebuffer(mState.readFramebuffer); +} + +Framebuffer *Context::getDrawFramebuffer() +{ + return mBoundDrawFramebuffer; +} + +void Context::bindArrayBuffer(unsigned int buffer) +{ + mResourceManager->checkBufferAllocation(buffer); + + mState.arrayBuffer.set(getBuffer(buffer)); +} + +void Context::bindElementArrayBuffer(unsigned int buffer) +{ + mResourceManager->checkBufferAllocation(buffer); + + mState.elementArrayBuffer.set(getBuffer(buffer)); +} + +void Context::bindTexture2D(GLuint texture) +{ + mResourceManager->checkTextureAllocation(texture, TEXTURE_2D); + + mState.samplerTexture[TEXTURE_2D][mState.activeSampler].set(getTexture(texture)); +} + +void Context::bindTextureCubeMap(GLuint texture) +{ + mResourceManager->checkTextureAllocation(texture, TEXTURE_CUBE); + + mState.samplerTexture[TEXTURE_CUBE][mState.activeSampler].set(getTexture(texture)); +} + +void Context::bindReadFramebuffer(GLuint framebuffer) +{ + if (!getFramebuffer(framebuffer)) + { + mFramebufferMap[framebuffer] = new Framebuffer(); + } + + mState.readFramebuffer = framebuffer; +} + +void Context::bindDrawFramebuffer(GLuint framebuffer) +{ + if (!getFramebuffer(framebuffer)) + { + mFramebufferMap[framebuffer] = new Framebuffer(); + } + + mState.drawFramebuffer = framebuffer; + + mBoundDrawFramebuffer = getFramebuffer(framebuffer); +} + +void Context::bindRenderbuffer(GLuint renderbuffer) +{ + mResourceManager->checkRenderbufferAllocation(renderbuffer); + + mState.renderbuffer.set(getRenderbuffer(renderbuffer)); +} + +void Context::useProgram(GLuint program) +{ + GLuint priorProgram = mState.currentProgram; + mState.currentProgram = program; // Must switch before trying to delete, otherwise it only gets flagged. + + if (priorProgram != program) + { + Program *newProgram = mResourceManager->getProgram(program); + Program *oldProgram = mResourceManager->getProgram(priorProgram); + mCurrentProgramBinary.set(NULL); + mDxUniformsDirty = true; + + if (newProgram) + { + newProgram->addRef(); + mCurrentProgramBinary.set(newProgram->getProgramBinary()); + } + + if (oldProgram) + { + oldProgram->release(); + } + } +} + +void Context::linkProgram(GLuint program) +{ + Program *programObject = mResourceManager->getProgram(program); + + bool linked = programObject->link(); + + // if the current program was relinked successfully we + // need to install the new executables + if (linked && program == mState.currentProgram) + { + mCurrentProgramBinary.set(programObject->getProgramBinary()); + mDxUniformsDirty = true; + } +} + +void Context::setProgramBinary(GLuint program, const void *binary, GLint length) +{ + Program *programObject = mResourceManager->getProgram(program); + + bool loaded = programObject->setProgramBinary(binary, length); + + // if the current program was reloaded successfully we + // need to install the new executables + if (loaded && program == mState.currentProgram) + { + mCurrentProgramBinary.set(programObject->getProgramBinary()); + mDxUniformsDirty = true; + } + +} + +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) +{ + Renderbuffer *renderbufferObject = mState.renderbuffer.get(); + renderbufferObject->setStorage(renderbuffer); +} + +Framebuffer *Context::getFramebuffer(unsigned int handle) +{ + FramebufferMap::iterator framebuffer = mFramebufferMap.find(handle); + + if (framebuffer == mFramebufferMap.end()) + { + return NULL; + } + else + { + return framebuffer->second; + } +} + +Fence *Context::getFence(unsigned int handle) +{ + FenceMap::iterator fence = mFenceMap.find(handle); + + if (fence == mFenceMap.end()) + { + return NULL; + } + else + { + return fence->second; + } +} + +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(); +} + +Buffer *Context::getElementArrayBuffer() +{ + return mState.elementArrayBuffer.get(); +} + +ProgramBinary *Context::getCurrentProgramBinary() +{ + return mCurrentProgramBinary.get(); +} + +Texture2D *Context::getTexture2D() +{ + return static_cast<Texture2D*>(getSamplerTexture(mState.activeSampler, TEXTURE_2D)); +} + +TextureCubeMap *Context::getTextureCubeMap() +{ + return static_cast<TextureCubeMap*>(getSamplerTexture(mState.activeSampler, TEXTURE_CUBE)); +} + +Texture *Context::getSamplerTexture(unsigned int sampler, TextureType type) +{ + GLuint texid = mState.samplerTexture[type][sampler].id(); + + if (texid == 0) // Special case: 0 refers to different initial textures based on the target + { + switch (type) + { + default: UNREACHABLE(); + case TEXTURE_2D: return mTexture2DZero.get(); + case TEXTURE_CUBE: return mTextureCubeMapZero.get(); + } + } + + return mState.samplerTexture[type][sampler].get(); +} + +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_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_CONTEXT_ROBUST_ACCESS_EXT: *params = mRobustAccess ? GL_TRUE : GL_FALSE; break; + default: + return false; + } + + return true; +} + +bool Context::getFloatv(GLenum pname, GLfloat *params) +{ + // Please note: DEPTH_CLEAR_VALUE is included in our internal getFloatv implementation + // because it is stored as a float, despite the fact that the GL ES 2.0 spec names + // GetIntegerv as its native query function. As it would require conversion in any + // case, this should make no difference to the calling application. + switch (pname) + { + case GL_LINE_WIDTH: *params = mState.lineWidth; break; + case GL_SAMPLE_COVERAGE_VALUE: *params = mState.sampleCoverageValue; break; + case GL_DEPTH_CLEAR_VALUE: *params = mState.depthClearValue; break; + case GL_POLYGON_OFFSET_FACTOR: *params = mState.polygonOffsetFactor; break; + case GL_POLYGON_OFFSET_UNITS: *params = mState.polygonOffsetUnits; break; + case GL_ALIASED_LINE_WIDTH_RANGE: + params[0] = gl::ALIASED_LINE_WIDTH_RANGE_MIN; + params[1] = gl::ALIASED_LINE_WIDTH_RANGE_MAX; + break; + case GL_ALIASED_POINT_SIZE_RANGE: + params[0] = gl::ALIASED_POINT_SIZE_RANGE_MIN; + params[1] = getMaximumPointSize(); + break; + case GL_DEPTH_RANGE: + params[0] = mState.zNear; + params[1] = mState.zFar; + break; + case GL_COLOR_CLEAR_VALUE: + params[0] = mState.colorClearValue.red; + params[1] = mState.colorClearValue.green; + params[2] = mState.colorClearValue.blue; + params[3] = mState.colorClearValue.alpha; + break; + case GL_BLEND_COLOR: + params[0] = mState.blendColor.red; + params[1] = mState.blendColor.green; + params[2] = mState.blendColor.blue; + params[3] = mState.blendColor.alpha; + break; + case GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT: + if (!supportsTextureFilterAnisotropy()) + { + return false; + } + *params = mMaxTextureAnisotropy; + break; + default: + return false; + } + + return true; +} + +bool Context::getIntegerv(GLenum pname, GLint *params) +{ + // Please note: DEPTH_CLEAR_VALUE is not included in our internal getIntegerv implementation + // because it is stored as a float, despite the fact that the GL ES 2.0 spec names + // GetIntegerv as its native query function. As it would require conversion in any + // case, this should make no difference to the calling application. You may find it in + // Context::getFloatv. + switch (pname) + { + case GL_MAX_VERTEX_ATTRIBS: *params = gl::MAX_VERTEX_ATTRIBS; break; + case GL_MAX_VERTEX_UNIFORM_VECTORS: *params = gl::MAX_VERTEX_UNIFORM_VECTORS; break; + case GL_MAX_VARYING_VECTORS: *params = getMaximumVaryingVectors(); 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; + case GL_NUM_SHADER_BINARY_FORMATS: *params = 0; break; + case GL_SHADER_BINARY_FORMATS: /* no shader binary formats are supported */ break; + case GL_ARRAY_BUFFER_BINDING: *params = mState.arrayBuffer.id(); break; + case GL_ELEMENT_ARRAY_BUFFER_BINDING: *params = mState.elementArrayBuffer.id(); break; + //case GL_FRAMEBUFFER_BINDING: // now equivalent to GL_DRAW_FRAMEBUFFER_BINDING_ANGLE + case GL_DRAW_FRAMEBUFFER_BINDING_ANGLE: *params = mState.drawFramebuffer; break; + case GL_READ_FRAMEBUFFER_BINDING_ANGLE: *params = mState.readFramebuffer; break; + case GL_RENDERBUFFER_BINDING: *params = mState.renderbuffer.id(); break; + case GL_CURRENT_PROGRAM: *params = mState.currentProgram; break; + case GL_PACK_ALIGNMENT: *params = mState.packAlignment; break; + case GL_PACK_REVERSE_ROW_ORDER_ANGLE: *params = mState.packReverseRowOrder; break; + case GL_UNPACK_ALIGNMENT: *params = mState.unpackAlignment; break; + case GL_GENERATE_MIPMAP_HINT: *params = mState.generateMipmapHint; break; + case GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES: *params = mState.fragmentShaderDerivativeHint; break; + case GL_ACTIVE_TEXTURE: *params = (mState.activeSampler + GL_TEXTURE0); break; + case GL_STENCIL_FUNC: *params = mState.stencilFunc; break; + case GL_STENCIL_REF: *params = mState.stencilRef; break; + case GL_STENCIL_VALUE_MASK: *params = mState.stencilMask; break; + case GL_STENCIL_BACK_FUNC: *params = mState.stencilBackFunc; break; + case GL_STENCIL_BACK_REF: *params = mState.stencilBackRef; break; + case GL_STENCIL_BACK_VALUE_MASK: *params = mState.stencilBackMask; break; + case GL_STENCIL_FAIL: *params = mState.stencilFail; break; + case GL_STENCIL_PASS_DEPTH_FAIL: *params = mState.stencilPassDepthFail; break; + case GL_STENCIL_PASS_DEPTH_PASS: *params = mState.stencilPassDepthPass; break; + case GL_STENCIL_BACK_FAIL: *params = mState.stencilBackFail; break; + case GL_STENCIL_BACK_PASS_DEPTH_FAIL: *params = mState.stencilBackPassDepthFail; break; + case GL_STENCIL_BACK_PASS_DEPTH_PASS: *params = mState.stencilBackPassDepthPass; break; + case GL_DEPTH_FUNC: *params = mState.depthFunc; break; + case GL_BLEND_SRC_RGB: *params = mState.sourceBlendRGB; break; + case GL_BLEND_SRC_ALPHA: *params = mState.sourceBlendAlpha; break; + case GL_BLEND_DST_RGB: *params = mState.destBlendRGB; break; + case GL_BLEND_DST_ALPHA: *params = mState.destBlendAlpha; break; + case GL_BLEND_EQUATION_RGB: *params = mState.blendEquationRGB; break; + case GL_BLEND_EQUATION_ALPHA: *params = mState.blendEquationAlpha; break; + case GL_STENCIL_WRITEMASK: *params = mState.stencilWritemask; break; + case GL_STENCIL_BACK_WRITEMASK: *params = mState.stencilBackWritemask; break; + case GL_STENCIL_CLEAR_VALUE: *params = mState.stencilClearValue; break; + case GL_SUBPIXEL_BITS: *params = 4; break; + case GL_MAX_TEXTURE_SIZE: *params = getMaximumTextureDimension(); break; + case GL_MAX_CUBE_MAP_TEXTURE_SIZE: *params = getMaximumCubeTextureDimension(); break; + case GL_NUM_COMPRESSED_TEXTURE_FORMATS: + params[0] = mNumCompressedTextureFormats; + break; + case GL_MAX_SAMPLES_ANGLE: + { + GLsizei maxSamples = getMaxSupportedSamples(); + if (maxSamples != 0) + { + *params = maxSamples; + } + else + { + return false; + } + + break; + } + case GL_SAMPLE_BUFFERS: + case GL_SAMPLES: + { + gl::Framebuffer *framebuffer = getDrawFramebuffer(); + if (framebuffer->completeness() == GL_FRAMEBUFFER_COMPLETE) + { + switch (pname) + { + case GL_SAMPLE_BUFFERS: + if (framebuffer->getSamples() != 0) + { + *params = 1; + } + else + { + *params = 0; + } + break; + case GL_SAMPLES: + *params = framebuffer->getSamples(); + break; + } + } + else + { + *params = 0; + } + } + break; + case GL_IMPLEMENTATION_COLOR_READ_TYPE: + case GL_IMPLEMENTATION_COLOR_READ_FORMAT: + { + GLenum format, type; + if (getCurrentReadFormatType(&format, &type)) + { + if (pname == GL_IMPLEMENTATION_COLOR_READ_FORMAT) + *params = format; + else + *params = type; + } + } + break; + case GL_MAX_VIEWPORT_DIMS: + { + int maxDimension = std::max(getMaximumRenderbufferDimension(), getMaximumTextureDimension()); + params[0] = maxDimension; + params[1] = maxDimension; + } + break; + case GL_COMPRESSED_TEXTURE_FORMATS: + { + 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++ = GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE; + } + } + break; + case GL_VIEWPORT: + params[0] = mState.viewportX; + params[1] = mState.viewportY; + params[2] = mState.viewportWidth; + params[3] = mState.viewportHeight; + break; + case GL_SCISSOR_BOX: + params[0] = mState.scissorX; + params[1] = mState.scissorY; + params[2] = mState.scissorWidth; + params[3] = mState.scissorHeight; + break; + case GL_CULL_FACE_MODE: *params = mState.cullMode; break; + case GL_FRONT_FACE: *params = mState.frontFace; break; + case GL_RED_BITS: + case GL_GREEN_BITS: + case GL_BLUE_BITS: + case GL_ALPHA_BITS: + { + gl::Framebuffer *framebuffer = getDrawFramebuffer(); + gl::Renderbuffer *colorbuffer = framebuffer->getColorbuffer(); + + if (colorbuffer) + { + switch (pname) + { + case GL_RED_BITS: *params = colorbuffer->getRedSize(); break; + case GL_GREEN_BITS: *params = colorbuffer->getGreenSize(); break; + case GL_BLUE_BITS: *params = colorbuffer->getBlueSize(); break; + case GL_ALPHA_BITS: *params = colorbuffer->getAlphaSize(); break; + } + } + else + { + *params = 0; + } + } + break; + case GL_DEPTH_BITS: + { + gl::Framebuffer *framebuffer = getDrawFramebuffer(); + gl::Renderbuffer *depthbuffer = framebuffer->getDepthbuffer(); + + if (depthbuffer) + { + *params = depthbuffer->getDepthSize(); + } + else + { + *params = 0; + } + } + break; + case GL_STENCIL_BITS: + { + gl::Framebuffer *framebuffer = getDrawFramebuffer(); + gl::Renderbuffer *stencilbuffer = framebuffer->getStencilbuffer(); + + if (stencilbuffer) + { + *params = stencilbuffer->getStencilSize(); + } + else + { + *params = 0; + } + } + break; + case GL_TEXTURE_BINDING_2D: + { + if (mState.activeSampler < 0 || mState.activeSampler > getMaximumCombinedTextureImageUnits() - 1) + { + error(GL_INVALID_OPERATION); + return false; + } + + *params = mState.samplerTexture[TEXTURE_2D][mState.activeSampler].id(); + } + break; + case GL_TEXTURE_BINDING_CUBE_MAP: + { + if (mState.activeSampler < 0 || mState.activeSampler > getMaximumCombinedTextureImageUnits() - 1) + { + error(GL_INVALID_OPERATION); + return false; + } + + *params = mState.samplerTexture[TEXTURE_CUBE][mState.activeSampler].id(); + } + break; + case GL_RESET_NOTIFICATION_STRATEGY_EXT: + *params = mResetStrategy; + break; + case GL_NUM_PROGRAM_BINARY_FORMATS_OES: + *params = 1; + break; + case GL_PROGRAM_BINARY_FORMATS_OES: + *params = GL_PROGRAM_BINARY_ANGLE; + break; + default: + return false; + } + + return true; +} + +bool Context::getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *numParams) +{ + // Please note: the query type returned for DEPTH_CLEAR_VALUE in this implementation + // is FLOAT rather than INT, as would be suggested by the GL ES 2.0 spec. This is due + // to the fact that it is stored internally as a float, and so would require conversion + // if returned from Context::getIntegerv. Since this conversion is already implemented + // in the case that one calls glGetIntegerv to retrieve a float-typed state variable, we + // place DEPTH_CLEAR_VALUE with the floats. This should make no difference to the calling + // application. + switch (pname) + { + case GL_COMPRESSED_TEXTURE_FORMATS: + { + *type = GL_INT; + *numParams = mNumCompressedTextureFormats; + } + break; + case GL_SHADER_BINARY_FORMATS: + { + *type = GL_INT; + *numParams = 0; + } + break; + case GL_MAX_VERTEX_ATTRIBS: + case GL_MAX_VERTEX_UNIFORM_VECTORS: + case GL_MAX_VARYING_VECTORS: + case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: + case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS: + case GL_MAX_TEXTURE_IMAGE_UNITS: + case GL_MAX_FRAGMENT_UNIFORM_VECTORS: + case GL_MAX_RENDERBUFFER_SIZE: + case GL_NUM_SHADER_BINARY_FORMATS: + case GL_NUM_COMPRESSED_TEXTURE_FORMATS: + case GL_ARRAY_BUFFER_BINDING: + case GL_FRAMEBUFFER_BINDING: + 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: + case GL_RED_BITS: + case GL_GREEN_BITS: + case GL_BLUE_BITS: + case GL_ALPHA_BITS: + case GL_DEPTH_BITS: + case GL_STENCIL_BITS: + case GL_ELEMENT_ARRAY_BUFFER_BINDING: + case GL_CULL_FACE_MODE: + case GL_FRONT_FACE: + case GL_ACTIVE_TEXTURE: + case GL_STENCIL_FUNC: + case GL_STENCIL_VALUE_MASK: + case GL_STENCIL_REF: + case GL_STENCIL_FAIL: + case GL_STENCIL_PASS_DEPTH_FAIL: + case GL_STENCIL_PASS_DEPTH_PASS: + case GL_STENCIL_BACK_FUNC: + case GL_STENCIL_BACK_VALUE_MASK: + case GL_STENCIL_BACK_REF: + case GL_STENCIL_BACK_FAIL: + case GL_STENCIL_BACK_PASS_DEPTH_FAIL: + case GL_STENCIL_BACK_PASS_DEPTH_PASS: + case GL_DEPTH_FUNC: + case GL_BLEND_SRC_RGB: + case GL_BLEND_SRC_ALPHA: + case GL_BLEND_DST_RGB: + case GL_BLEND_DST_ALPHA: + case GL_BLEND_EQUATION_RGB: + case GL_BLEND_EQUATION_ALPHA: + case GL_STENCIL_WRITEMASK: + case GL_STENCIL_BACK_WRITEMASK: + case GL_STENCIL_CLEAR_VALUE: + case GL_SUBPIXEL_BITS: + case GL_MAX_TEXTURE_SIZE: + case GL_MAX_CUBE_MAP_TEXTURE_SIZE: + case GL_SAMPLE_BUFFERS: + case GL_SAMPLES: + case GL_IMPLEMENTATION_COLOR_READ_TYPE: + case GL_IMPLEMENTATION_COLOR_READ_FORMAT: + case GL_TEXTURE_BINDING_2D: + case GL_TEXTURE_BINDING_CUBE_MAP: + case GL_RESET_NOTIFICATION_STRATEGY_EXT: + case GL_NUM_PROGRAM_BINARY_FORMATS_OES: + case GL_PROGRAM_BINARY_FORMATS_OES: + { + *type = GL_INT; + *numParams = 1; + } + break; + case GL_MAX_SAMPLES_ANGLE: + { + if (getMaxSupportedSamples() != 0) + { + *type = GL_INT; + *numParams = 1; + } + else + { + return false; + } + } + break; + case GL_MAX_VIEWPORT_DIMS: + { + *type = GL_INT; + *numParams = 2; + } + break; + case GL_VIEWPORT: + case GL_SCISSOR_BOX: + { + *type = GL_INT; + *numParams = 4; + } + break; + case GL_SHADER_COMPILER: + case GL_SAMPLE_COVERAGE_INVERT: + case GL_DEPTH_WRITEMASK: + case GL_CULL_FACE: // CULL_FACE through DITHER are natural to IsEnabled, + case GL_POLYGON_OFFSET_FILL: // but can be retrieved through the Get{Type}v queries. + case GL_SAMPLE_ALPHA_TO_COVERAGE: // For this purpose, they are treated here as bool-natural + case GL_SAMPLE_COVERAGE: + case GL_SCISSOR_TEST: + case GL_STENCIL_TEST: + case GL_DEPTH_TEST: + case GL_BLEND: + case GL_DITHER: + case GL_CONTEXT_ROBUST_ACCESS_EXT: + { + *type = GL_BOOL; + *numParams = 1; + } + break; + case GL_COLOR_WRITEMASK: + { + *type = GL_BOOL; + *numParams = 4; + } + break; + case GL_POLYGON_OFFSET_FACTOR: + case GL_POLYGON_OFFSET_UNITS: + case GL_SAMPLE_COVERAGE_VALUE: + case GL_DEPTH_CLEAR_VALUE: + case GL_LINE_WIDTH: + { + *type = GL_FLOAT; + *numParams = 1; + } + break; + case GL_ALIASED_LINE_WIDTH_RANGE: + case GL_ALIASED_POINT_SIZE_RANGE: + case GL_DEPTH_RANGE: + { + *type = GL_FLOAT; + *numParams = 2; + } + break; + case GL_COLOR_CLEAR_VALUE: + case GL_BLEND_COLOR: + { + *type = GL_FLOAT; + *numParams = 4; + } + break; + case GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT: + if (!supportsTextureFilterAnisotropy()) + { + return false; + } + *type = GL_FLOAT; + *numParams = 1; + break; + default: + return false; + } + + return true; +} + +// Applies the render target surface, depth stencil surface, viewport rectangle and +// scissor rectangle to the Direct3D 9 device +bool Context::applyRenderTarget(bool ignoreViewport) +{ + Framebuffer *framebufferObject = getDrawFramebuffer(); + + if (!framebufferObject || framebufferObject->completeness() != GL_FRAMEBUFFER_COMPLETE) + { + return error(GL_INVALID_FRAMEBUFFER_OPERATION, false); + } + + // if there is no color attachment we must synthesize a NULL colorattachment + // to keep the D3D runtime happy. This should only be possible if depth texturing. + Renderbuffer *renderbufferObject = NULL; + if (framebufferObject->getColorbufferType() != GL_NONE) + { + renderbufferObject = framebufferObject->getColorbuffer(); + } + else + { + renderbufferObject = framebufferObject->getNullColorbuffer(); + } + if (!renderbufferObject) + { + ERR("unable to locate renderbuffer for FBO."); + return false; + } + + bool renderTargetChanged = false; + unsigned int renderTargetSerial = renderbufferObject->getSerial(); + if (renderTargetSerial != mAppliedRenderTargetSerial) + { + IDirect3DSurface9 *renderTarget = renderbufferObject->getRenderTarget(); + if (!renderTarget) + { + ERR("render target pointer unexpectedly null."); + 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) + { + Renderbuffer *depthbuffer = framebufferObject->getDepthbuffer(); + depthStencil = depthbuffer->getDepthStencil(); + if (!depthStencil) + { + ERR("Depth stencil pointer unexpectedly null."); + return false; + } + + depthbufferSerial = depthbuffer->getSerial(); + } + else if (framebufferObject->getStencilbufferType() != GL_NONE) + { + Renderbuffer *stencilbuffer = framebufferObject->getStencilbuffer(); + depthStencil = stencilbuffer->getDepthStencil(); + if (!depthStencil) + { + ERR("Depth stencil pointer unexpectedly null."); + return false; + } + + stencilbufferSerial = stencilbuffer->getSerial(); + } + + if (depthbufferSerial != mAppliedDepthbufferSerial || + stencilbufferSerial != mAppliedStencilbufferSerial || + !mDepthStencilInitialized) + { + mDevice->SetDepthStencilSurface(depthStencil); + mAppliedDepthbufferSerial = depthbufferSerial; + mAppliedStencilbufferSerial = stencilbufferSerial; + mDepthStencilInitialized = true; + } + + if (depthStencil) + { + depthStencil->Release(); + } + + if (!mRenderTargetDescInitialized || renderTargetChanged) + { + IDirect3DSurface9 *renderTarget = renderbufferObject->getRenderTarget(); + if (!renderTarget) + { + return false; // Context must be lost + } + renderTarget->GetDesc(&mRenderTargetDesc); + mRenderTargetDescInitialized = true; + renderTarget->Release(); + } + + D3DVIEWPORT9 viewport; + + float zNear = clamp01(mState.zNear); + float zFar = clamp01(mState.zFar); + + if (ignoreViewport) + { + viewport.X = 0; + viewport.Y = 0; + viewport.Width = mRenderTargetDesc.Width; + viewport.Height = mRenderTargetDesc.Height; + viewport.MinZ = 0.0f; + viewport.MaxZ = 1.0f; + } + else + { + viewport.X = clamp(mState.viewportX, 0L, static_cast<LONG>(mRenderTargetDesc.Width)); + viewport.Y = clamp(mState.viewportY, 0L, static_cast<LONG>(mRenderTargetDesc.Height)); + viewport.Width = clamp(mState.viewportWidth, 0L, static_cast<LONG>(mRenderTargetDesc.Width) - static_cast<LONG>(viewport.X)); + viewport.Height = clamp(mState.viewportHeight, 0L, static_cast<LONG>(mRenderTargetDesc.Height) - static_cast<LONG>(viewport.Y)); + viewport.MinZ = zNear; + viewport.MaxZ = zFar; + } + + if (viewport.Width <= 0 || viewport.Height <= 0) + { + return false; // Nothing to render + } + + 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; + rect.left = clamp(mState.scissorX, 0L, static_cast<LONG>(mRenderTargetDesc.Width)); + rect.top = clamp(mState.scissorY, 0L, static_cast<LONG>(mRenderTargetDesc.Height)); + rect.right = clamp(mState.scissorX + mState.scissorWidth, 0L, static_cast<LONG>(mRenderTargetDesc.Width)); + rect.bottom = clamp(mState.scissorY + mState.scissorHeight, 0L, static_cast<LONG>(mRenderTargetDesc.Height)); + mDevice->SetScissorRect(&rect); + mDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE); + } + else + { + mDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE); + } + + mScissorStateDirty = false; + } + + if (mState.currentProgram && mDxUniformsDirty) + { + ProgramBinary *programBinary = getCurrentProgramBinary(); + + GLint halfPixelSize = programBinary->getDxHalfPixelSizeLocation(); + GLfloat xy[2] = {1.0f / viewport.Width, -1.0f / viewport.Height}; + programBinary->setUniform2fv(halfPixelSize, 1, xy); + + // These values are used for computing gl_FragCoord in Program::linkVaryings(). + GLint coord = programBinary->getDxCoordLocation(); + GLfloat whxy[4] = {mState.viewportWidth / 2.0f, mState.viewportHeight / 2.0f, + (float)mState.viewportX + mState.viewportWidth / 2.0f, + (float)mState.viewportY + mState.viewportHeight / 2.0f}; + programBinary->setUniform4fv(coord, 1, whxy); + + GLint depth = programBinary->getDxDepthLocation(); + GLfloat dz[2] = {(zFar - zNear) / 2.0f, (zNear + zFar) / 2.0f}; + programBinary->setUniform2fv(depth, 1, dz); + + GLint depthRange = programBinary->getDxDepthRangeLocation(); + GLfloat nearFarDiff[3] = {zNear, zFar, zFar - zNear}; + programBinary->setUniform3fv(depthRange, 1, nearFarDiff); + mDxUniformsDirty = false; + } + + return true; +} + +// Applies the fixed-function state (culling, depth test, alpha blending, stenciling, etc) to the Direct3D 9 device +void Context::applyState(GLenum drawMode) +{ + ProgramBinary *programBinary = getCurrentProgramBinary(); + + Framebuffer *framebufferObject = getDrawFramebuffer(); + + GLint frontCCW = programBinary->getDxFrontCCWLocation(); + GLint ccw = (mState.frontFace == GL_CCW); + programBinary->setUniform1iv(frontCCW, 1, &ccw); + + GLint pointsOrLines = programBinary->getDxPointsOrLinesLocation(); + GLint alwaysFront = !isTriangleMode(drawMode); + programBinary->setUniform1iv(pointsOrLines, 1, &alwaysFront); + + 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) + { + mDevice->SetRenderState(D3DRS_CULLMODE, es2dx::ConvertCullMode(mState.cullMode, mState.frontFace)); + } + else + { + mDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + } + + mCullStateDirty = false; + } + + if (mDepthStateDirty) + { + if (mState.depthTest) + { + mDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE); + mDevice->SetRenderState(D3DRS_ZFUNC, es2dx::ConvertComparison(mState.depthFunc)); + } + else + { + mDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE); + } + + mDepthStateDirty = false; + } + + if (!zeroColorMaskAllowed && (mMaskStateDirty || mBlendStateDirty)) + { + mBlendStateDirty = true; + mMaskStateDirty = true; + } + + if (mBlendStateDirty) + { + if (mState.blend) + { + 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) + { + mDevice->SetRenderState(D3DRS_BLENDFACTOR, es2dx::ConvertColor(mState.blendColor)); + } + else + { + 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))); + } + + 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) + { + 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 + { + mDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, FALSE); + } + } + else + { + mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + } + + mBlendStateDirty = false; + } + + if (mStencilStateDirty || mFrontFaceDirty) + { + if (mState.stencilTest && framebufferObject->hasStencil()) + { + mDevice->SetRenderState(D3DRS_STENCILENABLE, TRUE); + mDevice->SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, TRUE); + + // FIXME: Unsupported by D3D9 + const D3DRENDERSTATETYPE D3DRS_CCW_STENCILREF = D3DRS_STENCILREF; + const D3DRENDERSTATETYPE D3DRS_CCW_STENCILMASK = D3DRS_STENCILMASK; + const D3DRENDERSTATETYPE D3DRS_CCW_STENCILWRITEMASK = D3DRS_STENCILWRITEMASK; + if (mState.stencilWritemask != mState.stencilBackWritemask || + mState.stencilRef != mState.stencilBackRef || + mState.stencilMask != mState.stencilBackMask) + { + ERR("Separate front/back stencil writemasks, reference values, or stencil mask values are invalid under WebGL."); + return error(GL_INVALID_OPERATION); + } + + // get the maximum size of the stencil ref + gl::Renderbuffer *stencilbuffer = framebufferObject->getStencilbuffer(); + GLuint maxStencil = (1 << stencilbuffer->getStencilSize()) - 1; + + mDevice->SetRenderState(mState.frontFace == GL_CCW ? D3DRS_STENCILWRITEMASK : D3DRS_CCW_STENCILWRITEMASK, mState.stencilWritemask); + mDevice->SetRenderState(mState.frontFace == GL_CCW ? D3DRS_STENCILFUNC : D3DRS_CCW_STENCILFUNC, + es2dx::ConvertComparison(mState.stencilFunc)); + + mDevice->SetRenderState(mState.frontFace == GL_CCW ? D3DRS_STENCILREF : D3DRS_CCW_STENCILREF, (mState.stencilRef < (GLint)maxStencil) ? mState.stencilRef : maxStencil); + mDevice->SetRenderState(mState.frontFace == GL_CCW ? D3DRS_STENCILMASK : D3DRS_CCW_STENCILMASK, mState.stencilMask); + + mDevice->SetRenderState(mState.frontFace == GL_CCW ? D3DRS_STENCILFAIL : D3DRS_CCW_STENCILFAIL, + es2dx::ConvertStencilOp(mState.stencilFail)); + mDevice->SetRenderState(mState.frontFace == GL_CCW ? D3DRS_STENCILZFAIL : D3DRS_CCW_STENCILZFAIL, + es2dx::ConvertStencilOp(mState.stencilPassDepthFail)); + mDevice->SetRenderState(mState.frontFace == GL_CCW ? D3DRS_STENCILPASS : D3DRS_CCW_STENCILPASS, + es2dx::ConvertStencilOp(mState.stencilPassDepthPass)); + + mDevice->SetRenderState(mState.frontFace == GL_CW ? D3DRS_STENCILWRITEMASK : D3DRS_CCW_STENCILWRITEMASK, mState.stencilBackWritemask); + mDevice->SetRenderState(mState.frontFace == GL_CW ? D3DRS_STENCILFUNC : D3DRS_CCW_STENCILFUNC, + es2dx::ConvertComparison(mState.stencilBackFunc)); + + mDevice->SetRenderState(mState.frontFace == GL_CW ? D3DRS_STENCILREF : D3DRS_CCW_STENCILREF, (mState.stencilBackRef < (GLint)maxStencil) ? mState.stencilBackRef : maxStencil); + mDevice->SetRenderState(mState.frontFace == GL_CW ? D3DRS_STENCILMASK : D3DRS_CCW_STENCILMASK, mState.stencilBackMask); + + mDevice->SetRenderState(mState.frontFace == GL_CW ? D3DRS_STENCILFAIL : D3DRS_CCW_STENCILFAIL, + es2dx::ConvertStencilOp(mState.stencilBackFail)); + mDevice->SetRenderState(mState.frontFace == GL_CW ? D3DRS_STENCILZFAIL : D3DRS_CCW_STENCILZFAIL, + es2dx::ConvertStencilOp(mState.stencilBackPassDepthFail)); + mDevice->SetRenderState(mState.frontFace == GL_CW ? D3DRS_STENCILPASS : D3DRS_CCW_STENCILPASS, + es2dx::ConvertStencilOp(mState.stencilBackPassDepthPass)); + } + else + { + mDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE); + } + + mStencilStateDirty = false; + mFrontFaceDirty = false; + } + + if (mMaskStateDirty) + { + 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; + } + + if (mPolygonOffsetStateDirty) + { + if (mState.polygonOffsetFill) + { + gl::Renderbuffer *depthbuffer = framebufferObject->getDepthbuffer(); + if (depthbuffer) + { + mDevice->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, *((DWORD*)&mState.polygonOffsetFactor)); + float depthBias = ldexp(mState.polygonOffsetUnits, -(int)(depthbuffer->getDepthSize())); + mDevice->SetRenderState(D3DRS_DEPTHBIAS, *((DWORD*)&depthBias)); + } + } + else + { + mDevice->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, 0); + mDevice->SetRenderState(D3DRS_DEPTHBIAS, 0); + } + + mPolygonOffsetStateDirty = false; + } + + if (mSampleStateDirty) + { + if (mState.sampleAlphaToCoverage) + { + FIXME("Sample alpha to coverage is unimplemented."); + } + + mDevice->SetRenderState(D3DRS_MULTISAMPLEANTIALIAS, TRUE); + if (mState.sampleCoverage) + { + unsigned int mask = 0; + if (mState.sampleCoverageValue != 0) + { + float threshold = 0.5f; + + for (int i = 0; i < framebufferObject->getSamples(); ++i) + { + mask <<= 1; + + if ((i + 1) * mState.sampleCoverageValue >= threshold) + { + threshold += 1.0f; + mask |= 1; + } + } + } + + if (mState.sampleCoverageInvert) + { + mask = ~mask; + } + + mDevice->SetRenderState(D3DRS_MULTISAMPLEMASK, mask); + } + else + { + mDevice->SetRenderState(D3DRS_MULTISAMPLEMASK, 0xFFFFFFFF); + } + + mSampleStateDirty = false; + } + + if (mDitherStateDirty) + { + mDevice->SetRenderState(D3DRS_DITHERENABLE, mState.dither ? TRUE : FALSE); + + mDitherStateDirty = false; + } +} + +GLenum Context::applyVertexBuffer(GLint first, GLsizei count, GLsizei instances, GLsizei *repeatDraw) +{ + TranslatedAttribute attributes[MAX_VERTEX_ATTRIBS]; + + GLenum err = mVertexDataManager->prepareVertexData(first, count, attributes, instances); + if (err != GL_NO_ERROR) + { + return err; + } + + ProgramBinary *programBinary = getCurrentProgramBinary(); + return mVertexDeclarationCache.applyDeclaration(mDevice, attributes, programBinary, instances, repeatDraw); +} + +// Applies the indices and element array bindings to the Direct3D 9 device +GLenum Context::applyIndexBuffer(const GLvoid *indices, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo) +{ + GLenum err = mIndexDataManager->prepareIndexData(type, count, mState.elementArrayBuffer.get(), indices, indexInfo); + + if (err == GL_NO_ERROR) + { + if (indexInfo->serial != mAppliedIBSerial) + { + mDevice->SetIndices(indexInfo->indexBuffer); + mAppliedIBSerial = indexInfo->serial; + } + } + + return err; +} + +// Applies the shaders and shader constants to the Direct3D 9 device +void Context::applyShaders() +{ + ProgramBinary *programBinary = getCurrentProgramBinary(); + + if (programBinary->getSerial() != mAppliedProgramBinarySerial) + { + IDirect3DVertexShader9 *vertexShader = programBinary->getVertexShader(); + IDirect3DPixelShader9 *pixelShader = programBinary->getPixelShader(); + + mDevice->SetPixelShader(pixelShader); + mDevice->SetVertexShader(vertexShader); + programBinary->dirtyAllUniforms(); + mAppliedProgramBinarySerial = programBinary->getSerial(); + } + + programBinary->applyUniforms(); +} + +// Applies the textures and sampler states to the Direct3D 9 device +void Context::applyTextures() +{ + 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) +{ + ProgramBinary *programBinary = getCurrentProgramBinary(); + + 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 = programBinary->getUsedSamplerRange(type); + + for (int samplerIndex = 0; samplerIndex < samplerRange; samplerIndex++) + { + int textureUnit = programBinary->getSamplerMapping(type, samplerIndex); // OpenGL texture image unit index + int d3dSampler = samplerIndex + d3dSamplerOffset; + + if (textureUnit != -1) + { + TextureType textureType = programBinary->getSamplerTextureType(type, samplerIndex); + + Texture *texture = getSamplerTexture(textureUnit, textureType); + unsigned int texSerial = texture->getTextureSerial(); + + if (appliedTextureSerial[samplerIndex] != texSerial || texture->hasDirtyParameters() || texture->hasDirtyImages()) + { + IDirect3DBaseTexture9 *d3dTexture = texture->getTexture(); + + if (d3dTexture) + { + if (appliedTextureSerial[samplerIndex] != texSerial || texture->hasDirtyParameters()) + { + GLenum wrapS = texture->getWrapS(); + GLenum wrapT = texture->getWrapT(); + GLenum minFilter = texture->getMinFilter(); + GLenum magFilter = texture->getMagFilter(); + float maxAnisotropy = texture->getMaxAnisotropy(); + + mDevice->SetSamplerState(d3dSampler, D3DSAMP_ADDRESSU, es2dx::ConvertTextureWrap(wrapS)); + mDevice->SetSamplerState(d3dSampler, D3DSAMP_ADDRESSV, es2dx::ConvertTextureWrap(wrapT)); + + mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAGFILTER, es2dx::ConvertMagFilter(magFilter, maxAnisotropy)); + D3DTEXTUREFILTERTYPE d3dMinFilter, d3dMipFilter; + es2dx::ConvertMinFilter(minFilter, &d3dMinFilter, &d3dMipFilter, maxAnisotropy); + mDevice->SetSamplerState(d3dSampler, D3DSAMP_MINFILTER, d3dMinFilter); + mDevice->SetSamplerState(d3dSampler, D3DSAMP_MIPFILTER, d3dMipFilter); + mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAXMIPLEVEL, texture->getLodOffset()); + + if (supportsTextureFilterAnisotropy()) + { + mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAXANISOTROPY, (DWORD)maxAnisotropy); + } + } + + if (appliedTextureSerial[samplerIndex] != texSerial || texture->hasDirtyImages()) + { + mDevice->SetTexture(d3dSampler, d3dTexture); + } + } + else + { + mDevice->SetTexture(d3dSampler, getIncompleteTexture(textureType)->getTexture()); + } + + appliedTextureSerial[samplerIndex] = texSerial; + texture->resetDirty(); + } + } + else + { + if (appliedTextureSerial[samplerIndex] != 0) + { + 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, GLsizei *bufSize, void* pixels) +{ + Framebuffer *framebuffer = getReadFramebuffer(); + + if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE) + { + return error(GL_INVALID_FRAMEBUFFER_OPERATION); + } + + if (getReadFramebufferHandle() != 0 && framebuffer->getSamples() != 0) + { + return error(GL_INVALID_OPERATION); + } + + GLsizei outputPitch = ComputePitch(width, ConvertSizedInternalFormat(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 + } + + D3DSURFACE_DESC desc; + renderTarget->GetDesc(&desc); + + if (desc.MultiSampleType != D3DMULTISAMPLE_NONE) + { + UNIMPLEMENTED(); // FIXME: Requires resolve using StretchRect into non-multisampled render target + renderTarget->Release(); + return error(GL_OUT_OF_MEMORY); + } + + 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 (!directToPixels) + { + result = mDevice->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, + D3DPOOL_SYSTEMMEM, &systemSurface, NULL); + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + renderTarget->Release(); + return error(GL_OUT_OF_MEMORY); + } + } + + result = mDevice->GetRenderTargetData(renderTarget, systemSurface); + renderTarget->Release(); + renderTarget = NULL; + + if (FAILED(result)) + { + systemSurface->Release(); + + // It turns out that D3D will sometimes produce more error + // codes than those documented. + if (checkDeviceLost(result)) + return error(GL_OUT_OF_MEMORY); + else + { + UNREACHABLE(); + return; + } + + } + + if (directToPixels) + { + systemSurface->Release(); + return; + } + + RECT rect; + rect.left = clamp(x, 0L, static_cast<LONG>(desc.Width)); + rect.top = clamp(y, 0L, static_cast<LONG>(desc.Height)); + rect.right = clamp(x + width, 0L, static_cast<LONG>(desc.Width)); + rect.bottom = clamp(y + height, 0L, static_cast<LONG>(desc.Height)); + + D3DLOCKED_RECT lock; + result = systemSurface->LockRect(&lock, &rect, D3DLOCK_READONLY); + + if (FAILED(result)) + { + UNREACHABLE(); + systemSurface->Release(); + + return; // No sensible error to generate + } + + unsigned char *dest = (unsigned char*)pixels; + unsigned short *dest16 = (unsigned short*)pixels; + + unsigned char *source; + int inputPitch; + if (getPackReverseRowOrder()) + { + source = ((unsigned char*)lock.pBits) + lock.Pitch * (rect.bottom - rect.top - 1); + inputPitch = -lock.Pitch; + } + else + { + source = (unsigned char*)lock.pBits; + inputPitch = lock.Pitch; + } + + unsigned int fastPixelSize = 0; + + if (desc.Format == D3DFMT_A8R8G8B8 && + format == GL_BGRA_EXT && + type == GL_UNSIGNED_BYTE) + { + fastPixelSize = 4; + } + else if ((desc.Format == D3DFMT_A4R4G4B4 && + format == GL_BGRA_EXT && + type == GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT) || + (desc.Format == D3DFMT_A1R5G5B5 && + format == GL_BGRA_EXT && + type == GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT)) + { + fastPixelSize = 2; + } + else if (desc.Format == D3DFMT_A16B16G16R16F && + format == GL_RGBA && + type == GL_HALF_FLOAT_OES) + { + fastPixelSize = 8; + } + else if (desc.Format == D3DFMT_A32B32G32R32F && + format == GL_RGBA && + type == GL_FLOAT) + { + fastPixelSize = 16; + } + + for (int j = 0; j < rect.bottom - rect.top; j++) + { + if (fastPixelSize != 0) + { + // Fast path for formats which require no translation: + // D3DFMT_A8R8G8B8 to BGRA/UNSIGNED_BYTE + // D3DFMT_A4R4G4B4 to BGRA/UNSIGNED_SHORT_4_4_4_4_REV_EXT + // D3DFMT_A1R5G5B5 to BGRA/UNSIGNED_SHORT_1_5_5_5_REV_EXT + // D3DFMT_A16B16G16R16F to RGBA/HALF_FLOAT_OES + // D3DFMT_A32B32G32R32F to RGBA/FLOAT + // + // Note that buffers with no alpha go through the slow path below. + memcpy(dest + j * outputPitch, + source + j * inputPitch, + (rect.right - rect.left) * fastPixelSize); + continue; + } + + for (int i = 0; i < rect.right - rect.left; i++) + { + float r; + float g; + float b; + float a; + + switch (desc.Format) + { + case D3DFMT_R5G6B5: + { + unsigned short rgb = *(unsigned short*)(source + 2 * i + j * inputPitch); + + a = 1.0f; + b = (rgb & 0x001F) * (1.0f / 0x001F); + g = (rgb & 0x07E0) * (1.0f / 0x07E0); + r = (rgb & 0xF800) * (1.0f / 0xF800); + } + break; + case D3DFMT_A1R5G5B5: + { + unsigned short argb = *(unsigned short*)(source + 2 * i + j * inputPitch); + + a = (argb & 0x8000) ? 1.0f : 0.0f; + b = (argb & 0x001F) * (1.0f / 0x001F); + g = (argb & 0x03E0) * (1.0f / 0x03E0); + r = (argb & 0x7C00) * (1.0f / 0x7C00); + } + break; + case D3DFMT_A8R8G8B8: + { + unsigned int argb = *(unsigned int*)(source + 4 * i + j * inputPitch); + + a = (argb & 0xFF000000) * (1.0f / 0xFF000000); + b = (argb & 0x000000FF) * (1.0f / 0x000000FF); + g = (argb & 0x0000FF00) * (1.0f / 0x0000FF00); + r = (argb & 0x00FF0000) * (1.0f / 0x00FF0000); + } + break; + case D3DFMT_X8R8G8B8: + { + unsigned int xrgb = *(unsigned int*)(source + 4 * i + j * inputPitch); + + a = 1.0f; + b = (xrgb & 0x000000FF) * (1.0f / 0x000000FF); + g = (xrgb & 0x0000FF00) * (1.0f / 0x0000FF00); + r = (xrgb & 0x00FF0000) * (1.0f / 0x00FF0000); + } + break; + case D3DFMT_A2R10G10B10: + { + unsigned int argb = *(unsigned int*)(source + 4 * i + j * inputPitch); + + a = (argb & 0xC0000000) * (1.0f / 0xC0000000); + b = (argb & 0x000003FF) * (1.0f / 0x000003FF); + g = (argb & 0x000FFC00) * (1.0f / 0x000FFC00); + r = (argb & 0x3FF00000) * (1.0f / 0x3FF00000); + } + break; + case D3DFMT_A32B32G32R32F: + { + // float formats in D3D are stored rgba, rather than the other way round + 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: + { + // float formats in D3D are stored rgba, rather than the other way round + r = float16ToFloat32(*((unsigned short*)(source + 8 * i + j * inputPitch) + 0)); + g = float16ToFloat32(*((unsigned short*)(source + 8 * i + j * inputPitch) + 1)); + b = float16ToFloat32(*((unsigned short*)(source + 8 * i + j * inputPitch) + 2)); + a = float16ToFloat32(*((unsigned short*)(source + 8 * i + j * inputPitch) + 3)); + } + break; + default: + UNIMPLEMENTED(); // FIXME + UNREACHABLE(); + return; + } + + switch (format) + { + case GL_RGBA: + switch (type) + { + case GL_UNSIGNED_BYTE: + dest[4 * i + j * outputPitch + 0] = (unsigned char)(255 * r + 0.5f); + dest[4 * i + j * outputPitch + 1] = (unsigned char)(255 * g + 0.5f); + dest[4 * i + j * outputPitch + 2] = (unsigned char)(255 * b + 0.5f); + dest[4 * i + j * outputPitch + 3] = (unsigned char)(255 * a + 0.5f); + break; + default: UNREACHABLE(); + } + break; + case GL_BGRA_EXT: + switch (type) + { + case GL_UNSIGNED_BYTE: + dest[4 * i + j * outputPitch + 0] = (unsigned char)(255 * b + 0.5f); + dest[4 * i + j * outputPitch + 1] = (unsigned char)(255 * g + 0.5f); + dest[4 * i + j * outputPitch + 2] = (unsigned char)(255 * r + 0.5f); + dest[4 * i + j * outputPitch + 3] = (unsigned char)(255 * a + 0.5f); + break; + case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT: + // According to the desktop GL spec in the "Transfer of Pixel Rectangles" section + // this type is packed as follows: + // 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 + // -------------------------------------------------------------------------------- + // | 4th | 3rd | 2nd | 1st component | + // -------------------------------------------------------------------------------- + // in the case of BGRA_EXT, B is the first component, G the second, and so forth. + dest16[i + j * outputPitch / sizeof(unsigned short)] = + ((unsigned short)(15 * a + 0.5f) << 12)| + ((unsigned short)(15 * r + 0.5f) << 8) | + ((unsigned short)(15 * g + 0.5f) << 4) | + ((unsigned short)(15 * b + 0.5f) << 0); + break; + case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT: + // According to the desktop GL spec in the "Transfer of Pixel Rectangles" section + // this type is packed as follows: + // 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 + // -------------------------------------------------------------------------------- + // | 4th | 3rd | 2nd | 1st component | + // -------------------------------------------------------------------------------- + // in the case of BGRA_EXT, B is the first component, G the second, and so forth. + dest16[i + j * outputPitch / sizeof(unsigned short)] = + ((unsigned short)( a + 0.5f) << 15) | + ((unsigned short)(31 * r + 0.5f) << 10) | + ((unsigned short)(31 * g + 0.5f) << 5) | + ((unsigned short)(31 * b + 0.5f) << 0); + break; + default: UNREACHABLE(); + } + break; + case GL_RGB: + switch (type) + { + case GL_UNSIGNED_SHORT_5_6_5: + dest16[i + j * outputPitch / sizeof(unsigned short)] = + ((unsigned short)(31 * b + 0.5f) << 0) | + ((unsigned short)(63 * g + 0.5f) << 5) | + ((unsigned short)(31 * r + 0.5f) << 11); + break; + case GL_UNSIGNED_BYTE: + dest[3 * i + j * outputPitch + 0] = (unsigned char)(255 * r + 0.5f); + dest[3 * i + j * outputPitch + 1] = (unsigned char)(255 * g + 0.5f); + dest[3 * i + j * outputPitch + 2] = (unsigned char)(255 * b + 0.5f); + break; + default: UNREACHABLE(); + } + break; + default: UNREACHABLE(); + } + } + } + + systemSurface->UnlockRect(); + + systemSurface->Release(); +} + +void Context::clear(GLbitfield mask) +{ + Framebuffer *framebufferObject = getDrawFramebuffer(); + + if (!framebufferObject || framebufferObject->completeness() != GL_FRAMEBUFFER_COMPLETE) + { + return error(GL_INVALID_FRAMEBUFFER_OPERATION); + } + + DWORD flags = 0; + + if (mask & GL_COLOR_BUFFER_BIT) + { + mask &= ~GL_COLOR_BUFFER_BIT; + + if (framebufferObject->getColorbufferType() != GL_NONE) + { + flags |= D3DCLEAR_TARGET; + } + } + + if (mask & GL_DEPTH_BUFFER_BIT) + { + mask &= ~GL_DEPTH_BUFFER_BIT; + if (mState.depthMask && framebufferObject->getDepthbufferType() != GL_NONE) + { + flags |= D3DCLEAR_ZBUFFER; + } + } + + GLuint stencilUnmasked = 0x0; + + if (mask & GL_STENCIL_BUFFER_BIT) + { + mask &= ~GL_STENCIL_BUFFER_BIT; + if (framebufferObject->getStencilbufferType() != GL_NONE) + { + IDirect3DSurface9 *depthStencil = framebufferObject->getStencilbuffer()->getDepthStencil(); + if (!depthStencil) + { + ERR("Depth stencil pointer unexpectedly null."); + return; + } + + D3DSURFACE_DESC desc; + depthStencil->GetDesc(&desc); + depthStencil->Release(); + + unsigned int stencilSize = dx2es::GetStencilSize(desc.Format); + stencilUnmasked = (0x1 << stencilSize) - 1; + + if (stencilUnmasked != 0x0) + { + flags |= D3DCLEAR_STENCIL; + } + } + } + + if (mask != 0) + { + return error(GL_INVALID_VALUE); + } + + if (!applyRenderTarget(true)) // Clips the clear to the scissor rectangle but not the viewport + { + return; + } + + D3DCOLOR color = D3DCOLOR_ARGB(unorm<8>(mState.colorClearValue.alpha), + 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; + + bool alphaUnmasked = (dx2es::GetAlphaSize(mRenderTargetDesc.Format) == 0) || mState.colorMaskAlpha; + + const bool needMaskedStencilClear = (flags & D3DCLEAR_STENCIL) && + (mState.stencilWritemask & stencilUnmasked) != stencilUnmasked; + const bool needMaskedColorClear = (flags & D3DCLEAR_TARGET) && + !(mState.colorMaskRed && mState.colorMaskGreen && + mState.colorMaskBlue && alphaUnmasked); + + if (needMaskedColorClear || needMaskedStencilClear) + { + // State which is altered in all paths from this point to the clear call is saved. + // State which is altered in only some paths will be flagged dirty in the case that + // that path is taken. + HRESULT hr; + if (mMaskedClearSavedState == NULL) + { + hr = mDevice->BeginStateBlock(); + ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY); + + 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); + } + + ASSERT(mMaskedClearSavedState != NULL); + + if (mMaskedClearSavedState != NULL) + { + hr = mMaskedClearSavedState->Capture(); + ASSERT(SUCCEEDED(hr)); + } + + 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) + { + mDevice->SetRenderState(D3DRS_COLORWRITEENABLE, es2dx::ConvertColorMask(mState.colorMaskRed, mState.colorMaskGreen, mState.colorMaskBlue, mState.colorMaskAlpha)); + } + else + { + mDevice->SetRenderState(D3DRS_COLORWRITEENABLE, 0); + } + + if (stencilUnmasked != 0x0 && (flags & D3DCLEAR_STENCIL)) + { + 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 + { + mDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE); + } + + 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++) + { + 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; + + 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) + { + mDevice->SetRenderState(D3DRS_ZENABLE, TRUE); + mDevice->SetRenderState(D3DRS_ZWRITEENABLE, TRUE); + mDevice->Clear(0, NULL, D3DCLEAR_ZBUFFER, color, depth, stencil); + } + + if (mMaskedClearSavedState != NULL) + { + mMaskedClearSavedState->Apply(); + } + } + else if (flags) + { + mDevice->Clear(0, NULL, flags, color, depth, stencil); + } +} + +void Context::drawArrays(GLenum mode, GLint first, GLsizei count, GLsizei instances) +{ + if (!mState.currentProgram) + { + return error(GL_INVALID_OPERATION); + } + + D3DPRIMITIVETYPE primitiveType; + int primitiveCount; + + if(!es2dx::ConvertPrimitiveType(mode, count, &primitiveType, &primitiveCount)) + return error(GL_INVALID_ENUM); + + if (primitiveCount <= 0) + { + return; + } + + if (!applyRenderTarget(false)) + { + return; + } + + applyState(mode); + + GLsizei repeatDraw = 1; + GLenum err = applyVertexBuffer(first, count, instances, &repeatDraw); + if (err != GL_NO_ERROR) + { + return error(err); + } + + applyShaders(); + applyTextures(); + + if (!getCurrentProgramBinary()->validateSamplers(NULL)) + { + return error(GL_INVALID_OPERATION); + } + + if (!skipDraw(mode)) + { + mDisplay->startScene(); + + 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(); + } + + 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 + { + mDevice->DrawPrimitive(primitiveType, 0, primitiveCount); + } + } +} + +void Context::drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei instances) +{ + if (!mState.currentProgram) + { + return error(GL_INVALID_OPERATION); + } + + if (!indices && !mState.elementArrayBuffer) + { + return error(GL_INVALID_OPERATION); + } + + D3DPRIMITIVETYPE primitiveType; + int primitiveCount; + + if(!es2dx::ConvertPrimitiveType(mode, count, &primitiveType, &primitiveCount)) + return error(GL_INVALID_ENUM); + + if (primitiveCount <= 0) + { + return; + } + + if (!applyRenderTarget(false)) + { + return; + } + + applyState(mode); + + TranslatedIndexData indexInfo; + GLenum err = applyIndexBuffer(indices, count, mode, type, &indexInfo); + if (err != GL_NO_ERROR) + { + return error(err); + } + + GLsizei vertexCount = indexInfo.maxIndex - indexInfo.minIndex + 1; + GLsizei repeatDraw = 1; + err = applyVertexBuffer(indexInfo.minIndex, vertexCount, instances, &repeatDraw); + if (err != GL_NO_ERROR) + { + return error(err); + } + + applyShaders(); + applyTextures(); + + if (!getCurrentProgramBinary()->validateSamplers(false)) + { + return error(GL_INVALID_OPERATION); + } + + if (!skipDraw(mode)) + { + mDisplay->startScene(); + + if (mode == GL_LINE_LOOP) + { + drawLineLoop(count, type, indices, indexInfo.minIndex); + } + else + { + for (int i = 0; i < repeatDraw; i++) + { + mDevice->DrawIndexedPrimitive(primitiveType, -(INT)indexInfo.minIndex, indexInfo.minIndex, vertexCount, indexInfo.startIndex, primitiveCount); + } + } + } +} + +// Implements glFlush when block is false, glFinish when block is true +void Context::sync(bool block) +{ + mDisplay->sync(block); +} + +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()) + { + Buffer *indexBuffer = mState.elementArrayBuffer.get(); + intptr_t offset = reinterpret_cast<intptr_t>(indices); + indices = static_cast<const GLubyte*>(indexBuffer->data()) + offset; + } + + UINT startIndex = 0; + bool succeeded = false; + + if (supports32bitIndices()) + { + const int spaceNeeded = (count + 1) * sizeof(unsigned int); + + if (!mLineLoopIB) + { + mLineLoopIB = new StreamingIndexBuffer(mDevice, INITIAL_INDEX_BUFFER_SIZE, D3DFMT_INDEX32); + } + + if (mLineLoopIB) + { + mLineLoopIB->reserveSpace(spaceNeeded, GL_UNSIGNED_INT); + + UINT offset = 0; + unsigned int *data = static_cast<unsigned int*>(mLineLoopIB->map(spaceNeeded, &offset)); + startIndex = offset / 4; + + if (data) + { + 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 + { + const int spaceNeeded = (count + 1) * sizeof(unsigned short); + + if (!mLineLoopIB) + { + mLineLoopIB = new StreamingIndexBuffer(mDevice, INITIAL_INDEX_BUFFER_SIZE, D3DFMT_INDEX16); + } + + 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) + { + 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) + { + if (mAppliedIBSerial != mLineLoopIB->getSerial()) + { + mDevice->SetIndices(mLineLoopIB->getBuffer()); + mAppliedIBSerial = mLineLoopIB->getSerial(); + } + + mDevice->DrawIndexedPrimitive(D3DPT_LINESTRIP, -minIndex, minIndex, count, startIndex, count); + } + else + { + ERR("Could not create a looping index buffer for GL_LINE_LOOP."); + return error(GL_OUT_OF_MEMORY); + } +} + +void Context::recordInvalidEnum() +{ + mInvalidEnum = true; +} + +void Context::recordInvalidValue() +{ + mInvalidValue = true; +} + +void Context::recordInvalidOperation() +{ + mInvalidOperation = true; +} + +void Context::recordOutOfMemory() +{ + mOutOfMemory = true; +} + +void Context::recordInvalidFramebufferOperation() +{ + mInvalidFramebufferOperation = true; +} + +// Get one of the recorded errors and clear its flag, if any. +// [OpenGL ES 2.0.24] section 2.5 page 13. +GLenum Context::getError() +{ + if (mInvalidEnum) + { + mInvalidEnum = false; + + return GL_INVALID_ENUM; + } + + if (mInvalidValue) + { + mInvalidValue = false; + + return GL_INVALID_VALUE; + } + + if (mInvalidOperation) + { + mInvalidOperation = false; + + return GL_INVALID_OPERATION; + } + + if (mOutOfMemory) + { + mOutOfMemory = false; + + return GL_OUT_OF_MEMORY; + } + + if (mInvalidFramebufferOperation) + { + mInvalidFramebufferOperation = false; + + return GL_INVALID_FRAMEBUFFER_OPERATION; + } + + 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; +} + +float Context::getMaximumPointSize() const +{ + return mSupportsShaderModel3 ? mMaximumPointSize : ALIASED_POINT_SIZE_RANGE_MAX_SM2; +} + +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; +} + +int Context::getMaxSupportedSamples() const +{ + return mMaxSupportedSamples; +} + +int Context::getNearestSupportedSamples(D3DFORMAT format, int requested) const +{ + if (requested == 0) + { + return requested; + } + + std::map<D3DFORMAT, bool *>::const_iterator itr = mMultiSampleSupport.find(format); + if (itr == mMultiSampleSupport.end()) + { + return -1; + } + + for (int i = requested; i <= D3DMULTISAMPLE_16_SAMPLES; ++i) + { + if (itr->second[i] && i != D3DMULTISAMPLE_NONMASKABLE) + { + return i; + } + } + + return -1; +} + +bool Context::supportsEventQueries() const +{ + return mSupportsEventQueries; +} + +bool Context::supportsOcclusionQueries() const +{ + return mSupportsOcclusionQueries; +} + +bool Context::supportsDXT1Textures() const +{ + return mSupportsDXT1Textures; +} + +bool Context::supportsDXT3Textures() const +{ + return mSupportsDXT3Textures; +} + +bool Context::supportsDXT5Textures() const +{ + return mSupportsDXT5Textures; +} + +bool Context::supportsFloat32Textures() const +{ + return mSupportsFloat32Textures; +} + +bool Context::supportsFloat32LinearFilter() const +{ + return mSupportsFloat32LinearFilter; +} + +bool Context::supportsFloat32RenderableTextures() const +{ + return mSupportsFloat32RenderableTextures; +} + +bool Context::supportsFloat16Textures() const +{ + return mSupportsFloat16Textures; +} + +bool Context::supportsFloat16LinearFilter() const +{ + return mSupportsFloat16LinearFilter; +} + +bool Context::supportsFloat16RenderableTextures() const +{ + return mSupportsFloat16RenderableTextures; +} + +int Context::getMaximumRenderbufferDimension() const +{ + return mMaxRenderbufferDimension; +} + +int Context::getMaximumTextureDimension() const +{ + return mMaxTextureDimension; +} + +int Context::getMaximumCubeTextureDimension() const +{ + return mMaxCubeTextureDimension; +} + +int Context::getMaximumTextureLevel() const +{ + return mMaxTextureLevel; +} + +bool Context::supportsLuminanceTextures() const +{ + return mSupportsLuminanceTextures; +} + +bool Context::supportsLuminanceAlphaTextures() const +{ + return mSupportsLuminanceAlphaTextures; +} + +bool Context::supportsDepthTextures() const +{ + return mSupportsDepthTextures; +} + +bool Context::supports32bitIndices() const +{ + return mSupports32bitIndices; +} + +bool Context::supportsNonPower2Texture() const +{ + return mSupportsNonPower2Texture; +} + +bool Context::supportsInstancing() const +{ + return mSupportsInstancing; +} + +bool Context::supportsTextureFilterAnisotropy() const +{ + return mSupportsTextureFilterAnisotropy; +} + +float Context::getTextureMaxAnisotropy() const +{ + return mMaxTextureAnisotropy; +} + +bool Context::getCurrentReadFormatType(GLenum *format, GLenum *type) +{ + Framebuffer *framebuffer = getReadFramebuffer(); + if (!framebuffer || framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE) + { + return error(GL_INVALID_OPERATION, false); + } + + Renderbuffer *renderbuffer = framebuffer->getColorbuffer(); + if (!renderbuffer) + { + return error(GL_INVALID_OPERATION, false); + } + + if(!dx2es::ConvertReadBufferFormat(renderbuffer->getD3DFormat(), format, type)) + { + ASSERT(false); + return false; + } + + return true; +} + +void Context::detachBuffer(GLuint buffer) +{ + // [OpenGL ES 2.0.24] section 2.9 page 22: + // If a buffer object is deleted while it is bound, all bindings to that object in the current context + // (i.e. in the thread that called Delete-Buffers) are reset to zero. + + if (mState.arrayBuffer.id() == buffer) + { + mState.arrayBuffer.set(NULL); + } + + if (mState.elementArrayBuffer.id() == buffer) + { + mState.elementArrayBuffer.set(NULL); + } + + for (int attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++) + { + if (mState.vertexAttribute[attribute].mBoundBuffer.id() == buffer) + { + mState.vertexAttribute[attribute].mBoundBuffer.set(NULL); + } + } +} + +void Context::detachTexture(GLuint texture) +{ + // [OpenGL ES 2.0.24] section 3.8 page 84: + // If a texture object is deleted, it is as if all texture units which are bound to that texture object are + // rebound to texture object zero + + for (int type = 0; type < TEXTURE_TYPE_COUNT; type++) + { + for (int sampler = 0; sampler < MAX_COMBINED_TEXTURE_IMAGE_UNITS_VTF; sampler++) + { + if (mState.samplerTexture[type][sampler].id() == texture) + { + mState.samplerTexture[type][sampler].set(NULL); + } + } + } + + // [OpenGL ES 2.0.24] section 4.4 page 112: + // If a texture object is deleted while its image is attached to the currently bound framebuffer, then it is + // as if FramebufferTexture2D had been called, with a texture of 0, for each attachment point to which this + // image was attached in the currently bound framebuffer. + + Framebuffer *readFramebuffer = getReadFramebuffer(); + Framebuffer *drawFramebuffer = getDrawFramebuffer(); + + if (readFramebuffer) + { + readFramebuffer->detachTexture(texture); + } + + if (drawFramebuffer && drawFramebuffer != readFramebuffer) + { + drawFramebuffer->detachTexture(texture); + } +} + +void Context::detachFramebuffer(GLuint framebuffer) +{ + // [OpenGL ES 2.0.24] section 4.4 page 107: + // If a framebuffer that is currently bound to the target FRAMEBUFFER is deleted, it is as though + // BindFramebuffer had been executed with the target of FRAMEBUFFER and framebuffer of zero. + + if (mState.readFramebuffer == framebuffer) + { + bindReadFramebuffer(0); + } + + if (mState.drawFramebuffer == framebuffer) + { + bindDrawFramebuffer(0); + } +} + +void Context::detachRenderbuffer(GLuint renderbuffer) +{ + // [OpenGL ES 2.0.24] section 4.4 page 109: + // If a renderbuffer that is currently bound to RENDERBUFFER is deleted, it is as though BindRenderbuffer + // had been executed with the target RENDERBUFFER and name of zero. + + if (mState.renderbuffer.id() == renderbuffer) + { + bindRenderbuffer(0); + } + + // [OpenGL ES 2.0.24] section 4.4 page 111: + // If a renderbuffer object is deleted while its image is attached to the currently bound framebuffer, + // then it is as if FramebufferRenderbuffer had been called, with a renderbuffer of 0, for each attachment + // point to which this image was attached in the currently bound framebuffer. + + Framebuffer *readFramebuffer = getReadFramebuffer(); + Framebuffer *drawFramebuffer = getDrawFramebuffer(); + + if (readFramebuffer) + { + readFramebuffer->detachRenderbuffer(renderbuffer); + } + + if (drawFramebuffer && drawFramebuffer != readFramebuffer) + { + drawFramebuffer->detachRenderbuffer(renderbuffer); + } +} + +Texture *Context::getIncompleteTexture(TextureType type) +{ + Texture *t = mIncompleteTextures[type].get(); + + if (t == NULL) + { + static const GLubyte color[] = { 0, 0, 0, 255 }; + + switch (type) + { + default: + UNREACHABLE(); + // default falls through to TEXTURE_2D + + case TEXTURE_2D: + { + Texture2D *incomplete2d = new Texture2D(Texture::INCOMPLETE_TEXTURE_ID); + incomplete2d->setImage(0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color); + t = incomplete2d; + } + break; + + case TEXTURE_CUBE: + { + TextureCubeMap *incompleteCube = new TextureCubeMap(Texture::INCOMPLETE_TEXTURE_ID); + + incompleteCube->setImagePosX(0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color); + incompleteCube->setImageNegX(0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color); + incompleteCube->setImagePosY(0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color); + incompleteCube->setImageNegY(0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color); + incompleteCube->setImagePosZ(0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color); + incompleteCube->setImageNegZ(0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color); + + t = incompleteCube; + } + break; + } + + mIncompleteTextures[type].set(t); + } + + return t; +} + +bool Context::skipDraw(GLenum drawMode) +{ + if (drawMode == GL_POINTS) + { + // ProgramBinary assumes non-point rendering if gl_PointSize isn't written, + // which affects varying interpolation. Since the value of gl_PointSize is + // undefined when not written, just skip drawing to avoid unexpected results. + if (!getCurrentProgramBinary()->usesPointSize()) + { + // This is stictly speaking not an error, but developers should be + // notified of risking undefined behavior. + ERR("Point rendering without writing to gl_PointSize."); + + return true; + } + } + else if (isTriangleMode(drawMode)) + { + if (mState.cullFace && mState.cullMode == GL_FRONT_AND_BACK) + { + return true; + } + } + + return false; +} + +bool Context::isTriangleMode(GLenum drawMode) +{ + switch (drawMode) + { + case GL_TRIANGLES: + case GL_TRIANGLE_FAN: + case GL_TRIANGLE_STRIP: + return true; + case GL_POINTS: + case GL_LINES: + case GL_LINE_LOOP: + case GL_LINE_STRIP: + return false; + default: UNREACHABLE(); + } + + return false; +} + +void Context::setVertexAttrib(GLuint index, const GLfloat *values) +{ + ASSERT(index < gl::MAX_VERTEX_ATTRIBS); + + mState.vertexAttribute[index].mCurrentValue[0] = values[0]; + mState.vertexAttribute[index].mCurrentValue[1] = values[1]; + mState.vertexAttribute[index].mCurrentValue[2] = values[2]; + mState.vertexAttribute[index].mCurrentValue[3] = values[3]; + + 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_OES_get_program_binary "; + mExtensionString += "GL_OES_rgb8_rgba8 "; + mExtensionString += "GL_OES_standard_derivatives "; + + if (supportsFloat16Textures()) + { + mExtensionString += "GL_OES_texture_half_float "; + } + if (supportsFloat16LinearFilter()) + { + mExtensionString += "GL_OES_texture_half_float_linear "; + } + if (supportsFloat32Textures()) + { + mExtensionString += "GL_OES_texture_float "; + } + if (supportsFloat32LinearFilter()) + { + mExtensionString += "GL_OES_texture_float_linear "; + } + + if (supportsNonPower2Texture()) + { + mExtensionString += "GL_OES_texture_npot "; + } + + // Multi-vendor (EXT) extensions + if (supportsOcclusionQueries()) + { + mExtensionString += "GL_EXT_occlusion_query_boolean "; + } + + mExtensionString += "GL_EXT_read_format_bgra "; + mExtensionString += "GL_EXT_robustness "; + + if (supportsDXT1Textures()) + { + mExtensionString += "GL_EXT_texture_compression_dxt1 "; + } + + if (supportsTextureFilterAnisotropy()) + { + mExtensionString += "GL_EXT_texture_filter_anisotropic "; + } + + mExtensionString += "GL_EXT_texture_format_BGRA8888 "; + mExtensionString += "GL_EXT_texture_storage "; + + // ANGLE-specific extensions + if (supportsDepthTextures()) + { + mExtensionString += "GL_ANGLE_depth_texture "; + } + + mExtensionString += "GL_ANGLE_framebuffer_blit "; + if (getMaxSupportedSamples() != 0) + { + mExtensionString += "GL_ANGLE_framebuffer_multisample "; + } + + if (supportsInstancing()) + { + 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(' '); + if (end != std::string::npos) + { + mExtensionString.resize(end+1); + } +} + +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) +{ + Framebuffer *readFramebuffer = getReadFramebuffer(); + Framebuffer *drawFramebuffer = getDrawFramebuffer(); + + if (!readFramebuffer || readFramebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE || + !drawFramebuffer || drawFramebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE) + { + return error(GL_INVALID_FRAMEBUFFER_OPERATION); + } + + if (drawFramebuffer->getSamples() != 0) + { + return error(GL_INVALID_OPERATION); + } + + int readBufferWidth = readFramebuffer->getColorbuffer()->getWidth(); + int readBufferHeight = readFramebuffer->getColorbuffer()->getHeight(); + int drawBufferWidth = drawFramebuffer->getColorbuffer()->getWidth(); + int drawBufferHeight = drawFramebuffer->getColorbuffer()->getHeight(); + + RECT sourceRect; + RECT destRect; + + if (srcX0 < srcX1) + { + sourceRect.left = srcX0; + sourceRect.right = srcX1; + destRect.left = dstX0; + destRect.right = dstX1; + } + else + { + sourceRect.left = srcX1; + destRect.left = dstX1; + sourceRect.right = srcX0; + destRect.right = dstX0; + } + + if (srcY0 < srcY1) + { + sourceRect.bottom = srcY1; + destRect.bottom = dstY1; + sourceRect.top = srcY0; + destRect.top = dstY0; + } + else + { + sourceRect.bottom = srcY0; + destRect.bottom = dstY0; + sourceRect.top = srcY1; + destRect.top = dstY1; + } + + RECT sourceScissoredRect = sourceRect; + RECT destScissoredRect = destRect; + + if (mState.scissorTest) + { + // Only write to parts of the destination framebuffer which pass the scissor test + // Please note: the destRect is now in D3D-style coordinates, so the *top* of the + // rect will be checked against scissorY, rather than the bottom. + if (destRect.left < mState.scissorX) + { + int xDiff = mState.scissorX - destRect.left; + destScissoredRect.left = mState.scissorX; + sourceScissoredRect.left += xDiff; + } + + if (destRect.right > mState.scissorX + mState.scissorWidth) + { + int xDiff = destRect.right - (mState.scissorX + mState.scissorWidth); + destScissoredRect.right = mState.scissorX + mState.scissorWidth; + sourceScissoredRect.right -= xDiff; + } + + if (destRect.top < mState.scissorY) + { + int yDiff = mState.scissorY - destRect.top; + destScissoredRect.top = mState.scissorY; + sourceScissoredRect.top += yDiff; + } + + if (destRect.bottom > mState.scissorY + mState.scissorHeight) + { + int yDiff = destRect.bottom - (mState.scissorY + mState.scissorHeight); + destScissoredRect.bottom = mState.scissorY + mState.scissorHeight; + sourceScissoredRect.bottom -= yDiff; + } + } + + bool blitRenderTarget = false; + bool blitDepthStencil = false; + + RECT sourceTrimmedRect = sourceScissoredRect; + RECT destTrimmedRect = destScissoredRect; + + // The source & destination rectangles also may need to be trimmed if they fall out of the bounds of + // the actual draw and read surfaces. + if (sourceTrimmedRect.left < 0) + { + int xDiff = 0 - sourceTrimmedRect.left; + sourceTrimmedRect.left = 0; + destTrimmedRect.left += xDiff; + } + + if (sourceTrimmedRect.right > readBufferWidth) + { + int xDiff = sourceTrimmedRect.right - readBufferWidth; + sourceTrimmedRect.right = readBufferWidth; + destTrimmedRect.right -= xDiff; + } + + if (sourceTrimmedRect.top < 0) + { + int yDiff = 0 - sourceTrimmedRect.top; + sourceTrimmedRect.top = 0; + destTrimmedRect.top += yDiff; + } + + if (sourceTrimmedRect.bottom > readBufferHeight) + { + int yDiff = sourceTrimmedRect.bottom - readBufferHeight; + sourceTrimmedRect.bottom = readBufferHeight; + destTrimmedRect.bottom -= yDiff; + } + + if (destTrimmedRect.left < 0) + { + int xDiff = 0 - destTrimmedRect.left; + destTrimmedRect.left = 0; + sourceTrimmedRect.left += xDiff; + } + + if (destTrimmedRect.right > drawBufferWidth) + { + int xDiff = destTrimmedRect.right - drawBufferWidth; + destTrimmedRect.right = drawBufferWidth; + sourceTrimmedRect.right -= xDiff; + } + + if (destTrimmedRect.top < 0) + { + int yDiff = 0 - destTrimmedRect.top; + destTrimmedRect.top = 0; + sourceTrimmedRect.top += yDiff; + } + + if (destTrimmedRect.bottom > drawBufferHeight) + { + int yDiff = destTrimmedRect.bottom - drawBufferHeight; + destTrimmedRect.bottom = drawBufferHeight; + sourceTrimmedRect.bottom -= yDiff; + } + + bool partialBufferCopy = false; + if (sourceTrimmedRect.bottom - sourceTrimmedRect.top < readBufferHeight || + sourceTrimmedRect.right - sourceTrimmedRect.left < readBufferWidth || + destTrimmedRect.bottom - destTrimmedRect.top < drawBufferHeight || + destTrimmedRect.right - destTrimmedRect.left < drawBufferWidth || + sourceTrimmedRect.top != 0 || destTrimmedRect.top != 0 || sourceTrimmedRect.left != 0 || destTrimmedRect.left != 0) + { + partialBufferCopy = true; + } + + if (mask & GL_COLOR_BUFFER_BIT) + { + const bool validReadType = readFramebuffer->getColorbufferType() == GL_TEXTURE_2D || + readFramebuffer->getColorbufferType() == GL_RENDERBUFFER; + const bool validDrawType = drawFramebuffer->getColorbufferType() == GL_TEXTURE_2D || + drawFramebuffer->getColorbufferType() == GL_RENDERBUFFER; + if (!validReadType || !validDrawType || + readFramebuffer->getColorbuffer()->getD3DFormat() != drawFramebuffer->getColorbuffer()->getD3DFormat()) + { + ERR("Color buffer format conversion in BlitFramebufferANGLE not supported by this implementation"); + return error(GL_INVALID_OPERATION); + } + + if (partialBufferCopy && readFramebuffer->getSamples() != 0) + { + return error(GL_INVALID_OPERATION); + } + + blitRenderTarget = true; + + } + + if (mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) + { + Renderbuffer *readDSBuffer = NULL; + Renderbuffer *drawDSBuffer = NULL; + + // We support OES_packed_depth_stencil, and do not support a separately attached depth and stencil buffer, so if we have + // both a depth and stencil buffer, it will be the same buffer. + + if (mask & GL_DEPTH_BUFFER_BIT) + { + if (readFramebuffer->getDepthbuffer() && drawFramebuffer->getDepthbuffer()) + { + if (readFramebuffer->getDepthbufferType() != drawFramebuffer->getDepthbufferType() || + readFramebuffer->getDepthbuffer()->getD3DFormat() != drawFramebuffer->getDepthbuffer()->getD3DFormat()) + { + return error(GL_INVALID_OPERATION); + } + + blitDepthStencil = true; + readDSBuffer = readFramebuffer->getDepthbuffer(); + drawDSBuffer = drawFramebuffer->getDepthbuffer(); + } + } + + if (mask & GL_STENCIL_BUFFER_BIT) + { + if (readFramebuffer->getStencilbuffer() && drawFramebuffer->getStencilbuffer()) + { + if (readFramebuffer->getStencilbufferType() != drawFramebuffer->getStencilbufferType() || + readFramebuffer->getStencilbuffer()->getD3DFormat() != drawFramebuffer->getStencilbuffer()->getD3DFormat()) + { + return error(GL_INVALID_OPERATION); + } + + blitDepthStencil = true; + readDSBuffer = readFramebuffer->getStencilbuffer(); + drawDSBuffer = drawFramebuffer->getStencilbuffer(); + } + } + + if (partialBufferCopy) + { + ERR("Only whole-buffer depth and stencil blits are supported by this implementation."); + return error(GL_INVALID_OPERATION); // only whole-buffer copies are permitted + } + + if ((drawDSBuffer && drawDSBuffer->getSamples() != 0) || + (readDSBuffer && readDSBuffer->getSamples() != 0)) + { + return error(GL_INVALID_OPERATION); + } + } + + if (blitRenderTarget || blitDepthStencil) + { + mDisplay->endScene(); + + if (blitRenderTarget) + { + 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)) + { + ERR("BlitFramebufferANGLE failed: StretchRect returned %x.", result); + return; + } + } + + if (blitDepthStencil) + { + IDirect3DSurface9* readDepthStencil = readFramebuffer->getDepthStencil(); + IDirect3DSurface9* drawDepthStencil = drawFramebuffer->getDepthStencil(); + + HRESULT result = mDevice->StretchRect(readDepthStencil, NULL, drawDepthStencil, NULL, D3DTEXF_NONE); + + readDepthStencil->Release(); + drawDepthStencil->Release(); + + if (FAILED(result)) + { + ERR("BlitFramebufferANGLE failed: StretchRect returned %x.", result); + return; + } + } + } +} + +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[], ProgramBinary *programBinary, 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 = programBinary->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, bool notifyResets, bool robustAccess) +{ + return new gl::Context(config, shareContext, notifyResets, robustAccess); +} + +void glDestroyContext(gl::Context *context) +{ + delete context; + + if (context == gl::getContext()) + { + gl::makeCurrent(NULL, NULL, NULL); + } +} + +void glMakeCurrent(gl::Context *context, egl::Display *display, egl::Surface *surface) +{ + gl::makeCurrent(context, display, surface); +} + +gl::Context *glGetCurrentContext() +{ + return gl::getContext(); +} +} diff --git a/src/3rdparty/angle/src/libGLESv2/Context.h b/src/3rdparty/angle/src/libGLESv2/Context.h new file mode 100644 index 0000000000..2bbae76ef8 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/Context.h @@ -0,0 +1,685 @@ +// +// 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. +// + +// Context.h: Defines the gl::Context class, managing all GL state and performing +// rendering operations. It is the GLES2 specific implementation of EGLContext. + +#ifndef LIBGLESV2_CONTEXT_H_ +#define LIBGLESV2_CONTEXT_H_ + +#define GL_APICALL +#include <GLES2/gl2.h> +#include <GLES2/gl2ext.h> +#define EGLAPI +#include <EGL/egl.h> +#include <d3d9.h> + +#include <string> +#include <map> +#ifdef _MSC_VER +#include <hash_map> +#else +#include <unordered_map> +#endif + +#include "common/angleutils.h" +#include "common/RefCountObject.h" +#include "libGLESv2/ResourceManager.h" +#include "libGLESv2/HandleAllocator.h" + +namespace egl +{ +class Display; +class Surface; +class Config; +} + +namespace gl +{ +struct TranslatedAttribute; +struct TranslatedIndexData; + +class Buffer; +class Shader; +class Program; +class ProgramBinary; +class Texture; +class Texture2D; +class TextureCubeMap; +class Framebuffer; +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 = D3D9_MAX_FLOAT_CONSTANTS - 2, // Reserve space for dx_HalfPixelSize and dx_DepthRange. + MAX_VARYING_VECTORS_SM2 = 8, + MAX_VARYING_VECTORS_SM3 = 10, + MAX_TEXTURE_IMAGE_UNITS = 16, + 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, + + GL_BGRA4_ANGLEX = 0x6ABC, + GL_BGR5_A1_ANGLEX = 0x6ABD +}; + +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; +const float ALIASED_POINT_SIZE_RANGE_MAX_SM2 = 1.0f; + +struct Color +{ + float red; + float green; + float blue; + float alpha; +}; + +// Helper structure describing a single vertex attribute +class VertexAttribute +{ + public: + VertexAttribute() : mType(GL_FLOAT), mSize(0), mNormalized(false), mStride(0), mPointer(NULL), mArrayEnabled(false), mDivisor(0) + { + mCurrentValue[0] = 0.0f; + mCurrentValue[1] = 0.0f; + mCurrentValue[2] = 0.0f; + mCurrentValue[3] = 1.0f; + } + + int typeSize() const + { + switch (mType) + { + case GL_BYTE: return mSize * sizeof(GLbyte); + case GL_UNSIGNED_BYTE: return mSize * sizeof(GLubyte); + case GL_SHORT: return mSize * sizeof(GLshort); + case GL_UNSIGNED_SHORT: return mSize * sizeof(GLushort); + case GL_FIXED: return mSize * sizeof(GLfixed); + case GL_FLOAT: return mSize * sizeof(GLfloat); + default: UNREACHABLE(); return mSize * sizeof(GLfloat); + } + } + + GLsizei stride() const + { + return mStride ? mStride : typeSize(); + } + + // From glVertexAttribPointer + GLenum mType; + GLint mSize; + bool mNormalized; + GLsizei mStride; // 0 means natural stride + + union + { + const void *mPointer; + intptr_t mOffset; + }; + + BindingPointer<Buffer> mBoundBuffer; // Captured when glVertexAttribPointer is called. + + bool mArrayEnabled; // From glEnable/DisableVertexAttribArray + float mCurrentValue[4]; // From glVertexAttrib + unsigned int mDivisor; +}; + +typedef VertexAttribute VertexAttributeArray[MAX_VERTEX_ATTRIBS]; + +// Helper structure to store all raw state +struct State +{ + Color colorClearValue; + GLclampf depthClearValue; + int stencilClearValue; + + bool cullFace; + GLenum cullMode; + GLenum frontFace; + bool depthTest; + GLenum depthFunc; + bool blend; + GLenum sourceBlendRGB; + GLenum destBlendRGB; + GLenum sourceBlendAlpha; + GLenum destBlendAlpha; + GLenum blendEquationRGB; + GLenum blendEquationAlpha; + Color blendColor; + bool stencilTest; + GLenum stencilFunc; + GLint stencilRef; + GLuint stencilMask; + GLenum stencilFail; + GLenum stencilPassDepthFail; + GLenum stencilPassDepthPass; + GLuint stencilWritemask; + GLenum stencilBackFunc; + GLint stencilBackRef; + GLuint stencilBackMask; + GLenum stencilBackFail; + GLenum stencilBackPassDepthFail; + GLenum stencilBackPassDepthPass; + GLuint stencilBackWritemask; + bool polygonOffsetFill; + GLfloat polygonOffsetFactor; + GLfloat polygonOffsetUnits; + bool sampleAlphaToCoverage; + bool sampleCoverage; + GLclampf sampleCoverageValue; + bool sampleCoverageInvert; + bool scissorTest; + bool dither; + + GLfloat lineWidth; + + GLenum generateMipmapHint; + GLenum fragmentShaderDerivativeHint; + + GLint viewportX; + GLint viewportY; + GLsizei viewportWidth; + GLsizei viewportHeight; + float zNear; + float zFar; + + GLint scissorX; + GLint scissorY; + GLsizei scissorWidth; + GLsizei scissorHeight; + + bool colorMaskRed; + bool colorMaskGreen; + bool colorMaskBlue; + bool colorMaskAlpha; + bool depthMask; + + unsigned int activeSampler; // Active texture unit selector - GL_TEXTURE0 + BindingPointer<Buffer> arrayBuffer; + BindingPointer<Buffer> elementArrayBuffer; + GLuint readFramebuffer; + GLuint drawFramebuffer; + BindingPointer<Renderbuffer> renderbuffer; + GLuint currentProgram; + + VertexAttribute vertexAttribute[MAX_VERTEX_ATTRIBS]; + 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[], ProgramBinary *programBinary, GLsizei instances, GLsizei *repeatDraw); + + void markStateDirty(); + + private: + UINT mMaxLru; + + enum { NUM_VERTEX_DECL_CACHE_ENTRIES = 32 }; + + 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, bool notifyResets, bool robustAccess); + + ~Context(); + + void makeCurrent(egl::Display *display, egl::Surface *surface); + + virtual void markAllStateDirty(); + void markDxUniformsDirty(); + + virtual void markContextLost(); + bool isContextLost(); + + // State manipulation + void setClearColor(float red, float green, float blue, float alpha); + + void setClearDepth(float depth); + + void setClearStencil(int stencil); + + void setCullFace(bool enabled); + bool isCullFaceEnabled() const; + + void setCullMode(GLenum mode); + + void setFrontFace(GLenum front); + + void setDepthTest(bool enabled); + bool isDepthTestEnabled() const; + + void setDepthFunc(GLenum depthFunc); + + void setDepthRange(float zNear, float zFar); + + void setBlend(bool enabled); + bool isBlendEnabled() const; + + void setBlendFactors(GLenum sourceRGB, GLenum destRGB, GLenum sourceAlpha, GLenum destAlpha); + void setBlendColor(float red, float green, float blue, float alpha); + void setBlendEquation(GLenum rgbEquation, GLenum alphaEquation); + + void setStencilTest(bool enabled); + bool isStencilTestEnabled() const; + + void setStencilParams(GLenum stencilFunc, GLint stencilRef, GLuint stencilMask); + void setStencilBackParams(GLenum stencilBackFunc, GLint stencilBackRef, GLuint stencilBackMask); + void setStencilWritemask(GLuint stencilWritemask); + void setStencilBackWritemask(GLuint stencilBackWritemask); + void setStencilOperations(GLenum stencilFail, GLenum stencilPassDepthFail, GLenum stencilPassDepthPass); + void setStencilBackOperations(GLenum stencilBackFail, GLenum stencilBackPassDepthFail, GLenum stencilBackPassDepthPass); + + void setPolygonOffsetFill(bool enabled); + bool isPolygonOffsetFillEnabled() const; + + void setPolygonOffsetParams(GLfloat factor, GLfloat units); + + void setSampleAlphaToCoverage(bool enabled); + bool isSampleAlphaToCoverageEnabled() const; + + void setSampleCoverage(bool enabled); + bool isSampleCoverageEnabled() const; + + void setSampleCoverageParams(GLclampf value, bool invert); + + void setScissorTest(bool enabled); + bool isScissorTestEnabled() const; + + void setDither(bool enabled); + bool isDitherEnabled() const; + + void setLineWidth(GLfloat width); + + void setGenerateMipmapHint(GLenum hint); + void setFragmentShaderDerivativeHint(GLenum hint); + + void setViewportParams(GLint x, GLint y, GLsizei width, GLsizei height); + + void setScissorParams(GLint x, GLint y, GLsizei width, GLsizei height); + + void setColorMask(bool red, bool green, bool blue, bool alpha); + void setDepthMask(bool mask); + + void setActiveSampler(unsigned int active); + + GLuint getReadFramebufferHandle() const; + GLuint getDrawFramebufferHandle() const; + GLuint getRenderbufferHandle() const; + + 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, + bool normalized, GLsizei stride, const void *pointer); + const void *getVertexAttribPointer(unsigned int attribNum) const; + + const VertexAttributeArray &getVertexAttributes(); + + void setUnpackAlignment(GLint alignment); + GLint getUnpackAlignment() const; + + 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(); + GLuint createShader(GLenum type); + GLuint createProgram(); + GLuint createTexture(); + GLuint createRenderbuffer(); + + void deleteBuffer(GLuint buffer); + void deleteShader(GLuint shader); + void deleteProgram(GLuint program); + void deleteTexture(GLuint texture); + void deleteRenderbuffer(GLuint renderbuffer); + + // Framebuffers are owned by the Context, so these methods do not pass through + GLuint createFramebuffer(); + void deleteFramebuffer(GLuint framebuffer); + + // 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); + void bindTexture2D(GLuint texture); + void bindTextureCubeMap(GLuint texture); + void bindReadFramebuffer(GLuint framebuffer); + void bindDrawFramebuffer(GLuint framebuffer); + void bindRenderbuffer(GLuint renderbuffer); + void useProgram(GLuint program); + void linkProgram(GLuint program); + void setProgramBinary(GLuint program, const void *binary, GLint length); + + 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); + Shader *getShader(GLuint handle); + Program *getProgram(GLuint handle); + Texture *getTexture(GLuint handle); + Framebuffer *getFramebuffer(GLuint handle); + Renderbuffer *getRenderbuffer(GLuint handle); + Query *getQuery(GLuint handle, bool create, GLenum type); + + Buffer *getArrayBuffer(); + Buffer *getElementArrayBuffer(); + ProgramBinary *getCurrentProgramBinary(); + Texture2D *getTexture2D(); + TextureCubeMap *getTextureCubeMap(); + Texture *getSamplerTexture(unsigned int sampler, TextureType type); + Framebuffer *getReadFramebuffer(); + Framebuffer *getDrawFramebuffer(); + + bool getFloatv(GLenum pname, GLfloat *params); + bool getIntegerv(GLenum pname, GLint *params); + bool getBooleanv(GLenum pname, GLboolean *params); + + bool getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *numParams); + + 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, GLsizei instances); + void drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei instances); + void sync(bool block); // flush/finish + + void drawLineLoop(GLsizei count, GLenum type, const GLvoid *indices, int minIndex); + + void recordInvalidEnum(); + void recordInvalidValue(); + void recordInvalidOperation(); + void recordOutOfMemory(); + void recordInvalidFramebufferOperation(); + + GLenum getError(); + GLenum getResetStatus(); + virtual bool isResetNotificationEnabled(); + + bool supportsShaderModel3() const; + float getMaximumPointSize() const; + int getMaximumVaryingVectors() const; + unsigned int getMaximumVertexTextureImageUnits() const; + unsigned int getMaximumCombinedTextureImageUnits() const; + int getMaximumFragmentUniformVectors() const; + int getMaximumRenderbufferDimension() const; + int getMaximumTextureDimension() const; + int getMaximumCubeTextureDimension() const; + int getMaximumTextureLevel() const; + GLsizei getMaxSupportedSamples() const; + int getNearestSupportedSamples(D3DFORMAT format, int requested) const; + const char *getExtensionString() const; + const char *getRendererString() const; + bool supportsEventQueries() 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 supportsDepthTextures() const; + bool supports32bitIndices() const; + bool supportsNonPower2Texture() const; + bool supportsInstancing() const; + bool supportsTextureFilterAnisotropy() const; + + bool getCurrentReadFormatType(GLenum *format, GLenum *type); + + float getTextureMaxAnisotropy() const; + + void blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, + GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, + GLbitfield mask); + + Blit *getBlitter() { return mBlit; } + + const D3DCAPS9 &getDeviceCaps() { return mDeviceCaps; } + + private: + DISALLOW_COPY_AND_ASSIGN(Context); + + 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(TextureType type); + + bool skipDraw(GLenum drawMode); + bool isTriangleMode(GLenum drawMode); + + void initExtensionString(); + void initRendererString(); + + const egl::Config *const mConfig; + egl::Display *mDisplay; + IDirect3DDevice9 *mDevice; + + State mState; + + BindingPointer<Texture2D> mTexture2DZero; + BindingPointer<TextureCubeMap> mTextureCubeMapZero; + +#ifndef HASH_MAP +# ifdef _MSC_VER +# define HASH_MAP stdext::hash_map +# else +# define HASH_MAP std::unordered_map +# endif +#endif + + typedef HASH_MAP<GLuint, Framebuffer*> FramebufferMap; + FramebufferMap mFramebufferMap; + HandleAllocator mFramebufferHandleAllocator; + + typedef HASH_MAP<GLuint, Fence*> FenceMap; + FenceMap mFenceMap; + HandleAllocator mFenceHandleAllocator; + + typedef HASH_MAP<GLuint, Query*> QueryMap; + QueryMap mQueryMap; + HandleAllocator mQueryHandleAllocator; + + std::string mExtensionString; + std::string mRendererString; + + VertexDataManager *mVertexDataManager; + IndexDataManager *mIndexDataManager; + + Blit *mBlit; + + StreamingIndexBuffer *mLineLoopIB; + + BindingPointer<Texture> mIncompleteTextures[TEXTURE_TYPE_COUNT]; + + // Recorded errors + bool mInvalidEnum; + bool mInvalidValue; + bool mInvalidOperation; + bool mOutOfMemory; + bool mInvalidFramebufferOperation; + + // Current/lost context flags + bool mHasBeenCurrent; + 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 mAppliedProgramBinarySerial; + 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; + BindingPointer<ProgramBinary> mCurrentProgramBinary; + Framebuffer *mBoundDrawFramebuffer; + + bool mSupportsShaderModel3; + float mMaximumPointSize; + bool mSupportsVertexTexture; + bool mSupportsNonPower2Texture; + bool mSupportsInstancing; + int mMaxRenderbufferDimension; + int mMaxTextureDimension; + int mMaxCubeTextureDimension; + int mMaxTextureLevel; + float mMaxTextureAnisotropy; + std::map<D3DFORMAT, bool *> mMultiSampleSupport; + GLsizei mMaxSupportedSamples; + bool mSupportsEventQueries; + 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 mSupportsDepthTextures; + bool mSupports32bitIndices; + bool mSupportsTextureFilterAnisotropy; + int mNumCompressedTextureFormats; + + // state caching flags + bool mClearStateDirty; + bool mCullStateDirty; + bool mDepthStateDirty; + bool mMaskStateDirty; + bool mPixelPackingStateDirty; + bool mBlendStateDirty; + bool mStencilStateDirty; + bool mPolygonOffsetStateDirty; + bool mScissorStateDirty; + bool mSampleStateDirty; + bool mFrontFaceDirty; + bool mDitherStateDirty; + + IDirect3DStateBlock9 *mMaskedClearSavedState; + + 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, 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/src/3rdparty/angle/src/libGLESv2/D3DConstantTable.cpp b/src/3rdparty/angle/src/libGLESv2/D3DConstantTable.cpp new file mode 100644 index 0000000000..e136951bec --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/D3DConstantTable.cpp @@ -0,0 +1,231 @@ +// +// 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. +// + +// D3DConstantTable.cpp: Implements the D3DConstantTable class which parses +// information about constants from the CTAB comment in a D3D shader blob. +// Restructures the constant table as a hierarchy of constants in the same +// way as D3DX. + +#include "libGLESv2/D3DConstantTable.h" + +#include <d3d9.h> +#include <d3d9types.h> +#include <windows.h> +#include <mmsystem.h> + +#include "libGLESv2/BinaryStream.h" + +const static int SHADER_VERSION_MASK = D3DVS_VERSION(0, 0); +const static int FOURCC_CTAB = MAKEFOURCC('C','T','A','B'); + +namespace gl +{ +// These structs and constants correspond to the format of the constant table in a shader binary. +// They match the corresponding structures in d3dx9shader.h. +namespace ctab +{ +struct ConstantTable +{ + DWORD size; + DWORD creator; + DWORD version; + DWORD constants; + DWORD constantInfos; + DWORD flags; + DWORD target; +}; + +struct ConstantInfo +{ + DWORD name; + WORD registerSet; + WORD registerIndex; + WORD registerCount; + WORD reserved; + DWORD typeInfo; + DWORD defaultValue; +}; + +struct TypeInfo +{ + WORD typeClass; + WORD type; + WORD rows; + WORD columns; + WORD elements; + WORD structMembers; + DWORD structMemberInfos; +}; + +struct StructMemberInfo +{ + DWORD name; + DWORD typeInfo; +}; +} + +D3DConstant::D3DConstant(const char *base, const ctab::ConstantInfo *constantInfo) +{ + const ctab::TypeInfo *typeInfo = reinterpret_cast<const ctab::TypeInfo*>(base + constantInfo->typeInfo); + + name = base + constantInfo->name; + registerSet = static_cast<RegisterSet>(constantInfo->registerSet); + registerIndex = constantInfo->registerIndex; + registerCount = constantInfo->registerCount; + typeClass = static_cast<Class>(typeInfo->typeClass); + type = static_cast<Type>(typeInfo->type); + rows = typeInfo->rows; + columns = typeInfo->columns; + elements = typeInfo->elements; + + if (typeClass == CLASS_STRUCT) + { + addStructMembers(base, registerSet, registerIndex, typeInfo); + } +} + +D3DConstant::D3DConstant(const char *base, RegisterSet registerSet, unsigned registerIndex, const ctab::StructMemberInfo *memberInfo) + : registerSet(registerSet), registerIndex(registerIndex) +{ + const ctab::TypeInfo *typeInfo = reinterpret_cast<const ctab::TypeInfo*>(base + memberInfo->typeInfo); + + name = base + memberInfo->name; + registerCount = typeInfo->rows * typeInfo->elements; + typeClass = static_cast<Class>(typeInfo->typeClass); + type = static_cast<Type>(typeInfo->type); + rows = typeInfo->rows; + columns = typeInfo->columns; + elements = typeInfo->elements; + + if (typeClass == CLASS_STRUCT) + { + registerCount = addStructMembers(base, registerSet, registerIndex, typeInfo); + } +} + +D3DConstant::~D3DConstant() +{ + for (size_t j = 0; j < structMembers.size(); ++j) + { + for (size_t i = 0; i < structMembers[j].size(); ++i) + { + delete structMembers[j][i]; + } + } +} + +unsigned D3DConstant::addStructMembers(const char *base, RegisterSet registerSet, unsigned registerIndex, const ctab::TypeInfo *typeInfo) +{ + const ctab::StructMemberInfo *memberInfos = reinterpret_cast<const ctab::StructMemberInfo*>( + base + typeInfo->structMemberInfos); + + unsigned memberIndex = registerIndex; + + structMembers.resize(elements); + + for (unsigned j = 0; j < elements; ++j) + { + structMembers[j].resize(typeInfo->structMembers); + + for (unsigned i = 0; i < typeInfo->structMembers; ++i) + { + const ctab::TypeInfo *memberTypeInfo = reinterpret_cast<const ctab::TypeInfo*>( + base + memberInfos[i].typeInfo); + + D3DConstant *member = new D3DConstant(base, registerSet, memberIndex, memberInfos + i); + memberIndex += member->registerCount; + + structMembers[j][i] = member; + } + } + + return memberIndex - registerIndex; +} + +D3DConstantTable::D3DConstantTable(void *blob, size_t size) : mError(false) +{ + BinaryInputStream stream(blob, size); + + int version; + stream.read(&version); + if ((version & SHADER_VERSION_MASK) != SHADER_VERSION_MASK) + { + mError = true; + return; + } + + const ctab::ConstantTable* constantTable = NULL; + + while (!stream.error()) + { + int token; + stream.read(&token); + + if ((token & D3DSI_OPCODE_MASK) == D3DSIO_COMMENT) + { + size_t length = ((token & D3DSI_COMMENTSIZE_MASK) >> D3DSI_COMMENTSIZE_SHIFT) * sizeof(DWORD); + + int fourcc; + stream.read(&fourcc); + if (fourcc == FOURCC_CTAB) + { + constantTable = reinterpret_cast<const ctab::ConstantTable*>(static_cast<const char*>(blob) + stream.offset()); + break; + } + + stream.skip(length - sizeof(fourcc)); + } + else if (token == D3DSIO_END) + { + break; + } + } + + mError = !constantTable || stream.error(); + if (mError) + { + return; + } + + const char *base = reinterpret_cast<const char*>(constantTable); + + mConstants.resize(constantTable->constants); + const ctab::ConstantInfo *constantInfos = + reinterpret_cast<const ctab::ConstantInfo*>(base + constantTable->constantInfos); + for (size_t i = 0; i < constantTable->constants; ++i) + { + mConstants[i] = new D3DConstant(base, constantInfos + i); + } +} + +D3DConstantTable::~D3DConstantTable() +{ + for (size_t i = 0; i < mConstants.size(); ++i) + { + delete mConstants[i]; + } +} + +const D3DConstant *D3DConstantTable::getConstant(unsigned index) const +{ + return mConstants[index]; +} + +const D3DConstant *D3DConstantTable::getConstantByName(const char *name) const +{ + for (size_t i = 0; i < mConstants.size(); ++i) + { + const D3DConstant *constant = getConstant(i); + if (constant->name == name) + { + return constant; + } + } + + return NULL; +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/D3DConstantTable.h b/src/3rdparty/angle/src/libGLESv2/D3DConstantTable.h new file mode 100644 index 0000000000..ca6f3b9a3f --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/D3DConstantTable.h @@ -0,0 +1,117 @@ +// +// 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. +// + +// D3DConstantTable.h: Implements the D3DConstantTable class which parses +// information about constants from the CTAB comment in a D3D shader blob. +// Restructures the constant table as a hierarchy of constants in the same +// way as D3DX. + +#ifndef LIBGLESV2_D3DCONSTANTTABLE_H_ +#define LIBGLESV2_D3DCONSTANTTABLE_H_ + +#include <vector> +#include <string> + +#include "common/angleutils.h" + +namespace gl +{ + +namespace ctab +{ +struct ConstantTable; +struct ConstantInfo; +struct TypeInfo; +struct StructMemberInfo; +} + +struct D3DConstant +{ + // These enums match those in d3dx9shader.h. + enum Class + { + CLASS_SCALAR, + CLASS_VECTOR, + CLASS_MATRIX_ROWS, + CLASS_MATRIX_COLUMNS, + CLASS_OBJECT, + CLASS_STRUCT, + }; + + enum RegisterSet + { + RS_BOOL, + RS_INT4, + RS_FLOAT4, + RS_SAMPLER, + }; + + enum Type + { + PT_VOID, + PT_BOOL, + PT_INT, + PT_FLOAT, + PT_STRING, + PT_TEXTURE, + PT_TEXTURE1D, + PT_TEXTURE2D, + PT_TEXTURE3D, + PT_TEXTURECUBE, + PT_SAMPLER, + PT_SAMPLER1D, + PT_SAMPLER2D, + PT_SAMPLER3D, + PT_SAMPLERCUBE, + PT_PIXELSHADER, + PT_VERTEXSHADER, + PT_PIXELFRAGMENT, + PT_VERTEXFRAGMENT, + PT_UNSUPPORTED, + }; + + D3DConstant(const char *base, const ctab::ConstantInfo *constantInfo); + ~D3DConstant(); + + std::string name; + RegisterSet registerSet; + unsigned registerIndex; + unsigned registerCount; + Class typeClass; + Type type; + unsigned rows; + unsigned columns; + unsigned elements; + + // Array of structure members. + std::vector<std::vector<const D3DConstant*> > structMembers; + + private: + D3DConstant(const char *base, RegisterSet registerSet, unsigned registerIndex, const ctab::StructMemberInfo *memberInfo); + unsigned addStructMembers(const char *base, RegisterSet registerSet, unsigned registerIndex, const ctab::TypeInfo *typeInfo); +}; + +class D3DConstantTable +{ + public: + D3DConstantTable(void *blob, size_t size); + ~D3DConstantTable(); + + bool error() const { return mError; } + + unsigned constants() const { return mConstants.size(); } + const D3DConstant *getConstant(unsigned index) const; + const D3DConstant *getConstantByName(const char *name) const; + + private: + DISALLOW_COPY_AND_ASSIGN(D3DConstantTable); + std::vector<const D3DConstant*> mConstants; + bool mError; +}; + +} + +#endif // LIBGLESV2_D3DCONSTANTTABLE_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/Fence.cpp b/src/3rdparty/angle/src/libGLESv2/Fence.cpp new file mode 100644 index 0000000000..14d1239abf --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/Fence.cpp @@ -0,0 +1,132 @@ +// +// 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. +// + +// Fence.cpp: Implements the gl::Fence class, which supports the GL_NV_fence extension. + +#include "libGLESv2/Fence.h" + +#include "libGLESv2/main.h" + +namespace gl +{ + +Fence::Fence(egl::Display* display) +{ + mDisplay = display; + mQuery = NULL; + mCondition = GL_NONE; + mStatus = GL_FALSE; +} + +Fence::~Fence() +{ + if (mQuery != NULL) + { + mDisplay->freeEventQuery(mQuery); + } +} + +GLboolean Fence::isFence() +{ + // GL_NV_fence spec: + // A name returned by GenFencesNV, but not yet set via SetFenceNV, is not the name of an existing fence. + return mQuery != NULL; +} + +void Fence::setFence(GLenum condition) +{ + if (!mQuery) + { + mQuery = mDisplay->allocateEventQuery(); + if (!mQuery) + { + return error(GL_OUT_OF_MEMORY); + } + } + + HRESULT result = mQuery->Issue(D3DISSUE_END); + ASSERT(SUCCEEDED(result)); + + mCondition = condition; + mStatus = GL_FALSE; +} + +GLboolean Fence::testFence() +{ + if (mQuery == NULL) + { + return error(GL_INVALID_OPERATION, GL_TRUE); + } + + HRESULT result = mQuery->GetData(NULL, 0, D3DGETDATA_FLUSH); + + if (checkDeviceLost(result)) + { + return error(GL_OUT_OF_MEMORY, GL_TRUE); + } + + ASSERT(result == S_OK || result == S_FALSE); + mStatus = result == S_OK; + return mStatus; +} + +void Fence::finishFence() +{ + if (mQuery == NULL) + { + return error(GL_INVALID_OPERATION); + } + + while (!testFence()) + { + Sleep(0); + } +} + +void Fence::getFenceiv(GLenum pname, GLint *params) +{ + if (mQuery == NULL) + { + return error(GL_INVALID_OPERATION); + } + + switch (pname) + { + case GL_FENCE_STATUS_NV: + { + // GL_NV_fence spec: + // Once the status of a fence has been finished (via FinishFenceNV) or tested and the returned status is TRUE (via either TestFenceNV + // or GetFenceivNV querying the FENCE_STATUS_NV), the status remains TRUE until the next SetFenceNV of the fence. + if (mStatus) + { + params[0] = GL_TRUE; + return; + } + + HRESULT result = mQuery->GetData(NULL, 0, 0); + + if (checkDeviceLost(result)) + { + params[0] = GL_TRUE; + return error(GL_OUT_OF_MEMORY); + } + + ASSERT(result == S_OK || result == S_FALSE); + mStatus = result == S_OK; + params[0] = mStatus; + + break; + } + case GL_FENCE_CONDITION_NV: + params[0] = mCondition; + break; + default: + return error(GL_INVALID_ENUM); + break; + } +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/Fence.h b/src/3rdparty/angle/src/libGLESv2/Fence.h new file mode 100644 index 0000000000..9626cb0ff0 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/Fence.h @@ -0,0 +1,49 @@ +// +// 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. +// + +// Fence.h: Defines the gl::Fence class, which supports the GL_NV_fence extension. + +#ifndef LIBGLESV2_FENCE_H_ +#define LIBGLESV2_FENCE_H_ + +#define GL_APICALL +#include <GLES2/gl2.h> +#include <d3d9.h> + +#include "common/angleutils.h" + +namespace egl +{ +class Display; +} + +namespace gl +{ + +class Fence +{ + public: + explicit Fence(egl::Display* display); + virtual ~Fence(); + + GLboolean isFence(); + void setFence(GLenum condition); + GLboolean testFence(); + void finishFence(); + void getFenceiv(GLenum pname, GLint *params); + + private: + DISALLOW_COPY_AND_ASSIGN(Fence); + + egl::Display* mDisplay; + IDirect3DQuery9* mQuery; + GLenum mCondition; + GLboolean mStatus; +}; + +} + +#endif // LIBGLESV2_FENCE_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/Float16ToFloat32.cpp b/src/3rdparty/angle/src/libGLESv2/Float16ToFloat32.cpp new file mode 100644 index 0000000000..5bf7b3fce8 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/Float16ToFloat32.cpp @@ -0,0 +1,2203 @@ +// +// 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. +// + +// This file is automatically generated. + +namespace gl +{ + +const static unsigned g_mantissa[2048] = { + 0x00000000, + 0x33800000, + 0x34000000, + 0x34400000, + 0x34800000, + 0x34a00000, + 0x34c00000, + 0x34e00000, + 0x35000000, + 0x35100000, + 0x35200000, + 0x35300000, + 0x35400000, + 0x35500000, + 0x35600000, + 0x35700000, + 0x35800000, + 0x35880000, + 0x35900000, + 0x35980000, + 0x35a00000, + 0x35a80000, + 0x35b00000, + 0x35b80000, + 0x35c00000, + 0x35c80000, + 0x35d00000, + 0x35d80000, + 0x35e00000, + 0x35e80000, + 0x35f00000, + 0x35f80000, + 0x36000000, + 0x36040000, + 0x36080000, + 0x360c0000, + 0x36100000, + 0x36140000, + 0x36180000, + 0x361c0000, + 0x36200000, + 0x36240000, + 0x36280000, + 0x362c0000, + 0x36300000, + 0x36340000, + 0x36380000, + 0x363c0000, + 0x36400000, + 0x36440000, + 0x36480000, + 0x364c0000, + 0x36500000, + 0x36540000, + 0x36580000, + 0x365c0000, + 0x36600000, + 0x36640000, + 0x36680000, + 0x366c0000, + 0x36700000, + 0x36740000, + 0x36780000, + 0x367c0000, + 0x36800000, + 0x36820000, + 0x36840000, + 0x36860000, + 0x36880000, + 0x368a0000, + 0x368c0000, + 0x368e0000, + 0x36900000, + 0x36920000, + 0x36940000, + 0x36960000, + 0x36980000, + 0x369a0000, + 0x369c0000, + 0x369e0000, + 0x36a00000, + 0x36a20000, + 0x36a40000, + 0x36a60000, + 0x36a80000, + 0x36aa0000, + 0x36ac0000, + 0x36ae0000, + 0x36b00000, + 0x36b20000, + 0x36b40000, + 0x36b60000, + 0x36b80000, + 0x36ba0000, + 0x36bc0000, + 0x36be0000, + 0x36c00000, + 0x36c20000, + 0x36c40000, + 0x36c60000, + 0x36c80000, + 0x36ca0000, + 0x36cc0000, + 0x36ce0000, + 0x36d00000, + 0x36d20000, + 0x36d40000, + 0x36d60000, + 0x36d80000, + 0x36da0000, + 0x36dc0000, + 0x36de0000, + 0x36e00000, + 0x36e20000, + 0x36e40000, + 0x36e60000, + 0x36e80000, + 0x36ea0000, + 0x36ec0000, + 0x36ee0000, + 0x36f00000, + 0x36f20000, + 0x36f40000, + 0x36f60000, + 0x36f80000, + 0x36fa0000, + 0x36fc0000, + 0x36fe0000, + 0x37000000, + 0x37010000, + 0x37020000, + 0x37030000, + 0x37040000, + 0x37050000, + 0x37060000, + 0x37070000, + 0x37080000, + 0x37090000, + 0x370a0000, + 0x370b0000, + 0x370c0000, + 0x370d0000, + 0x370e0000, + 0x370f0000, + 0x37100000, + 0x37110000, + 0x37120000, + 0x37130000, + 0x37140000, + 0x37150000, + 0x37160000, + 0x37170000, + 0x37180000, + 0x37190000, + 0x371a0000, + 0x371b0000, + 0x371c0000, + 0x371d0000, + 0x371e0000, + 0x371f0000, + 0x37200000, + 0x37210000, + 0x37220000, + 0x37230000, + 0x37240000, + 0x37250000, + 0x37260000, + 0x37270000, + 0x37280000, + 0x37290000, + 0x372a0000, + 0x372b0000, + 0x372c0000, + 0x372d0000, + 0x372e0000, + 0x372f0000, + 0x37300000, + 0x37310000, + 0x37320000, + 0x37330000, + 0x37340000, + 0x37350000, + 0x37360000, + 0x37370000, + 0x37380000, + 0x37390000, + 0x373a0000, + 0x373b0000, + 0x373c0000, + 0x373d0000, + 0x373e0000, + 0x373f0000, + 0x37400000, + 0x37410000, + 0x37420000, + 0x37430000, + 0x37440000, + 0x37450000, + 0x37460000, + 0x37470000, + 0x37480000, + 0x37490000, + 0x374a0000, + 0x374b0000, + 0x374c0000, + 0x374d0000, + 0x374e0000, + 0x374f0000, + 0x37500000, + 0x37510000, + 0x37520000, + 0x37530000, + 0x37540000, + 0x37550000, + 0x37560000, + 0x37570000, + 0x37580000, + 0x37590000, + 0x375a0000, + 0x375b0000, + 0x375c0000, + 0x375d0000, + 0x375e0000, + 0x375f0000, + 0x37600000, + 0x37610000, + 0x37620000, + 0x37630000, + 0x37640000, + 0x37650000, + 0x37660000, + 0x37670000, + 0x37680000, + 0x37690000, + 0x376a0000, + 0x376b0000, + 0x376c0000, + 0x376d0000, + 0x376e0000, + 0x376f0000, + 0x37700000, + 0x37710000, + 0x37720000, + 0x37730000, + 0x37740000, + 0x37750000, + 0x37760000, + 0x37770000, + 0x37780000, + 0x37790000, + 0x377a0000, + 0x377b0000, + 0x377c0000, + 0x377d0000, + 0x377e0000, + 0x377f0000, + 0x37800000, + 0x37808000, + 0x37810000, + 0x37818000, + 0x37820000, + 0x37828000, + 0x37830000, + 0x37838000, + 0x37840000, + 0x37848000, + 0x37850000, + 0x37858000, + 0x37860000, + 0x37868000, + 0x37870000, + 0x37878000, + 0x37880000, + 0x37888000, + 0x37890000, + 0x37898000, + 0x378a0000, + 0x378a8000, + 0x378b0000, + 0x378b8000, + 0x378c0000, + 0x378c8000, + 0x378d0000, + 0x378d8000, + 0x378e0000, + 0x378e8000, + 0x378f0000, + 0x378f8000, + 0x37900000, + 0x37908000, + 0x37910000, + 0x37918000, + 0x37920000, + 0x37928000, + 0x37930000, + 0x37938000, + 0x37940000, + 0x37948000, + 0x37950000, + 0x37958000, + 0x37960000, + 0x37968000, + 0x37970000, + 0x37978000, + 0x37980000, + 0x37988000, + 0x37990000, + 0x37998000, + 0x379a0000, + 0x379a8000, + 0x379b0000, + 0x379b8000, + 0x379c0000, + 0x379c8000, + 0x379d0000, + 0x379d8000, + 0x379e0000, + 0x379e8000, + 0x379f0000, + 0x379f8000, + 0x37a00000, + 0x37a08000, + 0x37a10000, + 0x37a18000, + 0x37a20000, + 0x37a28000, + 0x37a30000, + 0x37a38000, + 0x37a40000, + 0x37a48000, + 0x37a50000, + 0x37a58000, + 0x37a60000, + 0x37a68000, + 0x37a70000, + 0x37a78000, + 0x37a80000, + 0x37a88000, + 0x37a90000, + 0x37a98000, + 0x37aa0000, + 0x37aa8000, + 0x37ab0000, + 0x37ab8000, + 0x37ac0000, + 0x37ac8000, + 0x37ad0000, + 0x37ad8000, + 0x37ae0000, + 0x37ae8000, + 0x37af0000, + 0x37af8000, + 0x37b00000, + 0x37b08000, + 0x37b10000, + 0x37b18000, + 0x37b20000, + 0x37b28000, + 0x37b30000, + 0x37b38000, + 0x37b40000, + 0x37b48000, + 0x37b50000, + 0x37b58000, + 0x37b60000, + 0x37b68000, + 0x37b70000, + 0x37b78000, + 0x37b80000, + 0x37b88000, + 0x37b90000, + 0x37b98000, + 0x37ba0000, + 0x37ba8000, + 0x37bb0000, + 0x37bb8000, + 0x37bc0000, + 0x37bc8000, + 0x37bd0000, + 0x37bd8000, + 0x37be0000, + 0x37be8000, + 0x37bf0000, + 0x37bf8000, + 0x37c00000, + 0x37c08000, + 0x37c10000, + 0x37c18000, + 0x37c20000, + 0x37c28000, + 0x37c30000, + 0x37c38000, + 0x37c40000, + 0x37c48000, + 0x37c50000, + 0x37c58000, + 0x37c60000, + 0x37c68000, + 0x37c70000, + 0x37c78000, + 0x37c80000, + 0x37c88000, + 0x37c90000, + 0x37c98000, + 0x37ca0000, + 0x37ca8000, + 0x37cb0000, + 0x37cb8000, + 0x37cc0000, + 0x37cc8000, + 0x37cd0000, + 0x37cd8000, + 0x37ce0000, + 0x37ce8000, + 0x37cf0000, + 0x37cf8000, + 0x37d00000, + 0x37d08000, + 0x37d10000, + 0x37d18000, + 0x37d20000, + 0x37d28000, + 0x37d30000, + 0x37d38000, + 0x37d40000, + 0x37d48000, + 0x37d50000, + 0x37d58000, + 0x37d60000, + 0x37d68000, + 0x37d70000, + 0x37d78000, + 0x37d80000, + 0x37d88000, + 0x37d90000, + 0x37d98000, + 0x37da0000, + 0x37da8000, + 0x37db0000, + 0x37db8000, + 0x37dc0000, + 0x37dc8000, + 0x37dd0000, + 0x37dd8000, + 0x37de0000, + 0x37de8000, + 0x37df0000, + 0x37df8000, + 0x37e00000, + 0x37e08000, + 0x37e10000, + 0x37e18000, + 0x37e20000, + 0x37e28000, + 0x37e30000, + 0x37e38000, + 0x37e40000, + 0x37e48000, + 0x37e50000, + 0x37e58000, + 0x37e60000, + 0x37e68000, + 0x37e70000, + 0x37e78000, + 0x37e80000, + 0x37e88000, + 0x37e90000, + 0x37e98000, + 0x37ea0000, + 0x37ea8000, + 0x37eb0000, + 0x37eb8000, + 0x37ec0000, + 0x37ec8000, + 0x37ed0000, + 0x37ed8000, + 0x37ee0000, + 0x37ee8000, + 0x37ef0000, + 0x37ef8000, + 0x37f00000, + 0x37f08000, + 0x37f10000, + 0x37f18000, + 0x37f20000, + 0x37f28000, + 0x37f30000, + 0x37f38000, + 0x37f40000, + 0x37f48000, + 0x37f50000, + 0x37f58000, + 0x37f60000, + 0x37f68000, + 0x37f70000, + 0x37f78000, + 0x37f80000, + 0x37f88000, + 0x37f90000, + 0x37f98000, + 0x37fa0000, + 0x37fa8000, + 0x37fb0000, + 0x37fb8000, + 0x37fc0000, + 0x37fc8000, + 0x37fd0000, + 0x37fd8000, + 0x37fe0000, + 0x37fe8000, + 0x37ff0000, + 0x37ff8000, + 0x38000000, + 0x38004000, + 0x38008000, + 0x3800c000, + 0x38010000, + 0x38014000, + 0x38018000, + 0x3801c000, + 0x38020000, + 0x38024000, + 0x38028000, + 0x3802c000, + 0x38030000, + 0x38034000, + 0x38038000, + 0x3803c000, + 0x38040000, + 0x38044000, + 0x38048000, + 0x3804c000, + 0x38050000, + 0x38054000, + 0x38058000, + 0x3805c000, + 0x38060000, + 0x38064000, + 0x38068000, + 0x3806c000, + 0x38070000, + 0x38074000, + 0x38078000, + 0x3807c000, + 0x38080000, + 0x38084000, + 0x38088000, + 0x3808c000, + 0x38090000, + 0x38094000, + 0x38098000, + 0x3809c000, + 0x380a0000, + 0x380a4000, + 0x380a8000, + 0x380ac000, + 0x380b0000, + 0x380b4000, + 0x380b8000, + 0x380bc000, + 0x380c0000, + 0x380c4000, + 0x380c8000, + 0x380cc000, + 0x380d0000, + 0x380d4000, + 0x380d8000, + 0x380dc000, + 0x380e0000, + 0x380e4000, + 0x380e8000, + 0x380ec000, + 0x380f0000, + 0x380f4000, + 0x380f8000, + 0x380fc000, + 0x38100000, + 0x38104000, + 0x38108000, + 0x3810c000, + 0x38110000, + 0x38114000, + 0x38118000, + 0x3811c000, + 0x38120000, + 0x38124000, + 0x38128000, + 0x3812c000, + 0x38130000, + 0x38134000, + 0x38138000, + 0x3813c000, + 0x38140000, + 0x38144000, + 0x38148000, + 0x3814c000, + 0x38150000, + 0x38154000, + 0x38158000, + 0x3815c000, + 0x38160000, + 0x38164000, + 0x38168000, + 0x3816c000, + 0x38170000, + 0x38174000, + 0x38178000, + 0x3817c000, + 0x38180000, + 0x38184000, + 0x38188000, + 0x3818c000, + 0x38190000, + 0x38194000, + 0x38198000, + 0x3819c000, + 0x381a0000, + 0x381a4000, + 0x381a8000, + 0x381ac000, + 0x381b0000, + 0x381b4000, + 0x381b8000, + 0x381bc000, + 0x381c0000, + 0x381c4000, + 0x381c8000, + 0x381cc000, + 0x381d0000, + 0x381d4000, + 0x381d8000, + 0x381dc000, + 0x381e0000, + 0x381e4000, + 0x381e8000, + 0x381ec000, + 0x381f0000, + 0x381f4000, + 0x381f8000, + 0x381fc000, + 0x38200000, + 0x38204000, + 0x38208000, + 0x3820c000, + 0x38210000, + 0x38214000, + 0x38218000, + 0x3821c000, + 0x38220000, + 0x38224000, + 0x38228000, + 0x3822c000, + 0x38230000, + 0x38234000, + 0x38238000, + 0x3823c000, + 0x38240000, + 0x38244000, + 0x38248000, + 0x3824c000, + 0x38250000, + 0x38254000, + 0x38258000, + 0x3825c000, + 0x38260000, + 0x38264000, + 0x38268000, + 0x3826c000, + 0x38270000, + 0x38274000, + 0x38278000, + 0x3827c000, + 0x38280000, + 0x38284000, + 0x38288000, + 0x3828c000, + 0x38290000, + 0x38294000, + 0x38298000, + 0x3829c000, + 0x382a0000, + 0x382a4000, + 0x382a8000, + 0x382ac000, + 0x382b0000, + 0x382b4000, + 0x382b8000, + 0x382bc000, + 0x382c0000, + 0x382c4000, + 0x382c8000, + 0x382cc000, + 0x382d0000, + 0x382d4000, + 0x382d8000, + 0x382dc000, + 0x382e0000, + 0x382e4000, + 0x382e8000, + 0x382ec000, + 0x382f0000, + 0x382f4000, + 0x382f8000, + 0x382fc000, + 0x38300000, + 0x38304000, + 0x38308000, + 0x3830c000, + 0x38310000, + 0x38314000, + 0x38318000, + 0x3831c000, + 0x38320000, + 0x38324000, + 0x38328000, + 0x3832c000, + 0x38330000, + 0x38334000, + 0x38338000, + 0x3833c000, + 0x38340000, + 0x38344000, + 0x38348000, + 0x3834c000, + 0x38350000, + 0x38354000, + 0x38358000, + 0x3835c000, + 0x38360000, + 0x38364000, + 0x38368000, + 0x3836c000, + 0x38370000, + 0x38374000, + 0x38378000, + 0x3837c000, + 0x38380000, + 0x38384000, + 0x38388000, + 0x3838c000, + 0x38390000, + 0x38394000, + 0x38398000, + 0x3839c000, + 0x383a0000, + 0x383a4000, + 0x383a8000, + 0x383ac000, + 0x383b0000, + 0x383b4000, + 0x383b8000, + 0x383bc000, + 0x383c0000, + 0x383c4000, + 0x383c8000, + 0x383cc000, + 0x383d0000, + 0x383d4000, + 0x383d8000, + 0x383dc000, + 0x383e0000, + 0x383e4000, + 0x383e8000, + 0x383ec000, + 0x383f0000, + 0x383f4000, + 0x383f8000, + 0x383fc000, + 0x38400000, + 0x38404000, + 0x38408000, + 0x3840c000, + 0x38410000, + 0x38414000, + 0x38418000, + 0x3841c000, + 0x38420000, + 0x38424000, + 0x38428000, + 0x3842c000, + 0x38430000, + 0x38434000, + 0x38438000, + 0x3843c000, + 0x38440000, + 0x38444000, + 0x38448000, + 0x3844c000, + 0x38450000, + 0x38454000, + 0x38458000, + 0x3845c000, + 0x38460000, + 0x38464000, + 0x38468000, + 0x3846c000, + 0x38470000, + 0x38474000, + 0x38478000, + 0x3847c000, + 0x38480000, + 0x38484000, + 0x38488000, + 0x3848c000, + 0x38490000, + 0x38494000, + 0x38498000, + 0x3849c000, + 0x384a0000, + 0x384a4000, + 0x384a8000, + 0x384ac000, + 0x384b0000, + 0x384b4000, + 0x384b8000, + 0x384bc000, + 0x384c0000, + 0x384c4000, + 0x384c8000, + 0x384cc000, + 0x384d0000, + 0x384d4000, + 0x384d8000, + 0x384dc000, + 0x384e0000, + 0x384e4000, + 0x384e8000, + 0x384ec000, + 0x384f0000, + 0x384f4000, + 0x384f8000, + 0x384fc000, + 0x38500000, + 0x38504000, + 0x38508000, + 0x3850c000, + 0x38510000, + 0x38514000, + 0x38518000, + 0x3851c000, + 0x38520000, + 0x38524000, + 0x38528000, + 0x3852c000, + 0x38530000, + 0x38534000, + 0x38538000, + 0x3853c000, + 0x38540000, + 0x38544000, + 0x38548000, + 0x3854c000, + 0x38550000, + 0x38554000, + 0x38558000, + 0x3855c000, + 0x38560000, + 0x38564000, + 0x38568000, + 0x3856c000, + 0x38570000, + 0x38574000, + 0x38578000, + 0x3857c000, + 0x38580000, + 0x38584000, + 0x38588000, + 0x3858c000, + 0x38590000, + 0x38594000, + 0x38598000, + 0x3859c000, + 0x385a0000, + 0x385a4000, + 0x385a8000, + 0x385ac000, + 0x385b0000, + 0x385b4000, + 0x385b8000, + 0x385bc000, + 0x385c0000, + 0x385c4000, + 0x385c8000, + 0x385cc000, + 0x385d0000, + 0x385d4000, + 0x385d8000, + 0x385dc000, + 0x385e0000, + 0x385e4000, + 0x385e8000, + 0x385ec000, + 0x385f0000, + 0x385f4000, + 0x385f8000, + 0x385fc000, + 0x38600000, + 0x38604000, + 0x38608000, + 0x3860c000, + 0x38610000, + 0x38614000, + 0x38618000, + 0x3861c000, + 0x38620000, + 0x38624000, + 0x38628000, + 0x3862c000, + 0x38630000, + 0x38634000, + 0x38638000, + 0x3863c000, + 0x38640000, + 0x38644000, + 0x38648000, + 0x3864c000, + 0x38650000, + 0x38654000, + 0x38658000, + 0x3865c000, + 0x38660000, + 0x38664000, + 0x38668000, + 0x3866c000, + 0x38670000, + 0x38674000, + 0x38678000, + 0x3867c000, + 0x38680000, + 0x38684000, + 0x38688000, + 0x3868c000, + 0x38690000, + 0x38694000, + 0x38698000, + 0x3869c000, + 0x386a0000, + 0x386a4000, + 0x386a8000, + 0x386ac000, + 0x386b0000, + 0x386b4000, + 0x386b8000, + 0x386bc000, + 0x386c0000, + 0x386c4000, + 0x386c8000, + 0x386cc000, + 0x386d0000, + 0x386d4000, + 0x386d8000, + 0x386dc000, + 0x386e0000, + 0x386e4000, + 0x386e8000, + 0x386ec000, + 0x386f0000, + 0x386f4000, + 0x386f8000, + 0x386fc000, + 0x38700000, + 0x38704000, + 0x38708000, + 0x3870c000, + 0x38710000, + 0x38714000, + 0x38718000, + 0x3871c000, + 0x38720000, + 0x38724000, + 0x38728000, + 0x3872c000, + 0x38730000, + 0x38734000, + 0x38738000, + 0x3873c000, + 0x38740000, + 0x38744000, + 0x38748000, + 0x3874c000, + 0x38750000, + 0x38754000, + 0x38758000, + 0x3875c000, + 0x38760000, + 0x38764000, + 0x38768000, + 0x3876c000, + 0x38770000, + 0x38774000, + 0x38778000, + 0x3877c000, + 0x38780000, + 0x38784000, + 0x38788000, + 0x3878c000, + 0x38790000, + 0x38794000, + 0x38798000, + 0x3879c000, + 0x387a0000, + 0x387a4000, + 0x387a8000, + 0x387ac000, + 0x387b0000, + 0x387b4000, + 0x387b8000, + 0x387bc000, + 0x387c0000, + 0x387c4000, + 0x387c8000, + 0x387cc000, + 0x387d0000, + 0x387d4000, + 0x387d8000, + 0x387dc000, + 0x387e0000, + 0x387e4000, + 0x387e8000, + 0x387ec000, + 0x387f0000, + 0x387f4000, + 0x387f8000, + 0x387fc000, + 0x38000000, + 0x38002000, + 0x38004000, + 0x38006000, + 0x38008000, + 0x3800a000, + 0x3800c000, + 0x3800e000, + 0x38010000, + 0x38012000, + 0x38014000, + 0x38016000, + 0x38018000, + 0x3801a000, + 0x3801c000, + 0x3801e000, + 0x38020000, + 0x38022000, + 0x38024000, + 0x38026000, + 0x38028000, + 0x3802a000, + 0x3802c000, + 0x3802e000, + 0x38030000, + 0x38032000, + 0x38034000, + 0x38036000, + 0x38038000, + 0x3803a000, + 0x3803c000, + 0x3803e000, + 0x38040000, + 0x38042000, + 0x38044000, + 0x38046000, + 0x38048000, + 0x3804a000, + 0x3804c000, + 0x3804e000, + 0x38050000, + 0x38052000, + 0x38054000, + 0x38056000, + 0x38058000, + 0x3805a000, + 0x3805c000, + 0x3805e000, + 0x38060000, + 0x38062000, + 0x38064000, + 0x38066000, + 0x38068000, + 0x3806a000, + 0x3806c000, + 0x3806e000, + 0x38070000, + 0x38072000, + 0x38074000, + 0x38076000, + 0x38078000, + 0x3807a000, + 0x3807c000, + 0x3807e000, + 0x38080000, + 0x38082000, + 0x38084000, + 0x38086000, + 0x38088000, + 0x3808a000, + 0x3808c000, + 0x3808e000, + 0x38090000, + 0x38092000, + 0x38094000, + 0x38096000, + 0x38098000, + 0x3809a000, + 0x3809c000, + 0x3809e000, + 0x380a0000, + 0x380a2000, + 0x380a4000, + 0x380a6000, + 0x380a8000, + 0x380aa000, + 0x380ac000, + 0x380ae000, + 0x380b0000, + 0x380b2000, + 0x380b4000, + 0x380b6000, + 0x380b8000, + 0x380ba000, + 0x380bc000, + 0x380be000, + 0x380c0000, + 0x380c2000, + 0x380c4000, + 0x380c6000, + 0x380c8000, + 0x380ca000, + 0x380cc000, + 0x380ce000, + 0x380d0000, + 0x380d2000, + 0x380d4000, + 0x380d6000, + 0x380d8000, + 0x380da000, + 0x380dc000, + 0x380de000, + 0x380e0000, + 0x380e2000, + 0x380e4000, + 0x380e6000, + 0x380e8000, + 0x380ea000, + 0x380ec000, + 0x380ee000, + 0x380f0000, + 0x380f2000, + 0x380f4000, + 0x380f6000, + 0x380f8000, + 0x380fa000, + 0x380fc000, + 0x380fe000, + 0x38100000, + 0x38102000, + 0x38104000, + 0x38106000, + 0x38108000, + 0x3810a000, + 0x3810c000, + 0x3810e000, + 0x38110000, + 0x38112000, + 0x38114000, + 0x38116000, + 0x38118000, + 0x3811a000, + 0x3811c000, + 0x3811e000, + 0x38120000, + 0x38122000, + 0x38124000, + 0x38126000, + 0x38128000, + 0x3812a000, + 0x3812c000, + 0x3812e000, + 0x38130000, + 0x38132000, + 0x38134000, + 0x38136000, + 0x38138000, + 0x3813a000, + 0x3813c000, + 0x3813e000, + 0x38140000, + 0x38142000, + 0x38144000, + 0x38146000, + 0x38148000, + 0x3814a000, + 0x3814c000, + 0x3814e000, + 0x38150000, + 0x38152000, + 0x38154000, + 0x38156000, + 0x38158000, + 0x3815a000, + 0x3815c000, + 0x3815e000, + 0x38160000, + 0x38162000, + 0x38164000, + 0x38166000, + 0x38168000, + 0x3816a000, + 0x3816c000, + 0x3816e000, + 0x38170000, + 0x38172000, + 0x38174000, + 0x38176000, + 0x38178000, + 0x3817a000, + 0x3817c000, + 0x3817e000, + 0x38180000, + 0x38182000, + 0x38184000, + 0x38186000, + 0x38188000, + 0x3818a000, + 0x3818c000, + 0x3818e000, + 0x38190000, + 0x38192000, + 0x38194000, + 0x38196000, + 0x38198000, + 0x3819a000, + 0x3819c000, + 0x3819e000, + 0x381a0000, + 0x381a2000, + 0x381a4000, + 0x381a6000, + 0x381a8000, + 0x381aa000, + 0x381ac000, + 0x381ae000, + 0x381b0000, + 0x381b2000, + 0x381b4000, + 0x381b6000, + 0x381b8000, + 0x381ba000, + 0x381bc000, + 0x381be000, + 0x381c0000, + 0x381c2000, + 0x381c4000, + 0x381c6000, + 0x381c8000, + 0x381ca000, + 0x381cc000, + 0x381ce000, + 0x381d0000, + 0x381d2000, + 0x381d4000, + 0x381d6000, + 0x381d8000, + 0x381da000, + 0x381dc000, + 0x381de000, + 0x381e0000, + 0x381e2000, + 0x381e4000, + 0x381e6000, + 0x381e8000, + 0x381ea000, + 0x381ec000, + 0x381ee000, + 0x381f0000, + 0x381f2000, + 0x381f4000, + 0x381f6000, + 0x381f8000, + 0x381fa000, + 0x381fc000, + 0x381fe000, + 0x38200000, + 0x38202000, + 0x38204000, + 0x38206000, + 0x38208000, + 0x3820a000, + 0x3820c000, + 0x3820e000, + 0x38210000, + 0x38212000, + 0x38214000, + 0x38216000, + 0x38218000, + 0x3821a000, + 0x3821c000, + 0x3821e000, + 0x38220000, + 0x38222000, + 0x38224000, + 0x38226000, + 0x38228000, + 0x3822a000, + 0x3822c000, + 0x3822e000, + 0x38230000, + 0x38232000, + 0x38234000, + 0x38236000, + 0x38238000, + 0x3823a000, + 0x3823c000, + 0x3823e000, + 0x38240000, + 0x38242000, + 0x38244000, + 0x38246000, + 0x38248000, + 0x3824a000, + 0x3824c000, + 0x3824e000, + 0x38250000, + 0x38252000, + 0x38254000, + 0x38256000, + 0x38258000, + 0x3825a000, + 0x3825c000, + 0x3825e000, + 0x38260000, + 0x38262000, + 0x38264000, + 0x38266000, + 0x38268000, + 0x3826a000, + 0x3826c000, + 0x3826e000, + 0x38270000, + 0x38272000, + 0x38274000, + 0x38276000, + 0x38278000, + 0x3827a000, + 0x3827c000, + 0x3827e000, + 0x38280000, + 0x38282000, + 0x38284000, + 0x38286000, + 0x38288000, + 0x3828a000, + 0x3828c000, + 0x3828e000, + 0x38290000, + 0x38292000, + 0x38294000, + 0x38296000, + 0x38298000, + 0x3829a000, + 0x3829c000, + 0x3829e000, + 0x382a0000, + 0x382a2000, + 0x382a4000, + 0x382a6000, + 0x382a8000, + 0x382aa000, + 0x382ac000, + 0x382ae000, + 0x382b0000, + 0x382b2000, + 0x382b4000, + 0x382b6000, + 0x382b8000, + 0x382ba000, + 0x382bc000, + 0x382be000, + 0x382c0000, + 0x382c2000, + 0x382c4000, + 0x382c6000, + 0x382c8000, + 0x382ca000, + 0x382cc000, + 0x382ce000, + 0x382d0000, + 0x382d2000, + 0x382d4000, + 0x382d6000, + 0x382d8000, + 0x382da000, + 0x382dc000, + 0x382de000, + 0x382e0000, + 0x382e2000, + 0x382e4000, + 0x382e6000, + 0x382e8000, + 0x382ea000, + 0x382ec000, + 0x382ee000, + 0x382f0000, + 0x382f2000, + 0x382f4000, + 0x382f6000, + 0x382f8000, + 0x382fa000, + 0x382fc000, + 0x382fe000, + 0x38300000, + 0x38302000, + 0x38304000, + 0x38306000, + 0x38308000, + 0x3830a000, + 0x3830c000, + 0x3830e000, + 0x38310000, + 0x38312000, + 0x38314000, + 0x38316000, + 0x38318000, + 0x3831a000, + 0x3831c000, + 0x3831e000, + 0x38320000, + 0x38322000, + 0x38324000, + 0x38326000, + 0x38328000, + 0x3832a000, + 0x3832c000, + 0x3832e000, + 0x38330000, + 0x38332000, + 0x38334000, + 0x38336000, + 0x38338000, + 0x3833a000, + 0x3833c000, + 0x3833e000, + 0x38340000, + 0x38342000, + 0x38344000, + 0x38346000, + 0x38348000, + 0x3834a000, + 0x3834c000, + 0x3834e000, + 0x38350000, + 0x38352000, + 0x38354000, + 0x38356000, + 0x38358000, + 0x3835a000, + 0x3835c000, + 0x3835e000, + 0x38360000, + 0x38362000, + 0x38364000, + 0x38366000, + 0x38368000, + 0x3836a000, + 0x3836c000, + 0x3836e000, + 0x38370000, + 0x38372000, + 0x38374000, + 0x38376000, + 0x38378000, + 0x3837a000, + 0x3837c000, + 0x3837e000, + 0x38380000, + 0x38382000, + 0x38384000, + 0x38386000, + 0x38388000, + 0x3838a000, + 0x3838c000, + 0x3838e000, + 0x38390000, + 0x38392000, + 0x38394000, + 0x38396000, + 0x38398000, + 0x3839a000, + 0x3839c000, + 0x3839e000, + 0x383a0000, + 0x383a2000, + 0x383a4000, + 0x383a6000, + 0x383a8000, + 0x383aa000, + 0x383ac000, + 0x383ae000, + 0x383b0000, + 0x383b2000, + 0x383b4000, + 0x383b6000, + 0x383b8000, + 0x383ba000, + 0x383bc000, + 0x383be000, + 0x383c0000, + 0x383c2000, + 0x383c4000, + 0x383c6000, + 0x383c8000, + 0x383ca000, + 0x383cc000, + 0x383ce000, + 0x383d0000, + 0x383d2000, + 0x383d4000, + 0x383d6000, + 0x383d8000, + 0x383da000, + 0x383dc000, + 0x383de000, + 0x383e0000, + 0x383e2000, + 0x383e4000, + 0x383e6000, + 0x383e8000, + 0x383ea000, + 0x383ec000, + 0x383ee000, + 0x383f0000, + 0x383f2000, + 0x383f4000, + 0x383f6000, + 0x383f8000, + 0x383fa000, + 0x383fc000, + 0x383fe000, + 0x38400000, + 0x38402000, + 0x38404000, + 0x38406000, + 0x38408000, + 0x3840a000, + 0x3840c000, + 0x3840e000, + 0x38410000, + 0x38412000, + 0x38414000, + 0x38416000, + 0x38418000, + 0x3841a000, + 0x3841c000, + 0x3841e000, + 0x38420000, + 0x38422000, + 0x38424000, + 0x38426000, + 0x38428000, + 0x3842a000, + 0x3842c000, + 0x3842e000, + 0x38430000, + 0x38432000, + 0x38434000, + 0x38436000, + 0x38438000, + 0x3843a000, + 0x3843c000, + 0x3843e000, + 0x38440000, + 0x38442000, + 0x38444000, + 0x38446000, + 0x38448000, + 0x3844a000, + 0x3844c000, + 0x3844e000, + 0x38450000, + 0x38452000, + 0x38454000, + 0x38456000, + 0x38458000, + 0x3845a000, + 0x3845c000, + 0x3845e000, + 0x38460000, + 0x38462000, + 0x38464000, + 0x38466000, + 0x38468000, + 0x3846a000, + 0x3846c000, + 0x3846e000, + 0x38470000, + 0x38472000, + 0x38474000, + 0x38476000, + 0x38478000, + 0x3847a000, + 0x3847c000, + 0x3847e000, + 0x38480000, + 0x38482000, + 0x38484000, + 0x38486000, + 0x38488000, + 0x3848a000, + 0x3848c000, + 0x3848e000, + 0x38490000, + 0x38492000, + 0x38494000, + 0x38496000, + 0x38498000, + 0x3849a000, + 0x3849c000, + 0x3849e000, + 0x384a0000, + 0x384a2000, + 0x384a4000, + 0x384a6000, + 0x384a8000, + 0x384aa000, + 0x384ac000, + 0x384ae000, + 0x384b0000, + 0x384b2000, + 0x384b4000, + 0x384b6000, + 0x384b8000, + 0x384ba000, + 0x384bc000, + 0x384be000, + 0x384c0000, + 0x384c2000, + 0x384c4000, + 0x384c6000, + 0x384c8000, + 0x384ca000, + 0x384cc000, + 0x384ce000, + 0x384d0000, + 0x384d2000, + 0x384d4000, + 0x384d6000, + 0x384d8000, + 0x384da000, + 0x384dc000, + 0x384de000, + 0x384e0000, + 0x384e2000, + 0x384e4000, + 0x384e6000, + 0x384e8000, + 0x384ea000, + 0x384ec000, + 0x384ee000, + 0x384f0000, + 0x384f2000, + 0x384f4000, + 0x384f6000, + 0x384f8000, + 0x384fa000, + 0x384fc000, + 0x384fe000, + 0x38500000, + 0x38502000, + 0x38504000, + 0x38506000, + 0x38508000, + 0x3850a000, + 0x3850c000, + 0x3850e000, + 0x38510000, + 0x38512000, + 0x38514000, + 0x38516000, + 0x38518000, + 0x3851a000, + 0x3851c000, + 0x3851e000, + 0x38520000, + 0x38522000, + 0x38524000, + 0x38526000, + 0x38528000, + 0x3852a000, + 0x3852c000, + 0x3852e000, + 0x38530000, + 0x38532000, + 0x38534000, + 0x38536000, + 0x38538000, + 0x3853a000, + 0x3853c000, + 0x3853e000, + 0x38540000, + 0x38542000, + 0x38544000, + 0x38546000, + 0x38548000, + 0x3854a000, + 0x3854c000, + 0x3854e000, + 0x38550000, + 0x38552000, + 0x38554000, + 0x38556000, + 0x38558000, + 0x3855a000, + 0x3855c000, + 0x3855e000, + 0x38560000, + 0x38562000, + 0x38564000, + 0x38566000, + 0x38568000, + 0x3856a000, + 0x3856c000, + 0x3856e000, + 0x38570000, + 0x38572000, + 0x38574000, + 0x38576000, + 0x38578000, + 0x3857a000, + 0x3857c000, + 0x3857e000, + 0x38580000, + 0x38582000, + 0x38584000, + 0x38586000, + 0x38588000, + 0x3858a000, + 0x3858c000, + 0x3858e000, + 0x38590000, + 0x38592000, + 0x38594000, + 0x38596000, + 0x38598000, + 0x3859a000, + 0x3859c000, + 0x3859e000, + 0x385a0000, + 0x385a2000, + 0x385a4000, + 0x385a6000, + 0x385a8000, + 0x385aa000, + 0x385ac000, + 0x385ae000, + 0x385b0000, + 0x385b2000, + 0x385b4000, + 0x385b6000, + 0x385b8000, + 0x385ba000, + 0x385bc000, + 0x385be000, + 0x385c0000, + 0x385c2000, + 0x385c4000, + 0x385c6000, + 0x385c8000, + 0x385ca000, + 0x385cc000, + 0x385ce000, + 0x385d0000, + 0x385d2000, + 0x385d4000, + 0x385d6000, + 0x385d8000, + 0x385da000, + 0x385dc000, + 0x385de000, + 0x385e0000, + 0x385e2000, + 0x385e4000, + 0x385e6000, + 0x385e8000, + 0x385ea000, + 0x385ec000, + 0x385ee000, + 0x385f0000, + 0x385f2000, + 0x385f4000, + 0x385f6000, + 0x385f8000, + 0x385fa000, + 0x385fc000, + 0x385fe000, + 0x38600000, + 0x38602000, + 0x38604000, + 0x38606000, + 0x38608000, + 0x3860a000, + 0x3860c000, + 0x3860e000, + 0x38610000, + 0x38612000, + 0x38614000, + 0x38616000, + 0x38618000, + 0x3861a000, + 0x3861c000, + 0x3861e000, + 0x38620000, + 0x38622000, + 0x38624000, + 0x38626000, + 0x38628000, + 0x3862a000, + 0x3862c000, + 0x3862e000, + 0x38630000, + 0x38632000, + 0x38634000, + 0x38636000, + 0x38638000, + 0x3863a000, + 0x3863c000, + 0x3863e000, + 0x38640000, + 0x38642000, + 0x38644000, + 0x38646000, + 0x38648000, + 0x3864a000, + 0x3864c000, + 0x3864e000, + 0x38650000, + 0x38652000, + 0x38654000, + 0x38656000, + 0x38658000, + 0x3865a000, + 0x3865c000, + 0x3865e000, + 0x38660000, + 0x38662000, + 0x38664000, + 0x38666000, + 0x38668000, + 0x3866a000, + 0x3866c000, + 0x3866e000, + 0x38670000, + 0x38672000, + 0x38674000, + 0x38676000, + 0x38678000, + 0x3867a000, + 0x3867c000, + 0x3867e000, + 0x38680000, + 0x38682000, + 0x38684000, + 0x38686000, + 0x38688000, + 0x3868a000, + 0x3868c000, + 0x3868e000, + 0x38690000, + 0x38692000, + 0x38694000, + 0x38696000, + 0x38698000, + 0x3869a000, + 0x3869c000, + 0x3869e000, + 0x386a0000, + 0x386a2000, + 0x386a4000, + 0x386a6000, + 0x386a8000, + 0x386aa000, + 0x386ac000, + 0x386ae000, + 0x386b0000, + 0x386b2000, + 0x386b4000, + 0x386b6000, + 0x386b8000, + 0x386ba000, + 0x386bc000, + 0x386be000, + 0x386c0000, + 0x386c2000, + 0x386c4000, + 0x386c6000, + 0x386c8000, + 0x386ca000, + 0x386cc000, + 0x386ce000, + 0x386d0000, + 0x386d2000, + 0x386d4000, + 0x386d6000, + 0x386d8000, + 0x386da000, + 0x386dc000, + 0x386de000, + 0x386e0000, + 0x386e2000, + 0x386e4000, + 0x386e6000, + 0x386e8000, + 0x386ea000, + 0x386ec000, + 0x386ee000, + 0x386f0000, + 0x386f2000, + 0x386f4000, + 0x386f6000, + 0x386f8000, + 0x386fa000, + 0x386fc000, + 0x386fe000, + 0x38700000, + 0x38702000, + 0x38704000, + 0x38706000, + 0x38708000, + 0x3870a000, + 0x3870c000, + 0x3870e000, + 0x38710000, + 0x38712000, + 0x38714000, + 0x38716000, + 0x38718000, + 0x3871a000, + 0x3871c000, + 0x3871e000, + 0x38720000, + 0x38722000, + 0x38724000, + 0x38726000, + 0x38728000, + 0x3872a000, + 0x3872c000, + 0x3872e000, + 0x38730000, + 0x38732000, + 0x38734000, + 0x38736000, + 0x38738000, + 0x3873a000, + 0x3873c000, + 0x3873e000, + 0x38740000, + 0x38742000, + 0x38744000, + 0x38746000, + 0x38748000, + 0x3874a000, + 0x3874c000, + 0x3874e000, + 0x38750000, + 0x38752000, + 0x38754000, + 0x38756000, + 0x38758000, + 0x3875a000, + 0x3875c000, + 0x3875e000, + 0x38760000, + 0x38762000, + 0x38764000, + 0x38766000, + 0x38768000, + 0x3876a000, + 0x3876c000, + 0x3876e000, + 0x38770000, + 0x38772000, + 0x38774000, + 0x38776000, + 0x38778000, + 0x3877a000, + 0x3877c000, + 0x3877e000, + 0x38780000, + 0x38782000, + 0x38784000, + 0x38786000, + 0x38788000, + 0x3878a000, + 0x3878c000, + 0x3878e000, + 0x38790000, + 0x38792000, + 0x38794000, + 0x38796000, + 0x38798000, + 0x3879a000, + 0x3879c000, + 0x3879e000, + 0x387a0000, + 0x387a2000, + 0x387a4000, + 0x387a6000, + 0x387a8000, + 0x387aa000, + 0x387ac000, + 0x387ae000, + 0x387b0000, + 0x387b2000, + 0x387b4000, + 0x387b6000, + 0x387b8000, + 0x387ba000, + 0x387bc000, + 0x387be000, + 0x387c0000, + 0x387c2000, + 0x387c4000, + 0x387c6000, + 0x387c8000, + 0x387ca000, + 0x387cc000, + 0x387ce000, + 0x387d0000, + 0x387d2000, + 0x387d4000, + 0x387d6000, + 0x387d8000, + 0x387da000, + 0x387dc000, + 0x387de000, + 0x387e0000, + 0x387e2000, + 0x387e4000, + 0x387e6000, + 0x387e8000, + 0x387ea000, + 0x387ec000, + 0x387ee000, + 0x387f0000, + 0x387f2000, + 0x387f4000, + 0x387f6000, + 0x387f8000, + 0x387fa000, + 0x387fc000, + 0x387fe000, +}; + +const static unsigned g_exponent[64] = { + 0x00000000, + 0x00800000, + 0x01000000, + 0x01800000, + 0x02000000, + 0x02800000, + 0x03000000, + 0x03800000, + 0x04000000, + 0x04800000, + 0x05000000, + 0x05800000, + 0x06000000, + 0x06800000, + 0x07000000, + 0x07800000, + 0x08000000, + 0x08800000, + 0x09000000, + 0x09800000, + 0x0a000000, + 0x0a800000, + 0x0b000000, + 0x0b800000, + 0x0c000000, + 0x0c800000, + 0x0d000000, + 0x0d800000, + 0x0e000000, + 0x0e800000, + 0x0f000000, + 0x47800000, + 0x80000000, + 0x80800000, + 0x81000000, + 0x81800000, + 0x82000000, + 0x82800000, + 0x83000000, + 0x83800000, + 0x84000000, + 0x84800000, + 0x85000000, + 0x85800000, + 0x86000000, + 0x86800000, + 0x87000000, + 0x87800000, + 0x88000000, + 0x88800000, + 0x89000000, + 0x89800000, + 0x8a000000, + 0x8a800000, + 0x8b000000, + 0x8b800000, + 0x8c000000, + 0x8c800000, + 0x8d000000, + 0x8d800000, + 0x8e000000, + 0x8e800000, + 0x8f000000, + 0xc7800000, +}; + +const static unsigned g_offset[64] = { + 0x00000000, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000000, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, +}; + +float float16ToFloat32(unsigned short h) +{ + unsigned i32 = g_mantissa[g_offset[h >> 10] + (h & 0x3ff)] + g_exponent[h >> 10]; + return *(float*) &i32; +} +} + diff --git a/src/3rdparty/angle/src/libGLESv2/Float16ToFloat32.py b/src/3rdparty/angle/src/libGLESv2/Float16ToFloat32.py new file mode 100644 index 0000000000..ae646ffa12 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/Float16ToFloat32.py @@ -0,0 +1,78 @@ +# 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. +# + +# This script generates a function that converts 16-bit precision floating +# point numbers to 32-bit. +# It is based on ftp://ftp.fox-toolkit.org/pub/fasthalffloatconversion.pdf. + +def convertMantissa(i): + if i == 0: + return 0 + elif i < 1024: + m = i << 13 + e = 0 + while not (m & 0x00800000): + e -= 0x00800000 + m = m << 1 + m &= ~0x00800000 + e += 0x38800000 + return m | e + else: + return 0x38000000 + ((i - 1024) << 13) + +def convertExponent(i): + if i == 0: + return 0 + elif i in range(1, 31): + return i << 23 + elif i == 31: + return 0x47800000 + elif i == 32: + return 0x80000000 + elif i in range(33, 63): + return 0x80000000 + ((i - 32) << 23) + else: + return 0xC7800000 + +def convertOffset(i): + if i == 0 or i == 32: + return 0 + else: + return 1024 + +print """// +// 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. +// + +// This file is automatically generated. + +namespace gl +{ +""" + +print "const static unsigned g_mantissa[2048] = {" +for i in range(0, 2048): + print " %08x," % convertMantissa(i) +print "};\n" + +print "const static unsigned g_exponent[64] = {" +for i in range(0, 64): + print " %08x," % convertExponent(i) +print "};\n" + +print "const static unsigned g_offset[64] = {" +for i in range(0, 64): + print " %08x," % convertOffset(i) +print "};\n" + +print """float float16ToFloat32(unsigned short h) +{ + unsigned i32 = =g_mantissa[g_offset[h >> 10] + (h & 0x3ff)] + g_exponent[h >> 10]; + return *(float*) &i32; +} +} +""" diff --git a/src/3rdparty/angle/src/libGLESv2/Framebuffer.cpp b/src/3rdparty/angle/src/libGLESv2/Framebuffer.cpp new file mode 100644 index 0000000000..77d79c0be2 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/Framebuffer.cpp @@ -0,0 +1,509 @@ +// +// 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. +// + +// Framebuffer.cpp: Implements the gl::Framebuffer class. Implements GL framebuffer +// objects and related functionality. [OpenGL ES 2.0.24] section 4.4 page 105. + +#include "libGLESv2/Framebuffer.h" + +#include "libGLESv2/main.h" +#include "libGLESv2/Renderbuffer.h" +#include "libGLESv2/Texture.h" +#include "libGLESv2/utilities.h" + +namespace gl +{ + +Framebuffer::Framebuffer() +{ + mColorbufferType = GL_NONE; + mDepthbufferType = GL_NONE; + mStencilbufferType = GL_NONE; +} + +Framebuffer::~Framebuffer() +{ + mColorbufferPointer.set(NULL); + mDepthbufferPointer.set(NULL); + mStencilbufferPointer.set(NULL); + mNullColorbufferPointer.set(NULL); +} + +Renderbuffer *Framebuffer::lookupRenderbuffer(GLenum type, GLuint handle) const +{ + gl::Context *context = gl::getContext(); + Renderbuffer *buffer = NULL; + + if (type == GL_NONE) + { + buffer = NULL; + } + else if (type == GL_RENDERBUFFER) + { + buffer = context->getRenderbuffer(handle); + } + else if (IsInternalTextureTarget(type)) + { + buffer = context->getTexture(handle)->getRenderbuffer(type); + } + else + { + UNREACHABLE(); + } + + return buffer; +} + +void Framebuffer::setColorbuffer(GLenum type, GLuint colorbuffer) +{ + mColorbufferType = (colorbuffer != 0) ? type : GL_NONE; + mColorbufferPointer.set(lookupRenderbuffer(type, colorbuffer)); +} + +void Framebuffer::setDepthbuffer(GLenum type, GLuint depthbuffer) +{ + mDepthbufferType = (depthbuffer != 0) ? type : GL_NONE; + mDepthbufferPointer.set(lookupRenderbuffer(type, depthbuffer)); +} + +void Framebuffer::setStencilbuffer(GLenum type, GLuint stencilbuffer) +{ + mStencilbufferType = (stencilbuffer != 0) ? type : GL_NONE; + mStencilbufferPointer.set(lookupRenderbuffer(type, stencilbuffer)); +} + +void Framebuffer::detachTexture(GLuint texture) +{ + if (mColorbufferPointer.id() == texture && IsInternalTextureTarget(mColorbufferType)) + { + mColorbufferType = GL_NONE; + mColorbufferPointer.set(NULL); + } + + if (mDepthbufferPointer.id() == texture && IsInternalTextureTarget(mDepthbufferType)) + { + mDepthbufferType = GL_NONE; + mDepthbufferPointer.set(NULL); + } + + if (mStencilbufferPointer.id() == texture && IsInternalTextureTarget(mStencilbufferType)) + { + mStencilbufferType = GL_NONE; + mStencilbufferPointer.set(NULL); + } +} + +void Framebuffer::detachRenderbuffer(GLuint renderbuffer) +{ + if (mColorbufferPointer.id() == renderbuffer && mColorbufferType == GL_RENDERBUFFER) + { + mColorbufferType = GL_NONE; + mColorbufferPointer.set(NULL); + } + + if (mDepthbufferPointer.id() == renderbuffer && mDepthbufferType == GL_RENDERBUFFER) + { + mDepthbufferType = GL_NONE; + mDepthbufferPointer.set(NULL); + } + + if (mStencilbufferPointer.id() == renderbuffer && mStencilbufferType == GL_RENDERBUFFER) + { + mStencilbufferType = GL_NONE; + mStencilbufferPointer.set(NULL); + } +} + +unsigned int Framebuffer::getRenderTargetSerial() +{ + Renderbuffer *colorbuffer = mColorbufferPointer.get(); + + if (colorbuffer) + { + return colorbuffer->getSerial(); + } + + return 0; +} + +// Increments refcount on surface. +// caller must Release() the returned surface +IDirect3DSurface9 *Framebuffer::getRenderTarget() +{ + Renderbuffer *colorbuffer = mColorbufferPointer.get(); + + if (colorbuffer) + { + return colorbuffer->getRenderTarget(); + } + + return NULL; +} + +// Increments refcount on surface. +// caller must Release() the returned surface +IDirect3DSurface9 *Framebuffer::getDepthStencil() +{ + Renderbuffer *depthstencilbuffer = mDepthbufferPointer.get(); + + if (!depthstencilbuffer) + { + depthstencilbuffer = mStencilbufferPointer.get(); + } + + if (depthstencilbuffer) + { + return depthstencilbuffer->getDepthStencil(); + } + + return NULL; +} + +unsigned int Framebuffer::getDepthbufferSerial() +{ + Renderbuffer *depthbuffer = mDepthbufferPointer.get(); + + if (depthbuffer) + { + return depthbuffer->getSerial(); + } + + return 0; +} + +unsigned int Framebuffer::getStencilbufferSerial() +{ + Renderbuffer *stencilbuffer = mStencilbufferPointer.get(); + + if (stencilbuffer) + { + return stencilbuffer->getSerial(); + } + + return 0; +} + +Renderbuffer *Framebuffer::getColorbuffer() +{ + return mColorbufferPointer.get(); +} + +Renderbuffer *Framebuffer::getDepthbuffer() +{ + return mDepthbufferPointer.get(); +} + +Renderbuffer *Framebuffer::getStencilbuffer() +{ + return mStencilbufferPointer.get(); +} + +Renderbuffer *Framebuffer::getNullColorbuffer() +{ + Renderbuffer *nullbuffer = mNullColorbufferPointer.get(); + Renderbuffer *depthbuffer = getDepthbuffer(); + + if (!depthbuffer) + { + ERR("Unexpected null depthbuffer for depth-only FBO."); + return NULL; + } + + GLsizei width = depthbuffer->getWidth(); + GLsizei height = depthbuffer->getHeight(); + + if (!nullbuffer || + width != nullbuffer->getWidth() || height != nullbuffer->getHeight()) + { + nullbuffer = new Renderbuffer(0, new Colorbuffer(width, height, GL_NONE, 0)); + mNullColorbufferPointer.set(nullbuffer); + } + + return nullbuffer; +} + +GLenum Framebuffer::getColorbufferType() +{ + return mColorbufferType; +} + +GLenum Framebuffer::getDepthbufferType() +{ + return mDepthbufferType; +} + +GLenum Framebuffer::getStencilbufferType() +{ + return mStencilbufferType; +} + +GLuint Framebuffer::getColorbufferHandle() +{ + return mColorbufferPointer.id(); +} + +GLuint Framebuffer::getDepthbufferHandle() +{ + return mDepthbufferPointer.id(); +} + +GLuint Framebuffer::getStencilbufferHandle() +{ + return mStencilbufferPointer.id(); +} + +bool Framebuffer::hasStencil() +{ + if (mStencilbufferType != GL_NONE) + { + Renderbuffer *stencilbufferObject = getStencilbuffer(); + + if (stencilbufferObject) + { + return stencilbufferObject->getStencilSize() > 0; + } + } + + return false; +} + +GLenum Framebuffer::completeness() +{ + gl::Context *context = gl::getContext(); + int width = 0; + int height = 0; + int samples = -1; + bool missingAttachment = true; + + if (mColorbufferType != GL_NONE) + { + Renderbuffer *colorbuffer = getColorbuffer(); + + if (!colorbuffer) + { + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } + + if (colorbuffer->getWidth() == 0 || colorbuffer->getHeight() == 0) + { + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } + + if (mColorbufferType == GL_RENDERBUFFER) + { + if (!gl::IsColorRenderable(colorbuffer->getInternalFormat())) + { + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } + } + else if (IsInternalTextureTarget(mColorbufferType)) + { + GLint internalformat = colorbuffer->getInternalFormat(); + GLenum format = gl::ExtractFormat(internalformat); + + if (IsCompressed(format) || + format == GL_ALPHA || + format == GL_LUMINANCE || + format == GL_LUMINANCE_ALPHA) + { + return GL_FRAMEBUFFER_UNSUPPORTED; + } + + if ((gl::IsFloat32Format(internalformat) && !context->supportsFloat32RenderableTextures()) || + (gl::IsFloat16Format(internalformat) && !context->supportsFloat16RenderableTextures())) + { + return GL_FRAMEBUFFER_UNSUPPORTED; + } + + if (gl::IsDepthTexture(internalformat) || gl::IsStencilTexture(internalformat)) + { + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } + } + else + { + UNREACHABLE(); + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } + + width = colorbuffer->getWidth(); + height = colorbuffer->getHeight(); + samples = colorbuffer->getSamples(); + missingAttachment = false; + } + + Renderbuffer *depthbuffer = NULL; + Renderbuffer *stencilbuffer = NULL; + + if (mDepthbufferType != GL_NONE) + { + depthbuffer = getDepthbuffer(); + + if (!depthbuffer) + { + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } + + if (depthbuffer->getWidth() == 0 || depthbuffer->getHeight() == 0) + { + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } + + if (mDepthbufferType == GL_RENDERBUFFER) + { + if (!gl::IsDepthRenderable(depthbuffer->getInternalFormat())) + { + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } + } + else if (IsInternalTextureTarget(mDepthbufferType)) + { + GLint internalformat = depthbuffer->getInternalFormat(); + + // depth texture attachments require OES/ANGLE_depth_texture + if (!context->supportsDepthTextures()) + { + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } + + if (!gl::IsDepthTexture(internalformat)) + { + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } + } + else + { + UNREACHABLE(); + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } + + if (missingAttachment) + { + width = depthbuffer->getWidth(); + height = depthbuffer->getHeight(); + samples = depthbuffer->getSamples(); + missingAttachment = false; + } + else if (width != depthbuffer->getWidth() || height != depthbuffer->getHeight()) + { + return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS; + } + else if (samples != depthbuffer->getSamples()) + { + return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE; + } + } + + if (mStencilbufferType != GL_NONE) + { + stencilbuffer = getStencilbuffer(); + + if (!stencilbuffer) + { + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } + + if (stencilbuffer->getWidth() == 0 || stencilbuffer->getHeight() == 0) + { + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } + + if (mStencilbufferType == GL_RENDERBUFFER) + { + if (!gl::IsStencilRenderable(stencilbuffer->getInternalFormat())) + { + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } + } + else if (IsInternalTextureTarget(mStencilbufferType)) + { + GLint internalformat = stencilbuffer->getInternalFormat(); + + // texture stencil attachments come along as part + // of OES_packed_depth_stencil + OES/ANGLE_depth_texture + if (!context->supportsDepthTextures()) + { + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } + + if (!gl::IsStencilTexture(internalformat)) + { + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } + } + else + { + UNREACHABLE(); + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } + + if (missingAttachment) + { + width = stencilbuffer->getWidth(); + height = stencilbuffer->getHeight(); + samples = stencilbuffer->getSamples(); + missingAttachment = false; + } + else if (width != stencilbuffer->getWidth() || height != stencilbuffer->getHeight()) + { + return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS; + } + else if (samples != stencilbuffer->getSamples()) + { + return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE; + } + } + + // if we have both a depth and stencil buffer, they must refer to the same object + // since we only support packed_depth_stencil and not separate depth and stencil + if (depthbuffer && stencilbuffer && (depthbuffer != stencilbuffer)) + { + return GL_FRAMEBUFFER_UNSUPPORTED; + } + + // we need to have at least one attachment to be complete + if (missingAttachment) + { + return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT; + } + + return GL_FRAMEBUFFER_COMPLETE; +} + +DefaultFramebuffer::DefaultFramebuffer(Colorbuffer *colorbuffer, DepthStencilbuffer *depthStencil) +{ + 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() +{ + if (completeness() == GL_FRAMEBUFFER_COMPLETE) + { + return getColorbuffer()->getSamples(); + } + else + { + return 0; + } +} + +GLenum DefaultFramebuffer::completeness() +{ + // The default framebuffer should always be complete + ASSERT(Framebuffer::completeness() == GL_FRAMEBUFFER_COMPLETE); + + return GL_FRAMEBUFFER_COMPLETE; +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/Framebuffer.h b/src/3rdparty/angle/src/libGLESv2/Framebuffer.h new file mode 100644 index 0000000000..14d9c2a74c --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/Framebuffer.h @@ -0,0 +1,98 @@ +// +// 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. +// + +// Framebuffer.h: Defines the gl::Framebuffer class. Implements GL framebuffer +// objects and related functionality. [OpenGL ES 2.0.24] section 4.4 page 105. + +#ifndef LIBGLESV2_FRAMEBUFFER_H_ +#define LIBGLESV2_FRAMEBUFFER_H_ + +#define GL_APICALL +#include <GLES2/gl2.h> +#include <d3d9.h> + +#include "common/angleutils.h" +#include "common/RefCountObject.h" + +namespace gl +{ +class Renderbuffer; +class Colorbuffer; +class Depthbuffer; +class Stencilbuffer; +class DepthStencilbuffer; + +class Framebuffer +{ + public: + Framebuffer(); + + virtual ~Framebuffer(); + + void setColorbuffer(GLenum type, GLuint colorbuffer); + void setDepthbuffer(GLenum type, GLuint depthbuffer); + void setStencilbuffer(GLenum type, GLuint stencilbuffer); + + void detachTexture(GLuint texture); + void detachRenderbuffer(GLuint renderbuffer); + + IDirect3DSurface9 *getRenderTarget(); + IDirect3DSurface9 *getDepthStencil(); + + unsigned int getRenderTargetSerial(); + unsigned int getDepthbufferSerial(); + unsigned int getStencilbufferSerial(); + + Renderbuffer *getColorbuffer(); + Renderbuffer *getDepthbuffer(); + Renderbuffer *getStencilbuffer(); + Renderbuffer *getNullColorbuffer(); + + GLenum getColorbufferType(); + GLenum getDepthbufferType(); + GLenum getStencilbufferType(); + + GLuint getColorbufferHandle(); + GLuint getDepthbufferHandle(); + GLuint getStencilbufferHandle(); + + bool hasStencil(); + int getSamples(); + + virtual GLenum completeness(); + + protected: + GLenum mColorbufferType; + BindingPointer<Renderbuffer> mColorbufferPointer; + + GLenum mDepthbufferType; + BindingPointer<Renderbuffer> mDepthbufferPointer; + + GLenum mStencilbufferType; + BindingPointer<Renderbuffer> mStencilbufferPointer; + + BindingPointer<Renderbuffer> mNullColorbufferPointer; + + private: + DISALLOW_COPY_AND_ASSIGN(Framebuffer); + + Renderbuffer *lookupRenderbuffer(GLenum type, GLuint handle) const; +}; + +class DefaultFramebuffer : public Framebuffer +{ + public: + DefaultFramebuffer(Colorbuffer *colorbuffer, DepthStencilbuffer *depthStencil); + + virtual GLenum completeness(); + + private: + DISALLOW_COPY_AND_ASSIGN(DefaultFramebuffer); +}; + +} + +#endif // LIBGLESV2_FRAMEBUFFER_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/HandleAllocator.cpp b/src/3rdparty/angle/src/libGLESv2/HandleAllocator.cpp new file mode 100644 index 0000000000..c498f8a178 --- /dev/null +++ b/src/3rdparty/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/src/3rdparty/angle/src/libGLESv2/HandleAllocator.h b/src/3rdparty/angle/src/libGLESv2/HandleAllocator.h new file mode 100644 index 0000000000..a92e1684d4 --- /dev/null +++ b/src/3rdparty/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/src/3rdparty/angle/src/libGLESv2/IndexDataManager.cpp b/src/3rdparty/angle/src/libGLESv2/IndexDataManager.cpp new file mode 100644 index 0000000000..3dc0aef3f1 --- /dev/null +++ b/src/3rdparty/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/src/3rdparty/angle/src/libGLESv2/IndexDataManager.h b/src/3rdparty/angle/src/libGLESv2/IndexDataManager.h new file mode 100644 index 0000000000..c1d4168315 --- /dev/null +++ b/src/3rdparty/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/src/3rdparty/angle/src/libGLESv2/Program.cpp b/src/3rdparty/angle/src/libGLESv2/Program.cpp new file mode 100644 index 0000000000..5f53a1f581 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/Program.cpp @@ -0,0 +1,528 @@ +// +// 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. +// + +// Program.cpp: Implements the gl::Program class. Implements GL program objects +// and related functionality. [OpenGL ES 2.0.24] section 2.10.3 page 28. + +#include "libGLESv2/Program.h" +#include "libGLESv2/ProgramBinary.h" + +#include "common/debug.h" + +#include "libGLESv2/main.h" +#include "libGLESv2/Shader.h" +#include "libGLESv2/utilities.h" + +#include <string> + +namespace gl +{ +const char * const g_fakepath = "C:\\fakepath"; + +AttributeBindings::AttributeBindings() +{ +} + +AttributeBindings::~AttributeBindings() +{ +} + +InfoLog::InfoLog() : mInfoLog(NULL) +{ +} + +InfoLog::~InfoLog() +{ + delete[] mInfoLog; +} + + +int InfoLog::getLength() const +{ + if (!mInfoLog) + { + return 0; + } + else + { + return strlen(mInfoLog) + 1; + } +} + +void InfoLog::getLog(GLsizei bufSize, GLsizei *length, char *infoLog) +{ + int index = 0; + + if (bufSize > 0) + { + if (mInfoLog) + { + index = std::min(bufSize - 1, (int)strlen(mInfoLog)); + memcpy(infoLog, mInfoLog, index); + } + + infoLog[index] = '\0'; + } + + if (length) + { + *length = index; + } +} + +// 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 InfoLog::appendSanitized(const char *message) +{ + std::string msg(message); + + size_t found; + do + { + found = msg.find(g_fakepath); + if (found != std::string::npos) + { + msg.erase(found, strlen(g_fakepath)); + } + } + while (found != std::string::npos); + + append("%s\n", msg.c_str()); +} + +void InfoLog::append(const char *format, ...) +{ + if (!format) + { + return; + } + + char info[1024]; + + va_list vararg; + va_start(vararg, format); + vsnprintf(info, sizeof(info), format, vararg); + va_end(vararg); + + size_t infoLength = strlen(info); + + if (!mInfoLog) + { + mInfoLog = new char[infoLength + 1]; + strcpy(mInfoLog, info); + } + else + { + size_t logLength = strlen(mInfoLog); + char *newLog = new char[logLength + infoLength + 1]; + strcpy(newLog, mInfoLog); + strcpy(newLog + logLength, info); + + delete[] mInfoLog; + mInfoLog = newLog; + } +} + +void InfoLog::reset() +{ + if (mInfoLog) + { + delete [] mInfoLog; + mInfoLog = NULL; + } +} + +Program::Program(ResourceManager *manager, GLuint handle) : mResourceManager(manager), mHandle(handle) +{ + mFragmentShader = NULL; + mVertexShader = NULL; + mProgramBinary.set(NULL); + mDeleteStatus = false; + mLinked = false; + mRefCount = 0; +} + +Program::~Program() +{ + unlink(true); + + if (mVertexShader != NULL) + { + mVertexShader->release(); + } + + if (mFragmentShader != NULL) + { + mFragmentShader->release(); + } +} + +bool Program::attachShader(Shader *shader) +{ + if (shader->getType() == GL_VERTEX_SHADER) + { + if (mVertexShader) + { + return false; + } + + mVertexShader = (VertexShader*)shader; + mVertexShader->addRef(); + } + else if (shader->getType() == GL_FRAGMENT_SHADER) + { + if (mFragmentShader) + { + return false; + } + + mFragmentShader = (FragmentShader*)shader; + mFragmentShader->addRef(); + } + else UNREACHABLE(); + + return true; +} + +bool Program::detachShader(Shader *shader) +{ + if (shader->getType() == GL_VERTEX_SHADER) + { + if (mVertexShader != shader) + { + return false; + } + + mVertexShader->release(); + mVertexShader = NULL; + } + else if (shader->getType() == GL_FRAGMENT_SHADER) + { + if (mFragmentShader != shader) + { + return false; + } + + mFragmentShader->release(); + mFragmentShader = NULL; + } + else UNREACHABLE(); + + return true; +} + +int Program::getAttachedShadersCount() const +{ + return (mVertexShader ? 1 : 0) + (mFragmentShader ? 1 : 0); +} + +void AttributeBindings::bindAttributeLocation(GLuint index, const char *name) +{ + if (index < MAX_VERTEX_ATTRIBS) + { + for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++) + { + mAttributeBinding[i].erase(name); + } + + mAttributeBinding[index].insert(name); + } +} + +void Program::bindAttributeLocation(GLuint index, const char *name) +{ + mAttributeBindings.bindAttributeLocation(index, name); +} + +// Links the HLSL code of the vertex and pixel shader by matching up their varyings, +// compiling them into binaries, determining the attribute mappings, and collecting +// a list of uniforms +bool Program::link() +{ + unlink(false); + + mInfoLog.reset(); + + mProgramBinary.set(new ProgramBinary()); + mLinked = mProgramBinary->link(mInfoLog, mAttributeBindings, mFragmentShader, mVertexShader); + + return mLinked; +} + +int AttributeBindings::getAttributeBinding(const std::string &name) const +{ + for (int location = 0; location < MAX_VERTEX_ATTRIBS; location++) + { + if (mAttributeBinding[location].find(name) != mAttributeBinding[location].end()) + { + return location; + } + } + + return -1; +} + +// Returns the program object to an unlinked state, before re-linking, or at destruction +void Program::unlink(bool destroy) +{ + if (destroy) // Object being destructed + { + if (mFragmentShader) + { + mFragmentShader->release(); + mFragmentShader = NULL; + } + + if (mVertexShader) + { + mVertexShader->release(); + mVertexShader = NULL; + } + } + + mProgramBinary.set(NULL); + mLinked = false; +} + +bool Program::isLinked() +{ + return mLinked; +} + +ProgramBinary* Program::getProgramBinary() +{ + return mProgramBinary.get(); +} + +bool Program::setProgramBinary(const void *binary, GLsizei length) +{ + unlink(false); + + mInfoLog.reset(); + + mProgramBinary.set(new ProgramBinary()); + mLinked = mProgramBinary->load(mInfoLog, binary, length); + if (!mLinked) + { + mProgramBinary.set(NULL); + } + + return mLinked; +} + +void Program::release() +{ + mRefCount--; + + if (mRefCount == 0 && mDeleteStatus) + { + mResourceManager->deleteProgram(mHandle); + } +} + +void Program::addRef() +{ + mRefCount++; +} + +unsigned int Program::getRefCount() const +{ + return mRefCount; +} + +GLint Program::getProgramBinaryLength() const +{ + ProgramBinary *programBinary = mProgramBinary.get(); + if (programBinary) + { + return programBinary->getLength(); + } + else + { + return 0; + } +} + +int Program::getInfoLogLength() const +{ + return mInfoLog.getLength(); +} + +void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) +{ + return mInfoLog.getLog(bufSize, length, infoLog); +} + +void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders) +{ + int total = 0; + + if (mVertexShader) + { + if (total < maxCount) + { + shaders[total] = mVertexShader->getHandle(); + } + + total++; + } + + if (mFragmentShader) + { + if (total < maxCount) + { + shaders[total] = mFragmentShader->getHandle(); + } + + total++; + } + + if (count) + { + *count = total; + } +} + +void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) +{ + ProgramBinary *programBinary = getProgramBinary(); + if (programBinary) + { + programBinary->getActiveAttribute(index, bufsize, length, size, type, name); + } + else + { + if (bufsize > 0) + { + name[0] = '\0'; + } + + if (length) + { + *length = 0; + } + + *type = GL_NONE; + *size = 1; + } +} + +GLint Program::getActiveAttributeCount() +{ + ProgramBinary *programBinary = getProgramBinary(); + if (programBinary) + { + return programBinary->getActiveAttributeCount(); + } + else + { + return 0; + } +} + +GLint Program::getActiveAttributeMaxLength() +{ + ProgramBinary *programBinary = getProgramBinary(); + if (programBinary) + { + return programBinary->getActiveAttributeMaxLength(); + } + else + { + return 0; + } +} + +void Program::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) +{ + ProgramBinary *programBinary = getProgramBinary(); + if (programBinary) + { + return programBinary->getActiveUniform(index, bufsize, length, size, type, name); + } + else + { + if (bufsize > 0) + { + name[0] = '\0'; + } + + if (length) + { + *length = 0; + } + + *size = 0; + *type = GL_NONE; + } +} + +GLint Program::getActiveUniformCount() +{ + ProgramBinary *programBinary = getProgramBinary(); + if (programBinary) + { + return programBinary->getActiveUniformCount(); + } + else + { + return 0; + } +} + +GLint Program::getActiveUniformMaxLength() +{ + ProgramBinary *programBinary = getProgramBinary(); + if (programBinary) + { + return programBinary->getActiveUniformMaxLength(); + } + else + { + return 0; + } +} + +void Program::flagForDeletion() +{ + mDeleteStatus = true; +} + +bool Program::isFlaggedForDeletion() const +{ + return mDeleteStatus; +} + +void Program::validate() +{ + mInfoLog.reset(); + + ProgramBinary *programBinary = getProgramBinary(); + if (isLinked() && programBinary) + { + programBinary->validate(mInfoLog); + } + else + { + mInfoLog.append("Program has not been successfully linked."); + } +} + +bool Program::isValidated() const +{ + ProgramBinary *programBinary = mProgramBinary.get(); + if (programBinary) + { + return programBinary->isValidated(); + } + else + { + return false; + } +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/Program.h b/src/3rdparty/angle/src/libGLESv2/Program.h new file mode 100644 index 0000000000..1c4716bfe8 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/Program.h @@ -0,0 +1,121 @@ +// +// 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. +// + +// Program.h: Defines the gl::Program class. Implements GL program objects +// and related functionality. [OpenGL ES 2.0.24] section 2.10.3 page 28. + +#ifndef LIBGLESV2_PROGRAM_H_ +#define LIBGLESV2_PROGRAM_H_ + +#include <string> +#include <set> + +#include "libGLESv2/Shader.h" +#include "libGLESv2/Context.h" + +namespace gl +{ +class ResourceManager; +class FragmentShader; +class VertexShader; + +extern const char * const g_fakepath; + +class AttributeBindings +{ + public: + AttributeBindings(); + ~AttributeBindings(); + + void bindAttributeLocation(GLuint index, const char *name); + int getAttributeBinding(const std::string &name) const; + + private: + std::set<std::string> mAttributeBinding[MAX_VERTEX_ATTRIBS]; +}; + +class InfoLog +{ + public: + InfoLog(); + ~InfoLog(); + + int getLength() const; + void getLog(GLsizei bufSize, GLsizei *length, char *infoLog); + + void appendSanitized(const char *message); + void append(const char *info, ...); + void reset(); + private: + DISALLOW_COPY_AND_ASSIGN(InfoLog); + char *mInfoLog; +}; + +class Program +{ + public: + Program(ResourceManager *manager, GLuint handle); + + ~Program(); + + bool attachShader(Shader *shader); + bool detachShader(Shader *shader); + int getAttachedShadersCount() const; + + void bindAttributeLocation(GLuint index, const char *name); + + bool link(); + bool isLinked(); + bool setProgramBinary(const void *binary, GLsizei length); + ProgramBinary *getProgramBinary(); + + int getInfoLogLength() const; + void getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog); + void getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders); + + void getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); + GLint getActiveAttributeCount(); + GLint getActiveAttributeMaxLength(); + + void getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); + GLint getActiveUniformCount(); + GLint getActiveUniformMaxLength(); + + void addRef(); + void release(); + unsigned int getRefCount() const; + void flagForDeletion(); + bool isFlaggedForDeletion() const; + + void validate(); + bool isValidated() const; + + GLint getProgramBinaryLength() const; + + private: + DISALLOW_COPY_AND_ASSIGN(Program); + + void unlink(bool destroy = false); + + FragmentShader *mFragmentShader; + VertexShader *mVertexShader; + + AttributeBindings mAttributeBindings; + + BindingPointer<ProgramBinary> mProgramBinary; + bool mLinked; + bool mDeleteStatus; // Flag to indicate that the program can be deleted when no longer in use + + unsigned int mRefCount; + + ResourceManager *mResourceManager; + const GLuint mHandle; + + InfoLog mInfoLog; +}; +} + +#endif // LIBGLESV2_PROGRAM_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/ProgramBinary.cpp b/src/3rdparty/angle/src/libGLESv2/ProgramBinary.cpp new file mode 100644 index 0000000000..b3f5e3b867 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/ProgramBinary.cpp @@ -0,0 +1,2794 @@ +// +// 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. +// + +// Program.cpp: Implements the gl::Program class. Implements GL program objects +// and related functionality. [OpenGL ES 2.0.24] section 2.10.3 page 28. + +#include "libGLESv2/BinaryStream.h" +#include "libGLESv2/Program.h" +#include "libGLESv2/ProgramBinary.h" + +#include "common/debug.h" +#include "common/version.h" + +#include "libGLESv2/main.h" +#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 +{ +std::string str(int i) +{ + char buffer[20]; + snprintf(buffer, sizeof(buffer), "%d", i); + return buffer; +} + +Uniform::Uniform(GLenum type, const std::string &_name, unsigned int arraySize) + : type(type), _name(_name), name(ProgramBinary::undecorateUniform(_name)), arraySize(arraySize) +{ + int bytes = UniformInternalSize(type) * arraySize; + data = new unsigned char[bytes]; + memset(data, 0, bytes); + dirty = true; +} + +Uniform::~Uniform() +{ + delete[] data; +} + +bool Uniform::isArray() +{ + size_t dot = _name.find_last_of('.'); + if (dot == std::string::npos) dot = -1; + + return _name.compare(dot + 1, dot + 4, "ar_") == 0; +} + +UniformLocation::UniformLocation(const std::string &_name, unsigned int element, unsigned int index) + : name(ProgramBinary::undecorateUniform(_name)), element(element), index(index) +{ +} + +unsigned int ProgramBinary::mCurrentSerial = 1; + +ProgramBinary::ProgramBinary() : RefCountObject(0), mSerial(issueSerial()) +{ + mDevice = getDevice(); + + mPixelExecutable = NULL; + mVertexExecutable = NULL; + mConstantTablePS = NULL; + mConstantTableVS = NULL; + + mValidated = false; + + for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++) + { + mSemanticIndex[index] = -1; + } + + for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++) + { + mSamplersPS[index].active = false; + } + + for (int index = 0; index < MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF; index++) + { + mSamplersVS[index].active = false; + } + + mUsedVertexSamplerRange = 0; + mUsedPixelSamplerRange = 0; + + mDxDepthRangeLocation = -1; + mDxDepthLocation = -1; + mDxCoordLocation = -1; + mDxHalfPixelSizeLocation = -1; + mDxFrontCCWLocation = -1; + mDxPointsOrLinesLocation = -1; +} + +ProgramBinary::~ProgramBinary() +{ + if (mPixelExecutable) + { + mPixelExecutable->Release(); + } + + if (mVertexExecutable) + { + mVertexExecutable->Release(); + } + + delete mConstantTablePS; + delete mConstantTableVS; + + while (!mUniforms.empty()) + { + delete mUniforms.back(); + mUniforms.pop_back(); + } +} + +unsigned int ProgramBinary::getSerial() const +{ + return mSerial; +} + +unsigned int ProgramBinary::issueSerial() +{ + return mCurrentSerial++; +} + +IDirect3DPixelShader9 *ProgramBinary::getPixelShader() +{ + return mPixelExecutable; +} + +IDirect3DVertexShader9 *ProgramBinary::getVertexShader() +{ + return mVertexExecutable; +} + +GLuint ProgramBinary::getAttributeLocation(const char *name) +{ + if (name) + { + for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++) + { + if (mLinkedAttribute[index].name == std::string(name)) + { + return index; + } + } + } + + return -1; +} + +int ProgramBinary::getSemanticIndex(int attributeIndex) +{ + ASSERT(attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS); + + return mSemanticIndex[attributeIndex]; +} + +// Returns one more than the highest sampler index used. +GLint ProgramBinary::getUsedSamplerRange(SamplerType type) +{ + switch (type) + { + case SAMPLER_PIXEL: + return mUsedPixelSamplerRange; + case SAMPLER_VERTEX: + return mUsedVertexSamplerRange; + default: + UNREACHABLE(); + return 0; + } +} + +bool ProgramBinary::usesPointSize() const +{ + return mUsesPointSize; +} + +// 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 ProgramBinary::getSamplerMapping(SamplerType type, unsigned int samplerIndex) +{ + GLint logicalTextureUnit = -1; + + switch (type) + { + 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 < (GLint)getContext()->getMaximumCombinedTextureImageUnits()) + { + return logicalTextureUnit; + } + + return -1; +} + +// 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 ProgramBinary::getSamplerTextureType(SamplerType type, unsigned int samplerIndex) +{ + switch (type) + { + 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(); + } + + return TEXTURE_2D; +} + +GLint ProgramBinary::getUniformLocation(std::string name) +{ + 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) + { + 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 && + mUniformIndex[location].element == subscript) + { + return location; + } + } + + return -1; +} + +bool ProgramBinary::setUniform1fv(GLint location, GLsizei count, const GLfloat* v) +{ + if (location < 0 || location >= (int)mUniformIndex.size()) + { + return false; + } + + Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; + targetUniform->dirty = true; + + if (targetUniform->type == GL_FLOAT) + { + int arraySize = targetUniform->arraySize; + + if (arraySize == 1 && count > 1) + 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); + + 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) + { + int arraySize = targetUniform->arraySize; + + if (arraySize == 1 && count > 1) + 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 = (GLboolean*)targetUniform->data + mUniformIndex[location].element; + + for (int i = 0; i < count; ++i) + { + if (v[i] == 0.0f) + { + boolParams[i] = GL_FALSE; + } + else + { + boolParams[i] = GL_TRUE; + } + } + } + else + { + return false; + } + + return true; +} + +bool ProgramBinary::setUniform2fv(GLint location, GLsizei count, const GLfloat *v) +{ + if (location < 0 || location >= (int)mUniformIndex.size()) + { + return false; + } + + Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; + targetUniform->dirty = true; + + if (targetUniform->type == GL_FLOAT_VEC2) + { + int arraySize = targetUniform->arraySize; + + if (arraySize == 1 && count > 1) + 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); + + 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) + { + int arraySize = targetUniform->arraySize; + + if (arraySize == 1 && count > 1) + 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 = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 2; + + for (int i = 0; i < count * 2; ++i) + { + if (v[i] == 0.0f) + { + boolParams[i] = GL_FALSE; + } + else + { + boolParams[i] = GL_TRUE; + } + } + } + else + { + return false; + } + + return true; +} + +bool ProgramBinary::setUniform3fv(GLint location, GLsizei count, const GLfloat *v) +{ + if (location < 0 || location >= (int)mUniformIndex.size()) + { + return false; + } + + Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; + targetUniform->dirty = true; + + if (targetUniform->type == GL_FLOAT_VEC3) + { + int arraySize = targetUniform->arraySize; + + if (arraySize == 1 && count > 1) + 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); + + 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) + { + int arraySize = targetUniform->arraySize; + + if (arraySize == 1 && count > 1) + 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 = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 3; + + for (int i = 0; i < count * 3; ++i) + { + if (v[i] == 0.0f) + { + boolParams[i] = GL_FALSE; + } + else + { + boolParams[i] = GL_TRUE; + } + } + } + else + { + return false; + } + + return true; +} + +bool ProgramBinary::setUniform4fv(GLint location, GLsizei count, const GLfloat *v) +{ + if (location < 0 || location >= (int)mUniformIndex.size()) + { + return false; + } + + Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; + targetUniform->dirty = true; + + if (targetUniform->type == GL_FLOAT_VEC4) + { + int arraySize = targetUniform->arraySize; + + if (arraySize == 1 && count > 1) + 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); + + memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 4, + v, 4 * sizeof(GLfloat) * count); + } + else if (targetUniform->type == GL_BOOL_VEC4) + { + int arraySize = targetUniform->arraySize; + + if (arraySize == 1 && count > 1) + 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 = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 4; + + for (int i = 0; i < count * 4; ++i) + { + if (v[i] == 0.0f) + { + boolParams[i] = GL_FALSE; + } + else + { + boolParams[i] = GL_TRUE; + } + } + } + else + { + return false; + } + + 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 ProgramBinary::setUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value) +{ + if (location < 0 || location >= (int)mUniformIndex.size()) + { + return false; + } + + Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; + targetUniform->dirty = true; + + if (targetUniform->type != GL_FLOAT_MAT2) + { + return false; + } + + int arraySize = targetUniform->arraySize; + + if (arraySize == 1 && count > 1) + 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); + + 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; +} + +bool ProgramBinary::setUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value) +{ + if (location < 0 || location >= (int)mUniformIndex.size()) + { + return false; + } + + Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; + targetUniform->dirty = true; + + if (targetUniform->type != GL_FLOAT_MAT3) + { + return false; + } + + int arraySize = targetUniform->arraySize; + + if (arraySize == 1 && count > 1) + 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); + + 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 ProgramBinary::setUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value) +{ + if (location < 0 || location >= (int)mUniformIndex.size()) + { + return false; + } + + Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; + targetUniform->dirty = true; + + if (targetUniform->type != GL_FLOAT_MAT4) + { + return false; + } + + int arraySize = targetUniform->arraySize; + + if (arraySize == 1 && count > 1) + 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); + + 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; +} + +bool ProgramBinary::setUniform1iv(GLint location, GLsizei count, const GLint *v) +{ + if (location < 0 || location >= (int)mUniformIndex.size()) + { + return false; + } + + Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; + targetUniform->dirty = true; + + if (targetUniform->type == GL_INT || + targetUniform->type == GL_SAMPLER_2D || + targetUniform->type == GL_SAMPLER_CUBE) + { + int arraySize = targetUniform->arraySize; + + if (arraySize == 1 && count > 1) + 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); + + memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint), + v, sizeof(GLint) * count); + } + else if (targetUniform->type == GL_BOOL) + { + int arraySize = targetUniform->arraySize; + + if (arraySize == 1 && count > 1) + 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 = (GLboolean*)targetUniform->data + mUniformIndex[location].element; + + for (int i = 0; i < count; ++i) + { + if (v[i] == 0) + { + boolParams[i] = GL_FALSE; + } + else + { + boolParams[i] = GL_TRUE; + } + } + } + else + { + return false; + } + + return true; +} + +bool ProgramBinary::setUniform2iv(GLint location, GLsizei count, const GLint *v) +{ + if (location < 0 || location >= (int)mUniformIndex.size()) + { + return false; + } + + Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; + targetUniform->dirty = true; + + if (targetUniform->type == GL_INT_VEC2) + { + int arraySize = targetUniform->arraySize; + + if (arraySize == 1 && count > 1) + 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); + + memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 2, + v, 2 * sizeof(GLint) * count); + } + else if (targetUniform->type == GL_BOOL_VEC2) + { + int arraySize = targetUniform->arraySize; + + if (arraySize == 1 && count > 1) + 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 = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 2; + + for (int i = 0; i < count * 2; ++i) + { + if (v[i] == 0) + { + boolParams[i] = GL_FALSE; + } + else + { + boolParams[i] = GL_TRUE; + } + } + } + else + { + return false; + } + + return true; +} + +bool ProgramBinary::setUniform3iv(GLint location, GLsizei count, const GLint *v) +{ + if (location < 0 || location >= (int)mUniformIndex.size()) + { + return false; + } + + Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; + targetUniform->dirty = true; + + if (targetUniform->type == GL_INT_VEC3) + { + int arraySize = targetUniform->arraySize; + + if (arraySize == 1 && count > 1) + 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); + + memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 3, + v, 3 * sizeof(GLint) * count); + } + else if (targetUniform->type == GL_BOOL_VEC3) + { + int arraySize = targetUniform->arraySize; + + if (arraySize == 1 && count > 1) + 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 = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 3; + + for (int i = 0; i < count * 3; ++i) + { + if (v[i] == 0) + { + boolParams[i] = GL_FALSE; + } + else + { + boolParams[i] = GL_TRUE; + } + } + } + else + { + return false; + } + + return true; +} + +bool ProgramBinary::setUniform4iv(GLint location, GLsizei count, const GLint *v) +{ + if (location < 0 || location >= (int)mUniformIndex.size()) + { + return false; + } + + Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; + targetUniform->dirty = true; + + if (targetUniform->type == GL_INT_VEC4) + { + int arraySize = targetUniform->arraySize; + + if (arraySize == 1 && count > 1) + 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); + + memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 4, + v, 4 * sizeof(GLint) * count); + } + else if (targetUniform->type == GL_BOOL_VEC4) + { + int arraySize = targetUniform->arraySize; + + if (arraySize == 1 && count > 1) + 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 = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 4; + + for (int i = 0; i < count * 4; ++i) + { + if (v[i] == 0) + { + boolParams[i] = GL_FALSE; + } + else + { + boolParams[i] = GL_TRUE; + } + } + } + else + { + return false; + } + + return true; +} + +bool ProgramBinary::getUniformfv(GLint location, GLsizei *bufSize, GLfloat *params) +{ + if (location < 0 || location >= (int)mUniformIndex.size()) + { + return false; + } + + Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; + + // sized queries -- ensure the provided buffer is large enough + if (bufSize) + { + int requiredBytes = UniformExternalSize(targetUniform->type); + if (*bufSize < requiredBytes) + { + 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_MAT4: + transposeMatrix<GLfloat,4,4,4,4>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 16); + break; + default: + { + unsigned int count = UniformExternalComponentCount(targetUniform->type); + unsigned int internalCount = UniformInternalComponentCount(targetUniform->type); + + switch (UniformComponentType(targetUniform->type)) + { + 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(); + } + } + } + + return true; +} + +bool ProgramBinary::getUniformiv(GLint location, GLsizei *bufSize, GLint *params) +{ + if (location < 0 || location >= (int)mUniformIndex.size()) + { + return false; + } + + Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; + + // sized queries -- ensure the provided buffer is large enough + if (bufSize) + { + int requiredBytes = UniformExternalSize(targetUniform->type); + if (*bufSize < requiredBytes) + { + return false; + } + } + + 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_MAT4: + { + transposeMatrix<GLint,4,4,4,4>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 16); + } + break; + default: + { + unsigned int count = UniformExternalComponentCount(targetUniform->type); + unsigned int internalCount = UniformInternalComponentCount(targetUniform->type); + + switch (UniformComponentType(targetUniform->type)) + { + 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(); + } + } + } + + return true; +} + +void ProgramBinary::dirtyAllUniforms() +{ + unsigned int numUniforms = mUniforms.size(); + for (unsigned int index = 0; index < numUniforms; index++) + { + mUniforms[index]->dirty = true; + } +} + +// Applies all the uniforms set for this program object to the Direct3D 9 device +void ProgramBinary::applyUniforms() +{ + for (std::vector<Uniform*>::iterator ub = mUniforms.begin(), ue = mUniforms.end(); ub != ue; ++ub) { + Uniform *targetUniform = *ub; + + if (targetUniform->dirty) + { + int arraySize = targetUniform->arraySize; + GLfloat *f = (GLfloat*)targetUniform->data; + GLint *i = (GLint*)targetUniform->data; + GLboolean *b = (GLboolean*)targetUniform->data; + + switch (targetUniform->type) + { + 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(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(); + } + + targetUniform->dirty = false; + } + } +} + +// Compiles the HLSL code of the attached shaders into executable binaries +ID3D10Blob *ProgramBinary::compileToBinary(InfoLog &infoLog, const char *hlsl, const char *profile, D3DConstantTable **constantTable) +{ + if (!hlsl) + { + return NULL; + } + + DWORD result = NOERROR; + UINT flags = 0; + std::string sourceText; + if (perfActive()) + { + flags |= D3DCOMPILE_DEBUG; +#ifdef NDEBUG + flags |= ANGLE_COMPILE_OPTIMIZATION_LEVEL; +#else + flags |= D3DCOMPILE_SKIP_OPTIMIZATION; +#endif + + 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 + { + flags |= ANGLE_COMPILE_OPTIMIZATION_LEVEL; + sourceText = hlsl; + } + + // Sometimes D3DCompile will fail with the default compilation flags for complicated shaders when it would otherwise pass with alternative options. + // Try the default flags first and if compilation fails, try some alternatives. + const static UINT extraFlags[] = + { + 0, + D3DCOMPILE_AVOID_FLOW_CONTROL, + D3DCOMPILE_PREFER_FLOW_CONTROL + }; + + const static char * const extraFlagNames[] = + { + "default", + "avoid flow control", + "prefer flow control" + }; + + for (int i = 0; i < sizeof(extraFlags) / sizeof(UINT); ++i) + { + ID3D10Blob *errorMessage = NULL; + ID3D10Blob *binary = NULL; + result = D3DCompile(hlsl, strlen(hlsl), g_fakepath, NULL, NULL, "main", profile, flags | extraFlags[i], 0, &binary, &errorMessage); + + if (errorMessage) + { + const char *message = (const char*)errorMessage->GetBufferPointer(); + + infoLog.appendSanitized(message); + TRACE("\n%s", hlsl); + TRACE("\n%s", message); + + errorMessage->Release(); + errorMessage = NULL; + } + + if (SUCCEEDED(result)) + { + D3DConstantTable *table = new D3DConstantTable(binary->GetBufferPointer(), binary->GetBufferSize()); + if (table->error()) + { + delete table; + binary->Release(); + return NULL; + } + + *constantTable = table; + + return binary; + } + else + { + if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY) + { + return error(GL_OUT_OF_MEMORY, (ID3D10Blob*) NULL); + } + + infoLog.append("Warning: D3D shader compilation failed with "); + infoLog.append(extraFlagNames[i]); + infoLog.append(" flags."); + if (i + 1 < sizeof(extraFlagNames) / sizeof(char*)) + { + infoLog.append(" Retrying with "); + infoLog.append(extraFlagNames[i + 1]); + infoLog.append(".\n"); + } + } + } + + return NULL; +} + +// Packs varyings into generic varying registers, using the algorithm from [OpenGL ES Shading Language 1.00 rev. 17] appendix A section 7 page 111 +// Returns the number of used varying registers, or -1 if unsuccesful +int ProgramBinary::packVaryings(InfoLog &infoLog, const Varying *packing[][4], FragmentShader *fragmentShader) +{ + Context *context = getContext(); + const int maxVaryingVectors = context->getMaximumVaryingVectors(); + + for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++) + { + int n = VariableRowCount(varying->type) * varying->size; + int m = VariableColumnCount(varying->type); + bool success = false; + + if (m == 2 || m == 3 || m == 4) + { + for (int r = 0; r <= maxVaryingVectors - n && !success; r++) + { + bool available = true; + + for (int y = 0; y < n && available; y++) + { + for (int x = 0; x < m && available; x++) + { + if (packing[r + y][x]) + { + available = false; + } + } + } + + if (available) + { + varying->reg = r; + varying->col = 0; + + for (int y = 0; y < n; y++) + { + for (int x = 0; x < m; x++) + { + packing[r + y][x] = &*varying; + } + } + + success = true; + } + } + + if (!success && m == 2) + { + for (int r = maxVaryingVectors - n; r >= 0 && !success; r--) + { + bool available = true; + + for (int y = 0; y < n && available; y++) + { + for (int x = 2; x < 4 && available; x++) + { + if (packing[r + y][x]) + { + available = false; + } + } + } + + if (available) + { + varying->reg = r; + varying->col = 2; + + for (int y = 0; y < n; y++) + { + for (int x = 2; x < 4; x++) + { + packing[r + y][x] = &*varying; + } + } + + success = true; + } + } + } + } + else if (m == 1) + { + int space[4] = {0}; + + for (int y = 0; y < maxVaryingVectors; y++) + { + for (int x = 0; x < 4; x++) + { + space[x] += packing[y][x] ? 0 : 1; + } + } + + int column = 0; + + for (int x = 0; x < 4; x++) + { + if (space[x] >= n && space[x] < space[column]) + { + column = x; + } + } + + if (space[column] >= n) + { + for (int r = 0; r < maxVaryingVectors; r++) + { + if (!packing[r][column]) + { + varying->reg = r; + + for (int y = r; y < r + n; y++) + { + packing[y][column] = &*varying; + } + + break; + } + } + + varying->col = column; + + success = true; + } + } + else UNREACHABLE(); + + if (!success) + { + infoLog.append("Could not pack varying %s", varying->name.c_str()); + + return -1; + } + } + + // Return the number of used registers + int registers = 0; + + for (int r = 0; r < maxVaryingVectors; r++) + { + if (packing[r][0] || packing[r][1] || packing[r][2] || packing[r][3]) + { + registers++; + } + } + + return registers; +} + +bool ProgramBinary::linkVaryings(InfoLog &infoLog, std::string& pixelHLSL, std::string& vertexHLSL, FragmentShader *fragmentShader, VertexShader *vertexShader) +{ + if (pixelHLSL.empty() || vertexHLSL.empty()) + { + return false; + } + + // Reset the varying register assignments + for (VaryingList::iterator fragVar = fragmentShader->mVaryings.begin(); fragVar != fragmentShader->mVaryings.end(); fragVar++) + { + fragVar->reg = -1; + fragVar->col = -1; + } + + for (VaryingList::iterator vtxVar = vertexShader->mVaryings.begin(); vtxVar != vertexShader->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(infoLog, packing, fragmentShader); + + if (registers < 0) + { + return false; + } + + // Write the HLSL input/output declarations + Context *context = getContext(); + const bool sm3 = context->supportsShaderModel3(); + const int maxVaryingVectors = context->getMaximumVaryingVectors(); + + if (registers == maxVaryingVectors && fragmentShader->mUsesFragCoord) + { + infoLog.append("No varying registers left to support gl_FragCoord"); + + return false; + } + + for (VaryingList::iterator input = fragmentShader->mVaryings.begin(); input != fragmentShader->mVaryings.end(); input++) + { + bool matched = false; + + for (VaryingList::iterator output = vertexShader->mVaryings.begin(); output != vertexShader->mVaryings.end(); output++) + { + if (output->name == input->name) + { + if (output->type != input->type || output->size != input->size) + { + infoLog.append("Type of vertex varying %s does not match that of the fragment varying", output->name.c_str()); + + return false; + } + + output->reg = input->reg; + output->col = input->col; + + matched = true; + break; + } + } + + if (!matched) + { + infoLog.append("Fragment varying %s does not match any vertex varying", input->name.c_str()); + + return false; + } + } + + mUsesPointSize = vertexShader->mUsesPointSize; + std::string varyingSemantic = (mUsesPointSize && sm3) ? "COLOR" : "TEXCOORD"; + + vertexHLSL += "struct VS_INPUT\n" + "{\n"; + + int semanticIndex = 0; + for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++) + { + switch (attribute->type) + { + case GL_FLOAT: vertexHLSL += " float "; break; + case GL_FLOAT_VEC2: vertexHLSL += " float2 "; break; + case GL_FLOAT_VEC3: vertexHLSL += " float3 "; break; + case GL_FLOAT_VEC4: vertexHLSL += " float4 "; break; + case GL_FLOAT_MAT2: vertexHLSL += " float2x2 "; break; + case GL_FLOAT_MAT3: vertexHLSL += " float3x3 "; break; + case GL_FLOAT_MAT4: vertexHLSL += " float4x4 "; break; + default: UNREACHABLE(); + } + + vertexHLSL += decorateAttribute(attribute->name) + " : TEXCOORD" + str(semanticIndex) + ";\n"; + + semanticIndex += VariableRowCount(attribute->type); + } + + vertexHLSL += "};\n" + "\n" + "struct VS_OUTPUT\n" + "{\n" + " float4 gl_Position : POSITION;\n"; + + for (int r = 0; r < registers; r++) + { + int registerSize = packing[r][3] ? 4 : (packing[r][2] ? 3 : (packing[r][1] ? 2 : 1)); + + vertexHLSL += " float" + str(registerSize) + " v" + str(r) + " : " + varyingSemantic + str(r) + ";\n"; + } + + if (fragmentShader->mUsesFragCoord) + { + vertexHLSL += " float4 gl_FragCoord : " + varyingSemantic + str(registers) + ";\n"; + } + + if (vertexShader->mUsesPointSize && sm3) + { + vertexHLSL += " float gl_PointSize : PSIZE;\n"; + } + + vertexHLSL += "};\n" + "\n" + "VS_OUTPUT main(VS_INPUT input)\n" + "{\n"; + + for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++) + { + vertexHLSL += " " + decorateAttribute(attribute->name) + " = "; + + if (VariableRowCount(attribute->type) > 1) // Matrix + { + vertexHLSL += "transpose"; + } + + vertexHLSL += "(input." + decorateAttribute(attribute->name) + ");\n"; + } + + vertexHLSL += "\n" + " gl_main();\n" + "\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.z = (gl_Position.z + gl_Position.w) * 0.5;\n" + " output.gl_Position.w = gl_Position.w;\n"; + + if (vertexShader->mUsesPointSize && sm3) + { + vertexHLSL += " output.gl_PointSize = gl_PointSize;\n"; + } + + if (fragmentShader->mUsesFragCoord) + { + vertexHLSL += " output.gl_FragCoord = gl_Position;\n"; + } + + for (VaryingList::iterator varying = vertexShader->mVaryings.begin(); varying != vertexShader->mVaryings.end(); varying++) + { + if (varying->reg >= 0) + { + for (int i = 0; i < varying->size; i++) + { + int rows = VariableRowCount(varying->type); + + for (int j = 0; j < rows; j++) + { + int r = varying->reg + i * rows + j; + vertexHLSL += " output.v" + str(r); + + bool sharedRegister = false; // Register used by multiple varyings + + for (int x = 0; x < 4; x++) + { + if (packing[r][x] && packing[r][x] != packing[r][0]) + { + sharedRegister = true; + break; + } + } + + if(sharedRegister) + { + vertexHLSL += "."; + + for (int x = 0; x < 4; x++) + { + if (packing[r][x] == &*varying) + { + switch(x) + { + case 0: vertexHLSL += "x"; break; + case 1: vertexHLSL += "y"; break; + case 2: vertexHLSL += "z"; break; + case 3: vertexHLSL += "w"; break; + } + } + } + } + + vertexHLSL += " = " + varying->name; + + if (varying->array) + { + vertexHLSL += "[" + str(i) + "]"; + } + + if (rows > 1) + { + vertexHLSL += "[" + str(j) + "]"; + } + + vertexHLSL += ";\n"; + } + } + } + } + + vertexHLSL += "\n" + " return output;\n" + "}\n"; + + pixelHLSL += "struct PS_INPUT\n" + "{\n"; + + for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++) + { + if (varying->reg >= 0) + { + for (int i = 0; i < varying->size; i++) + { + int rows = VariableRowCount(varying->type); + for (int j = 0; j < rows; j++) + { + std::string n = str(varying->reg + i * rows + j); + pixelHLSL += " float4 v" + n + " : " + varyingSemantic + n + ";\n"; + } + } + } + else UNREACHABLE(); + } + + if (fragmentShader->mUsesFragCoord) + { + pixelHLSL += " float4 gl_FragCoord : " + varyingSemantic + str(registers) + ";\n"; + if (sm3) { + pixelHLSL += " float2 dx_VPos : VPOS;\n"; + } + } + + if (fragmentShader->mUsesPointCoord && sm3) + { + pixelHLSL += " float2 gl_PointCoord : TEXCOORD0;\n"; + } + + if (fragmentShader->mUsesFrontFacing) + { + pixelHLSL += " float vFace : VFACE;\n"; + } + + pixelHLSL += "};\n" + "\n" + "struct PS_OUTPUT\n" + "{\n" + " float4 gl_Color[1] : COLOR;\n" + "};\n" + "\n" + "PS_OUTPUT main(PS_INPUT input)\n" + "{\n"; + + if (fragmentShader->mUsesFragCoord) + { + pixelHLSL += " float rhw = 1.0 / input.gl_FragCoord.w;\n"; + + if (sm3) + { + pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x + 0.5;\n" + " gl_FragCoord.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() + pixelHLSL += " 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"; + } + + pixelHLSL += " gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * dx_Depth.x + dx_Depth.y;\n" + " gl_FragCoord.w = rhw;\n"; + } + + if (fragmentShader->mUsesPointCoord && sm3) + { + pixelHLSL += " gl_PointCoord.x = input.gl_PointCoord.x;\n"; + pixelHLSL += " gl_PointCoord.y = 1.0 - input.gl_PointCoord.y;\n"; + } + + if (fragmentShader->mUsesFrontFacing) + { + pixelHLSL += " gl_FrontFacing = dx_PointsOrLines || (dx_FrontCCW ? (input.vFace >= 0.0) : (input.vFace <= 0.0));\n"; + } + + for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++) + { + if (varying->reg >= 0) + { + for (int i = 0; i < varying->size; i++) + { + int rows = VariableRowCount(varying->type); + for (int j = 0; j < rows; j++) + { + std::string n = str(varying->reg + i * rows + j); + pixelHLSL += " " + varying->name; + + if (varying->array) + { + pixelHLSL += "[" + str(i) + "]"; + } + + if (rows > 1) + { + pixelHLSL += "[" + str(j) + "]"; + } + + pixelHLSL += " = input.v" + n + ";\n"; + } + } + } + else UNREACHABLE(); + } + + pixelHLSL += "\n" + " gl_main();\n" + "\n" + " PS_OUTPUT output;\n" + " output.gl_Color[0] = gl_Color[0];\n" + "\n" + " return output;\n" + "}\n"; + + return true; +} + +bool ProgramBinary::load(InfoLog &infoLog, const void *binary, GLsizei length) +{ + BinaryInputStream stream(binary, length); + + int format = 0; + stream.read(&format); + if (format != GL_PROGRAM_BINARY_ANGLE) + { + infoLog.append("Invalid program binary format."); + return false; + } + + int version = 0; + stream.read(&version); + if (version != BUILD_REVISION) + { + infoLog.append("Invalid program binary version."); + return false; + } + + for (int i = 0; i < MAX_VERTEX_ATTRIBS; ++i) + { + stream.read(&mLinkedAttribute[i].type); + std::string name; + stream.read(&name); + mLinkedAttribute[i].name = name; + stream.read(&mSemanticIndex[i]); + } + + for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i) + { + stream.read(&mSamplersPS[i].active); + stream.read(&mSamplersPS[i].logicalTextureUnit); + + int textureType; + stream.read(&textureType); + mSamplersPS[i].textureType = (TextureType) textureType; + } + + for (unsigned int i = 0; i < MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF; ++i) + { + stream.read(&mSamplersVS[i].active); + stream.read(&mSamplersVS[i].logicalTextureUnit); + + int textureType; + stream.read(&textureType); + mSamplersVS[i].textureType = (TextureType) textureType; + } + + stream.read(&mUsedVertexSamplerRange); + stream.read(&mUsedPixelSamplerRange); + + unsigned int size; + stream.read(&size); + if (stream.error()) + { + infoLog.append("Invalid program binary."); + return false; + } + + mUniforms.resize(size); + for (unsigned int i = 0; i < size; ++i) + { + GLenum type; + std::string _name; + unsigned int arraySize; + + stream.read(&type); + stream.read(&_name); + stream.read(&arraySize); + + mUniforms[i] = new Uniform(type, _name, arraySize); + + stream.read(&mUniforms[i]->ps.float4Index); + stream.read(&mUniforms[i]->ps.samplerIndex); + stream.read(&mUniforms[i]->ps.boolIndex); + stream.read(&mUniforms[i]->ps.registerCount); + + stream.read(&mUniforms[i]->vs.float4Index); + stream.read(&mUniforms[i]->vs.samplerIndex); + stream.read(&mUniforms[i]->vs.boolIndex); + stream.read(&mUniforms[i]->vs.registerCount); + } + + stream.read(&size); + if (stream.error()) + { + infoLog.append("Invalid program binary."); + return false; + } + + mUniformIndex.resize(size); + for (unsigned int i = 0; i < size; ++i) + { + stream.read(&mUniformIndex[i].name); + stream.read(&mUniformIndex[i].element); + stream.read(&mUniformIndex[i].index); + } + + stream.read(&mDxDepthRangeLocation); + stream.read(&mDxDepthLocation); + stream.read(&mDxCoordLocation); + stream.read(&mDxHalfPixelSizeLocation); + stream.read(&mDxFrontCCWLocation); + stream.read(&mDxPointsOrLinesLocation); + + unsigned int pixelShaderSize; + stream.read(&pixelShaderSize); + + unsigned int vertexShaderSize; + stream.read(&vertexShaderSize); + + const char *ptr = (const char*) binary + stream.offset(); + + const D3DCAPS9 *binaryIdentifier = (const D3DCAPS9*) ptr; + ptr += sizeof(GUID); + + D3DADAPTER_IDENTIFIER9 *currentIdentifier = getDisplay()->getAdapterIdentifier(); + if (memcmp(¤tIdentifier->DeviceIdentifier, binaryIdentifier, sizeof(GUID)) != 0) + { + infoLog.append("Invalid program binary."); + return false; + } + + const char *pixelShaderFunction = ptr; + ptr += pixelShaderSize; + + const char *vertexShaderFunction = ptr; + ptr += vertexShaderSize; + + mPixelExecutable = getDisplay()->createPixelShader(reinterpret_cast<const DWORD*>(pixelShaderFunction), pixelShaderSize); + if (!mPixelExecutable) + { + infoLog.append("Could not create pixel shader."); + return false; + } + + mVertexExecutable = getDisplay()->createVertexShader(reinterpret_cast<const DWORD*>(vertexShaderFunction), vertexShaderSize); + if (!mVertexExecutable) + { + infoLog.append("Could not create vertex shader."); + mPixelExecutable->Release(); + mPixelExecutable = NULL; + return false; + } + + return true; +} + +bool ProgramBinary::save(void* binary, GLsizei bufSize, GLsizei *length) +{ + BinaryOutputStream stream; + + stream.write(GL_PROGRAM_BINARY_ANGLE); + stream.write(BUILD_REVISION); + + for (unsigned int i = 0; i < MAX_VERTEX_ATTRIBS; ++i) + { + stream.write(mLinkedAttribute[i].type); + stream.write(mLinkedAttribute[i].name); + stream.write(mSemanticIndex[i]); + } + + for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i) + { + stream.write(mSamplersPS[i].active); + stream.write(mSamplersPS[i].logicalTextureUnit); + stream.write((int) mSamplersPS[i].textureType); + } + + for (unsigned int i = 0; i < MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF; ++i) + { + stream.write(mSamplersVS[i].active); + stream.write(mSamplersVS[i].logicalTextureUnit); + stream.write((int) mSamplersVS[i].textureType); + } + + stream.write(mUsedVertexSamplerRange); + stream.write(mUsedPixelSamplerRange); + + stream.write(mUniforms.size()); + for (unsigned int i = 0; i < mUniforms.size(); ++i) + { + stream.write(mUniforms[i]->type); + stream.write(mUniforms[i]->_name); + stream.write(mUniforms[i]->arraySize); + + stream.write(mUniforms[i]->ps.float4Index); + stream.write(mUniforms[i]->ps.samplerIndex); + stream.write(mUniforms[i]->ps.boolIndex); + stream.write(mUniforms[i]->ps.registerCount); + + stream.write(mUniforms[i]->vs.float4Index); + stream.write(mUniforms[i]->vs.samplerIndex); + stream.write(mUniforms[i]->vs.boolIndex); + stream.write(mUniforms[i]->vs.registerCount); + } + + stream.write(mUniformIndex.size()); + for (unsigned int i = 0; i < mUniformIndex.size(); ++i) + { + stream.write(mUniformIndex[i].name); + stream.write(mUniformIndex[i].element); + stream.write(mUniformIndex[i].index); + } + + stream.write(mDxDepthRangeLocation); + stream.write(mDxDepthLocation); + stream.write(mDxCoordLocation); + stream.write(mDxHalfPixelSizeLocation); + stream.write(mDxFrontCCWLocation); + stream.write(mDxPointsOrLinesLocation); + + UINT pixelShaderSize; + HRESULT result = mPixelExecutable->GetFunction(NULL, &pixelShaderSize); + ASSERT(SUCCEEDED(result)); + stream.write(pixelShaderSize); + + UINT vertexShaderSize; + result = mVertexExecutable->GetFunction(NULL, &vertexShaderSize); + ASSERT(SUCCEEDED(result)); + stream.write(vertexShaderSize); + + D3DADAPTER_IDENTIFIER9 *identifier = getDisplay()->getAdapterIdentifier(); + + GLsizei streamLength = stream.length(); + const void *streamData = stream.data(); + + GLsizei totalLength = streamLength + sizeof(GUID) + pixelShaderSize + vertexShaderSize; + if (totalLength > bufSize) + { + if (length) + { + *length = 0; + } + + return false; + } + + if (binary) + { + char *ptr = (char*) binary; + + memcpy(ptr, streamData, streamLength); + ptr += streamLength; + + memcpy(ptr, &identifier->DeviceIdentifier, sizeof(GUID)); + ptr += sizeof(GUID); + + result = mPixelExecutable->GetFunction(ptr, &pixelShaderSize); + ASSERT(SUCCEEDED(result)); + ptr += pixelShaderSize; + + result = mVertexExecutable->GetFunction(ptr, &vertexShaderSize); + ASSERT(SUCCEEDED(result)); + ptr += vertexShaderSize; + + ASSERT(ptr - totalLength == binary); + } + + if (length) + { + *length = totalLength; + } + + return true; +} + +GLint ProgramBinary::getLength() +{ + GLint length; + if (save(NULL, INT_MAX, &length)) + { + return length; + } + else + { + return 0; + } +} + +bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader) +{ + if (!fragmentShader || !fragmentShader->isCompiled()) + { + return false; + } + + if (!vertexShader || !vertexShader->isCompiled()) + { + return false; + } + + std::string pixelHLSL = fragmentShader->getHLSL(); + std::string vertexHLSL = vertexShader->getHLSL(); + + if (!linkVaryings(infoLog, pixelHLSL, vertexHLSL, fragmentShader, vertexShader)) + { + return false; + } + + Context *context = getContext(); + const char *vertexProfile = context->supportsShaderModel3() ? "vs_3_0" : "vs_2_0"; + const char *pixelProfile = context->supportsShaderModel3() ? "ps_3_0" : "ps_2_0"; + + ID3D10Blob *vertexBinary = compileToBinary(infoLog, vertexHLSL.c_str(), vertexProfile, &mConstantTableVS); + ID3D10Blob *pixelBinary = compileToBinary(infoLog, pixelHLSL.c_str(), pixelProfile, &mConstantTablePS); + + if (vertexBinary && pixelBinary) + { + mVertexExecutable = getDisplay()->createVertexShader((DWORD*)vertexBinary->GetBufferPointer(), vertexBinary->GetBufferSize()); + if (!mVertexExecutable) + { + return error(GL_OUT_OF_MEMORY, false); + } + + mPixelExecutable = getDisplay()->createPixelShader((DWORD*)pixelBinary->GetBufferPointer(), pixelBinary->GetBufferSize()); + if (!mPixelExecutable) + { + mVertexExecutable->Release(); + mVertexExecutable = NULL; + return error(GL_OUT_OF_MEMORY, false); + } + + vertexBinary->Release(); + pixelBinary->Release(); + vertexBinary = NULL; + pixelBinary = NULL; + + if (!linkAttributes(infoLog, attributeBindings, fragmentShader, vertexShader)) + { + return false; + } + + if (!linkUniforms(infoLog, GL_FRAGMENT_SHADER, mConstantTablePS)) + { + return false; + } + + if (!linkUniforms(infoLog, GL_VERTEX_SHADER, mConstantTableVS)) + { + return false; + } + + // these uniforms are searched as already-decorated because gl_ and dx_ + // are reserved prefixes, and do not receive additional decoration + mDxDepthRangeLocation = getUniformLocation("dx_DepthRange"); + mDxDepthLocation = getUniformLocation("dx_Depth"); + mDxCoordLocation = getUniformLocation("dx_Coord"); + mDxHalfPixelSizeLocation = getUniformLocation("dx_HalfPixelSize"); + mDxFrontCCWLocation = getUniformLocation("dx_FrontCCW"); + mDxPointsOrLinesLocation = getUniformLocation("dx_PointsOrLines"); + + context->markDxUniformsDirty(); + + return true; + } + + return false; +} + +// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices +bool ProgramBinary::linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader) +{ + unsigned int usedLocations = 0; + + // Link attributes that have a binding location + for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++) + { + int location = attributeBindings.getAttributeBinding(attribute->name); + + if (location != -1) // Set by glBindAttribLocation + { + if (!mLinkedAttribute[location].name.empty()) + { + // Multiple active attributes bound to the same location; not an error + } + + mLinkedAttribute[location] = *attribute; + + int rows = VariableRowCount(attribute->type); + + if (rows + location > MAX_VERTEX_ATTRIBS) + { + infoLog.append("Active attribute (%s) at location %d is too big to fit", attribute->name.c_str(), location); + + return false; + } + + for (int i = 0; i < rows; i++) + { + usedLocations |= 1 << (location + i); + } + } + } + + // Link attributes that don't have a binding location + for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++) + { + int location = attributeBindings.getAttributeBinding(attribute->name); + + if (location == -1) // Not set by glBindAttribLocation + { + int rows = VariableRowCount(attribute->type); + int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS); + + if (availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS) + { + infoLog.append("Too many active attributes (%s)", attribute->name.c_str()); + + return false; // Fail to link + } + + mLinkedAttribute[availableIndex] = *attribute; + } + } + + for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; ) + { + int index = vertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name); + int rows = std::max(VariableRowCount(mLinkedAttribute[attributeIndex].type), 1); + + for (int r = 0; r < rows; r++) + { + mSemanticIndex[attributeIndex++] = index++; + } + } + + return true; +} + +bool ProgramBinary::linkUniforms(InfoLog &infoLog, GLenum shader, D3DConstantTable *constantTable) +{ + for (unsigned int constantIndex = 0; constantIndex < constantTable->constants(); constantIndex++) + { + const D3DConstant *constant = constantTable->getConstant(constantIndex); + + if (!defineUniform(infoLog, shader, constant)) + { + return false; + } + } + + return true; +} + +// Adds the description of a constant found in the binary shader to the list of uniforms +// Returns true if succesful (uniform not already defined) +bool ProgramBinary::defineUniform(InfoLog &infoLog, GLenum shader, const D3DConstant *constant, std::string name) +{ + if (constant->registerSet == D3DConstant::RS_SAMPLER) + { + for (unsigned int i = 0; i < constant->registerCount; i++) + { + const D3DConstant *psConstant = mConstantTablePS->getConstantByName(constant->name.c_str()); + const D3DConstant *vsConstant = mConstantTableVS->getConstantByName(constant->name.c_str()); + + if (psConstant) + { + unsigned int samplerIndex = psConstant->registerIndex + i; + + if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS) + { + mSamplersPS[samplerIndex].active = true; + mSamplersPS[samplerIndex].textureType = (constant->type == D3DConstant::PT_SAMPLERCUBE) ? TEXTURE_CUBE : TEXTURE_2D; + mSamplersPS[samplerIndex].logicalTextureUnit = 0; + mUsedPixelSamplerRange = std::max(samplerIndex + 1, mUsedPixelSamplerRange); + } + else + { + infoLog.append("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", MAX_TEXTURE_IMAGE_UNITS); + return false; + } + } + + if (vsConstant) + { + unsigned int samplerIndex = vsConstant->registerIndex + i; + + if (samplerIndex < getContext()->getMaximumVertexTextureImageUnits()) + { + mSamplersVS[samplerIndex].active = true; + mSamplersVS[samplerIndex].textureType = (constant->type == D3DConstant::PT_SAMPLERCUBE) ? TEXTURE_CUBE : TEXTURE_2D; + mSamplersVS[samplerIndex].logicalTextureUnit = 0; + mUsedVertexSamplerRange = std::max(samplerIndex + 1, mUsedVertexSamplerRange); + } + else + { + infoLog.append("Vertex shader sampler count exceeds MAX_VERTEX_TEXTURE_IMAGE_UNITS (%d).", getContext()->getMaximumVertexTextureImageUnits()); + return false; + } + } + } + } + + switch(constant->typeClass) + { + case D3DConstant::CLASS_STRUCT: + { + for (unsigned int arrayIndex = 0; arrayIndex < constant->elements; arrayIndex++) + { + for (unsigned int field = 0; field < constant->structMembers[arrayIndex].size(); field++) + { + const D3DConstant *fieldConstant = constant->structMembers[arrayIndex][field]; + + std::string structIndex = (constant->elements > 1) ? ("[" + str(arrayIndex) + "]") : ""; + + if (!defineUniform(infoLog, shader, fieldConstant, name + constant->name + structIndex + ".")) + { + return false; + } + } + } + + return true; + } + case D3DConstant::CLASS_SCALAR: + case D3DConstant::CLASS_VECTOR: + case D3DConstant::CLASS_MATRIX_COLUMNS: + case D3DConstant::CLASS_OBJECT: + return defineUniform(shader, constant, name + constant->name); + default: + UNREACHABLE(); + return false; + } +} + +bool ProgramBinary::defineUniform(GLenum shader, const D3DConstant *constant, const std::string &_name) +{ + Uniform *uniform = createUniform(constant, _name); + + if(!uniform) + { + return false; + } + + // Check if already defined + GLint location = getUniformLocation(uniform->name); + GLenum type = uniform->type; + + if (location >= 0) + { + delete uniform; + uniform = mUniforms[mUniformIndex[location].index]; + } + + if (shader == GL_FRAGMENT_SHADER) uniform->ps.set(constant); + if (shader == GL_VERTEX_SHADER) uniform->vs.set(constant); + + if (location >= 0) + { + return uniform->type == type; + } + + 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)); + } + + return true; +} + +Uniform *ProgramBinary::createUniform(const D3DConstant *constant, const std::string &_name) +{ + if (constant->rows == 1) // Vectors and scalars + { + switch (constant->type) + { + case D3DConstant::PT_SAMPLER2D: + switch (constant->columns) + { + case 1: return new Uniform(GL_SAMPLER_2D, _name, constant->elements); + default: UNREACHABLE(); + } + break; + case D3DConstant::PT_SAMPLERCUBE: + switch (constant->columns) + { + case 1: return new Uniform(GL_SAMPLER_CUBE, _name, constant->elements); + default: UNREACHABLE(); + } + break; + case D3DConstant::PT_BOOL: + switch (constant->columns) + { + case 1: return new Uniform(GL_BOOL, _name, constant->elements); + case 2: return new Uniform(GL_BOOL_VEC2, _name, constant->elements); + case 3: return new Uniform(GL_BOOL_VEC3, _name, constant->elements); + case 4: return new Uniform(GL_BOOL_VEC4, _name, constant->elements); + default: UNREACHABLE(); + } + break; + case D3DConstant::PT_INT: + switch (constant->columns) + { + case 1: return new Uniform(GL_INT, _name, constant->elements); + case 2: return new Uniform(GL_INT_VEC2, _name, constant->elements); + case 3: return new Uniform(GL_INT_VEC3, _name, constant->elements); + case 4: return new Uniform(GL_INT_VEC4, _name, constant->elements); + default: UNREACHABLE(); + } + break; + case D3DConstant::PT_FLOAT: + switch (constant->columns) + { + case 1: return new Uniform(GL_FLOAT, _name, constant->elements); + case 2: return new Uniform(GL_FLOAT_VEC2, _name, constant->elements); + case 3: return new Uniform(GL_FLOAT_VEC3, _name, constant->elements); + case 4: return new Uniform(GL_FLOAT_VEC4, _name, constant->elements); + default: UNREACHABLE(); + } + break; + default: + UNREACHABLE(); + } + } + else if (constant->rows == constant->columns) // Square matrices + { + switch (constant->type) + { + case D3DConstant::PT_FLOAT: + switch (constant->rows) + { + case 2: return new Uniform(GL_FLOAT_MAT2, _name, constant->elements); + case 3: return new Uniform(GL_FLOAT_MAT3, _name, constant->elements); + case 4: return new Uniform(GL_FLOAT_MAT4, _name, constant->elements); + default: UNREACHABLE(); + } + break; + default: UNREACHABLE(); + } + } + else UNREACHABLE(); + + return 0; +} + +// This method needs to match OutputHLSL::decorate +std::string ProgramBinary::decorateAttribute(const std::string &name) +{ + if (name.compare(0, 3, "gl_") != 0 && name.compare(0, 3, "dx_") != 0) + { + return "_" + name; + } + + return name; +} + +std::string ProgramBinary::undecorateUniform(const std::string &_name) +{ + std::string name = _name; + + // Remove any structure field decoration + size_t pos = 0; + while ((pos = name.find("._", pos)) != std::string::npos) + { + name.replace(pos, 2, "."); + } + + // Remove the leading decoration + if (name[0] == '_') + { + return name.substr(1); + } + else if (name.compare(0, 3, "ar_") == 0) + { + return name.substr(3); + } + + return name; +} + +void ProgramBinary::applyUniformnbv(Uniform *targetUniform, GLsizei count, int width, const GLboolean *v) +{ + float vector[D3D9_MAX_FLOAT_CONSTANTS * 4]; + BOOL boolVector[D3D9_MAX_BOOL_CONSTANTS]; + + if (targetUniform->ps.float4Index >= 0 || targetUniform->vs.float4Index >= 0) + { + 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 (targetUniform->ps.boolIndex >= 0 || targetUniform->vs.boolIndex >= 0) + { + int psCount = targetUniform->ps.boolIndex >= 0 ? targetUniform->ps.registerCount : 0; + int vsCount = targetUniform->vs.boolIndex >= 0 ? 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; + } + } + + if (targetUniform->ps.float4Index >= 0) + { + mDevice->SetPixelShaderConstantF(targetUniform->ps.float4Index, vector, targetUniform->ps.registerCount); + } + + if (targetUniform->ps.boolIndex >= 0) + { + mDevice->SetPixelShaderConstantB(targetUniform->ps.boolIndex, boolVector, targetUniform->ps.registerCount); + } + + if (targetUniform->vs.float4Index >= 0) + { + mDevice->SetVertexShaderConstantF(targetUniform->vs.float4Index, vector, targetUniform->vs.registerCount); + } + + if (targetUniform->vs.boolIndex >= 0) + { + mDevice->SetVertexShaderConstantB(targetUniform->vs.boolIndex, boolVector, targetUniform->vs.registerCount); + } +} + +bool ProgramBinary::applyUniformnfv(Uniform *targetUniform, const GLfloat *v) +{ + if (targetUniform->ps.registerCount) + { + mDevice->SetPixelShaderConstantF(targetUniform->ps.float4Index, v, targetUniform->ps.registerCount); + } + + if (targetUniform->vs.registerCount) + { + mDevice->SetVertexShaderConstantF(targetUniform->vs.float4Index, v, targetUniform->vs.registerCount); + } + + return true; +} + +bool ProgramBinary::applyUniform1iv(Uniform *targetUniform, GLsizei count, const GLint *v) +{ + ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS); + Vector4 vector[D3D9_MAX_FLOAT_CONSTANTS]; + + for (int i = 0; i < count; i++) + { + vector[i] = Vector4((float)v[i], 0, 0, 0); + } + + if (targetUniform->ps.registerCount) + { + if (targetUniform->ps.samplerIndex >= 0) + { + unsigned int firstIndex = targetUniform->ps.samplerIndex; + + for (int i = 0; i < count; i++) + { + unsigned int samplerIndex = firstIndex + i; + + if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS) + { + ASSERT(mSamplersPS[samplerIndex].active); + mSamplersPS[samplerIndex].logicalTextureUnit = v[i]; + } + } + } + else + { + ASSERT(targetUniform->ps.float4Index >= 0); + mDevice->SetPixelShaderConstantF(targetUniform->ps.float4Index, (const float*)vector, targetUniform->ps.registerCount); + } + } + + if (targetUniform->vs.registerCount) + { + if (targetUniform->vs.samplerIndex >= 0) + { + unsigned int firstIndex = targetUniform->vs.samplerIndex; + + 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.float4Index >= 0); + mDevice->SetVertexShaderConstantF(targetUniform->vs.float4Index, (const float *)vector, targetUniform->vs.registerCount); + } + } + + return true; +} + +bool ProgramBinary::applyUniform2iv(Uniform *targetUniform, GLsizei count, const GLint *v) +{ + ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS); + Vector4 vector[D3D9_MAX_FLOAT_CONSTANTS]; + + for (int i = 0; i < count; i++) + { + vector[i] = Vector4((float)v[0], (float)v[1], 0, 0); + + v += 2; + } + + applyUniformniv(targetUniform, count, vector); + + return true; +} + +bool ProgramBinary::applyUniform3iv(Uniform *targetUniform, GLsizei count, const GLint *v) +{ + ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS); + Vector4 vector[D3D9_MAX_FLOAT_CONSTANTS]; + + for (int i = 0; i < count; i++) + { + vector[i] = Vector4((float)v[0], (float)v[1], (float)v[2], 0); + + v += 3; + } + + applyUniformniv(targetUniform, count, vector); + + return true; +} + +bool ProgramBinary::applyUniform4iv(Uniform *targetUniform, GLsizei count, const GLint *v) +{ + ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS); + Vector4 vector[D3D9_MAX_FLOAT_CONSTANTS]; + + for (int i = 0; i < count; i++) + { + vector[i] = Vector4((float)v[0], (float)v[1], (float)v[2], (float)v[3]); + + v += 4; + } + + applyUniformniv(targetUniform, count, vector); + + return true; +} + +void ProgramBinary::applyUniformniv(Uniform *targetUniform, GLsizei count, const Vector4 *vector) +{ + if (targetUniform->ps.registerCount) + { + ASSERT(targetUniform->ps.float4Index >= 0); + mDevice->SetPixelShaderConstantF(targetUniform->ps.float4Index, (const float *)vector, targetUniform->ps.registerCount); + } + + if (targetUniform->vs.registerCount) + { + ASSERT(targetUniform->vs.float4Index >= 0); + mDevice->SetVertexShaderConstantF(targetUniform->vs.float4Index, (const float *)vector, targetUniform->vs.registerCount); + } +} + +bool ProgramBinary::isValidated() const +{ + return mValidated; +} + +void ProgramBinary::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) +{ + // Skip over inactive attributes + unsigned int activeAttribute = 0; + unsigned int attribute; + for (attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++) + { + if (mLinkedAttribute[attribute].name.empty()) + { + continue; + } + + if (activeAttribute == index) + { + break; + } + + activeAttribute++; + } + + if (bufsize > 0) + { + const char *string = mLinkedAttribute[attribute].name.c_str(); + + strncpy(name, string, bufsize); + name[bufsize - 1] = '\0'; + + if (length) + { + *length = strlen(name); + } + } + + *size = 1; // Always a single 'type' instance + + *type = mLinkedAttribute[attribute].type; +} + +GLint ProgramBinary::getActiveAttributeCount() +{ + int count = 0; + + for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++) + { + if (!mLinkedAttribute[attributeIndex].name.empty()) + { + count++; + } + } + + return count; +} + +GLint ProgramBinary::getActiveAttributeMaxLength() +{ + int maxLength = 0; + + for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++) + { + if (!mLinkedAttribute[attributeIndex].name.empty()) + { + maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength); + } + } + + return maxLength; +} + +void ProgramBinary::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) +{ + // Skip over internal uniforms + unsigned int activeUniform = 0; + unsigned int uniform; + for (uniform = 0; uniform < mUniforms.size(); uniform++) + { + if (mUniforms[uniform]->name.compare(0, 3, "dx_") == 0) + { + continue; + } + + if (activeUniform == index) + { + break; + } + + activeUniform++; + } + + ASSERT(uniform < mUniforms.size()); // index must be smaller than getActiveUniformCount() + + if (bufsize > 0) + { + std::string string = mUniforms[uniform]->name; + + if (mUniforms[uniform]->isArray()) + { + string += "[0]"; + } + + strncpy(name, string.c_str(), bufsize); + name[bufsize - 1] = '\0'; + + if (length) + { + *length = strlen(name); + } + } + + *size = mUniforms[uniform]->arraySize; + + *type = mUniforms[uniform]->type; +} + +GLint ProgramBinary::getActiveUniformCount() +{ + int count = 0; + + unsigned int numUniforms = mUniforms.size(); + for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++) + { + if (mUniforms[uniformIndex]->name.compare(0, 3, "dx_") != 0) + { + count++; + } + } + + return count; +} + +GLint ProgramBinary::getActiveUniformMaxLength() +{ + int maxLength = 0; + + unsigned int numUniforms = mUniforms.size(); + for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++) + { + if (!mUniforms[uniformIndex]->name.empty() && mUniforms[uniformIndex]->name.compare(0, 3, "dx_") != 0) + { + int length = (int)(mUniforms[uniformIndex]->name.length() + 1); + if (mUniforms[uniformIndex]->isArray()) + { + length += 3; // Counting in "[0]". + } + maxLength = std::max(length, maxLength); + } + } + + return maxLength; +} + +void ProgramBinary::validate(InfoLog &infoLog) +{ + applyUniforms(); + if (!validateSamplers(&infoLog)) + { + mValidated = false; + } + else + { + mValidated = true; + } +} + +bool ProgramBinary::validateSamplers(InfoLog *infoLog) +{ + // 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. + + 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 (mSamplersPS[i].active) + { + unsigned int unit = mSamplersPS[i].logicalTextureUnit; + + if (unit >= maxCombinedTextureImageUnits) + { + if (infoLog) + { + infoLog->append("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 (infoLog) + { + infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit); + } + + return false; + } + } + else + { + 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 (infoLog) + { + infoLog->append("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 (infoLog) + { + infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit); + } + + return false; + } + } + else + { + textureUnitType[unit] = mSamplersVS[i].textureType; + } + } + } + + return true; +} + +GLint ProgramBinary::getDxDepthRangeLocation() const +{ + return mDxDepthRangeLocation; +} + +GLint ProgramBinary::getDxDepthLocation() const +{ + return mDxDepthLocation; +} + +GLint ProgramBinary::getDxCoordLocation() const +{ + return mDxCoordLocation; +} + +GLint ProgramBinary::getDxHalfPixelSizeLocation() const +{ + return mDxHalfPixelSizeLocation; +} + +GLint ProgramBinary::getDxFrontCCWLocation() const +{ + return mDxFrontCCWLocation; +} + +GLint ProgramBinary::getDxPointsOrLinesLocation() const +{ + return mDxPointsOrLinesLocation; +} + +ProgramBinary::Sampler::Sampler() : active(false), logicalTextureUnit(0), textureType(TEXTURE_2D) +{ +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/ProgramBinary.h b/src/3rdparty/angle/src/libGLESv2/ProgramBinary.h new file mode 100644 index 0000000000..9ffe70b617 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/ProgramBinary.h @@ -0,0 +1,235 @@ +// +// 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. +// + +// Program.h: Defines the gl::Program class. Implements GL program objects +// and related functionality. [OpenGL ES 2.0.24] section 2.10.3 page 28. + +#ifndef LIBGLESV2_PROGRAM_BINARY_H_ +#define LIBGLESV2_PROGRAM_BINARY_H_ + +#define GL_APICALL +#include <GLES2/gl2.h> +#include <GLES2/gl2ext.h> + +#include <d3dcompiler.h> +#include <string> +#include <vector> + +#include "libGLESv2/Context.h" +#include "libGLESv2/D3DConstantTable.h" +#include "libGLESv2/mathutil.h" +#include "libGLESv2/Shader.h" + +namespace gl +{ +class FragmentShader; +class VertexShader; + +// Helper struct representing a single shader uniform +struct Uniform +{ + Uniform(GLenum type, const std::string &_name, unsigned int arraySize); + + ~Uniform(); + + bool isArray(); + + const GLenum type; + const std::string _name; // Decorated name + const std::string name; // Undecorated name + const unsigned int arraySize; + + unsigned char *data; + bool dirty; + + struct RegisterInfo + { + RegisterInfo() + { + float4Index = -1; + samplerIndex = -1; + boolIndex = -1; + registerCount = 0; + } + + void set(const D3DConstant *constant) + { + switch(constant->registerSet) + { + case D3DConstant::RS_BOOL: boolIndex = constant->registerIndex; break; + case D3DConstant::RS_FLOAT4: float4Index = constant->registerIndex; break; + case D3DConstant::RS_SAMPLER: samplerIndex = constant->registerIndex; break; + default: UNREACHABLE(); + } + + ASSERT(registerCount == 0 || registerCount == (int)constant->registerCount); + registerCount = constant->registerCount; + } + + int float4Index; + int samplerIndex; + int boolIndex; + + int registerCount; + }; + + RegisterInfo ps; + RegisterInfo vs; +}; + +// Struct used for correlating uniforms/elements of uniform arrays to handles +struct UniformLocation +{ + UniformLocation() + { + } + + UniformLocation(const std::string &_name, unsigned int element, unsigned int index); + + std::string name; + unsigned int element; + unsigned int index; +}; + +// This is the result of linking a program. It is the state that would be passed to ProgramBinary. +class ProgramBinary : public RefCountObject +{ + public: + ProgramBinary(); + ~ProgramBinary(); + + IDirect3DPixelShader9 *getPixelShader(); + IDirect3DVertexShader9 *getVertexShader(); + + GLuint getAttributeLocation(const char *name); + int getSemanticIndex(int attributeIndex); + + GLint getSamplerMapping(SamplerType type, unsigned int samplerIndex); + TextureType getSamplerTextureType(SamplerType type, unsigned int samplerIndex); + GLint getUsedSamplerRange(SamplerType type); + bool usesPointSize() const; + + 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); + bool setUniform4fv(GLint location, GLsizei count, const GLfloat *v); + bool setUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value); + bool setUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value); + bool setUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value); + bool setUniform1iv(GLint location, GLsizei count, const GLint *v); + bool setUniform2iv(GLint location, GLsizei count, const GLint *v); + bool setUniform3iv(GLint location, GLsizei count, const GLint *v); + bool setUniform4iv(GLint location, GLsizei count, const GLint *v); + + bool getUniformfv(GLint location, GLsizei *bufSize, GLfloat *params); + bool getUniformiv(GLint location, GLsizei *bufSize, GLint *params); + + GLint getDxDepthRangeLocation() const; + GLint getDxDepthLocation() const; + GLint getDxCoordLocation() const; + GLint getDxHalfPixelSizeLocation() const; + GLint getDxFrontCCWLocation() const; + GLint getDxPointsOrLinesLocation() const; + + void dirtyAllUniforms(); + void applyUniforms(); + + bool load(InfoLog &infoLog, const void *binary, GLsizei length); + bool save(void* binary, GLsizei bufSize, GLsizei *length); + GLint getLength(); + + bool link(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader); + void getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders); + + void getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); + GLint getActiveAttributeCount(); + GLint getActiveAttributeMaxLength(); + + void getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); + GLint getActiveUniformCount(); + GLint getActiveUniformMaxLength(); + + void validate(InfoLog &infoLog); + bool validateSamplers(InfoLog *infoLog); + 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(ProgramBinary); + + ID3D10Blob *compileToBinary(InfoLog &infoLog, const char *hlsl, const char *profile, D3DConstantTable **constantTable); + + int packVaryings(InfoLog &infoLog, const Varying *packing[][4], FragmentShader *fragmentShader); + bool linkVaryings(InfoLog &infoLog, std::string& pixelHLSL, std::string& vertexHLSL, FragmentShader *fragmentShader, VertexShader *vertexShader); + + bool linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader); + + bool linkUniforms(InfoLog &infoLog, GLenum shader, D3DConstantTable *constantTable); + bool defineUniform(InfoLog &infoLog, GLenum shader, const D3DConstant *constant, std::string name = ""); + bool defineUniform(GLenum shader, const D3DConstant *constant, const std::string &name); + Uniform *createUniform( const D3DConstant *constant, 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 Vector4 *vector); + void applyUniformnbv(Uniform *targetUniform, GLsizei count, int width, const GLboolean *v); + + IDirect3DDevice9 *mDevice; + + IDirect3DPixelShader9 *mPixelExecutable; + IDirect3DVertexShader9 *mVertexExecutable; + + // These are only used during linking. + D3DConstantTable *mConstantTablePS; + D3DConstantTable *mConstantTableVS; + + Attribute mLinkedAttribute[MAX_VERTEX_ATTRIBS]; + int mSemanticIndex[MAX_VERTEX_ATTRIBS]; + + struct Sampler + { + Sampler(); + + bool active; + GLint logicalTextureUnit; + TextureType textureType; + }; + + Sampler mSamplersPS[MAX_TEXTURE_IMAGE_UNITS]; + Sampler mSamplersVS[MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF]; + GLuint mUsedVertexSamplerRange; + GLuint mUsedPixelSamplerRange; + bool mUsesPointSize; + + typedef std::vector<Uniform*> UniformArray; + UniformArray mUniforms; + typedef std::vector<UniformLocation> UniformIndex; + UniformIndex mUniformIndex; + + GLint mDxDepthRangeLocation; + GLint mDxDepthLocation; + GLint mDxCoordLocation; + GLint mDxHalfPixelSizeLocation; + GLint mDxFrontCCWLocation; + GLint mDxPointsOrLinesLocation; + + bool mValidated; + + const unsigned int mSerial; + + static unsigned int issueSerial(); + static unsigned int mCurrentSerial; +}; +} + +#endif // LIBGLESV2_PROGRAM_BINARY_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/Query.cpp b/src/3rdparty/angle/src/libGLESv2/Query.cpp new file mode 100644 index 0000000000..10edda5c57 --- /dev/null +++ b/src/3rdparty/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/src/3rdparty/angle/src/libGLESv2/Query.h b/src/3rdparty/angle/src/libGLESv2/Query.h new file mode 100644 index 0000000000..79357a0583 --- /dev/null +++ b/src/3rdparty/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/src/3rdparty/angle/src/libGLESv2/Renderbuffer.cpp b/src/3rdparty/angle/src/libGLESv2/Renderbuffer.cpp new file mode 100644 index 0000000000..4b911e8120 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/Renderbuffer.cpp @@ -0,0 +1,577 @@ +// +// 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. +// + +// Renderbuffer.cpp: the gl::Renderbuffer class and its derived classes +// Colorbuffer, Depthbuffer and Stencilbuffer. Implements GL renderbuffer +// objects and related functionality. [OpenGL ES 2.0.24] section 4.4.3 page 108. + +#include "libGLESv2/Renderbuffer.h" + +#include "libGLESv2/main.h" +#include "libGLESv2/Texture.h" +#include "libGLESv2/utilities.h" + +namespace gl +{ +unsigned int RenderbufferStorage::mCurrentSerial = 1; + +RenderbufferInterface::RenderbufferInterface() +{ +} + +// 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()); +} + +///// RenderbufferTexture2D Implementation //////// + +RenderbufferTexture2D::RenderbufferTexture2D(Texture2D *texture, GLenum target) : mTarget(target) +{ + mTexture2D.set(texture); +} + +RenderbufferTexture2D::~RenderbufferTexture2D() +{ + mTexture2D.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 RenderbufferTexture2D::addProxyRef(const Renderbuffer *proxy) +{ + mTexture2D->addProxyRef(proxy); +} + +void RenderbufferTexture2D::releaseProxy(const Renderbuffer *proxy) +{ + mTexture2D->releaseProxy(proxy); +} + +// Increments refcount on surface. +// caller must Release() the returned surface +IDirect3DSurface9 *RenderbufferTexture2D::getRenderTarget() +{ + return mTexture2D->getRenderTarget(mTarget); +} + +// Increments refcount on surface. +// caller must Release() the returned surface +IDirect3DSurface9 *RenderbufferTexture2D::getDepthStencil() +{ + return mTexture2D->getDepthStencil(mTarget); +} + +GLsizei RenderbufferTexture2D::getWidth() const +{ + return mTexture2D->getWidth(0); +} + +GLsizei RenderbufferTexture2D::getHeight() const +{ + return mTexture2D->getHeight(0); +} + +GLenum RenderbufferTexture2D::getInternalFormat() const +{ + return mTexture2D->getInternalFormat(0); +} + +D3DFORMAT RenderbufferTexture2D::getD3DFormat() const +{ + return mTexture2D->getD3DFormat(0); +} + +GLsizei RenderbufferTexture2D::getSamples() const +{ + return 0; +} + +unsigned int RenderbufferTexture2D::getSerial() const +{ + return mTexture2D->getRenderTargetSerial(mTarget); +} + +///// RenderbufferTextureCubeMap Implementation //////// + +RenderbufferTextureCubeMap::RenderbufferTextureCubeMap(TextureCubeMap *texture, GLenum target) : mTarget(target) +{ + mTextureCubeMap.set(texture); +} + +RenderbufferTextureCubeMap::~RenderbufferTextureCubeMap() +{ + mTextureCubeMap.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 RenderbufferTextureCubeMap::addProxyRef(const Renderbuffer *proxy) +{ + mTextureCubeMap->addProxyRef(proxy); +} + +void RenderbufferTextureCubeMap::releaseProxy(const Renderbuffer *proxy) +{ + mTextureCubeMap->releaseProxy(proxy); +} + +// Increments refcount on surface. +// caller must Release() the returned surface +IDirect3DSurface9 *RenderbufferTextureCubeMap::getRenderTarget() +{ + return mTextureCubeMap->getRenderTarget(mTarget); +} + +// Increments refcount on surface. +// caller must Release() the returned surface +IDirect3DSurface9 *RenderbufferTextureCubeMap::getDepthStencil() +{ + return NULL; +} + +GLsizei RenderbufferTextureCubeMap::getWidth() const +{ + return mTextureCubeMap->getWidth(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0); +} + +GLsizei RenderbufferTextureCubeMap::getHeight() const +{ + return mTextureCubeMap->getHeight(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0); +} + +GLenum RenderbufferTextureCubeMap::getInternalFormat() const +{ + return mTextureCubeMap->getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0); +} + +D3DFORMAT RenderbufferTextureCubeMap::getD3DFormat() const +{ + return mTextureCubeMap->getD3DFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0); +} + +GLsizei RenderbufferTextureCubeMap::getSamples() const +{ + return 0; +} + +unsigned int RenderbufferTextureCubeMap::getSerial() const +{ + return mTextureCubeMap->getRenderTargetSerial(mTarget); +} + +////// Renderbuffer Implementation ////// + +Renderbuffer::Renderbuffer(GLuint id, RenderbufferInterface *instance) : RefCountObject(id) +{ + ASSERT(instance != NULL); + mInstance = instance; +} + +Renderbuffer::~Renderbuffer() +{ + delete mInstance; +} + +// The RenderbufferInterface contained in this Renderbuffer may need to maintain +// its own reference count, so we pass it on here. +void Renderbuffer::addRef() const +{ + mInstance->addProxyRef(this); + + RefCountObject::addRef(); +} + +void Renderbuffer::release() const +{ + mInstance->releaseProxy(this); + + RefCountObject::release(); +} + +// Increments refcount on surface. +// caller must Release() the returned surface +IDirect3DSurface9 *Renderbuffer::getRenderTarget() +{ + return mInstance->getRenderTarget(); +} + +// Increments refcount on surface. +// caller must Release() the returned surface +IDirect3DSurface9 *Renderbuffer::getDepthStencil() +{ + return mInstance->getDepthStencil(); +} + +GLsizei Renderbuffer::getWidth() const +{ + return mInstance->getWidth(); +} + +GLsizei Renderbuffer::getHeight() const +{ + return mInstance->getHeight(); +} + +GLenum Renderbuffer::getInternalFormat() const +{ + return mInstance->getInternalFormat(); +} + +D3DFORMAT Renderbuffer::getD3DFormat() const +{ + return mInstance->getD3DFormat(); +} + +GLuint Renderbuffer::getRedSize() const +{ + return mInstance->getRedSize(); +} + +GLuint Renderbuffer::getGreenSize() const +{ + return mInstance->getGreenSize(); +} + +GLuint Renderbuffer::getBlueSize() const +{ + return mInstance->getBlueSize(); +} + +GLuint Renderbuffer::getAlphaSize() const +{ + return mInstance->getAlphaSize(); +} + +GLuint Renderbuffer::getDepthSize() const +{ + return mInstance->getDepthSize(); +} + +GLuint Renderbuffer::getStencilSize() const +{ + return mInstance->getStencilSize(); +} + +GLsizei Renderbuffer::getSamples() const +{ + return mInstance->getSamples(); +} + +unsigned int Renderbuffer::getSerial() const +{ + return mInstance->getSerial(); +} + +void Renderbuffer::setStorage(RenderbufferStorage *newStorage) +{ + ASSERT(newStorage != NULL); + + delete mInstance; + mInstance = newStorage; +} + +RenderbufferStorage::RenderbufferStorage() : mSerial(issueSerial()) +{ + mWidth = 0; + mHeight = 0; + mInternalFormat = GL_RGBA4; + mD3DFormat = D3DFMT_A8R8G8B8; + mSamples = 0; +} + +RenderbufferStorage::~RenderbufferStorage() +{ +} + +// Increments refcount on surface. +// caller must Release() the returned surface +IDirect3DSurface9 *RenderbufferStorage::getRenderTarget() +{ + return NULL; +} + +// Increments refcount on surface. +// caller must Release() the returned surface +IDirect3DSurface9 *RenderbufferStorage::getDepthStencil() +{ + return NULL; +} + +GLsizei RenderbufferStorage::getWidth() const +{ + return mWidth; +} + +GLsizei RenderbufferStorage::getHeight() const +{ + return mHeight; +} + +GLenum RenderbufferStorage::getInternalFormat() const +{ + return mInternalFormat; +} + +D3DFORMAT RenderbufferStorage::getD3DFormat() const +{ + return mD3DFormat; +} + +GLsizei RenderbufferStorage::getSamples() const +{ + return mSamples; +} + +unsigned int RenderbufferStorage::getSerial() const +{ + return mSerial; +} + +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) + { + renderTarget->AddRef(); + + D3DSURFACE_DESC description; + renderTarget->GetDesc(&description); + + mWidth = description.Width; + mHeight = description.Height; + mInternalFormat = dx2es::ConvertBackBufferFormat(description.Format); + mD3DFormat = description.Format; + mSamples = dx2es::GetSamplesFromMultisampleType(description.MultiSampleType); + } +} + +Colorbuffer::Colorbuffer(int width, int height, GLenum format, GLsizei samples) : mRenderTarget(NULL) +{ + IDirect3DDevice9 *device = getDevice(); + + D3DFORMAT requestedFormat = es2dx::ConvertRenderbufferFormat(format); + int supportedSamples = getContext()->getNearestSupportedSamples(requestedFormat, samples); + + if (supportedSamples == -1) + { + error(GL_OUT_OF_MEMORY); + + return; + } + + if (width > 0 && height > 0) + { + HRESULT result = device->CreateRenderTarget(width, height, requestedFormat, + es2dx::GetMultisampleTypeFromSamples(supportedSamples), 0, FALSE, &mRenderTarget, NULL); + + if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY) + { + error(GL_OUT_OF_MEMORY); + + return; + } + + ASSERT(SUCCEEDED(result)); + } + + mWidth = width; + mHeight = height; + mInternalFormat = format; + mD3DFormat = requestedFormat; + mSamples = supportedSamples; +} + +Colorbuffer::~Colorbuffer() +{ + if (mRenderTarget) + { + mRenderTarget->Release(); + } +} + +// Increments refcount on surface. +// caller must Release() the returned surface +IDirect3DSurface9 *Colorbuffer::getRenderTarget() +{ + if (mRenderTarget) + { + mRenderTarget->AddRef(); + } + + return mRenderTarget; +} + +DepthStencilbuffer::DepthStencilbuffer(IDirect3DSurface9 *depthStencil) : mDepthStencil(depthStencil) +{ + if (depthStencil) + { + depthStencil->AddRef(); + + D3DSURFACE_DESC description; + depthStencil->GetDesc(&description); + + mWidth = description.Width; + mHeight = description.Height; + mInternalFormat = dx2es::ConvertDepthStencilFormat(description.Format); + mSamples = dx2es::GetSamplesFromMultisampleType(description.MultiSampleType); + mD3DFormat = description.Format; + } +} + +DepthStencilbuffer::DepthStencilbuffer(int width, int height, GLsizei samples) +{ + IDirect3DDevice9 *device = getDevice(); + + mDepthStencil = NULL; + + int supportedSamples = getContext()->getNearestSupportedSamples(D3DFMT_D24S8, samples); + + if (supportedSamples == -1) + { + error(GL_OUT_OF_MEMORY); + + return; + } + + if (width > 0 && height > 0) + { + HRESULT result = device->CreateDepthStencilSurface(width, height, D3DFMT_D24S8, es2dx::GetMultisampleTypeFromSamples(supportedSamples), + 0, FALSE, &mDepthStencil, 0); + + if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY) + { + error(GL_OUT_OF_MEMORY); + + return; + } + + ASSERT(SUCCEEDED(result)); + } + + mWidth = width; + mHeight = height; + mInternalFormat = GL_DEPTH24_STENCIL8_OES; + mD3DFormat = D3DFMT_D24S8; + mSamples = supportedSamples; +} + +DepthStencilbuffer::~DepthStencilbuffer() +{ + if (mDepthStencil) + { + mDepthStencil->Release(); + } +} + +// Increments refcount on surface. +// caller must Release() the returned surface +IDirect3DSurface9 *DepthStencilbuffer::getDepthStencil() +{ + if (mDepthStencil) + { + mDepthStencil->AddRef(); + } + + return mDepthStencil; +} + +Depthbuffer::Depthbuffer(IDirect3DSurface9 *depthStencil) : DepthStencilbuffer(depthStencil) +{ + if (depthStencil) + { + 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 (mDepthStencil) + { + 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() +{ +} + +Stencilbuffer::Stencilbuffer(IDirect3DSurface9 *depthStencil) : DepthStencilbuffer(depthStencil) +{ + if (depthStencil) + { + 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 (mDepthStencil) + { + 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() +{ +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/Renderbuffer.h b/src/3rdparty/angle/src/libGLESv2/Renderbuffer.h new file mode 100644 index 0000000000..e6d5ddb875 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/Renderbuffer.h @@ -0,0 +1,257 @@ +// +// 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. +// + +// Renderbuffer.h: Defines the wrapper class gl::Renderbuffer, as well as the +// class hierarchy used to store its contents: RenderbufferStorage, Colorbuffer, +// DepthStencilbuffer, Depthbuffer and Stencilbuffer. Implements GL renderbuffer +// objects and related functionality. [OpenGL ES 2.0.24] section 4.4.3 page 108. + +#ifndef LIBGLESV2_RENDERBUFFER_H_ +#define LIBGLESV2_RENDERBUFFER_H_ + +#define GL_APICALL +#include <GLES2/gl2.h> +#include <d3d9.h> + +#include "common/angleutils.h" +#include "common/RefCountObject.h" + +namespace gl +{ +class Texture2D; +class TextureCubeMap; +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 RenderbufferTexture2D : public RenderbufferInterface +{ + public: + RenderbufferTexture2D(Texture2D *texture, GLenum target); + + virtual ~RenderbufferTexture2D(); + + 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(RenderbufferTexture2D); + + BindingPointer <Texture2D> mTexture2D; + GLenum mTarget; +}; + +class RenderbufferTextureCubeMap : public RenderbufferInterface +{ + public: + RenderbufferTextureCubeMap(TextureCubeMap *texture, GLenum target); + + virtual ~RenderbufferTextureCubeMap(); + + 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(RenderbufferTextureCubeMap); + + BindingPointer <TextureCubeMap> mTextureCubeMap; + 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 : public RenderbufferInterface +{ + public: + RenderbufferStorage(); + + virtual ~RenderbufferStorage() = 0; + + virtual IDirect3DSurface9 *getRenderTarget(); + virtual 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; + + static unsigned int issueSerial(); + static unsigned int issueCubeSerials(); + + protected: + GLsizei mWidth; + GLsizei mHeight; + GLenum mInternalFormat; + D3DFORMAT mD3DFormat; + GLsizei mSamples; + + private: + DISALLOW_COPY_AND_ASSIGN(RenderbufferStorage); + + const unsigned int mSerial; + + static unsigned int mCurrentSerial; +}; + +// Renderbuffer implements the GL renderbuffer 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, RenderbufferInterface *storage); + + virtual ~Renderbuffer(); + + // 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(); + + 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); + + private: + DISALLOW_COPY_AND_ASSIGN(Renderbuffer); + + RenderbufferInterface *mInstance; +}; + +class Colorbuffer : public RenderbufferStorage +{ + public: + explicit Colorbuffer(IDirect3DSurface9 *renderTarget); + Colorbuffer(GLsizei width, GLsizei height, GLenum format, GLsizei samples); + + virtual ~Colorbuffer(); + + virtual IDirect3DSurface9 *getRenderTarget(); + + private: + DISALLOW_COPY_AND_ASSIGN(Colorbuffer); + + IDirect3DSurface9 *mRenderTarget; +}; + +class DepthStencilbuffer : public RenderbufferStorage +{ + public: + explicit DepthStencilbuffer(IDirect3DSurface9 *depthStencil); + DepthStencilbuffer(GLsizei width, GLsizei height, GLsizei samples); + + ~DepthStencilbuffer(); + + virtual IDirect3DSurface9 *getDepthStencil(); + + protected: + IDirect3DSurface9 *mDepthStencil; + + private: + DISALLOW_COPY_AND_ASSIGN(DepthStencilbuffer); +}; + +class Depthbuffer : public DepthStencilbuffer +{ + public: + explicit Depthbuffer(IDirect3DSurface9 *depthStencil); + Depthbuffer(GLsizei width, GLsizei height, GLsizei samples); + + virtual ~Depthbuffer(); + + private: + DISALLOW_COPY_AND_ASSIGN(Depthbuffer); +}; + +class Stencilbuffer : public DepthStencilbuffer +{ + public: + explicit Stencilbuffer(IDirect3DSurface9 *depthStencil); + Stencilbuffer(GLsizei width, GLsizei height, GLsizei samples); + + virtual ~Stencilbuffer(); + + private: + DISALLOW_COPY_AND_ASSIGN(Stencilbuffer); +}; +} + +#endif // LIBGLESV2_RENDERBUFFER_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/ResourceManager.cpp b/src/3rdparty/angle/src/libGLESv2/ResourceManager.cpp new file mode 100644 index 0000000000..4b97e9c113 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/ResourceManager.cpp @@ -0,0 +1,320 @@ +// +// 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. +// + +// ResourceManager.cpp: Implements the gl::ResourceManager class, which tracks and +// retrieves objects which may be shared by multiple Contexts. + +#include "libGLESv2/ResourceManager.h" + +#include "libGLESv2/Buffer.h" +#include "libGLESv2/Program.h" +#include "libGLESv2/Renderbuffer.h" +#include "libGLESv2/Shader.h" +#include "libGLESv2/Texture.h" + +namespace gl +{ +ResourceManager::ResourceManager() +{ + mRefCount = 1; +} + +ResourceManager::~ResourceManager() +{ + while (!mBufferMap.empty()) + { + deleteBuffer(mBufferMap.begin()->first); + } + + while (!mProgramMap.empty()) + { + deleteProgram(mProgramMap.begin()->first); + } + + while (!mShaderMap.empty()) + { + deleteShader(mShaderMap.begin()->first); + } + + while (!mRenderbufferMap.empty()) + { + deleteRenderbuffer(mRenderbufferMap.begin()->first); + } + + while (!mTextureMap.empty()) + { + deleteTexture(mTextureMap.begin()->first); + } +} + +void ResourceManager::addRef() +{ + mRefCount++; +} + +void ResourceManager::release() +{ + if (--mRefCount == 0) + { + delete this; + } +} + +// Returns an unused buffer name +GLuint ResourceManager::createBuffer() +{ + GLuint handle = mBufferHandleAllocator.allocate(); + + mBufferMap[handle] = NULL; + + return handle; +} + +// Returns an unused shader/program name +GLuint ResourceManager::createShader(GLenum type) +{ + GLuint handle = mProgramShaderHandleAllocator.allocate(); + + if (type == GL_VERTEX_SHADER) + { + mShaderMap[handle] = new VertexShader(this, handle); + } + else if (type == GL_FRAGMENT_SHADER) + { + mShaderMap[handle] = new FragmentShader(this, handle); + } + else UNREACHABLE(); + + return handle; +} + +// Returns an unused program/shader name +GLuint ResourceManager::createProgram() +{ + GLuint handle = mProgramShaderHandleAllocator.allocate(); + + mProgramMap[handle] = new Program(this, handle); + + return handle; +} + +// Returns an unused texture name +GLuint ResourceManager::createTexture() +{ + GLuint handle = mTextureHandleAllocator.allocate(); + + mTextureMap[handle] = NULL; + + return handle; +} + +// Returns an unused renderbuffer name +GLuint ResourceManager::createRenderbuffer() +{ + GLuint handle = mRenderbufferHandleAllocator.allocate(); + + mRenderbufferMap[handle] = NULL; + + return handle; +} + +void ResourceManager::deleteBuffer(GLuint buffer) +{ + BufferMap::iterator bufferObject = mBufferMap.find(buffer); + + if (bufferObject != mBufferMap.end()) + { + mBufferHandleAllocator.release(bufferObject->first); + if (bufferObject->second) bufferObject->second->release(); + mBufferMap.erase(bufferObject); + } +} + +void ResourceManager::deleteShader(GLuint shader) +{ + ShaderMap::iterator shaderObject = mShaderMap.find(shader); + + if (shaderObject != mShaderMap.end()) + { + if (shaderObject->second->getRefCount() == 0) + { + mProgramShaderHandleAllocator.release(shaderObject->first); + delete shaderObject->second; + mShaderMap.erase(shaderObject); + } + else + { + shaderObject->second->flagForDeletion(); + } + } +} + +void ResourceManager::deleteProgram(GLuint program) +{ + ProgramMap::iterator programObject = mProgramMap.find(program); + + if (programObject != mProgramMap.end()) + { + if (programObject->second->getRefCount() == 0) + { + mProgramShaderHandleAllocator.release(programObject->first); + delete programObject->second; + mProgramMap.erase(programObject); + } + else + { + programObject->second->flagForDeletion(); + } + } +} + +void ResourceManager::deleteTexture(GLuint texture) +{ + TextureMap::iterator textureObject = mTextureMap.find(texture); + + if (textureObject != mTextureMap.end()) + { + mTextureHandleAllocator.release(textureObject->first); + if (textureObject->second) textureObject->second->release(); + mTextureMap.erase(textureObject); + } +} + +void ResourceManager::deleteRenderbuffer(GLuint renderbuffer) +{ + RenderbufferMap::iterator renderbufferObject = mRenderbufferMap.find(renderbuffer); + + if (renderbufferObject != mRenderbufferMap.end()) + { + mRenderbufferHandleAllocator.release(renderbufferObject->first); + if (renderbufferObject->second) renderbufferObject->second->release(); + mRenderbufferMap.erase(renderbufferObject); + } +} + +Buffer *ResourceManager::getBuffer(unsigned int handle) +{ + BufferMap::iterator buffer = mBufferMap.find(handle); + + if (buffer == mBufferMap.end()) + { + return NULL; + } + else + { + return buffer->second; + } +} + +Shader *ResourceManager::getShader(unsigned int handle) +{ + ShaderMap::iterator shader = mShaderMap.find(handle); + + if (shader == mShaderMap.end()) + { + return NULL; + } + else + { + return shader->second; + } +} + +Texture *ResourceManager::getTexture(unsigned int handle) +{ + if (handle == 0) return NULL; + + TextureMap::iterator texture = mTextureMap.find(handle); + + if (texture == mTextureMap.end()) + { + return NULL; + } + else + { + return texture->second; + } +} + +Program *ResourceManager::getProgram(unsigned int handle) +{ + ProgramMap::iterator program = mProgramMap.find(handle); + + if (program == mProgramMap.end()) + { + return NULL; + } + else + { + return program->second; + } +} + +Renderbuffer *ResourceManager::getRenderbuffer(unsigned int handle) +{ + RenderbufferMap::iterator renderbuffer = mRenderbufferMap.find(handle); + + if (renderbuffer == mRenderbufferMap.end()) + { + return NULL; + } + else + { + return renderbuffer->second; + } +} + +void ResourceManager::setRenderbuffer(GLuint handle, Renderbuffer *buffer) +{ + mRenderbufferMap[handle] = buffer; +} + +void ResourceManager::checkBufferAllocation(unsigned int buffer) +{ + if (buffer != 0 && !getBuffer(buffer)) + { + Buffer *bufferObject = new Buffer(buffer); + mBufferMap[buffer] = bufferObject; + bufferObject->addRef(); + } +} + +void ResourceManager::checkTextureAllocation(GLuint texture, TextureType type) +{ + if (!getTexture(texture) && texture != 0) + { + Texture *textureObject; + + if (type == TEXTURE_2D) + { + textureObject = new Texture2D(texture); + } + else if (type == TEXTURE_CUBE) + { + textureObject = new TextureCubeMap(texture); + } + else + { + UNREACHABLE(); + return; + } + + mTextureMap[texture] = textureObject; + textureObject->addRef(); + } +} + +void ResourceManager::checkRenderbufferAllocation(GLuint renderbuffer) +{ + if (renderbuffer != 0 && !getRenderbuffer(renderbuffer)) + { + Renderbuffer *renderbufferObject = new Renderbuffer(renderbuffer, new Colorbuffer(0, 0, GL_RGBA4, 0)); + mRenderbufferMap[renderbuffer] = renderbufferObject; + renderbufferObject->addRef(); + } +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/ResourceManager.h b/src/3rdparty/angle/src/libGLESv2/ResourceManager.h new file mode 100644 index 0000000000..ae4f1b04a5 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/ResourceManager.h @@ -0,0 +1,116 @@ +// +// 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. +// + +// ResourceManager.h : Defines the ResourceManager class, which tracks objects +// shared by multiple GL contexts. + +#ifndef LIBGLESV2_RESOURCEMANAGER_H_ +#define LIBGLESV2_RESOURCEMANAGER_H_ + +#define GL_APICALL +#include <GLES2/gl2.h> + +#ifdef _MSC_VER +#include <hash_map> +#else +#include <unordered_map> +#endif + +#include "common/angleutils.h" +#include "libGLESv2/HandleAllocator.h" + +namespace gl +{ +class Buffer; +class Shader; +class Program; +class Texture; +class Renderbuffer; + +enum TextureType +{ + TEXTURE_2D, + TEXTURE_CUBE, + + TEXTURE_TYPE_COUNT, + TEXTURE_UNKNOWN +}; + +enum SamplerType +{ + SAMPLER_PIXEL, + SAMPLER_VERTEX +}; + +class ResourceManager +{ + public: + ResourceManager(); + ~ResourceManager(); + + void addRef(); + void release(); + + GLuint createBuffer(); + GLuint createShader(GLenum type); + GLuint createProgram(); + GLuint createTexture(); + GLuint createRenderbuffer(); + + void deleteBuffer(GLuint buffer); + void deleteShader(GLuint shader); + void deleteProgram(GLuint program); + void deleteTexture(GLuint texture); + void deleteRenderbuffer(GLuint renderbuffer); + + Buffer *getBuffer(GLuint handle); + Shader *getShader(GLuint handle); + Program *getProgram(GLuint handle); + Texture *getTexture(GLuint handle); + Renderbuffer *getRenderbuffer(GLuint handle); + + void setRenderbuffer(GLuint handle, Renderbuffer *renderbuffer); + + void checkBufferAllocation(unsigned int buffer); + void checkTextureAllocation(GLuint texture, TextureType type); + void checkRenderbufferAllocation(GLuint renderbuffer); + + private: + DISALLOW_COPY_AND_ASSIGN(ResourceManager); + + std::size_t mRefCount; + +#ifndef HASH_MAP +# ifdef _MSC_VER +# define HASH_MAP stdext::hash_map +# else +# define HASH_MAP std::unordered_map +# endif +#endif + + typedef HASH_MAP<GLuint, Buffer*> BufferMap; + BufferMap mBufferMap; + HandleAllocator mBufferHandleAllocator; + + typedef HASH_MAP<GLuint, Shader*> ShaderMap; + ShaderMap mShaderMap; + + typedef HASH_MAP<GLuint, Program*> ProgramMap; + ProgramMap mProgramMap; + HandleAllocator mProgramShaderHandleAllocator; + + typedef HASH_MAP<GLuint, Texture*> TextureMap; + TextureMap mTextureMap; + HandleAllocator mTextureHandleAllocator; + + typedef HASH_MAP<GLuint, Renderbuffer*> RenderbufferMap; + RenderbufferMap mRenderbufferMap; + HandleAllocator mRenderbufferHandleAllocator; +}; + +} + +#endif // LIBGLESV2_RESOURCEMANAGER_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/Shader.cpp b/src/3rdparty/angle/src/libGLESv2/Shader.cpp new file mode 100644 index 0000000000..1087f11b4a --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/Shader.cpp @@ -0,0 +1,584 @@ +// +// 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. +// + +// Shader.cpp: Implements the gl::Shader class and its derived classes +// VertexShader and FragmentShader. Implements GL shader objects and related +// functionality. [OpenGL ES 2.0.24] section 2.10 page 24 and section 3.8 page 84. + +#include "libGLESv2/Shader.h" + +#include <string> + +#include "GLSLANG/ShaderLang.h" +#include "libGLESv2/main.h" +#include "libGLESv2/utilities.h" + +namespace gl +{ +void *Shader::mFragmentCompiler = NULL; +void *Shader::mVertexCompiler = NULL; + +Shader::Shader(ResourceManager *manager, GLuint handle) : mHandle(handle), mResourceManager(manager) +{ + mSource = NULL; + mHlsl = NULL; + mInfoLog = NULL; + + uncompile(); + initializeCompiler(); + + mRefCount = 0; + mDeleteStatus = false; +} + +Shader::~Shader() +{ + delete[] mSource; + delete[] mHlsl; + delete[] mInfoLog; +} + +GLuint Shader::getHandle() const +{ + return mHandle; +} + +void Shader::setSource(GLsizei count, const char **string, const GLint *length) +{ + delete[] mSource; + int totalLength = 0; + + for (int i = 0; i < count; i++) + { + if (length && length[i] >= 0) + { + totalLength += length[i]; + } + else + { + totalLength += (int)strlen(string[i]); + } + } + + mSource = new char[totalLength + 1]; + char *code = mSource; + + for (int i = 0; i < count; i++) + { + int stringLength; + + if (length && length[i] >= 0) + { + stringLength = length[i]; + } + else + { + stringLength = (int)strlen(string[i]); + } + + strncpy(code, string[i], stringLength); + code += stringLength; + } + + mSource[totalLength] = '\0'; +} + +int Shader::getInfoLogLength() const +{ + if (!mInfoLog) + { + return 0; + } + else + { + return strlen(mInfoLog) + 1; + } +} + +void Shader::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) +{ + int index = 0; + + if (bufSize > 0) + { + if (mInfoLog) + { + index = std::min(bufSize - 1, (int)strlen(mInfoLog)); + memcpy(infoLog, mInfoLog, index); + } + + infoLog[index] = '\0'; + } + + if (length) + { + *length = index; + } +} + +int Shader::getSourceLength() const +{ + if (!mSource) + { + return 0; + } + else + { + return strlen(mSource) + 1; + } +} + +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 (bufSize > 0) + { + if (source) + { + index = std::min(bufSize - 1, (int)strlen(source)); + memcpy(buffer, source, index); + } + + buffer[index] = '\0'; + } + + if (length) + { + *length = index; + } +} + +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; +} + +const char *Shader::getHLSL() +{ + return mHlsl; +} + +void Shader::addRef() +{ + mRefCount++; +} + +void Shader::release() +{ + mRefCount--; + + if (mRefCount == 0 && mDeleteStatus) + { + mResourceManager->deleteShader(mHandle); + } +} + +unsigned int Shader::getRefCount() const +{ + return mRefCount; +} + +bool Shader::isFlaggedForDeletion() const +{ + return mDeleteStatus; +} + +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); + ShDestruct(mVertexCompiler); + + mFragmentCompiler = NULL; + mVertexCompiler = NULL; + + ShFinalize(); +} + +void Shader::parseVaryings() +{ + if (mHlsl) + { + const char *input = strstr(mHlsl, "// Varyings") + 12; + + while(true) + { + char varyingType[256]; + char varyingName[256]; + + int matches = sscanf(input, "static %255s %255s", varyingType, varyingName); + + if (matches != 2) + { + break; + } + + char *array = strstr(varyingName, "["); + int size = 1; + + if (array) + { + size = atoi(array + 1); + *array = '\0'; + } + + mVaryings.push_back(Varying(parseType(varyingType), varyingName, size, array != NULL)); + + input = strstr(input, ";") + 2; + } + + mUsesFragCoord = strstr(mHlsl, "GL_USES_FRAG_COORD") != NULL; + mUsesFrontFacing = strstr(mHlsl, "GL_USES_FRONT_FACING") != NULL; + mUsesPointSize = strstr(mHlsl, "GL_USES_POINT_SIZE") != NULL; + mUsesPointCoord = strstr(mHlsl, "GL_USES_POINT_COORD") != NULL; + } +} + +// 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) +{ + // ensure we don't pass a NULL source to the compiler + char *source = "\0"; + if (mSource) + { + source = mSource; + } + + // ensure the compiler is loaded + initializeCompiler(); + + 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 + }; + + result = ShCompile(compiler, sourceStrings, 2, compileOptions | SH_SOURCE_PATH); + } + + if (result) + { + int objCodeLen = 0; + ShGetInfo(compiler, SH_OBJECT_CODE_LENGTH, &objCodeLen); + mHlsl = new char[objCodeLen]; + ShGetObjectCode(compiler, mHlsl); + } + else + { + int infoLogLen = 0; + ShGetInfo(compiler, SH_INFO_LOG_LENGTH, &infoLogLen); + mInfoLog = new char[infoLogLen]; + ShGetInfoLog(compiler, mInfoLog); + + TRACE("\n%s", mInfoLog); + } +} + +GLenum Shader::parseType(const std::string &type) +{ + if (type == "float") + { + return GL_FLOAT; + } + else if (type == "float2") + { + return GL_FLOAT_VEC2; + } + else if (type == "float3") + { + return GL_FLOAT_VEC3; + } + else if (type == "float4") + { + return GL_FLOAT_VEC4; + } + else if (type == "float2x2") + { + return GL_FLOAT_MAT2; + } + else if (type == "float3x3") + { + return GL_FLOAT_MAT3; + } + else if (type == "float4x4") + { + return GL_FLOAT_MAT4; + } + else UNREACHABLE(); + + return GL_NONE; +} + +// true if varying x has a higher priority in packing than y +bool Shader::compareVarying(const Varying &x, const Varying &y) +{ + if(x.type == y.type) + { + return x.size > y.size; + } + + switch (x.type) + { + case GL_FLOAT_MAT4: return true; + case GL_FLOAT_MAT2: + switch(y.type) + { + case GL_FLOAT_MAT4: return false; + case GL_FLOAT_MAT2: return true; + case GL_FLOAT_VEC4: return true; + case GL_FLOAT_MAT3: return true; + case GL_FLOAT_VEC3: return true; + case GL_FLOAT_VEC2: return true; + case GL_FLOAT: return true; + default: UNREACHABLE(); + } + break; + case GL_FLOAT_VEC4: + switch(y.type) + { + case GL_FLOAT_MAT4: return false; + case GL_FLOAT_MAT2: return false; + case GL_FLOAT_VEC4: return true; + case GL_FLOAT_MAT3: return true; + case GL_FLOAT_VEC3: return true; + case GL_FLOAT_VEC2: return true; + case GL_FLOAT: return true; + default: UNREACHABLE(); + } + break; + case GL_FLOAT_MAT3: + switch(y.type) + { + case GL_FLOAT_MAT4: return false; + case GL_FLOAT_MAT2: return false; + case GL_FLOAT_VEC4: return false; + case GL_FLOAT_MAT3: return true; + case GL_FLOAT_VEC3: return true; + case GL_FLOAT_VEC2: return true; + case GL_FLOAT: return true; + default: UNREACHABLE(); + } + break; + case GL_FLOAT_VEC3: + switch(y.type) + { + case GL_FLOAT_MAT4: return false; + case GL_FLOAT_MAT2: return false; + case GL_FLOAT_VEC4: return false; + case GL_FLOAT_MAT3: return false; + case GL_FLOAT_VEC3: return true; + case GL_FLOAT_VEC2: return true; + case GL_FLOAT: return true; + default: UNREACHABLE(); + } + break; + case GL_FLOAT_VEC2: + switch(y.type) + { + case GL_FLOAT_MAT4: return false; + case GL_FLOAT_MAT2: return false; + case GL_FLOAT_VEC4: return false; + case GL_FLOAT_MAT3: return false; + case GL_FLOAT_VEC3: return false; + case GL_FLOAT_VEC2: return true; + case GL_FLOAT: return true; + default: UNREACHABLE(); + } + break; + case GL_FLOAT: return false; + default: UNREACHABLE(); + } + + return false; +} + +VertexShader::VertexShader(ResourceManager *manager, GLuint handle) : Shader(manager, handle) +{ +} + +VertexShader::~VertexShader() +{ +} + +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(); +} + +int VertexShader::getSemanticIndex(const std::string &attributeName) +{ + if (!attributeName.empty()) + { + int semanticIndex = 0; + for (AttributeArray::iterator attribute = mAttributes.begin(); attribute != mAttributes.end(); attribute++) + { + if (attribute->name == attributeName) + { + return semanticIndex; + } + + semanticIndex += VariableRowCount(attribute->type); + } + } + + return -1; +} + +void VertexShader::parseAttributes() +{ + const char *hlsl = getHLSL(); + if (hlsl) + { + const char *input = strstr(hlsl, "// Attributes") + 14; + + while(true) + { + char attributeType[256]; + char attributeName[256]; + + int matches = sscanf(input, "static %255s _%255s", attributeType, attributeName); + + if (matches != 2) + { + break; + } + + mAttributes.push_back(Attribute(parseType(attributeType), attributeName)); + + input = strstr(input, ";") + 2; + } + } +} + +FragmentShader::FragmentShader(ResourceManager *manager, GLuint handle) : Shader(manager, handle) +{ +} + +FragmentShader::~FragmentShader() +{ +} + +GLenum FragmentShader::getType() +{ + return GL_FRAGMENT_SHADER; +} + +void FragmentShader::compile() +{ + uncompile(); + + compileToHLSL(mFragmentCompiler); + parseVaryings(); + mVaryings.sort(compareVarying); +} +} diff --git a/src/3rdparty/angle/src/libGLESv2/Shader.h b/src/3rdparty/angle/src/libGLESv2/Shader.h new file mode 100644 index 0000000000..b73fc288a1 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/Shader.h @@ -0,0 +1,166 @@ +// +// 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. +// + +// Shader.h: Defines the abstract gl::Shader class and its concrete derived +// classes VertexShader and FragmentShader. Implements GL shader objects and +// related functionality. [OpenGL ES 2.0.24] section 2.10 page 24 and section +// 3.8 page 84. + +#ifndef LIBGLESV2_SHADER_H_ +#define LIBGLESV2_SHADER_H_ + +#define GL_APICALL +#include <GLES2/gl2.h> +#include <string> +#include <list> +#include <vector> + +#include "libGLESv2/ResourceManager.h" + +namespace gl +{ +struct Varying +{ + Varying(GLenum type, const std::string &name, int size, bool array) + : type(type), name(name), size(size), array(array), reg(-1), col(-1) + { + } + + GLenum type; + std::string name; + int size; // Number of 'type' elements + bool array; + + int reg; // First varying register, assigned during link + int col; // First register element, assigned during link +}; + +typedef std::list<Varying> VaryingList; + +class Shader +{ + friend class ProgramBinary; + + public: + Shader(ResourceManager *manager, GLuint handle); + + virtual ~Shader(); + + virtual GLenum getType() = 0; + GLuint getHandle() const; + + void deleteSource(); + void setSource(GLsizei count, const char **string, const GLint *length); + int getInfoLogLength() const; + void getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog); + int getSourceLength() const; + 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(); + + void addRef(); + void release(); + unsigned int getRefCount() const; + bool isFlaggedForDeletion() const; + void flagForDeletion(); + + static void releaseCompiler(); + + protected: + 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 + + char *mSource; + char *mHlsl; + char *mInfoLog; + + ResourceManager *mResourceManager; +}; + +struct Attribute +{ + Attribute() : type(GL_NONE), name("") + { + } + + Attribute(GLenum type, const std::string &name) : type(type), name(name) + { + } + + GLenum type; + std::string name; +}; + +typedef std::vector<Attribute> AttributeArray; + +class VertexShader : public Shader +{ + friend class ProgramBinary; + + public: + VertexShader(ResourceManager *manager, GLuint handle); + + ~VertexShader(); + + virtual GLenum getType(); + virtual void compile(); + virtual void uncompile(); + int getSemanticIndex(const std::string &attributeName); + + private: + DISALLOW_COPY_AND_ASSIGN(VertexShader); + + void parseAttributes(); + + AttributeArray mAttributes; +}; + +class FragmentShader : public Shader +{ + public: + FragmentShader(ResourceManager *manager, GLuint handle); + + ~FragmentShader(); + + virtual GLenum getType(); + virtual void compile(); + + private: + DISALLOW_COPY_AND_ASSIGN(FragmentShader); +}; +} + +#endif // LIBGLESV2_SHADER_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/Texture.cpp b/src/3rdparty/angle/src/libGLESv2/Texture.cpp new file mode 100644 index 0000000000..af430bf145 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/Texture.cpp @@ -0,0 +1,3118 @@ +// +// 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. +// + +// Texture.cpp: Implements the gl::Texture class and its derived classes +// Texture2D and TextureCubeMap. Implements GL texture objects and related +// functionality. [OpenGL ES 2.0.24] section 3.7 page 63. + +#include "libGLESv2/Texture.h" + +#include <algorithm> + +#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; + +static D3DFORMAT ConvertTextureInternalFormat(GLint internalformat) +{ + switch (internalformat) + { + case GL_DEPTH_COMPONENT16: + case GL_DEPTH_COMPONENT32_OES: + case GL_DEPTH24_STENCIL8_OES: + return D3DFMT_INTZ; + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + return D3DFMT_DXT1; + case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: + return D3DFMT_DXT3; + case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: + return D3DFMT_DXT5; + case GL_RGBA32F_EXT: + case GL_RGB32F_EXT: + case GL_ALPHA32F_EXT: + case GL_LUMINANCE32F_EXT: + case GL_LUMINANCE_ALPHA32F_EXT: + return D3DFMT_A32B32G32R32F; + case GL_RGBA16F_EXT: + case GL_RGB16F_EXT: + case GL_ALPHA16F_EXT: + case GL_LUMINANCE16F_EXT: + case GL_LUMINANCE_ALPHA16F_EXT: + return D3DFMT_A16B16G16R16F; + case GL_LUMINANCE8_EXT: + if (getContext()->supportsLuminanceTextures()) + { + return D3DFMT_L8; + } + break; + case GL_LUMINANCE8_ALPHA8_EXT: + if (getContext()->supportsLuminanceAlphaTextures()) + { + return D3DFMT_A8L8; + } + break; + case GL_RGB8_OES: + case GL_RGB565: + return D3DFMT_X8R8G8B8; + } + + return D3DFMT_A8R8G8B8; +} + +static bool IsTextureFormatRenderable(D3DFORMAT format) +{ + if (format == D3DFMT_INTZ) + { + return true; + } + 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; +} + +static inline DWORD GetTextureUsage(D3DFORMAT d3dfmt, GLenum glusage, bool forceRenderable) +{ + DWORD d3dusage = 0; + + if (d3dfmt == D3DFMT_INTZ) + { + d3dusage |= D3DUSAGE_DEPTHSTENCIL; + } + else if(forceRenderable || (IsTextureFormatRenderable(d3dfmt) && (glusage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE))) + { + d3dusage |= D3DUSAGE_RENDERTARGET; + } + return d3dusage; +} + +static void MakeValidSize(bool isImage, bool isCompressed, GLsizei *requestWidth, GLsizei *requestHeight, int *levelOffset) +{ + int upsampleCount = 0; + + if (isCompressed) + { + // Don't expand the size of full textures that are at least 4x4 + // already. + if (isImage || *requestWidth < 4 || *requestHeight < 4) + { + while (*requestWidth % 4 != 0 || *requestHeight % 4 != 0) + { + *requestWidth <<= 1; + *requestHeight <<= 1; + upsampleCount++; + } + } + } + *levelOffset = upsampleCount; +} + +static void CopyLockableSurfaces(IDirect3DSurface9 *dest, IDirect3DSurface9 *source) +{ + D3DLOCKED_RECT sourceLock = {0}; + D3DLOCKED_RECT destLock = {0}; + + source->LockRect(&sourceLock, NULL, 0); + dest->LockRect(&destLock, NULL, 0); + + if (sourceLock.pBits && destLock.pBits) + { + D3DSURFACE_DESC desc; + source->GetDesc(&desc); + + int rows = dx::IsCompressedFormat(desc.Format) ? desc.Height / 4 : desc.Height; + int bytes = dx::ComputeRowSize(desc.Format, desc.Width); + ASSERT(bytes <= sourceLock.Pitch && bytes <= destLock.Pitch); + + for(int i = 0; i < rows; i++) + { + memcpy((char*)destLock.pBits + destLock.Pitch * i, (char*)sourceLock.pBits + sourceLock.Pitch * i, bytes); + } + + source->UnlockRect(); + dest->UnlockRect(); + } + else UNREACHABLE(); +} + +Image::Image() +{ + mWidth = 0; + mHeight = 0; + mInternalFormat = GL_NONE; + + mSurface = NULL; + + mDirty = false; + + mD3DPool = D3DPOOL_SYSTEMMEM; + mD3DFormat = D3DFMT_UNKNOWN; +} + +Image::~Image() +{ + if (mSurface) + { + mSurface->Release(); + } +} + +bool Image::redefine(GLint internalformat, GLsizei width, GLsizei height, bool forceRelease) +{ + if (mWidth != width || + mHeight != height || + mInternalFormat != internalformat || + forceRelease) + { + mWidth = width; + mHeight = height; + mInternalFormat = internalformat; + // compute the d3d format that will be used + mD3DFormat = ConvertTextureInternalFormat(internalformat); + + if (mSurface) + { + mSurface->Release(); + mSurface = NULL; + } + + return true; + } + + return false; +} + +void Image::createSurface() +{ + if(mSurface) + { + return; + } + + IDirect3DTexture9 *newTexture = NULL; + IDirect3DSurface9 *newSurface = NULL; + const D3DPOOL poolToUse = D3DPOOL_SYSTEMMEM; + const D3DFORMAT d3dFormat = getD3DFormat(); + ASSERT(d3dFormat != D3DFMT_INTZ); // We should never get here for depth textures + + if (mWidth != 0 && mHeight != 0) + { + int levelToFetch = 0; + GLsizei requestWidth = mWidth; + GLsizei requestHeight = mHeight; + MakeValidSize(true, IsCompressed(mInternalFormat), &requestWidth, &requestHeight, &levelToFetch); + + HRESULT result = getDevice()->CreateTexture(requestWidth, requestHeight, levelToFetch + 1, NULL, d3dFormat, + 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(); + } + + mSurface = newSurface; + mDirty = false; + mD3DPool = poolToUse; +} + +HRESULT Image::lock(D3DLOCKED_RECT *lockedRect, const RECT *rect) +{ + createSurface(); + + HRESULT result = D3DERR_INVALIDCALL; + + if (mSurface) + { + result = mSurface->LockRect(lockedRect, rect, 0); + ASSERT(SUCCEEDED(result)); + + mDirty = true; + } + + return result; +} + +void Image::unlock() +{ + if (mSurface) + { + HRESULT result = mSurface->UnlockRect(); + ASSERT(SUCCEEDED(result)); + } +} + +bool Image::isRenderableFormat() const +{ + return IsTextureFormatRenderable(getD3DFormat()); +} + +D3DFORMAT Image::getD3DFormat() const +{ + // 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; +} + +IDirect3DSurface9 *Image::getSurface() +{ + createSurface(); + + return mSurface; +} + +void Image::setManagedSurface(IDirect3DSurface9 *surface) +{ + D3DSURFACE_DESC desc; + surface->GetDesc(&desc); + ASSERT(desc.Pool == D3DPOOL_MANAGED); + + if ((GLsizei)desc.Width == mWidth && (GLsizei)desc.Height == mHeight) + { + if (mSurface) + { + CopyLockableSurfaces(surface, mSurface); + mSurface->Release(); + } + + mSurface = surface; + mD3DPool = desc.Pool; + } +} + +void Image::updateSurface(IDirect3DSurface9 *destSurface, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) +{ + IDirect3DSurface9 *sourceSurface = getSurface(); + + if (sourceSurface && sourceSurface != destSurface) + { + RECT rect; + rect.left = xoffset; + rect.top = yoffset; + rect.right = xoffset + width; + rect.bottom = yoffset + height; + + POINT point = {rect.left, rect.top}; + + if (mD3DPool == D3DPOOL_MANAGED) + { + D3DSURFACE_DESC desc; + sourceSurface->GetDesc(&desc); + + IDirect3DSurface9 *surf = 0; + HRESULT result = getDevice()->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &surf, NULL); + + if (SUCCEEDED(result)) + { + CopyLockableSurfaces(surf, sourceSurface); + result = getDevice()->UpdateSurface(surf, &rect, destSurface, &point); + ASSERT(SUCCEEDED(result)); + surf->Release(); + } + } + else + { + // UpdateSurface: source must be SYSTEMMEM, dest must be DEFAULT pools + HRESULT result = getDevice()->UpdateSurface(sourceSurface, &rect, destSurface, &point); + ASSERT(SUCCEEDED(result)); + } + } +} + +// Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input +// into the target pixel rectangle. +void Image::loadData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + GLint unpackAlignment, const void *input) +{ + RECT lockRect = + { + xoffset, yoffset, + xoffset + width, yoffset + height + }; + + D3DLOCKED_RECT locked; + HRESULT result = lock(&locked, &lockRect); + if (FAILED(result)) + { + return; + } + + + GLsizei inputPitch = ComputePitch(width, mInternalFormat, unpackAlignment); + + switch (mInternalFormat) + { + case GL_ALPHA8_EXT: + if (supportsSSE2()) + { + loadAlphaDataSSE2(width, height, inputPitch, input, locked.Pitch, locked.pBits); + } + else + { + loadAlphaData(width, height, inputPitch, input, locked.Pitch, locked.pBits); + } + break; + case GL_LUMINANCE8_EXT: + loadLuminanceData(width, height, inputPitch, input, locked.Pitch, locked.pBits, getD3DFormat() == D3DFMT_L8); + break; + case GL_ALPHA32F_EXT: + loadAlphaFloatData(width, height, inputPitch, input, locked.Pitch, locked.pBits); + break; + case GL_LUMINANCE32F_EXT: + loadLuminanceFloatData(width, height, inputPitch, input, locked.Pitch, locked.pBits); + break; + case GL_ALPHA16F_EXT: + loadAlphaHalfFloatData(width, height, inputPitch, input, locked.Pitch, locked.pBits); + break; + case GL_LUMINANCE16F_EXT: + loadLuminanceHalfFloatData(width, height, inputPitch, input, locked.Pitch, locked.pBits); + break; + case GL_LUMINANCE8_ALPHA8_EXT: + loadLuminanceAlphaData(width, height, inputPitch, input, locked.Pitch, locked.pBits, getD3DFormat() == D3DFMT_A8L8); + break; + case GL_LUMINANCE_ALPHA32F_EXT: + loadLuminanceAlphaFloatData(width, height, inputPitch, input, locked.Pitch, locked.pBits); + break; + case GL_LUMINANCE_ALPHA16F_EXT: + loadLuminanceAlphaHalfFloatData(width, height, inputPitch, input, locked.Pitch, locked.pBits); + break; + case GL_RGB8_OES: + loadRGBUByteData(width, height, inputPitch, input, locked.Pitch, locked.pBits); + break; + case GL_RGB565: + loadRGB565Data(width, height, inputPitch, input, locked.Pitch, locked.pBits); + break; + case GL_RGBA8_OES: + if (supportsSSE2()) + { + loadRGBAUByteDataSSE2(width, height, inputPitch, input, locked.Pitch, locked.pBits); + } + else + { + loadRGBAUByteData(width, height, inputPitch, input, locked.Pitch, locked.pBits); + } + break; + case GL_RGBA4: + loadRGBA4444Data(width, height, inputPitch, input, locked.Pitch, locked.pBits); + break; + case GL_RGB5_A1: + loadRGBA5551Data(width, height, inputPitch, input, locked.Pitch, locked.pBits); + break; + case GL_BGRA8_EXT: + loadBGRAData(width, height, inputPitch, input, locked.Pitch, locked.pBits); + break; + // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D + case GL_RGB32F_EXT: + loadRGBFloatData(width, height, inputPitch, input, locked.Pitch, locked.pBits); + break; + case GL_RGB16F_EXT: + loadRGBHalfFloatData(width, height, inputPitch, input, locked.Pitch, locked.pBits); + break; + case GL_RGBA32F_EXT: + loadRGBAFloatData(width, height, inputPitch, input, locked.Pitch, locked.pBits); + break; + case GL_RGBA16F_EXT: + loadRGBAHalfFloatData(width, height, inputPitch, input, locked.Pitch, locked.pBits); + break; + default: UNREACHABLE(); + } + + unlock(); +} + +void Image::loadAlphaData(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const +{ + const unsigned char *source = NULL; + unsigned char *dest = NULL; + + for (int y = 0; y < height; y++) + { + source = static_cast<const unsigned char*>(input) + y * inputPitch; + dest = static_cast<unsigned char*>(output) + y * outputPitch; + for (int x = 0; x < width; x++) + { + dest[4 * x + 0] = 0; + dest[4 * x + 1] = 0; + dest[4 * x + 2] = 0; + dest[4 * x + 3] = source[x]; + } + } +} + +void Image::loadAlphaFloatData(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const +{ + const float *source = NULL; + float *dest = NULL; + + for (int y = 0; y < height; y++) + { + source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch); + dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + y * outputPitch); + for (int x = 0; x < width; x++) + { + dest[4 * x + 0] = 0; + dest[4 * x + 1] = 0; + dest[4 * x + 2] = 0; + dest[4 * x + 3] = source[x]; + } + } +} + +void Image::loadAlphaHalfFloatData(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const +{ + const unsigned short *source = NULL; + unsigned short *dest = NULL; + + for (int y = 0; y < height; y++) + { + source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch); + dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + y * outputPitch); + for (int x = 0; x < width; x++) + { + dest[4 * x + 0] = 0; + dest[4 * x + 1] = 0; + dest[4 * x + 2] = 0; + dest[4 * x + 3] = source[x]; + } + } +} + +void Image::loadLuminanceData(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const +{ + const unsigned char *source = NULL; + unsigned char *dest = NULL; + + for (int y = 0; y < height; y++) + { + source = static_cast<const unsigned char*>(input) + y * inputPitch; + dest = static_cast<unsigned char*>(output) + y * outputPitch; + + if (!native) // BGRA8 destination format + { + for (int x = 0; x < width; x++) + { + dest[4 * x + 0] = source[x]; + dest[4 * x + 1] = source[x]; + dest[4 * x + 2] = source[x]; + dest[4 * x + 3] = 0xFF; + } + } + else // L8 destination format + { + memcpy(dest, source, width); + } + } +} + +void Image::loadLuminanceFloatData(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const +{ + const float *source = NULL; + float *dest = NULL; + + for (int y = 0; y < height; y++) + { + source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch); + dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + y * outputPitch); + for (int x = 0; x < width; x++) + { + dest[4 * x + 0] = source[x]; + dest[4 * x + 1] = source[x]; + dest[4 * x + 2] = source[x]; + dest[4 * x + 3] = 1.0f; + } + } +} + +void Image::loadLuminanceHalfFloatData(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const +{ + const unsigned short *source = NULL; + unsigned short *dest = NULL; + + for (int y = 0; y < height; y++) + { + source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch); + dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + y * outputPitch); + for (int x = 0; x < width; x++) + { + dest[4 * x + 0] = source[x]; + dest[4 * x + 1] = source[x]; + dest[4 * x + 2] = source[x]; + dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1 + } + } +} + +void Image::loadLuminanceAlphaData(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const +{ + const unsigned char *source = NULL; + unsigned char *dest = NULL; + + for (int y = 0; y < height; y++) + { + source = static_cast<const unsigned char*>(input) + y * inputPitch; + dest = static_cast<unsigned char*>(output) + y * outputPitch; + + if (!native) // BGRA8 destination format + { + for (int x = 0; x < width; x++) + { + dest[4 * x + 0] = source[2*x+0]; + dest[4 * x + 1] = source[2*x+0]; + dest[4 * x + 2] = source[2*x+0]; + dest[4 * x + 3] = source[2*x+1]; + } + } + else + { + memcpy(dest, source, width * 2); + } + } +} + +void Image::loadLuminanceAlphaFloatData(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const +{ + const float *source = NULL; + float *dest = NULL; + + for (int y = 0; y < height; y++) + { + source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch); + dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + y * outputPitch); + for (int x = 0; x < width; x++) + { + dest[4 * x + 0] = source[2*x+0]; + dest[4 * x + 1] = source[2*x+0]; + dest[4 * x + 2] = source[2*x+0]; + dest[4 * x + 3] = source[2*x+1]; + } + } +} + +void Image::loadLuminanceAlphaHalfFloatData(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const +{ + const unsigned short *source = NULL; + unsigned short *dest = NULL; + + for (int y = 0; y < height; y++) + { + source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch); + dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + y * outputPitch); + for (int x = 0; x < width; x++) + { + dest[4 * x + 0] = source[2*x+0]; + dest[4 * x + 1] = source[2*x+0]; + dest[4 * x + 2] = source[2*x+0]; + dest[4 * x + 3] = source[2*x+1]; + } + } +} + +void Image::loadRGBUByteData(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const +{ + const unsigned char *source = NULL; + unsigned char *dest = NULL; + + for (int y = 0; y < height; y++) + { + source = static_cast<const unsigned char*>(input) + y * inputPitch; + dest = static_cast<unsigned char*>(output) + y * outputPitch; + for (int x = 0; x < width; x++) + { + dest[4 * x + 0] = source[x * 3 + 2]; + dest[4 * x + 1] = source[x * 3 + 1]; + dest[4 * x + 2] = source[x * 3 + 0]; + dest[4 * x + 3] = 0xFF; + } + } +} + +void Image::loadRGB565Data(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const +{ + const unsigned short *source = NULL; + unsigned char *dest = NULL; + + for (int y = 0; y < height; y++) + { + source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch); + dest = static_cast<unsigned char*>(output) + y * outputPitch; + for (int x = 0; x < width; x++) + { + unsigned short rgba = source[x]; + dest[4 * x + 0] = ((rgba & 0x001F) << 3) | ((rgba & 0x001F) >> 2); + dest[4 * x + 1] = ((rgba & 0x07E0) >> 3) | ((rgba & 0x07E0) >> 9); + dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13); + dest[4 * x + 3] = 0xFF; + } + } +} + +void Image::loadRGBFloatData(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const +{ + const float *source = NULL; + float *dest = NULL; + + for (int y = 0; y < height; y++) + { + source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch); + dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + y * outputPitch); + for (int x = 0; x < width; x++) + { + dest[4 * x + 0] = source[x * 3 + 0]; + dest[4 * x + 1] = source[x * 3 + 1]; + dest[4 * x + 2] = source[x * 3 + 2]; + dest[4 * x + 3] = 1.0f; + } + } +} + +void Image::loadRGBHalfFloatData(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const +{ + const unsigned short *source = NULL; + unsigned short *dest = NULL; + + for (int y = 0; y < height; y++) + { + source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch); + dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + y * outputPitch); + for (int x = 0; x < width; x++) + { + dest[4 * x + 0] = source[x * 3 + 0]; + dest[4 * x + 1] = source[x * 3 + 1]; + dest[4 * x + 2] = source[x * 3 + 2]; + dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1 + } + } +} + +void Image::loadRGBAUByteData(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 * outputPitch); + + for (int x = 0; x < width; x++) + { + unsigned int rgba = source[x]; + dest[x] = (_rotl(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00); + } + } +} + +void Image::loadRGBA4444Data(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const +{ + const unsigned short *source = NULL; + unsigned char *dest = NULL; + + for (int y = 0; y < height; y++) + { + source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch); + dest = static_cast<unsigned char*>(output) + y * outputPitch; + for (int x = 0; x < width; x++) + { + unsigned short rgba = source[x]; + dest[4 * x + 0] = ((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4); + dest[4 * x + 1] = ((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8); + dest[4 * x + 2] = ((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12); + dest[4 * x + 3] = ((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0); + } + } +} + +void Image::loadRGBA5551Data(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const +{ + const unsigned short *source = NULL; + unsigned char *dest = NULL; + + for (int y = 0; y < height; y++) + { + source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch); + dest = static_cast<unsigned char*>(output) + y * outputPitch; + for (int x = 0; x < width; x++) + { + unsigned short rgba = source[x]; + dest[4 * x + 0] = ((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3); + dest[4 * x + 1] = ((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8); + dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13); + dest[4 * x + 3] = (rgba & 0x0001) ? 0xFF : 0; + } + } +} + +void Image::loadRGBAFloatData(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const +{ + const float *source = NULL; + float *dest = NULL; + + for (int y = 0; y < height; y++) + { + source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch); + dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + y * outputPitch); + memcpy(dest, source, width * 16); + } +} + +void Image::loadRGBAHalfFloatData(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const +{ + const unsigned char *source = NULL; + unsigned char *dest = NULL; + + for (int y = 0; y < height; y++) + { + source = static_cast<const unsigned char*>(input) + y * inputPitch; + dest = static_cast<unsigned char*>(output) + y * outputPitch; + memcpy(dest, source, width * 8); + } +} + +void Image::loadBGRAData(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const +{ + const unsigned char *source = NULL; + unsigned char *dest = NULL; + + for (int y = 0; y < height; y++) + { + source = static_cast<const unsigned char*>(input) + y * inputPitch; + dest = static_cast<unsigned char*>(output) + y * outputPitch; + memcpy(dest, source, width*4); + } +} + +void Image::loadCompressedData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + const void *input) { + ASSERT(xoffset % 4 == 0); + ASSERT(yoffset % 4 == 0); + + RECT lockRect = { + xoffset, yoffset, + xoffset + width, yoffset + height + }; + + D3DLOCKED_RECT locked; + HRESULT result = lock(&locked, &lockRect); + if (FAILED(result)) + { + return; + } + + GLsizei inputSize = ComputeCompressedSize(width, height, mInternalFormat); + GLsizei inputPitch = ComputeCompressedPitch(width, mInternalFormat); + int rows = inputSize / inputPitch; + for (int i = 0; i < rows; ++i) + { + memcpy((void*)((BYTE*)locked.pBits + i * locked.Pitch), (void*)((BYTE*)input + i * inputPitch), inputPitch); + } + + unlock(); +} + +// 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 = {x, y, x + width, y + height}; + RECT destRect = {xoffset, yoffset, xoffset + width, yoffset + height}; + + D3DLOCKED_RECT sourceLock = {0}; + result = renderTargetData->LockRect(&sourceLock, &sourceRect, 0); + + 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)) + { + ERR("Failed to lock the destination surface (rectangle might be invalid)."); + renderTargetData->UnlockRect(); + renderTargetData->Release(); + return error(GL_OUT_OF_MEMORY); + } + + 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_X8R8G8B8: + case D3DFMT_A8R8G8B8: + for(int y = 0; y < height; y++) + { + memcpy(dest, source, 4 * width); + + source += sourceLock.Pitch; + dest += destLock.Pitch; + } + break; + 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_X8R8G8B8: + for(int y = 0; y < height; y++) + { + for(int x = 0; x < width; x++) + { + unsigned short rgb = ((unsigned short*)source)[x]; + unsigned char red = (rgb & 0xF800) >> 8; + unsigned char green = (rgb & 0x07E0) >> 3; + unsigned char blue = (rgb & 0x001F) << 3; + dest[x + 0] = blue | (blue >> 5); + dest[x + 1] = green | (green >> 6); + dest[x + 2] = red | (red >> 5); + dest[x + 3] = 0xFF; + } + + source += sourceLock.Pitch; + dest += destLock.Pitch; + } + break; + 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_X8R8G8B8: + for(int y = 0; y < height; y++) + { + for(int x = 0; x < width; x++) + { + unsigned short argb = ((unsigned short*)source)[x]; + unsigned char red = (argb & 0x7C00) >> 7; + unsigned char green = (argb & 0x03E0) >> 2; + unsigned char blue = (argb & 0x001F) << 3; + dest[x + 0] = blue | (blue >> 5); + dest[x + 1] = green | (green >> 5); + dest[x + 2] = red | (red >> 5); + dest[x + 3] = 0xFF; + } + + source += sourceLock.Pitch; + dest += destLock.Pitch; + } + break; + case D3DFMT_A8R8G8B8: + for(int y = 0; y < height; y++) + { + for(int x = 0; x < width; x++) + { + unsigned short argb = ((unsigned short*)source)[x]; + unsigned char red = (argb & 0x7C00) >> 7; + unsigned char green = (argb & 0x03E0) >> 2; + unsigned char blue = (argb & 0x001F) << 3; + unsigned char alpha = (signed short)argb >> 15; + dest[x + 0] = blue | (blue >> 5); + dest[x + 1] = green | (green >> 5); + dest[x + 2] = red | (red >> 5); + dest[x + 3] = alpha; + } + + source += sourceLock.Pitch; + dest += destLock.Pitch; + } + break; + 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(); + + renderTargetData->Release(); + + mDirty = true; +} + +namespace +{ +struct L8 +{ + unsigned char L; + + static void average(L8 *dst, const L8 *src1, const L8 *src2) + { + dst->L = ((src1->L ^ src2->L) >> 1) + (src1->L & src2->L); + } +}; + +struct A8L8 +{ + unsigned char L; + unsigned char A; + + static void average(A8L8 *dst, const A8L8 *src1, const A8L8 *src2) + { + *(unsigned short*)dst = (((*(unsigned short*)src1 ^ *(unsigned short*)src2) & 0xFEFE) >> 1) + (*(unsigned short*)src1 & *(unsigned short*)src2); + } +}; + +struct A8R8G8B8 +{ + unsigned char B; + unsigned char G; + unsigned char R; + unsigned char A; + + static void average(A8R8G8B8 *dst, const A8R8G8B8 *src1, const A8R8G8B8 *src2) + { + *(unsigned int*)dst = (((*(unsigned int*)src1 ^ *(unsigned int*)src2) & 0xFEFEFEFE) >> 1) + (*(unsigned int*)src1 & *(unsigned int*)src2); + } +}; + +struct A16B16G16R16F +{ + unsigned short R; + unsigned short G; + unsigned short B; + unsigned short A; + + static void average(A16B16G16R16F *dst, const A16B16G16R16F *src1, const A16B16G16R16F *src2) + { + dst->R = float32ToFloat16((float16ToFloat32(src1->R) + float16ToFloat32(src2->R)) * 0.5f); + dst->G = float32ToFloat16((float16ToFloat32(src1->G) + float16ToFloat32(src2->G)) * 0.5f); + dst->B = float32ToFloat16((float16ToFloat32(src1->B) + float16ToFloat32(src2->B)) * 0.5f); + dst->A = float32ToFloat16((float16ToFloat32(src1->A) + float16ToFloat32(src2->A)) * 0.5f); + } +}; + +struct A32B32G32R32F +{ + float R; + float G; + float B; + float A; + + static void average(A32B32G32R32F *dst, const A32B32G32R32F *src1, const A32B32G32R32F *src2) + { + dst->R = (src1->R + src2->R) * 0.5f; + dst->G = (src1->G + src2->G) * 0.5f; + dst->B = (src1->B + src2->B) * 0.5f; + dst->A = (src1->A + src2->A) * 0.5f; + } +}; + +template <typename T> +void GenerateMip(unsigned int sourceWidth, unsigned int sourceHeight, + const unsigned char *sourceData, int sourcePitch, + unsigned char *destData, int destPitch) +{ + unsigned int mipWidth = std::max(1U, sourceWidth >> 1); + unsigned int mipHeight = std::max(1U, sourceHeight >> 1); + + if (sourceHeight == 1) + { + ASSERT(sourceWidth != 1); + + const T *src = (const T*)sourceData; + T *dst = (T*)destData; + + for (unsigned int x = 0; x < mipWidth; x++) + { + T::average(&dst[x], &src[x * 2], &src[x * 2 + 1]); + } + } + else if (sourceWidth == 1) + { + ASSERT(sourceHeight != 1); + + for (unsigned int y = 0; y < mipHeight; y++) + { + const T *src0 = (const T*)(sourceData + y * 2 * sourcePitch); + const T *src1 = (const T*)(sourceData + y * 2 * sourcePitch + sourcePitch); + T *dst = (T*)(destData + y * destPitch); + + T::average(dst, src0, src1); + } + } + else + { + for (unsigned int y = 0; y < mipHeight; y++) + { + const T *src0 = (const T*)(sourceData + y * 2 * sourcePitch); + const T *src1 = (const T*)(sourceData + y * 2 * sourcePitch + sourcePitch); + T *dst = (T*)(destData + y * destPitch); + + for (unsigned int x = 0; x < mipWidth; x++) + { + T tmp0; + T tmp1; + + T::average(&tmp0, &src0[x * 2], &src0[x * 2 + 1]); + T::average(&tmp1, &src1[x * 2], &src1[x * 2 + 1]); + T::average(&dst[x], &tmp0, &tmp1); + } + } + } +} + +void GenerateMip(IDirect3DSurface9 *destSurface, IDirect3DSurface9 *sourceSurface) +{ + D3DSURFACE_DESC destDesc; + HRESULT result = destSurface->GetDesc(&destDesc); + ASSERT(SUCCEEDED(result)); + + D3DSURFACE_DESC sourceDesc; + result = sourceSurface->GetDesc(&sourceDesc); + ASSERT(SUCCEEDED(result)); + + ASSERT(sourceDesc.Format == destDesc.Format); + ASSERT(sourceDesc.Width == 1 || sourceDesc.Width / 2 == destDesc.Width); + ASSERT(sourceDesc.Height == 1 || sourceDesc.Height / 2 == destDesc.Height); + + D3DLOCKED_RECT sourceLocked = {0}; + result = sourceSurface->LockRect(&sourceLocked, NULL, D3DLOCK_READONLY); + ASSERT(SUCCEEDED(result)); + + D3DLOCKED_RECT destLocked = {0}; + result = destSurface->LockRect(&destLocked, NULL, 0); + ASSERT(SUCCEEDED(result)); + + const unsigned char *sourceData = reinterpret_cast<const unsigned char*>(sourceLocked.pBits); + unsigned char *destData = reinterpret_cast<unsigned char*>(destLocked.pBits); + + if (sourceData && destData) + { + switch (sourceDesc.Format) + { + case D3DFMT_L8: + GenerateMip<L8>(sourceDesc.Width, sourceDesc.Height, sourceData, sourceLocked.Pitch, destData, destLocked.Pitch); + break; + case D3DFMT_A8L8: + GenerateMip<A8L8>(sourceDesc.Width, sourceDesc.Height, sourceData, sourceLocked.Pitch, destData, destLocked.Pitch); + break; + case D3DFMT_A8R8G8B8: + case D3DFMT_X8R8G8B8: + GenerateMip<A8R8G8B8>(sourceDesc.Width, sourceDesc.Height, sourceData, sourceLocked.Pitch, destData, destLocked.Pitch); + break; + case D3DFMT_A16B16G16R16F: + GenerateMip<A16B16G16R16F>(sourceDesc.Width, sourceDesc.Height, sourceData, sourceLocked.Pitch, destData, destLocked.Pitch); + break; + case D3DFMT_A32B32G32R32F: + GenerateMip<A32B32G32R32F>(sourceDesc.Width, sourceDesc.Height, sourceData, sourceLocked.Pitch, destData, destLocked.Pitch); + break; + default: + UNREACHABLE(); + break; + } + + destSurface->UnlockRect(); + sourceSurface->UnlockRect(); + } +} +} + +TextureStorage::TextureStorage(DWORD usage) + : mD3DUsage(usage), + mD3DPool(getDisplay()->getTexturePool(usage)), + mTextureSerial(issueTextureSerial()), + mLodOffset(0) +{ +} + +TextureStorage::~TextureStorage() +{ +} + +bool TextureStorage::isRenderTarget() const +{ + return (mD3DUsage & (D3DUSAGE_RENDERTARGET | D3DUSAGE_DEPTHSTENCIL)) != 0; +} + +bool TextureStorage::isManaged() const +{ + return (mD3DPool == D3DPOOL_MANAGED); +} + +D3DPOOL TextureStorage::getPool() const +{ + return mD3DPool; +} + +DWORD TextureStorage::getUsage() const +{ + return mD3DUsage; +} + +unsigned int TextureStorage::getTextureSerial() const +{ + return mTextureSerial; +} + +unsigned int TextureStorage::issueTextureSerial() +{ + return mCurrentTextureSerial++; +} + +int TextureStorage::getLodOffset() const +{ + return mLodOffset; +} + +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; + mMaxAnisotropy = 1.0f; + + mDirtyImages = true; + + mImmutable = false; +} + +Texture::~Texture() +{ +} + +// Returns true on successful filter state update (valid enum parameter) +bool Texture::setMinFilter(GLenum filter) +{ + switch (filter) + { + 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; + } +} + +// 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; + } +} + +// 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; + } +} + +// 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: + { + if (mWrapT != wrap) + { + mWrapT = wrap; + mDirtyParameters = true; + } + return true; + } + default: + return false; + } +} + +// Returns true on successful max anisotropy update (valid anisotropy value) +bool Texture::setMaxAnisotropy(float textureMaxAnisotropy, float contextMaxAnisotropy) +{ + textureMaxAnisotropy = std::min(textureMaxAnisotropy, contextMaxAnisotropy); + if (textureMaxAnisotropy < 1.0f) + { + return false; + } + if (mMaxAnisotropy != textureMaxAnisotropy) + { + mMaxAnisotropy = textureMaxAnisotropy; + mDirtyParameters = true; + } + return 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; + } +} + +GLenum Texture::getMinFilter() const +{ + return mMinFilter; +} + +GLenum Texture::getMagFilter() const +{ + return mMagFilter; +} + +GLenum Texture::getWrapS() const +{ + return mWrapS; +} + +GLenum Texture::getWrapT() const +{ + return mWrapT; +} + +float Texture::getMaxAnisotropy() const +{ + return mMaxAnisotropy; +} + +GLenum Texture::getUsage() const +{ + return mUsage; +} + +void Texture::setImage(GLint unpackAlignment, const void *pixels, Image *image) +{ + if (pixels != NULL) + { + image->loadData(0, 0, image->getWidth(), image->getHeight(), unpackAlignment, pixels); + mDirtyImages = true; + } +} + +void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, Image *image) +{ + if (pixels != NULL) + { + image->loadCompressedData(0, 0, image->getWidth(), image->getHeight(), pixels); + mDirtyImages = true; + } +} + +bool Texture::subImage(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *image) +{ + if (pixels != NULL) + { + image->loadData(xoffset, yoffset, width, height, unpackAlignment, pixels); + mDirtyImages = true; + } + + return true; +} + +bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *image) +{ + if (pixels != NULL) + { + image->loadCompressedData(xoffset, yoffset, width, height, pixels); + mDirtyImages = true; + } + + return true; +} + +IDirect3DBaseTexture9 *Texture::getTexture() +{ + if (!isSamplerComplete()) + { + return NULL; + } + + // ensure the underlying texture is created + if (getStorage(false) == NULL) + { + return NULL; + } + + updateTexture(); + + return getBaseTexture(); +} + +bool Texture::hasDirtyParameters() const +{ + return mDirtyParameters; +} + +bool Texture::hasDirtyImages() const +{ + return mDirtyImages; +} + +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; +} + +int Texture::getLodOffset() +{ + TextureStorage *texture = getStorage(false); + return texture ? texture->getLodOffset() : 0; +} + +GLint Texture::creationLevels(GLsizei width, GLsizei height) const +{ + if ((isPow2(width) && isPow2(height)) || getContext()->supportsNonPower2Texture()) + { + return 0; // Maximum number of levels + } + else + { + // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps. + return 1; + } +} + +GLint Texture::creationLevels(GLsizei size) const +{ + return creationLevels(size, size); +} + +int Texture::levelCount() +{ + return getBaseTexture() ? getBaseTexture()->GetLevelCount() - getLodOffset() : 0; +} + +Blit *Texture::getBlitter() +{ + Context *context = getContext(); + return context->getBlitter(); +} + +bool Texture::copyToRenderTarget(IDirect3DSurface9 *dest, IDirect3DSurface9 *source, bool fromManaged) +{ + if (source && dest) + { + HRESULT result = D3DERR_OUTOFVIDEOMEMORY; + + if (fromManaged) + { + D3DSURFACE_DESC desc; + source->GetDesc(&desc); + + IDirect3DSurface9 *surf = 0; + result = getDevice()->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &surf, NULL); + + if (SUCCEEDED(result)) + { + CopyLockableSurfaces(surf, source); + result = getDevice()->UpdateSurface(surf, NULL, dest, NULL); + surf->Release(); + } + } + else + { + egl::Display *display = getDisplay(); + IDirect3DDevice9 *device = display->getDevice(); + + display->endScene(); + result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE); + } + + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + return false; + } + } + + return true; +} + +TextureStorage2D::TextureStorage2D(IDirect3DTexture9 *surfaceTexture) : TextureStorage(D3DUSAGE_RENDERTARGET), mRenderTargetSerial(RenderbufferStorage::issueSerial()) +{ + mTexture = surfaceTexture; +} + +TextureStorage2D::TextureStorage2D(int levels, D3DFORMAT format, DWORD usage, int width, int height) + : TextureStorage(usage), mRenderTargetSerial(RenderbufferStorage::issueSerial()) +{ + mTexture = NULL; + // if the width or height is not positive this should be treated as an incomplete texture + // we handle that here by skipping the d3d texture creation + if (width > 0 && height > 0) + { + IDirect3DDevice9 *device = getDevice(); + MakeValidSize(false, dx::IsCompressedFormat(format), &width, &height, &mLodOffset); + HRESULT result = device->CreateTexture(width, height, levels ? levels + mLodOffset : 0, getUsage(), format, getPool(), &mTexture, NULL); + + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + error(GL_OUT_OF_MEMORY); + } + } +} + +TextureStorage2D::~TextureStorage2D() +{ + if (mTexture) + { + mTexture->Release(); + } +} + +// Increments refcount on surface. +// caller must Release() the returned surface +IDirect3DSurface9 *TextureStorage2D::getSurfaceLevel(int level, bool dirty) +{ + IDirect3DSurface9 *surface = NULL; + + if (mTexture) + { + HRESULT result = mTexture->GetSurfaceLevel(level + mLodOffset, &surface); + ASSERT(SUCCEEDED(result)); + + // With managed textures the driver needs to be informed of updates to the lower mipmap levels + if (level != 0 && isManaged() && dirty) + { + mTexture->AddDirtyRect(NULL); + } + } + + return surface; +} + +IDirect3DBaseTexture9 *TextureStorage2D::getBaseTexture() const +{ + return mTexture; +} + +unsigned int TextureStorage2D::getRenderTargetSerial(GLenum target) const +{ + return mRenderTargetSerial; +} + +Texture2D::Texture2D(GLuint id) : Texture(id) +{ + mTexStorage = NULL; + mSurface = NULL; + mColorbufferProxy = NULL; + mProxyRefs = 0; +} + +Texture2D::~Texture2D() +{ + mColorbufferProxy = NULL; + + delete mTexStorage; + mTexStorage = NULL; + + if (mSurface) + { + mSurface->setBoundTexture(NULL); + mSurface = NULL; + } +} + +// 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 Texture2D::releaseProxy(const Renderbuffer *proxy) +{ + if (mProxyRefs > 0) + mProxyRefs--; + + if (mProxyRefs == 0) + mColorbufferProxy = NULL; +} + +GLenum Texture2D::getTarget() const +{ + return GL_TEXTURE_2D; +} + +GLsizei Texture2D::getWidth(GLint level) const +{ + if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) + return mImageArray[level].getWidth(); + else + return 0; +} + +GLsizei Texture2D::getHeight(GLint level) const +{ + if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) + return mImageArray[level].getHeight(); + else + return 0; +} + +GLenum Texture2D::getInternalFormat(GLint level) const +{ + if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) + return mImageArray[level].getInternalFormat(); + else + return GL_NONE; +} + +D3DFORMAT Texture2D::getD3DFormat(GLint level) const +{ + if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) + return mImageArray[level].getD3DFormat(); + else + return D3DFMT_UNKNOWN; +} + +void Texture2D::redefineImage(GLint level, GLint internalformat, GLsizei width, GLsizei height) +{ + releaseTexImage(); + + bool redefined = mImageArray[level].redefine(internalformat, width, height, false); + + if (mTexStorage && redefined) + { + for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) + { + mImageArray[i].markDirty(); + } + + delete mTexStorage; + mTexStorage = NULL; + mDirtyImages = true; + } +} + +void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) +{ + GLint internalformat = ConvertSizedInternalFormat(format, type); + redefineImage(level, internalformat, width, height); + + Texture::setImage(unpackAlignment, pixels, &mImageArray[level]); +} + +void Texture2D::bindTexImage(egl::Surface *surface) +{ + releaseTexImage(); + + GLint internalformat; + + switch(surface->getFormat()) + { + case D3DFMT_A8R8G8B8: + internalformat = GL_RGBA8_OES; + break; + case D3DFMT_X8R8G8B8: + internalformat = GL_RGB8_OES; + break; + default: + UNIMPLEMENTED(); + return; + } + + mImageArray[0].redefine(internalformat, surface->getWidth(), surface->getHeight(), true); + + delete mTexStorage; + mTexStorage = new TextureStorage2D(surface->getOffscreenTexture()); + + mDirtyImages = true; + mSurface = surface; + mSurface->setBoundTexture(this); +} + +void Texture2D::releaseTexImage() +{ + if (mSurface) + { + mSurface->setBoundTexture(NULL); + mSurface = NULL; + + if (mTexStorage) + { + delete mTexStorage; + mTexStorage = NULL; + } + + for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) + { + mImageArray[i].redefine(GL_RGBA8_OES, 0, 0, true); + } + } +} + +void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels) +{ + // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly + redefineImage(level, format, width, height); + + Texture::setCompressedImage(imageSize, pixels, &mImageArray[level]); +} + +void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) +{ + ASSERT(mImageArray[level].getSurface() != NULL); + + if (level < levelCount()) + { + IDirect3DSurface9 *destLevel = mTexStorage->getSurfaceLevel(level, true); + + if (destLevel) + { + Image *image = &mImageArray[level]; + image->updateSurface(destLevel, xoffset, yoffset, width, height); + + destLevel->Release(); + image->markClean(); + } + } +} + +void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) +{ + if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[level])) + { + commitRect(level, xoffset, yoffset, width, height); + } +} + +void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels) +{ + if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[level])) + { + commitRect(level, xoffset, yoffset, width, height); + } +} + +void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) +{ + IDirect3DSurface9 *renderTarget = source->getRenderTarget(); + + if (!renderTarget) + { + ERR("Failed to retrieve the render target."); + return error(GL_OUT_OF_MEMORY); + } + + GLint internalformat = ConvertSizedInternalFormat(format, GL_UNSIGNED_BYTE); + redefineImage(level, internalformat, width, height); + + if (!mImageArray[level].isRenderableFormat()) + { + mImageArray[level].copy(0, 0, x, y, width, height, renderTarget); + mDirtyImages = true; + } + else + { + if (!mTexStorage || !mTexStorage->isRenderTarget()) + { + convertToRenderTarget(); + } + + 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; + + IDirect3DSurface9 *dest = mTexStorage->getSurfaceLevel(level, true); + + if (dest) + { + getBlitter()->copy(renderTarget, sourceRect, format, 0, 0, dest); + dest->Release(); + } + } + } + + renderTarget->Release(); +} + +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].getWidth() || yoffset + height > mImageArray[level].getHeight()) + { + return error(GL_INVALID_VALUE); + } + + IDirect3DSurface9 *renderTarget = source->getRenderTarget(); + + if (!renderTarget) + { + ERR("Failed to retrieve the render target."); + return error(GL_OUT_OF_MEMORY); + } + + if (!mImageArray[level].isRenderableFormat() || (!mTexStorage && !isSamplerComplete())) + { + mImageArray[level].copy(xoffset, yoffset, x, y, width, height, renderTarget); + mDirtyImages = true; + } + else + { + if (!mTexStorage || !mTexStorage->isRenderTarget()) + { + convertToRenderTarget(); + } + + updateTexture(); + + if (level < levelCount()) + { + RECT sourceRect; + sourceRect.left = x; + sourceRect.right = x + width; + sourceRect.top = y; + sourceRect.bottom = y + height; + + IDirect3DSurface9 *dest = mTexStorage->getSurfaceLevel(level, true); + + if (dest) + { + getBlitter()->copy(renderTarget, sourceRect, + gl::ExtractFormat(mImageArray[0].getInternalFormat()), + xoffset, yoffset, dest); + dest->Release(); + } + } + } + + renderTarget->Release(); +} + +void Texture2D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) +{ + D3DFORMAT d3dfmt = ConvertTextureInternalFormat(internalformat); + DWORD d3dusage = GetTextureUsage(d3dfmt, mUsage, false); + + delete mTexStorage; + mTexStorage = new TextureStorage2D(levels, d3dfmt, d3dusage, width, height); + mImmutable = true; + + for (int level = 0; level < levels; level++) + { + mImageArray[level].redefine(internalformat, width, height, 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, true); + } + + if (mTexStorage->isManaged()) + { + int levels = levelCount(); + + for (int level = 0; level < levels; level++) + { + IDirect3DSurface9 *surface = mTexStorage->getSurfaceLevel(level, false); + 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) + { + return false; + } + + bool mipmapping = false; + + switch (mMinFilter) + { + case GL_NEAREST: + case GL_LINEAR: + mipmapping = false; + break; + case GL_NEAREST_MIPMAP_NEAREST: + case GL_LINEAR_MIPMAP_NEAREST: + case GL_NEAREST_MIPMAP_LINEAR: + case GL_LINEAR_MIPMAP_LINEAR: + mipmapping = true; + break; + default: UNREACHABLE(); + } + + if ((IsFloat32Format(getInternalFormat(0)) && !getContext()->supportsFloat32LinearFilter()) || + (IsFloat16Format(getInternalFormat(0)) && !getContext()->supportsFloat16LinearFilter())) + { + if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST)) + { + return false; + } + } + + bool npotSupport = getContext()->supportsNonPower2Texture(); + + if (!npotSupport) + { + if ((getWrapS() != GL_CLAMP_TO_EDGE && !isPow2(width)) || + (getWrapT() != GL_CLAMP_TO_EDGE && !isPow2(height))) + { + return false; + } + } + + if (mipmapping) + { + if (!npotSupport) + { + if (!isPow2(width) || !isPow2(height)) + { + return false; + } + } + + if (!isMipmapComplete()) + { + return false; + } + } + + return true; +} + +// 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].getInternalFormat() != mImageArray[0].getInternalFormat()) + { + return false; + } + + if (mImageArray[level].getWidth() != std::max(1, width >> level)) + { + return false; + } + + if (mImageArray[level].getHeight() != std::max(1, height >> level)) + { + return false; + } + } + + return true; +} + +bool Texture2D::isCompressed(GLint level) const +{ + return IsCompressed(getInternalFormat(level)); +} + +bool Texture2D::isDepth(GLint level) const +{ + return IsDepthTexture(getInternalFormat(level)); +} + +IDirect3DBaseTexture9 *Texture2D::getBaseTexture() const +{ + return mTexStorage ? mTexStorage->getBaseTexture() : NULL; +} + +// Constructs a Direct3D 9 texture resource from the texture images +void Texture2D::createTexture() +{ + GLsizei width = mImageArray[0].getWidth(); + GLsizei height = mImageArray[0].getHeight(); + + if (!(width > 0 && height > 0)) + return; // do not attempt to create d3d textures for nonexistant data + + GLint levels = creationLevels(width, height); + D3DFORMAT d3dfmt = mImageArray[0].getD3DFormat(); + DWORD d3dusage = GetTextureUsage(d3dfmt, mUsage, false); + + delete mTexStorage; + mTexStorage = new TextureStorage2D(levels, d3dfmt, d3dusage, width, height); + + if (mTexStorage->isManaged()) + { + int levels = levelCount(); + + for (int level = 0; level < levels; level++) + { + IDirect3DSurface9 *surface = mTexStorage->getSurfaceLevel(level, false); + mImageArray[level].setManagedSurface(surface); + } + } + + mDirtyImages = true; +} + +void Texture2D::updateTexture() +{ + int levels = levelCount(); + + for (int level = 0; level < levels; level++) + { + Image *image = &mImageArray[level]; + + if (image->isDirty()) + { + commitRect(level, 0, 0, mImageArray[level].getWidth(), mImageArray[level].getHeight()); + } + } +} + +void Texture2D::convertToRenderTarget() +{ + TextureStorage2D *newTexStorage = NULL; + + if (mImageArray[0].getWidth() != 0 && mImageArray[0].getHeight() != 0) + { + GLsizei width = mImageArray[0].getWidth(); + GLsizei height = mImageArray[0].getHeight(); + GLint levels = creationLevels(width, height); + D3DFORMAT d3dfmt = mImageArray[0].getD3DFormat(); + DWORD d3dusage = GetTextureUsage(d3dfmt, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, true); + + newTexStorage = new TextureStorage2D(levels, d3dfmt, d3dusage, width, height); + + if (mTexStorage != NULL) + { + int levels = levelCount(); + for (int i = 0; i < levels; i++) + { + IDirect3DSurface9 *source = mTexStorage->getSurfaceLevel(i, false); + IDirect3DSurface9 *dest = newTexStorage->getSurfaceLevel(i, true); + + if (!copyToRenderTarget(dest, source, mTexStorage->isManaged())) + { + delete newTexStorage; + if (source) source->Release(); + if (dest) dest->Release(); + return error(GL_OUT_OF_MEMORY); + } + + if (source) source->Release(); + if (dest) dest->Release(); + } + } + } + + delete mTexStorage; + mTexStorage = newTexStorage; + + mDirtyImages = true; +} + +void Texture2D::generateMipmaps() +{ + if (!getContext()->supportsNonPower2Texture()) + { + 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(mImageArray[0].getWidth(), mImageArray[0].getHeight())); + for (unsigned int i = 1; i <= q; i++) + { + redefineImage(i, mImageArray[0].getInternalFormat(), + std::max(mImageArray[0].getWidth() >> i, 1), + std::max(mImageArray[0].getHeight() >> i, 1)); + } + + if (mTexStorage && mTexStorage->isRenderTarget()) + { + for (unsigned int i = 1; i <= q; i++) + { + IDirect3DSurface9 *upper = mTexStorage->getSurfaceLevel(i - 1, false); + IDirect3DSurface9 *lower = mTexStorage->getSurfaceLevel(i, true); + + if (upper != NULL && lower != NULL) + { + getBlitter()->boxFilter(upper, lower); + } + + if (upper != NULL) upper->Release(); + if (lower != NULL) lower->Release(); + + mImageArray[i].markClean(); + } + } + else + { + for (unsigned int i = 1; i <= q; i++) + { + if (mImageArray[i].getSurface() == NULL) + { + return error(GL_OUT_OF_MEMORY); + } + + GenerateMip(mImageArray[i].getSurface(), mImageArray[i - 1].getSurface()); + + mImageArray[i].markDirty(); + } + } +} + +Renderbuffer *Texture2D::getRenderbuffer(GLenum target) +{ + if (target != GL_TEXTURE_2D) + { + return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL); + } + + if (mColorbufferProxy == NULL) + { + mColorbufferProxy = new Renderbuffer(id(), new RenderbufferTexture2D(this, target)); + } + + return mColorbufferProxy; +} + +// Increments refcount on surface. +// caller must Release() the returned surface +IDirect3DSurface9 *Texture2D::getRenderTarget(GLenum target) +{ + ASSERT(target == GL_TEXTURE_2D); + + // ensure the underlying texture is created + if (getStorage(true) == NULL) + { + return NULL; + } + + updateTexture(); + + // ensure this is NOT a depth texture + if (isDepth(0)) + { + return NULL; + } + return mTexStorage->getSurfaceLevel(0, false); +} + +// Increments refcount on surface. +// caller must Release() the returned surface +IDirect3DSurface9 *Texture2D::getDepthStencil(GLenum target) +{ + ASSERT(target == GL_TEXTURE_2D); + + // ensure the underlying texture is created + if (getStorage(true) == NULL) + { + return NULL; + } + + updateTexture(); + + // ensure this is actually a depth texture + if (!isDepth(0)) + { + return NULL; + } + return mTexStorage->getSurfaceLevel(0, false); +} + +TextureStorage *Texture2D::getStorage(bool renderTarget) +{ + if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget())) + { + if (renderTarget) + { + convertToRenderTarget(); + } + else + { + createTexture(); + } + } + + return mTexStorage; +} + +TextureStorageCubeMap::TextureStorageCubeMap(int levels, D3DFORMAT format, DWORD usage, int size) + : TextureStorage(usage), mFirstRenderTargetSerial(RenderbufferStorage::issueCubeSerials()) +{ + mTexture = NULL; + // if the size is not positive this should be treated as an incomplete texture + // we handle that here by skipping the d3d texture creation + if (size > 0) + { + IDirect3DDevice9 *device = getDevice(); + int height = size; + MakeValidSize(false, dx::IsCompressedFormat(format), &size, &height, &mLodOffset); + HRESULT result = device->CreateCubeTexture(size, levels ? levels + mLodOffset : 0, getUsage(), 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(); + } +} + +// Increments refcount on surface. +// caller must Release() the returned surface +IDirect3DSurface9 *TextureStorageCubeMap::getCubeMapSurface(GLenum faceTarget, int level, bool dirty) +{ + IDirect3DSurface9 *surface = NULL; + + if (mTexture) + { + D3DCUBEMAP_FACES face = es2dx::ConvertCubeFace(faceTarget); + HRESULT result = mTexture->GetCubeMapSurface(face, level + mLodOffset, &surface); + ASSERT(SUCCEEDED(result)); + + // With managed textures the driver needs to be informed of updates to the lower mipmap levels + if (level != 0 && isManaged() && dirty) + { + mTexture->AddDirtyRect(face, NULL); + } + } + + 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] = NULL; + } + + 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++) + { + 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; + } + } +} + +GLenum TextureCubeMap::getTarget() const +{ + return GL_TEXTURE_CUBE_MAP; +} + +GLsizei TextureCubeMap::getWidth(GLenum target, GLint level) const +{ + if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) + return mImageArray[faceIndex(target)][level].getWidth(); + else + return 0; +} + +GLsizei TextureCubeMap::getHeight(GLenum target, GLint level) const +{ + if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) + return mImageArray[faceIndex(target)][level].getHeight(); + else + return 0; +} + +GLenum TextureCubeMap::getInternalFormat(GLenum target, GLint level) const +{ + if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) + return mImageArray[faceIndex(target)][level].getInternalFormat(); + else + return GL_NONE; +} + +D3DFORMAT TextureCubeMap::getD3DFormat(GLenum target, GLint level) const +{ + if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) + return mImageArray[faceIndex(target)][level].getD3DFormat(); + else + return D3DFMT_UNKNOWN; +} + +void TextureCubeMap::setImagePosX(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) +{ + setImage(0, level, width, height, format, type, unpackAlignment, pixels); +} + +void TextureCubeMap::setImageNegX(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) +{ + setImage(1, level, width, height, format, type, unpackAlignment, pixels); +} + +void TextureCubeMap::setImagePosY(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) +{ + setImage(2, level, width, height, format, type, unpackAlignment, pixels); +} + +void TextureCubeMap::setImageNegY(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) +{ + setImage(3, level, width, height, format, type, unpackAlignment, pixels); +} + +void TextureCubeMap::setImagePosZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) +{ + setImage(4, level, width, height, format, type, unpackAlignment, pixels); +} + +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::setCompressedImage(GLenum face, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels) +{ + // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly + redefineImage(faceIndex(face), level, format, width, height); + + Texture::setCompressedImage(imageSize, pixels, &mImageArray[faceIndex(face)][level]); +} + +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 = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, true); + ASSERT(destLevel != NULL); + + if (destLevel != NULL) + { + Image *image = &mImageArray[face][level]; + image->updateSurface(destLevel, xoffset, yoffset, width, height); + + destLevel->Release(); + image->markClean(); + } + } +} + +void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) +{ + if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[faceIndex(target)][level])) + { + commitRect(faceIndex(target), level, xoffset, yoffset, width, height); + } +} + +void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels) +{ + if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[faceIndex(target)][level])) + { + commitRect(faceIndex(target), level, xoffset, yoffset, width, height); + } +} + +// 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].getWidth(); + + bool mipmapping; + + switch (mMinFilter) + { + case GL_NEAREST: + case GL_LINEAR: + mipmapping = false; + break; + case GL_NEAREST_MIPMAP_NEAREST: + case GL_LINEAR_MIPMAP_NEAREST: + case GL_NEAREST_MIPMAP_LINEAR: + case GL_LINEAR_MIPMAP_LINEAR: + mipmapping = true; + break; + default: + UNREACHABLE(); + return false; + } + + if ((gl::ExtractType(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0)) == GL_FLOAT && !getContext()->supportsFloat32LinearFilter()) || + (gl::ExtractType(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0) == GL_HALF_FLOAT_OES) && !getContext()->supportsFloat16LinearFilter())) + { + if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST)) + { + return false; + } + } + + if (!isPow2(size) && !getContext()->supportsNonPower2Texture()) + { + if (getWrapS() != GL_CLAMP_TO_EDGE || getWrapT() != GL_CLAMP_TO_EDGE || mipmapping) + { + return false; + } + } + + if (!mipmapping) + { + if (!isCubeComplete()) + { + return false; + } + } + else + { + if (!isMipmapCubeComplete()) // Also tests for isCubeComplete() + { + return false; + } + } + + return true; +} + +// 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].getInternalFormat() != mImageArray[0][0].getInternalFormat()) + { + 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].getInternalFormat() != mImageArray[0][0].getInternalFormat()) + { + return false; + } + + if (mImageArray[face][level].getWidth() != std::max(1, size >> level)) + { + return false; + } + } + } + + return true; +} + +bool TextureCubeMap::isCompressed(GLenum target, GLint level) const +{ + return IsCompressed(getInternalFormat(target, level)); +} + +IDirect3DBaseTexture9 *TextureCubeMap::getBaseTexture() const +{ + return mTexStorage ? mTexStorage->getBaseTexture() : NULL; +} + +// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one +void TextureCubeMap::createTexture() +{ + GLsizei size = mImageArray[0][0].getWidth(); + + if (!(size > 0)) + return; // do not attempt to create d3d textures for nonexistant data + + GLint levels = creationLevels(size); + D3DFORMAT d3dfmt = mImageArray[0][0].getD3DFormat(); + DWORD d3dusage = GetTextureUsage(d3dfmt, mUsage, false); + + delete mTexStorage; + mTexStorage = new TextureStorageCubeMap(levels, d3dfmt, d3dusage, size); + + 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, false); + mImageArray[face][level].setManagedSurface(surface); + } + } + } + + mDirtyImages = true; +} + +void TextureCubeMap::updateTexture() +{ + for (int face = 0; face < 6; face++) + { + int levels = levelCount(); + for (int level = 0; level < levels; level++) + { + Image *image = &mImageArray[face][level]; + + if (image->isDirty()) + { + commitRect(face, level, 0, 0, image->getWidth(), image->getHeight()); + } + } + } +} + +void TextureCubeMap::convertToRenderTarget() +{ + TextureStorageCubeMap *newTexStorage = NULL; + + if (mImageArray[0][0].getWidth() != 0) + { + GLsizei size = mImageArray[0][0].getWidth(); + GLint levels = creationLevels(size); + D3DFORMAT d3dfmt = mImageArray[0][0].getD3DFormat(); + DWORD d3dusage = GetTextureUsage(d3dfmt, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, true); + + newTexStorage = new TextureStorageCubeMap(levels, d3dfmt, d3dusage, size); + + if (mTexStorage != NULL) + { + int levels = levelCount(); + for (int f = 0; f < 6; f++) + { + for (int i = 0; i < levels; i++) + { + IDirect3DSurface9 *source = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i, false); + IDirect3DSurface9 *dest = newTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i, true); + + if (!copyToRenderTarget(dest, source, mTexStorage->isManaged())) + { + delete newTexStorage; + if (source) source->Release(); + if (dest) dest->Release(); + return error(GL_OUT_OF_MEMORY); + } + + if (source) source->Release(); + if (dest) dest->Release(); + } + } + } + } + + delete mTexStorage; + mTexStorage = newTexStorage; + + mDirtyImages = true; +} + +void TextureCubeMap::setImage(int faceIndex, GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) +{ + GLint internalformat = ConvertSizedInternalFormat(format, type); + redefineImage(faceIndex, level, internalformat, width, height); + + Texture::setImage(unpackAlignment, pixels, &mImageArray[faceIndex][level]); +} + +unsigned int TextureCubeMap::faceIndex(GLenum face) +{ + META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1); + META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2); + META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3); + META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4); + META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5); + + return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X; +} + +void TextureCubeMap::redefineImage(int face, GLint level, GLint internalformat, GLsizei width, GLsizei height) +{ + bool redefined = mImageArray[face][level].redefine(internalformat, width, height, false); + + if (mTexStorage && redefined) + { + for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) + { + for (int f = 0; f < 6; f++) + { + mImageArray[f][i].markDirty(); + } + } + + delete mTexStorage; + mTexStorage = NULL; + + mDirtyImages = true; + } +} + +void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) +{ + IDirect3DSurface9 *renderTarget = source->getRenderTarget(); + + if (!renderTarget) + { + ERR("Failed to retrieve the render target."); + return error(GL_OUT_OF_MEMORY); + } + + unsigned int faceindex = faceIndex(target); + GLint internalformat = gl::ConvertSizedInternalFormat(format, GL_UNSIGNED_BYTE); + redefineImage(faceindex, level, internalformat, width, height); + + if (!mImageArray[faceindex][level].isRenderableFormat()) + { + mImageArray[faceindex][level].copy(0, 0, x, y, width, height, renderTarget); + mDirtyImages = true; + } + else + { + if (!mTexStorage || !mTexStorage->isRenderTarget()) + { + convertToRenderTarget(); + } + + 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; + + IDirect3DSurface9 *dest = mTexStorage->getCubeMapSurface(target, level, true); + + if (dest) + { + getBlitter()->copy(renderTarget, sourceRect, format, 0, 0, dest); + dest->Release(); + } + } + } + + renderTarget->Release(); +} + +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].getWidth(); + + if (xoffset + width > size || yoffset + height > size) + { + return error(GL_INVALID_VALUE); + } + + IDirect3DSurface9 *renderTarget = source->getRenderTarget(); + + if (!renderTarget) + { + ERR("Failed to retrieve the render target."); + return error(GL_OUT_OF_MEMORY); + } + + unsigned int faceindex = faceIndex(target); + + if (!mImageArray[faceindex][level].isRenderableFormat() || (!mTexStorage && !isSamplerComplete())) + { + mImageArray[faceindex][level].copy(0, 0, x, y, width, height, renderTarget); + mDirtyImages = true; + } + else + { + if (!mTexStorage || !mTexStorage->isRenderTarget()) + { + convertToRenderTarget(); + } + + updateTexture(); + + if (level < levelCount()) + { + RECT sourceRect; + sourceRect.left = x; + sourceRect.right = x + width; + sourceRect.top = y; + sourceRect.bottom = y + height; + + IDirect3DSurface9 *dest = mTexStorage->getCubeMapSurface(target, level, true); + + if (dest) + { + getBlitter()->copy(renderTarget, sourceRect, gl::ExtractFormat(mImageArray[0][0].getInternalFormat()), xoffset, yoffset, dest); + dest->Release(); + } + } + } + + renderTarget->Release(); +} + +void TextureCubeMap::storage(GLsizei levels, GLenum internalformat, GLsizei size) +{ + D3DFORMAT d3dfmt = ConvertTextureInternalFormat(internalformat); + DWORD d3dusage = GetTextureUsage(d3dfmt, mUsage, false); + + delete mTexStorage; + mTexStorage = new TextureStorageCubeMap(levels, d3dfmt, d3dusage, size); + mImmutable = true; + + for (int level = 0; level < levels; level++) + { + for (int face = 0; face < 6; face++) + { + mImageArray[face][level].redefine(internalformat, size, size, true); + size = std::max(1, size >> 1); + } + } + + for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) + { + for (int face = 0; face < 6; face++) + { + mImageArray[face][level].redefine(GL_NONE, 0, 0, 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, false); + mImageArray[face][level].setManagedSurface(surface); + } + } + } +} + +void TextureCubeMap::generateMipmaps() +{ + if (!isCubeComplete()) + { + return error(GL_INVALID_OPERATION); + } + + if (!getContext()->supportsNonPower2Texture()) + { + if (!isPow2(mImageArray[0][0].getWidth())) + { + 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].getWidth()); + for (unsigned int f = 0; f < 6; f++) + { + for (unsigned int i = 1; i <= q; i++) + { + redefineImage(f, i, mImageArray[f][0].getInternalFormat(), + std::max(mImageArray[f][0].getWidth() >> i, 1), + std::max(mImageArray[f][0].getWidth() >> i, 1)); + } + } + + if (mTexStorage && mTexStorage->isRenderTarget()) + { + for (unsigned int f = 0; f < 6; f++) + { + for (unsigned int i = 1; i <= q; i++) + { + IDirect3DSurface9 *upper = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i - 1, false); + IDirect3DSurface9 *lower = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i, true); + + if (upper != NULL && lower != NULL) + { + getBlitter()->boxFilter(upper, lower); + } + + if (upper != NULL) upper->Release(); + if (lower != NULL) lower->Release(); + + mImageArray[f][i].markClean(); + } + } + } + else + { + for (unsigned int f = 0; f < 6; f++) + { + for (unsigned int i = 1; i <= q; i++) + { + if (mImageArray[f][i].getSurface() == NULL) + { + return error(GL_OUT_OF_MEMORY); + } + + GenerateMip(mImageArray[f][i].getSurface(), mImageArray[f][i - 1].getSurface()); + + mImageArray[f][i].markDirty(); + } + } + } +} + +Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target) +{ + if (!IsCubemapTextureTarget(target)) + { + return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL); + } + + unsigned int face = faceIndex(target); + + if (mFaceProxies[face] == NULL) + { + mFaceProxies[face] = new Renderbuffer(id(), new RenderbufferTextureCubeMap(this, target)); + } + + return mFaceProxies[face]; +} + +// Increments refcount on surface. +// caller must Release() the returned surface +IDirect3DSurface9 *TextureCubeMap::getRenderTarget(GLenum target) +{ + ASSERT(IsCubemapTextureTarget(target)); + + // ensure the underlying texture is created + if (getStorage(true) == NULL) + { + return NULL; + } + + updateTexture(); + + return mTexStorage->getCubeMapSurface(target, 0, false); +} + +TextureStorage *TextureCubeMap::getStorage(bool renderTarget) +{ + if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget())) + { + if (renderTarget) + { + convertToRenderTarget(); + } + else + { + createTexture(); + } + } + + return mTexStorage; +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/Texture.h b/src/3rdparty/angle/src/libGLESv2/Texture.h new file mode 100644 index 0000000000..7d7378f88b --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/Texture.h @@ -0,0 +1,433 @@ +// +// 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. +// + +// Texture.h: Defines the abstract gl::Texture class and its concrete derived +// classes Texture2D and TextureCubeMap. Implements GL texture objects and +// related functionality. [OpenGL ES 2.0.24] section 3.7 page 63. + +#ifndef LIBGLESV2_TEXTURE_H_ +#define LIBGLESV2_TEXTURE_H_ + +#include <vector> + +#define GL_APICALL +#include <GLES2/gl2.h> +#include <d3d9.h> + +#include "common/debug.h" +#include "common/RefCountObject.h" +#include "libGLESv2/Renderbuffer.h" +#include "libGLESv2/utilities.h" + +namespace egl +{ +class Surface; +} + +namespace gl +{ +class Blit; +class Framebuffer; + +enum +{ + // These are the maximums the implementation can support + // The actual GL caps are limited by the device caps + // and should be queried from the Context + IMPLEMENTATION_MAX_TEXTURE_SIZE = 16384, + IMPLEMENTATION_MAX_CUBE_MAP_TEXTURE_SIZE = 16384, + + IMPLEMENTATION_MAX_TEXTURE_LEVELS = 15 // 1+log2 of MAX_TEXTURE_SIZE +}; + +class Image +{ + public: + Image(); + ~Image(); + + bool redefine(GLint internalformat, GLsizei width, GLsizei height, bool forceRelease); + void markDirty() {mDirty = true;} + void markClean() {mDirty = false;} + + bool isRenderableFormat() const; + D3DFORMAT getD3DFormat() const; + + GLsizei getWidth() const {return mWidth;} + GLsizei getHeight() const {return mHeight;} + GLenum getInternalFormat() const {return mInternalFormat;} + 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, + GLint unpackAlignment, const void *input); + + void loadAlphaData(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadAlphaDataSSE2(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadAlphaFloatData(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadAlphaHalfFloatData(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadLuminanceData(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const; + void loadLuminanceFloatData(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadLuminanceHalfFloatData(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadLuminanceAlphaData(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const; + void loadLuminanceAlphaFloatData(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadLuminanceAlphaHalfFloatData(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadRGBUByteData(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadRGB565Data(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadRGBFloatData(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadRGBHalfFloatData(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadRGBAUByteDataSSE2(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadRGBAUByteData(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadRGBA4444Data(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadRGBA5551Data(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadRGBAFloatData(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadRGBAHalfFloatData(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadBGRAData(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, + const void *input); + + void copy(GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, IDirect3DSurface9 *renderTarget); + + private: + DISALLOW_COPY_AND_ASSIGN(Image); + + void createSurface(); + + HRESULT lock(D3DLOCKED_RECT *lockedRect, const RECT *rect); + void unlock(); + + GLsizei mWidth; + GLsizei mHeight; + GLint mInternalFormat; + + 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(DWORD usage); + + virtual ~TextureStorage(); + + bool isRenderTarget() const; + bool isManaged() const; + D3DPOOL getPool() const; + DWORD getUsage() const; + unsigned int getTextureSerial() const; + virtual unsigned int getRenderTargetSerial(GLenum target) const = 0; + int getLodOffset() const; + + protected: + int mLodOffset; + + private: + DISALLOW_COPY_AND_ASSIGN(TextureStorage); + + const DWORD mD3DUsage; + const D3DPOOL mD3DPool; + + const unsigned int mTextureSerial; + static unsigned int issueTextureSerial(); + + static unsigned int mCurrentTextureSerial; +}; + +class Texture : public RefCountObject +{ + public: + explicit Texture(GLuint id); + + 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 setMaxAnisotropy(float textureMaxAnisotropy, float contextMaxAnisotropy); + bool setUsage(GLenum usage); + + GLenum getMinFilter() const; + GLenum getMagFilter() const; + GLenum getWrapS() const; + GLenum getWrapT() const; + float getMaxAnisotropy() const; + GLenum getUsage() const; + + virtual bool isSamplerComplete() const = 0; + + IDirect3DBaseTexture9 *getTexture(); + 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, Framebuffer *source) = 0; + + bool hasDirtyParameters() const; + bool hasDirtyImages() const; + void resetDirty(); + unsigned int getTextureSerial(); + unsigned int getRenderTargetSerial(GLenum target); + + bool isImmutable() const; + int getLodOffset(); + + 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: + 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) const; + GLint creationLevels(GLsizei size) const; + + virtual IDirect3DBaseTexture9 *getBaseTexture() const = 0; + virtual void createTexture() = 0; + virtual void updateTexture() = 0; + virtual void convertToRenderTarget() = 0; + virtual IDirect3DSurface9 *getRenderTarget(GLenum target) = 0; + + int levelCount(); + + static Blit *getBlitter(); + static bool copyToRenderTarget(IDirect3DSurface9 *dest, IDirect3DSurface9 *source, bool fromManaged); + + GLenum mMinFilter; + GLenum mMagFilter; + GLenum mWrapS; + GLenum mWrapT; + float mMaxAnisotropy; + bool mDirtyParameters; + GLenum mUsage; + + bool mDirtyImages; + + bool mImmutable; + + private: + DISALLOW_COPY_AND_ASSIGN(Texture); + + virtual TextureStorage *getStorage(bool renderTarget) = 0; +}; + +class TextureStorage2D : public TextureStorage +{ + public: + explicit TextureStorage2D(IDirect3DTexture9 *surfaceTexture); + TextureStorage2D(int levels, D3DFORMAT format, DWORD usage, int width, int height); + + virtual ~TextureStorage2D(); + + IDirect3DSurface9 *getSurfaceLevel(int level, bool dirty); + 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 +{ + public: + explicit Texture2D(GLuint id); + + ~Texture2D(); + + void addProxyRef(const Renderbuffer *proxy); + void releaseProxy(const Renderbuffer *proxy); + + virtual GLenum getTarget() const; + + GLsizei getWidth(GLint level) const; + GLsizei getHeight(GLint level) const; + GLenum getInternalFormat(GLint level) const; + D3DFORMAT getD3DFormat(GLint level) const; + bool isCompressed(GLint level) const; + bool isDepth(GLint level) 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 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); + + virtual bool isSamplerComplete() const; + virtual void bindTexImage(egl::Surface *surface); + virtual void releaseTexImage(); + + virtual void generateMipmaps(); + + virtual Renderbuffer *getRenderbuffer(GLenum target); + + protected: + friend class RenderbufferTexture2D; + virtual IDirect3DSurface9 *getRenderTarget(GLenum target); + virtual IDirect3DSurface9 *getDepthStencil(GLenum target); + + private: + DISALLOW_COPY_AND_ASSIGN(Texture2D); + + virtual IDirect3DBaseTexture9 *getBaseTexture() const; + virtual void createTexture(); + virtual void updateTexture(); + virtual void convertToRenderTarget(); + virtual TextureStorage *getStorage(bool renderTarget); + + bool isMipmapComplete() const; + + void redefineImage(GLint level, GLint internalformat, GLsizei width, GLsizei height); + void commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height); + + Image mImageArray[IMPLEMENTATION_MAX_TEXTURE_LEVELS]; + + TextureStorage2D *mTexStorage; + egl::Surface *mSurface; + + // 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, DWORD usage, int size); + + virtual ~TextureStorageCubeMap(); + + IDirect3DSurface9 *getCubeMapSurface(GLenum faceTarget, int level, bool dirty); + 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 +{ + public: + explicit TextureCubeMap(GLuint id); + + ~TextureCubeMap(); + + void addProxyRef(const Renderbuffer *proxy); + void releaseProxy(const Renderbuffer *proxy); + + virtual GLenum getTarget() const; + + GLsizei getWidth(GLenum target, GLint level) const; + GLsizei getHeight(GLenum target, GLint level) const; + GLenum getInternalFormat(GLenum target, GLint level) const; + D3DFORMAT getD3DFormat(GLenum target, GLint level) const; + bool isCompressed(GLenum target, GLint level) const; + + 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 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 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); + + virtual bool isSamplerComplete() const; + + virtual void generateMipmaps(); + + virtual Renderbuffer *getRenderbuffer(GLenum target); + + static unsigned int faceIndex(GLenum face); + + protected: + friend class RenderbufferTextureCubeMap; + virtual IDirect3DSurface9 *getRenderTarget(GLenum target); + + private: + DISALLOW_COPY_AND_ASSIGN(TextureCubeMap); + + virtual IDirect3DBaseTexture9 *getBaseTexture() const; + virtual void createTexture(); + virtual void updateTexture(); + virtual void convertToRenderTarget(); + virtual TextureStorage *getStorage(bool renderTarget); + + bool isCubeComplete() const; + bool isMipmapCubeComplete() const; + + 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, GLint internalformat, GLsizei width, GLsizei height); + + Image mImageArray[6][IMPLEMENTATION_MAX_TEXTURE_LEVELS]; + + TextureStorageCubeMap *mTexStorage; + + // 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_ diff --git a/src/3rdparty/angle/src/libGLESv2/TextureSSE2.cpp b/src/3rdparty/angle/src/libGLESv2/TextureSSE2.cpp new file mode 100644 index 0000000000..48ea6643bc --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/TextureSSE2.cpp @@ -0,0 +1,100 @@ +// +// 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. +// + +// TextureSSE2.cpp: Implements SSE2-based functions of gl::Image class. It's +// in a separated file for GCC, which can enable SSE usage only per-file, +// not for code blocks that use SSE2 explicitly. + +#include "libGLESv2/Texture.h" + +#include <intrin.h> + +namespace gl +{ + +void Image::loadRGBAUByteDataSSE2(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const +{ + const unsigned int *source = NULL; + unsigned int *dest = NULL; + __m128i brMask = _mm_set1_epi32(0x00ff00ff); + + 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 * outputPitch); + 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::loadAlphaDataSSE2(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const +{ + const unsigned char *source = NULL; + unsigned int *dest = NULL; + __m128i zeroWide = _mm_setzero_si128(); + + for (int y = 0; y < height; y++) + { + source = static_cast<const unsigned char*>(input) + y * inputPitch; + dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + y * outputPitch); + + int x; + // Make output writes aligned + for (x = 0; ((reinterpret_cast<intptr_t>(&dest[x]) & 0xF) != 0 && x < width); x++) + { + dest[x] = static_cast<unsigned int>(source[x]) << 24; + } + + for (; x + 7 < width; x += 8) + { + __m128i sourceData = _mm_loadl_epi64(reinterpret_cast<const __m128i*>(&source[x])); + // Interleave each byte to 16bit, make the lower byte to zero + sourceData = _mm_unpacklo_epi8(zeroWide, sourceData); + // Interleave each 16bit to 32bit, make the lower 16bit to zero + __m128i lo = _mm_unpacklo_epi16(zeroWide, sourceData); + __m128i hi = _mm_unpackhi_epi16(zeroWide, sourceData); + + _mm_store_si128(reinterpret_cast<__m128i*>(&dest[x]), lo); + _mm_store_si128(reinterpret_cast<__m128i*>(&dest[x + 4]), hi); + } + + // Handle the remainder + for (; x < width; x++) + { + dest[x] = static_cast<unsigned int>(source[x]) << 24; + } + } +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/VertexDataManager.cpp b/src/3rdparty/angle/src/libGLESv2/VertexDataManager.cpp new file mode 100644 index 0000000000..32c40182d3 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/VertexDataManager.cpp @@ -0,0 +1,783 @@ +// +// 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/ProgramBinary.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(); + ProgramBinary *programBinary = mContext->getCurrentProgramBinary(); + + for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++) + { + translated[attributeIndex].active = (programBinary->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<GLint, 16> { }; +template <> struct ConversionRule<GL_FIXED, false, D3DVT_FLOAT> : gl::FixedToFloat<GLint, 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/src/3rdparty/angle/src/libGLESv2/VertexDataManager.h b/src/3rdparty/angle/src/libGLESv2/VertexDataManager.h new file mode 100644 index 0000000000..857591ac29 --- /dev/null +++ b/src/3rdparty/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/src/3rdparty/angle/src/libGLESv2/libGLESv2.cpp b/src/3rdparty/angle/src/libGLESv2/libGLESv2.cpp new file mode 100644 index 0000000000..16d9c1775d --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/libGLESv2.cpp @@ -0,0 +1,7002 @@ +// +// 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. +// + +// libGLESv2.cpp: Implements the exported OpenGL ES 2.0 functions. + +#define GL_APICALL +#include <GLES2/gl2.h> +#include <GLES2/gl2ext.h> + +#include <exception> +#include <limits> + +#include "common/debug.h" +#include "common/version.h" + +#include "libGLESv2/main.h" +#include "libGLESv2/mathutil.h" +#include "libGLESv2/utilities.h" +#include "libGLESv2/Buffer.h" +#include "libGLESv2/Context.h" +#include "libGLESv2/Fence.h" +#include "libGLESv2/Framebuffer.h" +#include "libGLESv2/Program.h" +#include "libGLESv2/ProgramBinary.h" +#include "libGLESv2/Renderbuffer.h" +#include "libGLESv2/Shader.h" +#include "libGLESv2/Texture.h" +#include "libGLESv2/Query.h" + +bool validImageSize(GLint level, GLsizei width, GLsizei height) +{ + if (level < 0 || width < 0 || height < 0) + { + return false; + } + + if (gl::getContext() && gl::getContext()->supportsNonPower2Texture()) + { + return true; + } + + if (level == 0) + { + return true; + } + + if (gl::isPow2(width) && gl::isPow2(height)) + { + return true; + } + + return false; +} + +// Verify that format/type are one of the combinations from table 3.4. +bool checkTextureFormatType(GLenum format, GLenum type) +{ + // validate <format> by itself (used as secondary key below) + switch (format) + { + case GL_RGBA: + case GL_BGRA_EXT: + case GL_RGB: + case GL_ALPHA: + case GL_LUMINANCE: + case GL_LUMINANCE_ALPHA: + case GL_DEPTH_COMPONENT: + case GL_DEPTH_STENCIL_OES: + break; + default: + return error(GL_INVALID_ENUM, false); + } + + // invalid <type> -> sets INVALID_ENUM + // invalid <format>+<type> combination -> sets INVALID_OPERATION + switch (type) + { + case GL_UNSIGNED_BYTE: + switch (format) + { + case GL_RGBA: + case GL_BGRA_EXT: + case GL_RGB: + case GL_ALPHA: + case GL_LUMINANCE: + case GL_LUMINANCE_ALPHA: + return true; + default: + return error(GL_INVALID_OPERATION, false); + } + + case GL_FLOAT: + case GL_HALF_FLOAT_OES: + switch (format) + { + case GL_RGBA: + case GL_RGB: + case GL_ALPHA: + case GL_LUMINANCE: + case GL_LUMINANCE_ALPHA: + return true; + default: + return error(GL_INVALID_OPERATION, false); + } + + case GL_UNSIGNED_SHORT_4_4_4_4: + case GL_UNSIGNED_SHORT_5_5_5_1: + switch (format) + { + case GL_RGBA: + return true; + default: + return error(GL_INVALID_OPERATION, false); + } + + case GL_UNSIGNED_SHORT_5_6_5: + switch (format) + { + case GL_RGB: + return true; + default: + return error(GL_INVALID_OPERATION, false); + } + + case GL_UNSIGNED_SHORT: + case GL_UNSIGNED_INT: + switch (format) + { + case GL_DEPTH_COMPONENT: + return true; + default: + return error(GL_INVALID_OPERATION, false); + } + + case GL_UNSIGNED_INT_24_8_OES: + switch (format) + { + case GL_DEPTH_STENCIL_OES: + return true; + default: + return error(GL_INVALID_OPERATION, false); + } + + default: + return error(GL_INVALID_ENUM, false); + } +} + +bool validateSubImageParams2D(bool compressed, GLsizei width, GLsizei height, + GLint xoffset, GLint yoffset, GLint level, GLenum format, GLenum type, + gl::Texture2D *texture) +{ + if (!texture) + { + return error(GL_INVALID_OPERATION, false); + } + + if (compressed != texture->isCompressed(level)) + { + return error(GL_INVALID_OPERATION, false); + } + + if (format != GL_NONE) + { + GLenum internalformat = gl::ConvertSizedInternalFormat(format, type); + if (internalformat != texture->getInternalFormat(level)) + { + 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_OPERATION, false); + } + } + + if (xoffset + width > texture->getWidth(level) || + yoffset + height > texture->getHeight(level)) + { + return error(GL_INVALID_VALUE, false); + } + + return true; +} + +bool validateSubImageParamsCube(bool compressed, GLsizei width, GLsizei height, + GLint xoffset, GLint yoffset, GLenum target, GLint level, GLenum format, GLenum type, + gl::TextureCubeMap *texture) +{ + if (!texture) + { + return error(GL_INVALID_OPERATION, false); + } + + if (compressed != texture->isCompressed(target, level)) + { + return error(GL_INVALID_OPERATION, false); + } + + if (format != GL_NONE) + { + GLenum internalformat = gl::ConvertSizedInternalFormat(format, type); + if (internalformat != texture->getInternalFormat(target, level)) + { + return error(GL_INVALID_OPERATION, false); + } + } + + if (compressed) + { + if ((width % 4 != 0 && width != texture->getWidth(target, 0)) || + (height % 4 != 0 && height != texture->getHeight(target, 0))) + { + return error(GL_INVALID_OPERATION, false); + } + } + + if (xoffset + width > texture->getWidth(target, level) || + yoffset + height > texture->getHeight(target, 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; + 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); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glAttachShader(GLuint program, GLuint shader) +{ + EVENT("(GLuint program = %d, GLuint shader = %d)", program, shader); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::Program *programObject = context->getProgram(program); + gl::Shader *shaderObject = context->getShader(shader); + + if (!programObject) + { + if (context->getShader(program)) + { + return error(GL_INVALID_OPERATION); + } + else + { + return error(GL_INVALID_VALUE); + } + } + + if (!shaderObject) + { + if (context->getProgram(shader)) + { + return error(GL_INVALID_OPERATION); + } + else + { + return error(GL_INVALID_VALUE); + } + } + + if (!programObject->attachShader(shaderObject)) + { + return error(GL_INVALID_OPERATION); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +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) +{ + EVENT("(GLuint program = %d, GLuint index = %d, const GLchar* name = 0x%0.8p)", program, index, name); + + try + { + if (index >= gl::MAX_VERTEX_ATTRIBS) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::Program *programObject = context->getProgram(program); + + if (!programObject) + { + if (context->getShader(program)) + { + return error(GL_INVALID_OPERATION); + } + else + { + return error(GL_INVALID_VALUE); + } + } + + if (strncmp(name, "gl_", 3) == 0) + { + return error(GL_INVALID_OPERATION); + } + + programObject->bindAttributeLocation(index, name); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glBindBuffer(GLenum target, GLuint buffer) +{ + EVENT("(GLenum target = 0x%X, GLuint buffer = %d)", target, buffer); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + switch (target) + { + case GL_ARRAY_BUFFER: + context->bindArrayBuffer(buffer); + return; + case GL_ELEMENT_ARRAY_BUFFER: + context->bindElementArrayBuffer(buffer); + return; + default: + return error(GL_INVALID_ENUM); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glBindFramebuffer(GLenum target, GLuint framebuffer) +{ + EVENT("(GLenum target = 0x%X, GLuint framebuffer = %d)", target, framebuffer); + + try + { + if (target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER_ANGLE && target != GL_READ_FRAMEBUFFER_ANGLE) + { + return error(GL_INVALID_ENUM); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (target == GL_READ_FRAMEBUFFER_ANGLE || target == GL_FRAMEBUFFER) + { + context->bindReadFramebuffer(framebuffer); + } + + if (target == GL_DRAW_FRAMEBUFFER_ANGLE || target == GL_FRAMEBUFFER) + { + context->bindDrawFramebuffer(framebuffer); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glBindRenderbuffer(GLenum target, GLuint renderbuffer) +{ + EVENT("(GLenum target = 0x%X, GLuint renderbuffer = %d)", target, renderbuffer); + + try + { + if (target != GL_RENDERBUFFER) + { + return error(GL_INVALID_ENUM); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + context->bindRenderbuffer(renderbuffer); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glBindTexture(GLenum target, GLuint texture) +{ + EVENT("(GLenum target = 0x%X, GLuint texture = %d)", target, texture); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::Texture *textureObject = context->getTexture(texture); + + if (textureObject && textureObject->getTarget() != target && texture != 0) + { + return error(GL_INVALID_OPERATION); + } + + switch (target) + { + case GL_TEXTURE_2D: + context->bindTexture2D(texture); + return; + case GL_TEXTURE_CUBE_MAP: + context->bindTextureCubeMap(texture); + return; + default: + return error(GL_INVALID_ENUM); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glBlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) +{ + EVENT("(GLclampf red = %f, GLclampf green = %f, GLclampf blue = %f, GLclampf alpha = %f)", + red, green, blue, alpha); + + try + { + gl::Context* context = gl::getNonLostContext(); + + if (context) + { + context->setBlendColor(gl::clamp01(red), gl::clamp01(green), gl::clamp01(blue), gl::clamp01(alpha)); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glBlendEquation(GLenum mode) +{ + glBlendEquationSeparate(mode, mode); +} + +void __stdcall glBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha) +{ + EVENT("(GLenum modeRGB = 0x%X, GLenum modeAlpha = 0x%X)", modeRGB, modeAlpha); + + try + { + switch (modeRGB) + { + case GL_FUNC_ADD: + case GL_FUNC_SUBTRACT: + case GL_FUNC_REVERSE_SUBTRACT: + break; + default: + return error(GL_INVALID_ENUM); + } + + switch (modeAlpha) + { + case GL_FUNC_ADD: + case GL_FUNC_SUBTRACT: + case GL_FUNC_REVERSE_SUBTRACT: + break; + default: + return error(GL_INVALID_ENUM); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + context->setBlendEquation(modeRGB, modeAlpha); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glBlendFunc(GLenum sfactor, GLenum dfactor) +{ + glBlendFuncSeparate(sfactor, dfactor, sfactor, dfactor); +} + +void __stdcall glBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) +{ + EVENT("(GLenum srcRGB = 0x%X, GLenum dstRGB = 0x%X, GLenum srcAlpha = 0x%X, GLenum dstAlpha = 0x%X)", + srcRGB, dstRGB, srcAlpha, dstAlpha); + + try + { + switch (srcRGB) + { + case GL_ZERO: + case GL_ONE: + case GL_SRC_COLOR: + case GL_ONE_MINUS_SRC_COLOR: + case GL_DST_COLOR: + case GL_ONE_MINUS_DST_COLOR: + case GL_SRC_ALPHA: + case GL_ONE_MINUS_SRC_ALPHA: + case GL_DST_ALPHA: + case GL_ONE_MINUS_DST_ALPHA: + case GL_CONSTANT_COLOR: + case GL_ONE_MINUS_CONSTANT_COLOR: + case GL_CONSTANT_ALPHA: + case GL_ONE_MINUS_CONSTANT_ALPHA: + case GL_SRC_ALPHA_SATURATE: + break; + default: + return error(GL_INVALID_ENUM); + } + + switch (dstRGB) + { + case GL_ZERO: + case GL_ONE: + case GL_SRC_COLOR: + case GL_ONE_MINUS_SRC_COLOR: + case GL_DST_COLOR: + case GL_ONE_MINUS_DST_COLOR: + case GL_SRC_ALPHA: + case GL_ONE_MINUS_SRC_ALPHA: + case GL_DST_ALPHA: + case GL_ONE_MINUS_DST_ALPHA: + case GL_CONSTANT_COLOR: + case GL_ONE_MINUS_CONSTANT_COLOR: + case GL_CONSTANT_ALPHA: + case GL_ONE_MINUS_CONSTANT_ALPHA: + break; + default: + return error(GL_INVALID_ENUM); + } + + switch (srcAlpha) + { + case GL_ZERO: + case GL_ONE: + case GL_SRC_COLOR: + case GL_ONE_MINUS_SRC_COLOR: + case GL_DST_COLOR: + case GL_ONE_MINUS_DST_COLOR: + case GL_SRC_ALPHA: + case GL_ONE_MINUS_SRC_ALPHA: + case GL_DST_ALPHA: + case GL_ONE_MINUS_DST_ALPHA: + case GL_CONSTANT_COLOR: + case GL_ONE_MINUS_CONSTANT_COLOR: + case GL_CONSTANT_ALPHA: + case GL_ONE_MINUS_CONSTANT_ALPHA: + case GL_SRC_ALPHA_SATURATE: + break; + default: + return error(GL_INVALID_ENUM); + } + + switch (dstAlpha) + { + case GL_ZERO: + case GL_ONE: + case GL_SRC_COLOR: + case GL_ONE_MINUS_SRC_COLOR: + case GL_DST_COLOR: + case GL_ONE_MINUS_DST_COLOR: + case GL_SRC_ALPHA: + case GL_ONE_MINUS_SRC_ALPHA: + case GL_DST_ALPHA: + case GL_ONE_MINUS_DST_ALPHA: + case GL_CONSTANT_COLOR: + case GL_ONE_MINUS_CONSTANT_COLOR: + case GL_CONSTANT_ALPHA: + case GL_ONE_MINUS_CONSTANT_ALPHA: + break; + default: + return error(GL_INVALID_ENUM); + } + + bool constantColorUsed = (srcRGB == GL_CONSTANT_COLOR || srcRGB == GL_ONE_MINUS_CONSTANT_COLOR || + dstRGB == GL_CONSTANT_COLOR || dstRGB == GL_ONE_MINUS_CONSTANT_COLOR); + + bool constantAlphaUsed = (srcRGB == GL_CONSTANT_ALPHA || srcRGB == GL_ONE_MINUS_CONSTANT_ALPHA || + dstRGB == GL_CONSTANT_ALPHA || dstRGB == GL_ONE_MINUS_CONSTANT_ALPHA); + + if (constantColorUsed && constantAlphaUsed) + { + ERR("Simultaneous use of GL_CONSTANT_ALPHA/GL_ONE_MINUS_CONSTANT_ALPHA and GL_CONSTANT_COLOR/GL_ONE_MINUS_CONSTANT_COLOR invalid under WebGL"); + return error(GL_INVALID_OPERATION); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + context->setBlendFactors(srcRGB, dstRGB, srcAlpha, dstAlpha); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage) +{ + EVENT("(GLenum target = 0x%X, GLsizeiptr size = %d, const GLvoid* data = 0x%0.8p, GLenum usage = %d)", + target, size, data, usage); + + try + { + if (size < 0) + { + return error(GL_INVALID_VALUE); + } + + switch (usage) + { + case GL_STREAM_DRAW: + case GL_STATIC_DRAW: + case GL_DYNAMIC_DRAW: + break; + default: + return error(GL_INVALID_ENUM); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::Buffer *buffer; + + switch (target) + { + case GL_ARRAY_BUFFER: + buffer = context->getArrayBuffer(); + break; + case GL_ELEMENT_ARRAY_BUFFER: + buffer = context->getElementArrayBuffer(); + break; + default: + return error(GL_INVALID_ENUM); + } + + if (!buffer) + { + return error(GL_INVALID_OPERATION); + } + + buffer->bufferData(data, size, usage); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data) +{ + EVENT("(GLenum target = 0x%X, GLintptr offset = %d, GLsizeiptr size = %d, const GLvoid* data = 0x%0.8p)", + target, offset, size, data); + + try + { + if (size < 0 || offset < 0) + { + return error(GL_INVALID_VALUE); + } + + if (data == NULL) + { + return; + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::Buffer *buffer; + + switch (target) + { + case GL_ARRAY_BUFFER: + buffer = context->getArrayBuffer(); + break; + case GL_ELEMENT_ARRAY_BUFFER: + buffer = context->getElementArrayBuffer(); + break; + default: + return error(GL_INVALID_ENUM); + } + + if (!buffer) + { + return error(GL_INVALID_OPERATION); + } + + if ((size_t)size + offset > buffer->size()) + { + return error(GL_INVALID_VALUE); + } + + buffer->bufferSubData(data, size, offset); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +GLenum __stdcall glCheckFramebufferStatus(GLenum target) +{ + EVENT("(GLenum target = 0x%X)", target); + + try + { + if (target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER_ANGLE && target != GL_READ_FRAMEBUFFER_ANGLE) + { + return error(GL_INVALID_ENUM, 0); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::Framebuffer *framebuffer = NULL; + if (target == GL_READ_FRAMEBUFFER_ANGLE) + { + framebuffer = context->getReadFramebuffer(); + } + else + { + framebuffer = context->getDrawFramebuffer(); + } + + return framebuffer->completeness(); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY, 0); + } + + return 0; +} + +void __stdcall glClear(GLbitfield mask) +{ + EVENT("(GLbitfield mask = %X)", mask); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + context->clear(mask); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) +{ + EVENT("(GLclampf red = %f, GLclampf green = %f, GLclampf blue = %f, GLclampf alpha = %f)", + red, green, blue, alpha); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + context->setClearColor(red, green, blue, alpha); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glClearDepthf(GLclampf depth) +{ + EVENT("(GLclampf depth = %f)", depth); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + context->setClearDepth(depth); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glClearStencil(GLint s) +{ + EVENT("(GLint s = %d)", s); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + context->setClearStencil(s); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) +{ + EVENT("(GLboolean red = %d, GLboolean green = %d, GLboolean blue = %d, GLboolean alpha = %d)", + red, green, blue, alpha); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + context->setColorMask(red == GL_TRUE, green == GL_TRUE, blue == GL_TRUE, alpha == GL_TRUE); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glCompileShader(GLuint shader) +{ + EVENT("(GLuint shader = %d)", shader); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::Shader *shaderObject = context->getShader(shader); + + if (!shaderObject) + { + if (context->getProgram(shader)) + { + return error(GL_INVALID_OPERATION); + } + else + { + return error(GL_INVALID_VALUE); + } + } + + shaderObject->compile(); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, + GLint border, GLsizei imageSize, const GLvoid* data) +{ + 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 (!validImageSize(level, width, height) || border != 0 || imageSize < 0) + { + return error(GL_INVALID_VALUE); + } + + switch (internalformat) + { + 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); + } + + if (border != 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (level > context->getMaximumTextureLevel()) + { + return error(GL_INVALID_VALUE); + } + + switch (target) + { + case GL_TEXTURE_2D: + if (width > (context->getMaximumTextureDimension() >> level) || + height > (context->getMaximumTextureDimension() >> level)) + { + return error(GL_INVALID_VALUE); + } + break; + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + if (width != height) + { + return error(GL_INVALID_VALUE); + } + + if (width > (context->getMaximumCubeTextureDimension() >> level) || + height > (context->getMaximumCubeTextureDimension() >> level)) + { + return error(GL_INVALID_VALUE); + } + break; + default: + return error(GL_INVALID_ENUM); + } + + 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)) + { + return error(GL_INVALID_VALUE); + } + + if (target == GL_TEXTURE_2D) + { + gl::Texture2D *texture = context->getTexture2D(); + + if (!texture) + { + return error(GL_INVALID_OPERATION); + } + + if (texture->isImmutable()) + { + return error(GL_INVALID_OPERATION); + } + + texture->setCompressedImage(level, internalformat, width, height, imageSize, data); + } + else + { + gl::TextureCubeMap *texture = context->getTextureCubeMap(); + + if (!texture) + { + return error(GL_INVALID_OPERATION); + } + + if (texture->isImmutable()) + { + return error(GL_INVALID_OPERATION); + } + + switch (target) + { + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + texture->setCompressedImage(target, level, internalformat, width, height, imageSize, data); + break; + default: UNREACHABLE(); + } + } + } + + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + GLenum format, GLsizei imageSize, const GLvoid* data) +{ + 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::IsInternalTextureTarget(target)) + { + return error(GL_INVALID_ENUM); + } + + if (xoffset < 0 || yoffset < 0 || !validImageSize(level, width, height) || imageSize < 0) + { + return error(GL_INVALID_VALUE); + } + + switch (format) + { + 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); + } + + if (width == 0 || height == 0 || data == NULL) + { + return; + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (level > context->getMaximumTextureLevel()) + { + return error(GL_INVALID_VALUE); + } + + 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)) + { + return error(GL_INVALID_VALUE); + } + + 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 DXT textures are supported. + } + + if (target == GL_TEXTURE_2D) + { + gl::Texture2D *texture = context->getTexture2D(); + if (validateSubImageParams2D(true, width, height, xoffset, yoffset, level, format, GL_NONE, texture)) + { + texture->subImageCompressed(level, xoffset, yoffset, width, height, format, imageSize, data); + } + } + else if (gl::IsCubemapTextureTarget(target)) + { + gl::TextureCubeMap *texture = context->getTextureCubeMap(); + if (validateSubImageParamsCube(true, width, height, xoffset, yoffset, target, level, format, GL_NONE, texture)) + { + texture->subImageCompressed(target, level, xoffset, yoffset, width, height, format, imageSize, data); + } + } + else + { + UNREACHABLE(); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) +{ + 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 (!validImageSize(level, width, height)) + { + return error(GL_INVALID_VALUE); + } + + if (border != 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (level > context->getMaximumTextureLevel()) + { + return error(GL_INVALID_VALUE); + } + + switch (target) + { + case GL_TEXTURE_2D: + if (width > (context->getMaximumTextureDimension() >> level) || + height > (context->getMaximumTextureDimension() >> level)) + { + return error(GL_INVALID_VALUE); + } + break; + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + if (width != height) + { + return error(GL_INVALID_VALUE); + } + + if (width > (context->getMaximumCubeTextureDimension() >> level) || + height > (context->getMaximumCubeTextureDimension() >> level)) + { + return error(GL_INVALID_VALUE); + } + break; + default: + return error(GL_INVALID_ENUM); + } + + gl::Framebuffer *framebuffer = context->getReadFramebuffer(); + + if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE) + { + return error(GL_INVALID_FRAMEBUFFER_OPERATION); + } + + if (context->getReadFramebufferHandle() != 0 && framebuffer->getColorbuffer()->getSamples() != 0) + { + return error(GL_INVALID_OPERATION); + } + + gl::Renderbuffer *source = framebuffer->getColorbuffer(); + GLenum colorbufferFormat = source->getInternalFormat(); + + // [OpenGL ES 2.0.24] table 3.9 + switch (internalformat) + { + case GL_ALPHA: + if (colorbufferFormat != GL_ALPHA8_EXT && + colorbufferFormat != GL_RGBA4 && + colorbufferFormat != GL_RGB5_A1 && + colorbufferFormat != GL_RGBA8_OES) + { + return error(GL_INVALID_OPERATION); + } + break; + case GL_LUMINANCE: + case GL_RGB: + if (colorbufferFormat != GL_RGB565 && + colorbufferFormat != GL_RGB8_OES && + colorbufferFormat != GL_RGBA4 && + colorbufferFormat != GL_RGB5_A1 && + colorbufferFormat != GL_RGBA8_OES) + { + return error(GL_INVALID_OPERATION); + } + break; + case GL_LUMINANCE_ALPHA: + case GL_RGBA: + if (colorbufferFormat != GL_RGBA4 && + colorbufferFormat != GL_RGB5_A1 && + colorbufferFormat != GL_RGBA8_OES) + { + return error(GL_INVALID_OPERATION); + } + break; + 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); + } + else + { + return error(GL_INVALID_ENUM); + } + break; + case GL_DEPTH_COMPONENT: + case GL_DEPTH_COMPONENT16: + case GL_DEPTH_COMPONENT32_OES: + case GL_DEPTH_STENCIL_OES: + case GL_DEPTH24_STENCIL8_OES: + if (context->supportsDepthTextures()) + { + return error(GL_INVALID_OPERATION); + } + else + { + return error(GL_INVALID_ENUM); + } + default: + return error(GL_INVALID_ENUM); + } + + if (target == GL_TEXTURE_2D) + { + gl::Texture2D *texture = context->getTexture2D(); + + if (!texture) + { + return error(GL_INVALID_OPERATION); + } + + if (texture->isImmutable()) + { + return error(GL_INVALID_OPERATION); + } + + texture->copyImage(level, internalformat, x, y, width, height, framebuffer); + } + else if (gl::IsCubemapTextureTarget(target)) + { + gl::TextureCubeMap *texture = context->getTextureCubeMap(); + + if (!texture) + { + return error(GL_INVALID_OPERATION); + } + + if (texture->isImmutable()) + { + return error(GL_INVALID_OPERATION); + } + + texture->copyImage(target, level, internalformat, x, y, width, height, framebuffer); + } + else UNREACHABLE(); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) +{ + 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::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 (width == 0 || height == 0) + { + return; + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (level > context->getMaximumTextureLevel()) + { + return error(GL_INVALID_VALUE); + } + + gl::Framebuffer *framebuffer = context->getReadFramebuffer(); + + if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE) + { + return error(GL_INVALID_FRAMEBUFFER_OPERATION); + } + + if (context->getReadFramebufferHandle() != 0 && framebuffer->getColorbuffer()->getSamples() != 0) + { + return error(GL_INVALID_OPERATION); + } + + gl::Renderbuffer *source = framebuffer->getColorbuffer(); + GLenum colorbufferFormat = source->getInternalFormat(); + gl::Texture *texture = NULL; + GLenum textureFormat = GL_RGBA; + + if (target == GL_TEXTURE_2D) + { + gl::Texture2D *tex2d = context->getTexture2D(); + + if (!validateSubImageParams2D(false, width, height, xoffset, yoffset, level, GL_NONE, GL_NONE, tex2d)) + { + return; // error already registered by validateSubImageParams + } + textureFormat = gl::ExtractFormat(tex2d->getInternalFormat(level)); + texture = tex2d; + } + else if (gl::IsCubemapTextureTarget(target)) + { + gl::TextureCubeMap *texcube = context->getTextureCubeMap(); + + if (!validateSubImageParamsCube(false, width, height, xoffset, yoffset, target, level, GL_NONE, GL_NONE, texcube)) + { + return; // error already registered by validateSubImageParams + } + textureFormat = gl::ExtractFormat(texcube->getInternalFormat(target, level)); + texture = texcube; + } + else UNREACHABLE(); + + // [OpenGL ES 2.0.24] table 3.9 + switch (textureFormat) + { + case GL_ALPHA: + if (colorbufferFormat != GL_ALPHA8_EXT && + colorbufferFormat != GL_RGBA4 && + colorbufferFormat != GL_RGB5_A1 && + colorbufferFormat != GL_RGBA8_OES) + { + return error(GL_INVALID_OPERATION); + } + break; + case GL_LUMINANCE: + case GL_RGB: + if (colorbufferFormat != GL_RGB565 && + colorbufferFormat != GL_RGB8_OES && + colorbufferFormat != GL_RGBA4 && + colorbufferFormat != GL_RGB5_A1 && + colorbufferFormat != GL_RGBA8_OES) + { + return error(GL_INVALID_OPERATION); + } + break; + case GL_LUMINANCE_ALPHA: + case GL_RGBA: + if (colorbufferFormat != GL_RGBA4 && + colorbufferFormat != GL_RGB5_A1 && + colorbufferFormat != GL_RGBA8_OES) + { + return error(GL_INVALID_OPERATION); + } + 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); + case GL_DEPTH_COMPONENT: + case GL_DEPTH_STENCIL_OES: + return error(GL_INVALID_OPERATION); + default: + return error(GL_INVALID_OPERATION); + } + + texture->copySubImage(target, level, xoffset, yoffset, x, y, width, height, framebuffer); + } + } + + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +GLuint __stdcall glCreateProgram(void) +{ + EVENT("()"); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + return context->createProgram(); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY, 0); + } + + return 0; +} + +GLuint __stdcall glCreateShader(GLenum type) +{ + EVENT("(GLenum type = 0x%X)", type); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + switch (type) + { + case GL_FRAGMENT_SHADER: + case GL_VERTEX_SHADER: + return context->createShader(type); + default: + return error(GL_INVALID_ENUM, 0); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY, 0); + } + + return 0; +} + +void __stdcall glCullFace(GLenum mode) +{ + EVENT("(GLenum mode = 0x%X)", mode); + + try + { + switch (mode) + { + case GL_FRONT: + case GL_BACK: + case GL_FRONT_AND_BACK: + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + context->setCullMode(mode); + } + } + break; + default: + return error(GL_INVALID_ENUM); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glDeleteBuffers(GLsizei n, const GLuint* buffers) +{ + EVENT("(GLsizei n = %d, const GLuint* buffers = 0x%0.8p)", n, buffers); + + try + { + if (n < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + for (int i = 0; i < n; i++) + { + context->deleteBuffer(buffers[i]); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glDeleteFencesNV(GLsizei n, const GLuint* fences) +{ + EVENT("(GLsizei n = %d, const GLuint* fences = 0x%0.8p)", n, fences); + + try + { + if (n < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + for (int i = 0; i < n; i++) + { + context->deleteFence(fences[i]); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glDeleteFramebuffers(GLsizei n, const GLuint* framebuffers) +{ + EVENT("(GLsizei n = %d, const GLuint* framebuffers = 0x%0.8p)", n, framebuffers); + + try + { + if (n < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + for (int i = 0; i < n; i++) + { + if (framebuffers[i] != 0) + { + context->deleteFramebuffer(framebuffers[i]); + } + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glDeleteProgram(GLuint program) +{ + EVENT("(GLuint program = %d)", program); + + try + { + if (program == 0) + { + return; + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (!context->getProgram(program)) + { + if(context->getShader(program)) + { + return error(GL_INVALID_OPERATION); + } + else + { + return error(GL_INVALID_VALUE); + } + } + + context->deleteProgram(program); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +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) +{ + EVENT("(GLsizei n = %d, const GLuint* renderbuffers = 0x%0.8p)", n, renderbuffers); + + try + { + if (n < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + for (int i = 0; i < n; i++) + { + context->deleteRenderbuffer(renderbuffers[i]); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glDeleteShader(GLuint shader) +{ + EVENT("(GLuint shader = %d)", shader); + + try + { + if (shader == 0) + { + return; + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (!context->getShader(shader)) + { + if(context->getProgram(shader)) + { + return error(GL_INVALID_OPERATION); + } + else + { + return error(GL_INVALID_VALUE); + } + } + + context->deleteShader(shader); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glDeleteTextures(GLsizei n, const GLuint* textures) +{ + EVENT("(GLsizei n = %d, const GLuint* textures = 0x%0.8p)", n, textures); + + try + { + if (n < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + for (int i = 0; i < n; i++) + { + if (textures[i] != 0) + { + context->deleteTexture(textures[i]); + } + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glDepthFunc(GLenum func) +{ + EVENT("(GLenum func = 0x%X)", func); + + try + { + switch (func) + { + case GL_NEVER: + case GL_ALWAYS: + case GL_LESS: + case GL_LEQUAL: + case GL_EQUAL: + case GL_GREATER: + case GL_GEQUAL: + case GL_NOTEQUAL: + break; + default: + return error(GL_INVALID_ENUM); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + context->setDepthFunc(func); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glDepthMask(GLboolean flag) +{ + EVENT("(GLboolean flag = %d)", flag); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + context->setDepthMask(flag != GL_FALSE); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glDepthRangef(GLclampf zNear, GLclampf zFar) +{ + EVENT("(GLclampf zNear = %f, GLclampf zFar = %f)", zNear, zFar); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + context->setDepthRange(zNear, zFar); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glDetachShader(GLuint program, GLuint shader) +{ + EVENT("(GLuint program = %d, GLuint shader = %d)", program, shader); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + + gl::Program *programObject = context->getProgram(program); + gl::Shader *shaderObject = context->getShader(shader); + + if (!programObject) + { + gl::Shader *shaderByProgramHandle; + shaderByProgramHandle = context->getShader(program); + if (!shaderByProgramHandle) + { + return error(GL_INVALID_VALUE); + } + else + { + return error(GL_INVALID_OPERATION); + } + } + + if (!shaderObject) + { + gl::Program *programByShaderHandle = context->getProgram(shader); + if (!programByShaderHandle) + { + return error(GL_INVALID_VALUE); + } + else + { + return error(GL_INVALID_OPERATION); + } + } + + if (!programObject->detachShader(shaderObject)) + { + return error(GL_INVALID_OPERATION); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glDisable(GLenum cap) +{ + EVENT("(GLenum cap = 0x%X)", cap); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + switch (cap) + { + case GL_CULL_FACE: context->setCullFace(false); break; + case GL_POLYGON_OFFSET_FILL: context->setPolygonOffsetFill(false); break; + case GL_SAMPLE_ALPHA_TO_COVERAGE: context->setSampleAlphaToCoverage(false); break; + case GL_SAMPLE_COVERAGE: context->setSampleCoverage(false); break; + case GL_SCISSOR_TEST: context->setScissorTest(false); break; + case GL_STENCIL_TEST: context->setStencilTest(false); break; + case GL_DEPTH_TEST: context->setDepthTest(false); break; + case GL_BLEND: context->setBlend(false); break; + case GL_DITHER: context->setDither(false); break; + default: + return error(GL_INVALID_ENUM); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glDisableVertexAttribArray(GLuint index) +{ + EVENT("(GLuint index = %d)", index); + + try + { + if (index >= gl::MAX_VERTEX_ATTRIBS) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + context->setEnableVertexAttribArray(index, false); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glDrawArrays(GLenum mode, GLint first, GLsizei count) +{ + EVENT("(GLenum mode = 0x%X, GLint first = %d, GLsizei count = %d)", mode, first, count); + + try + { + if (count < 0 || first < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + 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&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices) +{ + EVENT("(GLenum mode = 0x%X, GLsizei count = %d, GLenum type = 0x%X, const GLvoid* indices = 0x%0.8p)", + mode, count, type, indices); + + try + { + if (count < 0) + { + return error(GL_INVALID_VALUE); + } + + 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, 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&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glEnable(GLenum cap) +{ + EVENT("(GLenum cap = 0x%X)", cap); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + switch (cap) + { + case GL_CULL_FACE: context->setCullFace(true); break; + case GL_POLYGON_OFFSET_FILL: context->setPolygonOffsetFill(true); break; + case GL_SAMPLE_ALPHA_TO_COVERAGE: context->setSampleAlphaToCoverage(true); break; + case GL_SAMPLE_COVERAGE: context->setSampleCoverage(true); break; + case GL_SCISSOR_TEST: context->setScissorTest(true); break; + case GL_STENCIL_TEST: context->setStencilTest(true); break; + case GL_DEPTH_TEST: context->setDepthTest(true); break; + case GL_BLEND: context->setBlend(true); break; + case GL_DITHER: context->setDither(true); break; + default: + return error(GL_INVALID_ENUM); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glEnableVertexAttribArray(GLuint index) +{ + EVENT("(GLuint index = %d)", index); + + try + { + if (index >= gl::MAX_VERTEX_ATTRIBS) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + context->setEnableVertexAttribArray(index, true); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +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) +{ + EVENT("(GLuint fence = %d)", fence); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::Fence* fenceObject = context->getFence(fence); + + if (fenceObject == NULL) + { + return error(GL_INVALID_OPERATION); + } + + fenceObject->finishFence(); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glFinish(void) +{ + EVENT("()"); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + context->sync(true); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glFlush(void) +{ + EVENT("()"); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + context->sync(false); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) +{ + 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 && renderbuffer != 0)) + { + return error(GL_INVALID_ENUM); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::Framebuffer *framebuffer = NULL; + GLuint framebufferHandle = 0; + if (target == GL_READ_FRAMEBUFFER_ANGLE) + { + framebuffer = context->getReadFramebuffer(); + framebufferHandle = context->getReadFramebufferHandle(); + } + else + { + framebuffer = context->getDrawFramebuffer(); + framebufferHandle = context->getDrawFramebufferHandle(); + } + + if (!framebuffer || (framebufferHandle == 0 && renderbuffer != 0)) + { + return error(GL_INVALID_OPERATION); + } + + switch (attachment) + { + case GL_COLOR_ATTACHMENT0: + framebuffer->setColorbuffer(GL_RENDERBUFFER, renderbuffer); + break; + case GL_DEPTH_ATTACHMENT: + framebuffer->setDepthbuffer(GL_RENDERBUFFER, renderbuffer); + break; + case GL_STENCIL_ATTACHMENT: + framebuffer->setStencilbuffer(GL_RENDERBUFFER, renderbuffer); + break; + default: + return error(GL_INVALID_ENUM); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) +{ + 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 + { + if (target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER_ANGLE && target != GL_READ_FRAMEBUFFER_ANGLE) + { + return error(GL_INVALID_ENUM); + } + + switch (attachment) + { + case GL_COLOR_ATTACHMENT0: + case GL_DEPTH_ATTACHMENT: + case GL_STENCIL_ATTACHMENT: + break; + default: + return error(GL_INVALID_ENUM); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (texture == 0) + { + textarget = GL_NONE; + } + else + { + gl::Texture *tex = context->getTexture(texture); + + if (tex == NULL) + { + return error(GL_INVALID_OPERATION); + } + + switch (textarget) + { + case GL_TEXTURE_2D: + { + if (tex->getTarget() != GL_TEXTURE_2D) + { + return error(GL_INVALID_OPERATION); + } + gl::Texture2D *tex2d = static_cast<gl::Texture2D *>(tex); + if (tex2d->isCompressed(0)) + { + return error(GL_INVALID_OPERATION); + } + break; + } + + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + { + if (tex->getTarget() != GL_TEXTURE_CUBE_MAP) + { + return error(GL_INVALID_OPERATION); + } + gl::TextureCubeMap *texcube = static_cast<gl::TextureCubeMap *>(tex); + if (texcube->isCompressed(textarget, level)) + { + return error(GL_INVALID_OPERATION); + } + break; + } + + default: + return error(GL_INVALID_ENUM); + } + + if (level != 0) + { + return error(GL_INVALID_VALUE); + } + } + + gl::Framebuffer *framebuffer = NULL; + GLuint framebufferHandle = 0; + if (target == GL_READ_FRAMEBUFFER_ANGLE) + { + framebuffer = context->getReadFramebuffer(); + framebufferHandle = context->getReadFramebufferHandle(); + } + else + { + framebuffer = context->getDrawFramebuffer(); + framebufferHandle = context->getDrawFramebufferHandle(); + } + + if (framebufferHandle == 0 || !framebuffer) + { + return error(GL_INVALID_OPERATION); + } + + switch (attachment) + { + case GL_COLOR_ATTACHMENT0: framebuffer->setColorbuffer(textarget, texture); break; + case GL_DEPTH_ATTACHMENT: framebuffer->setDepthbuffer(textarget, texture); break; + case GL_STENCIL_ATTACHMENT: framebuffer->setStencilbuffer(textarget, texture); break; + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glFrontFace(GLenum mode) +{ + EVENT("(GLenum mode = 0x%X)", mode); + + try + { + switch (mode) + { + case GL_CW: + case GL_CCW: + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + context->setFrontFace(mode); + } + } + break; + default: + return error(GL_INVALID_ENUM); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGenBuffers(GLsizei n, GLuint* buffers) +{ + EVENT("(GLsizei n = %d, GLuint* buffers = 0x%0.8p)", n, buffers); + + try + { + if (n < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + for (int i = 0; i < n; i++) + { + buffers[i] = context->createBuffer(); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGenerateMipmap(GLenum target) +{ + EVENT("(GLenum target = 0x%X)", target); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + switch (target) + { + case GL_TEXTURE_2D: + { + gl::Texture2D *tex2d = context->getTexture2D(); + + if (tex2d->isCompressed(0)) + { + return error(GL_INVALID_OPERATION); + } + if (tex2d->isDepth(0)) + { + return error(GL_INVALID_OPERATION); + } + + tex2d->generateMipmaps(); + break; + } + + case GL_TEXTURE_CUBE_MAP: + { + gl::TextureCubeMap *texcube = context->getTextureCubeMap(); + + if (texcube->isCompressed(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0)) + { + return error(GL_INVALID_OPERATION); + } + + texcube->generateMipmaps(); + break; + } + + default: + return error(GL_INVALID_ENUM); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGenFencesNV(GLsizei n, GLuint* fences) +{ + EVENT("(GLsizei n = %d, GLuint* fences = 0x%0.8p)", n, fences); + + try + { + if (n < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + for (int i = 0; i < n; i++) + { + fences[i] = context->createFence(); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGenFramebuffers(GLsizei n, GLuint* framebuffers) +{ + EVENT("(GLsizei n = %d, GLuint* framebuffers = 0x%0.8p)", n, framebuffers); + + try + { + if (n < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + for (int i = 0; i < n; i++) + { + framebuffers[i] = context->createFramebuffer(); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +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) +{ + EVENT("(GLsizei n = %d, GLuint* renderbuffers = 0x%0.8p)", n, renderbuffers); + + try + { + if (n < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + for (int i = 0; i < n; i++) + { + renderbuffers[i] = context->createRenderbuffer(); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGenTextures(GLsizei n, GLuint* textures) +{ + EVENT("(GLsizei n = %d, GLuint* textures = 0x%0.8p)", n, textures); + + try + { + if (n < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + for (int i = 0; i < n; i++) + { + textures[i] = context->createTexture(); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) +{ + 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); + + try + { + if (bufsize < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::Program *programObject = context->getProgram(program); + + if (!programObject) + { + if (context->getShader(program)) + { + return error(GL_INVALID_OPERATION); + } + else + { + return error(GL_INVALID_VALUE); + } + } + + if (index >= (GLuint)programObject->getActiveAttributeCount()) + { + return error(GL_INVALID_VALUE); + } + + programObject->getActiveAttribute(index, bufsize, length, size, type, name); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGetActiveUniform(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name) +{ + 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); + + try + { + if (bufsize < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::Program *programObject = context->getProgram(program); + + if (!programObject) + { + if (context->getShader(program)) + { + return error(GL_INVALID_OPERATION); + } + else + { + return error(GL_INVALID_VALUE); + } + } + + if (index >= (GLuint)programObject->getActiveUniformCount()) + { + return error(GL_INVALID_VALUE); + } + + programObject->getActiveUniform(index, bufsize, length, size, type, name); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGetAttachedShaders(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders) +{ + EVENT("(GLuint program = %d, GLsizei maxcount = %d, GLsizei* count = 0x%0.8p, GLuint* shaders = 0x%0.8p)", + program, maxcount, count, shaders); + + try + { + if (maxcount < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::Program *programObject = context->getProgram(program); + + if (!programObject) + { + if (context->getShader(program)) + { + return error(GL_INVALID_OPERATION); + } + else + { + return error(GL_INVALID_VALUE); + } + } + + return programObject->getAttachedShaders(maxcount, count, shaders); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +int __stdcall glGetAttribLocation(GLuint program, const GLchar* name) +{ + EVENT("(GLuint program = %d, const GLchar* name = %s)", program, name); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + + gl::Program *programObject = context->getProgram(program); + + if (!programObject) + { + if (context->getShader(program)) + { + return error(GL_INVALID_OPERATION, -1); + } + else + { + return error(GL_INVALID_VALUE, -1); + } + } + + gl::ProgramBinary *programBinary = programObject->getProgramBinary(); + if (!programObject->isLinked() || !programBinary) + { + return error(GL_INVALID_OPERATION, -1); + } + + return programBinary->getAttributeLocation(name); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY, -1); + } + + return -1; +} + +void __stdcall glGetBooleanv(GLenum pname, GLboolean* params) +{ + EVENT("(GLenum pname = 0x%X, GLboolean* params = 0x%0.8p)", pname, params); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (!(context->getBooleanv(pname, params))) + { + GLenum nativeType; + unsigned int numParams = 0; + if (!context->getQueryParameterInfo(pname, &nativeType, &numParams)) + return error(GL_INVALID_ENUM); + + if (numParams == 0) + return; // it is known that the pname is valid, but there are no parameters to return + + if (nativeType == GL_FLOAT) + { + GLfloat *floatParams = NULL; + floatParams = new GLfloat[numParams]; + + context->getFloatv(pname, floatParams); + + for (unsigned int i = 0; i < numParams; ++i) + { + if (floatParams[i] == 0.0f) + params[i] = GL_FALSE; + else + params[i] = GL_TRUE; + } + + delete [] floatParams; + } + else if (nativeType == GL_INT) + { + GLint *intParams = NULL; + intParams = new GLint[numParams]; + + context->getIntegerv(pname, intParams); + + for (unsigned int i = 0; i < numParams; ++i) + { + if (intParams[i] == 0) + params[i] = GL_FALSE; + else + params[i] = GL_TRUE; + } + + delete [] intParams; + } + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGetBufferParameteriv(GLenum target, GLenum pname, GLint* params) +{ + EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", target, pname, params); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::Buffer *buffer; + + switch (target) + { + case GL_ARRAY_BUFFER: + buffer = context->getArrayBuffer(); + break; + case GL_ELEMENT_ARRAY_BUFFER: + buffer = context->getElementArrayBuffer(); + break; + default: return error(GL_INVALID_ENUM); + } + + if (!buffer) + { + // A null buffer means that "0" is bound to the requested buffer target + return error(GL_INVALID_OPERATION); + } + + switch (pname) + { + case GL_BUFFER_USAGE: + *params = buffer->usage(); + break; + case GL_BUFFER_SIZE: + *params = buffer->size(); + break; + default: return error(GL_INVALID_ENUM); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +GLenum __stdcall glGetError(void) +{ + EVENT("()"); + + gl::Context *context = gl::getContext(); + + if (context) + { + return context->getError(); + } + + return GL_NO_ERROR; +} + +void __stdcall glGetFenceivNV(GLuint fence, GLenum pname, GLint *params) +{ + EVENT("(GLuint fence = %d, GLenum pname = 0x%X, GLint *params = 0x%0.8p)", fence, pname, params); + + try + { + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::Fence *fenceObject = context->getFence(fence); + + if (fenceObject == NULL) + { + return error(GL_INVALID_OPERATION); + } + + fenceObject->getFenceiv(pname, params); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGetFloatv(GLenum pname, GLfloat* params) +{ + EVENT("(GLenum pname = 0x%X, GLfloat* params = 0x%0.8p)", pname, params); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (!(context->getFloatv(pname, params))) + { + GLenum nativeType; + unsigned int numParams = 0; + if (!context->getQueryParameterInfo(pname, &nativeType, &numParams)) + return error(GL_INVALID_ENUM); + + if (numParams == 0) + return; // it is known that the pname is valid, but that there are no parameters to return. + + if (nativeType == GL_BOOL) + { + GLboolean *boolParams = NULL; + boolParams = new GLboolean[numParams]; + + context->getBooleanv(pname, boolParams); + + for (unsigned int i = 0; i < numParams; ++i) + { + if (boolParams[i] == GL_FALSE) + params[i] = 0.0f; + else + params[i] = 1.0f; + } + + delete [] boolParams; + } + else if (nativeType == GL_INT) + { + GLint *intParams = NULL; + intParams = new GLint[numParams]; + + context->getIntegerv(pname, intParams); + + for (unsigned int i = 0; i < numParams; ++i) + { + params[i] = (GLfloat)intParams[i]; + } + + delete [] intParams; + } + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint* params) +{ + 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::getNonLostContext(); + + if (context) + { + if (target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER_ANGLE && target != GL_READ_FRAMEBUFFER_ANGLE) + { + return error(GL_INVALID_ENUM); + } + + gl::Framebuffer *framebuffer = NULL; + if (target == GL_READ_FRAMEBUFFER_ANGLE) + { + if(context->getReadFramebufferHandle() == 0) + { + return error(GL_INVALID_OPERATION); + } + + framebuffer = context->getReadFramebuffer(); + } + else + { + if (context->getDrawFramebufferHandle() == 0) + { + return error(GL_INVALID_OPERATION); + } + + framebuffer = context->getDrawFramebuffer(); + } + + GLenum attachmentType; + GLuint attachmentHandle; + switch (attachment) + { + case GL_COLOR_ATTACHMENT0: + attachmentType = framebuffer->getColorbufferType(); + attachmentHandle = framebuffer->getColorbufferHandle(); + break; + case GL_DEPTH_ATTACHMENT: + attachmentType = framebuffer->getDepthbufferType(); + attachmentHandle = framebuffer->getDepthbufferHandle(); + break; + case GL_STENCIL_ATTACHMENT: + attachmentType = framebuffer->getStencilbufferType(); + attachmentHandle = framebuffer->getStencilbufferHandle(); + break; + default: return error(GL_INVALID_ENUM); + } + + GLenum attachmentObjectType; // Type category + if (attachmentType == GL_NONE || attachmentType == GL_RENDERBUFFER) + { + attachmentObjectType = attachmentType; + } + else if (gl::IsInternalTextureTarget(attachmentType)) + { + attachmentObjectType = GL_TEXTURE; + } + else + { + UNREACHABLE(); + return; + } + + switch (pname) + { + case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE: + *params = attachmentObjectType; + break; + case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME: + if (attachmentObjectType == GL_RENDERBUFFER || attachmentObjectType == GL_TEXTURE) + { + *params = attachmentHandle; + } + else + { + return error(GL_INVALID_ENUM); + } + break; + case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL: + if (attachmentObjectType == GL_TEXTURE) + { + *params = 0; // FramebufferTexture2D will not allow level to be set to anything else in GL ES 2.0 + } + else + { + return error(GL_INVALID_ENUM); + } + break; + case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE: + if (attachmentObjectType == GL_TEXTURE) + { + if (gl::IsCubemapTextureTarget(attachmentType)) + { + *params = attachmentType; + } + else + { + *params = 0; + } + } + else + { + return error(GL_INVALID_ENUM); + } + break; + default: + return error(GL_INVALID_ENUM); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +GLenum __stdcall glGetGraphicsResetStatusEXT(void) +{ + EVENT("()"); + + try + { + gl::Context *context = gl::getContext(); + + 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; + unsigned int numParams = 0; + if (!context->getQueryParameterInfo(pname, &nativeType, &numParams)) + return error(GL_INVALID_ENUM); + + if (numParams == 0) + return; // it is known that pname is valid, but there are no parameters to return + + if (nativeType == GL_BOOL) + { + GLboolean *boolParams = NULL; + boolParams = new GLboolean[numParams]; + + context->getBooleanv(pname, boolParams); + + for (unsigned int i = 0; i < numParams; ++i) + { + if (boolParams[i] == GL_FALSE) + params[i] = 0; + else + params[i] = 1; + } + + delete [] boolParams; + } + else if (nativeType == GL_FLOAT) + { + GLfloat *floatParams = NULL; + floatParams = new GLfloat[numParams]; + + context->getFloatv(pname, floatParams); + + for (unsigned int i = 0; i < numParams; ++i) + { + if (pname == GL_DEPTH_RANGE || pname == GL_COLOR_CLEAR_VALUE || pname == GL_DEPTH_CLEAR_VALUE || pname == GL_BLEND_COLOR) + { + params[i] = (GLint)(((GLfloat)(0xFFFFFFFF) * floatParams[i] - 1.0f) / 2.0f); + } + else + params[i] = (GLint)(floatParams[i] > 0.0f ? floor(floatParams[i] + 0.5) : ceil(floatParams[i] - 0.5)); + } + + delete [] floatParams; + } + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGetProgramiv(GLuint program, GLenum pname, GLint* params) +{ + EVENT("(GLuint program = %d, GLenum pname = %d, GLint* params = 0x%0.8p)", program, pname, params); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::Program *programObject = context->getProgram(program); + + if (!programObject) + { + return error(GL_INVALID_VALUE); + } + + switch (pname) + { + case GL_DELETE_STATUS: + *params = programObject->isFlaggedForDeletion(); + return; + case GL_LINK_STATUS: + *params = programObject->isLinked(); + return; + case GL_VALIDATE_STATUS: + *params = programObject->isValidated(); + return; + case GL_INFO_LOG_LENGTH: + *params = programObject->getInfoLogLength(); + return; + case GL_ATTACHED_SHADERS: + *params = programObject->getAttachedShadersCount(); + return; + case GL_ACTIVE_ATTRIBUTES: + *params = programObject->getActiveAttributeCount(); + return; + case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH: + *params = programObject->getActiveAttributeMaxLength(); + return; + case GL_ACTIVE_UNIFORMS: + *params = programObject->getActiveUniformCount(); + return; + case GL_ACTIVE_UNIFORM_MAX_LENGTH: + *params = programObject->getActiveUniformMaxLength(); + return; + case GL_PROGRAM_BINARY_LENGTH_OES: + *params = programObject->getProgramBinaryLength(); + return; + default: + return error(GL_INVALID_ENUM); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGetProgramInfoLog(GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog) +{ + EVENT("(GLuint program = %d, GLsizei bufsize = %d, GLsizei* length = 0x%0.8p, GLchar* infolog = 0x%0.8p)", + program, bufsize, length, infolog); + + try + { + if (bufsize < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::Program *programObject = context->getProgram(program); + + if (!programObject) + { + return error(GL_INVALID_VALUE); + } + + programObject->getInfoLog(bufsize, length, infolog); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +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) +{ + EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", target, pname, params); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (target != GL_RENDERBUFFER) + { + return error(GL_INVALID_ENUM); + } + + if (context->getRenderbufferHandle() == 0) + { + return error(GL_INVALID_OPERATION); + } + + gl::Renderbuffer *renderbuffer = context->getRenderbuffer(context->getRenderbufferHandle()); + + 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->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 = renderbuffer->getSamples(); + } + else + { + return error(GL_INVALID_ENUM); + } + break; + default: + return error(GL_INVALID_ENUM); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGetShaderiv(GLuint shader, GLenum pname, GLint* params) +{ + EVENT("(GLuint shader = %d, GLenum pname = %d, GLint* params = 0x%0.8p)", shader, pname, params); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::Shader *shaderObject = context->getShader(shader); + + if (!shaderObject) + { + return error(GL_INVALID_VALUE); + } + + switch (pname) + { + case GL_SHADER_TYPE: + *params = shaderObject->getType(); + return; + case GL_DELETE_STATUS: + *params = shaderObject->isFlaggedForDeletion(); + return; + case GL_COMPILE_STATUS: + *params = shaderObject->isCompiled() ? GL_TRUE : GL_FALSE; + return; + case GL_INFO_LOG_LENGTH: + *params = shaderObject->getInfoLogLength(); + return; + 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); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGetShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog) +{ + EVENT("(GLuint shader = %d, GLsizei bufsize = %d, GLsizei* length = 0x%0.8p, GLchar* infolog = 0x%0.8p)", + shader, bufsize, length, infolog); + + 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_VALUE); + } + + shaderObject->getInfoLog(bufsize, length, infolog); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) +{ + EVENT("(GLenum shadertype = 0x%X, GLenum precisiontype = 0x%X, GLint* range = 0x%0.8p, GLint* precision = 0x%0.8p)", + shadertype, precisiontype, range, precision); + + try + { + switch (shadertype) + { + case GL_VERTEX_SHADER: + case GL_FRAGMENT_SHADER: + break; + default: + return error(GL_INVALID_ENUM); + } + + switch (precisiontype) + { + case GL_LOW_FLOAT: + case GL_MEDIUM_FLOAT: + case GL_HIGH_FLOAT: + // Assume IEEE 754 precision + range[0] = 127; + range[1] = 127; + *precision = 23; + break; + case GL_LOW_INT: + case GL_MEDIUM_INT: + case GL_HIGH_INT: + // Some (most) hardware only supports single-precision floating-point numbers, + // which can accurately represent integers up to +/-16777216 + range[0] = 24; + range[1] = 24; + *precision = 0; + break; + default: + return error(GL_INVALID_ENUM); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGetShaderSource(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->getSource(bufsize, length, source); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +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) +{ + EVENT("(GLenum name = 0x%X)", name); + + try + { + gl::Context *context = gl::getNonLostContext(); + + switch (name) + { + case GL_VENDOR: + return (GLubyte*)"Google Inc."; + case GL_RENDERER: + return (GLubyte*)((context != NULL) ? context->getRendererString() : "ANGLE"); + case GL_VERSION: + return (GLubyte*)"OpenGL ES 2.0 (ANGLE " VERSION_STRING ")"; + case GL_SHADING_LANGUAGE_VERSION: + return (GLubyte*)"OpenGL ES GLSL ES 1.00 (ANGLE " VERSION_STRING ")"; + case GL_EXTENSIONS: + return (GLubyte*)((context != NULL) ? context->getExtensionString() : ""); + default: + return error(GL_INVALID_ENUM, (GLubyte*)NULL); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY, (GLubyte*)NULL); + } +} + +void __stdcall glGetTexParameterfv(GLenum target, GLenum pname, GLfloat* params) +{ + EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLfloat* params = 0x%0.8p)", target, pname, params); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::Texture *texture; + + switch (target) + { + case GL_TEXTURE_2D: + texture = context->getTexture2D(); + break; + case GL_TEXTURE_CUBE_MAP: + texture = context->getTextureCubeMap(); + break; + default: + return error(GL_INVALID_ENUM); + } + + switch (pname) + { + case GL_TEXTURE_MAG_FILTER: + *params = (GLfloat)texture->getMagFilter(); + break; + case GL_TEXTURE_MIN_FILTER: + *params = (GLfloat)texture->getMinFilter(); + break; + case GL_TEXTURE_WRAP_S: + *params = (GLfloat)texture->getWrapS(); + break; + 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; + case GL_TEXTURE_MAX_ANISOTROPY_EXT: + if (!context->supportsTextureFilterAnisotropy()) + { + return error(GL_INVALID_ENUM); + } + *params = (GLfloat)texture->getMaxAnisotropy(); + break; + default: + return error(GL_INVALID_ENUM); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGetTexParameteriv(GLenum target, GLenum pname, GLint* params) +{ + EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", target, pname, params); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::Texture *texture; + + switch (target) + { + case GL_TEXTURE_2D: + texture = context->getTexture2D(); + break; + case GL_TEXTURE_CUBE_MAP: + texture = context->getTextureCubeMap(); + break; + default: + return error(GL_INVALID_ENUM); + } + + switch (pname) + { + case GL_TEXTURE_MAG_FILTER: + *params = texture->getMagFilter(); + break; + case GL_TEXTURE_MIN_FILTER: + *params = texture->getMinFilter(); + break; + case GL_TEXTURE_WRAP_S: + *params = texture->getWrapS(); + break; + 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; + case GL_TEXTURE_MAX_ANISOTROPY_EXT: + if (!context->supportsTextureFilterAnisotropy()) + { + return error(GL_INVALID_ENUM); + } + *params = (GLint)texture->getMaxAnisotropy(); + break; + default: + return error(GL_INVALID_ENUM); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +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); + } + + gl::ProgramBinary *programBinary = programObject->getProgramBinary(); + if (!programBinary) + { + return error(GL_INVALID_OPERATION); + } + + if (!programBinary->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) +{ + EVENT("(GLuint program = %d, GLint location = %d, GLfloat* params = 0x%0.8p)", program, location, params); + + try + { + 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); + } + + gl::ProgramBinary *programBinary = programObject->getProgramBinary(); + if (!programBinary) + { + return error(GL_INVALID_OPERATION); + } + + if (!programBinary->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) + { + if (program == 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Program *programObject = context->getProgram(program); + + if (!programObject || !programObject->isLinked()) + { + return error(GL_INVALID_OPERATION); + } + + gl::ProgramBinary *programBinary = programObject->getProgramBinary(); + if (!programBinary) + { + return error(GL_INVALID_OPERATION); + } + + if (!programBinary->getUniformiv(location, &bufSize, params)) + { + return error(GL_INVALID_OPERATION); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGetUniformiv(GLuint program, GLint location, GLint* params) +{ + EVENT("(GLuint program = %d, GLint location = %d, GLint* params = 0x%0.8p)", program, location, params); + + try + { + 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); + } + + gl::ProgramBinary *programBinary = programObject->getProgramBinary(); + if (!programBinary) + { + return error(GL_INVALID_OPERATION); + } + + if (!programBinary->getUniformiv(location, NULL, params)) + { + return error(GL_INVALID_OPERATION); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +int __stdcall glGetUniformLocation(GLuint program, const GLchar* name) +{ + EVENT("(GLuint program = %d, const GLchar* name = 0x%0.8p)", program, name); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (strstr(name, "gl_") == name) + { + return -1; + } + + if (context) + { + gl::Program *programObject = context->getProgram(program); + + if (!programObject) + { + if (context->getShader(program)) + { + return error(GL_INVALID_OPERATION, -1); + } + else + { + return error(GL_INVALID_VALUE, -1); + } + } + + gl::ProgramBinary *programBinary = programObject->getProgramBinary(); + if (!programObject->isLinked() || !programBinary) + { + return error(GL_INVALID_OPERATION, -1); + } + + return programBinary->getUniformLocation(name); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY, -1); + } + + return -1; +} + +void __stdcall glGetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params) +{ + EVENT("(GLuint index = %d, GLenum pname = 0x%X, GLfloat* params = 0x%0.8p)", index, pname, params); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (index >= gl::MAX_VERTEX_ATTRIBS) + { + return error(GL_INVALID_VALUE); + } + + const gl::VertexAttribute &attribState = context->getVertexAttribState(index); + + switch (pname) + { + case GL_VERTEX_ATTRIB_ARRAY_ENABLED: + *params = (GLfloat)(attribState.mArrayEnabled ? GL_TRUE : GL_FALSE); + break; + case GL_VERTEX_ATTRIB_ARRAY_SIZE: + *params = (GLfloat)attribState.mSize; + break; + case GL_VERTEX_ATTRIB_ARRAY_STRIDE: + *params = (GLfloat)attribState.mStride; + break; + case GL_VERTEX_ATTRIB_ARRAY_TYPE: + *params = (GLfloat)attribState.mType; + break; + case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED: + *params = (GLfloat)(attribState.mNormalized ? GL_TRUE : GL_FALSE); + break; + case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING: + *params = (GLfloat)attribState.mBoundBuffer.id(); + break; + case GL_CURRENT_VERTEX_ATTRIB: + for (int i = 0; i < 4; ++i) + { + params[i] = attribState.mCurrentValue[i]; + } + break; + case GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE: + *params = (GLfloat)attribState.mDivisor; + break; + default: return error(GL_INVALID_ENUM); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGetVertexAttribiv(GLuint index, GLenum pname, GLint* params) +{ + EVENT("(GLuint index = %d, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", index, pname, params); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (index >= gl::MAX_VERTEX_ATTRIBS) + { + return error(GL_INVALID_VALUE); + } + + const gl::VertexAttribute &attribState = context->getVertexAttribState(index); + + switch (pname) + { + case GL_VERTEX_ATTRIB_ARRAY_ENABLED: + *params = (attribState.mArrayEnabled ? GL_TRUE : GL_FALSE); + break; + case GL_VERTEX_ATTRIB_ARRAY_SIZE: + *params = attribState.mSize; + break; + case GL_VERTEX_ATTRIB_ARRAY_STRIDE: + *params = attribState.mStride; + break; + case GL_VERTEX_ATTRIB_ARRAY_TYPE: + *params = attribState.mType; + break; + case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED: + *params = (attribState.mNormalized ? GL_TRUE : GL_FALSE); + break; + case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING: + *params = attribState.mBoundBuffer.id(); + break; + case GL_CURRENT_VERTEX_ATTRIB: + for (int i = 0; i < 4; ++i) + { + float currentValue = attribState.mCurrentValue[i]; + 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); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGetVertexAttribPointerv(GLuint index, GLenum pname, GLvoid** pointer) +{ + EVENT("(GLuint index = %d, GLenum pname = 0x%X, GLvoid** pointer = 0x%0.8p)", index, pname, pointer); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (index >= gl::MAX_VERTEX_ATTRIBS) + { + return error(GL_INVALID_VALUE); + } + + if (pname != GL_VERTEX_ATTRIB_ARRAY_POINTER) + { + return error(GL_INVALID_ENUM); + } + + *pointer = const_cast<GLvoid*>(context->getVertexAttribPointer(index)); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glHint(GLenum target, GLenum mode) +{ + EVENT("(GLenum target = 0x%X, GLenum mode = 0x%X)", target, mode); + + try + { + switch (mode) + { + case GL_FASTEST: + case GL_NICEST: + case GL_DONT_CARE: + break; + default: + return error(GL_INVALID_ENUM); + } + + gl::Context *context = gl::getNonLostContext(); + switch (target) + { + case GL_GENERATE_MIPMAP_HINT: + if (context) context->setGenerateMipmapHint(mode); + break; + case GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES: + if (context) context->setFragmentShaderDerivativeHint(mode); + break; + default: + return error(GL_INVALID_ENUM); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +GLboolean __stdcall glIsBuffer(GLuint buffer) +{ + EVENT("(GLuint buffer = %d)", buffer); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context && buffer) + { + gl::Buffer *bufferObject = context->getBuffer(buffer); + + if (bufferObject) + { + return GL_TRUE; + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY, GL_FALSE); + } + + return GL_FALSE; +} + +GLboolean __stdcall glIsEnabled(GLenum cap) +{ + EVENT("(GLenum cap = 0x%X)", cap); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + switch (cap) + { + case GL_CULL_FACE: return context->isCullFaceEnabled(); + case GL_POLYGON_OFFSET_FILL: return context->isPolygonOffsetFillEnabled(); + case GL_SAMPLE_ALPHA_TO_COVERAGE: return context->isSampleAlphaToCoverageEnabled(); + case GL_SAMPLE_COVERAGE: return context->isSampleCoverageEnabled(); + case GL_SCISSOR_TEST: return context->isScissorTestEnabled(); + case GL_STENCIL_TEST: return context->isStencilTestEnabled(); + case GL_DEPTH_TEST: return context->isDepthTestEnabled(); + case GL_BLEND: return context->isBlendEnabled(); + case GL_DITHER: return context->isDitherEnabled(); + default: + return error(GL_INVALID_ENUM, false); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY, false); + } + + return false; +} + +GLboolean __stdcall glIsFenceNV(GLuint fence) +{ + EVENT("(GLuint fence = %d)", fence); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::Fence *fenceObject = context->getFence(fence); + + if (fenceObject == NULL) + { + return GL_FALSE; + } + + return fenceObject->isFence(); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY, GL_FALSE); + } + + return GL_FALSE; +} + +GLboolean __stdcall glIsFramebuffer(GLuint framebuffer) +{ + EVENT("(GLuint framebuffer = %d)", framebuffer); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context && framebuffer) + { + gl::Framebuffer *framebufferObject = context->getFramebuffer(framebuffer); + + if (framebufferObject) + { + return GL_TRUE; + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY, GL_FALSE); + } + + return GL_FALSE; +} + +GLboolean __stdcall glIsProgram(GLuint program) +{ + EVENT("(GLuint program = %d)", program); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context && program) + { + gl::Program *programObject = context->getProgram(program); + + if (programObject) + { + return GL_TRUE; + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY, GL_FALSE); + } + + 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) +{ + EVENT("(GLuint renderbuffer = %d)", renderbuffer); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context && renderbuffer) + { + gl::Renderbuffer *renderbufferObject = context->getRenderbuffer(renderbuffer); + + if (renderbufferObject) + { + return GL_TRUE; + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY, GL_FALSE); + } + + return GL_FALSE; +} + +GLboolean __stdcall glIsShader(GLuint shader) +{ + EVENT("(GLuint shader = %d)", shader); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context && shader) + { + gl::Shader *shaderObject = context->getShader(shader); + + if (shaderObject) + { + return GL_TRUE; + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY, GL_FALSE); + } + + return GL_FALSE; +} + +GLboolean __stdcall glIsTexture(GLuint texture) +{ + EVENT("(GLuint texture = %d)", texture); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context && texture) + { + gl::Texture *textureObject = context->getTexture(texture); + + if (textureObject) + { + return GL_TRUE; + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY, GL_FALSE); + } + + return GL_FALSE; +} + +void __stdcall glLineWidth(GLfloat width) +{ + EVENT("(GLfloat width = %f)", width); + + try + { + if (width <= 0.0f) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + context->setLineWidth(width); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glLinkProgram(GLuint program) +{ + EVENT("(GLuint program = %d)", program); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::Program *programObject = context->getProgram(program); + + if (!programObject) + { + if (context->getShader(program)) + { + return error(GL_INVALID_OPERATION); + } + else + { + return error(GL_INVALID_VALUE); + } + } + + context->linkProgram(program); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glPixelStorei(GLenum pname, GLint param) +{ + EVENT("(GLenum pname = 0x%X, GLint param = %d)", pname, param); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + switch (pname) + { + case GL_UNPACK_ALIGNMENT: + if (param != 1 && param != 2 && param != 4 && param != 8) + { + return error(GL_INVALID_VALUE); + } + + context->setUnpackAlignment(param); + break; + + case GL_PACK_ALIGNMENT: + if (param != 1 && param != 2 && param != 4 && param != 8) + { + return error(GL_INVALID_VALUE); + } + + context->setPackAlignment(param); + break; + + case GL_PACK_REVERSE_ROW_ORDER_ANGLE: + context->setPackReverseRowOrder(param != 0); + break; + + default: + return error(GL_INVALID_ENUM); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glPolygonOffset(GLfloat factor, GLfloat units) +{ + EVENT("(GLfloat factor = %f, GLfloat units = %f)", factor, units); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + context->setPolygonOffsetParams(factor, units); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +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); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + GLenum currentFormat, currentType; + + // Failure in getCurrentReadFormatType indicates that no color attachment is currently bound, + // and attempting to read back if that's the case is an error. The error will be registered + // by getCurrentReadFormat. + if (!context->getCurrentReadFormatType(¤tFormat, ¤tType)) + return; + + if (!(currentFormat == format && currentType == type) && !validReadFormatType(format, type)) + { + return error(GL_INVALID_OPERATION); + } + + 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) +{ + 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); + + try + { + if (width < 0 || height < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + GLenum currentFormat, currentType; + + // Failure in getCurrentReadFormatType indicates that no color attachment is currently bound, + // and attempting to read back if that's the case is an error. The error will be registered + // by getCurrentReadFormat. + if (!context->getCurrentReadFormatType(¤tFormat, ¤tType)) + return; + + if (!(currentFormat == format && currentType == type) && !validReadFormatType(format, type)) + { + return error(GL_INVALID_OPERATION); + } + + context->readPixels(x, y, width, height, format, type, NULL, pixels); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glReleaseShaderCompiler(void) +{ + EVENT("()"); + + try + { + gl::Shader::releaseCompiler(); + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glRenderbufferStorageMultisampleANGLE(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) +{ + EVENT("(GLenum target = 0x%X, GLsizei samples = %d, GLenum internalformat = 0x%X, GLsizei width = %d, GLsizei height = %d)", + target, samples, internalformat, width, height); + + try + { + switch (target) + { + case GL_RENDERBUFFER: + break; + default: + return error(GL_INVALID_ENUM); + } + + if (!gl::IsColorRenderable(internalformat) && !gl::IsDepthRenderable(internalformat) && !gl::IsStencilRenderable(internalformat)) + { + return error(GL_INVALID_ENUM); + } + + if (width < 0 || height < 0 || samples < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (width > context->getMaximumRenderbufferDimension() || + height > context->getMaximumRenderbufferDimension() || + samples > context->getMaxSupportedSamples()) + { + return error(GL_INVALID_VALUE); + } + + GLuint handle = context->getRenderbufferHandle(); + if (handle == 0) + { + return error(GL_INVALID_OPERATION); + } + + switch (internalformat) + { + case GL_DEPTH_COMPONENT16: + context->setRenderbufferStorage(new gl::Depthbuffer(width, height, samples)); + break; + case GL_RGBA4: + case GL_RGB5_A1: + case GL_RGB565: + case GL_RGB8_OES: + case GL_RGBA8_OES: + context->setRenderbufferStorage(new gl::Colorbuffer(width, height, internalformat, samples)); + break; + case GL_STENCIL_INDEX8: + context->setRenderbufferStorage(new gl::Stencilbuffer(width, height, samples)); + break; + case GL_DEPTH24_STENCIL8_OES: + context->setRenderbufferStorage(new gl::DepthStencilbuffer(width, height, samples)); + break; + default: + return error(GL_INVALID_ENUM); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height) +{ + glRenderbufferStorageMultisampleANGLE(target, 0, internalformat, width, height); +} + +void __stdcall glSampleCoverage(GLclampf value, GLboolean invert) +{ + EVENT("(GLclampf value = %f, GLboolean invert = %d)", value, invert); + + try + { + gl::Context* context = gl::getNonLostContext(); + + if (context) + { + context->setSampleCoverageParams(gl::clamp01(value), invert == GL_TRUE); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glSetFenceNV(GLuint fence, GLenum condition) +{ + EVENT("(GLuint fence = %d, GLenum condition = 0x%X)", fence, condition); + + try + { + if (condition != GL_ALL_COMPLETED_NV) + { + return error(GL_INVALID_ENUM); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::Fence *fenceObject = context->getFence(fence); + + if (fenceObject == NULL) + { + return error(GL_INVALID_OPERATION); + } + + fenceObject->setFence(condition); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glScissor(GLint x, GLint y, GLsizei width, GLsizei height) +{ + EVENT("(GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d)", x, y, width, height); + + try + { + if (width < 0 || height < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context* context = gl::getNonLostContext(); + + if (context) + { + context->setScissorParams(x, y, width, height); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glShaderBinary(GLsizei n, const GLuint* shaders, GLenum binaryformat, const GLvoid* binary, GLsizei length) +{ + 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); + + try + { + // No binary shader formats are supported. + return error(GL_INVALID_ENUM); + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glShaderSource(GLuint shader, GLsizei count, const GLchar** string, const GLint* length) +{ + EVENT("(GLuint shader = %d, GLsizei count = %d, const GLchar** string = 0x%0.8p, const GLint* length = 0x%0.8p)", + shader, count, string, length); + + try + { + if (count < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::Shader *shaderObject = context->getShader(shader); + + if (!shaderObject) + { + if (context->getProgram(shader)) + { + return error(GL_INVALID_OPERATION); + } + else + { + return error(GL_INVALID_VALUE); + } + } + + shaderObject->setSource(count, string, length); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glStencilFunc(GLenum func, GLint ref, GLuint mask) +{ + glStencilFuncSeparate(GL_FRONT_AND_BACK, func, ref, mask); +} + +void __stdcall glStencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask) +{ + EVENT("(GLenum face = 0x%X, GLenum func = 0x%X, GLint ref = %d, GLuint mask = %d)", face, func, ref, mask); + + try + { + switch (face) + { + case GL_FRONT: + case GL_BACK: + case GL_FRONT_AND_BACK: + break; + default: + return error(GL_INVALID_ENUM); + } + + switch (func) + { + case GL_NEVER: + case GL_ALWAYS: + case GL_LESS: + case GL_LEQUAL: + case GL_EQUAL: + case GL_GEQUAL: + case GL_GREATER: + case GL_NOTEQUAL: + break; + default: + return error(GL_INVALID_ENUM); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (face == GL_FRONT || face == GL_FRONT_AND_BACK) + { + context->setStencilParams(func, ref, mask); + } + + if (face == GL_BACK || face == GL_FRONT_AND_BACK) + { + context->setStencilBackParams(func, ref, mask); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glStencilMask(GLuint mask) +{ + glStencilMaskSeparate(GL_FRONT_AND_BACK, mask); +} + +void __stdcall glStencilMaskSeparate(GLenum face, GLuint mask) +{ + EVENT("(GLenum face = 0x%X, GLuint mask = %d)", face, mask); + + try + { + switch (face) + { + case GL_FRONT: + case GL_BACK: + case GL_FRONT_AND_BACK: + break; + default: + return error(GL_INVALID_ENUM); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (face == GL_FRONT || face == GL_FRONT_AND_BACK) + { + context->setStencilWritemask(mask); + } + + if (face == GL_BACK || face == GL_FRONT_AND_BACK) + { + context->setStencilBackWritemask(mask); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glStencilOp(GLenum fail, GLenum zfail, GLenum zpass) +{ + glStencilOpSeparate(GL_FRONT_AND_BACK, fail, zfail, zpass); +} + +void __stdcall glStencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass) +{ + EVENT("(GLenum face = 0x%X, GLenum fail = 0x%X, GLenum zfail = 0x%X, GLenum zpas = 0x%Xs)", + face, fail, zfail, zpass); + + try + { + switch (face) + { + case GL_FRONT: + case GL_BACK: + case GL_FRONT_AND_BACK: + break; + default: + return error(GL_INVALID_ENUM); + } + + switch (fail) + { + case GL_ZERO: + case GL_KEEP: + case GL_REPLACE: + case GL_INCR: + case GL_DECR: + case GL_INVERT: + case GL_INCR_WRAP: + case GL_DECR_WRAP: + break; + default: + return error(GL_INVALID_ENUM); + } + + switch (zfail) + { + case GL_ZERO: + case GL_KEEP: + case GL_REPLACE: + case GL_INCR: + case GL_DECR: + case GL_INVERT: + case GL_INCR_WRAP: + case GL_DECR_WRAP: + break; + default: + return error(GL_INVALID_ENUM); + } + + switch (zpass) + { + case GL_ZERO: + case GL_KEEP: + case GL_REPLACE: + case GL_INCR: + case GL_DECR: + case GL_INVERT: + case GL_INCR_WRAP: + case GL_DECR_WRAP: + break; + default: + return error(GL_INVALID_ENUM); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (face == GL_FRONT || face == GL_FRONT_AND_BACK) + { + context->setStencilOperations(fail, zfail, zpass); + } + + if (face == GL_BACK || face == GL_FRONT_AND_BACK) + { + context->setStencilBackOperations(fail, zfail, zpass); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +GLboolean __stdcall glTestFenceNV(GLuint fence) +{ + EVENT("(GLuint fence = %d)", fence); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::Fence *fenceObject = context->getFence(fence); + + if (fenceObject == NULL) + { + return error(GL_INVALID_OPERATION, GL_TRUE); + } + + return fenceObject->testFence(); + } + } + catch(std::bad_alloc&) + { + error(GL_OUT_OF_MEMORY); + } + + return GL_TRUE; +} + +void __stdcall glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, + GLint border, GLenum format, GLenum type, const GLvoid* pixels) +{ + 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 (!validImageSize(level, width, height)) + { + return error(GL_INVALID_VALUE); + } + + if (internalformat != GLint(format)) + { + return error(GL_INVALID_OPERATION); + } + + // validate <type> by itself (used as secondary key below) + switch (type) + { + case GL_UNSIGNED_BYTE: + case GL_UNSIGNED_SHORT_5_6_5: + case GL_UNSIGNED_SHORT_4_4_4_4: + case GL_UNSIGNED_SHORT_5_5_5_1: + case GL_UNSIGNED_SHORT: + case GL_UNSIGNED_INT: + case GL_UNSIGNED_INT_24_8_OES: + case GL_HALF_FLOAT_OES: + case GL_FLOAT: + break; + default: + return error(GL_INVALID_ENUM); + } + + // validate <format> + <type> combinations + // - invalid <format> -> sets INVALID_ENUM + // - invalid <format>+<type> combination -> sets INVALID_OPERATION + switch (format) + { + case GL_ALPHA: + case GL_LUMINANCE: + case GL_LUMINANCE_ALPHA: + switch (type) + { + case GL_UNSIGNED_BYTE: + case GL_FLOAT: + case GL_HALF_FLOAT_OES: + break; + default: + return error(GL_INVALID_OPERATION); + } + break; + case GL_RGB: + switch (type) + { + case GL_UNSIGNED_BYTE: + case GL_UNSIGNED_SHORT_5_6_5: + case GL_FLOAT: + case GL_HALF_FLOAT_OES: + break; + default: + return error(GL_INVALID_OPERATION); + } + break; + case GL_RGBA: + switch (type) + { + case GL_UNSIGNED_BYTE: + case GL_UNSIGNED_SHORT_4_4_4_4: + case GL_UNSIGNED_SHORT_5_5_5_1: + case GL_FLOAT: + case GL_HALF_FLOAT_OES: + break; + default: + return error(GL_INVALID_OPERATION); + } + break; + case GL_BGRA_EXT: + switch (type) + { + case GL_UNSIGNED_BYTE: + break; + default: + return error(GL_INVALID_OPERATION); + } + 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; + case GL_DEPTH_COMPONENT: + switch (type) + { + case GL_UNSIGNED_SHORT: + case GL_UNSIGNED_INT: + break; + default: + return error(GL_INVALID_OPERATION); + } + break; + case GL_DEPTH_STENCIL_OES: + switch (type) + { + case GL_UNSIGNED_INT_24_8_OES: + break; + default: + return error(GL_INVALID_OPERATION); + } + break; + default: + return error(GL_INVALID_ENUM); + } + + if (border != 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (level > context->getMaximumTextureLevel()) + { + return error(GL_INVALID_VALUE); + } + + switch (target) + { + case GL_TEXTURE_2D: + if (width > (context->getMaximumTextureDimension() >> level) || + height > (context->getMaximumTextureDimension() >> level)) + { + return error(GL_INVALID_VALUE); + } + break; + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + if (width != height) + { + return error(GL_INVALID_VALUE); + } + + if (width > (context->getMaximumCubeTextureDimension() >> level) || + height > (context->getMaximumCubeTextureDimension() >> level)) + { + return error(GL_INVALID_VALUE); + } + break; + default: + return error(GL_INVALID_ENUM); + } + + 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); + } + else + { + return error(GL_INVALID_ENUM); + } + break; + case GL_DEPTH_COMPONENT: + case GL_DEPTH_STENCIL_OES: + if (!context->supportsDepthTextures()) + { + return error(GL_INVALID_VALUE); + } + if (target != GL_TEXTURE_2D) + { + return error(GL_INVALID_OPERATION); + } + // OES_depth_texture supports loading depth data and multiple levels, + // but ANGLE_depth_texture does not + if (pixels != NULL || level != 0) + { + return error(GL_INVALID_OPERATION); + } + break; + default: + break; + } + + if (type == GL_FLOAT) + { + if (!context->supportsFloat32Textures()) + { + return error(GL_INVALID_ENUM); + } + } + else if (type == GL_HALF_FLOAT_OES) + { + if (!context->supportsFloat16Textures()) + { + return error(GL_INVALID_ENUM); + } + } + + if (target == GL_TEXTURE_2D) + { + gl::Texture2D *texture = context->getTexture2D(); + + if (!texture) + { + return error(GL_INVALID_OPERATION); + } + + if (texture->isImmutable()) + { + return error(GL_INVALID_OPERATION); + } + + texture->setImage(level, width, height, format, type, context->getUnpackAlignment(), pixels); + } + else + { + gl::TextureCubeMap *texture = context->getTextureCubeMap(); + + if (!texture) + { + 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, width, height, format, type, context->getUnpackAlignment(), pixels); + break; + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + texture->setImageNegX(level, width, height, format, type, context->getUnpackAlignment(), pixels); + break; + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + texture->setImagePosY(level, width, height, format, type, context->getUnpackAlignment(), pixels); + break; + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + texture->setImageNegY(level, width, height, format, type, context->getUnpackAlignment(), pixels); + break; + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + texture->setImagePosZ(level, width, height, format, type, context->getUnpackAlignment(), pixels); + break; + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + texture->setImageNegZ(level, width, height, format, type, context->getUnpackAlignment(), pixels); + break; + default: UNREACHABLE(); + } + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glTexParameterf(GLenum target, GLenum pname, GLfloat param) +{ + EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint param = %f)", target, pname, param); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::Texture *texture; + + switch (target) + { + case GL_TEXTURE_2D: + texture = context->getTexture2D(); + break; + case GL_TEXTURE_CUBE_MAP: + texture = context->getTextureCubeMap(); + break; + default: + return error(GL_INVALID_ENUM); + } + + switch (pname) + { + case GL_TEXTURE_WRAP_S: + if (!texture->setWrapS((GLenum)param)) + { + return error(GL_INVALID_ENUM); + } + break; + case GL_TEXTURE_WRAP_T: + if (!texture->setWrapT((GLenum)param)) + { + return error(GL_INVALID_ENUM); + } + break; + case GL_TEXTURE_MIN_FILTER: + if (!texture->setMinFilter((GLenum)param)) + { + return error(GL_INVALID_ENUM); + } + break; + case GL_TEXTURE_MAG_FILTER: + if (!texture->setMagFilter((GLenum)param)) + { + return error(GL_INVALID_ENUM); + } + break; + case GL_TEXTURE_USAGE_ANGLE: + if (!texture->setUsage((GLenum)param)) + { + return error(GL_INVALID_ENUM); + } + break; + case GL_TEXTURE_MAX_ANISOTROPY_EXT: + if (!context->supportsTextureFilterAnisotropy()) + { + return error(GL_INVALID_ENUM); + } + if (!texture->setMaxAnisotropy((float)param, context->getTextureMaxAnisotropy())) + { + return error(GL_INVALID_VALUE); + } + break; + default: + return error(GL_INVALID_ENUM); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glTexParameterfv(GLenum target, GLenum pname, const GLfloat* params) +{ + glTexParameterf(target, pname, (GLfloat)*params); +} + +void __stdcall glTexParameteri(GLenum target, GLenum pname, GLint param) +{ + EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint param = %d)", target, pname, param); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::Texture *texture; + + switch (target) + { + case GL_TEXTURE_2D: + texture = context->getTexture2D(); + break; + case GL_TEXTURE_CUBE_MAP: + texture = context->getTextureCubeMap(); + break; + default: + return error(GL_INVALID_ENUM); + } + + switch (pname) + { + case GL_TEXTURE_WRAP_S: + if (!texture->setWrapS((GLenum)param)) + { + return error(GL_INVALID_ENUM); + } + break; + case GL_TEXTURE_WRAP_T: + if (!texture->setWrapT((GLenum)param)) + { + return error(GL_INVALID_ENUM); + } + break; + case GL_TEXTURE_MIN_FILTER: + if (!texture->setMinFilter((GLenum)param)) + { + return error(GL_INVALID_ENUM); + } + break; + case GL_TEXTURE_MAG_FILTER: + if (!texture->setMagFilter((GLenum)param)) + { + return error(GL_INVALID_ENUM); + } + break; + case GL_TEXTURE_USAGE_ANGLE: + if (!texture->setUsage((GLenum)param)) + { + return error(GL_INVALID_ENUM); + } + break; + case GL_TEXTURE_MAX_ANISOTROPY_EXT: + if (!context->supportsTextureFilterAnisotropy()) + { + return error(GL_INVALID_ENUM); + } + if (!texture->setMaxAnisotropy((float)param, context->getTextureMaxAnisotropy())) + { + return error(GL_INVALID_VALUE); + } + break; + default: + return error(GL_INVALID_ENUM); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glTexParameteriv(GLenum target, GLenum pname, const GLint* params) +{ + glTexParameteri(target, pname, *params); +} + +void __stdcall glTexStorage2DEXT(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) +{ + 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 (target != GL_TEXTURE_2D && target != GL_TEXTURE_CUBE_MAP) + { + return error(GL_INVALID_ENUM); + } + + if (width < 1 || height < 1 || levels < 1) + { + return error(GL_INVALID_VALUE); + } + + if (target == GL_TEXTURE_CUBE_MAP && width != height) + { + return error(GL_INVALID_VALUE); + } + + if (levels != 1 && levels != gl::log2(std::max(width, height)) + 1) + { + return error(GL_INVALID_OPERATION); + } + + GLenum format = gl::ExtractFormat(internalformat); + GLenum type = gl::ExtractType(internalformat); + + if (format == GL_NONE || type == GL_NONE) + { + return error(GL_INVALID_ENUM); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + switch (target) + { + 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 (levels != 1 && !context->supportsNonPower2Texture()) + { + if (!gl::isPow2(width) || !gl::isPow2(height)) + { + return error(GL_INVALID_OPERATION); + } + } + + switch (internalformat) + { + 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; + case GL_DEPTH_COMPONENT16: + case GL_DEPTH_COMPONENT32_OES: + case GL_DEPTH24_STENCIL8_OES: + if (!context->supportsDepthTextures()) + { + return error(GL_INVALID_ENUM); + } + if (target != GL_TEXTURE_2D) + { + return error(GL_INVALID_OPERATION); + } + // ANGLE_depth_texture only supports 1-level textures + if (levels != 1) + { + return error(GL_INVALID_OPERATION); + } + break; + default: + break; + } + + if (target == GL_TEXTURE_2D) + { + gl::Texture2D *texture = context->getTexture2D(); + + if (!texture || texture->id() == 0) + { + return error(GL_INVALID_OPERATION); + } + + if (texture->isImmutable()) + { + return error(GL_INVALID_OPERATION); + } + + texture->storage(levels, internalformat, width, height); + } + else if (target == GL_TEXTURE_CUBE_MAP) + { + gl::TextureCubeMap *texture = context->getTextureCubeMap(); + + if (!texture || texture->id() == 0) + { + return error(GL_INVALID_OPERATION); + } + + if (texture->isImmutable()) + { + return error(GL_INVALID_OPERATION); + } + + 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 (!checkTextureFormatType(format, type)) + { + return; // error is set by helper function + } + + 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_ENUM); + } + } + else if (format == GL_HALF_FLOAT_OES) + { + if (!context->supportsFloat16Textures()) + { + return error(GL_INVALID_ENUM); + } + } + else if (gl::IsDepthTexture(format)) + { + if (!context->supportsDepthTextures()) + { + return error(GL_INVALID_ENUM); + } + if (target != GL_TEXTURE_2D) + { + return error(GL_INVALID_OPERATION); + } + // OES_depth_texture supports loading depth data, but ANGLE_depth_texture does not + return error(GL_INVALID_OPERATION); + } + + if (width == 0 || height == 0 || pixels == NULL) + { + return; + } + + if (target == GL_TEXTURE_2D) + { + gl::Texture2D *texture = context->getTexture2D(); + if (validateSubImageParams2D(false, width, height, xoffset, yoffset, level, format, type, texture)) + { + texture->subImage(level, xoffset, yoffset, width, height, format, type, context->getUnpackAlignment(), pixels); + } + } + else if (gl::IsCubemapTextureTarget(target)) + { + gl::TextureCubeMap *texture = context->getTextureCubeMap(); + if (validateSubImageParamsCube(false, width, height, xoffset, yoffset, target, level, format, type, texture)) + { + texture->subImage(target, level, xoffset, yoffset, width, height, format, type, context->getUnpackAlignment(), pixels); + } + } + else + { + UNREACHABLE(); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glUniform1f(GLint location, GLfloat x) +{ + glUniform1fv(location, 1, &x); +} + +void __stdcall glUniform1fv(GLint location, GLsizei count, const GLfloat* v) +{ + EVENT("(GLint location = %d, GLsizei count = %d, const GLfloat* v = 0x%0.8p)", location, count, v); + + try + { + if (count < 0) + { + return error(GL_INVALID_VALUE); + } + + if (location == -1) + { + return; + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::ProgramBinary *programBinary = context->getCurrentProgramBinary(); + if (!programBinary) + { + return error(GL_INVALID_OPERATION); + } + + if (!programBinary->setUniform1fv(location, count, v)) + { + return error(GL_INVALID_OPERATION); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glUniform1i(GLint location, GLint x) +{ + glUniform1iv(location, 1, &x); +} + +void __stdcall glUniform1iv(GLint location, GLsizei count, const GLint* v) +{ + EVENT("(GLint location = %d, GLsizei count = %d, const GLint* v = 0x%0.8p)", location, count, v); + + try + { + if (count < 0) + { + return error(GL_INVALID_VALUE); + } + + if (location == -1) + { + return; + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::ProgramBinary *programBinary = context->getCurrentProgramBinary(); + if (!programBinary) + { + return error(GL_INVALID_OPERATION); + } + + if (!programBinary->setUniform1iv(location, count, v)) + { + return error(GL_INVALID_OPERATION); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glUniform2f(GLint location, GLfloat x, GLfloat y) +{ + GLfloat xy[2] = {x, y}; + + glUniform2fv(location, 1, (GLfloat*)&xy); +} + +void __stdcall glUniform2fv(GLint location, GLsizei count, const GLfloat* v) +{ + EVENT("(GLint location = %d, GLsizei count = %d, const GLfloat* v = 0x%0.8p)", location, count, v); + + try + { + if (count < 0) + { + return error(GL_INVALID_VALUE); + } + + if (location == -1) + { + return; + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::ProgramBinary *programBinary = context->getCurrentProgramBinary(); + if (!programBinary) + { + return error(GL_INVALID_OPERATION); + } + + if (!programBinary->setUniform2fv(location, count, v)) + { + return error(GL_INVALID_OPERATION); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glUniform2i(GLint location, GLint x, GLint y) +{ + GLint xy[4] = {x, y}; + + glUniform2iv(location, 1, (GLint*)&xy); +} + +void __stdcall glUniform2iv(GLint location, GLsizei count, const GLint* v) +{ + EVENT("(GLint location = %d, GLsizei count = %d, const GLint* v = 0x%0.8p)", location, count, v); + + try + { + if (count < 0) + { + return error(GL_INVALID_VALUE); + } + + if (location == -1) + { + return; + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::ProgramBinary *programBinary = context->getCurrentProgramBinary(); + if (!programBinary) + { + return error(GL_INVALID_OPERATION); + } + + if (!programBinary->setUniform2iv(location, count, v)) + { + return error(GL_INVALID_OPERATION); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glUniform3f(GLint location, GLfloat x, GLfloat y, GLfloat z) +{ + GLfloat xyz[3] = {x, y, z}; + + glUniform3fv(location, 1, (GLfloat*)&xyz); +} + +void __stdcall glUniform3fv(GLint location, GLsizei count, const GLfloat* v) +{ + EVENT("(GLint location = %d, GLsizei count = %d, const GLfloat* v = 0x%0.8p)", location, count, v); + + try + { + if (count < 0) + { + return error(GL_INVALID_VALUE); + } + + if (location == -1) + { + return; + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::ProgramBinary *programBinary = context->getCurrentProgramBinary(); + if (!programBinary) + { + return error(GL_INVALID_OPERATION); + } + + if (!programBinary->setUniform3fv(location, count, v)) + { + return error(GL_INVALID_OPERATION); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glUniform3i(GLint location, GLint x, GLint y, GLint z) +{ + GLint xyz[3] = {x, y, z}; + + glUniform3iv(location, 1, (GLint*)&xyz); +} + +void __stdcall glUniform3iv(GLint location, GLsizei count, const GLint* v) +{ + EVENT("(GLint location = %d, GLsizei count = %d, const GLint* v = 0x%0.8p)", location, count, v); + + try + { + if (count < 0) + { + return error(GL_INVALID_VALUE); + } + + if (location == -1) + { + return; + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::ProgramBinary *programBinary = context->getCurrentProgramBinary(); + if (!programBinary) + { + return error(GL_INVALID_OPERATION); + } + + if (!programBinary->setUniform3iv(location, count, v)) + { + return error(GL_INVALID_OPERATION); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glUniform4f(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + GLfloat xyzw[4] = {x, y, z, w}; + + glUniform4fv(location, 1, (GLfloat*)&xyzw); +} + +void __stdcall glUniform4fv(GLint location, GLsizei count, const GLfloat* v) +{ + EVENT("(GLint location = %d, GLsizei count = %d, const GLfloat* v = 0x%0.8p)", location, count, v); + + try + { + if (count < 0) + { + return error(GL_INVALID_VALUE); + } + + if (location == -1) + { + return; + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::ProgramBinary *programBinary = context->getCurrentProgramBinary(); + if (!programBinary) + { + return error(GL_INVALID_OPERATION); + } + + if (!programBinary->setUniform4fv(location, count, v)) + { + return error(GL_INVALID_OPERATION); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glUniform4i(GLint location, GLint x, GLint y, GLint z, GLint w) +{ + GLint xyzw[4] = {x, y, z, w}; + + glUniform4iv(location, 1, (GLint*)&xyzw); +} + +void __stdcall glUniform4iv(GLint location, GLsizei count, const GLint* v) +{ + EVENT("(GLint location = %d, GLsizei count = %d, const GLint* v = 0x%0.8p)", location, count, v); + + try + { + if (count < 0) + { + return error(GL_INVALID_VALUE); + } + + if (location == -1) + { + return; + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::ProgramBinary *programBinary = context->getCurrentProgramBinary(); + if (!programBinary) + { + return error(GL_INVALID_OPERATION); + } + + if (!programBinary->setUniform4iv(location, count, v)) + { + return error(GL_INVALID_OPERATION); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +{ + EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %d, const GLfloat* value = 0x%0.8p)", + location, count, transpose, value); + + try + { + if (count < 0 || transpose != GL_FALSE) + { + return error(GL_INVALID_VALUE); + } + + if (location == -1) + { + return; + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::ProgramBinary *programBinary = context->getCurrentProgramBinary(); + if (!programBinary) + { + return error(GL_INVALID_OPERATION); + } + + if (!programBinary->setUniformMatrix2fv(location, count, value)) + { + return error(GL_INVALID_OPERATION); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +{ + EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %d, const GLfloat* value = 0x%0.8p)", + location, count, transpose, value); + + try + { + if (count < 0 || transpose != GL_FALSE) + { + return error(GL_INVALID_VALUE); + } + + if (location == -1) + { + return; + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::ProgramBinary *programBinary = context->getCurrentProgramBinary(); + if (!programBinary) + { + return error(GL_INVALID_OPERATION); + } + + if (!programBinary->setUniformMatrix3fv(location, count, value)) + { + return error(GL_INVALID_OPERATION); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +{ + EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %d, const GLfloat* value = 0x%0.8p)", + location, count, transpose, value); + + try + { + if (count < 0 || transpose != GL_FALSE) + { + return error(GL_INVALID_VALUE); + } + + if (location == -1) + { + return; + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::ProgramBinary *programBinary = context->getCurrentProgramBinary(); + if (!programBinary) + { + return error(GL_INVALID_OPERATION); + } + + if (!programBinary->setUniformMatrix4fv(location, count, value)) + { + return error(GL_INVALID_OPERATION); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glUseProgram(GLuint program) +{ + EVENT("(GLuint program = %d)", program); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::Program *programObject = context->getProgram(program); + + if (!programObject && program != 0) + { + if (context->getShader(program)) + { + return error(GL_INVALID_OPERATION); + } + else + { + return error(GL_INVALID_VALUE); + } + } + + if (program != 0 && !programObject->isLinked()) + { + return error(GL_INVALID_OPERATION); + } + + context->useProgram(program); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glValidateProgram(GLuint program) +{ + EVENT("(GLuint program = %d)", program); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::Program *programObject = context->getProgram(program); + + if (!programObject) + { + if (context->getShader(program)) + { + return error(GL_INVALID_OPERATION); + } + else + { + return error(GL_INVALID_VALUE); + } + } + + programObject->validate(); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glVertexAttrib1f(GLuint index, GLfloat x) +{ + EVENT("(GLuint index = %d, GLfloat x = %f)", index, x); + + try + { + if (index >= gl::MAX_VERTEX_ATTRIBS) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + GLfloat vals[4] = { x, 0, 0, 1 }; + context->setVertexAttrib(index, vals); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glVertexAttrib1fv(GLuint index, const GLfloat* values) +{ + EVENT("(GLuint index = %d, const GLfloat* values = 0x%0.8p)", index, values); + + try + { + if (index >= gl::MAX_VERTEX_ATTRIBS) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + GLfloat vals[4] = { values[0], 0, 0, 1 }; + context->setVertexAttrib(index, vals); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glVertexAttrib2f(GLuint index, GLfloat x, GLfloat y) +{ + EVENT("(GLuint index = %d, GLfloat x = %f, GLfloat y = %f)", index, x, y); + + try + { + if (index >= gl::MAX_VERTEX_ATTRIBS) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + GLfloat vals[4] = { x, y, 0, 1 }; + context->setVertexAttrib(index, vals); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glVertexAttrib2fv(GLuint index, const GLfloat* values) +{ + EVENT("(GLuint index = %d, const GLfloat* values = 0x%0.8p)", index, values); + + try + { + if (index >= gl::MAX_VERTEX_ATTRIBS) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + GLfloat vals[4] = { values[0], values[1], 0, 1 }; + context->setVertexAttrib(index, vals); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glVertexAttrib3f(GLuint index, GLfloat x, GLfloat y, GLfloat z) +{ + EVENT("(GLuint index = %d, GLfloat x = %f, GLfloat y = %f, GLfloat z = %f)", index, x, y, z); + + try + { + if (index >= gl::MAX_VERTEX_ATTRIBS) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + GLfloat vals[4] = { x, y, z, 1 }; + context->setVertexAttrib(index, vals); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glVertexAttrib3fv(GLuint index, const GLfloat* values) +{ + EVENT("(GLuint index = %d, const GLfloat* values = 0x%0.8p)", index, values); + + try + { + if (index >= gl::MAX_VERTEX_ATTRIBS) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + GLfloat vals[4] = { values[0], values[1], values[2], 1 }; + context->setVertexAttrib(index, vals); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glVertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + EVENT("(GLuint index = %d, GLfloat x = %f, GLfloat y = %f, GLfloat z = %f, GLfloat w = %f)", index, x, y, z, w); + + try + { + if (index >= gl::MAX_VERTEX_ATTRIBS) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + GLfloat vals[4] = { x, y, z, w }; + context->setVertexAttrib(index, vals); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glVertexAttrib4fv(GLuint index, const GLfloat* values) +{ + EVENT("(GLuint index = %d, const GLfloat* values = 0x%0.8p)", index, values); + + try + { + if (index >= gl::MAX_VERTEX_ATTRIBS) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + context->setVertexAttrib(index, values); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +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) +{ + 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); + + try + { + if (index >= gl::MAX_VERTEX_ATTRIBS) + { + return error(GL_INVALID_VALUE); + } + + if (size < 1 || size > 4) + { + return error(GL_INVALID_VALUE); + } + + switch (type) + { + case GL_BYTE: + case GL_UNSIGNED_BYTE: + case GL_SHORT: + case GL_UNSIGNED_SHORT: + case GL_FIXED: + case GL_FLOAT: + break; + default: + return error(GL_INVALID_ENUM); + } + + if (stride < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + context->setVertexAttribState(index, context->getArrayBuffer(), size, type, (normalized == GL_TRUE), stride, ptr); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glViewport(GLint x, GLint y, GLsizei width, GLsizei height) +{ + EVENT("(GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d)", x, y, width, height); + + try + { + if (width < 0 || height < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + context->setViewportParams(x, y, width, height); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glBlitFramebufferANGLE(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, + GLbitfield mask, GLenum filter) +{ + 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); + + try + { + switch (filter) + { + case GL_NEAREST: + break; + default: + return error(GL_INVALID_ENUM); + } + + if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0) + { + return error(GL_INVALID_VALUE); + } + + if (srcX1 - srcX0 != dstX1 - dstX0 || srcY1 - srcY0 != dstY1 - dstY0) + { + ERR("Scaling and flipping in BlitFramebufferANGLE not supported by this implementation"); + return error(GL_INVALID_OPERATION); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (context->getReadFramebufferHandle() == context->getDrawFramebufferHandle()) + { + ERR("Blits with the same source and destination framebuffer are not supported by this implementation."); + return error(GL_INVALID_OPERATION); + } + + context->blitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glTexImage3DOES(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, + GLint border, GLenum format, GLenum type, const GLvoid* pixels) +{ + 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); + + try + { + UNIMPLEMENTED(); // FIXME + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGetProgramBinaryOES(GLuint program, GLsizei bufSize, GLsizei *length, + GLenum *binaryFormat, void *binary) +{ + EVENT("(GLenum program = 0x%X, bufSize = %d, length = 0x%0.8p, binaryFormat = 0x%0.8p, binary = 0x%0.8p)", + program, bufSize, length, binaryFormat, binary); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::Program *programObject = context->getProgram(program); + + if (!programObject || !programObject->isLinked()) + { + return error(GL_INVALID_OPERATION); + } + + gl::ProgramBinary *programBinary = programObject->getProgramBinary(); + + if (!programBinary) + { + return error(GL_INVALID_OPERATION); + } + + if (!programBinary->save(binary, bufSize, length)) + { + return error(GL_INVALID_OPERATION); + } + + *binaryFormat = GL_PROGRAM_BINARY_ANGLE; + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glProgramBinaryOES(GLuint program, GLenum binaryFormat, + const void *binary, GLint length) +{ + EVENT("(GLenum program = 0x%X, binaryFormat = 0x%x, binary = 0x%0.8p, length = %d)", + program, binaryFormat, binary, length); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (binaryFormat != GL_PROGRAM_BINARY_ANGLE) + { + return error(GL_INVALID_ENUM); + } + + gl::Program *programObject = context->getProgram(program); + + if (!programObject) + { + return error(GL_INVALID_OPERATION); + } + + context->setProgramBinary(program, binary, length); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +__eglMustCastToProperFunctionPointerType __stdcall glGetProcAddress(const char *procname) +{ + struct Extension + { + const char *name; + __eglMustCastToProperFunctionPointerType address; + }; + + static const Extension glExtensions[] = + { + {"glTexImage3DOES", (__eglMustCastToProperFunctionPointerType)glTexImage3DOES}, + {"glBlitFramebufferANGLE", (__eglMustCastToProperFunctionPointerType)glBlitFramebufferANGLE}, + {"glRenderbufferStorageMultisampleANGLE", (__eglMustCastToProperFunctionPointerType)glRenderbufferStorageMultisampleANGLE}, + {"glDeleteFencesNV", (__eglMustCastToProperFunctionPointerType)glDeleteFencesNV}, + {"glGenFencesNV", (__eglMustCastToProperFunctionPointerType)glGenFencesNV}, + {"glIsFenceNV", (__eglMustCastToProperFunctionPointerType)glIsFenceNV}, + {"glTestFenceNV", (__eglMustCastToProperFunctionPointerType)glTestFenceNV}, + {"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}, + {"glGetProgramBinaryOES", (__eglMustCastToProperFunctionPointerType)glGetProgramBinaryOES}, + {"glProgramBinaryOES", (__eglMustCastToProperFunctionPointerType)glProgramBinaryOES}, }; + + for (int ext = 0; ext < sizeof(glExtensions) / sizeof(Extension); ext++) + { + if (strcmp(procname, glExtensions[ext].name) == 0) + { + return (__eglMustCastToProperFunctionPointerType)glExtensions[ext].address; + } + } + + 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/src/3rdparty/angle/src/libGLESv2/libGLESv2.def b/src/3rdparty/angle/src/libGLESv2/libGLESv2.def new file mode 100644 index 0000000000..5f935c3733 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/libGLESv2.def @@ -0,0 +1,182 @@ +LIBRARY libGLESv2 +EXPORTS + glActiveTexture @1 + glAttachShader @2 + glBindAttribLocation @3 + glBindBuffer @4 + glBindFramebuffer @5 + glBindRenderbuffer @6 + glBindTexture @7 + glBlendColor @8 + glBlendEquation @9 + glBlendEquationSeparate @10 + glBlendFunc @11 + glBlendFuncSeparate @12 + glBufferData @13 + glBufferSubData @14 + glCheckFramebufferStatus @15 + glClear @16 + glClearColor @17 + glClearDepthf @18 + glClearStencil @19 + glColorMask @20 + glCompileShader @21 + glCompressedTexImage2D @22 + glCompressedTexSubImage2D @23 + glCopyTexImage2D @24 + glCopyTexSubImage2D @25 + glCreateProgram @26 + glCreateShader @27 + glCullFace @28 + glDeleteBuffers @29 + glDeleteFramebuffers @30 + glDeleteProgram @32 + glDeleteRenderbuffers @33 + glDeleteShader @34 + glDeleteTextures @31 + glDepthFunc @36 + glDepthMask @37 + glDepthRangef @38 + glDetachShader @35 + glDisable @39 + glDisableVertexAttribArray @40 + glDrawArrays @41 + glDrawElements @42 + glEnable @43 + glEnableVertexAttribArray @44 + glFinish @45 + glFlush @46 + glFramebufferRenderbuffer @47 + glFramebufferTexture2D @48 + glFrontFace @49 + glGenBuffers @50 + glGenFramebuffers @52 + glGenRenderbuffers @53 + glGenTextures @54 + glGenerateMipmap @51 + glGetActiveAttrib @55 + glGetActiveUniform @56 + glGetAttachedShaders @57 + glGetAttribLocation @58 + glGetBooleanv @59 + glGetBufferParameteriv @60 + glGetError @61 + glGetFloatv @62 + glGetFramebufferAttachmentParameteriv @63 + glGetIntegerv @64 + glGetProgramInfoLog @66 + glGetProgramiv @65 + glGetRenderbufferParameteriv @67 + glGetShaderInfoLog @69 + glGetShaderPrecisionFormat @70 + glGetShaderSource @71 + glGetShaderiv @68 + glGetString @72 + glGetTexParameterfv @73 + glGetTexParameteriv @74 + glGetUniformLocation @77 + glGetUniformfv @75 + glGetUniformiv @76 + glGetVertexAttribPointerv @80 + glGetVertexAttribfv @78 + glGetVertexAttribiv @79 + glHint @81 + glIsBuffer @82 + glIsEnabled @83 + glIsFramebuffer @84 + glIsProgram @85 + glIsRenderbuffer @86 + glIsShader @87 + glIsTexture @88 + glLineWidth @89 + glLinkProgram @90 + glPixelStorei @91 + glPolygonOffset @92 + glReadPixels @93 + glReleaseShaderCompiler @94 + glRenderbufferStorage @95 + glSampleCoverage @96 + glScissor @97 + glShaderBinary @98 + glShaderSource @99 + glStencilFunc @100 + glStencilFuncSeparate @101 + glStencilMask @102 + glStencilMaskSeparate @103 + glStencilOp @104 + glStencilOpSeparate @105 + glTexImage2D @106 + glTexParameterf @107 + glTexParameterfv @108 + glTexParameteri @109 + glTexParameteriv @110 + glTexSubImage2D @111 + glUniform1f @112 + glUniform1fv @113 + glUniform1i @114 + glUniform1iv @115 + glUniform2f @116 + glUniform2fv @117 + glUniform2i @118 + glUniform2iv @119 + glUniform3f @120 + glUniform3fv @121 + glUniform3i @122 + glUniform3iv @123 + glUniform4f @124 + glUniform4fv @125 + glUniform4i @126 + glUniform4iv @127 + glUniformMatrix2fv @128 + glUniformMatrix3fv @129 + glUniformMatrix4fv @130 + glUseProgram @131 + glValidateProgram @132 + glVertexAttrib1f @133 + glVertexAttrib1fv @134 + glVertexAttrib2f @135 + glVertexAttrib2fv @136 + glVertexAttrib3f @137 + glVertexAttrib3fv @138 + glVertexAttrib4f @139 + glVertexAttrib4fv @140 + glVertexAttribPointer @141 + glViewport @142 + + ; Extensions + glTexImage3DOES @143 + glBlitFramebufferANGLE @149 + glRenderbufferStorageMultisampleANGLE @150 + glDeleteFencesNV @151 + glFinishFenceNV @152 + glGenFencesNV @153 + glGetFenceivNV @154 + 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 + glProgramBinaryOES @175 + glGetProgramBinaryOES @176 + + ; EGL dependencies + glCreateContext @144 NONAME + glDestroyContext @145 NONAME + glMakeCurrent @146 NONAME + glGetCurrentContext @147 NONAME + glGetProcAddress @148 NONAME + glBindTexImage @158 NONAME diff --git a/src/3rdparty/angle/src/libGLESv2/libGLESv2.rc b/src/3rdparty/angle/src/libGLESv2/libGLESv2.rc new file mode 100644 index 0000000000..0ad21e440e --- /dev/null +++ b/src/3rdparty/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/src/3rdparty/angle/src/libGLESv2/main.cpp b/src/3rdparty/angle/src/libGLESv2/main.cpp new file mode 100644 index 0000000000..6e678c2616 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/main.cpp @@ -0,0 +1,176 @@ +// +// 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. +// + +// 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" + +#include "libGLESv2/Framebuffer.h" + +static DWORD currentTLS = TLS_OUT_OF_INDEXES; + +extern "C" BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved) +{ + switch (reason) + { + case DLL_PROCESS_ATTACH: + { + currentTLS = TlsAlloc(); + + if (currentTLS == TLS_OUT_OF_INDEXES) + { + return FALSE; + } + } + // Fall throught to initialize index + case DLL_THREAD_ATTACH: + { + gl::Current *current = (gl::Current*)LocalAlloc(LPTR, sizeof(gl::Current)); + + if (current) + { + TlsSetValue(currentTLS, current); + + current->context = NULL; + current->display = NULL; + } + } + break; + case DLL_THREAD_DETACH: + { + void *current = TlsGetValue(currentTLS); + + if (current) + { + LocalFree((HLOCAL)current); + } + } + break; + case DLL_PROCESS_DETACH: + { + void *current = TlsGetValue(currentTLS); + + if (current) + { + LocalFree((HLOCAL)current); + } + + TlsFree(currentTLS); + } + break; + default: + break; + } + + return TRUE; +} + +namespace gl +{ +void makeCurrent(Context *context, egl::Display *display, egl::Surface *surface) +{ + Current *current = (Current*)TlsGetValue(currentTLS); + + current->context = context; + current->display = display; + + if (context && display && surface) + { + context->makeCurrent(display, surface); + } +} + +Context *getContext() +{ + Current *current = (Current*)TlsGetValue(currentTLS); + + 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); + + return current->display; +} + +IDirect3DDevice9 *getDevice() +{ + egl::Display *display = getDisplay(); + + 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 +void error(GLenum errorCode) +{ + gl::Context *context = glGetCurrentContext(); + + if (context) + { + switch (errorCode) + { + case GL_INVALID_ENUM: + context->recordInvalidEnum(); + TRACE("\t! Error generated: invalid enum\n"); + break; + case GL_INVALID_VALUE: + context->recordInvalidValue(); + TRACE("\t! Error generated: invalid value\n"); + break; + case GL_INVALID_OPERATION: + context->recordInvalidOperation(); + TRACE("\t! Error generated: invalid operation\n"); + break; + case GL_OUT_OF_MEMORY: + context->recordOutOfMemory(); + TRACE("\t! Error generated: out of memory\n"); + break; + case GL_INVALID_FRAMEBUFFER_OPERATION: + context->recordInvalidFramebufferOperation(); + TRACE("\t! Error generated: invalid framebuffer operation\n"); + break; + default: UNREACHABLE(); + } + } +} diff --git a/src/3rdparty/angle/src/libGLESv2/main.h b/src/3rdparty/angle/src/libGLESv2/main.h new file mode 100644 index 0000000000..504848aa65 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/main.h @@ -0,0 +1,50 @@ +// +// 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. +// + +// main.h: Management of thread-local data. + +#ifndef LIBGLESV2_MAIN_H_ +#define LIBGLESV2_MAIN_H_ + +#define GL_APICALL +#include <GLES2/gl2.h> +#include <GLES2/gl2ext.h> + +#include "common/debug.h" +#include "libEGL/Display.h" + +#include "libGLESv2/Context.h" + +namespace gl +{ +struct Current +{ + Context *context; + egl::Display *display; +}; + +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); + +template<class T> +const T &error(GLenum errorCode, const T &returnValue) +{ + error(errorCode); + + return returnValue; +} + +#endif // LIBGLESV2_MAIN_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/mathutil.h b/src/3rdparty/angle/src/libGLESv2/mathutil.h new file mode 100644 index 0000000000..790ecd89fa --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/mathutil.h @@ -0,0 +1,145 @@ +// +// 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. +// + +// mathutil.h: Math and bit manipulation functions. + +#ifndef LIBGLESV2_MATHUTIL_H_ +#define LIBGLESV2_MATHUTIL_H_ + +#include <intrin.h> +#include <math.h> +#include <windows.h> + +namespace gl +{ +struct Vector4 +{ + Vector4() {} + Vector4(float x, float y, float z, float w) : x(x), y(y), z(z), w(w) {} + + float x; + float y; + float z; + float w; +}; + +inline bool isPow2(int x) +{ + return (x & (x - 1)) == 0 && (x != 0); +} + +inline int log2(int x) +{ + int r = 0; + while ((x >> r) > 1) r++; + return r; +} + +inline unsigned int ceilPow2(unsigned int x) +{ + if (x != 0) x--; + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + x |= x >> 8; + x |= x >> 16; + 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 clamp(x, 0.0f, 1.0f); +} + +template<const int n> +inline unsigned int unorm(float x) +{ + const unsigned int max = 0xFFFFFFFF >> (32 - n); + + if (x > 1) + { + return max; + } + else if (x < 0) + { + return 0; + } + else + { + return (unsigned int)(max * x + 0.5f); + } +} + +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; +} + +inline unsigned short float32ToFloat16(float fp32) +{ + unsigned int fp32i = (unsigned int&)fp32; + unsigned int sign = (fp32i & 0x80000000) >> 16; + unsigned int abs = fp32i & 0x7FFFFFFF; + + if(abs > 0x47FFEFFF) // Infinity + { + return sign | 0x7FFF; + } + else if(abs < 0x38800000) // Denormal + { + unsigned int mantissa = (abs & 0x007FFFFF) | 0x00800000; + int e = 113 - (abs >> 23); + + if(e < 24) + { + abs = mantissa >> e; + } + else + { + abs = 0; + } + + return sign | (abs + 0x00000FFF + ((abs >> 13) & 1)) >> 13; + } + else + { + return sign | (abs + 0xC8000000 + 0x00000FFF + ((abs >> 13) & 1)) >> 13; + } +} + +float float16ToFloat32(unsigned short h); + +} + +#endif // LIBGLESV2_MATHUTIL_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/resource.h b/src/3rdparty/angle/src/libGLESv2/resource.h new file mode 100644 index 0000000000..39adaad0dd --- /dev/null +++ b/src/3rdparty/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/src/3rdparty/angle/src/libGLESv2/shaders/Blit.ps b/src/3rdparty/angle/src/libGLESv2/shaders/Blit.ps new file mode 100644 index 0000000000..dcb3bd0e76 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/shaders/Blit.ps @@ -0,0 +1,39 @@ +// +// 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. +// + +sampler2D tex : s0; + +uniform float4 mode : c0; + +// Passthrough Pixel Shader +// Outputs texture 0 sampled at texcoord 0. +float4 passthroughps(float4 texcoord : TEXCOORD0) : COLOR +{ + return tex2D(tex, texcoord.xy); +}; + +// Luminance Conversion Pixel Shader +// Outputs sample(tex0, tc0).rrra. +// For LA output (pass A) set C0.X = 1, C0.Y = 0. +// For L output (A = 1) set C0.X = 0, C0.Y = 1. +float4 luminanceps(float4 texcoord : TEXCOORD0) : COLOR +{ + float4 tmp = tex2D(tex, texcoord.xy); + tmp.w = tmp.w * mode.x + mode.y; + return tmp.xxxw; +}; + +// RGB/A Component Mask Pixel Shader +// Outputs sample(tex0, tc0) with options to force RGB = 0 and/or A = 1. +// To force RGB = 0, set C0.X = 0, otherwise C0.X = 1. +// To force A = 1, set C0.Z = 0, C0.W = 1, otherwise C0.Z = 1, C0.W = 0. +float4 componentmaskps(float4 texcoord : TEXCOORD0) : COLOR +{ + float4 tmp = tex2D(tex, texcoord.xy); + tmp.xyz = tmp.xyz * mode.x; + tmp.w = tmp.w * mode.z + mode.w; + return tmp; +}; diff --git a/src/3rdparty/angle/src/libGLESv2/shaders/Blit.vs b/src/3rdparty/angle/src/libGLESv2/shaders/Blit.vs new file mode 100644 index 0000000000..3a36980b93 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/shaders/Blit.vs @@ -0,0 +1,43 @@ +// +// 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. +// + +struct VS_OUTPUT +{ + float4 position : POSITION; + float4 texcoord : TEXCOORD0; +}; + +uniform float4 halfPixelSize : c0; + +// Standard Vertex Shader +// Input 0 is the homogenous position. +// Outputs the homogenous position as-is. +// Outputs a tex coord with (0,0) in the upper-left corner of the screen and (1,1) in the bottom right. +// C0.X must be negative half-pixel width, C0.Y must be half-pixel height. C0.ZW must be 0. +VS_OUTPUT standardvs(in float4 position : POSITION) +{ + VS_OUTPUT Out; + + Out.position = position + halfPixelSize; + Out.texcoord = position * float4(0.5, -0.5, 1.0, 1.0) + float4(0.5, 0.5, 0, 0); + + return Out; +}; + +// Flip Y Vertex Shader +// Input 0 is the homogenous position. +// Outputs the homogenous position as-is. +// Outputs a tex coord with (0,1) in the upper-left corner of the screen and (1,0) in the bottom right. +// C0.XY must be the half-pixel width and height. C0.ZW must be 0. +VS_OUTPUT flipyvs(in float4 position : POSITION) +{ + VS_OUTPUT Out; + + Out.position = position + halfPixelSize; + Out.texcoord = position * float4(0.5, 0.5, 1.0, 1.0) + float4(0.5, 0.5, 0, 0); + + return Out; +}; diff --git a/src/3rdparty/angle/src/libGLESv2/utilities.cpp b/src/3rdparty/angle/src/libGLESv2/utilities.cpp new file mode 100644 index 0000000000..a3eb27d392 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/utilities.cpp @@ -0,0 +1,1218 @@ +// +// 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. +// + +// utilities.cpp: Conversion functions and other utility routines. + +#include "libGLESv2/utilities.h" + +#include <limits> +#include <stdio.h> +#include <windows.h> + +#include "common/debug.h" + +#include "libGLESv2/mathutil.h" +#include "libGLESv2/Context.h" + +namespace gl +{ + +// This is how much data the application expects for a uniform +int UniformExternalComponentCount(GLenum type) +{ + switch (type) + { + case GL_BOOL: + case GL_FLOAT: + case GL_INT: + case GL_SAMPLER_2D: + case GL_SAMPLER_CUBE: + return 1; + case GL_BOOL_VEC2: + case GL_FLOAT_VEC2: + case GL_INT_VEC2: + return 2; + case GL_INT_VEC3: + case GL_FLOAT_VEC3: + case GL_BOOL_VEC3: + return 3; + case GL_BOOL_VEC4: + case GL_FLOAT_VEC4: + case GL_INT_VEC4: + case GL_FLOAT_MAT2: + return 4; + case GL_FLOAT_MAT3: + return 9; + case GL_FLOAT_MAT4: + return 16; + default: + UNREACHABLE(); + } + + 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) + { + case GL_BOOL: + case GL_BOOL_VEC2: + case GL_BOOL_VEC3: + case GL_BOOL_VEC4: + return GL_BOOL; + 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: + return GL_FLOAT; + case GL_INT: + case GL_SAMPLER_2D: + case GL_SAMPLER_CUBE: + case GL_INT_VEC2: + case GL_INT_VEC3: + case GL_INT_VEC4: + return GL_INT; + default: + UNREACHABLE(); + } + + return GL_NONE; +} + +size_t UniformComponentSize(GLenum type) +{ + switch(type) + { + case GL_BOOL: return sizeof(GLint); + case GL_FLOAT: return sizeof(GLfloat); + case GL_INT: return sizeof(GLint); + default: UNREACHABLE(); + } + + 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) +{ + switch (type) + { + case GL_NONE: + return 0; + case GL_BOOL: + case GL_FLOAT: + case GL_INT: + case GL_BOOL_VEC2: + case GL_FLOAT_VEC2: + case GL_INT_VEC2: + case GL_INT_VEC3: + case GL_FLOAT_VEC3: + case GL_BOOL_VEC3: + case GL_BOOL_VEC4: + case GL_FLOAT_VEC4: + case GL_INT_VEC4: + return 1; + case GL_FLOAT_MAT2: + return 2; + case GL_FLOAT_MAT3: + return 3; + case GL_FLOAT_MAT4: + return 4; + default: + UNREACHABLE(); + } + + return 0; +} + +int VariableColumnCount(GLenum type) +{ + switch (type) + { + case GL_NONE: + return 0; + case GL_BOOL: + case GL_FLOAT: + case GL_INT: + return 1; + case GL_BOOL_VEC2: + case GL_FLOAT_VEC2: + case GL_INT_VEC2: + case GL_FLOAT_MAT2: + return 2; + case GL_INT_VEC3: + case GL_FLOAT_VEC3: + case GL_BOOL_VEC3: + case GL_FLOAT_MAT3: + return 3; + case GL_BOOL_VEC4: + case GL_FLOAT_VEC4: + case GL_INT_VEC4: + case GL_FLOAT_MAT4: + return 4; + default: + UNREACHABLE(); + } + + return 0; +} + +int AllocateFirstFreeBits(unsigned int *bits, unsigned int allocationSize, unsigned int bitsSize) +{ + ASSERT(allocationSize <= bitsSize); + + unsigned int mask = std::numeric_limits<unsigned int>::max() >> (std::numeric_limits<unsigned int>::digits - allocationSize); + + for (unsigned int i = 0; i < bitsSize - allocationSize + 1; i++) + { + if ((*bits & mask) == 0) + { + *bits |= mask; + return i; + } + + mask <<= 1; + } + + return -1; +} + +GLsizei ComputePitch(GLsizei width, GLint internalformat, GLint alignment) +{ + ASSERT(alignment > 0 && isPow2(alignment)); + + GLsizei rawPitch = ComputePixelSize(internalformat) * width; + return (rawPitch + alignment - 1) & ~(alignment - 1); +} + +GLsizei ComputeCompressedPitch(GLsizei width, GLenum internalformat) +{ + return ComputeCompressedSize(width, 1, internalformat); +} + +GLsizei ComputeCompressedSize(GLsizei width, GLsizei height, GLenum internalformat) +{ + switch (internalformat) + { + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + return 8 * ((width + 3) / 4) * ((height + 3) / 4); + case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: + case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: + return 16 * ((width + 3) / 4) * ((height + 3) / 4); + default: + return 0; + } +} + +bool IsCompressed(GLenum format) +{ + if(format == GL_COMPRESSED_RGB_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; + } + else + { + return false; + } +} + +bool IsDepthTexture(GLenum format) +{ + if (format == GL_DEPTH_COMPONENT || + format == GL_DEPTH_STENCIL_OES || + format == GL_DEPTH_COMPONENT16 || + format == GL_DEPTH_COMPONENT32_OES || + format == GL_DEPTH24_STENCIL8_OES) + { + return true; + } + + return false; +} + +bool IsStencilTexture(GLenum format) +{ + if (format == GL_DEPTH_STENCIL_OES || + format == GL_DEPTH24_STENCIL8_OES) + { + return true; + } + + return false; +} + +// Returns the size, in bytes, of a single texel in an Image +int ComputePixelSize(GLint internalformat) +{ + switch (internalformat) + { + case GL_ALPHA8_EXT: return sizeof(unsigned char); + case GL_LUMINANCE8_EXT: return sizeof(unsigned char); + case GL_ALPHA32F_EXT: return sizeof(float); + case GL_LUMINANCE32F_EXT: return sizeof(float); + case GL_ALPHA16F_EXT: return sizeof(unsigned short); + case GL_LUMINANCE16F_EXT: return sizeof(unsigned short); + case GL_LUMINANCE8_ALPHA8_EXT: return sizeof(unsigned char) * 2; + case GL_LUMINANCE_ALPHA32F_EXT: return sizeof(float) * 2; + case GL_LUMINANCE_ALPHA16F_EXT: return sizeof(unsigned short) * 2; + case GL_RGB8_OES: return sizeof(unsigned char) * 3; + case GL_RGB565: return sizeof(unsigned short); + case GL_RGB32F_EXT: return sizeof(float) * 3; + case GL_RGB16F_EXT: return sizeof(unsigned short) * 3; + case GL_RGBA8_OES: return sizeof(unsigned char) * 4; + case GL_RGBA4: return sizeof(unsigned short); + case GL_RGB5_A1: return sizeof(unsigned short); + case GL_RGBA32F_EXT: return sizeof(float) * 4; + case GL_RGBA16F_EXT: return sizeof(unsigned short) * 4; + case GL_BGRA8_EXT: return sizeof(unsigned char) * 4; + case GL_BGRA4_ANGLEX: return sizeof(unsigned short); + case GL_BGR5_A1_ANGLEX: return sizeof(unsigned short); + default: UNREACHABLE(); + } + + return 0; +} + +bool IsCubemapTextureTarget(GLenum target) +{ + return (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z); +} + +bool IsInternalTextureTarget(GLenum target) +{ + return target == GL_TEXTURE_2D || IsCubemapTextureTarget(target); +} + +GLint ConvertSizedInternalFormat(GLenum format, GLenum type) +{ + switch (format) + { + case GL_ALPHA: + switch (type) + { + case GL_UNSIGNED_BYTE: return GL_ALPHA8_EXT; + case GL_FLOAT: return GL_ALPHA32F_EXT; + case GL_HALF_FLOAT_OES: return GL_ALPHA16F_EXT; + default: UNIMPLEMENTED(); + } + break; + case GL_LUMINANCE: + switch (type) + { + case GL_UNSIGNED_BYTE: return GL_LUMINANCE8_EXT; + case GL_FLOAT: return GL_LUMINANCE32F_EXT; + case GL_HALF_FLOAT_OES: return GL_LUMINANCE16F_EXT; + default: UNIMPLEMENTED(); + } + break; + case GL_LUMINANCE_ALPHA: + switch (type) + { + case GL_UNSIGNED_BYTE: return GL_LUMINANCE8_ALPHA8_EXT; + case GL_FLOAT: return GL_LUMINANCE_ALPHA32F_EXT; + case GL_HALF_FLOAT_OES: return GL_LUMINANCE_ALPHA16F_EXT; + default: UNIMPLEMENTED(); + } + break; + case GL_RGB: + switch (type) + { + case GL_UNSIGNED_BYTE: return GL_RGB8_OES; + case GL_UNSIGNED_SHORT_5_6_5: return GL_RGB565; + case GL_FLOAT: return GL_RGB32F_EXT; + case GL_HALF_FLOAT_OES: return GL_RGB16F_EXT; + default: UNIMPLEMENTED(); + } + break; + case GL_RGBA: + switch (type) + { + case GL_UNSIGNED_BYTE: return GL_RGBA8_OES; + case GL_UNSIGNED_SHORT_4_4_4_4: return GL_RGBA4; + case GL_UNSIGNED_SHORT_5_5_5_1: return GL_RGB5_A1; + case GL_FLOAT: return GL_RGBA32F_EXT; + case GL_HALF_FLOAT_OES: return GL_RGBA16F_EXT; + break; + default: UNIMPLEMENTED(); + } + break; + case GL_BGRA_EXT: + switch (type) + { + case GL_UNSIGNED_BYTE: return GL_BGRA8_EXT; + case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT: return GL_BGRA4_ANGLEX; + case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT: return GL_BGR5_A1_ANGLEX; + default: UNIMPLEMENTED(); + } + 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 format; + case GL_DEPTH_COMPONENT: + switch (type) + { + case GL_UNSIGNED_SHORT: return GL_DEPTH_COMPONENT16; + case GL_UNSIGNED_INT: return GL_DEPTH_COMPONENT32_OES; + default: UNIMPLEMENTED(); + } + break; + case GL_DEPTH_STENCIL_OES: + switch (type) + { + case GL_UNSIGNED_INT_24_8_OES: return GL_DEPTH24_STENCIL8_OES; + default: UNIMPLEMENTED(); + } + break; + default: + UNIMPLEMENTED(); + } + + return GL_NONE; +} + +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; + case GL_DEPTH_COMPONENT16: return GL_DEPTH_COMPONENT; + case GL_DEPTH_COMPONENT32_OES: return GL_DEPTH_COMPONENT; + case GL_DEPTH24_STENCIL8_OES: return GL_DEPTH_STENCIL_OES; + 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; + case GL_DEPTH_COMPONENT16: return GL_UNSIGNED_SHORT; + case GL_DEPTH_COMPONENT32_OES: return GL_UNSIGNED_INT; + case GL_DEPTH24_STENCIL8_OES: return GL_UNSIGNED_INT_24_8_OES; + default: return GL_NONE; // Unsupported + } +} + +bool IsColorRenderable(GLenum internalformat) +{ + switch (internalformat) + { + case GL_RGBA4: + case GL_RGB5_A1: + case GL_RGB565: + case GL_RGB8_OES: + case GL_RGBA8_OES: + return true; + case GL_DEPTH_COMPONENT16: + case GL_STENCIL_INDEX8: + case GL_DEPTH24_STENCIL8_OES: + return false; + default: + UNIMPLEMENTED(); + } + + return false; +} + +bool IsDepthRenderable(GLenum internalformat) +{ + switch (internalformat) + { + case GL_DEPTH_COMPONENT16: + case GL_DEPTH24_STENCIL8_OES: + return true; + case GL_STENCIL_INDEX8: + case GL_RGBA4: + case GL_RGB5_A1: + case GL_RGB565: + case GL_RGB8_OES: + case GL_RGBA8_OES: + return false; + default: + UNIMPLEMENTED(); + } + + return false; +} + +bool IsStencilRenderable(GLenum internalformat) +{ + switch (internalformat) + { + case GL_STENCIL_INDEX8: + case GL_DEPTH24_STENCIL8_OES: + return true; + case GL_RGBA4: + case GL_RGB5_A1: + case GL_RGB565: + case GL_RGB8_OES: + case GL_RGBA8_OES: + case GL_DEPTH_COMPONENT16: + return false; + default: + UNIMPLEMENTED(); + } + + return false; +} + +bool IsFloat32Format(GLint internalformat) +{ + switch (internalformat) + { + case GL_RGBA32F_EXT: + case GL_RGB32F_EXT: + case GL_ALPHA32F_EXT: + case GL_LUMINANCE32F_EXT: + case GL_LUMINANCE_ALPHA32F_EXT: + return true; + default: + return false; + } +} + +bool IsFloat16Format(GLint internalformat) +{ + switch (internalformat) + { + case GL_RGBA16F_EXT: + case GL_RGB16F_EXT: + case GL_ALPHA16F_EXT: + case GL_LUMINANCE16F_EXT: + case GL_LUMINANCE_ALPHA16F_EXT: + return true; + default: + return false; + } +} + +} + +namespace es2dx +{ + +D3DCMPFUNC ConvertComparison(GLenum comparison) +{ + D3DCMPFUNC d3dComp = D3DCMP_ALWAYS; + switch (comparison) + { + case GL_NEVER: d3dComp = D3DCMP_NEVER; break; + case GL_ALWAYS: d3dComp = D3DCMP_ALWAYS; break; + case GL_LESS: d3dComp = D3DCMP_LESS; break; + case GL_LEQUAL: d3dComp = D3DCMP_LESSEQUAL; break; + case GL_EQUAL: d3dComp = D3DCMP_EQUAL; break; + case GL_GREATER: d3dComp = D3DCMP_GREATER; break; + case GL_GEQUAL: d3dComp = D3DCMP_GREATEREQUAL; break; + case GL_NOTEQUAL: d3dComp = D3DCMP_NOTEQUAL; break; + default: UNREACHABLE(); + } + + return d3dComp; +} + +D3DCOLOR ConvertColor(gl::Color color) +{ + return D3DCOLOR_RGBA(gl::unorm<8>(color.red), + gl::unorm<8>(color.green), + gl::unorm<8>(color.blue), + gl::unorm<8>(color.alpha)); +} + +D3DBLEND ConvertBlendFunc(GLenum blend) +{ + D3DBLEND d3dBlend = D3DBLEND_ZERO; + + switch (blend) + { + case GL_ZERO: d3dBlend = D3DBLEND_ZERO; break; + case GL_ONE: d3dBlend = D3DBLEND_ONE; break; + case GL_SRC_COLOR: d3dBlend = D3DBLEND_SRCCOLOR; break; + case GL_ONE_MINUS_SRC_COLOR: d3dBlend = D3DBLEND_INVSRCCOLOR; break; + case GL_DST_COLOR: d3dBlend = D3DBLEND_DESTCOLOR; break; + case GL_ONE_MINUS_DST_COLOR: d3dBlend = D3DBLEND_INVDESTCOLOR; break; + case GL_SRC_ALPHA: d3dBlend = D3DBLEND_SRCALPHA; break; + case GL_ONE_MINUS_SRC_ALPHA: d3dBlend = D3DBLEND_INVSRCALPHA; break; + case GL_DST_ALPHA: d3dBlend = D3DBLEND_DESTALPHA; break; + case GL_ONE_MINUS_DST_ALPHA: d3dBlend = D3DBLEND_INVDESTALPHA; break; + case GL_CONSTANT_COLOR: d3dBlend = D3DBLEND_BLENDFACTOR; break; + case GL_ONE_MINUS_CONSTANT_COLOR: d3dBlend = D3DBLEND_INVBLENDFACTOR; break; + case GL_CONSTANT_ALPHA: d3dBlend = D3DBLEND_BLENDFACTOR; break; + case GL_ONE_MINUS_CONSTANT_ALPHA: d3dBlend = D3DBLEND_INVBLENDFACTOR; break; + case GL_SRC_ALPHA_SATURATE: d3dBlend = D3DBLEND_SRCALPHASAT; break; + default: UNREACHABLE(); + } + + return d3dBlend; +} + +D3DBLENDOP ConvertBlendOp(GLenum blendOp) +{ + D3DBLENDOP d3dBlendOp = D3DBLENDOP_ADD; + + switch (blendOp) + { + case GL_FUNC_ADD: d3dBlendOp = D3DBLENDOP_ADD; break; + case GL_FUNC_SUBTRACT: d3dBlendOp = D3DBLENDOP_SUBTRACT; break; + case GL_FUNC_REVERSE_SUBTRACT: d3dBlendOp = D3DBLENDOP_REVSUBTRACT; break; + default: UNREACHABLE(); + } + + return d3dBlendOp; +} + +D3DSTENCILOP ConvertStencilOp(GLenum stencilOp) +{ + D3DSTENCILOP d3dStencilOp = D3DSTENCILOP_KEEP; + + switch (stencilOp) + { + case GL_ZERO: d3dStencilOp = D3DSTENCILOP_ZERO; break; + case GL_KEEP: d3dStencilOp = D3DSTENCILOP_KEEP; break; + case GL_REPLACE: d3dStencilOp = D3DSTENCILOP_REPLACE; break; + case GL_INCR: d3dStencilOp = D3DSTENCILOP_INCRSAT; break; + case GL_DECR: d3dStencilOp = D3DSTENCILOP_DECRSAT; break; + case GL_INVERT: d3dStencilOp = D3DSTENCILOP_INVERT; break; + case GL_INCR_WRAP: d3dStencilOp = D3DSTENCILOP_INCR; break; + case GL_DECR_WRAP: d3dStencilOp = D3DSTENCILOP_DECR; break; + default: UNREACHABLE(); + } + + return d3dStencilOp; +} + +D3DTEXTUREADDRESS ConvertTextureWrap(GLenum wrap) +{ + D3DTEXTUREADDRESS d3dWrap = D3DTADDRESS_WRAP; + + switch (wrap) + { + case GL_REPEAT: d3dWrap = D3DTADDRESS_WRAP; break; + case GL_CLAMP_TO_EDGE: d3dWrap = D3DTADDRESS_CLAMP; break; + case GL_MIRRORED_REPEAT: d3dWrap = D3DTADDRESS_MIRROR; break; + default: UNREACHABLE(); + } + + return d3dWrap; +} + +D3DCULL ConvertCullMode(GLenum cullFace, GLenum frontFace) +{ + D3DCULL cull = D3DCULL_CCW; + switch (cullFace) + { + case GL_FRONT: + cull = (frontFace == GL_CCW ? D3DCULL_CW : D3DCULL_CCW); + break; + case GL_BACK: + cull = (frontFace == GL_CCW ? D3DCULL_CCW : D3DCULL_CW); + break; + case GL_FRONT_AND_BACK: + cull = D3DCULL_NONE; // culling will be handled during draw + break; + default: UNREACHABLE(); + } + + return cull; +} + +D3DCUBEMAP_FACES ConvertCubeFace(GLenum cubeFace) +{ + D3DCUBEMAP_FACES face = D3DCUBEMAP_FACE_POSITIVE_X; + + 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_POSITIVE_Y; + break; + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + face = D3DCUBEMAP_FACE_NEGATIVE_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) | + (green ? D3DCOLORWRITEENABLE_GREEN : 0) | + (blue ? D3DCOLORWRITEENABLE_BLUE : 0) | + (alpha ? D3DCOLORWRITEENABLE_ALPHA : 0); +} + +D3DTEXTUREFILTERTYPE ConvertMagFilter(GLenum magFilter, float maxAnisotropy) +{ + if (maxAnisotropy > 1.0f) + { + return D3DTEXF_ANISOTROPIC; + } + + D3DTEXTUREFILTERTYPE d3dMagFilter = D3DTEXF_POINT; + switch (magFilter) + { + case GL_NEAREST: d3dMagFilter = D3DTEXF_POINT; break; + case GL_LINEAR: d3dMagFilter = D3DTEXF_LINEAR; break; + default: UNREACHABLE(); + } + + return d3dMagFilter; +} + +void ConvertMinFilter(GLenum minFilter, D3DTEXTUREFILTERTYPE *d3dMinFilter, D3DTEXTUREFILTERTYPE *d3dMipFilter, float maxAnisotropy) +{ + switch (minFilter) + { + case GL_NEAREST: + *d3dMinFilter = D3DTEXF_POINT; + *d3dMipFilter = D3DTEXF_NONE; + break; + case GL_LINEAR: + *d3dMinFilter = D3DTEXF_LINEAR; + *d3dMipFilter = D3DTEXF_NONE; + break; + case GL_NEAREST_MIPMAP_NEAREST: + *d3dMinFilter = D3DTEXF_POINT; + *d3dMipFilter = D3DTEXF_POINT; + break; + case GL_LINEAR_MIPMAP_NEAREST: + *d3dMinFilter = D3DTEXF_LINEAR; + *d3dMipFilter = D3DTEXF_POINT; + break; + case GL_NEAREST_MIPMAP_LINEAR: + *d3dMinFilter = D3DTEXF_POINT; + *d3dMipFilter = D3DTEXF_LINEAR; + break; + case GL_LINEAR_MIPMAP_LINEAR: + *d3dMinFilter = D3DTEXF_LINEAR; + *d3dMipFilter = D3DTEXF_LINEAR; + break; + default: + *d3dMinFilter = D3DTEXF_POINT; + *d3dMipFilter = D3DTEXF_NONE; + UNREACHABLE(); + } + + if (maxAnisotropy > 1.0f) + { + *d3dMinFilter = D3DTEXF_ANISOTROPIC; + } +} + +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_NONE: return D3DFMT_NULL; + 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) +{ + if (stencilFormat == D3DFMT_INTZ) + { + return 8; + } + switch(stencilFormat) + { + case D3DFMT_D24FS8: + case D3DFMT_D24S8: + return 8; + case D3DFMT_D24X4S4: + return 4; + case D3DFMT_D15S1: + return 1; + case D3DFMT_D16_LOCKABLE: + case D3DFMT_D32: + case D3DFMT_D24X8: + 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: + return 0; + } +} + +unsigned int GetAlphaSize(D3DFORMAT colorFormat) +{ + switch (colorFormat) + { + case D3DFMT_A16B16G16R16F: + return 16; + case D3DFMT_A32B32G32R32F: + return 32; + case D3DFMT_A2R10G10B10: + return 2; + case D3DFMT_A8R8G8B8: + return 8; + case D3DFMT_A1R5G5B5: + return 1; + case D3DFMT_X8R8G8B8: + case D3DFMT_R5G6B5: + return 0; + default: + return 0; + } +} + +unsigned int GetRedSize(D3DFORMAT colorFormat) +{ + switch (colorFormat) + { + case D3DFMT_A16B16G16R16F: + return 16; + case D3DFMT_A32B32G32R32F: + return 32; + case D3DFMT_A2R10G10B10: + return 10; + case D3DFMT_A8R8G8B8: + case D3DFMT_X8R8G8B8: + return 8; + case D3DFMT_A1R5G5B5: + case D3DFMT_R5G6B5: + return 5; + default: + return 0; + } +} + +unsigned int GetGreenSize(D3DFORMAT colorFormat) +{ + switch (colorFormat) + { + case D3DFMT_A16B16G16R16F: + return 16; + case D3DFMT_A32B32G32R32F: + return 32; + case D3DFMT_A2R10G10B10: + return 10; + case D3DFMT_A8R8G8B8: + case D3DFMT_X8R8G8B8: + return 8; + case D3DFMT_A1R5G5B5: + return 5; + case D3DFMT_R5G6B5: + return 6; + default: + return 0; + } +} + +unsigned int GetBlueSize(D3DFORMAT colorFormat) +{ + switch (colorFormat) + { + case D3DFMT_A16B16G16R16F: + return 16; + case D3DFMT_A32B32G32R32F: + return 32; + case D3DFMT_A2R10G10B10: + return 10; + case D3DFMT_A8R8G8B8: + case D3DFMT_X8R8G8B8: + return 8; + case D3DFMT_A1R5G5B5: + case D3DFMT_R5G6B5: + return 5; + default: + return 0; + } +} + +unsigned int GetDepthSize(D3DFORMAT depthFormat) +{ + if (depthFormat == D3DFMT_INTZ) + { + return 24; + } + switch (depthFormat) + { + case D3DFMT_D16_LOCKABLE: return 16; + case D3DFMT_D32: return 32; + case D3DFMT_D15S1: return 15; + case D3DFMT_D24S8: return 24; + case D3DFMT_D24X8: return 24; + case D3DFMT_D24X4S4: return 24; + case D3DFMT_D16: return 16; + case D3DFMT_D32F_LOCKABLE: return 32; + case D3DFMT_D24FS8: return 24; + //case D3DFMT_D32_LOCKABLE: return 32; // D3D9Ex only + //case D3DFMT_S8_LOCKABLE: return 0; // D3D9Ex only + default: return 0; + } +} + +GLsizei GetSamplesFromMultisampleType(D3DMULTISAMPLE_TYPE type) +{ + if (type == D3DMULTISAMPLE_NONMASKABLE) + return 0; + else + return type; +} + +bool IsFormatChannelEquivalent(D3DFORMAT d3dformat, GLenum format) +{ + switch (d3dformat) + { + case D3DFMT_L8: + return (format == GL_LUMINANCE); + case D3DFMT_A8L8: + return (format == GL_LUMINANCE_ALPHA); + case D3DFMT_DXT1: + return (format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT || format == GL_COMPRESSED_RGB_S3TC_DXT1_EXT); + case D3DFMT_DXT3: + return (format == GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE); + case D3DFMT_DXT5: + return (format == GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE); + case D3DFMT_A8R8G8B8: + case D3DFMT_A16B16G16R16F: + case D3DFMT_A32B32G32R32F: + return (format == GL_RGBA || format == GL_BGRA_EXT); + case D3DFMT_X8R8G8B8: + return (format == GL_RGB); + default: + if (d3dformat == D3DFMT_INTZ && gl::IsDepthTexture(format)) + return true; + return false; + } +} + +bool ConvertReadBufferFormat(D3DFORMAT d3dformat, GLenum *format, GLenum *type) +{ + switch (d3dformat) + { + case D3DFMT_A8R8G8B8: + *type = GL_UNSIGNED_BYTE; + *format = GL_BGRA_EXT; + break; + case D3DFMT_X8R8G8B8: + *type = GL_UNSIGNED_BYTE; + *format = GL_RGB; + break; + case D3DFMT_R5G6B5: + *type = GL_UNSIGNED_SHORT_5_6_5; + *format = GL_RGB; + break; + case D3DFMT_A16B16G16R16F: + *type = GL_HALF_FLOAT_OES; + *format = GL_RGBA; + break; + case D3DFMT_A32B32G32R32F: + *type = GL_FLOAT; + *format = GL_RGBA; + break; + case D3DFMT_A4R4G4B4: + *type = GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT; + *format = GL_BGRA_EXT; + break; + case D3DFMT_A1R5G5B5: + *type = GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT; + *format = GL_BGRA_EXT; + break; + default: + *type = GL_NONE; + *format = GL_NONE; + return false; + } + return true; +} + +GLenum ConvertBackBufferFormat(D3DFORMAT format) +{ + switch (format) + { + case D3DFMT_A4R4G4B4: return GL_RGBA4; + case D3DFMT_A8R8G8B8: return GL_RGBA8_OES; + case D3DFMT_A1R5G5B5: return GL_RGB5_A1; + case D3DFMT_R5G6B5: return GL_RGB565; + case D3DFMT_X8R8G8B8: return GL_RGB8_OES; + default: + UNREACHABLE(); + } + + return GL_RGBA4; +} + +GLenum ConvertDepthStencilFormat(D3DFORMAT format) +{ + if (format == D3DFMT_INTZ) + { + return GL_DEPTH24_STENCIL8_OES; + } + switch (format) + { + case D3DFMT_D16: + case D3DFMT_D24X8: + return GL_DEPTH_COMPONENT16; + case D3DFMT_D24S8: + return GL_DEPTH24_STENCIL8_OES; + default: + UNREACHABLE(); + } + + return GL_DEPTH24_STENCIL8_OES; +} + +} + +namespace dx +{ + +bool IsCompressedFormat(D3DFORMAT surfaceFormat) +{ + switch(surfaceFormat) + { + case D3DFMT_DXT1: + case D3DFMT_DXT2: + case D3DFMT_DXT3: + case D3DFMT_DXT4: + case D3DFMT_DXT5: + return true; + default: + return false; + } +} + +size_t ComputeRowSize(D3DFORMAT format, unsigned int width) +{ + if (format == D3DFMT_INTZ) + { + return 4 * width; + } + switch (format) + { + case D3DFMT_L8: + return 1 * width; + case D3DFMT_A8L8: + return 2 * width; + case D3DFMT_X8R8G8B8: + case D3DFMT_A8R8G8B8: + return 4 * width; + case D3DFMT_A16B16G16R16F: + return 8 * width; + case D3DFMT_A32B32G32R32F: + return 16 * width; + case D3DFMT_DXT1: + return 8 * ((width + 3) / 4); + case D3DFMT_DXT3: + case D3DFMT_DXT5: + return 16 * ((width + 3) / 4); + default: + UNREACHABLE(); + return 0; + } +} + +} + +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/src/3rdparty/angle/src/libGLESv2/utilities.h b/src/3rdparty/angle/src/libGLESv2/utilities.h new file mode 100644 index 0000000000..29ad207313 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/utilities.h @@ -0,0 +1,121 @@ +// +// 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. +// + +// utilities.h: Conversion functions and other utility routines. + +#ifndef LIBGLESV2_UTILITIES_H +#define LIBGLESV2_UTILITIES_H + +#define GL_APICALL +#include <GLES2/gl2.h> +#include <GLES2/gl2ext.h> +#include <d3d9.h> + +#include <string> + +const D3DFORMAT D3DFMT_INTZ = ((D3DFORMAT)(MAKEFOURCC('I','N','T','Z'))); +const D3DFORMAT D3DFMT_NULL = ((D3DFORMAT)(MAKEFOURCC('N','U','L','L'))); + +namespace gl +{ + +struct Color; + +int UniformExternalComponentCount(GLenum type); +int UniformInternalComponentCount(GLenum type); +GLenum UniformComponentType(GLenum type); +size_t UniformInternalSize(GLenum type); +size_t UniformExternalSize(GLenum type); +int VariableRowCount(GLenum type); +int VariableColumnCount(GLenum type); + +int AllocateFirstFreeBits(unsigned int *bits, unsigned int allocationSize, unsigned int bitsSize); + +int ComputePixelSize(GLint internalformat); +GLsizei ComputePitch(GLsizei width, GLint internalformat, GLint alignment); +GLsizei ComputeCompressedPitch(GLsizei width, GLenum format); +GLsizei ComputeCompressedSize(GLsizei width, GLsizei height, GLenum format); +bool IsCompressed(GLenum format); +bool IsDepthTexture(GLenum format); +bool IsStencilTexture(GLenum format); +bool IsCubemapTextureTarget(GLenum target); +bool IsInternalTextureTarget(GLenum target); +GLint ConvertSizedInternalFormat(GLenum format, GLenum type); +GLenum ExtractFormat(GLenum internalformat); +GLenum ExtractType(GLenum internalformat); + +bool IsColorRenderable(GLenum internalformat); +bool IsDepthRenderable(GLenum internalformat); +bool IsStencilRenderable(GLenum internalformat); + +bool IsFloat32Format(GLint internalformat); +bool IsFloat16Format(GLint internalformat); +} + +namespace es2dx +{ + +D3DCMPFUNC ConvertComparison(GLenum comparison); +D3DCOLOR ConvertColor(gl::Color color); +D3DBLEND ConvertBlendFunc(GLenum blend); +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, float maxAnisotropy); +void ConvertMinFilter(GLenum minFilter, D3DTEXTUREFILTERTYPE *d3dMinFilter, D3DTEXTUREFILTERTYPE *d3dMipFilter, float maxAnisotropy); +bool ConvertPrimitiveType(GLenum primitiveType, GLsizei elementCount, + D3DPRIMITIVETYPE *d3dPrimitiveType, int *d3dPrimitiveCount); +D3DFORMAT ConvertRenderbufferFormat(GLenum format); +D3DMULTISAMPLE_TYPE GetMultisampleTypeFromSamples(GLsizei samples); + +} + +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); + +GLsizei GetSamplesFromMultisampleType(D3DMULTISAMPLE_TYPE type); + +bool IsFormatChannelEquivalent(D3DFORMAT d3dformat, GLenum format); +bool ConvertReadBufferFormat(D3DFORMAT d3dformat, GLenum *format, GLenum *type); +GLenum ConvertBackBufferFormat(D3DFORMAT format); +GLenum ConvertDepthStencilFormat(D3DFORMAT format); + +} + +namespace dx +{ +bool IsCompressedFormat(D3DFORMAT format); +size_t ComputeRowSize(D3DFORMAT format, unsigned int width); +} + +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/src/3rdparty/angle/src/libGLESv2/vertexconversion.h b/src/3rdparty/angle/src/libGLESv2/vertexconversion.h new file mode 100644 index 0000000000..5bb8b8995e --- /dev/null +++ b/src/3rdparty/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_ |