summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/angle/src/libGLESv2
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdparty/angle/src/libGLESv2')
-rw-r--r--src/3rdparty/angle/src/libGLESv2/BinaryStream.h167
-rw-r--r--src/3rdparty/angle/src/libGLESv2/Blit.cpp518
-rw-r--r--src/3rdparty/angle/src/libGLESv2/Blit.h94
-rw-r--r--src/3rdparty/angle/src/libGLESv2/Buffer.cpp117
-rw-r--r--src/3rdparty/angle/src/libGLESv2/Buffer.h61
-rw-r--r--src/3rdparty/angle/src/libGLESv2/Context.cpp4501
-rw-r--r--src/3rdparty/angle/src/libGLESv2/Context.h685
-rw-r--r--src/3rdparty/angle/src/libGLESv2/D3DConstantTable.cpp231
-rw-r--r--src/3rdparty/angle/src/libGLESv2/D3DConstantTable.h117
-rw-r--r--src/3rdparty/angle/src/libGLESv2/Fence.cpp132
-rw-r--r--src/3rdparty/angle/src/libGLESv2/Fence.h49
-rw-r--r--src/3rdparty/angle/src/libGLESv2/Float16ToFloat32.cpp2203
-rw-r--r--src/3rdparty/angle/src/libGLESv2/Float16ToFloat32.py78
-rw-r--r--src/3rdparty/angle/src/libGLESv2/Framebuffer.cpp509
-rw-r--r--src/3rdparty/angle/src/libGLESv2/Framebuffer.h98
-rw-r--r--src/3rdparty/angle/src/libGLESv2/HandleAllocator.cpp63
-rw-r--r--src/3rdparty/angle/src/libGLESv2/HandleAllocator.h45
-rw-r--r--src/3rdparty/angle/src/libGLESv2/IndexDataManager.cpp473
-rw-r--r--src/3rdparty/angle/src/libGLESv2/IndexDataManager.h149
-rw-r--r--src/3rdparty/angle/src/libGLESv2/Program.cpp528
-rw-r--r--src/3rdparty/angle/src/libGLESv2/Program.h121
-rw-r--r--src/3rdparty/angle/src/libGLESv2/ProgramBinary.cpp2794
-rw-r--r--src/3rdparty/angle/src/libGLESv2/ProgramBinary.h235
-rw-r--r--src/3rdparty/angle/src/libGLESv2/Query.cpp128
-rw-r--r--src/3rdparty/angle/src/libGLESv2/Query.h48
-rw-r--r--src/3rdparty/angle/src/libGLESv2/Renderbuffer.cpp577
-rw-r--r--src/3rdparty/angle/src/libGLESv2/Renderbuffer.h257
-rw-r--r--src/3rdparty/angle/src/libGLESv2/ResourceManager.cpp320
-rw-r--r--src/3rdparty/angle/src/libGLESv2/ResourceManager.h116
-rw-r--r--src/3rdparty/angle/src/libGLESv2/Shader.cpp584
-rw-r--r--src/3rdparty/angle/src/libGLESv2/Shader.h166
-rw-r--r--src/3rdparty/angle/src/libGLESv2/Texture.cpp3118
-rw-r--r--src/3rdparty/angle/src/libGLESv2/Texture.h433
-rw-r--r--src/3rdparty/angle/src/libGLESv2/TextureSSE2.cpp100
-rw-r--r--src/3rdparty/angle/src/libGLESv2/VertexDataManager.cpp783
-rw-r--r--src/3rdparty/angle/src/libGLESv2/VertexDataManager.h169
-rw-r--r--src/3rdparty/angle/src/libGLESv2/libGLESv2.cpp7002
-rw-r--r--src/3rdparty/angle/src/libGLESv2/libGLESv2.def182
-rw-r--r--src/3rdparty/angle/src/libGLESv2/libGLESv2.rc102
-rw-r--r--src/3rdparty/angle/src/libGLESv2/main.cpp176
-rw-r--r--src/3rdparty/angle/src/libGLESv2/main.h50
-rw-r--r--src/3rdparty/angle/src/libGLESv2/mathutil.h145
-rw-r--r--src/3rdparty/angle/src/libGLESv2/resource.h14
-rw-r--r--src/3rdparty/angle/src/libGLESv2/shaders/Blit.ps39
-rw-r--r--src/3rdparty/angle/src/libGLESv2/shaders/Blit.vs43
-rw-r--r--src/3rdparty/angle/src/libGLESv2/utilities.cpp1218
-rw-r--r--src/3rdparty/angle/src/libGLESv2/utilities.h121
-rw-r--r--src/3rdparty/angle/src/libGLESv2/vertexconversion.h208
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(&currentIdentifier->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(&currentFormat, &currentType))
+ 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(&currentFormat, &currentType))
+ 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_