Copy libGLESv2 to libGLES_CM.
BUG=18110152
Change-Id: Ibf9b8c47e2d7c145d844ac4e69d6a20a7342d5db
Reviewed-on: https://swiftshader-review.googlesource.com/1230
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
Tested-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/src/GLES2/libGLES_CM/Buffer.cpp b/src/GLES2/libGLES_CM/Buffer.cpp
new file mode 100644
index 0000000..fc535ac
--- /dev/null
+++ b/src/GLES2/libGLES_CM/Buffer.cpp
@@ -0,0 +1,83 @@
+// SwiftShader Software Renderer
+//
+// Copyright(c) 2005-2013 TransGaming Inc.
+//
+// All rights reserved. No part of this software may be copied, distributed, transmitted,
+// transcribed, stored in a retrieval system, translated into any human or computer
+// language by any means, or disclosed to third parties without the explicit written
+// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
+// or implied, including but not limited to any patent rights, are granted to you.
+//
+
+// Buffer.cpp: Implements the 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 "Buffer.h"
+
+#include "main.h"
+#include "VertexDataManager.h"
+#include "IndexDataManager.h"
+
+namespace gl
+{
+
+Buffer::Buffer(GLuint id) : RefCountObject(id)
+{
+ mContents = 0;
+ mSize = 0;
+ mUsage = GL_DYNAMIC_DRAW;
+}
+
+Buffer::~Buffer()
+{
+ if(mContents)
+ {
+ mContents->destruct();
+ }
+}
+
+void Buffer::bufferData(const void *data, GLsizeiptr size, GLenum usage)
+{
+ if(mContents)
+ {
+ mContents->destruct();
+ mContents = 0;
+ }
+
+ mSize = size;
+ mUsage = usage;
+
+ if(size > 0)
+ {
+ const int padding = 1024; // For SIMD processing of vertices
+ mContents = new sw::Resource(size + padding);
+
+ if(!mContents)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+
+ if(data)
+ {
+ memcpy((void*)mContents->getBuffer(), data, size);
+ }
+ }
+}
+
+void Buffer::bufferSubData(const void *data, GLsizeiptr size, GLintptr offset)
+{
+ if(mContents)
+ {
+ char *buffer = (char*)mContents->lock(sw::PUBLIC);
+ memcpy(buffer + offset, data, size);
+ mContents->unlock();
+ }
+}
+
+sw::Resource *Buffer::getResource()
+{
+ return mContents;
+}
+
+}
diff --git a/src/GLES2/libGLES_CM/Buffer.h b/src/GLES2/libGLES_CM/Buffer.h
new file mode 100644
index 0000000..91580e6
--- /dev/null
+++ b/src/GLES2/libGLES_CM/Buffer.h
@@ -0,0 +1,54 @@
+// SwiftShader Software Renderer
+//
+// Copyright(c) 2005-2012 TransGaming Inc.
+//
+// All rights reserved. No part of this software may be copied, distributed, transmitted,
+// transcribed, stored in a retrieval system, translated into any human or computer
+// language by any means, or disclosed to third parties without the explicit written
+// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
+// or implied, including but not limited to any patent rights, are granted to you.
+//
+
+// Buffer.h: Defines the 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 "RefCountObject.h"
+#include "Common/Resource.hpp"
+
+#define GL_APICALL
+#include <GLES2/gl2.h>
+
+#include <cstddef>
+#include <vector>
+
+namespace gl
+{
+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);
+
+ const void *data() { return mContents ? mContents->getBuffer() : 0; }
+ size_t size() const { return mSize; }
+ GLenum usage() const { return mUsage; }
+
+ sw::Resource *getResource();
+
+ private:
+ sw::Resource *mContents;
+ size_t mSize;
+ GLenum mUsage;
+};
+
+}
+
+#endif // LIBGLESV2_BUFFER_H_
diff --git a/src/GLES2/libGLES_CM/Context.cpp b/src/GLES2/libGLES_CM/Context.cpp
new file mode 100644
index 0000000..2eba52e
--- /dev/null
+++ b/src/GLES2/libGLES_CM/Context.cpp
@@ -0,0 +1,3052 @@
+// SwiftShader Software Renderer
+//
+// Copyright(c) 2005-2013 TransGaming Inc.
+//
+// All rights reserved. No part of this software may be copied, distributed, transmitted,
+// transcribed, stored in a retrieval system, translated into any human or computer
+// language by any means, or disclosed to third parties without the explicit written
+// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
+// or implied, including but not limited to any patent rights, are granted to you.
+//
+
+// Context.cpp: Implements the gl::Context class, managing all GL state and performing
+// rendering operations. It is the GLES2 specific implementation of EGLContext.
+
+#include "Context.h"
+
+#include "main.h"
+#include "mathutil.h"
+#include "utilities.h"
+#include "ResourceManager.h"
+#include "Buffer.h"
+#include "Fence.h"
+#include "Framebuffer.h"
+#include "Program.h"
+#include "Query.h"
+#include "Renderbuffer.h"
+#include "Shader.h"
+#include "Texture.h"
+#include "VertexDataManager.h"
+#include "IndexDataManager.h"
+#include "libEGL/Display.h"
+#include "Common/Half.hpp"
+
+#undef near
+#undef far
+
+namespace gl
+{
+Context::Context(const egl::Config *config, const Context *shareContext) : mConfig(config)
+{
+ 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));
+ mTextureExternalZero.set(new TextureExternal(0));
+
+ mState.activeSampler = 0;
+ bindArrayBuffer(0);
+ bindElementArrayBuffer(0);
+ bindTextureCubeMap(0);
+ bindTexture2D(0);
+ bindReadFramebuffer(0);
+ bindDrawFramebuffer(0);
+ bindRenderbuffer(0);
+
+ mState.currentProgram = 0;
+
+ mState.packAlignment = 4;
+ mState.unpackAlignment = 4;
+
+ mVertexDataManager = NULL;
+ mIndexDataManager = NULL;
+
+ mInvalidEnum = false;
+ mInvalidValue = false;
+ mInvalidOperation = false;
+ mOutOfMemory = false;
+ mInvalidFramebufferOperation = false;
+
+ mHasBeenCurrent = false;
+
+ markAllStateDirty();
+}
+
+Context::~Context()
+{
+ if(mState.currentProgram != 0)
+ {
+ Program *programObject = mResourceManager->getProgram(mState.currentProgram);
+ if(programObject)
+ {
+ programObject->release();
+ }
+ mState.currentProgram = 0;
+ }
+
+ while(!mFramebufferMap.empty())
+ {
+ deleteFramebuffer(mFramebufferMap.begin()->first);
+ }
+
+ while(!mFenceMap.empty())
+ {
+ deleteFence(mFenceMap.begin()->first);
+ }
+
+ while(!mQueryMap.empty())
+ {
+ deleteQuery(mQueryMap.begin()->first);
+ }
+
+ for(int type = 0; type < TEXTURE_TYPE_COUNT; type++)
+ {
+ for(int sampler = 0; sampler < MAX_COMBINED_TEXTURE_IMAGE_UNITS; sampler++)
+ {
+ mState.samplerTexture[type][sampler].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);
+ mTextureExternalZero.set(NULL);
+
+ delete mVertexDataManager;
+ delete mIndexDataManager;
+
+ mResourceManager->release();
+}
+
+void Context::makeCurrent(egl::Display *display, egl::Surface *surface)
+{
+ Device *device = display->getDevice();
+
+ if(!mHasBeenCurrent)
+ {
+ mVertexDataManager = new VertexDataManager(this);
+ mIndexDataManager = new IndexDataManager();
+
+ 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 resources into GL objects and assign them to the '0' names
+ Image *defaultRenderTarget = surface->getRenderTarget();
+ Image *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();
+ }
+
+ 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()
+{
+ mAppliedProgramSerial = 0;
+
+ mDepthStateDirty = true;
+ mMaskStateDirty = true;
+ mBlendStateDirty = true;
+ mStencilStateDirty = true;
+ mPolygonOffsetStateDirty = true;
+ mSampleStateDirty = true;
+ mDitherStateDirty = true;
+ mFrontFaceDirty = true;
+}
+
+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)
+{
+ mState.cullFace = enabled;
+}
+
+bool Context::isCullFaceEnabled() const
+{
+ return mState.cullFace;
+}
+
+void Context::setCullMode(GLenum mode)
+{
+ mState.cullMode = mode;
+}
+
+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)
+{
+ mState.scissorTest = enabled;
+}
+
+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)
+{
+ mState.scissorX = x;
+ mState.scissorY = y;
+ mState.scissorWidth = width;
+ mState.scissorHeight = height;
+}
+
+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();
+ }
+
+ 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;
+}
+
+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;
+
+ 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 getFramebuffer(mState.drawFramebuffer);
+}
+
+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::bindTextureExternal(GLuint texture)
+{
+ mResourceManager->checkTextureAllocation(texture, TEXTURE_EXTERNAL);
+
+ mState.samplerTexture[TEXTURE_EXTERNAL][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;
+}
+
+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);
+
+ if(newProgram)
+ {
+ newProgram->addRef();
+ }
+
+ if(oldProgram)
+ {
+ oldProgram->release();
+ }
+ }
+}
+
+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);
+ }
+
+ 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);
+ }
+
+ 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;
+}
+
+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();
+}
+
+Program *Context::getCurrentProgram()
+{
+ return mResourceManager->getProgram(mState.currentProgram);
+}
+
+Texture2D *Context::getTexture2D()
+{
+ return static_cast<Texture2D*>(getSamplerTexture(mState.activeSampler, TEXTURE_2D));
+}
+
+TextureCubeMap *Context::getTextureCubeMap()
+{
+ return static_cast<TextureCubeMap*>(getSamplerTexture(mState.activeSampler, TEXTURE_CUBE));
+}
+
+TextureExternal *Context::getTextureExternal()
+{
+ return static_cast<TextureExternal*>(getSamplerTexture(mState.activeSampler, TEXTURE_EXTERNAL));
+}
+
+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)
+ {
+ case TEXTURE_2D: return mTexture2DZero.get();
+ case TEXTURE_CUBE: return mTextureCubeMapZero.get();
+ case TEXTURE_EXTERNAL: return mTextureExternalZero.get();
+ default: UNREACHABLE();
+ }
+ }
+
+ 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;
+ 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] = ALIASED_LINE_WIDTH_RANGE_MIN;
+ params[1] = ALIASED_LINE_WIDTH_RANGE_MAX;
+ break;
+ case GL_ALIASED_POINT_SIZE_RANGE:
+ params[0] = ALIASED_POINT_SIZE_RANGE_MIN;
+ params[1] = ALIASED_POINT_SIZE_RANGE_MAX;
+ 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:
+ *params = MAX_TEXTURE_MAX_ANISOTROPY;
+ 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 = MAX_VERTEX_ATTRIBS; break;
+ case GL_MAX_VERTEX_UNIFORM_VECTORS: *params = MAX_VERTEX_UNIFORM_VECTORS; break;
+ case GL_MAX_VARYING_VECTORS: *params = MAX_VARYING_VECTORS; break;
+ case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: *params = MAX_COMBINED_TEXTURE_IMAGE_UNITS; break;
+ case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS: *params = MAX_VERTEX_TEXTURE_IMAGE_UNITS; break;
+ case GL_MAX_TEXTURE_IMAGE_UNITS: *params = MAX_TEXTURE_IMAGE_UNITS; break;
+ case GL_MAX_FRAGMENT_UNIFORM_VECTORS: *params = MAX_FRAGMENT_UNIFORM_VECTORS; break;
+ case GL_MAX_RENDERBUFFER_SIZE: *params = IMPLEMENTATION_MAX_RENDERBUFFER_SIZE; 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_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 = IMPLEMENTATION_MAX_TEXTURE_SIZE; break;
+ case GL_MAX_CUBE_MAP_TEXTURE_SIZE: *params = IMPLEMENTATION_MAX_CUBE_MAP_TEXTURE_SIZE; break;
+ case GL_NUM_COMPRESSED_TEXTURE_FORMATS:
+ {
+ if(S3TC_SUPPORT)
+ {
+ // GL_COMPRESSED_RGB_S3TC_DXT1_EXT
+ // GL_COMPRESSED_RGBA_S3TC_DXT1_EXT
+ // GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE
+ // GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE
+ *params = 4;
+ }
+ else
+ {
+ *params = 0;
+ }
+ }
+ break;
+ case GL_MAX_SAMPLES_ANGLE: *params = IMPLEMENTATION_MAX_SAMPLES; break;
+ case GL_SAMPLE_BUFFERS:
+ case GL_SAMPLES:
+ {
+ Framebuffer *framebuffer = getDrawFramebuffer();
+ int width, height, samples;
+
+ if(framebuffer->completeness(width, height, samples) == GL_FRAMEBUFFER_COMPLETE)
+ {
+ switch(pname)
+ {
+ case GL_SAMPLE_BUFFERS:
+ if(samples > 1)
+ {
+ *params = 1;
+ }
+ else
+ {
+ *params = 0;
+ }
+ break;
+ case GL_SAMPLES:
+ *params = samples & ~1;
+ break;
+ }
+ }
+ else
+ {
+ *params = 0;
+ }
+ }
+ break;
+ case GL_IMPLEMENTATION_COLOR_READ_TYPE: *params = IMPLEMENTATION_COLOR_READ_TYPE; break;
+ case GL_IMPLEMENTATION_COLOR_READ_FORMAT: *params = IMPLEMENTATION_COLOR_READ_FORMAT; break;
+ case GL_MAX_VIEWPORT_DIMS:
+ {
+ int maxDimension = IMPLEMENTATION_MAX_RENDERBUFFER_SIZE;
+ params[0] = maxDimension;
+ params[1] = maxDimension;
+ }
+ break;
+ case GL_COMPRESSED_TEXTURE_FORMATS:
+ {
+ if(S3TC_SUPPORT)
+ {
+ params[0] = GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
+ params[1] = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
+ params[2] = GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE;
+ params[3] = 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:
+ {
+ Framebuffer *framebuffer = getDrawFramebuffer();
+ 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:
+ {
+ Framebuffer *framebuffer = getDrawFramebuffer();
+ Renderbuffer *depthbuffer = framebuffer->getDepthbuffer();
+
+ if(depthbuffer)
+ {
+ *params = depthbuffer->getDepthSize();
+ }
+ else
+ {
+ *params = 0;
+ }
+ }
+ break;
+ case GL_STENCIL_BITS:
+ {
+ Framebuffer *framebuffer = getDrawFramebuffer();
+ Renderbuffer *stencilbuffer = framebuffer->getStencilbuffer();
+
+ if(stencilbuffer)
+ {
+ *params = stencilbuffer->getStencilSize();
+ }
+ else
+ {
+ *params = 0;
+ }
+ }
+ break;
+ case GL_TEXTURE_BINDING_2D:
+ {
+ if(mState.activeSampler < 0 || mState.activeSampler > MAX_COMBINED_TEXTURE_IMAGE_UNITS - 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 > MAX_COMBINED_TEXTURE_IMAGE_UNITS - 1)
+ {
+ error(GL_INVALID_OPERATION);
+ return false;
+ }
+
+ *params = mState.samplerTexture[TEXTURE_CUBE][mState.activeSampler].id();
+ }
+ break;
+ case GL_TEXTURE_BINDING_EXTERNAL_OES:
+ {
+ if(mState.activeSampler < 0 || mState.activeSampler > MAX_COMBINED_TEXTURE_IMAGE_UNITS - 1)
+ {
+ error(GL_INVALID_OPERATION);
+ return false;
+ }
+
+ *params = mState.samplerTexture[TEXTURE_EXTERNAL][mState.activeSampler].id();
+ }
+ 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 = S3TC_SUPPORT ? 4 : 0;
+ }
+ 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_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_TEXTURE_BINDING_EXTERNAL_OES:
+ {
+ *type = GL_INT;
+ *numParams = 1;
+ }
+ break;
+ case GL_MAX_SAMPLES_ANGLE:
+ {
+ *type = GL_INT;
+ *numParams = 1;
+ }
+ 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:
+ {
+ *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:
+ *type = GL_FLOAT;
+ *numParams = 1;
+ break;
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+// Applies the render target surface, depth stencil surface, viewport rectangle and scissor rectangle
+bool Context::applyRenderTarget()
+{
+ Device *device = getDevice();
+ Framebuffer *framebuffer = getDrawFramebuffer();
+ int width, height, samples;
+
+ if(!framebuffer || framebuffer->completeness(width, height, samples) != GL_FRAMEBUFFER_COMPLETE)
+ {
+ return error(GL_INVALID_FRAMEBUFFER_OPERATION, false);
+ }
+
+ Image *renderTarget = framebuffer->getRenderTarget();
+ device->setRenderTarget(renderTarget);
+ if(renderTarget) renderTarget->release();
+
+ Image *depthStencil = framebuffer->getDepthStencil();
+ device->setDepthStencilSurface(depthStencil);
+ if(depthStencil) depthStencil->release();
+
+ Viewport viewport;
+ float zNear = clamp01(mState.zNear);
+ float zFar = clamp01(mState.zFar);
+
+ viewport.x0 = mState.viewportX;
+ viewport.y0 = mState.viewportY;
+ viewport.width = mState.viewportWidth;
+ viewport.height = mState.viewportHeight;
+ viewport.minZ = zNear;
+ viewport.maxZ = zFar;
+
+ device->setViewport(viewport);
+
+ if(mState.scissorTest)
+ {
+ sw::Rect scissor = {mState.scissorX, mState.scissorY, mState.scissorX + mState.scissorWidth, mState.scissorY + mState.scissorHeight};
+ scissor.clip(0, 0, width, height);
+
+ device->setScissorRect(scissor);
+ device->setScissorEnable(true);
+ }
+ else
+ {
+ device->setScissorEnable(false);
+ }
+
+ Program *program = getCurrentProgram();
+
+ if(program)
+ {
+ GLfloat nearFarDiff[3] = {zNear, zFar, zFar - zNear};
+ program->setUniform1fv(program->getUniformLocation("gl_DepthRange.near"), 1, &nearFarDiff[0]);
+ program->setUniform1fv(program->getUniformLocation("gl_DepthRange.far"), 1, &nearFarDiff[1]);
+ program->setUniform1fv(program->getUniformLocation("gl_DepthRange.diff"), 1, &nearFarDiff[2]);
+ }
+
+ return true;
+}
+
+// Applies the fixed-function state (culling, depth test, alpha blending, stenciling, etc)
+void Context::applyState(GLenum drawMode)
+{
+ Device *device = getDevice();
+ Framebuffer *framebuffer = getDrawFramebuffer();
+
+ if(mState.cullFace)
+ {
+ device->setCullMode(es2sw::ConvertCullMode(mState.cullMode, mState.frontFace));
+ }
+ else
+ {
+ device->setCullMode(sw::CULL_NONE);
+ }
+
+ if(mDepthStateDirty)
+ {
+ if(mState.depthTest)
+ {
+ device->setDepthBufferEnable(true);
+ device->setDepthCompare(es2sw::ConvertDepthComparison(mState.depthFunc));
+ }
+ else
+ {
+ device->setDepthBufferEnable(false);
+ }
+
+ mDepthStateDirty = false;
+ }
+
+ if(mBlendStateDirty)
+ {
+ if(mState.blend)
+ {
+ device->setAlphaBlendEnable(true);
+ device->setSeparateAlphaBlendEnable(true);
+
+ device->setBlendConstant(es2sw::ConvertColor(mState.blendColor));
+
+ device->setSourceBlendFactor(es2sw::ConvertBlendFunc(mState.sourceBlendRGB));
+ device->setDestBlendFactor(es2sw::ConvertBlendFunc(mState.destBlendRGB));
+ device->setBlendOperation(es2sw::ConvertBlendOp(mState.blendEquationRGB));
+
+ device->setSourceBlendFactorAlpha(es2sw::ConvertBlendFunc(mState.sourceBlendAlpha));
+ device->setDestBlendFactorAlpha(es2sw::ConvertBlendFunc(mState.destBlendAlpha));
+ device->setBlendOperationAlpha(es2sw::ConvertBlendOp(mState.blendEquationAlpha));
+ }
+ else
+ {
+ device->setAlphaBlendEnable(false);
+ }
+
+ mBlendStateDirty = false;
+ }
+
+ if(mStencilStateDirty || mFrontFaceDirty)
+ {
+ if(mState.stencilTest && framebuffer->hasStencil())
+ {
+ device->setStencilEnable(true);
+ device->setTwoSidedStencil(true);
+
+ 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
+ Renderbuffer *stencilbuffer = framebuffer->getStencilbuffer();
+ GLuint maxStencil = (1 << stencilbuffer->getStencilSize()) - 1;
+
+ if(mState.frontFace == GL_CCW)
+ {
+ device->setStencilWriteMask(mState.stencilWritemask);
+ device->setStencilCompare(es2sw::ConvertStencilComparison(mState.stencilFunc));
+
+ device->setStencilReference((mState.stencilRef < (GLint)maxStencil) ? mState.stencilRef : maxStencil);
+ device->setStencilMask(mState.stencilMask);
+
+ device->setStencilFailOperation(es2sw::ConvertStencilOp(mState.stencilFail));
+ device->setStencilZFailOperation(es2sw::ConvertStencilOp(mState.stencilPassDepthFail));
+ device->setStencilPassOperation(es2sw::ConvertStencilOp(mState.stencilPassDepthPass));
+
+ device->setStencilWriteMaskCCW(mState.stencilBackWritemask);
+ device->setStencilCompareCCW(es2sw::ConvertStencilComparison(mState.stencilBackFunc));
+
+ device->setStencilReferenceCCW((mState.stencilBackRef < (GLint)maxStencil) ? mState.stencilBackRef : maxStencil);
+ device->setStencilMaskCCW(mState.stencilBackMask);
+
+ device->setStencilFailOperationCCW(es2sw::ConvertStencilOp(mState.stencilBackFail));
+ device->setStencilZFailOperationCCW(es2sw::ConvertStencilOp(mState.stencilBackPassDepthFail));
+ device->setStencilPassOperationCCW(es2sw::ConvertStencilOp(mState.stencilBackPassDepthPass));
+ }
+ else
+ {
+ device->setStencilWriteMaskCCW(mState.stencilWritemask);
+ device->setStencilCompareCCW(es2sw::ConvertStencilComparison(mState.stencilFunc));
+
+ device->setStencilReferenceCCW((mState.stencilRef < (GLint)maxStencil) ? mState.stencilRef : maxStencil);
+ device->setStencilMaskCCW(mState.stencilMask);
+
+ device->setStencilFailOperationCCW(es2sw::ConvertStencilOp(mState.stencilFail));
+ device->setStencilZFailOperationCCW(es2sw::ConvertStencilOp(mState.stencilPassDepthFail));
+ device->setStencilPassOperationCCW(es2sw::ConvertStencilOp(mState.stencilPassDepthPass));
+
+ device->setStencilWriteMask(mState.stencilBackWritemask);
+ device->setStencilCompare(es2sw::ConvertStencilComparison(mState.stencilBackFunc));
+
+ device->setStencilReference((mState.stencilBackRef < (GLint)maxStencil) ? mState.stencilBackRef : maxStencil);
+ device->setStencilMask(mState.stencilBackMask);
+
+ device->setStencilFailOperation(es2sw::ConvertStencilOp(mState.stencilBackFail));
+ device->setStencilZFailOperation(es2sw::ConvertStencilOp(mState.stencilBackPassDepthFail));
+ device->setStencilPassOperation(es2sw::ConvertStencilOp(mState.stencilBackPassDepthPass));
+ }
+ }
+ else
+ {
+ device->setStencilEnable(false);
+ }
+
+ mStencilStateDirty = false;
+ mFrontFaceDirty = false;
+ }
+
+ if(mMaskStateDirty)
+ {
+ device->setColorWriteMask(0, es2sw::ConvertColorMask(mState.colorMaskRed, mState.colorMaskGreen, mState.colorMaskBlue, mState.colorMaskAlpha));
+ device->setDepthWriteEnable(mState.depthMask);
+
+ mMaskStateDirty = false;
+ }
+
+ if(mPolygonOffsetStateDirty)
+ {
+ if(mState.polygonOffsetFill)
+ {
+ Renderbuffer *depthbuffer = framebuffer->getDepthbuffer();
+ if(depthbuffer)
+ {
+ device->setSlopeDepthBias(mState.polygonOffsetFactor);
+ float depthBias = ldexp(mState.polygonOffsetUnits, -(int)(depthbuffer->getDepthSize()));
+ device->setDepthBias(depthBias);
+ }
+ }
+ else
+ {
+ device->setSlopeDepthBias(0);
+ device->setDepthBias(0);
+ }
+
+ mPolygonOffsetStateDirty = false;
+ }
+
+ if(mSampleStateDirty)
+ {
+ if(mState.sampleAlphaToCoverage)
+ {
+ device->setTransparencyAntialiasing(sw::TRANSPARENCY_ALPHA_TO_COVERAGE);
+ }
+ else
+ {
+ device->setTransparencyAntialiasing(sw::TRANSPARENCY_NONE);
+ }
+
+ if(mState.sampleCoverage)
+ {
+ unsigned int mask = 0;
+ if(mState.sampleCoverageValue != 0)
+ {
+ int width, height, samples;
+ framebuffer->completeness(width, height, samples);
+
+ float threshold = 0.5f;
+
+ for(int i = 0; i < samples; i++)
+ {
+ mask <<= 1;
+
+ if((i + 1) * mState.sampleCoverageValue >= threshold)
+ {
+ threshold += 1.0f;
+ mask |= 1;
+ }
+ }
+ }
+
+ if(mState.sampleCoverageInvert)
+ {
+ mask = ~mask;
+ }
+
+ device->setMultiSampleMask(mask);
+ }
+ else
+ {
+ device->setMultiSampleMask(0xFFFFFFFF);
+ }
+
+ mSampleStateDirty = false;
+ }
+
+ if(mDitherStateDirty)
+ {
+ // UNIMPLEMENTED(); // FIXME
+
+ mDitherStateDirty = false;
+ }
+}
+
+GLenum Context::applyVertexBuffer(GLint base, GLint first, GLsizei count)
+{
+ TranslatedAttribute attributes[MAX_VERTEX_ATTRIBS];
+
+ GLenum err = mVertexDataManager->prepareVertexData(first, count, attributes);
+ if(err != GL_NO_ERROR)
+ {
+ return err;
+ }
+
+ Device *device = getDevice();
+ Program *program = getCurrentProgram();
+
+ device->resetInputStreams(false);
+
+ for(int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
+ {
+ if(program->getAttributeStream(i) == -1)
+ {
+ continue;
+ }
+
+ sw::Resource *resource = attributes[i].vertexBuffer;
+ const void *buffer = (char*)resource->getBuffer() + attributes[i].offset;
+
+ int stride = attributes[i].stride;
+
+ buffer = (char*)buffer + stride * base;
+
+ sw::Stream attribute(resource, buffer, stride);
+
+ attribute.type = attributes[i].type;
+ attribute.count = attributes[i].count;
+ attribute.normalized = attributes[i].normalized;
+
+ int stream = program->getAttributeStream(i);
+ device->setInputStream(stream, attribute);
+ }
+
+ return GL_NO_ERROR;
+}
+
+// Applies the indices and element array bindings
+GLenum Context::applyIndexBuffer(const void *indices, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo)
+{
+ Device *device = getDevice();
+ GLenum err = mIndexDataManager->prepareIndexData(type, count, mState.elementArrayBuffer.get(), indices, indexInfo);
+
+ if(err == GL_NO_ERROR)
+ {
+ device->setIndexBuffer(indexInfo->indexBuffer);
+ }
+
+ return err;
+}
+
+// Applies the shaders and shader constants
+void Context::applyShaders()
+{
+ Device *device = getDevice();
+ Program *programObject = getCurrentProgram();
+ sw::VertexShader *vertexShader = programObject->getVertexShader();
+ sw::PixelShader *pixelShader = programObject->getPixelShader();
+
+ device->setVertexShader(vertexShader);
+ device->setPixelShader(pixelShader);
+
+ if(programObject->getSerial() != mAppliedProgramSerial)
+ {
+ programObject->dirtyAllUniforms();
+ mAppliedProgramSerial = programObject->getSerial();
+ }
+
+ programObject->applyUniforms();
+}
+
+void Context::applyTextures()
+{
+ applyTextures(sw::SAMPLER_PIXEL);
+ applyTextures(sw::SAMPLER_VERTEX);
+}
+
+void Context::applyTextures(sw::SamplerType samplerType)
+{
+ Device *device = getDevice();
+ Program *programObject = getCurrentProgram();
+
+ int samplerCount = (samplerType == sw::SAMPLER_PIXEL) ? MAX_TEXTURE_IMAGE_UNITS : MAX_VERTEX_TEXTURE_IMAGE_UNITS; // Range of samplers of given sampler type
+
+ for(int samplerIndex = 0; samplerIndex < samplerCount; samplerIndex++)
+ {
+ int textureUnit = programObject->getSamplerMapping(samplerType, samplerIndex); // OpenGL texture image unit index
+
+ if(textureUnit != -1)
+ {
+ TextureType textureType = programObject->getSamplerTextureType(samplerType, samplerIndex);
+
+ Texture *texture = getSamplerTexture(textureUnit, textureType);
+
+ if(texture->isSamplerComplete())
+ {
+ GLenum wrapS = texture->getWrapS();
+ GLenum wrapT = texture->getWrapT();
+ GLenum texFilter = texture->getMinFilter();
+ GLenum magFilter = texture->getMagFilter();
+ GLenum maxAnisotropy = texture->getMaxAnisotropy();
+
+ device->setAddressingModeU(samplerType, samplerIndex, es2sw::ConvertTextureWrap(wrapS));
+ device->setAddressingModeV(samplerType, samplerIndex, es2sw::ConvertTextureWrap(wrapT));
+
+ sw::FilterType minFilter;
+ sw::MipmapType mipFilter;
+ es2sw::ConvertMinFilter(texFilter, &minFilter, &mipFilter, maxAnisotropy);
+ // ASSERT(minFilter == es2sw::ConvertMagFilter(magFilter));
+
+ device->setTextureFilter(samplerType, samplerIndex, minFilter);
+ // device->setTextureFilter(samplerType, samplerIndex, es2sw::ConvertMagFilter(magFilter));
+ device->setMipmapFilter(samplerType, samplerIndex, mipFilter);
+ device->setMaxAnisotropy(samplerType, samplerIndex, maxAnisotropy);
+
+ applyTexture(samplerType, samplerIndex, texture);
+ }
+ else
+ {
+ applyTexture(samplerType, samplerIndex, 0);
+ }
+ }
+ else
+ {
+ applyTexture(samplerType, samplerIndex, NULL);
+ }
+ }
+}
+
+void Context::applyTexture(sw::SamplerType type, int index, Texture *baseTexture)
+{
+ Device *device = getDevice();
+ Program *program = getCurrentProgram();
+ int sampler = (type == sw::SAMPLER_PIXEL) ? index : 16 + index;
+ bool textureUsed = false;
+
+ if(type == sw::SAMPLER_PIXEL)
+ {
+ textureUsed = program->getPixelShader()->usesSampler(index);
+ }
+ else if(type == sw::SAMPLER_VERTEX)
+ {
+ textureUsed = program->getVertexShader()->usesSampler(index);
+ }
+ else UNREACHABLE();
+
+ sw::Resource *resource = 0;
+
+ if(baseTexture && textureUsed)
+ {
+ resource = baseTexture->getResource();
+ }
+
+ device->setTextureResource(sampler, resource);
+
+ if(baseTexture && textureUsed)
+ {
+ int levelCount = baseTexture->getLevelCount();
+
+ if(baseTexture->getTarget() == GL_TEXTURE_2D || baseTexture->getTarget() == GL_TEXTURE_EXTERNAL_OES)
+ {
+ Texture2D *texture = static_cast<Texture2D*>(baseTexture);
+
+ for(int mipmapLevel = 0; mipmapLevel < MIPMAP_LEVELS; mipmapLevel++)
+ {
+ int surfaceLevel = mipmapLevel;
+
+ if(surfaceLevel < 0)
+ {
+ surfaceLevel = 0;
+ }
+ else if(surfaceLevel >= levelCount)
+ {
+ surfaceLevel = levelCount - 1;
+ }
+
+ Image *surface = texture->getImage(surfaceLevel);
+ device->setTextureLevel(sampler, 0, mipmapLevel, surface, sw::TEXTURE_2D);
+ }
+ }
+ else if(baseTexture->getTarget() == GL_TEXTURE_CUBE_MAP)
+ {
+ for(int face = 0; face < 6; face++)
+ {
+ TextureCubeMap *cubeTexture = static_cast<TextureCubeMap*>(baseTexture);
+
+ for(int mipmapLevel = 0; mipmapLevel < MIPMAP_LEVELS; mipmapLevel++)
+ {
+ int surfaceLevel = mipmapLevel;
+
+ if(surfaceLevel < 0)
+ {
+ surfaceLevel = 0;
+ }
+ else if(surfaceLevel >= levelCount)
+ {
+ surfaceLevel = levelCount - 1;
+ }
+
+ Image *surface = cubeTexture->getImage(face, surfaceLevel);
+ device->setTextureLevel(sampler, face, mipmapLevel, surface, sw::TEXTURE_CUBE);
+ }
+ }
+ }
+ else UNIMPLEMENTED();
+ }
+ else
+ {
+ device->setTextureLevel(sampler, 0, 0, 0, sw::TEXTURE_NULL);
+ }
+}
+
+void Context::readPixels(GLint x, GLint y, GLsizei width, GLsizei height,
+ GLenum format, GLenum type, GLsizei *bufSize, void* pixels)
+{
+ Framebuffer *framebuffer = getReadFramebuffer();
+ int framebufferWidth, framebufferHeight, framebufferSamples;
+
+ if(framebuffer->completeness(framebufferWidth, framebufferHeight, framebufferSamples) != GL_FRAMEBUFFER_COMPLETE)
+ {
+ return error(GL_INVALID_FRAMEBUFFER_OPERATION);
+ }
+
+ if(getReadFramebufferHandle() != 0 && framebufferSamples != 0)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ GLsizei outputPitch = ComputePitch(width, format, type, mState.packAlignment);
+
+ // Sized query sanity check
+ if(bufSize)
+ {
+ int requiredSize = outputPitch * height;
+ if(requiredSize > *bufSize)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+ }
+
+ Image *renderTarget = framebuffer->getRenderTarget();
+
+ if(!renderTarget)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+
+ sw::Rect rect = {x, y, x + width, y + height};
+ rect.clip(0, 0, renderTarget->getWidth(), renderTarget->getHeight());
+
+ unsigned char *source = (unsigned char*)renderTarget->lock(rect.x0, rect.y0, sw::LOCK_READONLY);
+ unsigned char *dest = (unsigned char*)pixels;
+ unsigned short *dest16 = (unsigned short*)pixels;
+ int inputPitch = (int)renderTarget->getPitch();
+
+ for(int j = 0; j < rect.y1 - rect.y0; j++)
+ {
+ if(renderTarget->getInternalFormat() == sw::FORMAT_A8R8G8B8 &&
+ format == GL_BGRA_EXT && type == GL_UNSIGNED_BYTE)
+ {
+ // Fast path for EXT_read_format_bgra, given an RGBA source buffer
+ // Note that buffers with no alpha go through the slow path below
+ memcpy(dest + j * outputPitch, source + j * inputPitch, (rect.x1 - rect.x0) * 4);
+ }
+ else
+ {
+ for(int i = 0; i < rect.x1 - rect.x0; i++)
+ {
+ float r;
+ float g;
+ float b;
+ float a;
+
+ switch(renderTarget->getInternalFormat())
+ {
+ case sw::FORMAT_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 sw::FORMAT_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 sw::FORMAT_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 sw::FORMAT_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 sw::FORMAT_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 sw::FORMAT_A32B32G32R32F:
+ {
+ 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 sw::FORMAT_A16B16G16R16F:
+ {
+ r = (float)*((sw::half*)(source + 8 * i + j * inputPitch) + 0);
+ g = (float)*((sw::half*)(source + 8 * i + j * inputPitch) + 1);
+ b = (float)*((sw::half*)(source + 8 * i + j * inputPitch) + 2);
+ a = (float)*((sw::half*)(source + 8 * i + j * inputPitch) + 3);
+ }
+ break;
+ default:
+ UNIMPLEMENTED(); // FIXME
+ UNREACHABLE();
+ }
+
+ 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: // IMPLEMENTATION_COLOR_READ_FORMAT
+ switch(type)
+ {
+ case GL_UNSIGNED_SHORT_5_6_5: // IMPLEMENTATION_COLOR_READ_TYPE
+ 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;
+ default: UNREACHABLE();
+ }
+ break;
+ default: UNREACHABLE();
+ }
+ }
+ }
+ }
+
+ renderTarget->unlock();
+ renderTarget->release();
+}
+
+void Context::clear(GLbitfield mask)
+{
+ Framebuffer *framebuffer = getDrawFramebuffer();
+
+ if(!framebuffer || framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
+ {
+ return error(GL_INVALID_FRAMEBUFFER_OPERATION);
+ }
+
+ if(!applyRenderTarget())
+ {
+ return;
+ }
+
+ Device *device = getDevice();
+
+ unsigned int color = (unorm<8>(mState.colorClearValue.alpha) << 24) |
+ (unorm<8>(mState.colorClearValue.red) << 16) |
+ (unorm<8>(mState.colorClearValue.green) << 8) |
+ (unorm<8>(mState.colorClearValue.blue) << 0);
+ float depth = clamp01(mState.depthClearValue);
+ int stencil = mState.stencilClearValue & 0x000000FF;
+
+ if(mask & GL_COLOR_BUFFER_BIT)
+ {
+ unsigned int rgbaMask = (mState.colorMaskRed ? 0x1 : 0) |
+ (mState.colorMaskGreen ? 0x2 : 0) |
+ (mState.colorMaskBlue ? 0x4 : 0) |
+ (mState.colorMaskAlpha ? 0x8 : 0);
+
+ if(rgbaMask != 0)
+ {
+ device->clearColor(color, rgbaMask);
+ }
+ }
+
+ if(mask & GL_DEPTH_BUFFER_BIT)
+ {
+ if(mState.depthMask != 0)
+ {
+ device->clearDepth(depth);
+ }
+ }
+
+ if(mask & GL_STENCIL_BUFFER_BIT)
+ {
+ if(mState.stencilWritemask != 0)
+ {
+ device->clearStencil(stencil, mState.stencilWritemask);
+ }
+ }
+}
+
+void Context::drawArrays(GLenum mode, GLint first, GLsizei count)
+{
+ if(!mState.currentProgram)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ Device *device = getDevice();
+ PrimitiveType primitiveType;
+ int primitiveCount;
+
+ if(!es2sw::ConvertPrimitiveType(mode, count, primitiveType, primitiveCount))
+ return error(GL_INVALID_ENUM);
+
+ if(primitiveCount <= 0)
+ {
+ return;
+ }
+
+ if(!applyRenderTarget())
+ {
+ return;
+ }
+
+ applyState(mode);
+
+ GLenum err = applyVertexBuffer(0, first, count);
+ if(err != GL_NO_ERROR)
+ {
+ return error(err);
+ }
+
+ applyShaders();
+ applyTextures();
+
+ if(!getCurrentProgram()->validateSamplers(false))
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ if(!cullSkipsDraw(mode))
+ {
+ device->drawPrimitive(primitiveType, primitiveCount);
+ }
+}
+
+void Context::drawElements(GLenum mode, GLsizei count, GLenum type, const void *indices)
+{
+ if(!mState.currentProgram)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ if(!indices && !mState.elementArrayBuffer)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ Device *device = getDevice();
+ PrimitiveType primitiveType;
+ int primitiveCount;
+
+ if(!es2sw::ConvertPrimitiveType(mode, count, primitiveType, primitiveCount))
+ return error(GL_INVALID_ENUM);
+
+ if(primitiveCount <= 0)
+ {
+ return;
+ }
+
+ if(!applyRenderTarget())
+ {
+ 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;
+ err = applyVertexBuffer(-(int)indexInfo.minIndex, indexInfo.minIndex, vertexCount);
+ if(err != GL_NO_ERROR)
+ {
+ return error(err);
+ }
+
+ applyShaders();
+ applyTextures();
+
+ if(!getCurrentProgram()->validateSamplers(false))
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ if(!cullSkipsDraw(mode))
+ {
+ device->drawIndexedPrimitive(primitiveType, indexInfo.indexOffset, primitiveCount, IndexDataManager::typeSize(type));
+ }
+}
+
+void Context::finish()
+{
+ Device *device = getDevice();
+
+ device->finish();
+}
+
+void Context::flush()
+{
+ // We don't queue anything without processing it as fast as possible
+}
+
+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;
+}
+
+int Context::getSupportedMultiSampleDepth(sw::Format format, int requested)
+{
+ if(requested <= 1)
+ {
+ return 1;
+ }
+
+ if(requested == 2)
+ {
+ return 2;
+ }
+
+ return 4;
+}
+
+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; 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);
+ }
+}
+
+bool Context::cullSkipsDraw(GLenum drawMode)
+{
+ return mState.cullFace && mState.cullMode == GL_FRONT_AND_BACK && isTriangleMode(drawMode);
+}
+
+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 < 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::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
+ GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
+ GLbitfield mask)
+{
+ Device *device = getDevice();
+
+ Framebuffer *readFramebuffer = getReadFramebuffer();
+ Framebuffer *drawFramebuffer = getDrawFramebuffer();
+
+ int readBufferWidth, readBufferHeight, readBufferSamples;
+ int drawBufferWidth, drawBufferHeight, drawBufferSamples;
+
+ if(!readFramebuffer || readFramebuffer->completeness(readBufferWidth, readBufferHeight, readBufferSamples) != GL_FRAMEBUFFER_COMPLETE ||
+ !drawFramebuffer || drawFramebuffer->completeness(drawBufferWidth, drawBufferHeight, drawBufferSamples) != GL_FRAMEBUFFER_COMPLETE)
+ {
+ return error(GL_INVALID_FRAMEBUFFER_OPERATION);
+ }
+
+ if(drawBufferSamples > 1)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ sw::Rect sourceRect;
+ sw::Rect destRect;
+
+ if(srcX0 < srcX1)
+ {
+ sourceRect.x0 = srcX0;
+ sourceRect.x1 = srcX1;
+ destRect.x0 = dstX0;
+ destRect.x1 = dstX1;
+ }
+ else
+ {
+ sourceRect.x0 = srcX1;
+ destRect.x0 = dstX1;
+ sourceRect.x1 = srcX0;
+ destRect.x1 = dstX0;
+ }
+
+ if(srcY0 < srcY1)
+ {
+ sourceRect.y0 = srcY0;
+ destRect.y0 = dstY0;
+ sourceRect.y1 = srcY1;
+ destRect.y1 = dstY1;
+ }
+ else
+ {
+ sourceRect.y0 = srcY1;
+ destRect.y0 = dstY1;
+ sourceRect.y1 = srcY0;
+ destRect.y1 = dstY0;
+ }
+
+ sw::Rect sourceScissoredRect = sourceRect;
+ sw::Rect destScissoredRect = destRect;
+
+ if(mState.scissorTest) // Only write to parts of the destination framebuffer which pass the scissor test
+ {
+ if(destRect.x0 < mState.scissorX)
+ {
+ int xDiff = mState.scissorX - destRect.x0;
+ destScissoredRect.x0 = mState.scissorX;
+ sourceScissoredRect.x0 += xDiff;
+ }
+
+ if(destRect.x1 > mState.scissorX + mState.scissorWidth)
+ {
+ int xDiff = destRect.x1 - (mState.scissorX + mState.scissorWidth);
+ destScissoredRect.x1 = mState.scissorX + mState.scissorWidth;
+ sourceScissoredRect.x1 -= xDiff;
+ }
+
+ if(destRect.y0 < mState.scissorY)
+ {
+ int yDiff = mState.scissorY - destRect.y0;
+ destScissoredRect.y0 = mState.scissorY;
+ sourceScissoredRect.y0 += yDiff;
+ }
+
+ if(destRect.y1 > mState.scissorY + mState.scissorHeight)
+ {
+ int yDiff = destRect.y1 - (mState.scissorY + mState.scissorHeight);
+ destScissoredRect.y1 = mState.scissorY + mState.scissorHeight;
+ sourceScissoredRect.y1 -= yDiff;
+ }
+ }
+
+ sw::Rect sourceTrimmedRect = sourceScissoredRect;
+ sw::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.x0 < 0)
+ {
+ int xDiff = 0 - sourceTrimmedRect.x0;
+ sourceTrimmedRect.x0 = 0;
+ destTrimmedRect.x0 += xDiff;
+ }
+
+ if(sourceTrimmedRect.x1 > readBufferWidth)
+ {
+ int xDiff = sourceTrimmedRect.x1 - readBufferWidth;
+ sourceTrimmedRect.x1 = readBufferWidth;
+ destTrimmedRect.x1 -= xDiff;
+ }
+
+ if(sourceTrimmedRect.y0 < 0)
+ {
+ int yDiff = 0 - sourceTrimmedRect.y0;
+ sourceTrimmedRect.y0 = 0;
+ destTrimmedRect.y0 += yDiff;
+ }
+
+ if(sourceTrimmedRect.y1 > readBufferHeight)
+ {
+ int yDiff = sourceTrimmedRect.y1 - readBufferHeight;
+ sourceTrimmedRect.y1 = readBufferHeight;
+ destTrimmedRect.y1 -= yDiff;
+ }
+
+ if(destTrimmedRect.x0 < 0)
+ {
+ int xDiff = 0 - destTrimmedRect.x0;
+ destTrimmedRect.x0 = 0;
+ sourceTrimmedRect.x0 += xDiff;
+ }
+
+ if(destTrimmedRect.x1 > drawBufferWidth)
+ {
+ int xDiff = destTrimmedRect.x1 - drawBufferWidth;
+ destTrimmedRect.x1 = drawBufferWidth;
+ sourceTrimmedRect.x1 -= xDiff;
+ }
+
+ if(destTrimmedRect.y0 < 0)
+ {
+ int yDiff = 0 - destTrimmedRect.y0;
+ destTrimmedRect.y0 = 0;
+ sourceTrimmedRect.y0 += yDiff;
+ }
+
+ if(destTrimmedRect.y1 > drawBufferHeight)
+ {
+ int yDiff = destTrimmedRect.y1 - drawBufferHeight;
+ destTrimmedRect.y1 = drawBufferHeight;
+ sourceTrimmedRect.y1 -= yDiff;
+ }
+
+ bool partialBufferCopy = false;
+
+ if(sourceTrimmedRect.y1 - sourceTrimmedRect.y0 < readBufferHeight ||
+ sourceTrimmedRect.x1 - sourceTrimmedRect.x0 < readBufferWidth ||
+ destTrimmedRect.y1 - destTrimmedRect.y0 < drawBufferHeight ||
+ destTrimmedRect.x1 - destTrimmedRect.x0 < drawBufferWidth ||
+ sourceTrimmedRect.y0 != 0 || destTrimmedRect.y0 != 0 || sourceTrimmedRect.x0 != 0 || destTrimmedRect.x0 != 0)
+ {
+ partialBufferCopy = true;
+ }
+
+ bool blitRenderTarget = false;
+ bool blitDepthStencil = false;
+
+ 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()->getInternalFormat() != drawFramebuffer->getColorbuffer()->getInternalFormat())
+ {
+ ERR("Color buffer format conversion in BlitFramebufferANGLE not supported by this implementation");
+ return error(GL_INVALID_OPERATION);
+ }
+
+ if(partialBufferCopy && readBufferSamples > 1)
+ {
+ 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()->getInternalFormat() != drawFramebuffer->getDepthbuffer()->getInternalFormat())
+ {
+ 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()->getInternalFormat() != drawFramebuffer->getStencilbuffer()->getInternalFormat())
+ {
+ 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() > 1) ||
+ (readDSBuffer && readDSBuffer->getSamples() > 1))
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+ }
+
+ if(blitRenderTarget || blitDepthStencil)
+ {
+ if(blitRenderTarget)
+ {
+ Image *readRenderTarget = readFramebuffer->getRenderTarget();
+ Image *drawRenderTarget = drawFramebuffer->getRenderTarget();
+
+ bool success = device->stretchRect(readRenderTarget, &sourceRect, drawRenderTarget, &destRect, false);
+
+ readRenderTarget->release();
+ drawRenderTarget->release();
+
+ if(!success)
+ {
+ ERR("BlitFramebufferANGLE failed.");
+ return;
+ }
+ }
+
+ if(blitDepthStencil)
+ {
+ bool success = device->stretchRect(readFramebuffer->getDepthStencil(), NULL, drawFramebuffer->getDepthStencil(), NULL, false);
+
+ if(!success)
+ {
+ ERR("BlitFramebufferANGLE failed.");
+ return;
+ }
+ }
+ }
+}
+
+}
+
+// Exported functions for use by EGL
+extern "C"
+{
+ gl::Context *glCreateContext(const egl::Config *config, const gl::Context *shareContext)
+ {
+ return new gl::Context(config, shareContext);
+ }
+
+ 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/GLES2/libGLES_CM/Context.h b/src/GLES2/libGLES_CM/Context.h
new file mode 100644
index 0000000..cbeb2bd
--- /dev/null
+++ b/src/GLES2/libGLES_CM/Context.h
@@ -0,0 +1,488 @@
+// SwiftShader Software Renderer
+//
+// Copyright(c) 2005-2013 TransGaming Inc.
+//
+// All rights reserved. No part of this software may be copied, distributed, transmitted,
+// transcribed, stored in a retrieval system, translated into any human or computer
+// language by any means, or disclosed to third parties without the explicit written
+// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
+// or implied, including but not limited to any patent rights, are granted to you.
+//
+
+// Context.h: Defines the 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_
+
+#include "ResourceManager.h"
+#include "HandleAllocator.h"
+#include "RefCountObject.h"
+#include "Image.hpp"
+#include "Renderer/Sampler.hpp"
+
+#define GL_APICALL
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#define EGLAPI
+#include <EGL/egl.h>
+
+#include <map>
+#include <string>
+
+namespace egl
+{
+class Display;
+class Surface;
+class Config;
+}
+
+namespace gl
+{
+struct TranslatedAttribute;
+struct TranslatedIndexData;
+
+class Buffer;
+class Shader;
+class Program;
+class Texture;
+class Texture2D;
+class TextureCubeMap;
+class TextureExternal;
+class Framebuffer;
+class Renderbuffer;
+class RenderbufferStorage;
+class Colorbuffer;
+class Depthbuffer;
+class StreamingIndexBuffer;
+class Stencilbuffer;
+class DepthStencilbuffer;
+class VertexDataManager;
+class IndexDataManager;
+class Fence;
+class Query;
+
+enum
+{
+ MAX_VERTEX_ATTRIBS = 16,
+ MAX_UNIFORM_VECTORS = 256, // Device limit
+ MAX_VERTEX_UNIFORM_VECTORS = 256 - 3, // Reserve space for gl_DepthRange
+ MAX_VARYING_VECTORS = 10,
+ MAX_TEXTURE_IMAGE_UNITS = 16,
+ MAX_VERTEX_TEXTURE_IMAGE_UNITS = 4,
+ MAX_COMBINED_TEXTURE_IMAGE_UNITS = MAX_TEXTURE_IMAGE_UNITS + MAX_VERTEX_TEXTURE_IMAGE_UNITS,
+ MAX_FRAGMENT_UNIFORM_VECTORS = 224 - 3, // Reserve space for gl_DepthRange
+ MAX_DRAW_BUFFERS = 1,
+
+ IMPLEMENTATION_COLOR_READ_FORMAT = GL_RGB,
+ IMPLEMENTATION_COLOR_READ_TYPE = GL_UNSIGNED_SHORT_5_6_5
+};
+
+enum QueryType
+{
+ QUERY_ANY_SAMPLES_PASSED,
+ QUERY_ANY_SAMPLES_PASSED_CONSERVATIVE,
+
+ QUERY_TYPE_COUNT
+};
+
+const float ALIASED_LINE_WIDTH_RANGE_MIN = 1.0f;
+const float ALIASED_LINE_WIDTH_RANGE_MAX = 1.0f;
+const float ALIASED_POINT_SIZE_RANGE_MIN = 0.125f;
+const float ALIASED_POINT_SIZE_RANGE_MAX = 8192.0f;
+const float MAX_TEXTURE_MAX_ANISOTROPY = 16.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)
+ {
+ 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
+};
+
+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];
+ BindingPointer<Query> activeQuery[QUERY_TYPE_COUNT];
+
+ GLint unpackAlignment;
+ GLint packAlignment;
+};
+
+class Context
+{
+ public:
+ Context(const egl::Config *config, const Context *shareContext);
+
+ virtual ~Context();
+
+ void makeCurrent(egl::Display *display, egl::Surface *surface);
+
+ void markAllStateDirty();
+
+ // 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 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 setScissorTest(bool enabled);
+ bool isScissorTestEnabled() const;
+ 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 getActiveQuery(GLenum target) const;
+
+ GLuint getArrayBufferHandle() 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;
+
+ // 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 bindTextureExternal(GLuint texture);
+ void bindReadFramebuffer(GLuint framebuffer);
+ void bindDrawFramebuffer(GLuint framebuffer);
+ void bindRenderbuffer(GLuint renderbuffer);
+ void useProgram(GLuint program);
+
+ void beginQuery(GLenum target, GLuint query);
+ void endQuery(GLenum target);
+
+ void setFramebufferZero(Framebuffer *framebuffer);
+
+ void setRenderbufferStorage(RenderbufferStorage *renderbuffer);
+
+ void setVertexAttrib(GLuint index, const GLfloat *values);
+
+ Buffer *getBuffer(GLuint handle);
+ Fence *getFence(GLuint handle);
+ Shader *getShader(GLuint handle);
+ Program *getProgram(GLuint handle);
+ virtual Texture *getTexture(GLuint handle);
+ Framebuffer *getFramebuffer(GLuint handle);
+ virtual Renderbuffer *getRenderbuffer(GLuint handle);
+ Query *getQuery(GLuint handle, bool create, GLenum type);
+
+ Buffer *getArrayBuffer();
+ Buffer *getElementArrayBuffer();
+ Program *getCurrentProgram();
+ Texture2D *getTexture2D();
+ TextureCubeMap *getTextureCubeMap();
+ TextureExternal *getTextureExternal();
+ 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);
+ void drawElements(GLenum mode, GLsizei count, GLenum type, const void *indices);
+ void finish();
+ void flush();
+
+ void recordInvalidEnum();
+ void recordInvalidValue();
+ void recordInvalidOperation();
+ void recordOutOfMemory();
+ void recordInvalidFramebufferOperation();
+
+ GLenum getError();
+
+ static int getSupportedMultiSampleDepth(sw::Format format, int requested);
+
+ void blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
+ GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
+ GLbitfield mask);
+
+ private:
+ bool applyRenderTarget();
+ void applyState(GLenum drawMode);
+ GLenum applyVertexBuffer(GLint base, GLint first, GLsizei count);
+ GLenum applyIndexBuffer(const void *indices, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo);
+ void applyShaders();
+ void applyTextures();
+ void applyTextures(sw::SamplerType type);
+ void applyTexture(sw::SamplerType type, int sampler, Texture *texture);
+
+ void detachBuffer(GLuint buffer);
+ void detachTexture(GLuint texture);
+ void detachFramebuffer(GLuint framebuffer);
+ void detachRenderbuffer(GLuint renderbuffer);
+
+ bool cullSkipsDraw(GLenum drawMode);
+ bool isTriangleMode(GLenum drawMode);
+
+ const egl::Config *const mConfig;
+
+ State mState;
+
+ BindingPointer<Texture2D> mTexture2DZero;
+ BindingPointer<TextureCubeMap> mTextureCubeMapZero;
+ BindingPointer<TextureExternal> mTextureExternalZero;
+
+ typedef std::map<GLint, Framebuffer*> FramebufferMap;
+ FramebufferMap mFramebufferMap;
+ HandleAllocator mFramebufferHandleAllocator;
+
+ typedef std::map<GLint, Fence*> FenceMap;
+ FenceMap mFenceMap;
+ HandleAllocator mFenceHandleAllocator;
+
+ typedef std::map<GLint, Query*> QueryMap;
+ QueryMap mQueryMap;
+ HandleAllocator mQueryHandleAllocator;
+
+ VertexDataManager *mVertexDataManager;
+ IndexDataManager *mIndexDataManager;
+
+ // Recorded errors
+ bool mInvalidEnum;
+ bool mInvalidValue;
+ bool mInvalidOperation;
+ bool mOutOfMemory;
+ bool mInvalidFramebufferOperation;
+
+ bool mHasBeenCurrent;
+
+ unsigned int mAppliedProgramSerial;
+
+ // state caching flags
+ bool mDepthStateDirty;
+ bool mMaskStateDirty;
+ bool mPixelPackingStateDirty;
+ bool mBlendStateDirty;
+ bool mStencilStateDirty;
+ bool mPolygonOffsetStateDirty;
+ bool mSampleStateDirty;
+ bool mFrontFaceDirty;
+ bool mDitherStateDirty;
+
+ ResourceManager *mResourceManager;
+};
+}
+
+#endif // INCLUDE_CONTEXT_H_
diff --git a/src/GLES2/libGLES_CM/Device.cpp b/src/GLES2/libGLES_CM/Device.cpp
new file mode 100644
index 0000000..c2cc36a
--- /dev/null
+++ b/src/GLES2/libGLES_CM/Device.cpp
@@ -0,0 +1,801 @@
+// SwiftShader Software Renderer
+//
+// Copyright(c) 2005-2013 TransGaming Inc.
+//
+// All rights reserved. No part of this software may be copied, distributed, transmitted,
+// transcribed, stored in a retrieval system, translated into any human or computer
+// language by any means, or disclosed to third parties without the explicit written
+// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
+// or implied, including but not limited to any patent rights, are granted to you.
+//
+
+#include "Device.hpp"
+
+#include "Image.hpp"
+#include "Texture.h"
+
+#include "Renderer/Renderer.hpp"
+#include "Renderer/Clipper.hpp"
+#include "Shader/PixelShader.hpp"
+#include "Shader/VertexShader.hpp"
+#include "Main/Config.hpp"
+#include "Main/FrameBuffer.hpp"
+#include "Common/Math.hpp"
+#include "Common/Configurator.hpp"
+#include "Common/Timer.hpp"
+#include "../common/debug.h"
+
+bool localShaderConstants = false;
+
+namespace gl
+{
+ using namespace sw;
+
+ Device::Device(Context *context) : Renderer(context, true, true, true, true, true), context(context)
+ {
+ depthStencil = 0;
+ renderTarget = 0;
+
+ setDepthBufferEnable(true);
+ setFillMode(FILL_SOLID);
+ setShadingMode(SHADING_GOURAUD);
+ setDepthWriteEnable(true);
+ setAlphaTestEnable(false);
+ setSourceBlendFactor(BLEND_ONE);
+ setDestBlendFactor(BLEND_ZERO);
+ setCullMode(CULL_COUNTERCLOCKWISE);
+ setDepthCompare(DEPTH_LESSEQUAL);
+ setAlphaReference(0);
+ setAlphaCompare(ALPHA_ALWAYS);
+ setAlphaBlendEnable(false);
+ setFogEnable(false);
+ setSpecularEnable(false);
+ setFogColor(0);
+ setPixelFogMode(FOG_NONE);
+ setFogStart(0.0f);
+ setFogEnd(1.0f);
+ setFogDensity(1.0f);
+ setRangeFogEnable(false);
+ setStencilEnable(false);
+ setStencilFailOperation(OPERATION_KEEP);
+ setStencilZFailOperation(OPERATION_KEEP);
+ setStencilPassOperation(OPERATION_KEEP);
+ setStencilCompare(STENCIL_ALWAYS);
+ setStencilReference(0);
+ setStencilMask(0xFFFFFFFF);
+ setStencilWriteMask(0xFFFFFFFF);
+ setVertexFogMode(FOG_NONE);
+ setClipFlags(0);
+ setPointSize(1.0f);
+ setPointSizeMin(0.125f);
+ setPointSpriteEnable(false);
+ setPointSizeMax(8192.0f);
+ setColorWriteMask(0, 0x0000000F);
+ setBlendOperation(BLENDOP_ADD);
+ scissorEnable = false;
+ setSlopeDepthBias(0.0f);
+ setTwoSidedStencil(false);
+ setStencilFailOperationCCW(OPERATION_KEEP);
+ setStencilZFailOperationCCW(OPERATION_KEEP);
+ setStencilPassOperationCCW(OPERATION_KEEP);
+ setStencilCompareCCW(STENCIL_ALWAYS);
+ setColorWriteMask(1, 0x0000000F);
+ setColorWriteMask(2, 0x0000000F);
+ setColorWriteMask(3, 0x0000000F);
+ setBlendConstant(0xFFFFFFFF);
+ setWriteSRGB(false);
+ setDepthBias(0.0f);
+ setSeparateAlphaBlendEnable(false);
+ setSourceBlendFactorAlpha(BLEND_ONE);
+ setDestBlendFactorAlpha(BLEND_ZERO);
+ setBlendOperationAlpha(BLENDOP_ADD);
+
+ for(int i = 0; i < 16; i++)
+ {
+ setAddressingModeU(sw::SAMPLER_PIXEL, i, ADDRESSING_WRAP);
+ setAddressingModeV(sw::SAMPLER_PIXEL, i, ADDRESSING_WRAP);
+ setAddressingModeW(sw::SAMPLER_PIXEL, i, ADDRESSING_WRAP);
+ setBorderColor(sw::SAMPLER_PIXEL, i, 0x00000000);
+ setTextureFilter(sw::SAMPLER_PIXEL, i, FILTER_POINT);
+ setMipmapFilter(sw::SAMPLER_PIXEL, i, MIPMAP_NONE);
+ setMipmapLOD(sw::SAMPLER_PIXEL, i, 0.0f);
+ }
+
+ for(int i = 0; i < 4; i++)
+ {
+ setAddressingModeU(sw::SAMPLER_VERTEX, i, ADDRESSING_WRAP);
+ setAddressingModeV(sw::SAMPLER_VERTEX, i, ADDRESSING_WRAP);
+ setAddressingModeW(sw::SAMPLER_VERTEX, i, ADDRESSING_WRAP);
+ setBorderColor(sw::SAMPLER_VERTEX, i, 0x00000000);
+ setTextureFilter(sw::SAMPLER_VERTEX, i, FILTER_POINT);
+ setMipmapFilter(sw::SAMPLER_VERTEX, i, MIPMAP_NONE);
+ setMipmapLOD(sw::SAMPLER_VERTEX, i, 0.0f);
+ }
+
+ for(int i = 0; i < 6; i++)
+ {
+ float plane[4] = {0, 0, 0, 0};
+
+ setClipPlane(i, plane);
+ }
+
+ pixelShader = 0;
+ vertexShader = 0;
+
+ pixelShaderDirty = true;
+ pixelShaderConstantsFDirty = 0;
+ vertexShaderDirty = true;
+ vertexShaderConstantsFDirty = 0;
+
+ for(int i = 0; i < 224; i++)
+ {
+ float zero[4] = {0, 0, 0, 0};
+
+ setPixelShaderConstantF(i, zero, 1);
+ }
+
+ for(int i = 0; i < 256; i++)
+ {
+ float zero[4] = {0, 0, 0, 0};
+
+ setVertexShaderConstantF(i, zero, 1);
+ }
+ }
+
+ Device::~Device()
+ {
+ if(depthStencil)
+ {
+ depthStencil->release();
+ depthStencil = 0;
+ }
+
+ if(renderTarget)
+ {
+ renderTarget->release();
+ renderTarget = 0;
+ }
+
+ delete context;
+ }
+
+ void Device::clearColor(unsigned int color, unsigned int rgbaMask)
+ {
+ TRACE("unsigned long color = 0x%0.8X", color);
+
+ if(!renderTarget)
+ {
+ return;
+ }
+
+ int x0 = 0;
+ int y0 = 0;
+ int width = renderTarget->getExternalWidth();
+ int height = renderTarget->getExternalHeight();
+
+ if(scissorEnable) // Clamp against scissor rectangle
+ {
+ if(x0 < scissorRect.x0) x0 = scissorRect.x0;
+ if(y0 < scissorRect.y0) y0 = scissorRect.y0;
+ if(width > scissorRect.x1 - scissorRect.x0) width = scissorRect.x1 - scissorRect.x0;
+ if(height > scissorRect.y1 - scissorRect.y0) height = scissorRect.y1 - scissorRect.y0;
+ }
+
+ renderTarget->clearColorBuffer(color, rgbaMask, x0, y0, width, height);
+ }
+
+ void Device::clearDepth(float z)
+ {
+ TRACE("float z = %f", z);
+
+ if(!depthStencil)
+ {
+ return;
+ }
+
+ if(z > 1) z = 1;
+ if(z < 0) z = 0;
+
+ int x0 = 0;
+ int y0 = 0;
+ int width = depthStencil->getExternalWidth();
+ int height = depthStencil->getExternalHeight();
+
+ if(scissorEnable) // Clamp against scissor rectangle
+ {
+ if(x0 < scissorRect.x0) x0 = scissorRect.x0;
+ if(y0 < scissorRect.y0) y0 = scissorRect.y0;
+ if(width > scissorRect.x1 - scissorRect.x0) width = scissorRect.x1 - scissorRect.x0;
+ if(height > scissorRect.y1 - scissorRect.y0) height = scissorRect.y1 - scissorRect.y0;
+ }
+
+ depthStencil->clearDepthBuffer(z, x0, y0, width, height);
+ }
+
+ void Device::clearStencil(unsigned int stencil, unsigned int mask)
+ {
+ TRACE("unsigned long stencil = %d", stencil);
+
+ if(!depthStencil)
+ {
+ return;
+ }
+
+ int x0 = 0;
+ int y0 = 0;
+ int width = depthStencil->getExternalWidth();
+ int height = depthStencil->getExternalHeight();
+
+ if(scissorEnable) // Clamp against scissor rectangle
+ {
+ if(x0 < scissorRect.x0) x0 = scissorRect.x0;
+ if(y0 < scissorRect.y0) y0 = scissorRect.y0;
+ if(width > scissorRect.x1 - scissorRect.x0) width = scissorRect.x1 - scissorRect.x0;
+ if(height > scissorRect.y1 - scissorRect.y0) height = scissorRect.y1 - scissorRect.y0;
+ }
+
+ depthStencil->clearStencilBuffer(stencil, mask, x0, y0, width, height);
+ }
+
+ Image *Device::createDepthStencilSurface(unsigned int width, unsigned int height, sw::Format format, int multiSampleDepth, bool discard)
+ {
+ TRACE("unsigned int width = %d, unsigned int height = %d, sw::Format format = %d, int multiSampleDepth = %d, bool discard = %d", width, height, format, multiSampleDepth, discard);
+
+ if(width == 0 || height == 0 || height > OUTLINE_RESOLUTION)
+ {
+ ERR("Invalid parameters");
+ return 0;
+ }
+
+ bool lockable = true;
+
+ switch(format)
+ {
+ // case FORMAT_D15S1:
+ case FORMAT_D24S8:
+ case FORMAT_D24X8:
+ // case FORMAT_D24X4S4:
+ case FORMAT_D24FS8:
+ case FORMAT_D32:
+ case FORMAT_D16:
+ lockable = false;
+ break;
+ // case FORMAT_S8_LOCKABLE:
+ // case FORMAT_D16_LOCKABLE:
+ case FORMAT_D32F_LOCKABLE:
+ // case FORMAT_D32_LOCKABLE:
+ case FORMAT_DF24S8:
+ case FORMAT_DF16S8:
+ lockable = true;
+ break;
+ default:
+ UNREACHABLE();
+ }
+
+ Image *surface = new Image(0, width, height, format, GL_NONE, GL_NONE, multiSampleDepth, lockable, true);
+
+ if(!surface)
+ {
+ ERR("Out of memory");
+ return 0;
+ }
+
+ return surface;
+ }
+
+ Image *Device::createRenderTarget(unsigned int width, unsigned int height, sw::Format format, int multiSampleDepth, bool lockable)
+ {
+ TRACE("unsigned int width = %d, unsigned int height = %d, sw::Format format = %d, int multiSampleDepth = %d, bool lockable = %d", width, height, format, multiSampleDepth, lockable);
+
+ if(height > OUTLINE_RESOLUTION)
+ {
+ ERR("Invalid parameters");
+ return 0;
+ }
+
+ Image *surface = new Image(0, width, height, format, GL_NONE, GL_NONE, multiSampleDepth, lockable, true);
+
+ if(!surface)
+ {
+ ERR("Out of memory");
+ return 0;
+ }
+
+ return surface;
+ }
+
+ void Device::drawIndexedPrimitive(PrimitiveType type, unsigned int indexOffset, unsigned int primitiveCount, int indexSize)
+ {
+ TRACE("");
+
+ if(!bindResources() || !primitiveCount)
+ {
+ return;
+ }
+
+ DrawType drawType;
+
+ if(indexSize == 4)
+ {
+ switch(type)
+ {
+ case DRAW_POINTLIST: drawType = sw::DRAW_INDEXEDPOINTLIST32; break;
+ case DRAW_LINELIST: drawType = sw::DRAW_INDEXEDLINELIST32; break;
+ case DRAW_LINESTRIP: drawType = sw::DRAW_INDEXEDLINESTRIP32; break;
+ case DRAW_LINELOOP: drawType = sw::DRAW_INDEXEDLINELOOP32; break;
+ case DRAW_TRIANGLELIST: drawType = sw::DRAW_INDEXEDTRIANGLELIST32; break;
+ case DRAW_TRIANGLESTRIP: drawType = sw::DRAW_INDEXEDTRIANGLESTRIP32; break;
+ case DRAW_TRIANGLEFAN: drawType = sw::DRAW_INDEXEDTRIANGLEFAN32; break;
+ default: UNREACHABLE();
+ }
+ }
+ else if(indexSize == 2)
+ {
+ switch(type)
+ {
+ case DRAW_POINTLIST: drawType = sw::DRAW_INDEXEDPOINTLIST16; break;
+ case DRAW_LINELIST: drawType = sw::DRAW_INDEXEDLINELIST16; break;
+ case DRAW_LINESTRIP: drawType = sw::DRAW_INDEXEDLINESTRIP16; break;
+ case DRAW_LINELOOP: drawType = sw::DRAW_INDEXEDLINELOOP16; break;
+ case DRAW_TRIANGLELIST: drawType = sw::DRAW_INDEXEDTRIANGLELIST16; break;
+ case DRAW_TRIANGLESTRIP: drawType = sw::DRAW_INDEXEDTRIANGLESTRIP16; break;
+ case DRAW_TRIANGLEFAN: drawType = sw::DRAW_INDEXEDTRIANGLEFAN16; break;
+ default: UNREACHABLE();
+ }
+ }
+ else if(indexSize == 1)
+ {
+ switch(type)
+ {
+ case DRAW_POINTLIST: drawType = sw::DRAW_INDEXEDPOINTLIST8; break;
+ case DRAW_LINELIST: drawType = sw::DRAW_INDEXEDLINELIST8; break;
+ case DRAW_LINESTRIP: drawType = sw::DRAW_INDEXEDLINESTRIP8; break;
+ case DRAW_LINELOOP: drawType = sw::DRAW_INDEXEDLINELOOP8; break;
+ case DRAW_TRIANGLELIST: drawType = sw::DRAW_INDEXEDTRIANGLELIST8; break;
+ case DRAW_TRIANGLESTRIP: drawType = sw::DRAW_INDEXEDTRIANGLESTRIP8; break;
+ case DRAW_TRIANGLEFAN: drawType = sw::DRAW_INDEXEDTRIANGLEFAN8; break;
+ default: UNREACHABLE();
+ }
+ }
+ else UNREACHABLE();
+
+ draw(drawType, indexOffset, primitiveCount);
+ }
+
+ void Device::drawPrimitive(PrimitiveType primitiveType, unsigned int primitiveCount)
+ {
+ TRACE("");
+
+ if(!bindResources() || !primitiveCount)
+ {
+ return;
+ }
+
+ setIndexBuffer(0);
+
+ DrawType drawType;
+
+ switch(primitiveType)
+ {
+ case DRAW_POINTLIST: drawType = sw::DRAW_POINTLIST; break;
+ case DRAW_LINELIST: drawType = sw::DRAW_LINELIST; break;
+ case DRAW_LINESTRIP: drawType = sw::DRAW_LINESTRIP; break;
+ case DRAW_LINELOOP: drawType = sw::DRAW_LINELOOP; break;
+ case DRAW_TRIANGLELIST: drawType = sw::DRAW_TRIANGLELIST; break;
+ case DRAW_TRIANGLESTRIP: drawType = sw::DRAW_TRIANGLESTRIP; break;
+ case DRAW_TRIANGLEFAN: drawType = sw::DRAW_TRIANGLEFAN; break;
+ default: UNREACHABLE();
+ }
+
+ draw(drawType, 0, primitiveCount);
+ }
+
+ void Device::setDepthStencilSurface(Image *depthStencil)
+ {
+ TRACE("Image *newDepthStencil = 0x%0.8p", depthStencil);
+
+ if(this->depthStencil == depthStencil)
+ {
+ return;
+ }
+
+ if(depthStencil)
+ {
+ depthStencil->addRef();
+ }
+
+ if(this->depthStencil)
+ {
+ this->depthStencil->release();
+ }
+
+ this->depthStencil = depthStencil;
+
+ setDepthStencil(depthStencil);
+ }
+
+ void Device::setPixelShader(PixelShader *pixelShader)
+ {
+ TRACE("PixelShader *shader = 0x%0.8p", pixelShader);
+
+ this->pixelShader = pixelShader;
+ pixelShaderDirty = true;
+ }
+
+ void Device::setPixelShaderConstantF(unsigned int startRegister, const float *constantData, unsigned int count)
+ {
+ TRACE("unsigned int startRegister = %d, const int *constantData = 0x%0.8p, unsigned int count = %d", startRegister, constantData, count);
+
+ for(unsigned int i = 0; i < count && startRegister + i < 224; i++)
+ {
+ pixelShaderConstantF[startRegister + i][0] = constantData[i * 4 + 0];
+ pixelShaderConstantF[startRegister + i][1] = constantData[i * 4 + 1];
+ pixelShaderConstantF[startRegister + i][2] = constantData[i * 4 + 2];
+ pixelShaderConstantF[startRegister + i][3] = constantData[i * 4 + 3];
+ }
+
+ pixelShaderConstantsFDirty = max(startRegister + count, pixelShaderConstantsFDirty);
+ pixelShaderDirty = true; // Reload DEF constants
+ }
+
+ void Device::setScissorEnable(bool enable)
+ {
+ scissorEnable = enable;
+ }
+
+ void Device::setRenderTarget(Image *renderTarget)
+ {
+ TRACE("Image *newRenderTarget = 0x%0.8p", renderTarget);
+
+ if(renderTarget)
+ {
+ renderTarget->addRef();
+ }
+
+ if(this->renderTarget)
+ {
+ this->renderTarget->release();
+ }
+
+ this->renderTarget = renderTarget;
+
+ Renderer::setRenderTarget(0, renderTarget);
+ }
+
+ void Device::setScissorRect(const sw::Rect &rect)
+ {
+ TRACE("const sw::Rect *rect = 0x%0.8p", rect);
+
+ scissorRect = rect;
+ }
+
+ void Device::setVertexShader(VertexShader *vertexShader)
+ {
+ TRACE("VertexShader *shader = 0x%0.8p", vertexShader);
+
+ this->vertexShader = vertexShader;
+ vertexShaderDirty = true;
+ }
+
+ void Device::setVertexShaderConstantF(unsigned int startRegister, const float *constantData, unsigned int count)
+ {
+ TRACE("unsigned int startRegister = %d, const int *constantData = 0x%0.8p, unsigned int count = %d", startRegister, constantData, count);
+
+ for(unsigned int i = 0; i < count && startRegister + i < 256; i++)
+ {
+ vertexShaderConstantF[startRegister + i][0] = constantData[i * 4 + 0];
+ vertexShaderConstantF[startRegister + i][1] = constantData[i * 4 + 1];
+ vertexShaderConstantF[startRegister + i][2] = constantData[i * 4 + 2];
+ vertexShaderConstantF[startRegister + i][3] = constantData[i * 4 + 3];
+ }
+
+ vertexShaderConstantsFDirty = max(startRegister + count, vertexShaderConstantsFDirty);
+ vertexShaderDirty = true; // Reload DEF constants
+ }
+
+ void Device::setViewport(const Viewport &viewport)
+ {
+ TRACE("const Viewport *viewport = 0x%0.8p", viewport);
+
+ this->viewport = viewport;
+ }
+
+ bool Device::stretchRect(Image *source, const sw::Rect *sourceRect, Image *dest, const sw::Rect *destRect, bool filter)
+ {
+ TRACE("Image *sourceSurface = 0x%0.8p, const sw::Rect *sourceRect = 0x%0.8p, Image *destSurface = 0x%0.8p, const sw::Rect *destRect = 0x%0.8p, bool filter = %d", source, sourceRect, dest, destRect, filter);
+
+ if(!source || !dest || !validRectangle(sourceRect, source) || !validRectangle(destRect, dest))
+ {
+ ERR("Invalid parameters");
+ return false;
+ }
+
+ int sWidth = source->getExternalWidth();
+ int sHeight = source->getExternalHeight();
+ int dWidth = dest->getExternalWidth();
+ int dHeight = dest->getExternalHeight();
+
+ Rect sRect;
+ Rect dRect;
+
+ if(sourceRect)
+ {
+ sRect = *sourceRect;
+ }
+ else
+ {
+ sRect.y0 = 0;
+ sRect.x0 = 0;
+ sRect.y1 = sHeight;
+ sRect.x1 = sWidth;
+ }
+
+ if(destRect)
+ {
+ dRect = *destRect;
+ }
+ else
+ {
+ dRect.y0 = 0;
+ dRect.x0 = 0;
+ dRect.y1 = dHeight;
+ dRect.x1 = dWidth;
+ }
+
+ bool scaling = (sRect.x1 - sRect.x0 != dRect.x1 - dRect.x0) || (sRect.y1 - sRect.y0 != dRect.y1 - dRect.y0);
+ bool equalFormats = source->getInternalFormat() == dest->getInternalFormat();
+ bool depthStencil = Image::isDepth(source->getInternalFormat()) || Image::isStencil(source->getInternalFormat());
+ bool alpha0xFF = false;
+
+ if((source->getInternalFormat() == FORMAT_A8R8G8B8 && dest->getInternalFormat() == FORMAT_X8R8G8B8) ||
+ (source->getInternalFormat() == FORMAT_X8R8G8B8 && dest->getInternalFormat() == FORMAT_A8R8G8B8))
+ {
+ equalFormats = true;
+ alpha0xFF = true;
+ }
+
+ if(depthStencil) // Copy entirely, internally // FIXME: Check
+ {
+ if(source->hasDepth())
+ {
+ sw::byte *sourceBuffer = (sw::byte*)source->lockInternal(0, 0, 0, LOCK_READONLY, PUBLIC);
+ sw::byte *destBuffer = (sw::byte*)dest->lockInternal(0, 0, 0, LOCK_DISCARD, PUBLIC);
+
+ unsigned int width = source->getInternalWidth();
+ unsigned int height = source->getInternalHeight();
+ unsigned int pitch = source->getInternalPitchB();
+
+ for(unsigned int y = 0; y < height; y++)
+ {
+ memcpy(destBuffer, sourceBuffer, pitch); // FIXME: Only copy width * bytes
+
+ sourceBuffer += pitch;
+ destBuffer += pitch;
+ }
+
+ source->unlockInternal();
+ dest->unlockInternal();
+ }
+
+ if(source->hasStencil())
+ {
+ sw::byte *sourceBuffer = (sw::byte*)source->lockStencil(0, PUBLIC);
+ sw::byte *destBuffer = (sw::byte*)dest->lockStencil(0, PUBLIC);
+
+ unsigned int width = source->getInternalWidth();
+ unsigned int height = source->getInternalHeight();
+ unsigned int pitch = source->getStencilPitchB();
+
+ for(unsigned int y = 0; y < height; y++)
+ {
+ memcpy(destBuffer, sourceBuffer, pitch); // FIXME: Only copy width * bytes
+
+ sourceBuffer += pitch;
+ destBuffer += pitch;
+ }
+
+ source->unlockStencil();
+ dest->unlockStencil();
+ }
+ }
+ else if(!scaling && equalFormats)
+ {
+ unsigned char *sourceBytes = (unsigned char*)source->lockInternal(sRect.x0, sRect.y0, 0, LOCK_READONLY, PUBLIC);
+ unsigned char *destBytes = (unsigned char*)dest->lockInternal(dRect.x0, dRect.y0, 0, LOCK_READWRITE, PUBLIC);
+ unsigned int sourcePitch = source->getInternalPitchB();
+ unsigned int destPitch = dest->getInternalPitchB();
+
+ unsigned int width = dRect.x1 - dRect.x0;
+ unsigned int height = dRect.y1 - dRect.y0;
+ unsigned int bytes = width * Image::bytes(source->getInternalFormat());
+
+ for(unsigned int y = 0; y < height; y++)
+ {
+ memcpy(destBytes, sourceBytes, bytes);
+
+ if(alpha0xFF)
+ {
+ for(unsigned int x = 0; x < width; x++)
+ {
+ destBytes[4 * x + 3] = 0xFF;
+ }
+ }
+
+ sourceBytes += sourcePitch;
+ destBytes += destPitch;
+ }
+
+ source->unlockInternal();
+ dest->unlockInternal();
+ }
+ else
+ {
+ blit(source, sRect, dest, dRect, scaling && filter);
+ }
+
+ return true;
+ }
+
+ bool Device::bindResources()
+ {
+ if(!bindViewport())
+ {
+ return false; // Zero-area target region
+ }
+
+ bindShaderConstants();
+
+ return true;
+ }
+
+ void Device::bindShaderConstants()
+ {
+ if(pixelShaderDirty)
+ {
+ if(pixelShader)
+ {
+ if(pixelShaderConstantsFDirty)
+ {
+ Renderer::setPixelShaderConstantF(0, pixelShaderConstantF[0], pixelShaderConstantsFDirty);
+ }
+
+ Renderer::setPixelShader(pixelShader); // Loads shader constants set with DEF
+ pixelShaderConstantsFDirty = pixelShader->dirtyConstantsF; // Shader DEF'ed constants are dirty
+ }
+ else
+ {
+ setPixelShader(0);
+ }
+
+ pixelShaderDirty = false;
+ }
+
+ if(vertexShaderDirty)
+ {
+ if(vertexShader)
+ {
+ if(vertexShaderConstantsFDirty)
+ {
+ Renderer::setVertexShaderConstantF(0, vertexShaderConstantF[0], vertexShaderConstantsFDirty);
+ }
+
+ Renderer::setVertexShader(vertexShader); // Loads shader constants set with DEF
+ vertexShaderConstantsFDirty = vertexShader->dirtyConstantsF; // Shader DEF'ed constants are dirty
+ }
+ else
+ {
+ setVertexShader(0);
+ }
+
+ vertexShaderDirty = false;
+ }
+ }
+
+ bool Device::bindViewport()
+ {
+ if(viewport.width <= 0 || viewport.height <= 0)
+ {
+ return false;
+ }
+
+ if(scissorEnable)
+ {
+ if(scissorRect.x0 >= scissorRect.x1 || scissorRect.y0 >= scissorRect.y1)
+ {
+ return false;
+ }
+
+ sw::Rect scissor;
+ scissor.x0 = scissorRect.x0;
+ scissor.x1 = scissorRect.x1;
+ scissor.y0 = scissorRect.y0;
+ scissor.y1 = scissorRect.y1;
+
+ setScissor(scissor);
+ }
+ else
+ {
+ sw::Rect scissor;
+ scissor.x0 = viewport.x0;
+ scissor.x1 = viewport.x0 + viewport.width;
+ scissor.y0 = viewport.y0;
+ scissor.y1 = viewport.y0 + viewport.height;
+
+ if(renderTarget)
+ {
+ scissor.x0 = max(scissor.x0, 0);
+ scissor.x1 = min(scissor.x1, renderTarget->getExternalWidth());
+ scissor.y0 = max(scissor.y0, 0);
+ scissor.y1 = min(scissor.y1, renderTarget->getExternalHeight());
+ }
+
+ if(depthStencil)
+ {
+ scissor.x0 = max(scissor.x0, 0);
+ scissor.x1 = min(scissor.x1, depthStencil->getExternalWidth());
+ scissor.y0 = max(scissor.y0, 0);
+ scissor.y1 = min(scissor.y1, depthStencil->getExternalHeight());
+ }
+
+ setScissor(scissor);
+ }
+
+ sw::Viewport view;
+ view.x0 = (float)viewport.x0;
+ view.y0 = (float)viewport.y0;
+ view.width = (float)viewport.width;
+ view.height = (float)viewport.height;
+ view.minZ = viewport.minZ;
+ view.maxZ = viewport.maxZ;
+
+ Renderer::setViewport(view);
+
+ return true;
+ }
+
+ bool Device::validRectangle(const sw::Rect *rect, Image *surface)
+ {
+ if(!rect)
+ {
+ return true;
+ }
+
+ if(rect->x1 <= rect->x0 || rect->y1 <= rect->y0)
+ {
+ return false;
+ }
+
+ if(rect->x0 < 0 || rect->y0 < 0)
+ {
+ return false;
+ }
+
+ if(rect->x1 > (int)surface->getWidth() || rect->y1 > (int)surface->getHeight())
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ void Device::finish()
+ {
+ synchronize();
+ }
+}
+
+// Exported functions for use by EGL
+extern "C"
+{
+ gl::Device *createDevice()
+ {
+ sw::Context *context = new sw::Context();
+
+ if(context)
+ {
+ return new gl::Device(context);
+ }
+
+ return 0;
+ }
+}
\ No newline at end of file
diff --git a/src/GLES2/libGLES_CM/Device.hpp b/src/GLES2/libGLES_CM/Device.hpp
new file mode 100644
index 0000000..4e0337d
--- /dev/null
+++ b/src/GLES2/libGLES_CM/Device.hpp
@@ -0,0 +1,103 @@
+// SwiftShader Software Renderer
+//
+// Copyright(c) 2005-2012 TransGaming Inc.
+//
+// All rights reserved. No part of this software may be copied, distributed, transmitted,
+// transcribed, stored in a retrieval system, translated into any human or computer
+// language by any means, or disclosed to third parties without the explicit written
+// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
+// or implied, including but not limited to any patent rights, are granted to you.
+//
+
+#ifndef gl_Device_hpp
+#define gl_Device_hpp
+
+#include "Renderer/Renderer.hpp"
+
+namespace gl
+{
+ class Texture;
+}
+
+namespace gl
+{
+ class Image;
+
+ enum PrimitiveType
+ {
+ DRAW_POINTLIST,
+ DRAW_LINELIST,
+ DRAW_LINESTRIP,
+ DRAW_LINELOOP,
+ DRAW_TRIANGLELIST,
+ DRAW_TRIANGLESTRIP,
+ DRAW_TRIANGLEFAN
+ };
+
+ struct Viewport
+ {
+ int x0;
+ int y0;
+ unsigned int width;
+ unsigned int height;
+ float minZ;
+ float maxZ;
+ };
+
+ class Device : public sw::Renderer
+ {
+ public:
+ explicit Device(sw::Context *context);
+
+ virtual ~Device();
+
+ virtual void clearColor(unsigned int color, unsigned int rgbaMask);
+ virtual void clearDepth(float z);
+ virtual void clearStencil(unsigned int stencil, unsigned int mask);
+ virtual Image *createDepthStencilSurface(unsigned int width, unsigned int height, sw::Format format, int multiSampleDepth, bool discard);
+ virtual Image *createRenderTarget(unsigned int width, unsigned int height, sw::Format format, int multiSampleDepth, bool lockable);
+ virtual void drawIndexedPrimitive(PrimitiveType type, unsigned int indexOffset, unsigned int primitiveCount, int indexSize);
+ virtual void drawPrimitive(PrimitiveType primitiveType, unsigned int primiveCount);
+ virtual void setDepthStencilSurface(Image *newDepthStencil);
+ virtual void setPixelShader(sw::PixelShader *shader);
+ virtual void setPixelShaderConstantF(unsigned int startRegister, const float *constantData, unsigned int count);
+ virtual void setScissorEnable(bool enable);
+ virtual void setRenderTarget(Image *renderTarget);
+ virtual void setScissorRect(const sw::Rect &rect);
+ virtual void setVertexShader(sw::VertexShader *shader);
+ virtual void setVertexShaderConstantF(unsigned int startRegister, const float *constantData, unsigned int count);
+ virtual void setViewport(const Viewport &viewport);
+
+ virtual bool stretchRect(Image *sourceSurface, const sw::Rect *sourceRect, Image *destSurface, const sw::Rect *destRect, bool filter);
+ virtual void finish();
+
+ private:
+ sw::Context *const context;
+
+ bool bindResources();
+ void bindShaderConstants();
+ bool bindViewport(); // Also adjusts for scissoring
+
+ bool validRectangle(const sw::Rect *rect, Image *surface);
+
+ Viewport viewport;
+ sw::Rect scissorRect;
+ bool scissorEnable;
+
+ sw::PixelShader *pixelShader;
+ sw::VertexShader *vertexShader;
+
+ bool pixelShaderDirty;
+ unsigned int pixelShaderConstantsFDirty;
+ bool vertexShaderDirty;
+ unsigned int vertexShaderConstantsFDirty;
+
+ float pixelShaderConstantF[224][4];
+ float vertexShaderConstantF[256][4];
+
+ Image *renderTarget;
+ Image *depthStencil;
+ };
+}
+
+#endif // gl_Device_hpp
diff --git a/src/GLES2/libGLES_CM/Fence.cpp b/src/GLES2/libGLES_CM/Fence.cpp
new file mode 100644
index 0000000..8221075
--- /dev/null
+++ b/src/GLES2/libGLES_CM/Fence.cpp
@@ -0,0 +1,108 @@
+// SwiftShader Software Renderer
+//
+// Copyright(c) 2005-2012 TransGaming Inc.
+//
+// All rights reserved. No part of this software may be copied, distributed, transmitted,
+// transcribed, stored in a retrieval system, translated into any human or computer
+// language by any means, or disclosed to third parties without the explicit written
+// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
+// or implied, including but not limited to any patent rights, are granted to you.
+//
+
+// Fence.cpp: Implements the Fence class, which supports the GL_NV_fence extension.
+
+#include "Fence.h"
+
+#include "main.h"
+#include "Common/Thread.hpp"
+
+namespace gl
+{
+
+Fence::Fence()
+{
+ mQuery = false;
+ mCondition = GL_NONE;
+ mStatus = GL_FALSE;
+}
+
+Fence::~Fence()
+{
+ mQuery = false;
+}
+
+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;
+}
+
+void Fence::setFence(GLenum condition)
+{
+ mQuery = true;
+ mCondition = condition;
+ mStatus = GL_FALSE;
+}
+
+GLboolean Fence::testFence()
+{
+ if(!mQuery)
+ {
+ return error(GL_INVALID_OPERATION, GL_TRUE);
+ }
+
+ UNIMPLEMENTED();
+ mStatus = GL_TRUE;
+
+ return mStatus;
+}
+
+void Fence::finishFence()
+{
+ if(!mQuery)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ while(!testFence())
+ {
+ sw::Thread::yield();
+ }
+}
+
+void Fence::getFenceiv(GLenum pname, GLint *params)
+{
+ if(!mQuery)
+ {
+ 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;
+ }
+
+ mStatus = testFence();
+
+ params[0] = mStatus;
+ break;
+ }
+ case GL_FENCE_CONDITION_NV:
+ params[0] = mCondition;
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ break;
+ }
+}
+
+}
diff --git a/src/GLES2/libGLES_CM/Fence.h b/src/GLES2/libGLES_CM/Fence.h
new file mode 100644
index 0000000..bd6d9ac
--- /dev/null
+++ b/src/GLES2/libGLES_CM/Fence.h
@@ -0,0 +1,43 @@
+// SwiftShader Software Renderer
+//
+// Copyright(c) 2005-2012 TransGaming Inc.
+//
+// All rights reserved. No part of this software may be copied, distributed, transmitted,
+// transcribed, stored in a retrieval system, translated into any human or computer
+// language by any means, or disclosed to third parties without the explicit written
+// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
+// or implied, including but not limited to any patent rights, are granted to you.
+//
+
+// Fence.h: Defines the Fence class, which supports the GL_NV_fence extension.
+
+#ifndef LIBGLESV2_FENCE_H_
+#define LIBGLESV2_FENCE_H_
+
+#define GL_APICALL
+#include <GLES2/gl2.h>
+
+namespace gl
+{
+
+class Fence
+{
+ public:
+ Fence();
+ virtual ~Fence();
+
+ GLboolean isFence();
+ void setFence(GLenum condition);
+ GLboolean testFence();
+ void finishFence();
+ void getFenceiv(GLenum pname, GLint *params);
+
+ private:
+ bool mQuery;
+ GLenum mCondition;
+ GLboolean mStatus;
+};
+
+}
+
+#endif // LIBGLESV2_FENCE_H_
diff --git a/src/GLES2/libGLES_CM/Framebuffer.cpp b/src/GLES2/libGLES_CM/Framebuffer.cpp
new file mode 100644
index 0000000..8ba7d9e
--- /dev/null
+++ b/src/GLES2/libGLES_CM/Framebuffer.cpp
@@ -0,0 +1,423 @@
+// SwiftShader Software Renderer
+//
+// Copyright(c) 2005-2013 TransGaming Inc.
+//
+// All rights reserved. No part of this software may be copied, distributed, transmitted,
+// transcribed, stored in a retrieval system, translated into any human or computer
+// language by any means, or disclosed to third parties without the explicit written
+// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
+// or implied, including but not limited to any patent rights, are granted to you.
+//
+
+// Framebuffer.cpp: Implements the Framebuffer class. Implements GL framebuffer
+// objects and related functionality. [OpenGL ES 2.0.24] section 4.4 page 105.
+
+#include "Framebuffer.h"
+
+#include "main.h"
+#include "Renderbuffer.h"
+#include "Texture.h"
+#include "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);
+}
+
+Renderbuffer *Framebuffer::lookupRenderbuffer(GLenum type, GLuint handle) const
+{
+ Context *context = getContext();
+ Renderbuffer *buffer = NULL;
+
+ if(type == GL_NONE)
+ {
+ buffer = NULL;
+ }
+ else if(type == GL_RENDERBUFFER)
+ {
+ buffer = context->getRenderbuffer(handle);
+ }
+ else if(IsTextureTarget(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 && IsTextureTarget(mColorbufferType))
+ {
+ mColorbufferType = GL_NONE;
+ mColorbufferPointer.set(NULL);
+ }
+
+ if(mDepthbufferPointer.id() == texture && IsTextureTarget(mDepthbufferType))
+ {
+ mDepthbufferType = GL_NONE;
+ mDepthbufferPointer.set(NULL);
+ }
+
+ if(mStencilbufferPointer.id() == texture && IsTextureTarget(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);
+ }
+}
+
+// Increments refcount on surface.
+// caller must Release() the returned surface
+Image *Framebuffer::getRenderTarget()
+{
+ Renderbuffer *colorbuffer = mColorbufferPointer.get();
+
+ if(colorbuffer)
+ {
+ return colorbuffer->getRenderTarget();
+ }
+
+ return NULL;
+}
+
+// Increments refcount on surface.
+// caller must Release() the returned surface
+Image *Framebuffer::getDepthStencil()
+{
+ Renderbuffer *depthstencilbuffer = mDepthbufferPointer.get();
+
+ if(!depthstencilbuffer)
+ {
+ depthstencilbuffer = mStencilbufferPointer.get();
+ }
+
+ if(depthstencilbuffer)
+ {
+ return depthstencilbuffer->getRenderTarget();
+ }
+
+ return NULL;
+}
+
+Renderbuffer *Framebuffer::getColorbuffer()
+{
+ return mColorbufferPointer.get();
+}
+
+Renderbuffer *Framebuffer::getDepthbuffer()
+{
+ return mDepthbufferPointer.get();
+}
+
+Renderbuffer *Framebuffer::getStencilbuffer()
+{
+ return mStencilbufferPointer.get();
+}
+
+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()
+{
+ int width;
+ int height;
+ int samples;
+
+ return completeness(width, height, samples);
+}
+
+GLenum Framebuffer::completeness(int &width, int &height, int &samples)
+{
+ width = -1;
+ height = -1;
+ samples = -1;
+
+ 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->getFormat()))
+ {
+ return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+ }
+ }
+ else if(IsTextureTarget(mColorbufferType))
+ {
+ GLenum format = colorbuffer->getFormat();
+
+ if(IsCompressed(format) ||
+ format == GL_ALPHA ||
+ format == GL_LUMINANCE ||
+ format == GL_LUMINANCE_ALPHA)
+ {
+ return GL_FRAMEBUFFER_UNSUPPORTED;
+ }
+
+ if(gl::IsDepthTexture(format) || gl::IsStencilTexture(format))
+ {
+ return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+ }
+ }
+ else
+ {
+ UNREACHABLE();
+ return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+ }
+
+ width = colorbuffer->getWidth();
+ height = colorbuffer->getHeight();
+ samples = colorbuffer->getSamples();
+ }
+
+ 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->getFormat()))
+ {
+ return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+ }
+ }
+ else if(IsTextureTarget(mDepthbufferType))
+ {
+ if(!gl::IsDepthTexture(depthbuffer->getFormat()))
+ {
+ return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+ }
+ }
+ else
+ {
+ UNREACHABLE();
+ return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+ }
+
+ if(width == -1 || height == -1)
+ {
+ width = depthbuffer->getWidth();
+ height = depthbuffer->getHeight();
+ samples = depthbuffer->getSamples();
+ }
+ 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->getFormat()))
+ {
+ return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+ }
+ }
+ else if(IsTextureTarget(mStencilbufferType))
+ {
+ GLenum internalformat = stencilbuffer->getFormat();
+
+ if(!gl::IsStencilTexture(internalformat))
+ {
+ return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+ }
+ }
+ else
+ {
+ UNREACHABLE();
+ return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+ }
+
+ if(width == -1 || height == -1)
+ {
+ width = stencilbuffer->getWidth();
+ height = stencilbuffer->getHeight();
+ samples = stencilbuffer->getSamples();
+ }
+ 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(width == -1 || height == -1)
+ {
+ 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;
+}
+
+GLenum DefaultFramebuffer::completeness()
+{
+ // The default framebuffer should always be complete
+ ASSERT(Framebuffer::completeness() == GL_FRAMEBUFFER_COMPLETE);
+
+ return GL_FRAMEBUFFER_COMPLETE;
+}
+
+}
diff --git a/src/GLES2/libGLES_CM/Framebuffer.h b/src/GLES2/libGLES_CM/Framebuffer.h
new file mode 100644
index 0000000..c3e0f0b
--- /dev/null
+++ b/src/GLES2/libGLES_CM/Framebuffer.h
@@ -0,0 +1,90 @@
+// SwiftShader Software Renderer
+//
+// Copyright(c) 2005-2013 TransGaming Inc.
+//
+// All rights reserved. No part of this software may be copied, distributed, transmitted,
+// transcribed, stored in a retrieval system, translated into any human or computer
+// language by any means, or disclosed to third parties without the explicit written
+// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
+// or implied, including but not limited to any patent rights, are granted to you.
+//
+
+// Framebuffer.h: Defines the 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_
+
+#include "RefCountObject.h"
+#include "Image.hpp"
+
+#define GL_APICALL
+#include <GLES2/gl2.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);
+
+ Image *getRenderTarget();
+ Image *getDepthStencil();
+
+ Renderbuffer *getColorbuffer();
+ Renderbuffer *getDepthbuffer();
+ Renderbuffer *getStencilbuffer();
+
+ GLenum getColorbufferType();
+ GLenum getDepthbufferType();
+ GLenum getStencilbufferType();
+
+ GLuint getColorbufferHandle();
+ GLuint getDepthbufferHandle();
+ GLuint getStencilbufferHandle();
+
+ bool hasStencil();
+
+ virtual GLenum completeness();
+ GLenum completeness(int &width, int &height, int &samples);
+
+protected:
+ GLenum mColorbufferType;
+ BindingPointer<Renderbuffer> mColorbufferPointer;
+
+ GLenum mDepthbufferType;
+ BindingPointer<Renderbuffer> mDepthbufferPointer;
+
+ GLenum mStencilbufferType;
+ BindingPointer<Renderbuffer> mStencilbufferPointer;
+
+private:
+ Renderbuffer *lookupRenderbuffer(GLenum type, GLuint handle) const;
+};
+
+class DefaultFramebuffer : public Framebuffer
+{
+public:
+ DefaultFramebuffer(Colorbuffer *colorbuffer, DepthStencilbuffer *depthStencil);
+
+ virtual GLenum completeness();
+};
+
+}
+
+#endif // LIBGLESV2_FRAMEBUFFER_H_
diff --git a/src/GLES2/libGLES_CM/HandleAllocator.cpp b/src/GLES2/libGLES_CM/HandleAllocator.cpp
new file mode 100644
index 0000000..7db672a
--- /dev/null
+++ b/src/GLES2/libGLES_CM/HandleAllocator.cpp
@@ -0,0 +1,68 @@
+// SwiftShader Software Renderer
+//
+// Copyright(c) 2005-2012 TransGaming Inc.
+//
+// All rights reserved. No part of this software may be copied, distributed, transmitted,
+// transcribed, stored in a retrieval system, translated into any human or computer
+// language by any means, or disclosed to third parties without the explicit written
+// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
+// or implied, including but not limited to any patent rights, are granted to you.
+//
+
+// HandleAllocator.cpp: Implements the HandleAllocator class, which is used
+// to allocate GL handles.
+
+#include "HandleAllocator.h"
+
+#include "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/GLES2/libGLES_CM/HandleAllocator.h b/src/GLES2/libGLES_CM/HandleAllocator.h
new file mode 100644
index 0000000..3dc5a34
--- /dev/null
+++ b/src/GLES2/libGLES_CM/HandleAllocator.h
@@ -0,0 +1,46 @@
+// SwiftShader Software Renderer
+//
+// Copyright(c) 2005-2012 TransGaming Inc.
+//
+// All rights reserved. No part of this software may be copied, distributed, transmitted,
+// transcribed, stored in a retrieval system, translated into any human or computer
+// language by any means, or disclosed to third parties without the explicit written
+// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
+// or implied, including but not limited to any patent rights, are granted to you.
+//
+
+// HandleAllocator.h: Defines the 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>
+
+namespace gl
+{
+
+class HandleAllocator
+{
+ public:
+ HandleAllocator();
+ virtual ~HandleAllocator();
+
+ void setBaseHandle(GLuint value);
+
+ GLuint allocate();
+ void release(GLuint handle);
+
+ private:
+ GLuint mBaseValue;
+ GLuint mNextValue;
+ typedef std::vector<GLuint> HandleList;
+ HandleList mFreeValues;
+};
+
+}
+
+#endif // LIBGLESV2_HANDLEALLOCATOR_H_
diff --git a/src/GLES2/libGLES_CM/Image.cpp b/src/GLES2/libGLES_CM/Image.cpp
new file mode 100644
index 0000000..a2950c6
--- /dev/null
+++ b/src/GLES2/libGLES_CM/Image.cpp
@@ -0,0 +1,717 @@
+// SwiftShader Software Renderer
+//
+// Copyright(c) 2005-2013 TransGaming Inc.
+//
+// All rights reserved. No part of this software may be copied, distributed, transmitted,
+// transcribed, stored in a retrieval system, translated into any human or computer
+// language by any means, or disclosed to third parties without the explicit written
+// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
+// or implied, including but not limited to any patent rights, are granted to you.
+//
+
+#include "Image.hpp"
+
+#include "Texture.h"
+#include "utilities.h"
+#include "../common/debug.h"
+#include "Common/Thread.hpp"
+
+#include <GLES2/gl2ext.h>
+
+namespace gl
+{
+ static sw::Resource *getParentResource(Texture *texture)
+ {
+ if(texture)
+ {
+ return texture->getResource();
+ }
+
+ return 0;
+ }
+
+ Image::Image(Texture *parentTexture, GLsizei width, GLsizei height, GLenum format, GLenum type)
+ : parentTexture(parentTexture), width(width), height(height), format(format), type(type)
+ , internalFormat(selectInternalFormat(format, type)), multiSampleDepth(1)
+ , sw::Surface(getParentResource(parentTexture), width, height, 1, selectInternalFormat(format, type), true, true)
+ {
+ shared = false;
+ referenceCount = 1;
+ }
+
+ Image::Image(Texture *parentTexture, GLsizei width, GLsizei height, sw::Format internalFormat, GLenum format, GLenum type, int multiSampleDepth, bool lockable, bool renderTarget)
+ : parentTexture(parentTexture), width(width), height(height), internalFormat(internalFormat), format(format), type(type), multiSampleDepth(multiSampleDepth)
+ , sw::Surface(getParentResource(parentTexture), width, height, multiSampleDepth, internalFormat, lockable, renderTarget)
+ {
+ shared = false;
+ referenceCount = 1;
+ }
+
+ Image::~Image()
+ {
+ ASSERT(referenceCount == 0);
+ }
+
+ void *Image::lock(unsigned int left, unsigned int top, sw::Lock lock)
+ {
+ return lockExternal(left, top, 0, lock, sw::PUBLIC);
+ }
+
+ unsigned int Image::getPitch() const
+ {
+ return getExternalPitchB();
+ }
+
+ void Image::unlock()
+ {
+ unlockExternal();
+ }
+
+ int Image::getWidth()
+ {
+ return width;
+ }
+
+ int Image::getHeight()
+ {
+ return height;
+ }
+
+ GLenum Image::getFormat()
+ {
+ return format;
+ }
+
+ GLenum Image::getType()
+ {
+ return type;
+ }
+
+ sw::Format Image::getInternalFormat()
+ {
+ return internalFormat;
+ }
+
+ int Image::getMultiSampleDepth()
+ {
+ return multiSampleDepth;
+ }
+
+ void Image::addRef()
+ {
+ if(parentTexture)
+ {
+ return parentTexture->addRef();
+ }
+
+ sw::atomicIncrement(&referenceCount);
+ }
+
+ void Image::release()
+ {
+ if(parentTexture)
+ {
+ return parentTexture->release();
+ }
+
+ if(referenceCount > 0)
+ {
+ sw::atomicDecrement(&referenceCount);
+ }
+
+ if(referenceCount == 0)
+ {
+ delete this;
+ }
+ }
+
+ void Image::unbind()
+ {
+ parentTexture = 0;
+
+ release();
+ }
+
+ bool Image::isShared() const
+ {
+ return shared;
+ }
+
+ void Image::markShared()
+ {
+ shared = true;
+ }
+
+ sw::Format Image::selectInternalFormat(GLenum format, GLenum type)
+ {
+ #if S3TC_SUPPORT
+ if(format == GL_COMPRESSED_RGB_S3TC_DXT1_EXT ||
+ format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT)
+ {
+ return sw::FORMAT_DXT1;
+ }
+ else if(format == GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE)
+ {
+ return sw::FORMAT_DXT3;
+ }
+ else if(format == GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE)
+ {
+ return sw::FORMAT_DXT5;
+ }
+ else
+ #endif
+ if(type == GL_FLOAT)
+ {
+ return sw::FORMAT_A32B32G32R32F;
+ }
+ else if(type == GL_HALF_FLOAT_OES)
+ {
+ return sw::FORMAT_A16B16G16R16F;
+ }
+ else if(type == GL_UNSIGNED_BYTE)
+ {
+ if(format == GL_LUMINANCE)
+ {
+ return sw::FORMAT_L8;
+ }
+ else if(format == GL_LUMINANCE_ALPHA)
+ {
+ return sw::FORMAT_A8L8;
+ }
+ else if(format == GL_RGBA || format == GL_BGRA_EXT)
+ {
+ return sw::FORMAT_A8R8G8B8;
+ }
+ else if(format == GL_RGB)
+ {
+ return sw::FORMAT_X8R8G8B8;
+ }
+ else if(format == GL_ALPHA)
+ {
+ return sw::FORMAT_A8;
+ }
+ else UNREACHABLE();
+ }
+ else if(type == GL_UNSIGNED_SHORT || type == GL_UNSIGNED_INT)
+ {
+ if(format == GL_DEPTH_COMPONENT)
+ {
+ return sw::FORMAT_D32FS8_TEXTURE;
+ }
+ else UNREACHABLE();
+ }
+ else if(type == GL_UNSIGNED_INT_24_8_OES)
+ {
+ if(format == GL_DEPTH_STENCIL_OES)
+ {
+ return sw::FORMAT_D32FS8_TEXTURE;
+ }
+ else UNREACHABLE();
+ }
+ else if(type == GL_UNSIGNED_SHORT_4_4_4_4)
+ {
+ return sw::FORMAT_A8R8G8B8;
+ }
+ else if(type == GL_UNSIGNED_SHORT_5_5_5_1)
+ {
+ return sw::FORMAT_A8R8G8B8;
+ }
+ else if(type == GL_UNSIGNED_SHORT_5_6_5)
+ {
+ return sw::FORMAT_X8R8G8B8;
+ }
+ else UNREACHABLE();
+
+ return sw::FORMAT_A8R8G8B8;
+ }
+
+ int Image::bytes(sw::Format format)
+ {
+ return sw::Surface::bytes(format);
+ }
+
+ void Image::loadImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *input)
+ {
+ GLsizei inputPitch = ComputePitch(width, format, type, unpackAlignment);
+ void *buffer = lock(0, 0, sw::LOCK_WRITEONLY);
+
+ if(buffer)
+ {
+ switch(type)
+ {
+ case GL_UNSIGNED_BYTE:
+ switch(format)
+ {
+ case GL_ALPHA:
+ loadAlphaImageData(xoffset, yoffset, width, height, inputPitch, input, buffer);
+ break;
+ case GL_LUMINANCE:
+ loadLuminanceImageData(xoffset, yoffset, width, height, inputPitch, input, buffer);
+ break;
+ case GL_LUMINANCE_ALPHA:
+ loadLuminanceAlphaImageData(xoffset, yoffset, width, height, inputPitch, input, buffer);
+ break;
+ case GL_RGB:
+ loadRGBUByteImageData(xoffset, yoffset, width, height, inputPitch, input, buffer);
+ break;
+ case GL_RGBA:
+ loadRGBAUByteImageData(xoffset, yoffset, width, height, inputPitch, input, buffer);
+ break;
+ case GL_BGRA_EXT:
+ loadBGRAImageData(xoffset, yoffset, width, height, inputPitch, input, buffer);
+ break;
+ default: UNREACHABLE();
+ }
+ break;
+ case GL_UNSIGNED_SHORT_5_6_5:
+ switch(format)
+ {
+ case GL_RGB:
+ loadRGB565ImageData(xoffset, yoffset, width, height, inputPitch, input, buffer);
+ break;
+ default: UNREACHABLE();
+ }
+ break;
+ case GL_UNSIGNED_SHORT_4_4_4_4:
+ switch(format)
+ {
+ case GL_RGBA:
+ loadRGBA4444ImageData(xoffset, yoffset, width, height, inputPitch, input, buffer);
+ break;
+ default: UNREACHABLE();
+ }
+ break;
+ case GL_UNSIGNED_SHORT_5_5_5_1:
+ switch(format)
+ {
+ case GL_RGBA:
+ loadRGBA5551ImageData(xoffset, yoffset, width, height, inputPitch, input, buffer);
+ break;
+ default: UNREACHABLE();
+ }
+ break;
+ case GL_FLOAT:
+ switch(format)
+ {
+ // float textures are converted to RGBA, not BGRA
+ case GL_ALPHA:
+ loadAlphaFloatImageData(xoffset, yoffset, width, height, inputPitch, input, buffer);
+ break;
+ case GL_LUMINANCE:
+ loadLuminanceFloatImageData(xoffset, yoffset, width, height, inputPitch, input, buffer);
+ break;
+ case GL_LUMINANCE_ALPHA:
+ loadLuminanceAlphaFloatImageData(xoffset, yoffset, width, height, inputPitch, input, buffer);
+ break;
+ case GL_RGB:
+ loadRGBFloatImageData(xoffset, yoffset, width, height, inputPitch, input, buffer);
+ break;
+ case GL_RGBA:
+ loadRGBAFloatImageData(xoffset, yoffset, width, height, inputPitch, input, buffer);
+ break;
+ default: UNREACHABLE();
+ }
+ break;
+ case GL_HALF_FLOAT_OES:
+ switch(format)
+ {
+ // float textures are converted to RGBA, not BGRA
+ case GL_ALPHA:
+ loadAlphaHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, buffer);
+ break;
+ case GL_LUMINANCE:
+ loadLuminanceHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, buffer);
+ break;
+ case GL_LUMINANCE_ALPHA:
+ loadLuminanceAlphaHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, buffer);
+ break;
+ case GL_RGB:
+ loadRGBHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, buffer);
+ break;
+ case GL_RGBA:
+ loadRGBAHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, buffer);
+ break;
+ default: UNREACHABLE();
+ }
+ break;
+ case GL_UNSIGNED_SHORT:
+ loadD16ImageData(xoffset, yoffset, width, height, inputPitch, input, buffer);
+ break;
+ case GL_UNSIGNED_INT:
+ loadD32ImageData(xoffset, yoffset, width, height, inputPitch, input, buffer);
+ break;
+ case GL_UNSIGNED_INT_24_8_OES:
+ loadD24S8ImageData(xoffset, yoffset, width, height, inputPitch, input, buffer);
+ break;
+ default: UNREACHABLE();
+ }
+ }
+
+ unlock();
+ }
+
+ void Image::loadAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const
+ {
+ for(int y = 0; y < height; y++)
+ {
+ const unsigned char *source = static_cast<const unsigned char*>(input) + y * inputPitch;
+ unsigned char *dest = static_cast<unsigned char*>(buffer) + (y + yoffset) * getPitch() + xoffset;
+
+ memcpy(dest, source, width);
+ }
+ }
+
+ void Image::loadAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const
+ {
+ for(int y = 0; y < height; y++)
+ {
+ const float *source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+ float *dest = reinterpret_cast<float*>(static_cast<unsigned char*>(buffer) + (y + yoffset) * getPitch() + xoffset * 16);
+
+ 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::loadAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const
+ {
+ for(int y = 0; y < height; y++)
+ {
+ const unsigned short *source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+ unsigned short *dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(buffer) + (y + yoffset) * getPitch() + xoffset * 8);
+
+ 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::loadLuminanceImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const
+ {
+ for(int y = 0; y < height; y++)
+ {
+ const unsigned char *source = static_cast<const unsigned char*>(input) + y * inputPitch;
+ unsigned char *dest = static_cast<unsigned char*>(buffer) + (y + yoffset) * getPitch() + xoffset;
+
+ memcpy(dest, source, width);
+ }
+ }
+
+ void Image::loadLuminanceFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const
+ {
+ for(int y = 0; y < height; y++)
+ {
+ const float *source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+ float *dest = reinterpret_cast<float*>(static_cast<unsigned char*>(buffer) + (y + yoffset) * getPitch() + xoffset * 16);
+
+ 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::loadLuminanceHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const
+ {
+ for(int y = 0; y < height; y++)
+ {
+ const unsigned short *source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+ unsigned short *dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(buffer) + (y + yoffset) * getPitch() + xoffset * 8);
+
+ 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::loadLuminanceAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const
+ {
+ for(int y = 0; y < height; y++)
+ {
+ const unsigned char *source = static_cast<const unsigned char*>(input) + y * inputPitch;
+ unsigned char *dest = static_cast<unsigned char*>(buffer) + (y + yoffset) * getPitch() + xoffset * 2;
+
+ memcpy(dest, source, width * 2);
+ }
+ }
+
+ void Image::loadLuminanceAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const
+ {
+ for(int y = 0; y < height; y++)
+ {
+ const float *source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+ float *dest = reinterpret_cast<float*>(static_cast<unsigned char*>(buffer) + (y + yoffset) * getPitch() + xoffset * 16);
+
+ 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::loadLuminanceAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const
+ {
+ for(int y = 0; y < height; y++)
+ {
+ const unsigned short *source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+ unsigned short *dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(buffer) + (y + yoffset) * getPitch() + xoffset * 8);
+
+ 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::loadRGBUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const
+ {
+ for(int y = 0; y < height; y++)
+ {
+ const unsigned char *source = static_cast<const unsigned char*>(input) + y * inputPitch;
+ unsigned char *dest = static_cast<unsigned char*>(buffer) + (y + yoffset) * getPitch() + xoffset * 4;
+
+ 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::loadRGB565ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const
+ {
+ for(int y = 0; y < height; y++)
+ {
+ const unsigned short *source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+ unsigned char *dest = static_cast<unsigned char*>(buffer) + (y + yoffset) * getPitch() + xoffset * 4;
+
+ 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::loadRGBFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const
+ {
+ for(int y = 0; y < height; y++)
+ {
+ const float *source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+ float *dest = reinterpret_cast<float*>(static_cast<unsigned char*>(buffer) + (y + yoffset) * getPitch() + xoffset * 16);
+
+ 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::loadRGBHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const
+ {
+ for(int y = 0; y < height; y++)
+ {
+ const unsigned short *source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+ unsigned short *dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(buffer) + (y + yoffset) * getPitch() + xoffset * 8);
+
+ 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::loadRGBAUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const
+ {
+ for(int y = 0; y < height; y++)
+ {
+ const unsigned int *source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+ unsigned int *dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(buffer) + (y + yoffset) * getPitch() + xoffset * 4);
+
+ for(int x = 0; x < width; x++)
+ {
+ unsigned int rgba = source[x];
+ dest[x] = (rgba & 0xFF00FF00) | ((rgba << 16) & 0x00FF0000) | ((rgba >> 16) & 0x000000FF);
+ }
+ }
+ }
+
+ void Image::loadRGBA4444ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const
+ {
+ for(int y = 0; y < height; y++)
+ {
+ const unsigned short *source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+ unsigned char *dest = static_cast<unsigned char*>(buffer) + (y + yoffset) * getPitch() + xoffset * 4;
+
+ 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::loadRGBA5551ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const
+ {
+ for(int y = 0; y < height; y++)
+ {
+ const unsigned short *source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+ unsigned char *dest = static_cast<unsigned char*>(buffer) + (y + yoffset) * getPitch() + xoffset * 4;
+
+ 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::loadRGBAFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const
+ {
+ for(int y = 0; y < height; y++)
+ {
+ const float *source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+ float *dest = reinterpret_cast<float*>(static_cast<unsigned char*>(buffer) + (y + yoffset) * getPitch() + xoffset * 16);
+
+ memcpy(dest, source, width * 16);
+ }
+ }
+
+ void Image::loadRGBAHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const
+ {
+ for(int y = 0; y < height; y++)
+ {
+ const unsigned char *source = static_cast<const unsigned char*>(input) + y * inputPitch;
+ unsigned char *dest = static_cast<unsigned char*>(buffer) + (y + yoffset) * getPitch() + xoffset * 8;
+
+ memcpy(dest, source, width * 8);
+ }
+ }
+
+ void Image::loadBGRAImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const
+ {
+ for(int y = 0; y < height; y++)
+ {
+ const unsigned char *source = static_cast<const unsigned char*>(input) + y * inputPitch;
+ unsigned char *dest = static_cast<unsigned char*>(buffer) + (y + yoffset) * getPitch() + xoffset * 4;
+
+ memcpy(dest, source, width*4);
+ }
+ }
+
+ void Image::loadD16ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const
+ {
+ for(int y = 0; y < height; y++)
+ {
+ const unsigned short *source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+ float *dest = reinterpret_cast<float*>(static_cast<unsigned char*>(buffer) + (y + yoffset) * getPitch() + xoffset * 4);
+
+ for(int x = 0; x < width; x++)
+ {
+ dest[x] = (float)source[x] / 0xFFFF;
+ }
+ }
+ }
+
+ void Image::loadD32ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const
+ {
+ for(int y = 0; y < height; y++)
+ {
+ const unsigned int *source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+ float *dest = reinterpret_cast<float*>(static_cast<unsigned char*>(buffer) + (y + yoffset) * getPitch() + xoffset * 4);
+
+ for(int x = 0; x < width; x++)
+ {
+ dest[x] = (float)source[x] / 0xFFFFFFFF;
+ }
+ }
+ }
+
+ void Image::loadD24S8ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer)
+ {
+ for(int y = 0; y < height; y++)
+ {
+ const unsigned int *source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+ float *dest = reinterpret_cast<float*>(static_cast<unsigned char*>(buffer) + (y + yoffset) * getPitch() + xoffset * 4);
+
+ for(int x = 0; x < width; x++)
+ {
+ dest[x] = (float)(source[x] & 0xFFFFFF00) / 0xFFFFFF00;
+ }
+ }
+
+ unsigned char *stencil = reinterpret_cast<unsigned char*>(lockStencil(0, sw::PUBLIC));
+
+ if(stencil)
+ {
+ for(int y = 0; y < height; y++)
+ {
+ const unsigned int *source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+ unsigned char *dest = static_cast<unsigned char*>(stencil) + (y + yoffset) * getStencilPitchB() + xoffset;
+
+ for(int x = 0; x < width; x++)
+ {
+ dest[x] = static_cast<unsigned char>(source[x] & 0x000000FF); // FIXME: Quad layout
+ }
+ }
+
+ unlockStencil();
+ }
+ }
+
+ void Image::loadCompressedData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
+ {
+ int inputPitch = ComputeCompressedPitch(width, format);
+ int rows = imageSize / inputPitch;
+ void *buffer = lock(xoffset, yoffset, sw::LOCK_WRITEONLY);
+
+ if(buffer)
+ {
+ for(int i = 0; i < rows; i++)
+ {
+ memcpy((void*)((GLbyte*)buffer + i * getPitch()), (void*)((GLbyte*)pixels + i * inputPitch), inputPitch);
+ }
+ }
+
+ unlock();
+ }
+}
\ No newline at end of file
diff --git a/src/GLES2/libGLES_CM/Image.hpp b/src/GLES2/libGLES_CM/Image.hpp
new file mode 100644
index 0000000..faae7d5
--- /dev/null
+++ b/src/GLES2/libGLES_CM/Image.hpp
@@ -0,0 +1,94 @@
+// SwiftShader Software Renderer
+//
+// Copyright(c) 2005-2013 TransGaming Inc.
+//
+// All rights reserved. No part of this software may be copied, distributed, transmitted,
+// transcribed, stored in a retrieval system, translated into any human or computer
+// language by any means, or disclosed to third parties without the explicit written
+// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
+// or implied, including but not limited to any patent rights, are granted to you.
+//
+
+#ifndef gl_Image_hpp
+#define gl_Image_hpp
+
+#include "Renderer/Surface.hpp"
+
+#define GL_APICALL
+#include <GLES2/gl2.h>
+
+namespace gl
+{
+ class Texture;
+
+ class Image : public sw::Surface
+ {
+ public:
+ Image(Texture *parentTexture, GLsizei width, GLsizei height, GLenum format, GLenum type);
+ Image(Texture *parentTexture, GLsizei width, GLsizei height, sw::Format internalFormat, GLenum format, GLenum type, int multiSampleDepth, bool lockable, bool renderTarget);
+
+ void loadImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *input);
+ void loadCompressedData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels);
+
+ void *lock(unsigned int left, unsigned int top, sw::Lock lock);
+ unsigned int getPitch() const;
+ void unlock();
+
+ int getWidth();
+ int getHeight();
+ GLenum getFormat();
+ GLenum getType();
+ virtual sw::Format getInternalFormat();
+ virtual int getMultiSampleDepth();
+
+ virtual void addRef();
+ virtual void release();
+ void unbind(); // Break parent ownership and release
+
+ virtual bool isShared() const;
+ void markShared();
+
+ static sw::Format selectInternalFormat(GLenum format, GLenum type);
+ static int bytes(sw::Format format);
+
+ private:
+ virtual ~Image();
+
+ void loadAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const;
+ void loadAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const;
+ void loadAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const;
+ void loadLuminanceImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const;
+ void loadLuminanceFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const;
+ void loadLuminanceHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const;
+ void loadLuminanceAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const;
+ void loadLuminanceAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const;
+ void loadLuminanceAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const;
+ void loadRGBUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const;
+ void loadRGB565ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const;
+ void loadRGBFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const;
+ void loadRGBHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const;
+ void loadRGBAUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const;
+ void loadRGBA4444ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const;
+ void loadRGBA5551ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const;
+ void loadRGBAFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const;
+ void loadRGBAHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const;
+ void loadBGRAImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const;
+ void loadD16ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const;
+ void loadD32ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const;
+ void loadD24S8ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer);
+
+ Texture *parentTexture;
+ bool shared; // Used as an EGLImage
+
+ const GLsizei width;
+ const GLsizei height;
+ const GLenum format;
+ const GLenum type;
+ const sw::Format internalFormat;
+ const int multiSampleDepth;
+
+ volatile int referenceCount;
+ };
+}
+
+#endif // gl_Image_hpp
diff --git a/src/GLES2/libGLES_CM/IndexDataManager.cpp b/src/GLES2/libGLES_CM/IndexDataManager.cpp
new file mode 100644
index 0000000..3dbfe44
--- /dev/null
+++ b/src/GLES2/libGLES_CM/IndexDataManager.cpp
@@ -0,0 +1,259 @@
+// SwiftShader Software Renderer
+//
+// Copyright(c) 2005-2012 TransGaming Inc.
+//
+// All rights reserved. No part of this software may be copied, distributed, transmitted,
+// transcribed, stored in a retrieval system, translated into any human or computer
+// language by any means, or disclosed to third parties without the explicit written
+// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
+// or implied, including but not limited to any patent rights, are granted to you.
+//
+
+// IndexDataManager.cpp: Defines the IndexDataManager, a class that
+// runs the Buffer translation process for index buffers.
+
+#include "IndexDataManager.h"
+
+#include "Buffer.h"
+#include "common/debug.h"
+
+#include <string.h>
+#include <algorithm>
+
+namespace
+{
+ enum { INITIAL_INDEX_BUFFER_SIZE = 4096 * sizeof(GLuint) };
+}
+
+namespace gl
+{
+
+IndexDataManager::IndexDataManager()
+{
+ mStreamingBuffer = new StreamingIndexBuffer(INITIAL_INDEX_BUFFER_SIZE);
+
+ if(!mStreamingBuffer)
+ {
+ ERR("Failed to allocate the streaming index buffer.");
+ }
+}
+
+IndexDataManager::~IndexDataManager()
+{
+ delete mStreamingBuffer;
+}
+
+void copyIndices(GLenum type, const void *input, GLsizei count, void *output)
+{
+ if(type == GL_UNSIGNED_BYTE)
+ {
+ memcpy(output, input, count * sizeof(GLubyte));
+ }
+ 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 void *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 void *indices, TranslatedIndexData *translated)
+{
+ if(!mStreamingBuffer)
+ {
+ return GL_OUT_OF_MEMORY;
+ }
+
+ 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 = mStreamingBuffer;
+
+ sw::Resource *staticBuffer = buffer ? buffer->getResource() : NULL;
+
+ if(staticBuffer)
+ {
+ computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
+
+ translated->indexBuffer = staticBuffer;
+ translated->indexOffset = offset;
+ }
+ else
+ {
+ unsigned int streamOffset = 0;
+ int convertCount = count;
+
+ streamingBuffer->reserveSpace(convertCount * typeSize(type), type);
+ void *output = streamingBuffer->map(typeSize(type) * convertCount, &streamOffset);
+
+ if(output == NULL)
+ {
+ ERR("Failed to map index buffer.");
+ return GL_OUT_OF_MEMORY;
+ }
+
+ copyIndices(type, staticBuffer ? buffer->data() : indices, convertCount, output);
+ streamingBuffer->unmap();
+
+ computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
+
+ translated->indexBuffer = streamingBuffer->getResource();
+ translated->indexOffset = streamOffset;
+ }
+
+ return GL_NO_ERROR;
+}
+
+std::size_t IndexDataManager::typeSize(GLenum type)
+{
+ 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);
+ }
+}
+
+StreamingIndexBuffer::StreamingIndexBuffer(unsigned int initialSize) : mBufferSize(initialSize), mIndexBuffer(NULL)
+{
+ if(initialSize > 0)
+ {
+ mIndexBuffer = new sw::Resource(initialSize + 16);
+
+ if(!mIndexBuffer)
+ {
+ ERR("Out of memory allocating an index buffer of size %lu.", initialSize);
+ }
+ }
+
+ mWritePosition = 0;
+}
+
+StreamingIndexBuffer::~StreamingIndexBuffer()
+{
+ if(mIndexBuffer)
+ {
+ mIndexBuffer->destruct();
+ }
+}
+
+void *StreamingIndexBuffer::map(unsigned int requiredSpace, unsigned int *offset)
+{
+ void *mapPtr = NULL;
+
+ if(mIndexBuffer)
+ {
+ mapPtr = (char*)mIndexBuffer->lock(sw::PUBLIC) + mWritePosition;
+
+ if(!mapPtr)
+ {
+ ERR(" Lock failed");
+ return NULL;
+ }
+
+ *offset = mWritePosition;
+ mWritePosition += requiredSpace;
+ }
+
+ return mapPtr;
+}
+
+void StreamingIndexBuffer::unmap()
+{
+ if(mIndexBuffer)
+ {
+ mIndexBuffer->unlock();
+ }
+}
+
+void StreamingIndexBuffer::reserveSpace(unsigned int requiredSpace, GLenum type)
+{
+ if(requiredSpace > mBufferSize)
+ {
+ if(mIndexBuffer)
+ {
+ mIndexBuffer->destruct();
+ mIndexBuffer = 0;
+ }
+
+ mBufferSize = std::max(requiredSpace, 2 * mBufferSize);
+
+ mIndexBuffer = new sw::Resource(mBufferSize + 16);
+
+ if(!mIndexBuffer)
+ {
+ ERR("Out of memory allocating an index buffer of size %lu.", mBufferSize);
+ }
+
+ mWritePosition = 0;
+ }
+ else if(mWritePosition + requiredSpace > mBufferSize) // Recycle
+ {
+ if(mIndexBuffer)
+ {
+ mIndexBuffer->destruct();
+ mIndexBuffer = new sw::Resource(mBufferSize + 16);
+ }
+
+ mWritePosition = 0;
+ }
+}
+
+sw::Resource *StreamingIndexBuffer::getResource() const
+{
+ return mIndexBuffer;
+}
+
+}
diff --git a/src/GLES2/libGLES_CM/IndexDataManager.h b/src/GLES2/libGLES_CM/IndexDataManager.h
new file mode 100644
index 0000000..059e9fc
--- /dev/null
+++ b/src/GLES2/libGLES_CM/IndexDataManager.h
@@ -0,0 +1,69 @@
+// SwiftShader Software Renderer
+//
+// Copyright(c) 2005-2012 TransGaming Inc.
+//
+// All rights reserved. No part of this software may be copied, distributed, transmitted,
+// transcribed, stored in a retrieval system, translated into any human or computer
+// language by any means, or disclosed to third parties without the explicit written
+// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
+// or implied, including but not limited to any patent rights, are granted to you.
+//
+
+// 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 "Context.h"
+
+#define GL_APICALL
+#include <GLES2/gl2.h>
+
+namespace gl
+{
+
+struct TranslatedIndexData
+{
+ unsigned int minIndex;
+ unsigned int maxIndex;
+ unsigned int indexOffset;
+
+ sw::Resource *indexBuffer;
+};
+
+class StreamingIndexBuffer
+{
+ public:
+ StreamingIndexBuffer(unsigned int initialSize);
+ virtual ~StreamingIndexBuffer();
+
+ void *map(unsigned int requiredSpace, unsigned int *offset);
+ void unmap();
+ void reserveSpace(unsigned int requiredSpace, GLenum type);
+
+ sw::Resource *getResource() const;
+
+ private:
+ sw::Resource *mIndexBuffer;
+ unsigned int mBufferSize;
+ unsigned int mWritePosition;
+};
+
+class IndexDataManager
+{
+ public:
+ IndexDataManager();
+ virtual ~IndexDataManager();
+
+ GLenum prepareIndexData(GLenum type, GLsizei count, Buffer *arrayElementBuffer, const void *indices, TranslatedIndexData *translated);
+
+ static std::size_t typeSize(GLenum type);
+
+ private:
+ StreamingIndexBuffer *mStreamingBuffer;
+};
+
+}
+
+#endif // LIBGLESV2_INDEXDATAMANAGER_H_
diff --git a/src/GLES2/libGLES_CM/Program.cpp b/src/GLES2/libGLES_CM/Program.cpp
new file mode 100644
index 0000000..ca0ddd6
--- /dev/null
+++ b/src/GLES2/libGLES_CM/Program.cpp
@@ -0,0 +1,2294 @@
+// SwiftShader Software Renderer
+//
+// Copyright(c) 2005-2013 TransGaming Inc.
+//
+// All rights reserved. No part of this software may be copied, distributed, transmitted,
+// transcribed, stored in a retrieval system, translated into any human or computer
+// language by any means, or disclosed to third parties without the explicit written
+// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
+// or implied, including but not limited to any patent rights, are granted to you.
+//
+
+// Program.cpp: Implements the Program class. Implements GL program objects
+// and related functionality. [OpenGL ES 2.0.24] section 2.10.3 page 28.
+
+#include "Program.h"
+
+#include "main.h"
+#include "Shader.h"
+#include "utilities.h"
+#include "common/debug.h"
+#include "Shader/PixelShader.hpp"
+#include "Shader/VertexShader.hpp"
+
+#include <string>
+#include <stdlib.h>
+
+namespace gl
+{
+ unsigned int Program::currentSerial = 1;
+
+ std::string str(int i)
+ {
+ char buffer[20];
+ sprintf(buffer, "%d", i);
+ return buffer;
+ }
+
+ Uniform::Uniform(GLenum type, GLenum precision, const std::string &name, unsigned int arraySize) : type(type), precision(precision), name(name), arraySize(arraySize)
+ {
+ int bytes = UniformTypeSize(type) * size();
+ data = new unsigned char[bytes];
+ memset(data, 0, bytes);
+ dirty = true;
+
+ psRegisterIndex = -1;
+ vsRegisterIndex = -1;
+ }
+
+ Uniform::~Uniform()
+ {
+ delete[] data;
+ }
+
+ bool Uniform::isArray() const
+ {
+ return arraySize >= 1;
+ }
+
+ int Uniform::size() const
+ {
+ return arraySize > 0 ? arraySize : 1;
+ }
+
+ int Uniform::registerCount() const
+ {
+ return size() * VariableRowCount(type);
+ }
+
+ UniformLocation::UniformLocation(const std::string &name, unsigned int element, unsigned int index) : name(name), element(element), index(index)
+ {
+ }
+
+ Program::Program(ResourceManager *manager, GLuint handle) : resourceManager(manager), handle(handle), serial(issueSerial())
+ {
+ device = getDevice();
+
+ fragmentShader = 0;
+ vertexShader = 0;
+ pixelBinary = 0;
+ vertexBinary = 0;
+
+ infoLog = 0;
+ validated = false;
+
+ unlink();
+
+ orphaned = false;
+ referenceCount = 0;
+ }
+
+ Program::~Program()
+ {
+ unlink();
+
+ if(vertexShader)
+ {
+ vertexShader->release();
+ }
+
+ if(fragmentShader)
+ {
+ fragmentShader->release();
+ }
+ }
+
+ bool Program::attachShader(Shader *shader)
+ {
+ if(shader->getType() == GL_VERTEX_SHADER)
+ {
+ if(vertexShader)
+ {
+ return false;
+ }
+
+ vertexShader = (VertexShader*)shader;
+ vertexShader->addRef();
+ }
+ else if(shader->getType() == GL_FRAGMENT_SHADER)
+ {
+ if(fragmentShader)
+ {
+ return false;
+ }
+
+ fragmentShader = (FragmentShader*)shader;
+ fragmentShader->addRef();
+ }
+ else UNREACHABLE();
+
+ return true;
+ }
+
+ bool Program::detachShader(Shader *shader)
+ {
+ if(shader->getType() == GL_VERTEX_SHADER)
+ {
+ if(vertexShader != shader)
+ {
+ return false;
+ }
+
+ vertexShader->release();
+ vertexShader = 0;
+ }
+ else if(shader->getType() == GL_FRAGMENT_SHADER)
+ {
+ if(fragmentShader != shader)
+ {
+ return false;
+ }
+
+ fragmentShader->release();
+ fragmentShader = 0;
+ }
+ else UNREACHABLE();
+
+ return true;
+ }
+
+ int Program::getAttachedShadersCount() const
+ {
+ return (vertexShader ? 1 : 0) + (fragmentShader ? 1 : 0);
+ }
+
+ sw::PixelShader *Program::getPixelShader()
+ {
+ return pixelBinary;
+ }
+
+ sw::VertexShader *Program::getVertexShader()
+ {
+ return vertexBinary;
+ }
+
+ void Program::bindAttributeLocation(GLuint index, const char *name)
+ {
+ if(index < MAX_VERTEX_ATTRIBS)
+ {
+ for(int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
+ {
+ attributeBinding[i].erase(name);
+ }
+
+ attributeBinding[index].insert(name);
+ }
+ }
+
+ GLuint Program::getAttributeLocation(const char *name)
+ {
+ if(name)
+ {
+ for(int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
+ {
+ if(linkedAttribute[index].name == std::string(name))
+ {
+ return index;
+ }
+ }
+ }
+
+ return -1;
+ }
+
+ int Program::getAttributeStream(int attributeIndex)
+ {
+ ASSERT(attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS);
+
+ return attributeStream[attributeIndex];
+ }
+
+ // Returns the index of the texture image unit (0-19) corresponding to a sampler index (0-15 for the pixel shader and 0-3 for the vertex shader)
+ GLint Program::getSamplerMapping(sw::SamplerType type, unsigned int samplerIndex)
+ {
+ GLuint logicalTextureUnit = -1;
+
+ switch(type)
+ {
+ case sw::SAMPLER_PIXEL:
+ ASSERT(samplerIndex < sizeof(samplersPS) / sizeof(samplersPS[0]));
+
+ if(samplersPS[samplerIndex].active)
+ {
+ logicalTextureUnit = samplersPS[samplerIndex].logicalTextureUnit;
+ }
+ break;
+ case sw::SAMPLER_VERTEX:
+ ASSERT(samplerIndex < sizeof(samplersVS) / sizeof(samplersVS[0]));
+
+ if(samplersVS[samplerIndex].active)
+ {
+ logicalTextureUnit = samplersVS[samplerIndex].logicalTextureUnit;
+ }
+ break;
+ default: UNREACHABLE();
+ }
+
+ if(logicalTextureUnit >= 0 && logicalTextureUnit < MAX_COMBINED_TEXTURE_IMAGE_UNITS)
+ {
+ return logicalTextureUnit;
+ }
+
+ return -1;
+ }
+
+ // Returns the texture type for a given sampler type and index (0-15 for the pixel shader and 0-3 for the vertex shader)
+ TextureType Program::getSamplerTextureType(sw::SamplerType type, unsigned int samplerIndex)
+ {
+ switch(type)
+ {
+ case sw::SAMPLER_PIXEL:
+ ASSERT(samplerIndex < sizeof(samplersPS)/sizeof(samplersPS[0]));
+ ASSERT(samplersPS[samplerIndex].active);
+ return samplersPS[samplerIndex].textureType;
+ case sw::SAMPLER_VERTEX:
+ ASSERT(samplerIndex < sizeof(samplersVS)/sizeof(samplersVS[0]));
+ ASSERT(samplersVS[samplerIndex].active);
+ return samplersVS[samplerIndex].textureType;
+ default: UNREACHABLE();
+ }
+
+ return TEXTURE_2D;
+ }
+
+ GLint Program::getUniformLocation(std::string name)
+ {
+ 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 = uniformIndex.size();
+ for(unsigned int location = 0; location < numUniforms; location++)
+ {
+ if(uniformIndex[location].name == name &&
+ uniformIndex[location].element == subscript)
+ {
+ return location;
+ }
+ }
+
+ return -1;
+ }
+
+ bool Program::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)
+ {
+ if(location < 0 || location >= (int)uniformIndex.size())
+ {
+ return false;
+ }
+
+ Uniform *targetUniform = uniforms[uniformIndex[location].index];
+ targetUniform->dirty = true;
+
+ int size = targetUniform->size();
+
+ if(size == 1 && count > 1)
+ {
+ return false; // Attempting to write an array to a non-array uniform is an INVALID_OPERATION
+ }
+
+ count = std::min(size - (int)uniformIndex[location].element, count);
+
+ if(targetUniform->type == GL_FLOAT)
+ {
+ memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLfloat),
+ v, sizeof(GLfloat) * count);
+ }
+ else if(targetUniform->type == GL_BOOL)
+ {
+ GLboolean *boolParams = (GLboolean*)targetUniform->data + uniformIndex[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 Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
+ {
+ if(location < 0 || location >= (int)uniformIndex.size())
+ {
+ return false;
+ }
+
+ Uniform *targetUniform = uniforms[uniformIndex[location].index];
+ targetUniform->dirty = true;
+
+ int size = targetUniform->size();
+
+ if(size == 1 && count > 1)
+ {
+ return false; // Attempting to write an array to a non-array uniform is an INVALID_OPERATION
+ }
+
+ count = std::min(size - (int)uniformIndex[location].element, count);
+
+ if(targetUniform->type == GL_FLOAT_VEC2)
+ {
+ memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLfloat) * 2,
+ v, 2 * sizeof(GLfloat) * count);
+ }
+ else if(targetUniform->type == GL_BOOL_VEC2)
+ {
+ GLboolean *boolParams = (GLboolean*)targetUniform->data + uniformIndex[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 Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
+ {
+ if(location < 0 || location >= (int)uniformIndex.size())
+ {
+ return false;
+ }
+
+ Uniform *targetUniform = uniforms[uniformIndex[location].index];
+ targetUniform->dirty = true;
+
+ int size = targetUniform->size();
+
+ if(size == 1 && count > 1)
+ {
+ return false; // Attempting to write an array to a non-array uniform is an INVALID_OPERATION
+ }
+
+ count = std::min(size - (int)uniformIndex[location].element, count);
+
+ if(targetUniform->type == GL_FLOAT_VEC3)
+ {
+ memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLfloat) * 3,
+ v, 3 * sizeof(GLfloat) * count);
+ }
+ else if(targetUniform->type == GL_BOOL_VEC3)
+ {
+ GLboolean *boolParams = (GLboolean*)targetUniform->data + uniformIndex[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 Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
+ {
+ if(location < 0 || location >= (int)uniformIndex.size())
+ {
+ return false;
+ }
+
+ Uniform *targetUniform = uniforms[uniformIndex[location].index];
+ targetUniform->dirty = true;
+
+ int size = targetUniform->size();
+
+ if(size == 1 && count > 1)
+ {
+ return false; // Attempting to write an array to a non-array uniform is an INVALID_OPERATION
+ }
+
+ count = std::min(size - (int)uniformIndex[location].element, count);
+
+ if(targetUniform->type == GL_FLOAT_VEC4)
+ {
+ memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLfloat) * 4,
+ v, 4 * sizeof(GLfloat) * count);
+ }
+ else if(targetUniform->type == GL_BOOL_VEC4)
+ {
+ GLboolean *boolParams = (GLboolean*)targetUniform->data + uniformIndex[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;
+ }
+
+ bool Program::setUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
+ {
+ if(location < 0 || location >= (int)uniformIndex.size())
+ {
+ return false;
+ }
+
+ Uniform *targetUniform = uniforms[uniformIndex[location].index];
+ targetUniform->dirty = true;
+
+ if(targetUniform->type != GL_FLOAT_MAT2)
+ {
+ return false;
+ }
+
+ int size = targetUniform->size();
+
+ if(size == 1 && count > 1)
+ {
+ return false; // Attempting to write an array to a non-array uniform is an INVALID_OPERATION
+ }
+
+ count = std::min(size - (int)uniformIndex[location].element, count);
+
+ memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLfloat) * 4,
+ value, 4 * sizeof(GLfloat) * count);
+
+ return true;
+ }
+
+ bool Program::setUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
+ {
+ if(location < 0 || location >= (int)uniformIndex.size())
+ {
+ return false;
+ }
+
+ Uniform *targetUniform = uniforms[uniformIndex[location].index];
+ targetUniform->dirty = true;
+
+ if(targetUniform->type != GL_FLOAT_MAT3)
+ {
+ return false;
+ }
+
+ int size = targetUniform->size();
+
+ if(size == 1 && count > 1)
+ {
+ return false; // Attempting to write an array to a non-array uniform is an INVALID_OPERATION
+ }
+
+ count = std::min(size - (int)uniformIndex[location].element, count);
+
+ memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLfloat) * 9,
+ value, 9 * sizeof(GLfloat) * count);
+
+ return true;
+ }
+
+ bool Program::setUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
+ {
+ if(location < 0 || location >= (int)uniformIndex.size())
+ {
+ return false;
+ }
+
+ Uniform *targetUniform = uniforms[uniformIndex[location].index];
+ targetUniform->dirty = true;
+
+ if(targetUniform->type != GL_FLOAT_MAT4)
+ {
+ return false;
+ }
+
+ int size = targetUniform->size();
+
+ if(size == 1 && count > 1)
+ {
+ return false; // Attempting to write an array to a non-array uniform is an INVALID_OPERATION
+ }
+
+ count = std::min(size - (int)uniformIndex[location].element, count);
+
+ memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLfloat) * 16,
+ value, 16 * sizeof(GLfloat) * count);
+
+ return true;
+ }
+
+ bool Program::setUniform1iv(GLint location, GLsizei count, const GLint *v)
+ {
+ if(location < 0 || location >= (int)uniformIndex.size())
+ {
+ return false;
+ }
+
+ Uniform *targetUniform = uniforms[uniformIndex[location].index];
+ targetUniform->dirty = true;
+
+ int size = targetUniform->size();
+
+ if(size == 1 && count > 1)
+ {
+ return false; // Attempting to write an array to a non-array uniform is an INVALID_OPERATION
+ }
+
+ count = std::min(size - (int)uniformIndex[location].element, count);
+
+ if(targetUniform->type == GL_INT ||
+ targetUniform->type == GL_SAMPLER_2D ||
+ targetUniform->type == GL_SAMPLER_CUBE ||
+ targetUniform->type == GL_SAMPLER_EXTERNAL_OES)
+ {
+ memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLint),
+ v, sizeof(GLint) * count);
+ }
+ else if(targetUniform->type == GL_BOOL)
+ {
+ GLboolean *boolParams = new GLboolean[count];
+
+ for(int i = 0; i < count; i++)
+ {
+ if(v[i] == 0)
+ {
+ boolParams[i] = GL_FALSE;
+ }
+ else
+ {
+ boolParams[i] = GL_TRUE;
+ }
+ }
+
+ memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLboolean),
+ boolParams, sizeof(GLboolean) * count);
+
+ delete[] boolParams;
+ }
+ else
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ bool Program::setUniform2iv(GLint location, GLsizei count, const GLint *v)
+ {
+ if(location < 0 || location >= (int)uniformIndex.size())
+ {
+ return false;
+ }
+
+ Uniform *targetUniform = uniforms[uniformIndex[location].index];
+ targetUniform->dirty = true;
+
+ int size = targetUniform->size();
+
+ if(size == 1 && count > 1)
+ {
+ return false; // Attempting to write an array to a non-array uniform is an INVALID_OPERATION
+ }
+
+ count = std::min(size - (int)uniformIndex[location].element, count);
+
+ if(targetUniform->type == GL_INT_VEC2)
+ {
+ memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLint) * 2,
+ v, 2 * sizeof(GLint) * count);
+ }
+ else if(targetUniform->type == GL_BOOL_VEC2)
+ {
+ GLboolean *boolParams = new GLboolean[count * 2];
+
+ for(int i = 0; i < count * 2; i++)
+ {
+ if(v[i] == 0)
+ {
+ boolParams[i] = GL_FALSE;
+ }
+ else
+ {
+ boolParams[i] = GL_TRUE;
+ }
+ }
+
+ memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLboolean) * 2,
+ boolParams, 2 * sizeof(GLboolean) * count);
+
+ delete[] boolParams;
+ }
+ else
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ bool Program::setUniform3iv(GLint location, GLsizei count, const GLint *v)
+ {
+ if(location < 0 || location >= (int)uniformIndex.size())
+ {
+ return false;
+ }
+
+ Uniform *targetUniform = uniforms[uniformIndex[location].index];
+ targetUniform->dirty = true;
+
+ int size = targetUniform->size();
+
+ if(size == 1 && count > 1)
+ {
+ return false; // Attempting to write an array to a non-array uniform is an INVALID_OPERATION
+ }
+
+ count = std::min(size - (int)uniformIndex[location].element, count);
+
+ if(targetUniform->type == GL_INT_VEC3)
+ {
+ memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLint) * 3,
+ v, 3 * sizeof(GLint) * count);
+ }
+ else if(targetUniform->type == GL_BOOL_VEC3)
+ {
+ GLboolean *boolParams = new GLboolean[count * 3];
+
+ for(int i = 0; i < count * 3; i++)
+ {
+ if(v[i] == 0)
+ {
+ boolParams[i] = GL_FALSE;
+ }
+ else
+ {
+ boolParams[i] = GL_TRUE;
+ }
+ }
+
+ memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLboolean) * 3,
+ boolParams, 3 * sizeof(GLboolean) * count);
+
+ delete[] boolParams;
+ }
+ else
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ bool Program::setUniform4iv(GLint location, GLsizei count, const GLint *v)
+ {
+ if(location < 0 || location >= (int)uniformIndex.size())
+ {
+ return false;
+ }
+
+ Uniform *targetUniform = uniforms[uniformIndex[location].index];
+ targetUniform->dirty = true;
+
+ int size = targetUniform->size();
+
+ if(size == 1 && count > 1)
+ {
+ return false; // Attempting to write an array to a non-array uniform is an INVALID_OPERATION
+ }
+
+ count = std::min(size - (int)uniformIndex[location].element, count);
+
+ if(targetUniform->type == GL_INT_VEC4)
+ {
+ memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLint) * 4,
+ v, 4 * sizeof(GLint) * count);
+ }
+ else if(targetUniform->type == GL_BOOL_VEC4)
+ {
+ GLboolean *boolParams = new GLboolean[count * 4];
+
+ for(int i = 0; i < count * 4; i++)
+ {
+ if(v[i] == 0)
+ {
+ boolParams[i] = GL_FALSE;
+ }
+ else
+ {
+ boolParams[i] = GL_TRUE;
+ }
+ }
+
+ memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLboolean) * 4,
+ boolParams, 4 * sizeof(GLboolean) * count);
+
+ delete[] boolParams;
+ }
+ else
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ bool Program::getUniformfv(GLint location, GLsizei *bufSize, GLfloat *params)
+ {
+ if(location < 0 || location >= (int)uniformIndex.size())
+ {
+ return false;
+ }
+
+ Uniform *targetUniform = uniforms[uniformIndex[location].index];
+ unsigned int count = UniformComponentCount(targetUniform->type);
+
+ // Sized query - ensure the provided buffer is large enough
+ if(bufSize && *bufSize < count * sizeof(GLfloat))
+ {
+ return false;
+ }
+
+ switch (UniformComponentType(targetUniform->type))
+ {
+ case GL_BOOL:
+ {
+ GLboolean *boolParams = (GLboolean*)targetUniform->data + uniformIndex[location].element * count;
+
+ 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 + uniformIndex[location].element * count * sizeof(GLfloat),
+ count * sizeof(GLfloat));
+ break;
+ case GL_INT:
+ {
+ GLint *intParams = (GLint*)targetUniform->data + uniformIndex[location].element * count;
+
+ for(unsigned int i = 0; i < count; i++)
+ {
+ params[i] = (float)intParams[i];
+ }
+ }
+ break;
+ default: UNREACHABLE();
+ }
+
+ return true;
+ }
+
+ bool Program::getUniformiv(GLint location, GLsizei *bufSize, GLint *params)
+ {
+ if(location < 0 || location >= (int)uniformIndex.size())
+ {
+ return false;
+ }
+
+ Uniform *targetUniform = uniforms[uniformIndex[location].index];
+ unsigned int count = UniformComponentCount(targetUniform->type);
+
+ // Sized query - ensure the provided buffer is large enough
+ if(bufSize && *bufSize < count * sizeof(GLint))
+ {
+ return false;
+ }
+
+ switch (UniformComponentType(targetUniform->type))
+ {
+ case GL_BOOL:
+ {
+ GLboolean *boolParams = targetUniform->data + uniformIndex[location].element * count;
+
+ for(unsigned int i = 0; i < count; i++)
+ {
+ params[i] = (GLint)boolParams[i];
+ }
+ }
+ break;
+ case GL_FLOAT:
+ {
+ GLfloat *floatParams = (GLfloat*)targetUniform->data + uniformIndex[location].element * count;
+
+ for(unsigned int i = 0; i < count; i++)
+ {
+ params[i] = (GLint)floatParams[i];
+ }
+ }
+ break;
+ case GL_INT:
+ memcpy(params, targetUniform->data + uniformIndex[location].element * count * sizeof(GLint),
+ count * sizeof(GLint));
+ break;
+ default: UNREACHABLE();
+ }
+
+ return true;
+ }
+
+ void Program::dirtyAllUniforms()
+ {
+ unsigned int numUniforms = uniforms.size();
+ for(unsigned int index = 0; index < numUniforms; index++)
+ {
+ uniforms[index]->dirty = true;
+ }
+ }
+
+ // Applies all the uniforms set for this program object to the device
+ void Program::applyUniforms()
+ {
+ unsigned int numUniforms = uniformIndex.size();
+ for(unsigned int location = 0; location < numUniforms; location++)
+ {
+ if(uniformIndex[location].element != 0)
+ {
+ continue;
+ }
+
+ Uniform *targetUniform = uniforms[uniformIndex[location].index];
+
+ if(targetUniform->dirty)
+ {
+ int size = targetUniform->size();
+ GLfloat *f = (GLfloat*)targetUniform->data;
+ GLint *i = (GLint*)targetUniform->data;
+ GLboolean *b = (GLboolean*)targetUniform->data;
+
+ switch(targetUniform->type)
+ {
+ case GL_BOOL: applyUniform1bv(location, size, b); break;
+ case GL_BOOL_VEC2: applyUniform2bv(location, size, b); break;
+ case GL_BOOL_VEC3: applyUniform3bv(location, size, b); break;
+ case GL_BOOL_VEC4: applyUniform4bv(location, size, b); break;
+ case GL_FLOAT: applyUniform1fv(location, size, f); break;
+ case GL_FLOAT_VEC2: applyUniform2fv(location, size, f); break;
+ case GL_FLOAT_VEC3: applyUniform3fv(location, size, f); break;
+ case GL_FLOAT_VEC4: applyUniform4fv(location, size, f); break;
+ case GL_FLOAT_MAT2: applyUniformMatrix2fv(location, size, f); break;
+ case GL_FLOAT_MAT3: applyUniformMatrix3fv(location, size, f); break;
+ case GL_FLOAT_MAT4: applyUniformMatrix4fv(location, size, f); break;
+ case GL_SAMPLER_2D:
+ case GL_SAMPLER_CUBE:
+ case GL_SAMPLER_EXTERNAL_OES:
+ case GL_INT: applyUniform1iv(location, size, i); break;
+ case GL_INT_VEC2: applyUniform2iv(location, size, i); break;
+ case GL_INT_VEC3: applyUniform3iv(location, size, i); break;
+ case GL_INT_VEC4: applyUniform4iv(location, size, i); break;
+ default:
+ UNREACHABLE();
+ }
+
+ targetUniform->dirty = false;
+ }
+ }
+ }
+
+ // 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 Program::packVaryings(const Varying *packing[][4])
+ {
+ for(VaryingList::iterator varying = fragmentShader->varyings.begin(); varying != fragmentShader->varyings.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 <= MAX_VARYING_VECTORS - 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 = MAX_VARYING_VECTORS - 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 < MAX_VARYING_VECTORS; 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 < MAX_VARYING_VECTORS; 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)
+ {
+ appendToInfoLog("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 < MAX_VARYING_VECTORS; r++)
+ {
+ if(packing[r][0] || packing[r][1] || packing[r][2] || packing[r][3])
+ {
+ registers++;
+ }
+ }
+
+ return registers;
+ }
+
+ bool Program::linkVaryings()
+ {
+ for(VaryingList::iterator input = fragmentShader->varyings.begin(); input != fragmentShader->varyings.end(); input++)
+ {
+ bool matched = false;
+
+ for(VaryingList::iterator output = vertexShader->varyings.begin(); output != vertexShader->varyings.end(); output++)
+ {
+ if(output->name == input->name)
+ {
+ if(output->type != input->type || output->size() != input->size())
+ {
+ appendToInfoLog("Type of vertex varying %s does not match that of the fragment varying", output->name.c_str());
+
+ return false;
+ }
+
+ matched = true;
+ break;
+ }
+ }
+
+ if(!matched)
+ {
+ appendToInfoLog("Fragment varying %s does not match any vertex varying", input->name.c_str());
+
+ return false;
+ }
+ }
+
+ VaryingList &psVaryings = fragmentShader->varyings;
+ VaryingList &vsVaryings = vertexShader->varyings;
+
+ for(VaryingList::iterator output = vsVaryings.begin(); output != vsVaryings.end(); output++)
+ {
+ for(VaryingList::iterator input = psVaryings.begin(); input != psVaryings.end(); input++)
+ {
+ if(output->name == input->name)
+ {
+ int in = input->reg;
+ int out = output->reg;
+ int components = VariableColumnCount(output->type);
+ int registers = VariableRowCount(output->type) * output->size();
+
+ ASSERT(in >= 0);
+
+ if(in + registers > MAX_VARYING_VECTORS)
+ {
+ appendToInfoLog("Too many varyings");
+ return false;
+ }
+
+ if(out >= 0)
+ {
+ if(out + registers > MAX_VARYING_VECTORS)
+ {
+ appendToInfoLog("Too many varyings");
+ return false;
+ }
+
+ for(int i = 0; i < registers; i++)
+ {
+ if(components >= 1) vertexBinary->output[out + i][0] = sw::Shader::Semantic(sw::Shader::USAGE_COLOR, in + i);
+ if(components >= 2) vertexBinary->output[out + i][1] = sw::Shader::Semantic(sw::Shader::USAGE_COLOR, in + i);
+ if(components >= 3) vertexBinary->output[out + i][2] = sw::Shader::Semantic(sw::Shader::USAGE_COLOR, in + i);
+ if(components >= 4) vertexBinary->output[out + i][3] = sw::Shader::Semantic(sw::Shader::USAGE_COLOR, in + i);
+ }
+ }
+ else // Vertex varying is declared but not written to
+ {
+ for(int i = 0; i < registers; i++)
+ {
+ if(components >= 1) pixelBinary->semantic[in + i][0] = sw::Shader::Semantic();
+ if(components >= 2) pixelBinary->semantic[in + i][1] = sw::Shader::Semantic();
+ if(components >= 3) pixelBinary->semantic[in + i][2] = sw::Shader::Semantic();
+ if(components >= 4) pixelBinary->semantic[in + i][3] = sw::Shader::Semantic();
+ }
+ }
+
+ break;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ // Links the 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
+ void Program::link()
+ {
+ unlink();
+
+ if(!fragmentShader || !fragmentShader->isCompiled())
+ {
+ return;
+ }
+
+ if(!vertexShader || !vertexShader->isCompiled())
+ {
+ return;
+ }
+
+ vertexBinary = new sw::VertexShader(vertexShader->getVertexShader());
+ pixelBinary = new sw::PixelShader(fragmentShader->getPixelShader());
+
+ if(!linkVaryings())
+ {
+ return;
+ }
+
+ if(!linkAttributes())
+ {
+ return;
+ }
+
+ if(!linkUniforms(fragmentShader))
+ {
+ return;
+ }
+
+ if(!linkUniforms(vertexShader))
+ {
+ return;
+ }
+
+ linked = true; // Success
+ }
+
+ // Determines the mapping between GL attributes and vertex stream usage indices
+ bool Program::linkAttributes()
+ {
+ unsigned int usedLocations = 0;
+
+ // Link attributes that have a binding location
+ for(sh::ActiveAttributes::iterator attribute = vertexShader->activeAttributes.begin(); attribute != vertexShader->activeAttributes.end(); attribute++)
+ {
+ int location = getAttributeBinding(attribute->name);
+
+ if(location != -1) // Set by glBindAttribLocation
+ {
+ if(!linkedAttribute[location].name.empty())
+ {
+ // Multiple active attributes bound to the same location; not an error
+ }
+
+ linkedAttribute[location] = *attribute;
+
+ int rows = VariableRowCount(attribute->type);
+
+ if(rows + location > MAX_VERTEX_ATTRIBS)
+ {
+ appendToInfoLog("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(sh::ActiveAttributes::iterator attribute = vertexShader->activeAttributes.begin(); attribute != vertexShader->activeAttributes.end(); attribute++)
+ {
+ int location = 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)
+ {
+ appendToInfoLog("Too many active attributes (%s)", attribute->name.c_str());
+ return false; // Fail to link
+ }
+
+ linkedAttribute[availableIndex] = *attribute;
+ }
+ }
+
+ for(int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
+ {
+ int index = vertexShader->getSemanticIndex(linkedAttribute[attributeIndex].name);
+ int rows = std::max(VariableRowCount(linkedAttribute[attributeIndex].type), 1);
+
+ for(int r = 0; r < rows; r++)
+ {
+ attributeStream[attributeIndex++] = index++;
+ }
+ }
+
+ return true;
+ }
+
+ int Program::getAttributeBinding(const std::string &name)
+ {
+ for(int location = 0; location < MAX_VERTEX_ATTRIBS; location++)
+ {
+ if(attributeBinding[location].find(name) != attributeBinding[location].end())
+ {
+ return location;
+ }
+ }
+
+ return -1;
+ }
+
+ bool Program::linkUniforms(Shader *shader)
+ {
+ const sh::ActiveUniforms &activeUniforms = shader->activeUniforms;
+
+ for(unsigned int uniformIndex = 0; uniformIndex < activeUniforms.size(); uniformIndex++)
+ {
+ const sh::Uniform &uniform = activeUniforms[uniformIndex];
+
+ if(!defineUniform(shader->getType(), uniform.type, uniform.precision, uniform.name, uniform.arraySize, uniform.registerIndex))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ bool Program::defineUniform(GLenum shader, GLenum type, GLenum precision, const std::string &name, unsigned int arraySize, int registerIndex)
+ {
+ if(type == GL_SAMPLER_2D || type == GL_SAMPLER_CUBE || type == GL_SAMPLER_EXTERNAL_OES)
+ {
+ int index = registerIndex;
+
+ do
+ {
+ if(shader == GL_VERTEX_SHADER)
+ {
+ if(index < MAX_VERTEX_TEXTURE_IMAGE_UNITS)
+ {
+ samplersVS[index].active = true;
+ samplersVS[index].textureType = (type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D;
+ samplersVS[index].logicalTextureUnit = 0;
+ }
+ else
+ {
+ appendToInfoLog("Vertex shader sampler count exceeds MAX_VERTEX_TEXTURE_IMAGE_UNITS (%d).", MAX_VERTEX_TEXTURE_IMAGE_UNITS);
+ return false;
+ }
+ }
+ else if(shader == GL_FRAGMENT_SHADER)
+ {
+ if(index < MAX_TEXTURE_IMAGE_UNITS)
+ {
+ samplersPS[index].active = true;
+ samplersPS[index].textureType = (type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D;
+ samplersPS[index].logicalTextureUnit = 0;
+ }
+ else
+ {
+ appendToInfoLog("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", MAX_TEXTURE_IMAGE_UNITS);
+ return false;
+ }
+ }
+ else UNREACHABLE();
+
+ index++;
+ }
+ while(index < registerIndex + arraySize);
+ }
+
+ Uniform *uniform = 0;
+ GLint location = getUniformLocation(name);
+
+ if(location >= 0) // Previously defined, types must match
+ {
+ uniform = uniforms[uniformIndex[location].index];
+
+ if(uniform->type != type)
+ {
+ appendToInfoLog("Types for uniform %s do not match between the vertex and fragment shader", uniform->name.c_str());
+ return false;
+ }
+
+ if(uniform->precision != precision)
+ {
+ appendToInfoLog("Precisions for uniform %s do not match between the vertex and fragment shader", uniform->name.c_str());
+ return false;
+ }
+ }
+ else
+ {
+ uniform = new Uniform(type, precision, name, arraySize);
+ }
+
+ if(!uniform)
+ {
+ return false;
+ }
+
+ if(shader == GL_VERTEX_SHADER)
+ {
+ uniform->vsRegisterIndex = registerIndex;
+ }
+ else if(shader == GL_FRAGMENT_SHADER)
+ {
+ uniform->psRegisterIndex = registerIndex;
+ }
+ else UNREACHABLE();
+
+ if(location == -1) // Not previously defined
+ {
+ uniforms.push_back(uniform);
+ unsigned int index = uniforms.size() - 1;
+
+ for(unsigned int i = 0; i < uniform->size(); i++)
+ {
+ uniformIndex.push_back(UniformLocation(name, i, index));
+ }
+ }
+
+ if(shader == GL_VERTEX_SHADER)
+ {
+ if(registerIndex + uniform->registerCount() > MAX_VERTEX_UNIFORM_VECTORS)
+ {
+ appendToInfoLog("Vertex shader active uniforms exceed GL_MAX_VERTEX_UNIFORM_VECTORS (%d)", MAX_VERTEX_UNIFORM_VECTORS);
+ return false;
+ }
+ }
+ else if(shader == GL_FRAGMENT_SHADER)
+ {
+ if(registerIndex + uniform->registerCount() > MAX_FRAGMENT_UNIFORM_VECTORS)
+ {
+ appendToInfoLog("Fragment shader active uniforms exceed GL_MAX_FRAGMENT_UNIFORM_VECTORS (%d)", MAX_FRAGMENT_UNIFORM_VECTORS);
+ return false;
+ }
+ }
+ else UNREACHABLE();
+
+ return true;
+ }
+
+ bool Program::applyUniform1bv(GLint location, GLsizei count, const GLboolean *v)
+ {
+ int vector[MAX_UNIFORM_VECTORS][4];
+
+ for(int i = 0; i < count; i++)
+ {
+ vector[i][0] = (v[0] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);
+ vector[i][1] = 0;
+ vector[i][2] = 0;
+ vector[i][3] = 0;
+
+ v += 1;
+ }
+
+ Uniform *targetUniform = uniforms[uniformIndex[location].index];
+
+ if(targetUniform->psRegisterIndex != -1)
+ {
+ device->setPixelShaderConstantF(targetUniform->psRegisterIndex, (float*)vector, targetUniform->registerCount());
+ }
+
+ if(targetUniform->vsRegisterIndex != -1)
+ {
+ device->setVertexShaderConstantF(targetUniform->vsRegisterIndex, (float*)vector, targetUniform->registerCount());
+ }
+
+ return true;
+ }
+
+ bool Program::applyUniform2bv(GLint location, GLsizei count, const GLboolean *v)
+ {
+ int vector[MAX_UNIFORM_VECTORS][4];
+
+ for(int i = 0; i < count; i++)
+ {
+ vector[i][0] = (v[0] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);
+ vector[i][1] = (v[1] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);
+ vector[i][2] = 0;
+ vector[i][3] = 0;
+
+ v += 2;
+ }
+
+ Uniform *targetUniform = uniforms[uniformIndex[location].index];
+
+ if(targetUniform->psRegisterIndex != -1)
+ {
+ device->setPixelShaderConstantF(targetUniform->psRegisterIndex, (float*)vector, targetUniform->registerCount());
+ }
+
+ if(targetUniform->vsRegisterIndex != -1)
+ {
+ device->setVertexShaderConstantF(targetUniform->vsRegisterIndex, (float*)vector, targetUniform->registerCount());
+ }
+
+ return true;
+ }
+
+ bool Program::applyUniform3bv(GLint location, GLsizei count, const GLboolean *v)
+ {
+ int vector[MAX_UNIFORM_VECTORS][4];
+
+ for(int i = 0; i < count; i++)
+ {
+ vector[i][0] = (v[0] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);
+ vector[i][1] = (v[1] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);
+ vector[i][2] = (v[2] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);
+ vector[i][3] = 0;
+
+ v += 3;
+ }
+
+ Uniform *targetUniform = uniforms[uniformIndex[location].index];
+
+ if(targetUniform->psRegisterIndex != -1)
+ {
+ device->setPixelShaderConstantF(targetUniform->psRegisterIndex, (float*)vector, targetUniform->registerCount());
+ }
+
+ if(targetUniform->vsRegisterIndex != -1)
+ {
+ device->setVertexShaderConstantF(targetUniform->vsRegisterIndex, (float*)vector, targetUniform->registerCount());
+ }
+
+ return true;
+ }
+
+ bool Program::applyUniform4bv(GLint location, GLsizei count, const GLboolean *v)
+ {
+ int vector[MAX_UNIFORM_VECTORS][4];
+
+ for(int i = 0; i < count; i++)
+ {
+ vector[i][0] = (v[0] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);
+ vector[i][1] = (v[1] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);
+ vector[i][2] = (v[2] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);
+ vector[i][3] = (v[3] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);
+
+ v += 4;
+ }
+
+ Uniform *targetUniform = uniforms[uniformIndex[location].index];
+
+ if(targetUniform->psRegisterIndex != -1)
+ {
+ device->setPixelShaderConstantF(targetUniform->psRegisterIndex, (float*)vector, targetUniform->registerCount());
+ }
+
+ if(targetUniform->vsRegisterIndex != -1)
+ {
+ device->setVertexShaderConstantF(targetUniform->vsRegisterIndex, (float*)vector, targetUniform->registerCount());
+ }
+
+ return true;
+ }
+
+ bool Program::applyUniform1fv(GLint location, GLsizei count, const GLfloat *v)
+ {
+ float vector[MAX_UNIFORM_VECTORS][4];
+
+ for(int i = 0; i < count; i++)
+ {
+ vector[i][0] = v[0];
+ vector[i][1] = 0;
+ vector[i][2] = 0;
+ vector[i][3] = 0;
+
+ v += 1;
+ }
+
+ Uniform *targetUniform = uniforms[uniformIndex[location].index];
+
+ if(targetUniform->psRegisterIndex != -1)
+ {
+ device->setPixelShaderConstantF(targetUniform->psRegisterIndex, (float*)vector, targetUniform->registerCount());
+ }
+
+ if(targetUniform->vsRegisterIndex != -1)
+ {
+ device->setVertexShaderConstantF(targetUniform->vsRegisterIndex, (float*)vector, targetUniform->registerCount());
+ }
+
+ return true;
+ }
+
+ bool Program::applyUniform2fv(GLint location, GLsizei count, const GLfloat *v)
+ {
+ float vector[MAX_UNIFORM_VECTORS][4];
+
+ for(int i = 0; i < count; i++)
+ {
+ vector[i][0] = v[0];
+ vector[i][1] = v[1];
+ vector[i][2] = 0;
+ vector[i][3] = 0;
+
+ v += 2;
+ }
+
+ Uniform *targetUniform = uniforms[uniformIndex[location].index];
+
+ if(targetUniform->psRegisterIndex != -1)
+ {
+ device->setPixelShaderConstantF(targetUniform->psRegisterIndex, (float*)vector, targetUniform->registerCount());
+ }
+
+ if(targetUniform->vsRegisterIndex != -1)
+ {
+ device->setVertexShaderConstantF(targetUniform->vsRegisterIndex, (float*)vector, targetUniform->registerCount());
+ }
+
+ return true;
+ }
+
+ bool Program::applyUniform3fv(GLint location, GLsizei count, const GLfloat *v)
+ {
+ float vector[MAX_UNIFORM_VECTORS][4];
+
+ for(int i = 0; i < count; i++)
+ {
+ vector[i][0] = v[0];
+ vector[i][1] = v[1];
+ vector[i][2] = v[2];
+ vector[i][3] = 0;
+
+ v += 3;
+ }
+
+ Uniform *targetUniform = uniforms[uniformIndex[location].index];
+
+ if(targetUniform->psRegisterIndex != -1)
+ {
+ device->setPixelShaderConstantF(targetUniform->psRegisterIndex, (float*)vector, targetUniform->registerCount());
+ }
+
+ if(targetUniform->vsRegisterIndex != -1)
+ {
+ device->setVertexShaderConstantF(targetUniform->vsRegisterIndex, (float*)vector, targetUniform->registerCount());
+ }
+
+ return true;
+ }
+
+ bool Program::applyUniform4fv(GLint location, GLsizei count, const GLfloat *v)
+ {
+ Uniform *targetUniform = uniforms[uniformIndex[location].index];
+
+ if(targetUniform->psRegisterIndex != -1)
+ {
+ device->setPixelShaderConstantF(targetUniform->psRegisterIndex, (float*)v, targetUniform->registerCount());
+ }
+
+ if(targetUniform->vsRegisterIndex != -1)
+ {
+ device->setVertexShaderConstantF(targetUniform->vsRegisterIndex, (float*)v, targetUniform->registerCount());
+ }
+
+ return true;
+ }
+
+ bool Program::applyUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
+ {
+ float matrix[(MAX_UNIFORM_VECTORS + 1) / 2][2][4];
+
+ for(int i = 0; i < count; i++)
+ {
+ matrix[i][0][0] = value[0]; matrix[i][0][1] = value[1]; matrix[i][0][2] = 0; matrix[i][0][3] = 0;
+ matrix[i][1][0] = value[2]; matrix[i][1][1] = value[3]; matrix[i][1][2] = 0; matrix[i][1][3] = 0;
+
+ value += 4;
+ }
+
+ Uniform *targetUniform = uniforms[uniformIndex[location].index];
+
+ if(targetUniform->psRegisterIndex != -1)
+ {
+ device->setPixelShaderConstantF(targetUniform->psRegisterIndex, (float*)matrix, targetUniform->registerCount());
+ }
+
+ if(targetUniform->vsRegisterIndex != -1)
+ {
+ device->setVertexShaderConstantF(targetUniform->vsRegisterIndex, (float*)matrix, targetUniform->registerCount());
+ }
+
+ return true;
+ }
+
+ bool Program::applyUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
+ {
+ float matrix[(MAX_UNIFORM_VECTORS + 2) / 3][3][4];
+
+ for(int i = 0; i < count; i++)
+ {
+ matrix[i][0][0] = value[0]; matrix[i][0][1] = value[1]; matrix[i][0][2] = value[2]; matrix[i][0][3] = 0;
+ matrix[i][1][0] = value[3]; matrix[i][1][1] = value[4]; matrix[i][1][2] = value[5]; matrix[i][1][3] = 0;
+ matrix[i][2][0] = value[6]; matrix[i][2][1] = value[7]; matrix[i][2][2] = value[8]; matrix[i][2][3] = 0;
+
+ value += 9;
+ }
+
+ Uniform *targetUniform = uniforms[uniformIndex[location].index];
+
+ if(targetUniform->psRegisterIndex != -1)
+ {
+ device->setPixelShaderConstantF(targetUniform->psRegisterIndex, (float*)matrix, targetUniform->registerCount());
+ }
+
+ if(targetUniform->vsRegisterIndex != -1)
+ {
+ device->setVertexShaderConstantF(targetUniform->vsRegisterIndex, (float*)matrix, targetUniform->registerCount());
+ }
+
+ return true;
+ }
+
+ bool Program::applyUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
+ {
+ Uniform *targetUniform = uniforms[uniformIndex[location].index];
+
+ if(targetUniform->psRegisterIndex != -1)
+ {
+ device->setPixelShaderConstantF(targetUniform->psRegisterIndex, (float*)value, targetUniform->registerCount());
+ }
+
+ if(targetUniform->vsRegisterIndex != -1)
+ {
+ device->setVertexShaderConstantF(targetUniform->vsRegisterIndex, (float*)value, targetUniform->registerCount());
+ }
+
+ return true;
+ }
+
+ bool Program::applyUniform1iv(GLint location, GLsizei count, const GLint *v)
+ {
+ float vector[MAX_UNIFORM_VECTORS][4];
+
+ for(int i = 0; i < count; i++)
+ {
+ vector[i][0] = (float)v[i];
+ vector[i][1] = 0;
+ vector[i][2] = 0;
+ vector[i][3] = 0;
+ }
+
+ Uniform *targetUniform = uniforms[uniformIndex[location].index];
+
+ if(targetUniform->psRegisterIndex != -1)
+ {
+ if(targetUniform->type == GL_SAMPLER_2D ||
+ targetUniform->type == GL_SAMPLER_CUBE ||
+ targetUniform->type == GL_SAMPLER_EXTERNAL_OES)
+ {
+ for(int i = 0; i < count; i++)
+ {
+ unsigned int samplerIndex = targetUniform->psRegisterIndex + i;
+
+ if(samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
+ {
+ ASSERT(samplersPS[samplerIndex].active);
+ samplersPS[samplerIndex].logicalTextureUnit = v[i];
+ }
+ }
+ }
+ else
+ {
+ device->setPixelShaderConstantF(targetUniform->psRegisterIndex, (float*)vector, targetUniform->registerCount());
+ }
+ }
+
+ if(targetUniform->vsRegisterIndex != -1)
+ {
+ if(targetUniform->type == GL_SAMPLER_2D ||
+ targetUniform->type == GL_SAMPLER_CUBE ||
+ targetUniform->type == GL_SAMPLER_EXTERNAL_OES)
+ {
+ for(int i = 0; i < count; i++)
+ {
+ unsigned int samplerIndex = targetUniform->vsRegisterIndex + i;
+
+ if(samplerIndex < MAX_VERTEX_TEXTURE_IMAGE_UNITS)
+ {
+ ASSERT(samplersVS[samplerIndex].active);
+ samplersVS[samplerIndex].logicalTextureUnit = v[i];
+ }
+ }
+ }
+ else
+ {
+ device->setVertexShaderConstantF(targetUniform->vsRegisterIndex, (float*)vector, targetUniform->registerCount());
+ }
+ }
+
+ return true;
+ }
+
+ bool Program::applyUniform2iv(GLint location, GLsizei count, const GLint *v)
+ {
+ float vector[MAX_UNIFORM_VECTORS][4];
+
+ for(int i = 0; i < count; i++)
+ {
+ vector[i][0] = (float)v[0];
+ vector[i][1] = (float)v[1];
+ vector[i][2] = 0;
+ vector[i][3] = 0;
+
+ v += 2;
+ }
+
+ Uniform *targetUniform = uniforms[uniformIndex[location].index];
+
+ if(targetUniform->psRegisterIndex != -1)
+ {
+ device->setPixelShaderConstantF(targetUniform->psRegisterIndex, (float*)vector, targetUniform->registerCount());
+ }
+
+ if(targetUniform->vsRegisterIndex != -1)
+ {
+ device->setVertexShaderConstantF(targetUniform->vsRegisterIndex, (float*)vector, targetUniform->registerCount());
+ }
+
+ return true;
+ }
+
+ bool Program::applyUniform3iv(GLint location, GLsizei count, const GLint *v)
+ {
+ float vector[MAX_UNIFORM_VECTORS][4];
+
+ for(int i = 0; i < count; i++)
+ {
+ vector[i][0] = (float)v[0];
+ vector[i][1] = (float)v[1];
+ vector[i][2] = (float)v[2];
+ vector[i][3] = 0;
+
+ v += 3;
+ }
+
+ Uniform *targetUniform = uniforms[uniformIndex[location].index];
+
+ if(targetUniform->psRegisterIndex != -1)
+ {
+ device->setPixelShaderConstantF(targetUniform->psRegisterIndex, (float*)vector, targetUniform->registerCount());
+ }
+
+ if(targetUniform->vsRegisterIndex != -1)
+ {
+ device->setVertexShaderConstantF(targetUniform->vsRegisterIndex, (float*)vector, targetUniform->registerCount());
+ }
+
+ return true;
+ }
+
+ bool Program::applyUniform4iv(GLint location, GLsizei count, const GLint *v)
+ {
+ float vector[MAX_UNIFORM_VECTORS][4];
+
+ for(int i = 0; i < count; i++)
+ {
+ vector[i][0] = (float)v[0];
+ vector[i][1] = (float)v[1];
+ vector[i][2] = (float)v[2];
+ vector[i][3] = (float)v[3];
+
+ v += 4;
+ }
+
+ Uniform *targetUniform = uniforms[uniformIndex[location].index];
+
+ if(targetUniform->psRegisterIndex != -1)
+ {
+ device->setPixelShaderConstantF(targetUniform->psRegisterIndex, (float*)vector, targetUniform->registerCount());
+ }
+
+ if(targetUniform->vsRegisterIndex != -1)
+ {
+ device->setVertexShaderConstantF(targetUniform->vsRegisterIndex, (float*)vector, targetUniform->registerCount());
+ }
+
+ return true;
+ }
+
+ void Program::appendToInfoLog(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(!infoLog)
+ {
+ infoLog = new char[infoLength + 2];
+ strcpy(infoLog, info);
+ strcpy(infoLog + infoLength, "\n");
+ }
+ else
+ {
+ size_t logLength = strlen(infoLog);
+ char *newLog = new char[logLength + infoLength + 2];
+ strcpy(newLog, infoLog);
+ strcpy(newLog + logLength, info);
+ strcpy(newLog + logLength + infoLength, "\n");
+
+ delete[] infoLog;
+ infoLog = newLog;
+ }
+ }
+
+ void Program::resetInfoLog()
+ {
+ if(infoLog)
+ {
+ delete[] infoLog;
+ infoLog = 0;
+ }
+ }
+
+ // Returns the program object to an unlinked state, before re-linking, or at destruction
+ void Program::unlink()
+ {
+ delete vertexBinary;
+ vertexBinary = 0;
+ delete pixelBinary;
+ pixelBinary = 0;
+
+ for(int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
+ {
+ linkedAttribute[index].name.clear();
+ attributeStream[index] = -1;
+ }
+
+ for(int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
+ {
+ samplersPS[index].active = false;
+ }
+
+ for(int index = 0; index < MAX_VERTEX_TEXTURE_IMAGE_UNITS; index++)
+ {
+ samplersVS[index].active = false;
+ }
+
+ while(!uniforms.empty())
+ {
+ delete uniforms.back();
+ uniforms.pop_back();
+ }
+
+ uniformIndex.clear();
+
+ delete[] infoLog;
+ infoLog = 0;
+
+ linked = false;
+ }
+
+ bool Program::isLinked()
+ {
+ return linked;
+ }
+
+ bool Program::isValidated() const
+ {
+ return validated;
+ }
+
+ void Program::release()
+ {
+ referenceCount--;
+
+ if(referenceCount == 0 && orphaned)
+ {
+ resourceManager->deleteProgram(handle);
+ }
+ }
+
+ void Program::addRef()
+ {
+ referenceCount++;
+ }
+
+ unsigned int Program::getRefCount() const
+ {
+ return referenceCount;
+ }
+
+ unsigned int Program::getSerial() const
+ {
+ return serial;
+ }
+
+ unsigned int Program::issueSerial()
+ {
+ return currentSerial++;
+ }
+
+ int Program::getInfoLogLength() const
+ {
+ if(!infoLog)
+ {
+ return 0;
+ }
+ else
+ {
+ return strlen(infoLog) + 1;
+ }
+ }
+
+ void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *buffer)
+ {
+ int index = 0;
+
+ if(bufSize > 0)
+ {
+ if(infoLog)
+ {
+ index = std::min(bufSize - 1, (int)strlen(infoLog));
+ memcpy(buffer, infoLog, index);
+ }
+
+ buffer[index] = '\0';
+ }
+
+ if(length)
+ {
+ *length = index;
+ }
+ }
+
+ void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders)
+ {
+ int total = 0;
+
+ if(vertexShader)
+ {
+ if(total < maxCount)
+ {
+ shaders[total] = vertexShader->getHandle();
+ }
+
+ total++;
+ }
+
+ if(fragmentShader)
+ {
+ if(total < maxCount)
+ {
+ shaders[total] = fragmentShader->getHandle();
+ }
+
+ total++;
+ }
+
+ if(count)
+ {
+ *count = total;
+ }
+ }
+
+ void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
+ {
+ // Skip over inactive attributes
+ unsigned int activeAttribute = 0;
+ unsigned int attribute;
+ for(attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
+ {
+ if(linkedAttribute[attribute].name.empty())
+ {
+ continue;
+ }
+
+ if(activeAttribute == index)
+ {
+ break;
+ }
+
+ activeAttribute++;
+ }
+
+ if(bufsize > 0)
+ {
+ const char *string = linkedAttribute[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 = linkedAttribute[attribute].type;
+ }
+
+ GLint Program::getActiveAttributeCount() const
+ {
+ int count = 0;
+
+ for(int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
+ {
+ if(!linkedAttribute[attributeIndex].name.empty())
+ {
+ count++;
+ }
+ }
+
+ return count;
+ }
+
+ GLint Program::getActiveAttributeMaxLength() const
+ {
+ int maxLength = 0;
+
+ for(int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
+ {
+ if(!linkedAttribute[attributeIndex].name.empty())
+ {
+ maxLength = std::max((int)(linkedAttribute[attributeIndex].name.length() + 1), maxLength);
+ }
+ }
+
+ return maxLength;
+ }
+
+ void Program::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
+ {
+ if(bufsize > 0)
+ {
+ std::string string = uniforms[index]->name;
+
+ if(uniforms[index]->isArray())
+ {
+ string += "[0]";
+ }
+
+ strncpy(name, string.c_str(), bufsize);
+ name[bufsize - 1] = '\0';
+
+ if(length)
+ {
+ *length = strlen(name);
+ }
+ }
+
+ *size = uniforms[index]->size();
+
+ *type = uniforms[index]->type;
+ }
+
+ GLint Program::getActiveUniformCount() const
+ {
+ return uniforms.size();
+ }
+
+ GLint Program::getActiveUniformMaxLength() const
+ {
+ int maxLength = 0;
+
+ unsigned int numUniforms = uniforms.size();
+ for(unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
+ {
+ if(!uniforms[uniformIndex]->name.empty())
+ {
+ int length = (int)(uniforms[uniformIndex]->name.length() + 1);
+ if(uniforms[uniformIndex]->isArray())
+ {
+ length += 3; // Counting in "[0]".
+ }
+ maxLength = std::max(length, maxLength);
+ }
+ }
+
+ return maxLength;
+ }
+
+ void Program::flagForDeletion()
+ {
+ orphaned = true;
+ }
+
+ bool Program::isFlaggedForDeletion() const
+ {
+ return orphaned;
+ }
+
+ void Program::validate()
+ {
+ resetInfoLog();
+
+ if(!isLinked())
+ {
+ appendToInfoLog("Program has not been successfully linked.");
+ validated = false;
+ }
+ else
+ {
+ applyUniforms();
+ if(!validateSamplers(true))
+ {
+ validated = false;
+ }
+ else
+ {
+ validated = true;
+ }
+ }
+ }
+
+ bool Program::validateSamplers(bool logErrors)
+ {
+ // if any two active samplers in a program are of different types, but refer to the same
+ // texture image unit, and this is the current program, then ValidateProgram will fail, and
+ // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
+
+ TextureType textureUnitType[MAX_COMBINED_TEXTURE_IMAGE_UNITS];
+
+ for(unsigned int i = 0; i < MAX_COMBINED_TEXTURE_IMAGE_UNITS; i++)
+ {
+ textureUnitType[i] = TEXTURE_UNKNOWN;
+ }
+
+ for(unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; i++)
+ {
+ if(samplersPS[i].active)
+ {
+ unsigned int unit = samplersPS[i].logicalTextureUnit;
+
+ if(unit >= MAX_COMBINED_TEXTURE_IMAGE_UNITS)
+ {
+ if(logErrors)
+ {
+ appendToInfoLog("Sampler uniform (%d) exceeds MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, MAX_COMBINED_TEXTURE_IMAGE_UNITS);
+ }
+
+ return false;
+ }
+
+ if(textureUnitType[unit] != TEXTURE_UNKNOWN)
+ {
+ if(samplersPS[i].textureType != textureUnitType[unit])
+ {
+ if(logErrors)
+ {
+ appendToInfoLog("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
+ }
+
+ return false;
+ }
+ }
+ else
+ {
+ textureUnitType[unit] = samplersPS[i].textureType;
+ }
+ }
+ }
+
+ for(unsigned int i = 0; i < MAX_VERTEX_TEXTURE_IMAGE_UNITS; i++)
+ {
+ if(samplersVS[i].active)
+ {
+ unsigned int unit = samplersVS[i].logicalTextureUnit;
+
+ if(unit >= MAX_COMBINED_TEXTURE_IMAGE_UNITS)
+ {
+ if(logErrors)
+ {
+ appendToInfoLog("Sampler uniform (%d) exceeds MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, MAX_COMBINED_TEXTURE_IMAGE_UNITS);
+ }
+
+ return false;
+ }
+
+ if(textureUnitType[unit] != TEXTURE_UNKNOWN)
+ {
+ if(samplersVS[i].textureType != textureUnitType[unit])
+ {
+ if(logErrors)
+ {
+ appendToInfoLog("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
+ }
+
+ return false;
+ }
+ }
+ else
+ {
+ textureUnitType[unit] = samplersVS[i].textureType;
+ }
+ }
+ }
+
+ return true;
+ }
+}
diff --git a/src/GLES2/libGLES_CM/Program.h b/src/GLES2/libGLES_CM/Program.h
new file mode 100644
index 0000000..33e358c
--- /dev/null
+++ b/src/GLES2/libGLES_CM/Program.h
@@ -0,0 +1,207 @@
+// SwiftShader Software Renderer
+//
+// Copyright(c) 2005-2013 TransGaming Inc.
+//
+// All rights reserved. No part of this software may be copied, distributed, transmitted,
+// transcribed, stored in a retrieval system, translated into any human or computer
+// language by any means, or disclosed to third parties without the explicit written
+// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
+// or implied, including but not limited to any patent rights, are granted to you.
+//
+
+// Program.h: Defines the 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 "Shader.h"
+#include "Context.h"
+#include "Shader/PixelShader.hpp"
+#include "Shader/VertexShader.hpp"
+
+#include <string>
+#include <vector>
+#include <set>
+
+namespace gl
+{
+ class Device;
+ class ResourceManager;
+ class FragmentShader;
+ class VertexShader;
+
+ // Helper struct representing a single shader uniform
+ struct Uniform
+ {
+ Uniform(GLenum type, GLenum precision, const std::string &name, unsigned int arraySize);
+
+ ~Uniform();
+
+ bool isArray() const;
+ int size() const;
+ int registerCount() const;
+
+ const GLenum type;
+ const GLenum precision;
+ const std::string name;
+ const unsigned int arraySize;
+
+ unsigned char *data;
+ bool dirty;
+
+ short psRegisterIndex;
+ short vsRegisterIndex;
+ };
+
+ // Struct used for correlating uniforms/elements of uniform arrays to handles
+ struct UniformLocation
+ {
+ UniformLocation(const std::string &name, unsigned int element, unsigned int index);
+
+ std::string name;
+ unsigned int element;
+ unsigned int index;
+ };
+
+ class Program
+ {
+ public:
+ Program(ResourceManager *manager, GLuint handle);
+
+ ~Program();
+
+ bool attachShader(Shader *shader);
+ bool detachShader(Shader *shader);
+ int getAttachedShadersCount() const;
+
+ sw::PixelShader *getPixelShader();
+ sw::VertexShader *getVertexShader();
+
+ void bindAttributeLocation(GLuint index, const char *name);
+ GLuint getAttributeLocation(const char *name);
+ int getAttributeStream(int attributeIndex);
+
+ GLint getSamplerMapping(sw::SamplerType type, unsigned int samplerIndex);
+ TextureType getSamplerTextureType(sw::SamplerType type, unsigned int samplerIndex);
+
+ 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);
+
+ void dirtyAllUniforms();
+ void applyUniforms();
+
+ void link();
+ bool isLinked();
+ 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) const;
+ GLint getActiveAttributeCount() const;
+ GLint getActiveAttributeMaxLength() const;
+
+ void getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const;
+ GLint getActiveUniformCount() const;
+ GLint getActiveUniformMaxLength() const;
+
+ void addRef();
+ void release();
+ unsigned int getRefCount() const;
+ void flagForDeletion();
+ bool isFlaggedForDeletion() const;
+
+ void validate();
+ bool validateSamplers(bool logErrors);
+ bool isValidated() const;
+
+ unsigned int getSerial() const;
+
+ private:
+ void unlink();
+
+ int packVaryings(const Varying *packing[][4]);
+ bool linkVaryings();
+
+ bool linkAttributes();
+ int getAttributeBinding(const std::string &name);
+
+ bool linkUniforms(Shader *shader);
+ bool defineUniform(GLenum shader, GLenum type, GLenum precision, const std::string &_name, unsigned int arraySize, int registerIndex);
+ bool applyUniform1bv(GLint location, GLsizei count, const GLboolean *v);
+ bool applyUniform2bv(GLint location, GLsizei count, const GLboolean *v);
+ bool applyUniform3bv(GLint location, GLsizei count, const GLboolean *v);
+ bool applyUniform4bv(GLint location, GLsizei count, const GLboolean *v);
+ bool applyUniform1fv(GLint location, GLsizei count, const GLfloat *v);
+ bool applyUniform2fv(GLint location, GLsizei count, const GLfloat *v);
+ bool applyUniform3fv(GLint location, GLsizei count, const GLfloat *v);
+ bool applyUniform4fv(GLint location, GLsizei count, const GLfloat *v);
+ bool applyUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value);
+ bool applyUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value);
+ bool applyUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value);
+ bool applyUniform1iv(GLint location, GLsizei count, const GLint *v);
+ bool applyUniform2iv(GLint location, GLsizei count, const GLint *v);
+ bool applyUniform3iv(GLint location, GLsizei count, const GLint *v);
+ bool applyUniform4iv(GLint location, GLsizei count, const GLint *v);
+
+ void appendToInfoLog(const char *info, ...);
+ void resetInfoLog();
+
+ static unsigned int issueSerial();
+
+ private:
+ gl::Device *device;
+ FragmentShader *fragmentShader;
+ VertexShader *vertexShader;
+
+ sw::PixelShader *pixelBinary;
+ sw::VertexShader *vertexBinary;
+
+ std::set<std::string> attributeBinding[MAX_VERTEX_ATTRIBS];
+ sh::Attribute linkedAttribute[MAX_VERTEX_ATTRIBS];
+ int attributeStream[MAX_VERTEX_ATTRIBS];
+
+ struct Sampler
+ {
+ bool active;
+ GLint logicalTextureUnit;
+ TextureType textureType;
+ };
+
+ Sampler samplersPS[MAX_TEXTURE_IMAGE_UNITS];
+ Sampler samplersVS[MAX_VERTEX_TEXTURE_IMAGE_UNITS];
+
+ typedef std::vector<Uniform*> UniformArray;
+ UniformArray uniforms;
+ typedef std::vector<UniformLocation> UniformIndex;
+ UniformIndex uniformIndex;
+
+ bool linked;
+ bool orphaned; // Flag to indicate that the program can be deleted when no longer in use
+ char *infoLog;
+ bool validated;
+
+ unsigned int referenceCount;
+ const unsigned int serial;
+
+ static unsigned int currentSerial;
+
+ ResourceManager *resourceManager;
+ const GLuint handle;
+ };
+}
+
+#endif // LIBGLESV2_PROGRAM_H_
diff --git a/src/GLES2/libGLES_CM/Query.cpp b/src/GLES2/libGLES_CM/Query.cpp
new file mode 100644
index 0000000..8e69d70
--- /dev/null
+++ b/src/GLES2/libGLES_CM/Query.cpp
@@ -0,0 +1,127 @@
+// SwiftShader Software Renderer
+//
+// Copyright(c) 2005-2012 TransGaming Inc.
+//
+// All rights reserved. No part of this software may be copied, distributed, transmitted,
+// transcribed, stored in a retrieval system, translated into any human or computer
+// language by any means, or disclosed to third parties without the explicit written
+// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
+// or implied, including but not limited to any patent rights, are granted to you.
+//
+
+// Query.cpp: Implements the gl::Query class
+
+#include "Query.h"
+
+#include "main.h"
+#include "Common/Thread.hpp"
+
+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)
+ {
+ delete mQuery;
+ }
+}
+
+void Query::begin()
+{
+ if(mQuery == NULL)
+ {
+ mQuery = new sw::Query();
+
+ if(!mQuery)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+ }
+
+ Device *device = getDevice();
+
+ mQuery->begin();
+ device->addQuery(mQuery);
+ device->setOcclusionEnabled(true);
+}
+
+void Query::end()
+{
+ if(mQuery == NULL)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ Device *device = getDevice();
+
+ mQuery->end();
+ device->removeQuery(mQuery);
+ device->setOcclusionEnabled(false);
+
+ mStatus = GL_FALSE;
+ mResult = GL_FALSE;
+}
+
+GLuint Query::getResult()
+{
+ if(mQuery != NULL)
+ {
+ while(!testQuery())
+ {
+ sw::Thread::yield();
+ }
+ }
+
+ 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)
+ {
+ if(!mQuery->building && mQuery->reference == 0)
+ {
+ unsigned int numPixels = mQuery->data;
+ 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);
+ }
+ }
+
+ return mStatus;
+ }
+
+ return GL_TRUE; // Prevent blocking when query is null
+}
+}
diff --git a/src/GLES2/libGLES_CM/Query.h b/src/GLES2/libGLES_CM/Query.h
new file mode 100644
index 0000000..a80456e
--- /dev/null
+++ b/src/GLES2/libGLES_CM/Query.h
@@ -0,0 +1,50 @@
+// SwiftShader Software Renderer
+//
+// Copyright(c) 2005-2012 TransGaming Inc.
+//
+// All rights reserved. No part of this software may be copied, distributed, transmitted,
+// transcribed, stored in a retrieval system, translated into any human or computer
+// language by any means, or disclosed to third parties without the explicit written
+// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
+// or implied, including but not limited to any patent rights, are granted to you.
+//
+
+// Query.h: Defines the gl::Query class
+
+#ifndef LIBGLESV2_QUERY_H_
+#define LIBGLESV2_QUERY_H_
+
+#include "RefCountObject.h"
+#include "Renderer/Renderer.hpp"
+
+#define GL_APICALL
+#include <GLES2/gl2.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:
+ GLboolean testQuery();
+
+ sw::Query* mQuery;
+ GLenum mType;
+ GLboolean mStatus;
+ GLint mResult;
+};
+
+}
+
+#endif // LIBGLESV2_QUERY_H_
diff --git a/src/GLES2/libGLES_CM/RefCountObject.cpp b/src/GLES2/libGLES_CM/RefCountObject.cpp
new file mode 100644
index 0000000..b470ab2
--- /dev/null
+++ b/src/GLES2/libGLES_CM/RefCountObject.cpp
@@ -0,0 +1,65 @@
+// SwiftShader Software Renderer
+//
+// Copyright(c) 2005-2012 TransGaming Inc.
+//
+// All rights reserved. No part of this software may be copied, distributed, transmitted,
+// transcribed, stored in a retrieval system, translated into any human or computer
+// language by any means, or disclosed to third parties without the explicit written
+// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
+// or implied, including but not limited to any patent rights, are granted to you.
+//
+
+// RefCountObject.cpp: Defines the RefCountObject base class that provides
+// lifecycle support for GL objects using the traditional BindObject scheme, but
+// that need to be reference counted for correct cross-context deletion.
+// (Concretely, textures, buffers and renderbuffers.)
+
+#include "RefCountObject.h"
+
+#include "Common/Thread.hpp"
+
+namespace gl
+{
+
+RefCountObject::RefCountObject(GLuint id)
+{
+ mId = id;
+
+ referenceCount = 0;
+}
+
+RefCountObject::~RefCountObject()
+{
+ ASSERT(referenceCount == 0);
+}
+
+void RefCountObject::addRef()
+{
+ sw::atomicIncrement(&referenceCount);
+}
+
+void RefCountObject::release()
+{
+ ASSERT(referenceCount > 0);
+
+ if(referenceCount > 0)
+ {
+ sw::atomicDecrement(&referenceCount);
+ }
+
+ if(referenceCount == 0)
+ {
+ delete this;
+ }
+}
+
+void RefCountObjectBindingPointer::set(RefCountObject *newObject)
+{
+ // addRef first in case newObject == mObject and this is the last reference to it.
+ if(newObject != NULL) newObject->addRef();
+ if(mObject != NULL) mObject->release();
+
+ mObject = newObject;
+}
+
+}
diff --git a/src/GLES2/libGLES_CM/RefCountObject.h b/src/GLES2/libGLES_CM/RefCountObject.h
new file mode 100644
index 0000000..a9a11e0
--- /dev/null
+++ b/src/GLES2/libGLES_CM/RefCountObject.h
@@ -0,0 +1,75 @@
+// SwiftShader Software Renderer
+//
+// Copyright(c) 2005-2012 TransGaming Inc.
+//
+// All rights reserved. No part of this software may be copied, distributed, transmitted,
+// transcribed, stored in a retrieval system, translated into any human or computer
+// language by any means, or disclosed to third parties without the explicit written
+// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
+// or implied, including but not limited to any patent rights, are granted to you.
+//
+
+// RefCountObject.h: Defines the RefCountObject base class that provides
+// lifecycle support for GL objects using the traditional BindObject scheme, but
+// that need to be reference counted for correct cross-context deletion.
+// (Concretely, textures, buffers and renderbuffers.)
+
+#ifndef LIBGLESV2_REFCOUNTOBJECT_H_
+#define LIBGLESV2_REFCOUNTOBJECT_H_
+
+#include "common/debug.h"
+
+#define GL_APICALL
+#include <GLES2/gl2.h>
+
+#include <cstddef>
+
+namespace gl
+{
+
+class RefCountObject
+{
+ public:
+ explicit RefCountObject(GLuint id);
+ virtual ~RefCountObject();
+
+ virtual void addRef();
+ virtual void release();
+
+ GLuint id() const {return mId;}
+
+ private:
+ GLuint mId;
+
+ volatile int referenceCount;
+};
+
+class RefCountObjectBindingPointer
+{
+ protected:
+ RefCountObjectBindingPointer() : mObject(NULL) { }
+ ~RefCountObjectBindingPointer() { ASSERT(mObject == NULL); } // Objects have to be released before the resource manager is destroyed, so they must be explicitly cleaned up.
+
+ void set(RefCountObject *newObject);
+ RefCountObject *get() const { return mObject; }
+
+ public:
+ GLuint id() const { return (mObject != NULL) ? mObject->id() : 0; }
+ bool operator ! () const { return (get() == NULL); }
+
+ private:
+ RefCountObject *mObject;
+};
+
+template<class ObjectType>
+class BindingPointer : public RefCountObjectBindingPointer
+{
+ public:
+ void set(ObjectType *newObject) { RefCountObjectBindingPointer::set(newObject); }
+ ObjectType *get() const { return static_cast<ObjectType*>(RefCountObjectBindingPointer::get()); }
+ ObjectType *operator -> () const { return get(); }
+};
+
+}
+
+#endif // LIBGLESV2_REFCOUNTOBJECT_H_
diff --git a/src/GLES2/libGLES_CM/Renderbuffer.cpp b/src/GLES2/libGLES_CM/Renderbuffer.cpp
new file mode 100644
index 0000000..6ca0c15
--- /dev/null
+++ b/src/GLES2/libGLES_CM/Renderbuffer.cpp
@@ -0,0 +1,557 @@
+// SwiftShader Software Renderer
+//
+// Copyright(c) 2005-2013 TransGaming Inc.
+//
+// All rights reserved. No part of this software may be copied, distributed, transmitted,
+// transcribed, stored in a retrieval system, translated into any human or computer
+// language by any means, or disclosed to third parties without the explicit written
+// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
+// or implied, including but not limited to any patent rights, are granted to you.
+//
+
+// Renderbuffer.cpp: the 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 "Renderbuffer.h"
+
+#include "main.h"
+#include "Texture.h"
+#include "utilities.h"
+
+namespace gl
+{
+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 sw2es::GetRedSize(getInternalFormat());
+}
+
+GLuint RenderbufferInterface::getGreenSize() const
+{
+ return sw2es::GetGreenSize(getInternalFormat());
+}
+
+GLuint RenderbufferInterface::getBlueSize() const
+{
+ return sw2es::GetBlueSize(getInternalFormat());
+}
+
+GLuint RenderbufferInterface::getAlphaSize() const
+{
+ return sw2es::GetAlphaSize(getInternalFormat());
+}
+
+GLuint RenderbufferInterface::getDepthSize() const
+{
+ return sw2es::GetDepthSize(getInternalFormat());
+}
+
+GLuint RenderbufferInterface::getStencilSize() const
+{
+ return sw2es::GetStencilSize(getInternalFormat());
+}
+
+///// RenderbufferTexture2D Implementation ////////
+
+RenderbufferTexture2D::RenderbufferTexture2D(Texture2D *texture)
+{
+ 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 image.
+// caller must release() the returned image
+Image *RenderbufferTexture2D::getRenderTarget()
+{
+ return mTexture2D->getRenderTarget(GL_TEXTURE_2D, 0);
+}
+
+// Increments refcount on image.
+// caller must release() the returned image
+Image *RenderbufferTexture2D::createSharedImage()
+{
+ return mTexture2D->createSharedImage(GL_TEXTURE_2D, 0);
+}
+
+bool RenderbufferTexture2D::isShared() const
+{
+ return mTexture2D->isShared(GL_TEXTURE_2D, 0);
+}
+
+GLsizei RenderbufferTexture2D::getWidth() const
+{
+ return mTexture2D->getWidth(GL_TEXTURE_2D, 0);
+}
+
+GLsizei RenderbufferTexture2D::getHeight() const
+{
+ return mTexture2D->getHeight(GL_TEXTURE_2D, 0);
+}
+
+GLenum RenderbufferTexture2D::getFormat() const
+{
+ return mTexture2D->getFormat(GL_TEXTURE_2D, 0);
+}
+
+sw::Format RenderbufferTexture2D::getInternalFormat() const
+{
+ return mTexture2D->getInternalFormat(GL_TEXTURE_2D, 0);
+}
+
+GLsizei RenderbufferTexture2D::getSamples() const
+{
+ return 0;
+}
+
+///// 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 image.
+// caller must release() the returned image
+Image *RenderbufferTextureCubeMap::getRenderTarget()
+{
+ return mTextureCubeMap->getRenderTarget(mTarget, 0);
+}
+
+// Increments refcount on image.
+// caller must release() the returned image
+Image *RenderbufferTextureCubeMap::createSharedImage()
+{
+ return mTextureCubeMap->createSharedImage(mTarget, 0);
+}
+
+bool RenderbufferTextureCubeMap::isShared() const
+{
+ return mTextureCubeMap->isShared(mTarget, 0);
+}
+
+GLsizei RenderbufferTextureCubeMap::getWidth() const
+{
+ return mTextureCubeMap->getWidth(mTarget, 0);
+}
+
+GLsizei RenderbufferTextureCubeMap::getHeight() const
+{
+ return mTextureCubeMap->getHeight(mTarget, 0);
+}
+
+GLenum RenderbufferTextureCubeMap::getFormat() const
+{
+ return mTextureCubeMap->getFormat(mTarget, 0);
+}
+
+sw::Format RenderbufferTextureCubeMap::getInternalFormat() const
+{
+ return mTextureCubeMap->getInternalFormat(mTarget, 0);
+}
+
+GLsizei RenderbufferTextureCubeMap::getSamples() const
+{
+ return 0;
+}
+
+////// 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()
+{
+ mInstance->addProxyRef(this);
+
+ RefCountObject::addRef();
+}
+
+void Renderbuffer::release()
+{
+ mInstance->releaseProxy(this);
+
+ RefCountObject::release();
+}
+
+// Increments refcount on image.
+// caller must Release() the returned image
+Image *Renderbuffer::getRenderTarget()
+{
+ return mInstance->getRenderTarget();
+}
+
+// Increments refcount on image.
+// caller must Release() the returned image
+Image *Renderbuffer::createSharedImage()
+{
+ return mInstance->createSharedImage();
+}
+
+bool Renderbuffer::isShared() const
+{
+ return mInstance->isShared();
+}
+
+GLsizei Renderbuffer::getWidth() const
+{
+ return mInstance->getWidth();
+}
+
+GLsizei Renderbuffer::getHeight() const
+{
+ return mInstance->getHeight();
+}
+
+GLenum Renderbuffer::getFormat() const
+{
+ return mInstance->getFormat();
+}
+
+sw::Format Renderbuffer::getInternalFormat() const
+{
+ return mInstance->getInternalFormat();
+}
+
+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();
+}
+
+void Renderbuffer::setStorage(RenderbufferStorage *newStorage)
+{
+ ASSERT(newStorage != NULL);
+
+ delete mInstance;
+ mInstance = newStorage;
+}
+
+RenderbufferStorage::RenderbufferStorage()
+{
+ mWidth = 0;
+ mHeight = 0;
+ format = GL_RGBA4;
+ internalFormat = sw::FORMAT_A8R8G8B8;
+ mSamples = 0;
+}
+
+RenderbufferStorage::~RenderbufferStorage()
+{
+}
+
+GLsizei RenderbufferStorage::getWidth() const
+{
+ return mWidth;
+}
+
+GLsizei RenderbufferStorage::getHeight() const
+{
+ return mHeight;
+}
+
+GLenum RenderbufferStorage::getFormat() const
+{
+ return format;
+}
+
+sw::Format RenderbufferStorage::getInternalFormat() const
+{
+ return internalFormat;
+}
+
+GLsizei RenderbufferStorage::getSamples() const
+{
+ return mSamples;
+}
+
+Colorbuffer::Colorbuffer(Image *renderTarget) : mRenderTarget(renderTarget)
+{
+ if(renderTarget)
+ {
+ renderTarget->addRef();
+
+ mWidth = renderTarget->getWidth();
+ mHeight = renderTarget->getHeight();
+ internalFormat = renderTarget->getInternalFormat();
+ format = sw2es::ConvertBackBufferFormat(internalFormat);
+ mSamples = renderTarget->getMultiSampleDepth() & ~1;
+ }
+}
+
+Colorbuffer::Colorbuffer(int width, int height, GLenum format, GLsizei samples) : mRenderTarget(NULL)
+{
+ Device *device = getDevice();
+
+ sw::Format requestedFormat = es2sw::ConvertRenderbufferFormat(format);
+ int supportedSamples = Context::getSupportedMultiSampleDepth(requestedFormat, samples);
+
+ if(width > 0 && height > 0)
+ {
+ mRenderTarget = device->createRenderTarget(width, height, requestedFormat, supportedSamples, false);
+
+ if(!mRenderTarget)
+ {
+ error(GL_OUT_OF_MEMORY);
+ return;
+ }
+ }
+
+ mWidth = width;
+ mHeight = height;
+ this->format = format;
+ internalFormat = requestedFormat;
+ mSamples = supportedSamples & ~1;
+}
+
+Colorbuffer::~Colorbuffer()
+{
+ if(mRenderTarget)
+ {
+ mRenderTarget->release();
+ }
+}
+
+// Increments refcount on image.
+// caller must release() the returned image
+Image *Colorbuffer::getRenderTarget()
+{
+ if(mRenderTarget)
+ {
+ mRenderTarget->addRef();
+ }
+
+ return mRenderTarget;
+}
+
+// Increments refcount on image.
+// caller must release() the returned image
+Image *Colorbuffer::createSharedImage()
+{
+ if(mRenderTarget)
+ {
+ mRenderTarget->addRef();
+ mRenderTarget->markShared();
+ }
+
+ return mRenderTarget;
+}
+
+bool Colorbuffer::isShared() const
+{
+ return mRenderTarget->isShared();
+}
+
+DepthStencilbuffer::DepthStencilbuffer(Image *depthStencil) : mDepthStencil(depthStencil)
+{
+ if(depthStencil)
+ {
+ depthStencil->addRef();
+
+ mWidth = depthStencil->getWidth();
+ mHeight = depthStencil->getHeight();
+ internalFormat = depthStencil->getInternalFormat();
+ format = sw2es::ConvertDepthStencilFormat(internalFormat);
+ mSamples = depthStencil->getMultiSampleDepth() & ~1;
+ }
+}
+
+DepthStencilbuffer::DepthStencilbuffer(int width, int height, GLsizei samples)
+{
+ Device *device = getDevice();
+
+ mDepthStencil = NULL;
+
+ int supportedSamples = Context::getSupportedMultiSampleDepth(sw::FORMAT_D24S8, samples);
+
+ if(width > 0 && height > 0)
+ {
+ mDepthStencil = device->createDepthStencilSurface(width, height, sw::FORMAT_D24S8, supportedSamples, false);
+
+ if(!mDepthStencil)
+ {
+ error(GL_OUT_OF_MEMORY);
+ return;
+ }
+ }
+
+ mWidth = width;
+ mHeight = height;
+ format = GL_DEPTH24_STENCIL8_OES;
+ internalFormat = sw::FORMAT_D24S8;
+ mSamples = supportedSamples & ~1;
+}
+
+DepthStencilbuffer::~DepthStencilbuffer()
+{
+ if(mDepthStencil)
+ {
+ mDepthStencil->release();
+ }
+}
+
+// Increments refcount on image.
+// caller must release() the returned image
+Image *DepthStencilbuffer::getRenderTarget()
+{
+ if(mDepthStencil)
+ {
+ mDepthStencil->addRef();
+ }
+
+ return mDepthStencil;
+}
+
+// Increments refcount on image.
+// caller must release() the returned image
+Image *DepthStencilbuffer::createSharedImage()
+{
+ if(mDepthStencil)
+ {
+ mDepthStencil->addRef();
+ mDepthStencil->markShared();
+ }
+
+ return mDepthStencil;
+}
+
+bool DepthStencilbuffer::isShared() const
+{
+ return mDepthStencil->isShared();
+}
+
+Depthbuffer::Depthbuffer(Image *depthStencil) : DepthStencilbuffer(depthStencil)
+{
+ if(depthStencil)
+ {
+ format = 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)
+ {
+ format = 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(Image *depthStencil) : DepthStencilbuffer(depthStencil)
+{
+ if(depthStencil)
+ {
+ format = 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)
+ {
+ format = 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/GLES2/libGLES_CM/Renderbuffer.h b/src/GLES2/libGLES_CM/Renderbuffer.h
new file mode 100644
index 0000000..2e8a49e
--- /dev/null
+++ b/src/GLES2/libGLES_CM/Renderbuffer.h
@@ -0,0 +1,229 @@
+// SwiftShader Software Renderer
+//
+// Copyright(c) 2005-2013 TransGaming Inc.
+//
+// All rights reserved. No part of this software may be copied, distributed, transmitted,
+// transcribed, stored in a retrieval system, translated into any human or computer
+// language by any means, or disclosed to third parties without the explicit written
+// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
+// or implied, including but not limited to any patent rights, are granted to you.
+//
+
+// Renderbuffer.h: Defines the wrapper class 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_
+
+#include "RefCountObject.h"
+#include "Image.hpp"
+
+#define GL_APICALL
+#include <GLES2/gl2.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 Image *getRenderTarget() = 0;
+ virtual Image *createSharedImage() = 0;
+ virtual bool isShared() const = 0;
+
+ virtual GLsizei getWidth() const = 0;
+ virtual GLsizei getHeight() const = 0;
+ virtual GLenum getFormat() const = 0;
+ virtual sw::Format getInternalFormat() 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;
+};
+
+class RenderbufferTexture2D : public RenderbufferInterface
+{
+public:
+ RenderbufferTexture2D(Texture2D *texture);
+
+ virtual ~RenderbufferTexture2D();
+
+ virtual void addProxyRef(const Renderbuffer *proxy);
+ virtual void releaseProxy(const Renderbuffer *proxy);
+
+ virtual Image *getRenderTarget();
+ virtual Image *createSharedImage();
+ virtual bool isShared() const;
+
+ virtual GLsizei getWidth() const;
+ virtual GLsizei getHeight() const;
+ virtual GLenum getFormat() const;
+ virtual sw::Format getInternalFormat() const;
+ virtual GLsizei getSamples() const;
+
+private:
+ BindingPointer<Texture2D> mTexture2D;
+};
+
+class RenderbufferTextureCubeMap : public RenderbufferInterface
+{
+public:
+ RenderbufferTextureCubeMap(TextureCubeMap *texture, GLenum target);
+
+ virtual ~RenderbufferTextureCubeMap();
+
+ virtual void addProxyRef(const Renderbuffer *proxy);
+ virtual void releaseProxy(const Renderbuffer *proxy);
+
+ virtual Image *getRenderTarget();
+ virtual Image *createSharedImage();
+ virtual bool isShared() const;
+
+ virtual GLsizei getWidth() const;
+ virtual GLsizei getHeight() const;
+ virtual GLenum getFormat() const;
+ virtual sw::Format getInternalFormat() const;
+ virtual GLsizei getSamples() const;
+
+private:
+ 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 Image *getRenderTarget() = 0;
+ virtual Image *createSharedImage() = 0;
+ virtual bool isShared() const = 0;
+
+ virtual GLsizei getWidth() const;
+ virtual GLsizei getHeight() const;
+ virtual GLenum getFormat() const;
+ virtual sw::Format getInternalFormat() const;
+ virtual GLsizei getSamples() const;
+
+protected:
+ GLsizei mWidth;
+ GLsizei mHeight;
+ GLenum format;
+ sw::Format internalFormat;
+ GLsizei mSamples;
+};
+
+// 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.
+ virtual void addRef();
+ virtual void release();
+
+ Image *getRenderTarget();
+ virtual Image *createSharedImage();
+ virtual bool isShared() const;
+
+ GLsizei getWidth() const;
+ GLsizei getHeight() const;
+ GLenum getFormat() const;
+ sw::Format getInternalFormat() const;
+ GLuint getRedSize() const;
+ GLuint getGreenSize() const;
+ GLuint getBlueSize() const;
+ GLuint getAlphaSize() const;
+ GLuint getDepthSize() const;
+ GLuint getStencilSize() const;
+ GLsizei getSamples() const;
+
+ void setStorage(RenderbufferStorage *newStorage);
+
+private:
+ RenderbufferInterface *mInstance;
+};
+
+class Colorbuffer : public RenderbufferStorage
+{
+public:
+ explicit Colorbuffer(Image *renderTarget);
+ Colorbuffer(GLsizei width, GLsizei height, GLenum format, GLsizei samples);
+
+ virtual ~Colorbuffer();
+
+ virtual Image *getRenderTarget();
+ virtual Image *createSharedImage();
+ virtual bool isShared() const;
+
+private:
+ Image *mRenderTarget;
+};
+
+class DepthStencilbuffer : public RenderbufferStorage
+{
+public:
+ explicit DepthStencilbuffer(Image *depthStencil);
+ DepthStencilbuffer(GLsizei width, GLsizei height, GLsizei samples);
+
+ ~DepthStencilbuffer();
+
+ virtual Image *getRenderTarget();
+ virtual Image *createSharedImage();
+ virtual bool isShared() const;
+
+protected:
+ Image *mDepthStencil;
+};
+
+class Depthbuffer : public DepthStencilbuffer
+{
+public:
+ explicit Depthbuffer(Image *depthStencil);
+ Depthbuffer(GLsizei width, GLsizei height, GLsizei samples);
+
+ virtual ~Depthbuffer();
+};
+
+class Stencilbuffer : public DepthStencilbuffer
+{
+public:
+ explicit Stencilbuffer(Image *depthStencil);
+ Stencilbuffer(GLsizei width, GLsizei height, GLsizei samples);
+
+ virtual ~Stencilbuffer();
+};
+}
+
+#endif // LIBGLESV2_RENDERBUFFER_H_
diff --git a/src/GLES2/libGLES_CM/ResourceManager.cpp b/src/GLES2/libGLES_CM/ResourceManager.cpp
new file mode 100644
index 0000000..8bddcc8
--- /dev/null
+++ b/src/GLES2/libGLES_CM/ResourceManager.cpp
@@ -0,0 +1,329 @@
+// SwiftShader Software Renderer
+//
+// Copyright(c) 2005-2012 TransGaming Inc.
+//
+// All rights reserved. No part of this software may be copied, distributed, transmitted,
+// transcribed, stored in a retrieval system, translated into any human or computer
+// language by any means, or disclosed to third parties without the explicit written
+// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
+// or implied, including but not limited to any patent rights, are granted to you.
+//
+
+// ResourceManager.cpp: Implements the ResourceManager class, which tracks and
+// retrieves objects which may be shared by multiple Contexts.
+
+#include "ResourceManager.h"
+
+#include "Buffer.h"
+#include "Program.h"
+#include "Renderbuffer.h"
+#include "Shader.h"
+#include "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 if(type == TEXTURE_EXTERNAL)
+ {
+ textureObject = new TextureExternal(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/GLES2/libGLES_CM/ResourceManager.h b/src/GLES2/libGLES_CM/ResourceManager.h
new file mode 100644
index 0000000..cd4ae12
--- /dev/null
+++ b/src/GLES2/libGLES_CM/ResourceManager.h
@@ -0,0 +1,101 @@
+// SwiftShader Software Renderer
+//
+// Copyright(c) 2005-2012 TransGaming Inc.
+//
+// All rights reserved. No part of this software may be copied, distributed, transmitted,
+// transcribed, stored in a retrieval system, translated into any human or computer
+// language by any means, or disclosed to third parties without the explicit written
+// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
+// or implied, including but not limited to any patent rights, are granted to you.
+//
+
+// ResourceManager.h : Defines the ResourceManager class, which tracks objects
+// shared by multiple GL contexts.
+
+#ifndef LIBGLESV2_RESOURCEMANAGER_H_
+#define LIBGLESV2_RESOURCEMANAGER_H_
+
+#include "HandleAllocator.h"
+
+#define GL_APICALL
+#include <GLES2/gl2.h>
+
+#include <map>
+
+namespace gl
+{
+class Buffer;
+class Shader;
+class Program;
+class Texture;
+class Renderbuffer;
+
+enum TextureType
+{
+ TEXTURE_2D,
+ TEXTURE_CUBE,
+ TEXTURE_EXTERNAL,
+
+ TEXTURE_TYPE_COUNT,
+ TEXTURE_UNKNOWN
+};
+
+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:
+ std::size_t mRefCount;
+
+ typedef std::map<GLint, Buffer*> BufferMap;
+ BufferMap mBufferMap;
+ HandleAllocator mBufferHandleAllocator;
+
+ typedef std::map<GLint, Shader*> ShaderMap;
+ ShaderMap mShaderMap;
+
+ typedef std::map<GLint, Program*> ProgramMap;
+ ProgramMap mProgramMap;
+ HandleAllocator mProgramShaderHandleAllocator;
+
+ typedef std::map<GLint, Texture*> TextureMap;
+ TextureMap mTextureMap;
+ HandleAllocator mTextureHandleAllocator;
+
+ typedef std::map<GLint, Renderbuffer*> RenderbufferMap;
+ RenderbufferMap mRenderbufferMap;
+ HandleAllocator mRenderbufferHandleAllocator;
+};
+
+}
+
+#endif // LIBGLESV2_RESOURCEMANAGER_H_
diff --git a/src/GLES2/libGLES_CM/Shader.cpp b/src/GLES2/libGLES_CM/Shader.cpp
new file mode 100644
index 0000000..e4cb5ee
--- /dev/null
+++ b/src/GLES2/libGLES_CM/Shader.cpp
@@ -0,0 +1,511 @@
+// SwiftShader Software Renderer
+//
+// Copyright(c) 2005-2013 TransGaming Inc.
+//
+// All rights reserved. No part of this software may be copied, distributed, transmitted,
+// transcribed, stored in a retrieval system, translated into any human or computer
+// language by any means, or disclosed to third parties without the explicit written
+// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
+// or implied, including but not limited to any patent rights, are granted to you.
+//
+
+// Shader.cpp: Implements the 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 "Shader.h"
+
+#include "main.h"
+#include "utilities.h"
+
+#include "GLSLANG/ShaderLang.h"
+
+#include <string>
+
+namespace gl
+{
+Shader::Shader(ResourceManager *manager, GLuint handle) : mHandle(handle), mResourceManager(manager)
+{
+ mSource = NULL;
+ mInfoLog = NULL;
+
+ clear();
+
+ mRefCount = 0;
+ mDeleteStatus = false;
+}
+
+Shader::~Shader()
+{
+ delete[] mSource;
+ 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;
+ }
+}
+
+void Shader::getSource(GLsizei bufSize, GLsizei *length, char *source)
+{
+ int index = 0;
+
+ if(bufSize > 0)
+ {
+ if(mSource)
+ {
+ index = std::min(bufSize - 1, (int)strlen(mSource));
+ memcpy(source, mSource, index);
+ }
+
+ source[index] = '\0';
+ }
+
+ if(length)
+ {
+ *length = index;
+ }
+}
+
+TranslatorASM *Shader::createCompiler(ShShaderType type)
+{
+ ShInitialize();
+
+ TranslatorASM *assembler = new TranslatorASM(this, type, SH_GLES2_SPEC);
+
+ ShBuiltInResources resources;
+ ShInitBuiltInResources(&resources);
+ resources.MaxVertexAttribs = MAX_VERTEX_ATTRIBS;
+ resources.MaxVertexUniformVectors = MAX_VERTEX_UNIFORM_VECTORS;
+ resources.MaxVaryingVectors = MAX_VARYING_VECTORS;
+ resources.MaxVertexTextureImageUnits = MAX_VERTEX_TEXTURE_IMAGE_UNITS;
+ resources.MaxCombinedTextureImageUnits = MAX_COMBINED_TEXTURE_IMAGE_UNITS;
+ resources.MaxTextureImageUnits = MAX_TEXTURE_IMAGE_UNITS;
+ resources.MaxFragmentUniformVectors = MAX_FRAGMENT_UNIFORM_VECTORS;
+ resources.MaxDrawBuffers = MAX_DRAW_BUFFERS;
+ resources.OES_standard_derivatives = 1;
+ resources.OES_fragment_precision_high = 1;
+ resources.MaxCallStackDepth = 16;
+ assembler->Init(resources);
+
+ return assembler;
+}
+
+void Shader::clear()
+{
+ delete[] mInfoLog;
+ mInfoLog = NULL;
+
+ varyings.clear();
+ activeAttributes.clear();
+}
+
+bool Shader::isCompiled()
+{
+ return getShader() != 0;
+}
+
+sw::PixelShader *Shader::getPixelShader() const
+{
+ return 0;
+}
+
+sw::VertexShader *Shader::getVertexShader() const
+{
+ return 0;
+}
+
+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;
+}
+
+void Shader::releaseCompiler()
+{
+ ShFinalize();
+}
+
+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 = 0;
+}
+
+VertexShader::~VertexShader()
+{
+ delete vertexShader;
+}
+
+GLenum VertexShader::getType()
+{
+ return GL_VERTEX_SHADER;
+}
+
+void VertexShader::compile()
+{
+ clear();
+
+ delete vertexShader;
+ vertexShader = new sw::VertexShader();
+
+ TranslatorASM *compiler = createCompiler(SH_VERTEX_SHADER);
+
+ // Ensure we don't pass a NULL source to the compiler
+ char *source = "\0";
+ if(mSource)
+ {
+ source = mSource;
+ }
+
+ int success = ShCompile(compiler, &source, 1, SH_OBJECT_CODE);
+
+ if(false)
+ {
+ static int serial = 1;
+ char buffer[256];
+ sprintf(buffer, "vertex-input-%d-%d.txt", getHandle(), serial);
+ FILE *file = fopen(buffer, "wt");
+ fprintf(file, mSource);
+ fclose(file);
+ vertexShader->print("vertex-output-%d-%d.txt", getHandle(), serial);
+ serial++;
+ }
+
+ if(!success)
+ {
+ delete vertexShader;
+ vertexShader = 0;
+
+ int infoLogLen = 0;
+ ShGetInfo(compiler, SH_INFO_LOG_LENGTH, &infoLogLen);
+ mInfoLog = new char[infoLogLen];
+ ShGetInfoLog(compiler, mInfoLog);
+ TRACE("\n%s", mInfoLog);
+ }
+
+ delete compiler;
+}
+
+int VertexShader::getSemanticIndex(const std::string &attributeName)
+{
+ if(!attributeName.empty())
+ {
+ for(sh::ActiveAttributes::iterator attribute = activeAttributes.begin(); attribute != activeAttributes.end(); attribute++)
+ {
+ if(attribute->name == attributeName)
+ {
+ return attribute->registerIndex;
+ }
+ }
+ }
+
+ return -1;
+}
+
+sw::Shader *VertexShader::getShader() const
+{
+ return vertexShader;
+}
+
+sw::VertexShader *VertexShader::getVertexShader() const
+{
+ return vertexShader;
+}
+
+FragmentShader::FragmentShader(ResourceManager *manager, GLuint handle) : Shader(manager, handle)
+{
+ pixelShader = 0;
+}
+
+FragmentShader::~FragmentShader()
+{
+ delete pixelShader;
+}
+
+GLenum FragmentShader::getType()
+{
+ return GL_FRAGMENT_SHADER;
+}
+
+void FragmentShader::compile()
+{
+ clear();
+
+ delete pixelShader;
+ pixelShader = new sw::PixelShader();
+
+ TranslatorASM *compiler = createCompiler(SH_FRAGMENT_SHADER);
+
+ // Ensure we don't pass a NULL source to the compiler
+ char *source = "\0";
+ if(mSource)
+ {
+ source = mSource;
+ }
+
+ int success = ShCompile(compiler, &source, 1, SH_OBJECT_CODE);
+
+ if(false)
+ {
+ static int serial = 1;
+ char buffer[256];
+ sprintf(buffer, "pixel-input-%d-%d.txt", getHandle(), serial);
+ FILE *file = fopen(buffer, "wt");
+ fprintf(file, mSource);
+ fclose(file);
+ pixelShader->print("pixel-output-%d-%d.txt", getHandle(), serial);
+ serial++;
+ }
+
+ if(!success)
+ {
+ delete pixelShader;
+ pixelShader = 0;
+
+ int infoLogLen = 0;
+ ShGetInfo(compiler, SH_INFO_LOG_LENGTH, &infoLogLen);
+ mInfoLog = new char[infoLogLen];
+ ShGetInfoLog(compiler, mInfoLog);
+ TRACE("\n%s", mInfoLog);
+ }
+
+ delete compiler;
+}
+
+sw::Shader *FragmentShader::getShader() const
+{
+ return pixelShader;
+}
+
+sw::PixelShader *FragmentShader::getPixelShader() const
+{
+ return pixelShader;
+}
+}
diff --git a/src/GLES2/libGLES_CM/Shader.h b/src/GLES2/libGLES_CM/Shader.h
new file mode 100644
index 0000000..b6e7e70
--- /dev/null
+++ b/src/GLES2/libGLES_CM/Shader.h
@@ -0,0 +1,159 @@
+// SwiftShader Software Renderer
+//
+// Copyright(c) 2005-2013 TransGaming Inc.
+//
+// All rights reserved. No part of this software may be copied, distributed, transmitted,
+// transcribed, stored in a retrieval system, translated into any human or computer
+// language by any means, or disclosed to third parties without the explicit written
+// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
+// or implied, including but not limited to any patent rights, are granted to you.
+//
+
+// Shader.h: Defines the abstract 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_
+
+#include "ResourceManager.h"
+
+#include "compiler/TranslatorASM.h"
+
+#define GL_APICALL
+#include <GLES2/gl2.h>
+
+#include <list>
+#include <vector>
+
+namespace sh
+{
+ class OutputASM;
+}
+
+namespace gl
+{
+struct Varying
+{
+ Varying(GLenum type, const std::string &name, int arraySize, int reg = -1, int col = -1)
+ : type(type), name(name), arraySize(arraySize), reg(reg), col(col)
+ {
+ }
+
+ bool isArray() const
+ {
+ return arraySize >= 1;
+ }
+
+ int size() const // Unify with gl::Uniform?
+ {
+ return arraySize > 0 ? arraySize : 1;
+ }
+
+ GLenum type;
+ std::string name;
+ int arraySize;
+
+ 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 Program;
+ friend class sh::OutputASM;
+
+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 *source);
+
+ virtual void compile() = 0;
+ bool isCompiled();
+
+ virtual sw::Shader *getShader() const = 0;
+ virtual sw::PixelShader *getPixelShader() const;
+ virtual sw::VertexShader *getVertexShader() const;
+
+ void addRef();
+ void release();
+ unsigned int getRefCount() const;
+ bool isFlaggedForDeletion() const;
+ void flagForDeletion();
+
+ static void releaseCompiler();
+
+protected:
+ TranslatorASM *createCompiler(ShShaderType type);
+ void clear();
+
+ static GLenum parseType(const std::string &type);
+ static bool compareVarying(const Varying &x, const Varying &y);
+
+ char *mSource;
+ char *mInfoLog;
+
+ VaryingList varyings;
+ sh::ActiveUniforms activeUniforms;
+ sh::ActiveAttributes activeAttributes;
+
+private:
+ 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
+
+ ResourceManager *mResourceManager;
+};
+
+class VertexShader : public Shader
+{
+ friend class Program;
+
+public:
+ VertexShader(ResourceManager *manager, GLuint handle);
+
+ ~VertexShader();
+
+ virtual GLenum getType();
+ virtual void compile();
+ int getSemanticIndex(const std::string &attributeName);
+
+ virtual sw::Shader *getShader() const;
+ virtual sw::VertexShader *getVertexShader() const;
+
+private:
+ sw::VertexShader *vertexShader;
+};
+
+class FragmentShader : public Shader
+{
+public:
+ FragmentShader(ResourceManager *manager, GLuint handle);
+
+ ~FragmentShader();
+
+ virtual GLenum getType();
+ virtual void compile();
+
+ virtual sw::Shader *getShader() const;
+ virtual sw::PixelShader *getPixelShader() const;
+
+private:
+ sw::PixelShader *pixelShader;
+};
+}
+
+#endif // LIBGLESV2_SHADER_H_
diff --git a/src/GLES2/libGLES_CM/Texture.cpp b/src/GLES2/libGLES_CM/Texture.cpp
new file mode 100644
index 0000000..25dbdb1
--- /dev/null
+++ b/src/GLES2/libGLES_CM/Texture.cpp
@@ -0,0 +1,1167 @@
+// SwiftShader Software Renderer
+//
+// Copyright(c) 2005-2013 TransGaming Inc.
+//
+// All rights reserved. No part of this software may be copied, distributed, transmitted,
+// transcribed, stored in a retrieval system, translated into any human or computer
+// language by any means, or disclosed to third parties without the explicit written
+// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
+// or implied, including but not limited to any patent rights, are granted to you.
+//
+
+// Texture.cpp: Implements the 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 "Texture.h"
+
+#include "main.h"
+#include "mathutil.h"
+#include "Framebuffer.h"
+#include "Device.hpp"
+#include "libEGL/Display.h"
+#include "common/debug.h"
+
+#include <algorithm>
+
+namespace gl
+{
+
+Texture::Texture(GLuint id) : RefCountObject(id)
+{
+ mMinFilter = GL_NEAREST_MIPMAP_LINEAR;
+ mMagFilter = GL_LINEAR;
+ mWrapS = GL_REPEAT;
+ mWrapT = GL_REPEAT;
+ mMaxAnisotropy = 1.0f;
+
+ resource = new sw::Resource(0);
+}
+
+Texture::~Texture()
+{
+ resource->destruct();
+}
+
+sw::Resource *Texture::getResource() const
+{
+ return resource;
+}
+
+// Returns true on successful filter state update (valid enum parameter)
+bool Texture::setMinFilter(GLenum filter)
+{
+ switch(filter)
+ {
+ case GL_NEAREST_MIPMAP_NEAREST:
+ case GL_LINEAR_MIPMAP_NEAREST:
+ case GL_NEAREST_MIPMAP_LINEAR:
+ case GL_LINEAR_MIPMAP_LINEAR:
+ if(getTarget() == GL_TEXTURE_EXTERNAL_OES)
+ {
+ return false;
+ }
+ // Fall through
+ case GL_NEAREST:
+ case GL_LINEAR:
+ mMinFilter = filter;
+ 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:
+ mMagFilter = filter;
+ 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_MIRRORED_REPEAT:
+ if(getTarget() == GL_TEXTURE_EXTERNAL_OES)
+ {
+ return false;
+ }
+ // Fall through
+ case GL_CLAMP_TO_EDGE:
+ mWrapS = wrap;
+ 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_MIRRORED_REPEAT:
+ if(getTarget() == GL_TEXTURE_EXTERNAL_OES)
+ {
+ return false;
+ }
+ // Fall through
+ case GL_CLAMP_TO_EDGE:
+ mWrapT = wrap;
+ return true;
+ default:
+ return false;
+ }
+}
+
+// Returns true on successful max anisotropy update (valid anisotropy value)
+bool Texture::setMaxAnisotropy(float textureMaxAnisotropy)
+{
+ textureMaxAnisotropy = std::min(textureMaxAnisotropy, MAX_TEXTURE_MAX_ANISOTROPY);
+
+ if(textureMaxAnisotropy < 1.0f)
+ {
+ return false;
+ }
+
+ if(mMaxAnisotropy != textureMaxAnisotropy)
+ {
+ mMaxAnisotropy = textureMaxAnisotropy;
+ }
+
+ return true;
+}
+
+GLenum Texture::getMinFilter() const
+{
+ return mMinFilter;
+}
+
+GLenum Texture::getMagFilter() const
+{
+ return mMagFilter;
+}
+
+GLenum Texture::getWrapS() const
+{
+ return mWrapS;
+}
+
+GLenum Texture::getWrapT() const
+{
+ return mWrapT;
+}
+
+GLfloat Texture::getMaxAnisotropy() const
+{
+ return mMaxAnisotropy;
+}
+
+Image *Texture::createSharedImage(GLenum target, unsigned int level)
+{
+ Image *image = getRenderTarget(target, level); // Increments reference count
+
+ if(image)
+ {
+ image->markShared();
+ }
+
+ return image;
+}
+
+void Texture::setImage(GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *image)
+{
+ if(pixels && image)
+ {
+ image->loadImageData(0, 0, image->getWidth(), image->getHeight(), format, type, unpackAlignment, pixels);
+ }
+}
+
+void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, Image *image)
+{
+ if(pixels && image)
+ {
+ image->loadCompressedData(0, 0, image->getWidth(), image->getHeight(), imageSize, pixels);
+ }
+}
+
+void Texture::subImage(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *image)
+{
+ if(!image)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ if(width + xoffset > image->getWidth() || height + yoffset > image->getHeight())
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ if(IsCompressed(image->getFormat()))
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ if(format != image->getFormat())
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ if(pixels)
+ {
+ image->loadImageData(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels);
+ }
+}
+
+void Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *image)
+{
+ if(!image)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ if(width + xoffset > image->getWidth() || height + yoffset > image->getHeight())
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ if(format != image->getFormat())
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ if(pixels)
+ {
+ image->loadCompressedData(xoffset, yoffset, width, height, imageSize, pixels);
+ }
+}
+
+bool Texture::copy(Image *source, const sw::Rect &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, Image *dest)
+{
+ Device *device = getDevice();
+
+ sw::Rect destRect = {xoffset, yoffset, xoffset + (sourceRect.x1 - sourceRect.x0), yoffset + (sourceRect.y1 - sourceRect.y0)};
+ bool success = device->stretchRect(source, &sourceRect, dest, &destRect, false);
+
+ if(!success)
+ {
+ return error(GL_OUT_OF_MEMORY, false);
+ }
+
+ return true;
+}
+
+bool Texture::isMipmapFiltered() const
+{
+ switch(mMinFilter)
+ {
+ case GL_NEAREST:
+ case GL_LINEAR:
+ return false;
+ case GL_NEAREST_MIPMAP_NEAREST:
+ case GL_LINEAR_MIPMAP_NEAREST:
+ case GL_NEAREST_MIPMAP_LINEAR:
+ case GL_LINEAR_MIPMAP_LINEAR:
+ return true;
+ default: UNREACHABLE();
+ }
+
+ return false;
+}
+
+Texture2D::Texture2D(GLuint id) : Texture(id)
+{
+ for(int i = 0; i < MIPMAP_LEVELS; i++)
+ {
+ image[i] = 0;
+ }
+
+ mSurface = NULL;
+
+ mColorbufferProxy = NULL;
+ mProxyRefs = 0;
+}
+
+Texture2D::~Texture2D()
+{
+ resource->lock(sw::DESTRUCT);
+
+ for(int i = 0; i < MIPMAP_LEVELS; i++)
+ {
+ if(image[i])
+ {
+ image[i]->unbind();
+ image[i] = 0;
+ }
+ }
+
+ resource->unlock();
+
+ if(mSurface)
+ {
+ mSurface->setBoundTexture(NULL);
+ mSurface = NULL;
+ }
+
+ mColorbufferProxy = 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(GLenum target, GLint level) const
+{
+ ASSERT(target == GL_TEXTURE_2D);
+ return image[level] ? image[level]->getWidth() : 0;
+}
+
+GLsizei Texture2D::getHeight(GLenum target, GLint level) const
+{
+ ASSERT(target == GL_TEXTURE_2D);
+ return image[level] ? image[level]->getHeight() : 0;
+}
+
+GLenum Texture2D::getFormat(GLenum target, GLint level) const
+{
+ ASSERT(target == GL_TEXTURE_2D);
+ return image[level] ? image[level]->getFormat() : 0;
+}
+
+GLenum Texture2D::getType(GLenum target, GLint level) const
+{
+ ASSERT(target == GL_TEXTURE_2D);
+ return image[level] ? image[level]->getType() : 0;
+}
+
+sw::Format Texture2D::getInternalFormat(GLenum target, GLint level) const
+{
+ ASSERT(target == GL_TEXTURE_2D);
+ return image[level] ? image[level]->getInternalFormat() : sw::FORMAT_NULL;
+}
+
+int Texture2D::getLevelCount() const
+{
+ ASSERT(isSamplerComplete());
+ int levels = 0;
+
+ while(levels < MIPMAP_LEVELS && image[levels])
+ {
+ levels++;
+ }
+
+ return levels;
+}
+
+void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
+{
+ if(image[level])
+ {
+ image[level]->unbind();
+ }
+
+ image[level] = new Image(this, width, height, format, type);
+
+ if(!image[level])
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+
+ Texture::setImage(format, type, unpackAlignment, pixels, image[level]);
+}
+
+void Texture2D::bindTexImage(egl::Surface *surface)
+{
+ GLenum format;
+
+ switch(surface->getInternalFormat())
+ {
+ case sw::FORMAT_A8R8G8B8:
+ format = GL_RGBA;
+ break;
+ case sw::FORMAT_X8R8G8B8:
+ format = GL_RGB;
+ break;
+ default:
+ UNIMPLEMENTED();
+ return;
+ }
+
+ for(int level = 0; level < MIPMAP_LEVELS; level++)
+ {
+ if(image[level])
+ {
+ image[level]->unbind();
+ image[level] = 0;
+ }
+ }
+
+ image[0] = surface->getRenderTarget();
+
+ mSurface = surface;
+ mSurface->setBoundTexture(this);
+}
+
+void Texture2D::releaseTexImage()
+{
+ for(int level = 0; level < MIPMAP_LEVELS; level++)
+ {
+ if(image[level])
+ {
+ image[level]->unbind();
+ image[level] = 0;
+ }
+ }
+}
+
+void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
+{
+ if(image[level])
+ {
+ image[level]->unbind();
+ }
+
+ image[level] = new Image(this, width, height, format, GL_UNSIGNED_BYTE);
+
+ if(!image[level])
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+
+ Texture::setCompressedImage(imageSize, pixels, image[level]);
+}
+
+void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
+{
+ Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, image[level]);
+}
+
+void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
+{
+ Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, image[level]);
+}
+
+void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
+{
+ Image *renderTarget = source->getRenderTarget();
+
+ if(!renderTarget)
+ {
+ ERR("Failed to retrieve the render target.");
+ return error(GL_OUT_OF_MEMORY);
+ }
+
+ if(image[level])
+ {
+ image[level]->unbind();
+ }
+
+ image[level] = new Image(this, width, height, format, GL_UNSIGNED_BYTE);
+
+ if(!image[level])
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+
+ if(width != 0 && height != 0)
+ {
+ sw::Rect sourceRect = {x, y, x + width, y + height};
+ sourceRect.clip(0, 0, source->getColorbuffer()->getWidth(), source->getColorbuffer()->getHeight());
+
+ copy(renderTarget, sourceRect, format, 0, 0, image[level]);
+ }
+
+ renderTarget->release();
+}
+
+void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
+{
+ if(!image[level])
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ if(xoffset + width > image[level]->getWidth() || yoffset + height > image[level]->getHeight())
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ Image *renderTarget = source->getRenderTarget();
+
+ if(!renderTarget)
+ {
+ ERR("Failed to retrieve the render target.");
+ return error(GL_OUT_OF_MEMORY);
+ }
+
+ sw::Rect sourceRect = {x, y, x + width, y + height};
+ sourceRect.clip(0, 0, source->getColorbuffer()->getWidth(), source->getColorbuffer()->getHeight());
+
+ copy(renderTarget, sourceRect, image[level]->getFormat(), xoffset, yoffset, image[level]);
+
+ renderTarget->release();
+}
+
+// Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.
+bool Texture2D::isSamplerComplete() const
+{
+ if(!image[0])
+ {
+ return false;
+ }
+
+ GLsizei width = image[0]->getWidth();
+ GLsizei height = image[0]->getHeight();
+
+ if(width <= 0 || height <= 0)
+ {
+ return false;
+ }
+
+ if(isMipmapFiltered())
+ {
+ 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
+{
+ GLsizei width = image[0]->getWidth();
+ GLsizei height = image[0]->getHeight();
+
+ int q = log2(std::max(width, height));
+
+ for(int level = 1; level <= q; level++)
+ {
+ if(!image[level])
+ {
+ return false;
+ }
+
+ if(image[level]->getFormat() != image[0]->getFormat())
+ {
+ return false;
+ }
+
+ if(image[level]->getType() != image[0]->getType())
+ {
+ return false;
+ }
+
+ if(image[level]->getWidth() != std::max(1, width >> level))
+ {
+ return false;
+ }
+
+ if(image[level]->getHeight() != std::max(1, height >> level))
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool Texture2D::isCompressed(GLenum target, GLint level) const
+{
+ return IsCompressed(getFormat(target, level));
+}
+
+bool Texture2D::isDepth(GLenum target, GLint level) const
+{
+ return IsDepthTexture(getFormat(target, level));
+}
+
+void Texture2D::generateMipmaps()
+{
+ if(!image[0])
+ {
+ return; // FIXME: error?
+ }
+
+ unsigned int q = log2(std::max(image[0]->getWidth(), image[0]->getHeight()));
+
+ for(unsigned int i = 1; i <= q; i++)
+ {
+ if(image[i])
+ {
+ image[i]->unbind();
+ }
+
+ image[i] = new Image(this, std::max(image[0]->getWidth() >> i, 1), std::max(image[0]->getHeight() >> i, 1), image[0]->getFormat(), image[0]->getType());
+
+ if(!image[i])
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+
+ getDevice()->stretchRect(image[i - 1], 0, image[i], 0, true);
+ }
+}
+
+Image *Texture2D::getImage(unsigned int level)
+{
+ return image[level];
+}
+
+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));
+ }
+
+ return mColorbufferProxy;
+}
+
+Image *Texture2D::getRenderTarget(GLenum target, unsigned int level)
+{
+ ASSERT(target == GL_TEXTURE_2D);
+ ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
+
+ if(image[level])
+ {
+ image[level]->addRef();
+ }
+
+ return image[level];
+}
+
+bool Texture2D::isShared(GLenum target, unsigned int level) const
+{
+ ASSERT(target == GL_TEXTURE_2D);
+ ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
+
+ if(mSurface) // Bound to an EGLSurface
+ {
+ return true;
+ }
+
+ if(!image[level])
+ {
+ return false;
+ }
+
+ return image[level]->isShared();
+}
+
+TextureCubeMap::TextureCubeMap(GLuint id) : Texture(id)
+{
+ for(int f = 0; f < 6; f++)
+ {
+ for(int i = 0; i < MIPMAP_LEVELS; i++)
+ {
+ image[f][i] = 0;
+ }
+ }
+
+ for(int f = 0; f < 6; f++)
+ {
+ mFaceProxies[f] = NULL;
+ mFaceProxyRefs[f] = 0;
+ }
+}
+
+TextureCubeMap::~TextureCubeMap()
+{
+ resource->lock(sw::DESTRUCT);
+
+ for(int f = 0; f < 6; f++)
+ {
+ for(int i = 0; i < MIPMAP_LEVELS; i++)
+ {
+ if(image[f][i])
+ {
+ image[f][i]->unbind();
+ image[f][i] = 0;
+ }
+ }
+ }
+
+ resource->unlock();
+
+ for(int i = 0; i < 6; i++)
+ {
+ mFaceProxies[i] = 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 f = 0; f < 6; f++)
+ {
+ if(mFaceProxies[f] == proxy)
+ {
+ mFaceProxyRefs[f]++;
+ }
+ }
+}
+
+void TextureCubeMap::releaseProxy(const Renderbuffer *proxy)
+{
+ for(int f = 0; f < 6; f++)
+ {
+ if(mFaceProxies[f] == proxy)
+ {
+ if(mFaceProxyRefs[f] > 0)
+ {
+ mFaceProxyRefs[f]--;
+ }
+
+ if(mFaceProxyRefs[f] == 0)
+ {
+ mFaceProxies[f] = NULL;
+ }
+ }
+ }
+}
+
+GLenum TextureCubeMap::getTarget() const
+{
+ return GL_TEXTURE_CUBE_MAP;
+}
+
+GLsizei TextureCubeMap::getWidth(GLenum target, GLint level) const
+{
+ int face = CubeFaceIndex(target);
+ return image[face][level] ? image[face][level]->getWidth() : 0;
+}
+
+GLsizei TextureCubeMap::getHeight(GLenum target, GLint level) const
+{
+ int face = CubeFaceIndex(target);
+ return image[face][level] ? image[face][level]->getHeight() : 0;
+}
+
+GLenum TextureCubeMap::getFormat(GLenum target, GLint level) const
+{
+ int face = CubeFaceIndex(target);
+ return image[face][level] ? image[face][level]->getFormat() : 0;
+}
+
+GLenum TextureCubeMap::getType(GLenum target, GLint level) const
+{
+ int face = CubeFaceIndex(target);
+ return image[face][level] ? image[face][level]->getType() : 0;
+}
+
+sw::Format TextureCubeMap::getInternalFormat(GLenum target, GLint level) const
+{
+ int face = CubeFaceIndex(target);
+ return image[face][level] ? image[face][level]->getInternalFormat() : sw::FORMAT_NULL;
+}
+
+int TextureCubeMap::getLevelCount() const
+{
+ ASSERT(isSamplerComplete());
+ int levels = 0;
+
+ while(levels < MIPMAP_LEVELS && image[0][levels])
+ {
+ levels++;
+ }
+
+ return levels;
+}
+
+void TextureCubeMap::setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
+{
+ int face = CubeFaceIndex(target);
+
+ if(image[face][level])
+ {
+ image[face][level]->unbind();
+ }
+
+ image[face][level] = new Image(this, width, height, format, GL_UNSIGNED_BYTE);
+
+ if(!image[face][level])
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+
+ Texture::setCompressedImage(imageSize, pixels, image[face][level]);
+}
+
+void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
+{
+ Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, image[CubeFaceIndex(target)][level]);
+}
+
+void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
+{
+ Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, image[CubeFaceIndex(target)][level]);
+}
+
+// Tests for cube map sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 86.
+bool TextureCubeMap::isSamplerComplete() const
+{
+ for(int face = 0; face < 6; face++)
+ {
+ if(!image[face][0])
+ {
+ return false;
+ }
+ }
+
+ int size = image[0][0]->getWidth();
+
+ if(size <= 0)
+ {
+ return false;
+ }
+
+ if(!isMipmapFiltered())
+ {
+ 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(image[0][0]->getWidth() <= 0 || image[0][0]->getHeight() != image[0][0]->getWidth())
+ {
+ return false;
+ }
+
+ for(unsigned int face = 1; face < 6; face++)
+ {
+ if(image[face][0]->getWidth() != image[0][0]->getWidth() ||
+ image[face][0]->getWidth() != image[0][0]->getHeight() ||
+ image[face][0]->getFormat() != image[0][0]->getFormat() ||
+ image[face][0]->getType() != image[0][0]->getType())
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool TextureCubeMap::isMipmapCubeComplete() const
+{
+ if(!isCubeComplete())
+ {
+ return false;
+ }
+
+ GLsizei size = image[0][0]->getWidth();
+ int q = log2(size);
+
+ for(int face = 0; face < 6; face++)
+ {
+ for(int level = 1; level <= q; level++)
+ {
+ if(!image[face][level])
+ {
+ return false;
+ }
+
+ if(image[face][level]->getFormat() != image[0][0]->getFormat())
+ {
+ return false;
+ }
+
+ if(image[face][level]->getType() != image[0][0]->getType())
+ {
+ return false;
+ }
+
+ if(image[face][level]->getWidth() != std::max(1, size >> level))
+ {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+bool TextureCubeMap::isCompressed(GLenum target, GLint level) const
+{
+ return IsCompressed(getFormat(target, level));
+}
+
+bool TextureCubeMap::isDepth(GLenum target, GLint level) const
+{
+ return IsDepthTexture(getFormat(target, level));
+}
+
+void TextureCubeMap::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
+{
+ int face = CubeFaceIndex(target);
+
+ if(image[face][level])
+ {
+ image[face][level]->unbind();
+ }
+
+ image[face][level] = new Image(this, width, height, format, type);
+
+ if(!image[face][level])
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+
+ Texture::setImage(format, type, unpackAlignment, pixels, image[face][level]);
+}
+
+void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
+{
+ Image *renderTarget = source->getRenderTarget();
+
+ if(!renderTarget)
+ {
+ ERR("Failed to retrieve the render target.");
+ return error(GL_OUT_OF_MEMORY);
+ }
+
+ int face = CubeFaceIndex(target);
+
+ if(image[face][level])
+ {
+ image[face][level]->unbind();
+ }
+
+ image[face][level] = new Image(this, width, height, format, GL_UNSIGNED_BYTE);
+
+ if(!image[face][level])
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+
+ if(width != 0 && height != 0)
+ {
+ sw::Rect sourceRect = {x, y, x + width, y + height};
+ sourceRect.clip(0, 0, source->getColorbuffer()->getWidth(), source->getColorbuffer()->getHeight());
+
+ copy(renderTarget, sourceRect, format, 0, 0, image[face][level]);
+ }
+
+ renderTarget->release();
+}
+
+Image *TextureCubeMap::getImage(int face, unsigned int level)
+{
+ return image[face][level];
+}
+
+Image *TextureCubeMap::getImage(GLenum face, unsigned int level)
+{
+ return image[CubeFaceIndex(face)][level];
+}
+
+void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
+{
+ int face = CubeFaceIndex(target);
+
+ if(!image[face][level])
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ GLsizei size = image[face][level]->getWidth();
+
+ if(xoffset + width > size || yoffset + height > size)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ Image *renderTarget = source->getRenderTarget();
+
+ if(!renderTarget)
+ {
+ ERR("Failed to retrieve the render target.");
+ return error(GL_OUT_OF_MEMORY);
+ }
+
+ sw::Rect sourceRect = {x, y, x + width, y + height};
+ sourceRect.clip(0, 0, source->getColorbuffer()->getWidth(), source->getColorbuffer()->getHeight());
+
+ copy(renderTarget, sourceRect, image[face][level]->getFormat(), xoffset, yoffset, image[face][level]);
+
+ renderTarget->release();
+}
+
+void TextureCubeMap::generateMipmaps()
+{
+ if(!isCubeComplete())
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ unsigned int q = log2(image[0][0]->getWidth());
+
+ for(unsigned int f = 0; f < 6; f++)
+ {
+ for(unsigned int i = 1; i <= q; i++)
+ {
+ if(image[f][i])
+ {
+ image[f][i]->unbind();
+ }
+
+ image[f][i] = new Image(this, std::max(image[0][0]->getWidth() >> i, 1), std::max(image[0][0]->getHeight() >> i, 1), image[0][0]->getFormat(), image[0][0]->getType());
+
+ if(!image[f][i])
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+
+ getDevice()->stretchRect(image[f][i - 1], 0, image[f][i], 0, true);
+ }
+ }
+}
+
+Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target)
+{
+ if(!IsCubemapTextureTarget(target))
+ {
+ return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
+ }
+
+ int face = CubeFaceIndex(target);
+
+ if(mFaceProxies[face] == NULL)
+ {
+ mFaceProxies[face] = new Renderbuffer(id(), new RenderbufferTextureCubeMap(this, target));
+ }
+
+ return mFaceProxies[face];
+}
+
+Image *TextureCubeMap::getRenderTarget(GLenum target, unsigned int level)
+{
+ ASSERT(IsCubemapTextureTarget(target));
+ ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
+
+ int face = CubeFaceIndex(target);
+
+ if(image[face][level])
+ {
+ image[face][level]->addRef();
+ }
+
+ return image[face][level];
+}
+
+bool TextureCubeMap::isShared(GLenum target, unsigned int level) const
+{
+ ASSERT(IsCubemapTextureTarget(target));
+ ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
+
+ int face = CubeFaceIndex(target);
+
+ if(!image[face][level])
+ {
+ return false;
+ }
+
+ return image[face][level]->isShared();
+}
+
+TextureExternal::TextureExternal(GLuint id) : Texture2D(id)
+{
+ mMinFilter = GL_LINEAR;
+ mMagFilter = GL_LINEAR;
+ mWrapS = GL_CLAMP_TO_EDGE;
+ mWrapT = GL_CLAMP_TO_EDGE;
+}
+
+TextureExternal::~TextureExternal()
+{
+}
+
+GLenum TextureExternal::getTarget() const
+{
+ return GL_TEXTURE_EXTERNAL_OES;
+}
+
+void TextureExternal::setImage(Image *sharedImage)
+{
+ if(image[0])
+ {
+ image[0]->release();
+ }
+
+ sharedImage->addRef();
+ image[0] = sharedImage;
+}
+
+}
+
+// Exported functions for use by EGL
+extern "C"
+{
+ gl::Image *createBackBuffer(int width, int height, const egl::Config *config)
+ {
+ if(config)
+ {
+ return new gl::Image(0, width, height, config->mAlphaSize ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE);
+ }
+
+ return 0;
+ }
+}
diff --git a/src/GLES2/libGLES_CM/Texture.h b/src/GLES2/libGLES_CM/Texture.h
new file mode 100644
index 0000000..085fe92
--- /dev/null
+++ b/src/GLES2/libGLES_CM/Texture.h
@@ -0,0 +1,238 @@
+// SwiftShader Software Renderer
+//
+// Copyright(c) 2005-2013 TransGaming Inc.
+//
+// All rights reserved. No part of this software may be copied, distributed, transmitted,
+// transcribed, stored in a retrieval system, translated into any human or computer
+// language by any means, or disclosed to third parties without the explicit written
+// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
+// or implied, including but not limited to any patent rights, are granted to you.
+//
+
+// Texture.h: Defines the abstract 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 "Renderbuffer.h"
+#include "RefCountObject.h"
+#include "utilities.h"
+#include "common/debug.h"
+
+#define GL_APICALL
+#include <GLES2/gl2.h>
+
+#include <vector>
+
+namespace egl
+{
+class Surface;
+class Config;
+}
+
+namespace gl
+{
+class Framebuffer;
+
+enum
+{
+ IMPLEMENTATION_MAX_TEXTURE_LEVELS = MIPMAP_LEVELS,
+ IMPLEMENTATION_MAX_TEXTURE_SIZE = 1 << (MIPMAP_LEVELS - 1),
+ IMPLEMENTATION_MAX_CUBE_MAP_TEXTURE_SIZE = 1 << (MIPMAP_LEVELS - 1),
+ IMPLEMENTATION_MAX_RENDERBUFFER_SIZE = OUTLINE_RESOLUTION,
+ IMPLEMENTATION_MAX_SAMPLES = 4
+};
+
+class Texture : public RefCountObject
+{
+public:
+ explicit Texture(GLuint id);
+
+ virtual ~Texture();
+
+ sw::Resource *getResource() const;
+
+ 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(GLfloat textureMaxAnisotropy);
+
+ GLenum getMinFilter() const;
+ GLenum getMagFilter() const;
+ GLenum getWrapS() const;
+ GLenum getWrapT() const;
+ GLfloat getMaxAnisotropy() const;
+
+ virtual GLsizei getWidth(GLenum target, GLint level) const = 0;
+ virtual GLsizei getHeight(GLenum target, GLint level) const = 0;
+ virtual GLenum getFormat(GLenum target, GLint level) const = 0;
+ virtual GLenum getType(GLenum target, GLint level) const = 0;
+ virtual sw::Format getInternalFormat(GLenum target, GLint level) const = 0;
+ virtual int getLevelCount() const = 0;
+
+ virtual bool isSamplerComplete() const = 0;
+ virtual bool isCompressed(GLenum target, GLint level) const = 0;
+ virtual bool isDepth(GLenum target, GLint level) const = 0;
+
+ virtual Renderbuffer *getRenderbuffer(GLenum target) = 0;
+ virtual Image *getRenderTarget(GLenum target, unsigned int level) = 0;
+ virtual Image *createSharedImage(GLenum target, unsigned int level);
+ virtual bool isShared(GLenum target, unsigned int level) const = 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;
+
+protected:
+ void setImage(GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *image);
+ void 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);
+ void subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *image);
+
+ bool copy(Image *source, const sw::Rect &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, Image *dest);
+
+ bool isMipmapFiltered() const;
+
+ GLenum mMinFilter;
+ GLenum mMagFilter;
+ GLenum mWrapS;
+ GLenum mWrapT;
+ GLfloat mMaxAnisotropy;
+
+ sw::Resource *resource;
+};
+
+class Texture2D : public Texture
+{
+public:
+ explicit Texture2D(GLuint id);
+
+ virtual ~Texture2D();
+
+ void addProxyRef(const Renderbuffer *proxy);
+ void releaseProxy(const Renderbuffer *proxy);
+
+ virtual GLenum getTarget() const;
+
+ virtual GLsizei getWidth(GLenum target, GLint level) const;
+ virtual GLsizei getHeight(GLenum target, GLint level) const;
+ virtual GLenum getFormat(GLenum target, GLint level) const;
+ virtual GLenum getType(GLenum target, GLint level) const;
+ virtual sw::Format getInternalFormat(GLenum target, GLint level) const;
+ virtual int getLevelCount() 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);
+ void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source);
+
+ virtual bool isSamplerComplete() const;
+ virtual bool isCompressed(GLenum target, GLint level) const;
+ virtual bool isDepth(GLenum target, GLint level) const;
+ virtual void bindTexImage(egl::Surface *surface);
+ virtual void releaseTexImage();
+
+ virtual void generateMipmaps();
+
+ virtual Renderbuffer *getRenderbuffer(GLenum target);
+ virtual Image *getRenderTarget(GLenum target, unsigned int level);
+ virtual bool isShared(GLenum target, unsigned int level) const;
+
+ Image *getImage(unsigned int level);
+
+protected:
+ bool isMipmapComplete() const;
+
+ Image *image[IMPLEMENTATION_MAX_TEXTURE_LEVELS];
+
+ 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 TextureCubeMap : public Texture
+{
+public:
+ explicit TextureCubeMap(GLuint id);
+
+ virtual ~TextureCubeMap();
+
+ void addProxyRef(const Renderbuffer *proxy);
+ void releaseProxy(const Renderbuffer *proxy);
+
+ virtual GLenum getTarget() const;
+
+ virtual GLsizei getWidth(GLenum target, GLint level) const;
+ virtual GLsizei getHeight(GLenum target, GLint level) const;
+ virtual GLenum getFormat(GLenum target, GLint level) const;
+ virtual GLenum getType(GLenum target, GLint level) const;
+ virtual sw::Format getInternalFormat(GLenum target, GLint level) const;
+ virtual int getLevelCount() const;
+
+ void setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels);
+ void setCompressedImage(GLenum target, 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);
+
+ virtual bool isSamplerComplete() const;
+ virtual bool isCompressed(GLenum target, GLint level) const;
+ virtual bool isDepth(GLenum target, GLint level) const;
+
+ virtual void generateMipmaps();
+
+ virtual Renderbuffer *getRenderbuffer(GLenum target);
+ virtual Image *getRenderTarget(GLenum target, unsigned int level);
+ virtual bool isShared(GLenum target, unsigned int level) const;
+
+ Image *getImage(int face, unsigned int level);
+
+private:
+ bool isCubeComplete() const;
+ bool isMipmapCubeComplete() const;
+
+ // face is one of the GL_TEXTURE_CUBE_MAP_* enumerants. Returns NULL on failure.
+ Image *getImage(GLenum face, unsigned int level);
+
+ Image *image[6][IMPLEMENTATION_MAX_TEXTURE_LEVELS];
+
+ // 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];
+};
+
+class TextureExternal : public Texture2D
+{
+public:
+ explicit TextureExternal(GLuint id);
+
+ virtual ~TextureExternal();
+
+ virtual GLenum getTarget() const;
+
+ void setImage(Image *image);
+};
+}
+
+#endif // LIBGLESV2_TEXTURE_H_
diff --git a/src/GLES2/libGLES_CM/VertexDataManager.cpp b/src/GLES2/libGLES_CM/VertexDataManager.cpp
new file mode 100644
index 0000000..ff88a6d
--- /dev/null
+++ b/src/GLES2/libGLES_CM/VertexDataManager.cpp
@@ -0,0 +1,334 @@
+// SwiftShader Software Renderer
+//
+// Copyright(c) 2005-2012 TransGaming Inc.
+//
+// All rights reserved. No part of this software may be copied, distributed, transmitted,
+// transcribed, stored in a retrieval system, translated into any human or computer
+// language by any means, or disclosed to third parties without the explicit written
+// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
+// or implied, including but not limited to any patent rights, are granted to you.
+//
+
+// VertexDataManager.h: Defines the VertexDataManager, a class that
+// runs the Buffer translation process.
+
+#include "VertexDataManager.h"
+
+#include "Buffer.h"
+#include "Program.h"
+#include "IndexDataManager.h"
+#include "common/debug.h"
+
+namespace
+{
+ enum {INITIAL_STREAM_BUFFER_SIZE = 1024 * 1024};
+}
+
+namespace gl
+{
+
+VertexDataManager::VertexDataManager(Context *context) : mContext(context)
+{
+ for(int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
+ {
+ mDirtyCurrentValue[i] = true;
+ mCurrentValueBuffer[i] = NULL;
+ }
+
+ mStreamingBuffer = new StreamingVertexBuffer(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];
+ }
+}
+
+unsigned int VertexDataManager::writeAttributeData(StreamingVertexBuffer *vertexBuffer, GLint start, GLsizei count, const VertexAttribute &attribute)
+{
+ Buffer *buffer = attribute.mBoundBuffer.get();
+
+ int inputStride = attribute.stride();
+ int elementSize = attribute.typeSize();
+ unsigned int streamOffset = 0;
+
+ char *output = NULL;
+
+ if(vertexBuffer)
+ {
+ output = (char*)vertexBuffer->map(attribute, attribute.typeSize() * count, &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);
+ }
+
+ input += inputStride * start;
+
+ if(inputStride == elementSize)
+ {
+ memcpy(output, input, count * inputStride);
+ }
+ else
+ {
+ for(int i = 0; i < count; i++)
+ {
+ memcpy(output, input, elementSize);
+ output += elementSize;
+ input += inputStride;
+ }
+ }
+
+ vertexBuffer->unmap();
+
+ return streamOffset;
+}
+
+GLenum VertexDataManager::prepareVertexData(GLint start, GLsizei count, TranslatedAttribute *translated)
+{
+ if(!mStreamingBuffer)
+ {
+ return GL_OUT_OF_MEMORY;
+ }
+
+ const VertexAttributeArray &attribs = mContext->getVertexAttributes();
+ Program *program = mContext->getCurrentProgram();
+
+ // Determine the required storage size per used buffer
+ for(int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
+ {
+ if(program->getAttributeStream(i) != -1 && attribs[i].mArrayEnabled)
+ {
+ if(!attribs[i].mBoundBuffer)
+ {
+ mStreamingBuffer->addRequiredSpace(attribs[i].typeSize() * count);
+ }
+ }
+ }
+
+ mStreamingBuffer->reserveRequiredSpace();
+
+ // Perform the vertex data translations
+ for(int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
+ {
+ if(program->getAttributeStream(i) != -1)
+ {
+ 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;
+ }
+
+ sw::Resource *staticBuffer = buffer ? buffer->getResource() : NULL;
+
+ if(staticBuffer)
+ {
+ translated[i].vertexBuffer = staticBuffer;
+ translated[i].offset = start * attribs[i].stride() + attribs[i].mOffset;
+ translated[i].stride = attribs[i].stride();
+ }
+ else
+ {
+ unsigned int streamOffset = writeAttributeData(mStreamingBuffer, start, count, attribs[i]);
+
+ if(streamOffset == -1)
+ {
+ return GL_OUT_OF_MEMORY;
+ }
+
+ translated[i].vertexBuffer = mStreamingBuffer->getResource();
+ translated[i].offset = streamOffset;
+ translated[i].stride = attribs[i].typeSize();
+ }
+
+ switch(attribs[i].mType)
+ {
+ case GL_BYTE: translated[i].type = sw::STREAMTYPE_SBYTE; break;
+ case GL_UNSIGNED_BYTE: translated[i].type = sw::STREAMTYPE_BYTE; break;
+ case GL_SHORT: translated[i].type = sw::STREAMTYPE_SHORT; break;
+ case GL_UNSIGNED_SHORT: translated[i].type = sw::STREAMTYPE_USHORT; break;
+ case GL_FIXED: translated[i].type = sw::STREAMTYPE_FIXED; break;
+ case GL_FLOAT: translated[i].type = sw::STREAMTYPE_FLOAT; break;
+ default: UNREACHABLE(); translated[i].type = sw::STREAMTYPE_FLOAT; break;
+ }
+
+ translated[i].count = attribs[i].mSize;
+ translated[i].normalized = attribs[i].mNormalized;
+ }
+ else
+ {
+ if(mDirtyCurrentValue[i])
+ {
+ delete mCurrentValueBuffer[i];
+ mCurrentValueBuffer[i] = new ConstantVertexBuffer(attribs[i].mCurrentValue[0], attribs[i].mCurrentValue[1], attribs[i].mCurrentValue[2], attribs[i].mCurrentValue[3]);
+ mDirtyCurrentValue[i] = false;
+ }
+
+ translated[i].vertexBuffer = mCurrentValueBuffer[i]->getResource();
+
+ translated[i].type = sw::STREAMTYPE_FLOAT;
+ translated[i].count = 4;
+ translated[i].stride = 0;
+ translated[i].offset = 0;
+ }
+ }
+ }
+
+ return GL_NO_ERROR;
+}
+
+VertexBuffer::VertexBuffer(unsigned int size) : mVertexBuffer(NULL)
+{
+ if(size > 0)
+ {
+ mVertexBuffer = new sw::Resource(size + 1024);
+
+ if(!mVertexBuffer)
+ {
+ ERR("Out of memory allocating a vertex buffer of size %lu.", size);
+ }
+ }
+}
+
+VertexBuffer::~VertexBuffer()
+{
+ if(mVertexBuffer)
+ {
+ mVertexBuffer->destruct();
+ }
+}
+
+void VertexBuffer::unmap()
+{
+ if(mVertexBuffer)
+ {
+ mVertexBuffer->unlock();
+ }
+}
+
+sw::Resource *VertexBuffer::getResource() const
+{
+ return mVertexBuffer;
+}
+
+ConstantVertexBuffer::ConstantVertexBuffer(float x, float y, float z, float w) : VertexBuffer(4 * sizeof(float))
+{
+ if(mVertexBuffer)
+ {
+ float *vector = (float*)mVertexBuffer->lock(sw::PUBLIC);
+
+ vector[0] = x;
+ vector[1] = y;
+ vector[2] = z;
+ vector[3] = w;
+
+ mVertexBuffer->unlock();
+ }
+}
+
+ConstantVertexBuffer::~ConstantVertexBuffer()
+{
+}
+
+StreamingVertexBuffer::StreamingVertexBuffer(unsigned int size) : VertexBuffer(size)
+{
+ mBufferSize = size;
+ mWritePosition = 0;
+ mRequiredSpace = 0;
+}
+
+StreamingVertexBuffer::~StreamingVertexBuffer()
+{
+}
+
+void StreamingVertexBuffer::addRequiredSpace(unsigned int requiredSpace)
+{
+ mRequiredSpace += requiredSpace;
+}
+
+void *StreamingVertexBuffer::map(const VertexAttribute &attribute, unsigned int requiredSpace, unsigned int *offset)
+{
+ void *mapPtr = NULL;
+
+ if(mVertexBuffer)
+ {
+ mapPtr = (char*)mVertexBuffer->lock(sw::PUBLIC) + mWritePosition;
+
+ if(!mapPtr)
+ {
+ ERR("Lock failed");
+ return NULL;
+ }
+
+ *offset = mWritePosition;
+ mWritePosition += requiredSpace;
+ }
+
+ return mapPtr;
+}
+
+void StreamingVertexBuffer::reserveRequiredSpace()
+{
+ if(mRequiredSpace > mBufferSize)
+ {
+ if(mVertexBuffer)
+ {
+ mVertexBuffer->destruct();
+ mVertexBuffer = 0;
+ }
+
+ 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.
+
+ mVertexBuffer = new sw::Resource(mBufferSize);
+
+ if(!mVertexBuffer)
+ {
+ ERR("Out of memory allocating a vertex buffer of size %lu.", mBufferSize);
+ }
+
+ mWritePosition = 0;
+ }
+ else if(mWritePosition + mRequiredSpace > mBufferSize) // Recycle
+ {
+ if(mVertexBuffer)
+ {
+ mVertexBuffer->destruct();
+ mVertexBuffer = new sw::Resource(mBufferSize);
+ }
+
+ mWritePosition = 0;
+ }
+
+ mRequiredSpace = 0;
+}
+
+}
diff --git a/src/GLES2/libGLES_CM/VertexDataManager.h b/src/GLES2/libGLES_CM/VertexDataManager.h
new file mode 100644
index 0000000..8800219
--- /dev/null
+++ b/src/GLES2/libGLES_CM/VertexDataManager.h
@@ -0,0 +1,99 @@
+// SwiftShader Software Renderer
+//
+// Copyright(c) 2005-2012 TransGaming Inc.
+//
+// All rights reserved. No part of this software may be copied, distributed, transmitted,
+// transcribed, stored in a retrieval system, translated into any human or computer
+// language by any means, or disclosed to third parties without the explicit written
+// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
+// or implied, including but not limited to any patent rights, are granted to you.
+//
+
+// VertexDataManager.h: Defines the VertexDataManager, a class that
+// runs the Buffer translation process.
+
+#ifndef LIBGLESV2_VERTEXDATAMANAGER_H_
+#define LIBGLESV2_VERTEXDATAMANAGER_H_
+
+#include "Context.h"
+#include "Device.hpp"
+
+#define GL_APICALL
+#include <GLES2/gl2.h>
+
+namespace gl
+{
+
+struct TranslatedAttribute
+{
+ sw::StreamType type;
+ int count;
+ bool normalized;
+
+ unsigned int offset;
+ unsigned int stride; // 0 means not to advance the read pointer at all
+
+ sw::Resource *vertexBuffer;
+};
+
+class VertexBuffer
+{
+ public:
+ VertexBuffer(unsigned int size);
+ virtual ~VertexBuffer();
+
+ void unmap();
+
+ sw::Resource *getResource() const;
+
+ protected:
+ sw::Resource *mVertexBuffer;
+};
+
+class ConstantVertexBuffer : public VertexBuffer
+{
+ public:
+ ConstantVertexBuffer(float x, float y, float z, float w);
+ ~ConstantVertexBuffer();
+};
+
+class StreamingVertexBuffer : public VertexBuffer
+{
+ public:
+ StreamingVertexBuffer(unsigned int size);
+ ~StreamingVertexBuffer();
+
+ void *map(const VertexAttribute &attribute, unsigned int requiredSpace, unsigned int *streamOffset);
+ void reserveRequiredSpace();
+ void addRequiredSpace(unsigned int requiredSpace);
+
+ protected:
+ unsigned int mBufferSize;
+ unsigned int mWritePosition;
+ unsigned int mRequiredSpace;
+};
+
+class VertexDataManager
+{
+ public:
+ VertexDataManager(Context *context);
+ virtual ~VertexDataManager();
+
+ void dirtyCurrentValue(int index) { mDirtyCurrentValue[index] = true; }
+
+ GLenum prepareVertexData(GLint start, GLsizei count, TranslatedAttribute *outAttribs);
+
+ private:
+ unsigned int writeAttributeData(StreamingVertexBuffer *vertexBuffer, GLint start, GLsizei count, const VertexAttribute &attribute);
+
+ Context *const mContext;
+
+ StreamingVertexBuffer *mStreamingBuffer;
+
+ bool mDirtyCurrentValue[MAX_VERTEX_ATTRIBS];
+ ConstantVertexBuffer *mCurrentValueBuffer[MAX_VERTEX_ATTRIBS];
+};
+
+}
+
+#endif // LIBGLESV2_VERTEXDATAMANAGER_H_
diff --git a/src/GLES2/libGLES_CM/exports.map b/src/GLES2/libGLES_CM/exports.map
new file mode 100644
index 0000000..7d08ed0
--- /dev/null
+++ b/src/GLES2/libGLES_CM/exports.map
@@ -0,0 +1,186 @@
+{
+global:
+ glActiveTexture;
+ glAttachShader;
+ glBindAttribLocation;
+ glBindBuffer;
+ glBindFramebuffer;
+ glBindRenderbuffer;
+ glBindTexture;
+ glBlendColor;
+ glBlendEquation;
+ glBlendEquationSeparate;
+ glBlendFunc;
+ glBlendFuncSeparate;
+ glBufferData;
+ glBufferSubData;
+ glCheckFramebufferStatus;
+ glClear;
+ glClearColor;
+ glClearDepthf;
+ glClearStencil;
+ glColorMask;
+ glCompileShader;
+ glCompressedTexImage2D;
+ glCompressedTexSubImage2D;
+ glCopyTexImage2D;
+ glCopyTexSubImage2D;
+ glCreateProgram;
+ glCreateShader;
+ glCullFace;
+ glDeleteBuffers;
+ glDeleteFramebuffers;
+ glDeleteProgram;
+ glDeleteRenderbuffers;
+ glDeleteShader;
+ glDeleteTextures;
+ glDepthFunc;
+ glDepthMask;
+ glDepthRangef;
+ glDetachShader;
+ glDisable;
+ glDisableVertexAttribArray;
+ glDrawArrays;
+ glDrawElements;
+ glEnable;
+ glEnableVertexAttribArray;
+ glFinish;
+ glFlush;
+ glFramebufferRenderbuffer;
+ glFramebufferTexture2D;
+ glFrontFace;
+ glGenBuffers;
+ glGenFramebuffers;
+ glGenRenderbuffers;
+ glGenTextures;
+ glGenerateMipmap;
+ glGetActiveAttrib;
+ glGetActiveUniform;
+ glGetAttachedShaders;
+ glGetAttribLocation;
+ glGetBooleanv;
+ glGetBufferParameteriv;
+ glGetError;
+ glGetFloatv;
+ glGetFramebufferAttachmentParameteriv;
+ glGetIntegerv;
+ glGetProgramInfoLog;
+ glGetProgramiv;
+ glGetRenderbufferParameteriv;
+ glGetShaderInfoLog;
+ glGetShaderPrecisionFormat;
+ glGetShaderSource;
+ glGetShaderiv;
+ glGetString;
+ glGetTexParameterfv;
+ glGetTexParameteriv;
+ glGetUniformLocation;
+ glGetUniformfv;
+ glGetUniformiv;
+ glGetVertexAttribPointerv;
+ glGetVertexAttribfv;
+ glGetVertexAttribiv;
+ glHint;
+ glIsBuffer;
+ glIsEnabled;
+ glIsFramebuffer;
+ glIsProgram;
+ glIsRenderbuffer;
+ glIsShader;
+ glIsTexture;
+ glLineWidth;
+ glLinkProgram;
+ glPixelStorei;
+ glPolygonOffset;
+ glReadPixels;
+ glReleaseShaderCompiler;
+ glRenderbufferStorage;
+ glSampleCoverage;
+ glScissor;
+ glShaderBinary;
+ glShaderSource;
+ glStencilFunc;
+ glStencilFuncSeparate;
+ glStencilMask;
+ glStencilMaskSeparate;
+ glStencilOp;
+ glStencilOpSeparate;
+ glTexImage2D;
+ glTexParameterf;
+ glTexParameterfv;
+ glTexParameteri;
+ glTexParameteriv;
+ glTexSubImage2D;
+ glUniform1f;
+ glUniform1fv;
+ glUniform1i;
+ glUniform1iv;
+ glUniform2f;
+ glUniform2fv;
+ glUniform2i;
+ glUniform2iv;
+ glUniform3f;
+ glUniform3fv;
+ glUniform3i;
+ glUniform3iv;
+ glUniform4f;
+ glUniform4fv;
+ glUniform4i;
+ glUniform4iv;
+ glUniformMatrix2fv;
+ glUniformMatrix3fv;
+ glUniformMatrix4fv;
+ glUseProgram;
+ glValidateProgram;
+ glVertexAttrib1f;
+ glVertexAttrib1fv;
+ glVertexAttrib2f;
+ glVertexAttrib2fv;
+ glVertexAttrib3f;
+ glVertexAttrib3fv;
+ glVertexAttrib4f;
+ glVertexAttrib4fv;
+ glVertexAttribPointer;
+ glViewport;
+
+ # Extensions
+ glTexImage3DOES;
+ glBlitFramebufferANGLE;
+ glRenderbufferStorageMultisampleANGLE;
+ glDeleteFencesNV;
+ glFinishFenceNV;
+ glGenFencesNV;
+ glGetFenceivNV;
+ glIsFenceNV;
+ glSetFenceNV;
+ glTestFenceNV;
+ glGetGraphicsResetStatusEXT;
+ glReadnPixelsEXT;
+ glGetnUniformfvEXT;
+ glGetnUniformivEXT;
+ glGenQueriesEXT;
+ glDeleteQueriesEXT;
+ glIsQueryEXT;
+ glBeginQueryEXT;
+ glEndQueryEXT;
+ glGetQueryivEXT;
+ glGetQueryObjectuivEXT;
+
+ # EGL dependencies
+ glCreateContext;
+ glDestroyContext;
+ glMakeCurrent;
+ glGetCurrentContext;
+ glGetProcAddress;
+ glBindTexImage;
+
+ createFrameBuffer;
+ createBackBuffer;
+ createDevice;
+
+ Register;
+
+local:
+ *;
+};
+
diff --git a/src/GLES2/libGLES_CM/libGLESv2.cbp b/src/GLES2/libGLES_CM/libGLESv2.cbp
new file mode 100644
index 0000000..a045a3a
--- /dev/null
+++ b/src/GLES2/libGLES_CM/libGLESv2.cbp
@@ -0,0 +1,367 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
+<CodeBlocks_project_file>
+ <FileVersion major="1" minor="6" />
+ <Project>
+ <Option title="libGLESv2" />
+ <Option pch_mode="2" />
+ <Option compiler="gcc" />
+ <Build>
+ <Target title="Debug x86">
+ <Option output="./../../bin/x86/Debug/libGLESv2.so.2" prefix_auto="0" extension_auto="0" />
+ <Option object_output="obj/x86/Debug/" />
+ <Option type="3" />
+ <Option compiler="gcc" />
+ <Option createDefFile="1" />
+ <Option createStaticLib="1" />
+ <Compiler>
+ <Add option="-g" />
+ <Add option="-m32" />
+ </Compiler>
+ <Linker>
+ <Add option="-m32" />
+ <Add library="./../../LLVM/bin/x86/Debug/libLLVM.a" />
+ </Linker>
+ </Target>
+ <Target title="Release x86">
+ <Option output="./../../bin/x86/Release/libGLESv2.so.2" prefix_auto="0" extension_auto="0" />
+ <Option object_output="obj/x86/Release/" />
+ <Option type="3" />
+ <Option compiler="gcc" />
+ <Option createDefFile="1" />
+ <Option createStaticLib="1" />
+ <Compiler>
+ <Add option="-march=i686" />
+ <Add option="-fomit-frame-pointer" />
+ <Add option="-O2" />
+ <Add option="-m32" />
+ <Add option="-ffunction-sections" />
+ <Add option="-fdata-sections" />
+ <Add option="-DNDEBUG" />
+ <Add option="-DANGLE_DISABLE_TRACE" />
+ </Compiler>
+ <Linker>
+ <Add option="-s" />
+ <Add option="-m32" />
+ <Add option="-Wl,--gc-sections" />
+ <Add library="./../../LLVM/bin/x86/Release/libLLVM.a" />
+ </Linker>
+ </Target>
+ <Target title="Debug x64">
+ <Option output="./../../bin/x64/Debug/libGLESv2.so.2" prefix_auto="0" extension_auto="0" />
+ <Option object_output="obj/x64/Debug/" />
+ <Option type="3" />
+ <Option compiler="gcc" />
+ <Option createDefFile="1" />
+ <Option createStaticLib="1" />
+ <Compiler>
+ <Add option="-g" />
+ <Add option="-m64" />
+ <Add option="-fPIC" />
+ </Compiler>
+ <Linker>
+ <Add option="-m64" />
+ <Add library="./../../LLVM/bin/x64/Debug/libLLVM.a" />
+ </Linker>
+ </Target>
+ <Target title="Release x64">
+ <Option output="./../../bin/x64/Release/libGLESv2.so.2" prefix_auto="0" extension_auto="0" />
+ <Option object_output="obj/x64/Release/" />
+ <Option type="3" />
+ <Option compiler="gcc" />
+ <Option createDefFile="1" />
+ <Option createStaticLib="1" />
+ <Compiler>
+ <Add option="-march=core2" />
+ <Add option="-fomit-frame-pointer" />
+ <Add option="-O2" />
+ <Add option="-m64" />
+ <Add option="-fPIC" />
+ <Add option="-ffunction-sections" />
+ <Add option="-fdata-sections" />
+ <Add option="-DNDEBUG" />
+ <Add option="-DANGLE_DISABLE_TRACE" />
+ </Compiler>
+ <Linker>
+ <Add option="-s" />
+ <Add option="-m64" />
+ <Add option="-Wl,--gc-sections" />
+ <Add library="./../../LLVM/bin/x64/Release/libLLVM.a" />
+ </Linker>
+ </Target>
+ </Build>
+ <Compiler>
+ <Add option="-Wall" />
+ <Add option="-fexceptions" />
+ <Add option="-fno-operator-names" />
+ <Add option="-ffriend-injection" />
+ <Add option="-msse2" />
+ <Add option="-D__STDC_LIMIT_MACROS" />
+ <Add option="-D__STDC_CONSTANT_MACROS" />
+ <Add directory="./../" />
+ <Add directory="./../include/" />
+ <Add directory="./../../" />
+ <Add directory="./../../LLVM/include-linux/" />
+ <Add directory="./../../LLVM/include/" />
+ <Add directory="./../../LLVM/lib/Target/X86" />
+ <Add directory="./../../Renderer/" />
+ <Add directory="./../../Common/" />
+ <Add directory="./../../Shader/" />
+ <Add directory="./../../Main/" />
+ </Compiler>
+ <Linker>
+ <Add option="-Wl,--version-script=./exports.map" />
+ <Add library="pthread" />
+ <Add library="X11" />
+ <Add library="Xext" />
+ </Linker>
+ <Unit filename="./../../Common/CPUID.cpp" />
+ <Unit filename="./../../Common/CPUID.hpp" />
+ <Unit filename="./../../Common/Configurator.cpp" />
+ <Unit filename="./../../Common/Configurator.hpp" />
+ <Unit filename="./../../Common/Debug.cpp" />
+ <Unit filename="./../../Common/Debug.hpp" />
+ <Unit filename="./../../Common/ExceptionHandling.hpp" />
+ <Unit filename="./../../Common/Half.cpp" />
+ <Unit filename="./../../Common/Half.hpp" />
+ <Unit filename="./../../Common/Math.cpp" />
+ <Unit filename="./../../Common/Math.hpp" />
+ <Unit filename="./../../Common/Memory.cpp" />
+ <Unit filename="./../../Common/Memory.hpp" />
+ <Unit filename="./../../Common/MetaMacro.hpp" />
+ <Unit filename="./../../Common/MutexLock.hpp" />
+ <Unit filename="./../../Common/Resource.cpp" />
+ <Unit filename="./../../Common/Resource.hpp" />
+ <Unit filename="./../../Common/Socket.cpp" />
+ <Unit filename="./../../Common/Socket.hpp" />
+ <Unit filename="./../../Common/Thread.cpp" />
+ <Unit filename="./../../Common/Thread.hpp" />
+ <Unit filename="./../../Common/Timer.cpp" />
+ <Unit filename="./../../Common/Timer.hpp" />
+ <Unit filename="./../../Common/Types.hpp" />
+ <Unit filename="./../../Common/Version.h" />
+ <Unit filename="./../common/debug.cpp" />
+ <Unit filename="./../common/debug.h" />
+ <Unit filename="../compiler/AnalyzeCallDepth.cpp" />
+ <Unit filename="../compiler/AnalyzeCallDepth.h" />
+ <Unit filename="../compiler/BaseTypes.h" />
+ <Unit filename="../compiler/Common.h" />
+ <Unit filename="../compiler/Compiler.cpp" />
+ <Unit filename="../compiler/ConstantUnion.h" />
+ <Unit filename="../compiler/Diagnostics.cpp" />
+ <Unit filename="../compiler/Diagnostics.h" />
+ <Unit filename="../compiler/DirectiveHandler.cpp" />
+ <Unit filename="../compiler/DirectiveHandler.h" />
+ <Unit filename="../compiler/ExtensionBehavior.h" />
+ <Unit filename="../compiler/InfoSink.cpp" />
+ <Unit filename="../compiler/InfoSink.h" />
+ <Unit filename="../compiler/Initialize.cpp" />
+ <Unit filename="../compiler/Initialize.h" />
+ <Unit filename="../compiler/InitializeDll.cpp" />
+ <Unit filename="../compiler/InitializeDll.h" />
+ <Unit filename="../compiler/InitializeGlobals.h" />
+ <Unit filename="../compiler/InitializeParseContext.cpp" />
+ <Unit filename="../compiler/InitializeParseContext.h" />
+ <Unit filename="../compiler/IntermTraverse.cpp" />
+ <Unit filename="../compiler/Intermediate.cpp" />
+ <Unit filename="../compiler/MMap.h" />
+ <Unit filename="../compiler/OutputASM.cpp" />
+ <Unit filename="../compiler/OutputASM.h" />
+ <Unit filename="../compiler/ParseHelper.cpp" />
+ <Unit filename="../compiler/ParseHelper.h" />
+ <Unit filename="../compiler/PoolAlloc.cpp" />
+ <Unit filename="../compiler/PoolAlloc.h" />
+ <Unit filename="../compiler/Pragma.h" />
+ <Unit filename="../compiler/RemoveTree.cpp" />
+ <Unit filename="../compiler/RemoveTree.h" />
+ <Unit filename="../compiler/ShHandle.h" />
+ <Unit filename="../compiler/ShaderLang.cpp" />
+ <Unit filename="../compiler/SymbolTable.cpp" />
+ <Unit filename="../compiler/SymbolTable.h" />
+ <Unit filename="../compiler/TranslatorASM.cpp" />
+ <Unit filename="../compiler/TranslatorASM.h" />
+ <Unit filename="../compiler/Types.h" />
+ <Unit filename="../compiler/ValidateLimitations.cpp" />
+ <Unit filename="../compiler/ValidateLimitations.h" />
+ <Unit filename="../compiler/debug.cpp" />
+ <Unit filename="../compiler/debug.h" />
+ <Unit filename="../compiler/glslang.h" />
+ <Unit filename="../compiler/glslang_lex.cpp" />
+ <Unit filename="../compiler/glslang_tab.cpp" />
+ <Unit filename="../compiler/glslang_tab.h" />
+ <Unit filename="../compiler/intermOut.cpp" />
+ <Unit filename="../compiler/intermediate.h" />
+ <Unit filename="../compiler/localintermediate.h" />
+ <Unit filename="../compiler/osinclude.h" />
+ <Unit filename="../compiler/ossource_posix.cpp" />
+ <Unit filename="../compiler/parseConst.cpp" />
+ <Unit filename="../compiler/preprocessor/Diagnostics.cpp" />
+ <Unit filename="../compiler/preprocessor/Diagnostics.h" />
+ <Unit filename="../compiler/preprocessor/DirectiveHandler.cpp" />
+ <Unit filename="../compiler/preprocessor/DirectiveHandler.h" />
+ <Unit filename="../compiler/preprocessor/DirectiveParser.cpp" />
+ <Unit filename="../compiler/preprocessor/DirectiveParser.h" />
+ <Unit filename="../compiler/preprocessor/ExpressionParser.cpp" />
+ <Unit filename="../compiler/preprocessor/ExpressionParser.h" />
+ <Unit filename="../compiler/preprocessor/Input.cpp" />
+ <Unit filename="../compiler/preprocessor/Input.h" />
+ <Unit filename="../compiler/preprocessor/Lexer.cpp" />
+ <Unit filename="../compiler/preprocessor/Lexer.h" />
+ <Unit filename="../compiler/preprocessor/Macro.cpp" />
+ <Unit filename="../compiler/preprocessor/Macro.h" />
+ <Unit filename="../compiler/preprocessor/MacroExpander.cpp" />
+ <Unit filename="../compiler/preprocessor/MacroExpander.h" />
+ <Unit filename="../compiler/preprocessor/Preprocessor.cpp" />
+ <Unit filename="../compiler/preprocessor/Preprocessor.h" />
+ <Unit filename="../compiler/preprocessor/SourceLocation.h" />
+ <Unit filename="../compiler/preprocessor/Token.cpp" />
+ <Unit filename="../compiler/preprocessor/Token.h" />
+ <Unit filename="../compiler/preprocessor/Tokenizer.cpp" />
+ <Unit filename="../compiler/preprocessor/Tokenizer.h" />
+ <Unit filename="../compiler/preprocessor/length_limits.h" />
+ <Unit filename="../compiler/preprocessor/numeric_lex.h" />
+ <Unit filename="../compiler/preprocessor/pp_utils.h" />
+ <Unit filename="../compiler/util.cpp" />
+ <Unit filename="../compiler/util.h" />
+ <Unit filename="./../include/EGL/egl.h" />
+ <Unit filename="./../include/EGL/eglext.h" />
+ <Unit filename="./../include/EGL/eglplatform.h" />
+ <Unit filename="./../include/GLES2/gl2.h" />
+ <Unit filename="./../include/GLES2/gl2ext.h" />
+ <Unit filename="./../include/GLES2/gl2platform.h" />
+ <Unit filename="./../include/GLSLANG/ShaderLang.h" />
+ <Unit filename="./../include/KHR/khrplatform.h" />
+ <Unit filename="./../libGLESv2/Buffer.cpp" />
+ <Unit filename="./../libGLESv2/Buffer.h" />
+ <Unit filename="./../libGLESv2/Context.cpp" />
+ <Unit filename="./../libGLESv2/Context.h" />
+ <Unit filename="./../libGLESv2/Device.cpp" />
+ <Unit filename="./../libGLESv2/Device.hpp" />
+ <Unit filename="./../libGLESv2/Fence.cpp" />
+ <Unit filename="./../libGLESv2/Fence.h" />
+ <Unit filename="./../libGLESv2/Framebuffer.cpp" />
+ <Unit filename="./../libGLESv2/Framebuffer.h" />
+ <Unit filename="./../libGLESv2/HandleAllocator.cpp" />
+ <Unit filename="./../libGLESv2/HandleAllocator.h" />
+ <Unit filename="./../libGLESv2/Image.cpp" />
+ <Unit filename="./../libGLESv2/Image.hpp" />
+ <Unit filename="./../libGLESv2/IndexDataManager.cpp" />
+ <Unit filename="./../libGLESv2/IndexDataManager.h" />
+ <Unit filename="./../libGLESv2/Program.cpp" />
+ <Unit filename="./../libGLESv2/Program.h" />
+ <Unit filename="./../libGLESv2/Query.cpp" />
+ <Unit filename="./../libGLESv2/Query.h" />
+ <Unit filename="./../libGLESv2/RefCountObject.cpp" />
+ <Unit filename="./../libGLESv2/RefCountObject.h" />
+ <Unit filename="./../libGLESv2/Renderbuffer.cpp" />
+ <Unit filename="./../libGLESv2/Renderbuffer.h" />
+ <Unit filename="./../libGLESv2/ResourceManager.cpp" />
+ <Unit filename="./../libGLESv2/ResourceManager.h" />
+ <Unit filename="./../libGLESv2/Shader.cpp" />
+ <Unit filename="./../libGLESv2/Shader.h" />
+ <Unit filename="./../libGLESv2/Texture.cpp" />
+ <Unit filename="./../libGLESv2/Texture.h" />
+ <Unit filename="./../libGLESv2/Unknown.hpp" />
+ <Unit filename="./../libGLESv2/VertexDataManager.cpp" />
+ <Unit filename="./../libGLESv2/VertexDataManager.h" />
+ <Unit filename="./../libGLESv2/libGLESv2.cpp" />
+ <Unit filename="./../libGLESv2/main.cpp" />
+ <Unit filename="./../libGLESv2/main.h" />
+ <Unit filename="./../libGLESv2/mathutil.h" />
+ <Unit filename="./../libGLESv2/resource.h" />
+ <Unit filename="./../libGLESv2/utilities.cpp" />
+ <Unit filename="./../libGLESv2/utilities.h" />
+ <Unit filename="./../libGLESv2/vertexconversion.h" />
+ <Unit filename="./../../Main/Config.cpp" />
+ <Unit filename="./../../Main/Config.hpp" />
+ <Unit filename="./../../Main/FrameBuffer.cpp" />
+ <Unit filename="./../../Main/FrameBuffer.hpp" />
+ <Unit filename="./../../Main/FrameBufferX11.cpp" />
+ <Unit filename="./../../Main/FrameBufferX11.hpp" />
+ <Unit filename="./../../Main/Logo.cpp" />
+ <Unit filename="./../../Main/Register.cpp" />
+ <Unit filename="./../../Main/Register.hpp" />
+ <Unit filename="./../../Main/SwiftConfig.cpp" />
+ <Unit filename="./../../Main/SwiftConfig.hpp" />
+ <Unit filename="./../../Main/crc.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="./../../Main/crc.h" />
+ <Unit filename="./../../Main/serialcommon.h" />
+ <Unit filename="./../../Main/serialvalid.cpp" />
+ <Unit filename="./../../Main/serialvalid.h" />
+ <Unit filename="./../../Reactor/Routine.cpp" />
+ <Unit filename="./../../Reactor/Routine.hpp" />
+ <Unit filename="./../../Reactor/RoutineManager.cpp" />
+ <Unit filename="./../../Reactor/RoutineManager.hpp" />
+ <Unit filename="./../../Reactor/Nucleus.cpp" />
+ <Unit filename="./../../Reactor/Nucleus.hpp" />
+ <Unit filename="./../../Reactor/Reactor.hpp" />
+ <Unit filename="./../../Reactor/x86.hpp" />
+ <Unit filename="./../../Renderer/Blitter.cpp" />
+ <Unit filename="./../../Renderer/Blitter.hpp" />
+ <Unit filename="./../../Renderer/Clipper.cpp" />
+ <Unit filename="./../../Renderer/Clipper.hpp" />
+ <Unit filename="./../../Renderer/Color.cpp" />
+ <Unit filename="./../../Renderer/Color.hpp" />
+ <Unit filename="./../../Renderer/Context.cpp" />
+ <Unit filename="./../../Renderer/Context.hpp" />
+ <Unit filename="./../../Renderer/LRUCache.hpp" />
+ <Unit filename="./../../Renderer/Matrix.cpp" />
+ <Unit filename="./../../Renderer/Matrix.hpp" />
+ <Unit filename="./../../Renderer/PixelProcessor.cpp" />
+ <Unit filename="./../../Renderer/PixelProcessor.hpp" />
+ <Unit filename="./../../Renderer/Plane.cpp" />
+ <Unit filename="./../../Renderer/Plane.hpp" />
+ <Unit filename="./../../Renderer/Point.cpp" />
+ <Unit filename="./../../Renderer/Point.hpp" />
+ <Unit filename="./../../Renderer/Polygon.hpp" />
+ <Unit filename="./../../Renderer/Primitive.hpp" />
+ <Unit filename="./../../Renderer/QuadRasterizer.cpp" />
+ <Unit filename="./../../Renderer/QuadRasterizer.hpp" />
+ <Unit filename="./../../Renderer/Rasterizer.cpp" />
+ <Unit filename="./../../Renderer/Rasterizer.hpp" />
+ <Unit filename="./../../Renderer/Renderer.cpp" />
+ <Unit filename="./../../Renderer/Renderer.hpp" />
+ <Unit filename="./../../Renderer/Sampler.cpp" />
+ <Unit filename="./../../Renderer/Sampler.hpp" />
+ <Unit filename="./../../Renderer/SetupProcessor.cpp" />
+ <Unit filename="./../../Renderer/SetupProcessor.hpp" />
+ <Unit filename="./../../Renderer/Stream.hpp" />
+ <Unit filename="./../../Renderer/Surface.cpp" />
+ <Unit filename="./../../Renderer/Surface.hpp" />
+ <Unit filename="./../../Renderer/TextureStage.cpp" />
+ <Unit filename="./../../Renderer/TextureStage.hpp" />
+ <Unit filename="./../../Renderer/Triangle.hpp" />
+ <Unit filename="./../../Renderer/Vector.cpp" />
+ <Unit filename="./../../Renderer/Vector.hpp" />
+ <Unit filename="./../../Renderer/Vertex.hpp" />
+ <Unit filename="./../../Renderer/VertexProcessor.cpp" />
+ <Unit filename="./../../Renderer/VertexProcessor.hpp" />
+ <Unit filename="./../../Shader/Constants.cpp" />
+ <Unit filename="./../../Shader/Constants.hpp" />
+ <Unit filename="./../../Shader/PixelRoutine.cpp" />
+ <Unit filename="./../../Shader/PixelRoutine.hpp" />
+ <Unit filename="./../../Shader/PixelShader.cpp" />
+ <Unit filename="./../../Shader/PixelShader.hpp" />
+ <Unit filename="./../../Shader/SamplerCore.cpp" />
+ <Unit filename="./../../Shader/SamplerCore.hpp" />
+ <Unit filename="./../../Shader/SetupRoutine.cpp" />
+ <Unit filename="./../../Shader/SetupRoutine.hpp" />
+ <Unit filename="./../../Shader/Shader.cpp" />
+ <Unit filename="./../../Shader/Shader.hpp" />
+ <Unit filename="./../../Shader/ShaderCore.cpp" />
+ <Unit filename="./../../Shader/ShaderCore.hpp" />
+ <Unit filename="./../../Shader/VertexPipeline.cpp" />
+ <Unit filename="./../../Shader/VertexPipeline.hpp" />
+ <Unit filename="./../../Shader/VertexProgram.cpp" />
+ <Unit filename="./../../Shader/VertexProgram.hpp" />
+ <Unit filename="./../../Shader/VertexRoutine.cpp" />
+ <Unit filename="./../../Shader/VertexRoutine.hpp" />
+ <Unit filename="./../../Shader/VertexShader.cpp" />
+ <Unit filename="./../../Shader/VertexShader.hpp" />
+ <Extensions>
+ <code_completion />
+ <debugger />
+ </Extensions>
+ </Project>
+</CodeBlocks_project_file>
diff --git a/src/GLES2/libGLES_CM/libGLESv2.cpp b/src/GLES2/libGLES_CM/libGLESv2.cpp
new file mode 100644
index 0000000..cde61ed
--- /dev/null
+++ b/src/GLES2/libGLES_CM/libGLESv2.cpp
@@ -0,0 +1,6214 @@
+// SwiftShader Software Renderer
+//
+// Copyright(c) 2005-2013 TransGaming Inc.
+//
+// All rights reserved. No part of this software may be copied, distributed, transmitted,
+// transcribed, stored in a retrieval system, translated into any human or computer
+// language by any means, or disclosed to third parties without the explicit written
+// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
+// or implied, including but not limited to any patent rights, are granted to you.
+//
+// libGLESv2.cpp: Implements the exported OpenGL ES 2.0 functions.
+
+#include "main.h"
+#include "mathutil.h"
+#include "utilities.h"
+#include "Buffer.h"
+#include "Context.h"
+#include "Fence.h"
+#include "Framebuffer.h"
+#include "Program.h"
+#include "Renderbuffer.h"
+#include "Shader.h"
+#include "Texture.h"
+#include "Query.h"
+#include "common/debug.h"
+#include "Common/Version.h"
+#include "Main/Register.hpp"
+
+#define GL_APICALL
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#include <exception>
+#include <limits>
+
+static bool validImageSize(GLint level, GLsizei width, GLsizei height)
+{
+ if(level < 0 || level >= gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS || width < 0 || height < 0)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+static bool validateSubImageParams(bool compressed, GLsizei width, GLsizei height, GLint xoffset, GLint yoffset, GLenum target, GLint level, GLenum format, gl::Texture *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 && format != texture->getFormat(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
+static bool validReadFormatType(GLenum format, GLenum type)
+{
+ switch(format)
+ {
+ case GL_RGBA:
+ switch (type)
+ {
+ case GL_UNSIGNED_BYTE:
+ break;
+ default:
+ return false;
+ }
+ break;
+ case GL_BGRA_EXT:
+ switch (type)
+ {
+ case GL_UNSIGNED_BYTE:
+ case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT:
+ case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT:
+ break;
+ default:
+ return false;
+ }
+ break;
+ case gl::IMPLEMENTATION_COLOR_READ_FORMAT:
+ switch (type)
+ {
+ case gl::IMPLEMENTATION_COLOR_READ_TYPE:
+ break;
+ default:
+ return false;
+ }
+ break;
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+extern "C"
+{
+
+void GL_APIENTRY glActiveTexture(GLenum texture)
+{
+ TRACE("(GLenum texture = 0x%X)", texture);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if(context)
+ {
+ if(texture < GL_TEXTURE0 || texture > GL_TEXTURE0 + gl::MAX_COMBINED_TEXTURE_IMAGE_UNITS - 1)
+ {
+ return error(GL_INVALID_ENUM);
+ }
+
+ context->setActiveSampler(texture - GL_TEXTURE0);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glAttachShader(GLuint program, GLuint shader)
+{
+ TRACE("(GLuint program = %d, GLuint shader = %d)", program, shader);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ 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 GL_APIENTRY glBeginQueryEXT(GLenum target, GLuint id)
+{
+ TRACE("(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::getContext();
+
+ if(context)
+ {
+ context->beginQuery(target, id);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glBindAttribLocation(GLuint program, GLuint index, const GLchar* name)
+{
+ TRACE("(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::getContext();
+
+ 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 GL_APIENTRY glBindBuffer(GLenum target, GLuint buffer)
+{
+ TRACE("(GLenum target = 0x%X, GLuint buffer = %d)", target, buffer);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ 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 GL_APIENTRY glBindFramebuffer(GLenum target, GLuint framebuffer)
+{
+ TRACE("(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::getContext();
+
+ 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 GL_APIENTRY glBindRenderbuffer(GLenum target, GLuint renderbuffer)
+{
+ TRACE("(GLenum target = 0x%X, GLuint renderbuffer = %d)", target, renderbuffer);
+
+ try
+ {
+ if(target != GL_RENDERBUFFER)
+ {
+ return error(GL_INVALID_ENUM);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if(context)
+ {
+ context->bindRenderbuffer(renderbuffer);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glBindTexture(GLenum target, GLuint texture)
+{
+ TRACE("(GLenum target = 0x%X, GLuint texture = %d)", target, texture);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ 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;
+ case GL_TEXTURE_EXTERNAL_OES:
+ context->bindTextureExternal(texture);
+ return;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glBlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
+{
+ TRACE("(GLclampf red = %f, GLclampf green = %f, GLclampf blue = %f, GLclampf alpha = %f)",
+ red, green, blue, alpha);
+
+ try
+ {
+ gl::Context* context = gl::getContext();
+
+ 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 GL_APIENTRY glBlendEquation(GLenum mode)
+{
+ glBlendEquationSeparate(mode, mode);
+}
+
+void GL_APIENTRY glBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha)
+{
+ TRACE("(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:
+ case GL_MIN_EXT:
+ case GL_MAX_EXT:
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+
+ switch(modeAlpha)
+ {
+ case GL_FUNC_ADD:
+ case GL_FUNC_SUBTRACT:
+ case GL_FUNC_REVERSE_SUBTRACT:
+ case GL_MIN_EXT:
+ case GL_MAX_EXT:
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if(context)
+ {
+ context->setBlendEquation(modeRGB, modeAlpha);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glBlendFunc(GLenum sfactor, GLenum dfactor)
+{
+ glBlendFuncSeparate(sfactor, dfactor, sfactor, dfactor);
+}
+
+void GL_APIENTRY glBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha)
+{
+ TRACE("(GLenum srcRGB = 0x%X, GLenum dstRGB = 0x%X, GLenum srcAlpha = 0x%X, GLenum dstAlpha = 0x%X)",
+ 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);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if(context)
+ {
+ context->setBlendFactors(srcRGB, dstRGB, srcAlpha, dstAlpha);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage)
+{
+ TRACE("(GLenum target = 0x%X, GLsizeiptr size = %d, const GLvoid* data = 0x%0.8p, GLenum usage = %d)",
+ 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::getContext();
+
+ 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 GL_APIENTRY glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data)
+{
+ TRACE("(GLenum target = 0x%X, GLintptr offset = %d, GLsizeiptr size = %d, const GLvoid* data = 0x%0.8p)",
+ target, offset, size, data);
+
+ try
+ {
+ if(size < 0 || offset < 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ if(data == NULL)
+ {
+ return;
+ }
+
+ gl::Context *context = gl::getContext();
+
+ 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 GL_APIENTRY glCheckFramebufferStatus(GLenum target)
+{
+ TRACE("(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::getContext();
+
+ 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 GL_APIENTRY glClear(GLbitfield mask)
+{
+ TRACE("(GLbitfield mask = %X)", mask);
+
+ try
+ {
+ if((mask & ~(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) != 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if(context)
+ {
+ context->clear(mask);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
+{
+ TRACE("(GLclampf red = %f, GLclampf green = %f, GLclampf blue = %f, GLclampf alpha = %f)",
+ red, green, blue, alpha);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if(context)
+ {
+ context->setClearColor(red, green, blue, alpha);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glClearDepthf(GLclampf depth)
+{
+ TRACE("(GLclampf depth = %f)", depth);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if(context)
+ {
+ context->setClearDepth(depth);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glClearStencil(GLint s)
+{
+ TRACE("(GLint s = %d)", s);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if(context)
+ {
+ context->setClearStencil(s);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha)
+{
+ TRACE("(GLboolean red = %d, GLboolean green = %d, GLboolean blue = %d, GLboolean alpha = %d)",
+ red, green, blue, alpha);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ 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 GL_APIENTRY glCompileShader(GLuint shader)
+{
+ TRACE("(GLuint shader = %d)", shader);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ 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 GL_APIENTRY glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height,
+ GLint border, GLsizei imageSize, const GLvoid* data)
+{
+ TRACE("(GLenum target = 0x%X, GLint level = %d, GLenum internalformat = 0x%X, GLsizei width = %d, "
+ "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:
+ if(!S3TC_SUPPORT)
+ {
+ 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:
+ return error(GL_INVALID_OPERATION);
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+
+ if(border != 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if(context)
+ {
+ if(level > gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ switch(target)
+ {
+ case GL_TEXTURE_2D:
+ if(width > (gl::IMPLEMENTATION_MAX_TEXTURE_SIZE >> level) ||
+ height > (gl::IMPLEMENTATION_MAX_TEXTURE_SIZE >> 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 > (gl::IMPLEMENTATION_MAX_CUBE_MAP_TEXTURE_SIZE >> level) ||
+ height > (gl::IMPLEMENTATION_MAX_CUBE_MAP_TEXTURE_SIZE >> level))
+ {
+ return error(GL_INVALID_VALUE);
+ }
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+
+ 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);
+ }
+
+ texture->setCompressedImage(level, internalformat, width, height, imageSize, data);
+ }
+ else
+ {
+ gl::TextureCubeMap *texture = context->getTextureCubeMap();
+
+ if(!texture)
+ {
+ 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 GL_APIENTRY glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ GLenum format, GLsizei imageSize, const GLvoid* data)
+{
+ TRACE("(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, "
+ "GLsizei width = %d, GLsizei height = %d, GLenum format = 0x%X, "
+ "GLsizei imageSize = %d, const GLvoid* data = 0x%0.8p)",
+ target, level, xoffset, yoffset, width, height, format, imageSize, data);
+
+ try
+ {
+ if(!gl::IsTextureTarget(target))
+ {
+ 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:
+ if(!S3TC_SUPPORT)
+ {
+ return error(GL_INVALID_ENUM);
+ }
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+
+ if(width == 0 || height == 0 || data == NULL)
+ {
+ return;
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if(context)
+ {
+ if(level > gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ if(imageSize != gl::ComputeCompressedSize(width, height, format))
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ if(xoffset % 4 != 0 || yoffset % 4 != 0)
+ {
+ // We wait to check the offsets until this point, because the multiple-of-four restriction does not exist unless DXT1 textures are supported
+ return error(GL_INVALID_OPERATION);
+ }
+
+ if(target == GL_TEXTURE_2D)
+ {
+ gl::Texture2D *texture = context->getTexture2D();
+
+ if(validateSubImageParams(true, width, height, xoffset, yoffset, target, level, format, texture))
+ {
+ texture->subImageCompressed(level, xoffset, yoffset, width, height, format, imageSize, data);
+ }
+ }
+ else if(gl::IsCubemapTextureTarget(target))
+ {
+ gl::TextureCubeMap *texture = context->getTextureCubeMap();
+
+ if(validateSubImageParams(true, width, height, xoffset, yoffset, target, level, format, 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 GL_APIENTRY glCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border)
+{
+ TRACE("(GLenum target = 0x%X, GLint level = %d, GLenum internalformat = 0x%X, "
+ "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::getContext();
+
+ if(context)
+ {
+ switch(target)
+ {
+ case GL_TEXTURE_2D:
+ if(width > (gl::IMPLEMENTATION_MAX_TEXTURE_SIZE >> level) ||
+ height > (gl::IMPLEMENTATION_MAX_TEXTURE_SIZE >> 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 > (gl::IMPLEMENTATION_MAX_CUBE_MAP_TEXTURE_SIZE >> level) ||
+ height > (gl::IMPLEMENTATION_MAX_CUBE_MAP_TEXTURE_SIZE >> 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() > 1)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ gl::Renderbuffer *source = framebuffer->getColorbuffer();
+ GLenum colorbufferFormat = source->getFormat();
+
+ // [OpenGL ES 2.0.24] table 3.9
+ switch(internalformat)
+ {
+ case GL_ALPHA:
+ if(colorbufferFormat != GL_ALPHA &&
+ colorbufferFormat != GL_RGBA &&
+ 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_RGB &&
+ colorbufferFormat != GL_RGB565 &&
+ colorbufferFormat != GL_RGB8_OES &&
+ colorbufferFormat != GL_RGBA &&
+ 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_RGBA &&
+ 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:
+ if(S3TC_SUPPORT)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+ else
+ {
+ return error(GL_INVALID_ENUM);
+ }
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+
+ if(target == GL_TEXTURE_2D)
+ {
+ gl::Texture2D *texture = context->getTexture2D();
+
+ if(!texture)
+ {
+ 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);
+ }
+
+ texture->copyImage(target, level, internalformat, x, y, width, height, framebuffer);
+ }
+ else UNREACHABLE();
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height)
+{
+ TRACE("(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, "
+ "GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d)",
+ target, level, xoffset, yoffset, x, y, width, height);
+
+ try
+ {
+ if(!gl::IsTextureTarget(target))
+ {
+ 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::getContext();
+
+ if(context)
+ {
+ if(level > gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
+ {
+ 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() > 1)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ gl::Renderbuffer *source = framebuffer->getColorbuffer();
+ GLenum colorbufferFormat = source->getFormat();
+ gl::Texture *texture = NULL;
+
+ if(target == GL_TEXTURE_2D)
+ {
+ texture = context->getTexture2D();
+ }
+ else if(gl::IsCubemapTextureTarget(target))
+ {
+ texture = context->getTextureCubeMap();
+ }
+ else UNREACHABLE();
+
+ if(!validateSubImageParams(false, width, height, xoffset, yoffset, target, level, GL_NONE, texture))
+ {
+ return;
+ }
+
+ GLenum textureFormat = texture->getFormat(target, level);
+
+ // [OpenGL ES 2.0.24] table 3.9
+ switch(textureFormat)
+ {
+ case GL_ALPHA:
+ if(colorbufferFormat != GL_ALPHA &&
+ colorbufferFormat != GL_RGBA &&
+ 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_RGB &&
+ colorbufferFormat != GL_RGB565 &&
+ colorbufferFormat != GL_RGB8_OES &&
+ colorbufferFormat != GL_RGBA &&
+ 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_RGBA &&
+ 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 GL_APIENTRY glCreateProgram(void)
+{
+ TRACE("()");
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if(context)
+ {
+ return context->createProgram();
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY, 0);
+ }
+
+ return 0;
+}
+
+GLuint GL_APIENTRY glCreateShader(GLenum type)
+{
+ TRACE("(GLenum type = 0x%X)", type);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ 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 GL_APIENTRY glCullFace(GLenum mode)
+{
+ TRACE("(GLenum mode = 0x%X)", mode);
+
+ try
+ {
+ switch(mode)
+ {
+ case GL_FRONT:
+ case GL_BACK:
+ case GL_FRONT_AND_BACK:
+ {
+ gl::Context *context = gl::getContext();
+
+ if(context)
+ {
+ context->setCullMode(mode);
+ }
+ }
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glDeleteBuffers(GLsizei n, const GLuint* buffers)
+{
+ TRACE("(GLsizei n = %d, const GLuint* buffers = 0x%0.8p)", n, buffers);
+
+ try
+ {
+ if(n < 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if(context)
+ {
+ for(int i = 0; i < n; i++)
+ {
+ context->deleteBuffer(buffers[i]);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glDeleteFencesNV(GLsizei n, const GLuint* fences)
+{
+ TRACE("(GLsizei n = %d, const GLuint* fences = 0x%0.8p)", n, fences);
+
+ try
+ {
+ if(n < 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if(context)
+ {
+ for(int i = 0; i < n; i++)
+ {
+ context->deleteFence(fences[i]);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glDeleteFramebuffers(GLsizei n, const GLuint* framebuffers)
+{
+ TRACE("(GLsizei n = %d, const GLuint* framebuffers = 0x%0.8p)", n, framebuffers);
+
+ try
+ {
+ if(n < 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ 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 GL_APIENTRY glDeleteProgram(GLuint program)
+{
+ TRACE("(GLuint program = %d)", program);
+
+ try
+ {
+ if(program == 0)
+ {
+ return;
+ }
+
+ gl::Context *context = gl::getContext();
+
+ 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 GL_APIENTRY glDeleteQueriesEXT(GLsizei n, const GLuint *ids)
+{
+ TRACE("(GLsizei n = %d, const GLuint *ids = 0x%0.8p)", n, ids);
+
+ try
+ {
+ if(n < 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if(context)
+ {
+ for(int i = 0; i < n; i++)
+ {
+ context->deleteQuery(ids[i]);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glDeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers)
+{
+ TRACE("(GLsizei n = %d, const GLuint* renderbuffers = 0x%0.8p)", n, renderbuffers);
+
+ try
+ {
+ if(n < 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if(context)
+ {
+ for(int i = 0; i < n; i++)
+ {
+ context->deleteRenderbuffer(renderbuffers[i]);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glDeleteShader(GLuint shader)
+{
+ TRACE("(GLuint shader = %d)", shader);
+
+ try
+ {
+ if(shader == 0)
+ {
+ return;
+ }
+
+ gl::Context *context = gl::getContext();
+
+ 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 GL_APIENTRY glDeleteTextures(GLsizei n, const GLuint* textures)
+{
+ TRACE("(GLsizei n = %d, const GLuint* textures = 0x%0.8p)", n, textures);
+
+ try
+ {
+ if(n < 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ 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 GL_APIENTRY glDepthFunc(GLenum func)
+{
+ TRACE("(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::getContext();
+
+ if(context)
+ {
+ context->setDepthFunc(func);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glDepthMask(GLboolean flag)
+{
+ TRACE("(GLboolean flag = %d)", flag);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if(context)
+ {
+ context->setDepthMask(flag != GL_FALSE);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glDepthRangef(GLclampf zNear, GLclampf zFar)
+{
+ TRACE("(GLclampf zNear = %f, GLclampf zFar = %f)", zNear, zFar);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if(context)
+ {
+ context->setDepthRange(zNear, zFar);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glDetachShader(GLuint program, GLuint shader)
+{
+ TRACE("(GLuint program = %d, GLuint shader = %d)", program, shader);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ 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 GL_APIENTRY glDisable(GLenum cap)
+{
+ TRACE("(GLenum cap = 0x%X)", cap);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ 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 GL_APIENTRY glDisableVertexAttribArray(GLuint index)
+{
+ TRACE("(GLuint index = %d)", index);
+
+ try
+ {
+ if(index >= gl::MAX_VERTEX_ATTRIBS)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if(context)
+ {
+ context->setEnableVertexAttribArray(index, false);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glDrawArrays(GLenum mode, GLint first, GLsizei count)
+{
+ TRACE("(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::getContext();
+
+ if(context)
+ {
+ context->drawArrays(mode, first, count);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices)
+{
+ TRACE("(GLenum mode = 0x%X, GLsizei count = %d, GLenum type = 0x%X, const GLvoid* indices = 0x%0.8p)",
+ mode, count, type, indices);
+
+ try
+ {
+ if(count < 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if(context)
+ {
+ switch(type)
+ {
+ case GL_UNSIGNED_BYTE:
+ case GL_UNSIGNED_SHORT:
+ case GL_UNSIGNED_INT:
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+
+ context->drawElements(mode, count, type, indices);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glEnable(GLenum cap)
+{
+ TRACE("(GLenum cap = 0x%X)", cap);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ 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 GL_APIENTRY glEnableVertexAttribArray(GLuint index)
+{
+ TRACE("(GLuint index = %d)", index);
+
+ try
+ {
+ if(index >= gl::MAX_VERTEX_ATTRIBS)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if(context)
+ {
+ context->setEnableVertexAttribArray(index, true);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glEndQueryEXT(GLenum target)
+{
+ TRACE("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::getContext();
+
+ if(context)
+ {
+ context->endQuery(target);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glFinishFenceNV(GLuint fence)
+{
+ TRACE("(GLuint fence = %d)", fence);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ 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 GL_APIENTRY glFinish(void)
+{
+ TRACE("()");
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if(context)
+ {
+ context->finish();
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glFlush(void)
+{
+ TRACE("()");
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if(context)
+ {
+ context->flush();
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)
+{
+ TRACE("(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::getContext();
+
+ 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 GL_APIENTRY glFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)
+{
+ TRACE("(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::getContext();
+
+ if(context)
+ {
+ if(texture == 0)
+ {
+ textarget = GL_NONE;
+ }
+ else
+ {
+ gl::Texture *tex = context->getTexture(texture);
+
+ if(tex == NULL)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ if(tex->isCompressed(textarget, level))
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ switch(textarget)
+ {
+ case GL_TEXTURE_2D:
+ if(tex->getTarget() != GL_TEXTURE_2D)
+ {
+ 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);
+ }
+ 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 GL_APIENTRY glFrontFace(GLenum mode)
+{
+ TRACE("(GLenum mode = 0x%X)", mode);
+
+ try
+ {
+ switch(mode)
+ {
+ case GL_CW:
+ case GL_CCW:
+ {
+ gl::Context *context = gl::getContext();
+
+ if(context)
+ {
+ context->setFrontFace(mode);
+ }
+ }
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glGenBuffers(GLsizei n, GLuint* buffers)
+{
+ TRACE("(GLsizei n = %d, GLuint* buffers = 0x%0.8p)", n, buffers);
+
+ try
+ {
+ if(n < 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if(context)
+ {
+ for(int i = 0; i < n; i++)
+ {
+ buffers[i] = context->createBuffer();
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glGenerateMipmap(GLenum target)
+{
+ TRACE("(GLenum target = 0x%X)", target);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ 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);
+ }
+
+ if(texture->isCompressed(target, 0) || texture->isDepth(target, 0))
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ texture->generateMipmaps();
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glGenFencesNV(GLsizei n, GLuint* fences)
+{
+ TRACE("(GLsizei n = %d, GLuint* fences = 0x%0.8p)", n, fences);
+
+ try
+ {
+ if(n < 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if(context)
+ {
+ for(int i = 0; i < n; i++)
+ {
+ fences[i] = context->createFence();
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glGenFramebuffers(GLsizei n, GLuint* framebuffers)
+{
+ TRACE("(GLsizei n = %d, GLuint* framebuffers = 0x%0.8p)", n, framebuffers);
+
+ try
+ {
+ if(n < 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if(context)
+ {
+ for(int i = 0; i < n; i++)
+ {
+ framebuffers[i] = context->createFramebuffer();
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glGenQueriesEXT(GLsizei n, GLuint* ids)
+{
+ TRACE("(GLsizei n = %d, GLuint* ids = 0x%0.8p)", n, ids);
+
+ try
+ {
+ if(n < 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if(context)
+ {
+ for(int i = 0; i < n; i++)
+ {
+ ids[i] = context->createQuery();
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glGenRenderbuffers(GLsizei n, GLuint* renderbuffers)
+{
+ TRACE("(GLsizei n = %d, GLuint* renderbuffers = 0x%0.8p)", n, renderbuffers);
+
+ try
+ {
+ if(n < 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if(context)
+ {
+ for(int i = 0; i < n; i++)
+ {
+ renderbuffers[i] = context->createRenderbuffer();
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glGenTextures(GLsizei n, GLuint* textures)
+{
+ TRACE("(GLsizei n = %d, GLuint* textures = 0x%0.8p)", n, textures);
+
+ try
+ {
+ if(n < 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if(context)
+ {
+ for(int i = 0; i < n; i++)
+ {
+ textures[i] = context->createTexture();
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glGetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
+{
+ TRACE("(GLuint program = %d, GLuint index = %d, GLsizei bufsize = %d, GLsizei *length = 0x%0.8p, "
+ "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::getContext();
+
+ 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 GL_APIENTRY glGetActiveUniform(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name)
+{
+ TRACE("(GLuint program = %d, GLuint index = %d, GLsizei bufsize = %d, "
+ "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::getContext();
+
+ 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 GL_APIENTRY glGetAttachedShaders(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders)
+{
+ TRACE("(GLuint program = %d, GLsizei maxcount = %d, GLsizei* count = 0x%0.8p, GLuint* shaders = 0x%0.8p)",
+ program, maxcount, count, shaders);
+
+ try
+ {
+ if(maxcount < 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ 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 GL_APIENTRY glGetAttribLocation(GLuint program, const GLchar* name)
+{
+ TRACE("(GLuint program = %d, const GLchar* name = %s)", program, name);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ 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);
+ }
+ }
+
+ if(!programObject->isLinked())
+ {
+ return error(GL_INVALID_OPERATION, -1);
+ }
+
+ return programObject->getAttributeLocation(name);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY, -1);
+ }
+
+ return -1;
+}
+
+void GL_APIENTRY glGetBooleanv(GLenum pname, GLboolean* params)
+{
+ TRACE("(GLenum pname = 0x%X, GLboolean* params = 0x%0.8p)", pname, params);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ 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 GL_APIENTRY glGetBufferParameteriv(GLenum target, GLenum pname, GLint* params)
+{
+ TRACE("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", target, pname, params);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ 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 GL_APIENTRY glGetError(void)
+{
+ TRACE("()");
+
+ gl::Context *context = gl::getContext();
+
+ if(context)
+ {
+ return context->getError();
+ }
+
+ return GL_NO_ERROR;
+}
+
+void GL_APIENTRY glGetFenceivNV(GLuint fence, GLenum pname, GLint *params)
+{
+ TRACE("(GLuint fence = %d, GLenum pname = 0x%X, GLint *params = 0x%0.8p)", fence, pname, params);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ 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 GL_APIENTRY glGetFloatv(GLenum pname, GLfloat* params)
+{
+ TRACE("(GLenum pname = 0x%X, GLfloat* params = 0x%0.8p)", pname, params);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ 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 GL_APIENTRY glGetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint* params)
+{
+ TRACE("(GLenum target = 0x%X, GLenum attachment = 0x%X, GLenum pname = 0x%X, GLint* params = 0x%0.8p)",
+ target, attachment, pname, params);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ 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::IsTextureTarget(attachmentType))
+ {
+ attachmentObjectType = GL_TEXTURE;
+ }
+ else UNREACHABLE();
+
+ 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 GL_APIENTRY glGetGraphicsResetStatusEXT(void)
+{
+ TRACE("()");
+
+ return GL_NO_ERROR;
+}
+
+void GL_APIENTRY glGetIntegerv(GLenum pname, GLint* params)
+{
+ TRACE("(GLenum pname = 0x%X, GLint* params = 0x%0.8p)", pname, params);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ 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 GL_APIENTRY glGetProgramiv(GLuint program, GLenum pname, GLint* params)
+{
+ TRACE("(GLuint program = %d, GLenum pname = %d, GLint* params = 0x%0.8p)", program, pname, params);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ 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;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glGetProgramInfoLog(GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog)
+{
+ TRACE("(GLuint program = %d, GLsizei bufsize = %d, GLsizei* length = 0x%0.8p, GLchar* infolog = 0x%0.8p)",
+ program, bufsize, length, infolog);
+
+ try
+ {
+ if(bufsize < 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ 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 GL_APIENTRY glGetQueryivEXT(GLenum target, GLenum pname, GLint *params)
+{
+ TRACE("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::getContext();
+
+ if(context)
+ {
+ params[0] = context->getActiveQuery(target);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glGetQueryObjectuivEXT(GLuint id, GLenum pname, GLuint *params)
+{
+ TRACE("(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::getContext();
+
+ 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 GL_APIENTRY glGetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params)
+{
+ TRACE("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", target, pname, params);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ 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->getFormat(); 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: *params = renderbuffer->getSamples(); break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glGetShaderiv(GLuint shader, GLenum pname, GLint* params)
+{
+ TRACE("(GLuint shader = %d, GLenum pname = %d, GLint* params = 0x%0.8p)", shader, pname, params);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ 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;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glGetShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog)
+{
+ TRACE("(GLuint shader = %d, GLsizei bufsize = %d, GLsizei* length = 0x%0.8p, GLchar* infolog = 0x%0.8p)",
+ shader, bufsize, length, infolog);
+
+ try
+ {
+ if(bufsize < 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ 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 GL_APIENTRY glGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision)
+{
+ TRACE("(GLenum shadertype = 0x%X, GLenum precisiontype = 0x%X, GLint* range = 0x%0.8p, GLint* precision = 0x%0.8p)",
+ 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:
+ // IEEE 754 single-precision
+ range[0] = 127;
+ range[1] = 127;
+ *precision = 23;
+ break;
+ case GL_LOW_INT:
+ case GL_MEDIUM_INT:
+ case GL_HIGH_INT:
+ // Single-precision floating-point numbers 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 GL_APIENTRY glGetShaderSource(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source)
+{
+ TRACE("(GLuint shader = %d, GLsizei bufsize = %d, GLsizei* length = 0x%0.8p, GLchar* source = 0x%0.8p)",
+ shader, bufsize, length, source);
+
+ try
+ {
+ if(bufsize < 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ 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);
+ }
+}
+
+const GLubyte* GL_APIENTRY glGetString(GLenum name)
+{
+ TRACE("(GLenum name = 0x%X)", name);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ switch(name)
+ {
+ case GL_VENDOR:
+ return (GLubyte*)"TransGaming Inc.";
+ case GL_RENDERER:
+ return (GLubyte*)"SwiftShader";
+ case GL_VERSION:
+ return (GLubyte*)"OpenGL ES 2.0 SwiftShader "VERSION_STRING;
+ case GL_SHADING_LANGUAGE_VERSION:
+ return (GLubyte*)"OpenGL ES GLSL ES 1.00 SwiftShader "VERSION_STRING;
+ case GL_EXTENSIONS:
+ // Keep list sorted in following order:
+ // OES extensions
+ // EXT extensions
+ // Vendor extensions
+ return (GLubyte*)
+ "GL_OES_depth_texture "
+ "GL_OES_depth_texture_cube_map "
+ "GL_OES_EGL_image_external "
+ "GL_OES_element_index_uint "
+ "GL_OES_packed_depth_stencil "
+ "GL_OES_rgb8_rgba8 "
+ "GL_OES_standard_derivatives "
+ "GL_OES_texture_float "
+ "GL_OES_texture_float_linear "
+ "GL_OES_texture_half_float "
+ "GL_OES_texture_half_float_linear "
+ "GL_OES_texture_npot "
+ "GL_EXT_blend_minmax "
+ "GL_EXT_occlusion_query_boolean "
+ "GL_EXT_read_format_bgra "
+ #if (S3TC_SUPPORT)
+ "GL_EXT_texture_compression_dxt1 "
+ "GL_ANGLE_texture_compression_dxt3 "
+ "GL_ANGLE_texture_compression_dxt5 "
+ #endif
+ "GL_EXT_texture_filter_anisotropic "
+ "GL_EXT_texture_format_BGRA8888 "
+ "GL_ANGLE_framebuffer_blit "
+ "GL_ANGLE_framebuffer_multisample "
+ "GL_NV_fence";
+ default:
+ return error(GL_INVALID_ENUM, (GLubyte*)NULL);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY, (GLubyte*)NULL);
+ }
+
+ return NULL;
+}
+
+void GL_APIENTRY glGetTexParameterfv(GLenum target, GLenum pname, GLfloat* params)
+{
+ TRACE("(GLenum target = 0x%X, GLenum pname = 0x%X, GLfloat* params = 0x%0.8p)", target, pname, params);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if(context)
+ {
+ gl::Texture *texture;
+
+ switch(target)
+ {
+ case GL_TEXTURE_2D:
+ texture = context->getTexture2D();
+ break;
+ case GL_TEXTURE_CUBE_MAP:
+ texture = context->getTextureCubeMap();
+ break;
+ case GL_TEXTURE_EXTERNAL_OES:
+ texture = context->getTextureExternal();
+ 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_MAX_ANISOTROPY_EXT:
+ *params = texture->getMaxAnisotropy();
+ break;
+ case GL_REQUIRED_TEXTURE_IMAGE_UNITS_OES:
+ *params = (GLfloat)1;
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glGetTexParameteriv(GLenum target, GLenum pname, GLint* params)
+{
+ TRACE("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", target, pname, params);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if(context)
+ {
+ gl::Texture *texture;
+
+ switch(target)
+ {
+ case GL_TEXTURE_2D:
+ texture = context->getTexture2D();
+ break;
+ case GL_TEXTURE_CUBE_MAP:
+ texture = context->getTextureCubeMap();
+ break;
+ case GL_TEXTURE_EXTERNAL_OES:
+ texture = context->getTextureExternal();
+ 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_MAX_ANISOTROPY_EXT:
+ *params = (GLint)texture->getMaxAnisotropy();
+ break;
+ case GL_REQUIRED_TEXTURE_IMAGE_UNITS_OES:
+ *params = 1;
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glGetnUniformfvEXT(GLuint program, GLint location, GLsizei bufSize, GLfloat* params)
+{
+ TRACE("(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::getContext();
+
+ if(context)
+ {
+ if(program == 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Program *programObject = context->getProgram(program);
+
+ if(!programObject || !programObject->isLinked())
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ if(!programObject->getUniformfv(location, &bufSize, params))
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glGetUniformfv(GLuint program, GLint location, GLfloat* params)
+{
+ TRACE("(GLuint program = %d, GLint location = %d, GLfloat* params = 0x%0.8p)", program, location, params);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if(context)
+ {
+ if(program == 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Program *programObject = context->getProgram(program);
+
+ if(!programObject || !programObject->isLinked())
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ if(!programObject->getUniformfv(location, NULL, params))
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glGetnUniformivEXT(GLuint program, GLint location, GLsizei bufSize, GLint* params)
+{
+ TRACE("(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::getContext();
+
+ if(context)
+ {
+ if(program == 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Program *programObject = context->getProgram(program);
+
+ if(!programObject || !programObject->isLinked())
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ if(!programObject)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ if(!programObject->getUniformiv(location, &bufSize, params))
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glGetUniformiv(GLuint program, GLint location, GLint* params)
+{
+ TRACE("(GLuint program = %d, GLint location = %d, GLint* params = 0x%0.8p)", program, location, params);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if(context)
+ {
+ if(program == 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Program *programObject = context->getProgram(program);
+
+ if(!programObject || !programObject->isLinked())
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ if(!programObject)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ if(!programObject->getUniformiv(location, NULL, params))
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+int GL_APIENTRY glGetUniformLocation(GLuint program, const GLchar* name)
+{
+ TRACE("(GLuint program = %d, const GLchar* name = 0x%0.8p)", program, name);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ 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);
+ }
+ }
+
+ if(!programObject->isLinked())
+ {
+ return error(GL_INVALID_OPERATION, -1);
+ }
+
+ return programObject->getUniformLocation(name);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY, -1);
+ }
+
+ return -1;
+}
+
+void GL_APIENTRY glGetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params)
+{
+ TRACE("(GLuint index = %d, GLenum pname = 0x%X, GLfloat* params = 0x%0.8p)", index, pname, params);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ 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;
+ default: return error(GL_INVALID_ENUM);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glGetVertexAttribiv(GLuint index, GLenum pname, GLint* params)
+{
+ TRACE("(GLuint index = %d, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", index, pname, params);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ 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;
+ default: return error(GL_INVALID_ENUM);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glGetVertexAttribPointerv(GLuint index, GLenum pname, GLvoid** pointer)
+{
+ TRACE("(GLuint index = %d, GLenum pname = 0x%X, GLvoid** pointer = 0x%0.8p)", index, pname, pointer);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ 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 GL_APIENTRY glHint(GLenum target, GLenum mode)
+{
+ TRACE("(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::getContext();
+ 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 GL_APIENTRY glIsBuffer(GLuint buffer)
+{
+ TRACE("(GLuint buffer = %d)", buffer);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ 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 GL_APIENTRY glIsEnabled(GLenum cap)
+{
+ TRACE("(GLenum cap = 0x%X)", cap);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ 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 GL_APIENTRY glIsFenceNV(GLuint fence)
+{
+ TRACE("(GLuint fence = %d)", fence);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ 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 GL_APIENTRY glIsFramebuffer(GLuint framebuffer)
+{
+ TRACE("(GLuint framebuffer = %d)", framebuffer);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ 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 GL_APIENTRY glIsProgram(GLuint program)
+{
+ TRACE("(GLuint program = %d)", program);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ 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 GL_APIENTRY glIsQueryEXT(GLuint id)
+{
+ TRACE("(GLuint id = %d)", id);
+
+ try
+ {
+ if(id == 0)
+ {
+ return GL_FALSE;
+ }
+
+ gl::Context *context = gl::getContext();
+
+ 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 GL_APIENTRY glIsRenderbuffer(GLuint renderbuffer)
+{
+ TRACE("(GLuint renderbuffer = %d)", renderbuffer);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ 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 GL_APIENTRY glIsShader(GLuint shader)
+{
+ TRACE("(GLuint shader = %d)", shader);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ 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 GL_APIENTRY glIsTexture(GLuint texture)
+{
+ TRACE("(GLuint texture = %d)", texture);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ 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 GL_APIENTRY glLineWidth(GLfloat width)
+{
+ TRACE("(GLfloat width = %f)", width);
+
+ try
+ {
+ if(width <= 0.0f)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if(context)
+ {
+ context->setLineWidth(width);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glLinkProgram(GLuint program)
+{
+ TRACE("(GLuint program = %d)", program);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ 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->link();
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glPixelStorei(GLenum pname, GLint param)
+{
+ TRACE("(GLenum pname = 0x%X, GLint param = %d)", pname, param);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ 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;
+
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glPolygonOffset(GLfloat factor, GLfloat units)
+{
+ TRACE("(GLfloat factor = %f, GLfloat units = %f)", factor, units);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if(context)
+ {
+ context->setPolygonOffsetParams(factor, units);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glReadnPixelsEXT(GLint x, GLint y, GLsizei width, GLsizei height,
+ GLenum format, GLenum type, GLsizei bufSize,
+ GLvoid *data)
+{
+ TRACE("(GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d, "
+ "GLenum format = 0x%X, GLenum type = 0x%X, GLsizei bufSize = 0x%d, GLvoid *data = 0x%0.8p)",
+ x, y, width, height, format, type, bufSize, data);
+
+ try
+ {
+ if(width < 0 || height < 0 || bufSize < 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ if(!validReadFormatType(format, type))
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if(context)
+ {
+ context->readPixels(x, y, width, height, format, type, &bufSize, data);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels)
+{
+ TRACE("(GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d, "
+ "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);
+ }
+
+ if(!validReadFormatType(format, type))
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if(context)
+ {
+ context->readPixels(x, y, width, height, format, type, NULL, pixels);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glReleaseShaderCompiler(void)
+{
+ TRACE("()");
+
+ try
+ {
+ gl::Shader::releaseCompiler();
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glRenderbufferStorageMultisampleANGLE(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height)
+{
+ TRACE("(GLenum target = 0x%X, GLsizei samples = %d, GLenum internalformat = 0x%X, GLsizei width = %d, GLsizei height = %d)",
+ 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::getContext();
+
+ if(context)
+ {
+ if(width > gl::IMPLEMENTATION_MAX_RENDERBUFFER_SIZE ||
+ height > gl::IMPLEMENTATION_MAX_RENDERBUFFER_SIZE ||
+ samples > gl::IMPLEMENTATION_MAX_SAMPLES)
+ {
+ 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 GL_APIENTRY glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height)
+{
+ glRenderbufferStorageMultisampleANGLE(target, 0, internalformat, width, height);
+}
+
+void GL_APIENTRY glSampleCoverage(GLclampf value, GLboolean invert)
+{
+ TRACE("(GLclampf value = %f, GLboolean invert = %d)", value, invert);
+
+ try
+ {
+ gl::Context* context = gl::getContext();
+
+ if(context)
+ {
+ context->setSampleCoverageParams(gl::clamp01(value), invert == GL_TRUE);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glSetFenceNV(GLuint fence, GLenum condition)
+{
+ TRACE("(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::getContext();
+
+ 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 GL_APIENTRY glScissor(GLint x, GLint y, GLsizei width, GLsizei height)
+{
+ TRACE("(GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d)", x, y, width, height);
+
+ try
+ {
+ if(width < 0 || height < 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Context* context = gl::getContext();
+
+ if(context)
+ {
+ context->setScissorParams(x, y, width, height);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glShaderBinary(GLsizei n, const GLuint* shaders, GLenum binaryformat, const GLvoid* binary, GLsizei length)
+{
+ TRACE("(GLsizei n = %d, const GLuint* shaders = 0x%0.8p, GLenum binaryformat = 0x%X, "
+ "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 GL_APIENTRY glShaderSource(GLuint shader, GLsizei count, const GLchar** string, const GLint* length)
+{
+ TRACE("(GLuint shader = %d, GLsizei count = %d, const GLchar** string = 0x%0.8p, const GLint* length = 0x%0.8p)",
+ shader, count, string, length);
+
+ try
+ {
+ if(count < 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ 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 GL_APIENTRY glStencilFunc(GLenum func, GLint ref, GLuint mask)
+{
+ glStencilFuncSeparate(GL_FRONT_AND_BACK, func, ref, mask);
+}
+
+void GL_APIENTRY glStencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask)
+{
+ TRACE("(GLenum face = 0x%X, GLenum func = 0x%X, GLint ref = %d, GLuint mask = %d)", face, func, ref, mask);
+
+ 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::getContext();
+
+ 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 GL_APIENTRY glStencilMask(GLuint mask)
+{
+ glStencilMaskSeparate(GL_FRONT_AND_BACK, mask);
+}
+
+void GL_APIENTRY glStencilMaskSeparate(GLenum face, GLuint mask)
+{
+ TRACE("(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::getContext();
+
+ 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 GL_APIENTRY glStencilOp(GLenum fail, GLenum zfail, GLenum zpass)
+{
+ glStencilOpSeparate(GL_FRONT_AND_BACK, fail, zfail, zpass);
+}
+
+void GL_APIENTRY glStencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass)
+{
+ TRACE("(GLenum face = 0x%X, GLenum fail = 0x%X, GLenum zfail = 0x%X, GLenum zpas = 0x%Xs)",
+ 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::getContext();
+
+ 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 GL_APIENTRY glTestFenceNV(GLuint fence)
+{
+ TRACE("(GLuint fence = %d)", fence);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ 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 GL_APIENTRY glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height,
+ GLint border, GLenum format, GLenum type, const GLvoid* pixels)
+{
+ TRACE("(GLenum target = 0x%X, GLint level = %d, GLint internalformat = %d, GLsizei width = %d, GLsizei height = %d, "
+ "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 != format)
+ {
+ return error(GL_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_ENUM);
+ }
+ 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_ENUM);
+ }
+ 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_ENUM);
+ }
+ break;
+ case GL_BGRA_EXT:
+ switch(type)
+ {
+ case GL_UNSIGNED_BYTE:
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+ 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_ENUM);
+ }
+ break;
+ case GL_DEPTH_STENCIL_OES:
+ switch(type)
+ {
+ case GL_UNSIGNED_INT_24_8_OES:
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+ break;
+ default:
+ return error(GL_INVALID_VALUE);
+ }
+
+ if(border != 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if(context)
+ {
+ switch(target)
+ {
+ case GL_TEXTURE_2D:
+ if(width > (gl::IMPLEMENTATION_MAX_TEXTURE_SIZE >> level) ||
+ height > (gl::IMPLEMENTATION_MAX_TEXTURE_SIZE >> 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 > (gl::IMPLEMENTATION_MAX_CUBE_MAP_TEXTURE_SIZE >> level) ||
+ height > (gl::IMPLEMENTATION_MAX_CUBE_MAP_TEXTURE_SIZE >> level))
+ {
+ return error(GL_INVALID_VALUE);
+ }
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+
+ 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)
+ {
+ if(S3TC_SUPPORT)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+ else
+ {
+ return error(GL_INVALID_ENUM);
+ }
+ }
+
+ if(target == GL_TEXTURE_2D)
+ {
+ gl::Texture2D *texture = context->getTexture2D();
+
+ if(!texture)
+ {
+ 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);
+ }
+
+ texture->setImage(target, level, width, height, format, type, context->getUnpackAlignment(), pixels);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glTexParameterf(GLenum target, GLenum pname, GLfloat param)
+{
+ TRACE("(GLenum target = 0x%X, GLenum pname = 0x%X, GLfloat param = %f)", target, pname, param);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if(context)
+ {
+ gl::Texture *texture;
+
+ switch(target)
+ {
+ case GL_TEXTURE_2D:
+ texture = context->getTexture2D();
+ break;
+ case GL_TEXTURE_CUBE_MAP:
+ texture = context->getTextureCubeMap();
+ break;
+ case GL_TEXTURE_EXTERNAL_OES:
+ texture = context->getTextureExternal();
+ 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_MAX_ANISOTROPY_EXT:
+ if(!texture->setMaxAnisotropy(param))
+ {
+ return error(GL_INVALID_VALUE);
+ }
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glTexParameterfv(GLenum target, GLenum pname, const GLfloat* params)
+{
+ glTexParameterf(target, pname, *params);
+}
+
+void GL_APIENTRY glTexParameteri(GLenum target, GLenum pname, GLint param)
+{
+ TRACE("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint param = %d)", target, pname, param);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if(context)
+ {
+ gl::Texture *texture;
+
+ switch(target)
+ {
+ case GL_TEXTURE_2D:
+ texture = context->getTexture2D();
+ break;
+ case GL_TEXTURE_CUBE_MAP:
+ texture = context->getTextureCubeMap();
+ break;
+ case GL_TEXTURE_EXTERNAL_OES:
+ texture = context->getTextureExternal();
+ 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_MAX_ANISOTROPY_EXT:
+ if(!texture->setMaxAnisotropy((GLfloat)param))
+ {
+ return error(GL_INVALID_VALUE);
+ }
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glTexParameteriv(GLenum target, GLenum pname, const GLint* params)
+{
+ glTexParameteri(target, pname, *params);
+}
+
+void GL_APIENTRY glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ GLenum format, GLenum type, const GLvoid* pixels)
+{
+ TRACE("(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, "
+ "GLsizei width = %d, GLsizei height = %d, GLenum format = 0x%X, GLenum type = 0x%X, "
+ "const GLvoid* pixels = 0x%0.8p)",
+ target, level, xoffset, yoffset, width, height, format, type, pixels);
+
+ try
+ {
+ if(!gl::IsTextureTarget(target))
+ {
+ return error(GL_INVALID_ENUM);
+ }
+
+ if(level < 0 || xoffset < 0 || yoffset < 0 || width < 0 || height < 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ if(std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ if(!gl::CheckTextureFormatType(format, type))
+ {
+ return error(GL_INVALID_ENUM);
+ }
+
+ if(width == 0 || height == 0 || pixels == NULL)
+ {
+ return;
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if(context)
+ {
+ if(level > gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ if(target == GL_TEXTURE_2D)
+ {
+ gl::Texture2D *texture = context->getTexture2D();
+
+ if(validateSubImageParams(false, width, height, xoffset, yoffset, target, level, format, texture))
+ {
+ texture->subImage(level, xoffset, yoffset, width, height, format, type, context->getUnpackAlignment(), pixels);
+ }
+ }
+ else if(gl::IsCubemapTextureTarget(target))
+ {
+ gl::TextureCubeMap *texture = context->getTextureCubeMap();
+
+ if(validateSubImageParams(false, width, height, xoffset, yoffset, target, level, format, 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 GL_APIENTRY glUniform1f(GLint location, GLfloat x)
+{
+ glUniform1fv(location, 1, &x);
+}
+
+void GL_APIENTRY glUniform1fv(GLint location, GLsizei count, const GLfloat* v)
+{
+ TRACE("(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::getContext();
+
+ if(context)
+ {
+ gl::Program *program = context->getCurrentProgram();
+
+ if(!program)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ if(!program->setUniform1fv(location, count, v))
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glUniform1i(GLint location, GLint x)
+{
+ glUniform1iv(location, 1, &x);
+}
+
+void GL_APIENTRY glUniform1iv(GLint location, GLsizei count, const GLint* v)
+{
+ TRACE("(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::getContext();
+
+ if(context)
+ {
+ gl::Program *program = context->getCurrentProgram();
+
+ if(!program)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ if(!program->setUniform1iv(location, count, v))
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glUniform2f(GLint location, GLfloat x, GLfloat y)
+{
+ GLfloat xy[2] = {x, y};
+
+ glUniform2fv(location, 1, (GLfloat*)&xy);
+}
+
+void GL_APIENTRY glUniform2fv(GLint location, GLsizei count, const GLfloat* v)
+{
+ TRACE("(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::getContext();
+
+ if(context)
+ {
+ gl::Program *program = context->getCurrentProgram();
+
+ if(!program)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ if(!program->setUniform2fv(location, count, v))
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glUniform2i(GLint location, GLint x, GLint y)
+{
+ GLint xy[4] = {x, y};
+
+ glUniform2iv(location, 1, (GLint*)&xy);
+}
+
+void GL_APIENTRY glUniform2iv(GLint location, GLsizei count, const GLint* v)
+{
+ TRACE("(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::getContext();
+
+ if(context)
+ {
+ gl::Program *program = context->getCurrentProgram();
+
+ if(!program)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ if(!program->setUniform2iv(location, count, v))
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glUniform3f(GLint location, GLfloat x, GLfloat y, GLfloat z)
+{
+ GLfloat xyz[3] = {x, y, z};
+
+ glUniform3fv(location, 1, (GLfloat*)&xyz);
+}
+
+void GL_APIENTRY glUniform3fv(GLint location, GLsizei count, const GLfloat* v)
+{
+ TRACE("(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::getContext();
+
+ if(context)
+ {
+ gl::Program *program = context->getCurrentProgram();
+
+ if(!program)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ if(!program->setUniform3fv(location, count, v))
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glUniform3i(GLint location, GLint x, GLint y, GLint z)
+{
+ GLint xyz[3] = {x, y, z};
+
+ glUniform3iv(location, 1, (GLint*)&xyz);
+}
+
+void GL_APIENTRY glUniform3iv(GLint location, GLsizei count, const GLint* v)
+{
+ TRACE("(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::getContext();
+
+ if(context)
+ {
+ gl::Program *program = context->getCurrentProgram();
+
+ if(!program)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ if(!program->setUniform3iv(location, count, v))
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glUniform4f(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+{
+ GLfloat xyzw[4] = {x, y, z, w};
+
+ glUniform4fv(location, 1, (GLfloat*)&xyzw);
+}
+
+void GL_APIENTRY glUniform4fv(GLint location, GLsizei count, const GLfloat* v)
+{
+ TRACE("(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::getContext();
+
+ if(context)
+ {
+ gl::Program *program = context->getCurrentProgram();
+
+ if(!program)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ if(!program->setUniform4fv(location, count, v))
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glUniform4i(GLint location, GLint x, GLint y, GLint z, GLint w)
+{
+ GLint xyzw[4] = {x, y, z, w};
+
+ glUniform4iv(location, 1, (GLint*)&xyzw);
+}
+
+void GL_APIENTRY glUniform4iv(GLint location, GLsizei count, const GLint* v)
+{
+ TRACE("(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::getContext();
+
+ if(context)
+ {
+ gl::Program *program = context->getCurrentProgram();
+
+ if(!program)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ if(!program->setUniform4iv(location, count, v))
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+{
+ TRACE("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %d, const GLfloat* value = 0x%0.8p)",
+ location, count, transpose, value);
+
+ try
+ {
+ if(count < 0 || transpose != GL_FALSE)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ if(location == -1)
+ {
+ return;
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if(context)
+ {
+ gl::Program *program = context->getCurrentProgram();
+
+ if(!program)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ if(!program->setUniformMatrix2fv(location, count, value))
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+{
+ TRACE("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %d, const GLfloat* value = 0x%0.8p)",
+ location, count, transpose, value);
+
+ try
+ {
+ if(count < 0 || transpose != GL_FALSE)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ if(location == -1)
+ {
+ return;
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if(context)
+ {
+ gl::Program *program = context->getCurrentProgram();
+
+ if(!program)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ if(!program->setUniformMatrix3fv(location, count, value))
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+{
+ TRACE("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %d, const GLfloat* value = 0x%0.8p)",
+ location, count, transpose, value);
+
+ try
+ {
+ if(count < 0 || transpose != GL_FALSE)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ if(location == -1)
+ {
+ return;
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if(context)
+ {
+ gl::Program *program = context->getCurrentProgram();
+
+ if(!program)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ if(!program->setUniformMatrix4fv(location, count, value))
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glUseProgram(GLuint program)
+{
+ TRACE("(GLuint program = %d)", program);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ 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 GL_APIENTRY glValidateProgram(GLuint program)
+{
+ TRACE("(GLuint program = %d)", program);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ 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 GL_APIENTRY glVertexAttrib1f(GLuint index, GLfloat x)
+{
+ TRACE("(GLuint index = %d, GLfloat x = %f)", index, x);
+
+ try
+ {
+ if(index >= gl::MAX_VERTEX_ATTRIBS)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if(context)
+ {
+ GLfloat vals[4] = { x, 0, 0, 1 };
+ context->setVertexAttrib(index, vals);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glVertexAttrib1fv(GLuint index, const GLfloat* values)
+{
+ TRACE("(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::getContext();
+
+ 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 GL_APIENTRY glVertexAttrib2f(GLuint index, GLfloat x, GLfloat y)
+{
+ TRACE("(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::getContext();
+
+ if(context)
+ {
+ GLfloat vals[4] = { x, y, 0, 1 };
+ context->setVertexAttrib(index, vals);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glVertexAttrib2fv(GLuint index, const GLfloat* values)
+{
+ TRACE("(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::getContext();
+
+ 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 GL_APIENTRY glVertexAttrib3f(GLuint index, GLfloat x, GLfloat y, GLfloat z)
+{
+ TRACE("(GLuint index = %d, GLfloat x = %f, GLfloat y = %f, GLfloat z = %f)", index, x, y, z);
+
+ try
+ {
+ if(index >= gl::MAX_VERTEX_ATTRIBS)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if(context)
+ {
+ GLfloat vals[4] = { x, y, z, 1 };
+ context->setVertexAttrib(index, vals);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glVertexAttrib3fv(GLuint index, const GLfloat* values)
+{
+ TRACE("(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::getContext();
+
+ 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 GL_APIENTRY glVertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+{
+ TRACE("(GLuint index = %d, GLfloat x = %f, GLfloat y = %f, GLfloat z = %f, GLfloat w = %f)", index, x, y, z, w);
+
+ try
+ {
+ if(index >= gl::MAX_VERTEX_ATTRIBS)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if(context)
+ {
+ GLfloat vals[4] = { x, y, z, w };
+ context->setVertexAttrib(index, vals);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glVertexAttrib4fv(GLuint index, const GLfloat* values)
+{
+ TRACE("(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::getContext();
+
+ if(context)
+ {
+ context->setVertexAttrib(index, values);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr)
+{
+ TRACE("(GLuint index = %d, GLint size = %d, GLenum type = 0x%X, "
+ "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::getContext();
+
+ 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 GL_APIENTRY glViewport(GLint x, GLint y, GLsizei width, GLsizei height)
+{
+ TRACE("(GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d)", x, y, width, height);
+
+ try
+ {
+ if(width < 0 || height < 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if(context)
+ {
+ context->setViewportParams(x, y, width, height);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY glBlitFramebufferANGLE(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
+ GLbitfield mask, GLenum filter)
+{
+ TRACE("(GLint srcX0 = %d, GLint srcY0 = %d, GLint srcX1 = %d, GLint srcY1 = %d, "
+ "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::getContext();
+
+ 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 GL_APIENTRY glTexImage3DOES(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth,
+ GLint border, GLenum format, GLenum type, const GLvoid* pixels)
+{
+ TRACE("(GLenum target = 0x%X, GLint level = %d, GLenum internalformat = 0x%X, "
+ "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 GL_APIENTRY glEGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image)
+{
+ TRACE("(GLenum target = 0x%X, GLeglImageOES image = 0x%0.8p)", target, image);
+
+ try
+ {
+ switch(target)
+ {
+ case GL_TEXTURE_EXTERNAL_OES:
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+
+ if(!image)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if(context)
+ {
+ gl::TextureExternal *texture = context->getTextureExternal();
+
+ if(!texture)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ gl::Image *glImage = static_cast<gl::Image*>(image);
+
+ texture->setImage(glImage);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+__eglMustCastToProperFunctionPointerType 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},
+ {"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},
+ {"glEGLImageTargetTexture2DOES", (__eglMustCastToProperFunctionPointerType)glEGLImageTargetTexture2DOES}
+ };
+
+ for(int ext = 0; ext < sizeof(glExtensions) / sizeof(Extension); ext++)
+ {
+ if(strcmp(procname, glExtensions[ext].name) == 0)
+ {
+ return (__eglMustCastToProperFunctionPointerType)glExtensions[ext].address;
+ }
+ }
+
+ return NULL;
+}
+
+void glBindTexImage(egl::Surface *surface)
+{
+ TRACE("(egl::Surface* surface = 0x%0.8p)",
+ surface);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if(context)
+ {
+ gl::Texture2D *textureObject = context->getTexture2D();
+
+ if(textureObject)
+ {
+ textureObject->bindTexImage(surface);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void GL_APIENTRY Register(const char *licenseKey)
+{
+ RegisterLicenseKey(licenseKey);
+}
+
+}
diff --git a/src/GLES2/libGLES_CM/libGLESv2.def b/src/GLES2/libGLES_CM/libGLESv2.def
new file mode 100644
index 0000000..bd087d3
--- /dev/null
+++ b/src/GLES2/libGLES_CM/libGLESv2.def
@@ -0,0 +1,183 @@
+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
+
+ ; EGL dependencies
+ glCreateContext @144
+ glDestroyContext @145
+ glMakeCurrent @146
+ glGetCurrentContext @147
+ glGetProcAddress @148
+ glBindTexImage @158
+
+ createFrameBuffer @172
+ createBackBuffer @173
+ createDevice @174
+
+ Register
\ No newline at end of file
diff --git a/src/GLES2/libGLES_CM/libGLESv2.rc b/src/GLES2/libGLES_CM/libGLESv2.rc
new file mode 100644
index 0000000..919c7ed
--- /dev/null
+++ b/src/GLES2/libGLES_CM/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", "SwiftShader libGLESv2 Dynamic Link Library"
+ VALUE "FileVersion", VERSION_STRING
+ VALUE "InternalName", "libGLESv2"
+ VALUE "LegalCopyright", "Copyright (C) 2012 TransGaming Inc."
+ VALUE "OriginalFilename", "libGLESv2.dll"
+ VALUE "PrivateBuild", VERSION_STRING
+ VALUE "ProductName", "SwiftShader 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/GLES2/libGLES_CM/libGLESv2.vcxproj b/src/GLES2/libGLES_CM/libGLESv2.vcxproj
new file mode 100644
index 0000000..c833496
--- /dev/null
+++ b/src/GLES2/libGLES_CM/libGLESv2.vcxproj
@@ -0,0 +1,232 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Profile|Win32">
+ <Configuration>Profile</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{B5871A7A-968C-42E3-A33B-981E6F448E78}</ProjectGuid>
+ <RootNamespace>libGLESv2</RootNamespace>
+ <Keyword>Win32Proj</Keyword>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <CharacterSet>NotSet</CharacterSet>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <PlatformToolset>v120</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <CharacterSet>NotSet</CharacterSet>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <PlatformToolset>v120</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <CharacterSet>NotSet</CharacterSet>
+ <PlatformToolset>v120</PlatformToolset>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup>
+ <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Platform)\$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Platform)\$(Configuration)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Platform)\$(Configuration)\</OutDir>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'">$(Platform)\$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Platform)\$(Configuration)\</IntDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'">$(Platform)\$(Configuration)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'">false</LinkIncremental>
+ <IncludePath Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(DXSDK_DIR)\Include;..\include;$(DXSDK_DIR)\Include;$(VCInstallDir)PlatformSDK\include;$(IncludePath)</IncludePath>
+ <IncludePath Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'">$(DXSDK_DIR)\Include;..\include;$(DXSDK_DIR)\Include;$(VCInstallDir)PlatformSDK\include;$(IncludePath)</IncludePath>
+ <IncludePath Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(DXSDK_DIR)\Include;..\include;$(DXSDK_DIR)\Include;$(VCInstallDir)PlatformSDK\include;$(IncludePath)</IncludePath>
+ <LibraryPath Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(DXSDK_DIR)\Lib\x86;$(VCInstallDir)PlatformSDK\lib;$(LibraryPath)</LibraryPath>
+ <LibraryPath Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'">$(DXSDK_DIR)\Lib\x86;$(VCInstallDir)PlatformSDK\lib;$(LibraryPath)</LibraryPath>
+ <LibraryPath Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(DXSDK_DIR)\Lib\x86;$(VCInstallDir)PlatformSDK\lib;$(LibraryPath)</LibraryPath>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>$(SolutionDir);$(ProjectDir)/..;$(ProjectDir)/../..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBGLESV2_EXPORTS;_CRT_SECURE_NO_DEPRECATE;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>true</MinimalRebuild>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <BrowseInformation>true</BrowseInformation>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>dxguid.lib;WS2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <ModuleDefinitionFile>libGLESv2.def</ModuleDefinitionFile>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <SubSystem>Windows</SubSystem>
+ <TargetMachine>MachineX86</TargetMachine>
+ </Link>
+ <PostBuildEvent>
+ <Command>mkdir "$(ProjectDir)..\..\..\lib\$(Configuration)\"
+copy "$(OutDir)libGLESv2.dll" "$(ProjectDir)..\..\..\lib\$(Configuration)\"</Command>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <Optimization>Full</Optimization>
+ <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
+ <AdditionalIncludeDirectories>$(ProjectDir)/..;$(ProjectDir)/../..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBGLESV2_EXPORTS;_CRT_SECURE_NO_DEPRECATE;NOMINMAX;_SECURE_SCL=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>
+ </DebugInformationFormat>
+ <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
+ <OmitFramePointers>true</OmitFramePointers>
+ <EnableFiberSafeOptimizations>true</EnableFiberSafeOptimizations>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <IntrinsicFunctions>false</IntrinsicFunctions>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>dxguid.lib;WS2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
+ <ModuleDefinitionFile>libGLESv2.def</ModuleDefinitionFile>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <SubSystem>Windows</SubSystem>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <TargetMachine>MachineX86</TargetMachine>
+ </Link>
+ <PostBuildEvent>
+ <Command>mkdir "$(ProjectDir)..\..\..\lib\$(Configuration)\"
+copy "$(OutDir)libGLESv2.dll" "$(ProjectDir)..\..\..\lib\$(Configuration)\"</Command>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'">
+ <ClCompile>
+ <Optimization>Full</Optimization>
+ <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
+ <AdditionalIncludeDirectories>$(ProjectDir)/..; $(ProjectDir)/../..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBGLESV2_EXPORTS;_CRT_SECURE_NO_DEPRECATE;NOMINMAX;_SECURE_SCL=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
+ <OmitFramePointers>false</OmitFramePointers>
+ <EnableFiberSafeOptimizations>true</EnableFiberSafeOptimizations>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <IntrinsicFunctions>false</IntrinsicFunctions>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>dxguid.lib;WS2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
+ <ModuleDefinitionFile>libGLESv2.def</ModuleDefinitionFile>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <SubSystem>Windows</SubSystem>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <TargetMachine>MachineX86</TargetMachine>
+ </Link>
+ <PostBuildEvent>
+ <Command>mkdir "$(ProjectDir)..\..\..\lib\$(Configuration)\"
+copy "$(OutDir)libGLESv2.dll" "$(ProjectDir)..\..\..\lib\$(Configuration)\"</Command>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="Buffer.cpp" />
+ <ClCompile Include="Context.cpp" />
+ <ClCompile Include="..\common\debug.cpp" />
+ <ClCompile Include="Device.cpp" />
+ <ClCompile Include="Fence.cpp" />
+ <ClCompile Include="Framebuffer.cpp" />
+ <ClCompile Include="HandleAllocator.cpp" />
+ <ClCompile Include="Image.cpp" />
+ <ClCompile Include="IndexDataManager.cpp" />
+ <ClCompile Include="libGLESv2.cpp" />
+ <ClCompile Include="main.cpp" />
+ <ClCompile Include="Program.cpp" />
+ <ClCompile Include="Query.cpp" />
+ <ClCompile Include="RefCountObject.cpp" />
+ <ClCompile Include="Renderbuffer.cpp" />
+ <ClCompile Include="ResourceManager.cpp" />
+ <ClCompile Include="Shader.cpp" />
+ <ClCompile Include="Texture.cpp" />
+ <ClCompile Include="utilities.cpp" />
+ <ClCompile Include="VertexDataManager.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\common\debug.h" />
+ <ClInclude Include="..\include\GLES2\gl2.h" />
+ <ClInclude Include="..\include\GLES2\gl2ext.h" />
+ <ClInclude Include="..\include\GLES2\gl2platform.h" />
+ <ClInclude Include="Buffer.h" />
+ <ClInclude Include="Context.h" />
+ <ClInclude Include="Device.hpp" />
+ <ClInclude Include="Fence.h" />
+ <ClInclude Include="Framebuffer.h" />
+ <ClInclude Include="HandleAllocator.h" />
+ <ClInclude Include="Image.hpp" />
+ <ClInclude Include="IndexDataManager.h" />
+ <ClInclude Include="main.h" />
+ <ClInclude Include="mathutil.h" />
+ <ClInclude Include="Program.h" />
+ <ClInclude Include="Query.h" />
+ <ClInclude Include="RefCountObject.h" />
+ <ClInclude Include="Renderbuffer.h" />
+ <ClInclude Include="resource.h" />
+ <ClInclude Include="ResourceManager.h" />
+ <ClInclude Include="Shader.h" />
+ <ClInclude Include="Texture.h" />
+ <ClInclude Include="utilities.h" />
+ <ClInclude Include="VertexDataManager.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="libGLESv2.def" />
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="libGLESv2.rc" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\SwiftShader\SwiftShader.vcxproj">
+ <Project>{7b02cb19-4cdf-4f79-bc9b-7f3f6164a003}</Project>
+ <Private>true</Private>
+ <ReferenceOutputAssembly>true</ReferenceOutputAssembly>
+ <CopyLocalSatelliteAssemblies>false</CopyLocalSatelliteAssemblies>
+ <LinkLibraryDependencies>true</LinkLibraryDependencies>
+ <UseLibraryDependencyInputs>true</UseLibraryDependencyInputs>
+ </ProjectReference>
+ <ProjectReference Include="..\compiler\Compiler.vcxproj">
+ <Project>{5b3a6db8-1e7e-40d7-92b9-da8aae619fad}</Project>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project>
\ No newline at end of file
diff --git a/src/GLES2/libGLES_CM/libGLESv2.vcxproj.filters b/src/GLES2/libGLES_CM/libGLESv2.vcxproj.filters
new file mode 100644
index 0000000..91125de
--- /dev/null
+++ b/src/GLES2/libGLES_CM/libGLESv2.vcxproj.filters
@@ -0,0 +1,155 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="Buffer.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Context.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\common\debug.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Fence.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Framebuffer.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="HandleAllocator.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="IndexDataManager.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="libGLESv2.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="main.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Program.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="RefCountObject.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Renderbuffer.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="ResourceManager.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Shader.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Texture.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="utilities.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="VertexDataManager.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Device.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Image.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Query.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="Buffer.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Context.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Fence.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Framebuffer.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="HandleAllocator.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="IndexDataManager.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="main.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="mathutil.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Program.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="RefCountObject.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Renderbuffer.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="resource.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ResourceManager.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Shader.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Texture.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="utilities.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="VertexDataManager.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Device.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Image.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\GLES2\gl2.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\GLES2\gl2ext.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\GLES2\gl2platform.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Query.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\common\debug.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="libGLESv2.rc" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="libGLESv2.def" />
+ </ItemGroup>
+</Project>
\ No newline at end of file
diff --git a/src/GLES2/libGLES_CM/main.cpp b/src/GLES2/libGLES_CM/main.cpp
new file mode 100644
index 0000000..9ddca97
--- /dev/null
+++ b/src/GLES2/libGLES_CM/main.cpp
@@ -0,0 +1,189 @@
+// SwiftShader Software Renderer
+//
+// Copyright(c) 2005-2013 TransGaming Inc.
+//
+// All rights reserved. No part of this software may be copied, distributed, transmitted,
+// transcribed, stored in a retrieval system, translated into any human or computer
+// language by any means, or disclosed to third parties without the explicit written
+// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
+// or implied, including but not limited to any patent rights, are granted to you.
+//
+
+// main.cpp: DLL entry point and management of thread-local data.
+
+#include "main.h"
+
+#include "Framebuffer.h"
+#include "libEGL/Surface.h"
+#include "Common/Thread.hpp"
+#include "common/debug.h"
+
+static sw::Thread::LocalStorageKey currentTLS = TLS_OUT_OF_INDEXES;
+
+#if !defined(_MSC_VER)
+#define CONSTRUCTOR __attribute__((constructor))
+#define DESTRUCTOR __attribute__((destructor))
+#else
+#define CONSTRUCTOR
+#define DESTRUCTOR
+#endif
+
+static void glAttachThread()
+{
+ TRACE("()");
+
+ gl::Current *current = new gl::Current;
+
+ if(current)
+ {
+ sw::Thread::setLocalStorage(currentTLS, current);
+
+ current->context = NULL;
+ current->display = NULL;
+ }
+}
+
+static void glDetachThread()
+{
+ TRACE("()");
+
+ gl::Current *current = (gl::Current*)sw::Thread::getLocalStorage(currentTLS);
+
+ if(current)
+ {
+ delete current;
+ }
+}
+
+CONSTRUCTOR static bool glAttachProcess()
+{
+ TRACE("()");
+
+ currentTLS = sw::Thread::allocateLocalStorageKey();
+
+ if(currentTLS == TLS_OUT_OF_INDEXES)
+ {
+ return false;
+ }
+
+ glAttachThread();
+
+ return true;
+}
+
+DESTRUCTOR static void glDetachProcess()
+{
+ TRACE("()");
+
+ glDetachThread();
+
+ sw::Thread::freeLocalStorageKey(currentTLS);
+}
+
+#if defined(_WIN32)
+extern "C" BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved)
+{
+ switch(reason)
+ {
+ case DLL_PROCESS_ATTACH:
+ return glAttachProcess();
+ break;
+ case DLL_THREAD_ATTACH:
+ glAttachThread();
+ break;
+ case DLL_THREAD_DETACH:
+ glDetachThread();
+ break;
+ case DLL_PROCESS_DETACH:
+ glDetachProcess();
+ break;
+ default:
+ break;
+ }
+
+ return TRUE;
+}
+#endif
+
+namespace gl
+{
+static gl::Current *getCurrent(void)
+{
+ Current *current = (Current*)sw::Thread::getLocalStorage(currentTLS);
+
+ if(!current)
+ {
+ glAttachThread();
+ }
+
+ return (Current*)sw::Thread::getLocalStorage(currentTLS);
+}
+
+void makeCurrent(Context *context, egl::Display *display, egl::Surface *surface)
+{
+ Current *current = getCurrent();
+
+ current->context = context;
+ current->display = display;
+
+ if(context && display && surface)
+ {
+ context->makeCurrent(display, surface);
+ }
+}
+
+Context *getContext()
+{
+ Current *current = getCurrent();
+
+ return current->context;
+}
+
+egl::Display *getDisplay()
+{
+ Current *current = getCurrent();
+
+ return current->display;
+}
+
+Device *getDevice()
+{
+ egl::Display *display = getDisplay();
+
+ return display->getDevice();
+}
+}
+
+// Records an error code
+void error(GLenum errorCode)
+{
+ gl::Context *context = gl::getContext();
+
+ 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/GLES2/libGLES_CM/main.h b/src/GLES2/libGLES_CM/main.h
new file mode 100644
index 0000000..fdb0dc0
--- /dev/null
+++ b/src/GLES2/libGLES_CM/main.h
@@ -0,0 +1,52 @@
+// SwiftShader Software Renderer
+//
+// Copyright(c) 2005-2012 TransGaming Inc.
+//
+// All rights reserved. No part of this software may be copied, distributed, transmitted,
+// transcribed, stored in a retrieval system, translated into any human or computer
+// language by any means, or disclosed to third parties without the explicit written
+// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
+// or implied, including but not limited to any patent rights, are granted to you.
+//
+
+// main.h: Management of thread-local data.
+
+#ifndef LIBGLESV2_MAIN_H_
+#define LIBGLESV2_MAIN_H_
+
+#include "Context.h"
+#include "Device.hpp"
+#include "common/debug.h"
+#include "libEGL/Display.h"
+
+#define GL_APICALL
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+namespace gl
+{
+ struct Current
+ {
+ Context *context;
+ egl::Display *display;
+ };
+
+ void makeCurrent(Context *context, egl::Display *display, egl::Surface *surface);
+
+ Context *getContext();
+ egl::Display *getDisplay();
+
+ Device *getDevice();
+}
+
+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/GLES2/libGLES_CM/mathutil.h b/src/GLES2/libGLES_CM/mathutil.h
new file mode 100644
index 0000000..9955fb2
--- /dev/null
+++ b/src/GLES2/libGLES_CM/mathutil.h
@@ -0,0 +1,79 @@
+// SwiftShader Software Renderer
+//
+// Copyright(c) 2005-2012 TransGaming Inc.
+//
+// All rights reserved. No part of this software may be copied, distributed, transmitted,
+// transcribed, stored in a retrieval system, translated into any human or computer
+// language by any means, or disclosed to third parties without the explicit written
+// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
+// or implied, including but not limited to any patent rights, are granted to you.
+//
+
+// mathutil.h: Math and bit manipulation functions.
+
+#ifndef LIBGLESV2_MATHUTIL_H_
+#define LIBGLESV2_MATHUTIL_H_
+
+#include "common/debug.h"
+
+#include <math.h>
+
+namespace gl
+{
+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);
+ }
+}
+}
+
+#endif // LIBGLESV2_MATHUTIL_H_
diff --git a/src/GLES2/libGLES_CM/resource.h b/src/GLES2/libGLES_CM/resource.h
new file mode 100644
index 0000000..39adaad
--- /dev/null
+++ b/src/GLES2/libGLES_CM/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/GLES2/libGLES_CM/utilities.cpp b/src/GLES2/libGLES_CM/utilities.cpp
new file mode 100644
index 0000000..c0004bf
--- /dev/null
+++ b/src/GLES2/libGLES_CM/utilities.cpp
@@ -0,0 +1,854 @@
+// SwiftShader Software Renderer
+//
+// Copyright(c) 2005-2013 TransGaming Inc.
+//
+// All rights reserved. No part of this software may be copied, distributed, transmitted,
+// transcribed, stored in a retrieval system, translated into any human or computer
+// language by any means, or disclosed to third parties without the explicit written
+// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
+// or implied, including but not limited to any patent rights, are granted to you.
+//
+
+// utilities.cpp: Conversion functions and other utility routines.
+
+#include "utilities.h"
+
+#include "mathutil.h"
+#include "Context.h"
+#include "common/debug.h"
+
+#include <limits>
+#include <stdio.h>
+
+namespace gl
+{
+ int UniformComponentCount(GLenum type)
+ {
+ switch(type)
+ {
+ case GL_BOOL:
+ case GL_FLOAT:
+ case GL_INT:
+ case GL_SAMPLER_2D:
+ case GL_SAMPLER_CUBE:
+ case GL_SAMPLER_EXTERNAL_OES:
+ 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;
+ }
+
+ 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_SAMPLER_EXTERNAL_OES:
+ case GL_INT_VEC2:
+ case GL_INT_VEC3:
+ case GL_INT_VEC4:
+ return GL_INT;
+ default:
+ UNREACHABLE();
+ }
+
+ return GL_NONE;
+ }
+
+ size_t UniformTypeSize(GLenum type)
+ {
+ switch(type)
+ {
+ case GL_BOOL: return sizeof(GLboolean);
+ case GL_FLOAT: return sizeof(GLfloat);
+ case GL_INT: return sizeof(GLint);
+ }
+
+ return UniformTypeSize(UniformComponentType(type)) * UniformComponentCount(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:
+ case GL_SAMPLER_2D:
+ case GL_SAMPLER_CUBE:
+ case GL_SAMPLER_EXTERNAL_OES:
+ 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, GLenum format, GLenum type, GLint alignment)
+ {
+ ASSERT(alignment > 0 && isPow2(alignment));
+
+ GLsizei rawPitch = ComputePixelSize(format, type) * width;
+ return (rawPitch + alignment - 1) & ~(alignment - 1);
+ }
+
+ GLsizei ComputeCompressedPitch(GLsizei width, GLenum format)
+ {
+ return ComputeCompressedSize(width, 1, format);
+ }
+
+ GLsizei ComputeCompressedSize(GLsizei width, GLsizei height, GLenum format)
+ {
+ switch(format)
+ {
+ case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
+ case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
+ return 8 * (GLsizei)ceil((float)width / 4.0f) * (GLsizei)ceil((float)height / 4.0f);
+ case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
+ case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
+ return 16 * (GLsizei)ceil((float)width / 4.0f) * (GLsizei)ceil((float)height / 4.0f);
+ default:
+ return 0;
+ }
+ }
+
+ 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)
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ bool IsStencilTexture(GLenum format)
+ {
+ if(format == GL_STENCIL_INDEX ||
+ format == GL_DEPTH_STENCIL_OES)
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ // Returns the size, in bytes, of a single texel in an Image
+ int ComputePixelSize(GLenum format, GLenum type)
+ {
+ switch(type)
+ {
+ case GL_UNSIGNED_BYTE:
+ switch(format)
+ {
+ case GL_ALPHA: return sizeof(unsigned char);
+ case GL_LUMINANCE: return sizeof(unsigned char);
+ case GL_LUMINANCE_ALPHA: return sizeof(unsigned char) * 2;
+ case GL_RGB: return sizeof(unsigned char) * 3;
+ case GL_RGBA: return sizeof(unsigned char) * 4;
+ case GL_BGRA_EXT: return sizeof(unsigned char) * 4;
+ default: UNREACHABLE();
+ }
+ break;
+ case GL_UNSIGNED_SHORT_4_4_4_4:
+ case GL_UNSIGNED_SHORT_5_5_5_1:
+ case GL_UNSIGNED_SHORT_5_6_5:
+ case GL_UNSIGNED_SHORT:
+ return sizeof(unsigned short);
+ case GL_UNSIGNED_INT:
+ case GL_UNSIGNED_INT_24_8_OES:
+ return sizeof(unsigned int);
+ case GL_FLOAT:
+ switch(format)
+ {
+ case GL_ALPHA: return sizeof(float);
+ case GL_LUMINANCE: return sizeof(float);
+ case GL_LUMINANCE_ALPHA: return sizeof(float) * 2;
+ case GL_RGB: return sizeof(float) * 3;
+ case GL_RGBA: return sizeof(float) * 4;
+ default: UNREACHABLE();
+ }
+ break;
+ case GL_HALF_FLOAT_OES:
+ switch(format)
+ {
+ case GL_ALPHA: return sizeof(unsigned short);
+ case GL_LUMINANCE: return sizeof(unsigned short);
+ case GL_LUMINANCE_ALPHA: return sizeof(unsigned short) * 2;
+ case GL_RGB: return sizeof(unsigned short) * 3;
+ case GL_RGBA: return sizeof(unsigned short) * 4;
+ default: UNREACHABLE();
+ }
+ break;
+ default: UNREACHABLE();
+ }
+
+ return 0;
+ }
+
+ bool IsCubemapTextureTarget(GLenum target)
+ {
+ return (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z);
+ }
+
+ int CubeFaceIndex(GLenum cubeFace)
+ {
+ switch(cubeFace)
+ {
+ case GL_TEXTURE_CUBE_MAP:
+ case GL_TEXTURE_CUBE_MAP_POSITIVE_X: return 0;
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: return 1;
+ case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: return 2;
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: return 3;
+ case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: return 4;
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: return 5;
+ default: UNREACHABLE(); return 0;
+ }
+ }
+
+ bool IsTextureTarget(GLenum target)
+ {
+ return target == GL_TEXTURE_2D || IsCubemapTextureTarget(target);
+ }
+
+ // Verify that format/type are one of the combinations from table 3.4.
+ bool CheckTextureFormatType(GLenum format, GLenum type)
+ {
+ 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 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 false;
+ }
+ case GL_UNSIGNED_SHORT_4_4_4_4:
+ case GL_UNSIGNED_SHORT_5_5_5_1:
+ return (format == GL_RGBA);
+ case GL_UNSIGNED_SHORT_5_6_5:
+ return (format == GL_RGB);
+ case GL_UNSIGNED_INT:
+ return (format == GL_DEPTH_COMPONENT);
+ case GL_UNSIGNED_INT_24_8_OES:
+ return (format == GL_DEPTH_STENCIL_OES);
+ default:
+ return false;
+ }
+ }
+
+ 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;
+ }
+}
+
+namespace es2sw
+{
+ sw::DepthCompareMode ConvertDepthComparison(GLenum comparison)
+ {
+ switch(comparison)
+ {
+ case GL_NEVER: return sw::DEPTH_NEVER;
+ case GL_ALWAYS: return sw::DEPTH_ALWAYS;
+ case GL_LESS: return sw::DEPTH_LESS;
+ case GL_LEQUAL: return sw::DEPTH_LESSEQUAL;
+ case GL_EQUAL: return sw::DEPTH_EQUAL;
+ case GL_GREATER: return sw::DEPTH_GREATER;
+ case GL_GEQUAL: return sw::DEPTH_GREATEREQUAL;
+ case GL_NOTEQUAL: return sw::DEPTH_NOTEQUAL;
+ default: UNREACHABLE();
+ }
+
+ return sw::DEPTH_ALWAYS;
+ }
+
+ sw::StencilCompareMode ConvertStencilComparison(GLenum comparison)
+ {
+ switch(comparison)
+ {
+ case GL_NEVER: return sw::STENCIL_NEVER;
+ case GL_ALWAYS: return sw::STENCIL_ALWAYS;
+ case GL_LESS: return sw::STENCIL_LESS;
+ case GL_LEQUAL: return sw::STENCIL_LESSEQUAL;
+ case GL_EQUAL: return sw::STENCIL_EQUAL;
+ case GL_GREATER: return sw::STENCIL_GREATER;
+ case GL_GEQUAL: return sw::STENCIL_GREATEREQUAL;
+ case GL_NOTEQUAL: return sw::STENCIL_NOTEQUAL;
+ default: UNREACHABLE();
+ }
+
+ return sw::STENCIL_ALWAYS;
+ }
+
+ sw::Color<float> ConvertColor(gl::Color color)
+ {
+ return sw::Color<float>(color.red, color.green, color.blue, color.alpha);
+ }
+
+ sw::BlendFactor ConvertBlendFunc(GLenum blend)
+ {
+ switch(blend)
+ {
+ case GL_ZERO: return sw::BLEND_ZERO;
+ case GL_ONE: return sw::BLEND_ONE;
+ case GL_SRC_COLOR: return sw::BLEND_SOURCE;
+ case GL_ONE_MINUS_SRC_COLOR: return sw::BLEND_INVSOURCE;
+ case GL_DST_COLOR: return sw::BLEND_DEST;
+ case GL_ONE_MINUS_DST_COLOR: return sw::BLEND_INVDEST;
+ case GL_SRC_ALPHA: return sw::BLEND_SOURCEALPHA;
+ case GL_ONE_MINUS_SRC_ALPHA: return sw::BLEND_INVSOURCEALPHA;
+ case GL_DST_ALPHA: return sw::BLEND_DESTALPHA;
+ case GL_ONE_MINUS_DST_ALPHA: return sw::BLEND_INVDESTALPHA;
+ case GL_CONSTANT_COLOR: return sw::BLEND_CONSTANT;
+ case GL_ONE_MINUS_CONSTANT_COLOR: return sw::BLEND_INVCONSTANT;
+ case GL_CONSTANT_ALPHA: return sw::BLEND_CONSTANTALPHA;
+ case GL_ONE_MINUS_CONSTANT_ALPHA: return sw::BLEND_INVCONSTANTALPHA;
+ case GL_SRC_ALPHA_SATURATE: return sw::BLEND_SRCALPHASAT;
+ default: UNREACHABLE();
+ }
+
+ return sw::BLEND_ZERO;
+ }
+
+ sw::BlendOperation ConvertBlendOp(GLenum blendOp)
+ {
+ switch(blendOp)
+ {
+ case GL_FUNC_ADD: return sw::BLENDOP_ADD;
+ case GL_FUNC_SUBTRACT: return sw::BLENDOP_SUB;
+ case GL_FUNC_REVERSE_SUBTRACT: return sw::BLENDOP_INVSUB;
+ case GL_MIN_EXT: return sw::BLENDOP_MIN;
+ case GL_MAX_EXT: return sw::BLENDOP_MAX;
+ default: UNREACHABLE();
+ }
+
+ return sw::BLENDOP_ADD;
+ }
+
+ sw::StencilOperation ConvertStencilOp(GLenum stencilOp)
+ {
+ switch(stencilOp)
+ {
+ case GL_ZERO: return sw::OPERATION_ZERO;
+ case GL_KEEP: return sw::OPERATION_KEEP;
+ case GL_REPLACE: return sw::OPERATION_REPLACE;
+ case GL_INCR: return sw::OPERATION_INCRSAT;
+ case GL_DECR: return sw::OPERATION_DECRSAT;
+ case GL_INVERT: return sw::OPERATION_INVERT;
+ case GL_INCR_WRAP: return sw::OPERATION_INCR;
+ case GL_DECR_WRAP: return sw::OPERATION_DECR;
+ default: UNREACHABLE();
+ }
+
+ return sw::OPERATION_KEEP;
+ }
+
+ sw::AddressingMode ConvertTextureWrap(GLenum wrap)
+ {
+ switch(wrap)
+ {
+ case GL_REPEAT: return sw::ADDRESSING_WRAP;
+ case GL_CLAMP_TO_EDGE: return sw::ADDRESSING_CLAMP;
+ case GL_MIRRORED_REPEAT: return sw::ADDRESSING_MIRROR;
+ default: UNREACHABLE();
+ }
+
+ return sw::ADDRESSING_WRAP;
+ }
+
+ sw::CullMode ConvertCullMode(GLenum cullFace, GLenum frontFace)
+ {
+ switch(cullFace)
+ {
+ case GL_FRONT:
+ return (frontFace == GL_CCW ? sw::CULL_CLOCKWISE : sw::CULL_COUNTERCLOCKWISE);
+ case GL_BACK:
+ return (frontFace == GL_CCW ? sw::CULL_COUNTERCLOCKWISE : sw::CULL_CLOCKWISE);
+ case GL_FRONT_AND_BACK:
+ return sw::CULL_NONE; // culling will be handled during draw
+ default: UNREACHABLE();
+ }
+
+ return sw::CULL_COUNTERCLOCKWISE;
+ }
+
+ unsigned int ConvertColorMask(bool red, bool green, bool blue, bool alpha)
+ {
+ return (red ? 0x00000001 : 0) |
+ (green ? 0x00000002 : 0) |
+ (blue ? 0x00000004 : 0) |
+ (alpha ? 0x00000008 : 0);
+ }
+
+ sw::FilterType ConvertMagFilter(GLenum magFilter)
+ {
+ switch(magFilter)
+ {
+ case GL_NEAREST: return sw::FILTER_POINT;
+ case GL_LINEAR: return sw::FILTER_LINEAR;
+ default: UNREACHABLE();
+ }
+
+ return sw::FILTER_POINT;
+ }
+
+ void ConvertMinFilter(GLenum texFilter, sw::FilterType *minFilter, sw::MipmapType *mipFilter, float maxAnisotropy)
+ {
+ switch(texFilter)
+ {
+ case GL_NEAREST:
+ *minFilter = sw::FILTER_POINT;
+ *mipFilter = sw::MIPMAP_NONE;
+ break;
+ case GL_LINEAR:
+ *minFilter = sw::FILTER_LINEAR;
+ *mipFilter = sw::MIPMAP_NONE;
+ break;
+ case GL_NEAREST_MIPMAP_NEAREST:
+ *minFilter = sw::FILTER_POINT;
+ *mipFilter = sw::MIPMAP_POINT;
+ break;
+ case GL_LINEAR_MIPMAP_NEAREST:
+ *minFilter = sw::FILTER_LINEAR;
+ *mipFilter = sw::MIPMAP_POINT;
+ break;
+ case GL_NEAREST_MIPMAP_LINEAR:
+ *minFilter = sw::FILTER_POINT;
+ *mipFilter = sw::MIPMAP_LINEAR;
+ break;
+ case GL_LINEAR_MIPMAP_LINEAR:
+ *minFilter = sw::FILTER_LINEAR;
+ *mipFilter = sw::MIPMAP_LINEAR;
+ break;
+ default:
+ *minFilter = sw::FILTER_POINT;
+ *mipFilter = sw::MIPMAP_NONE;
+ UNREACHABLE();
+ }
+
+ if(maxAnisotropy > 1.0f)
+ {
+ *minFilter = sw::FILTER_ANISOTROPIC;
+ }
+ }
+
+ bool ConvertPrimitiveType(GLenum primitiveType, GLsizei elementCount, gl::PrimitiveType &swPrimitiveType, int &primitiveCount)
+ {
+ switch(primitiveType)
+ {
+ case GL_POINTS:
+ swPrimitiveType = gl::DRAW_POINTLIST;
+ primitiveCount = elementCount;
+ break;
+ case GL_LINES:
+ swPrimitiveType = gl::DRAW_LINELIST;
+ primitiveCount = elementCount / 2;
+ break;
+ case GL_LINE_LOOP:
+ swPrimitiveType = gl::DRAW_LINELOOP;
+ primitiveCount = elementCount;
+ break;
+ case GL_LINE_STRIP:
+ swPrimitiveType = gl::DRAW_LINESTRIP;
+ primitiveCount = elementCount - 1;
+ break;
+ case GL_TRIANGLES:
+ swPrimitiveType = gl::DRAW_TRIANGLELIST;
+ primitiveCount = elementCount / 3;
+ break;
+ case GL_TRIANGLE_STRIP:
+ swPrimitiveType = gl::DRAW_TRIANGLESTRIP;
+ primitiveCount = elementCount - 2;
+ break;
+ case GL_TRIANGLE_FAN:
+ swPrimitiveType = gl::DRAW_TRIANGLEFAN;
+ primitiveCount = elementCount - 2;
+ break;
+ default:
+ return false;
+ }
+
+ return true;
+ }
+
+ sw::Format ConvertRenderbufferFormat(GLenum format)
+ {
+ switch(format)
+ {
+ case GL_RGBA4:
+ case GL_RGB5_A1:
+ case GL_RGBA8_OES: return sw::FORMAT_A8R8G8B8;
+ case GL_RGB565: return sw::FORMAT_R5G6B5;
+ case GL_RGB8_OES: return sw::FORMAT_X8R8G8B8;
+ case GL_DEPTH_COMPONENT16:
+ case GL_STENCIL_INDEX8:
+ case GL_DEPTH24_STENCIL8_OES: return sw::FORMAT_D24S8;
+ default: UNREACHABLE(); return sw::FORMAT_A8R8G8B8;
+ }
+ }
+}
+
+namespace sw2es
+{
+ unsigned int GetStencilSize(sw::Format stencilFormat)
+ {
+ switch(stencilFormat)
+ {
+ case sw::FORMAT_D24FS8:
+ case sw::FORMAT_D24S8:
+ case sw::FORMAT_D32FS8_TEXTURE:
+ return 8;
+ // case sw::FORMAT_D24X4S4:
+ // return 4;
+ // case sw::FORMAT_D15S1:
+ // return 1;
+ // case sw::FORMAT_D16_LOCKABLE:
+ case sw::FORMAT_D32:
+ case sw::FORMAT_D24X8:
+ case sw::FORMAT_D32F_LOCKABLE:
+ case sw::FORMAT_D16:
+ return 0;
+ // case sw::FORMAT_D32_LOCKABLE: return 0;
+ // case sw::FORMAT_S8_LOCKABLE: return 8;
+ default:
+ return 0;
+ }
+ }
+
+ unsigned int GetAlphaSize(sw::Format colorFormat)
+ {
+ switch(colorFormat)
+ {
+ case sw::FORMAT_A16B16G16R16F:
+ return 16;
+ case sw::FORMAT_A32B32G32R32F:
+ return 32;
+ case sw::FORMAT_A2R10G10B10:
+ return 2;
+ case sw::FORMAT_A8R8G8B8:
+ return 8;
+ case sw::FORMAT_A1R5G5B5:
+ return 1;
+ case sw::FORMAT_X8R8G8B8:
+ case sw::FORMAT_R5G6B5:
+ return 0;
+ default:
+ return 0;
+ }
+ }
+
+ unsigned int GetRedSize(sw::Format colorFormat)
+ {
+ switch(colorFormat)
+ {
+ case sw::FORMAT_A16B16G16R16F:
+ return 16;
+ case sw::FORMAT_A32B32G32R32F:
+ return 32;
+ case sw::FORMAT_A2R10G10B10:
+ return 10;
+ case sw::FORMAT_A8R8G8B8:
+ case sw::FORMAT_X8R8G8B8:
+ return 8;
+ case sw::FORMAT_A1R5G5B5:
+ case sw::FORMAT_R5G6B5:
+ return 5;
+ default:
+ return 0;
+ }
+ }
+
+ unsigned int GetGreenSize(sw::Format colorFormat)
+ {
+ switch(colorFormat)
+ {
+ case sw::FORMAT_A16B16G16R16F:
+ return 16;
+ case sw::FORMAT_A32B32G32R32F:
+ return 32;
+ case sw::FORMAT_A2R10G10B10:
+ return 10;
+ case sw::FORMAT_A8R8G8B8:
+ case sw::FORMAT_X8R8G8B8:
+ return 8;
+ case sw::FORMAT_A1R5G5B5:
+ return 5;
+ case sw::FORMAT_R5G6B5:
+ return 6;
+ default:
+ return 0;
+ }
+ }
+
+ unsigned int GetBlueSize(sw::Format colorFormat)
+ {
+ switch(colorFormat)
+ {
+ case sw::FORMAT_A16B16G16R16F:
+ return 16;
+ case sw::FORMAT_A32B32G32R32F:
+ return 32;
+ case sw::FORMAT_A2R10G10B10:
+ return 10;
+ case sw::FORMAT_A8R8G8B8:
+ case sw::FORMAT_X8R8G8B8:
+ return 8;
+ case sw::FORMAT_A1R5G5B5:
+ case sw::FORMAT_R5G6B5:
+ return 5;
+ default:
+ return 0;
+ }
+ }
+
+ unsigned int GetDepthSize(sw::Format depthFormat)
+ {
+ switch(depthFormat)
+ {
+ // case sw::FORMAT_D16_LOCKABLE: return 16;
+ case sw::FORMAT_D32: return 32;
+ // case sw::FORMAT_D15S1: return 15;
+ case sw::FORMAT_D24S8: return 24;
+ case sw::FORMAT_D24X8: return 24;
+ // case sw::FORMAT_D24X4S4: return 24;
+ case sw::FORMAT_D16: return 16;
+ case sw::FORMAT_D32F_LOCKABLE: return 32;
+ case sw::FORMAT_D24FS8: return 24;
+ // case sw::FORMAT_D32_LOCKABLE: return 32;
+ // case sw::FORMAT_S8_LOCKABLE: return 0;
+ case sw::FORMAT_D32FS8_TEXTURE: return 32;
+ default: return 0;
+ }
+ }
+
+ GLenum ConvertBackBufferFormat(sw::Format format)
+ {
+ switch(format)
+ {
+ case sw::FORMAT_A4R4G4B4: return GL_RGBA4;
+ case sw::FORMAT_A8R8G8B8: return GL_RGBA8_OES;
+ case sw::FORMAT_A1R5G5B5: return GL_RGB5_A1;
+ case sw::FORMAT_R5G6B5: return GL_RGB565;
+ case sw::FORMAT_X8R8G8B8: return GL_RGB8_OES;
+ default:
+ UNREACHABLE();
+ }
+
+ return GL_RGBA4;
+ }
+
+ GLenum ConvertDepthStencilFormat(sw::Format format)
+ {
+ switch(format)
+ {
+ case sw::FORMAT_D16:
+ case sw::FORMAT_D24X8:
+ case sw::FORMAT_D32:
+ return GL_DEPTH_COMPONENT16;
+ case sw::FORMAT_D24S8:
+ return GL_DEPTH24_STENCIL8_OES;
+ default:
+ UNREACHABLE();
+ }
+
+ return GL_DEPTH24_STENCIL8_OES;
+ }
+}
diff --git a/src/GLES2/libGLES_CM/utilities.h b/src/GLES2/libGLES_CM/utilities.h
new file mode 100644
index 0000000..8475050
--- /dev/null
+++ b/src/GLES2/libGLES_CM/utilities.h
@@ -0,0 +1,86 @@
+// SwiftShader Software Renderer
+//
+// Copyright(c) 2005-2013 TransGaming Inc.
+//
+// All rights reserved. No part of this software may be copied, distributed, transmitted,
+// transcribed, stored in a retrieval system, translated into any human or computer
+// language by any means, or disclosed to third parties without the explicit written
+// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
+// or implied, including but not limited to any patent rights, are granted to you.
+//
+
+// utilities.h: Conversion functions and other utility routines.
+
+#ifndef LIBGLESV2_UTILITIES_H
+#define LIBGLESV2_UTILITIES_H
+
+#include "Device.hpp"
+#include "Image.hpp"
+#include "Texture.h"
+
+#define GL_APICALL
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#include <string>
+
+namespace gl
+{
+ struct Color;
+
+ int UniformComponentCount(GLenum type);
+ GLenum UniformComponentType(GLenum type);
+ size_t UniformTypeSize(GLenum type);
+ int VariableRowCount(GLenum type);
+ int VariableColumnCount(GLenum type);
+
+ int AllocateFirstFreeBits(unsigned int *bits, unsigned int allocationSize, unsigned int bitsSize);
+
+ int ComputePixelSize(GLenum format, GLenum type);
+ GLsizei ComputePitch(GLsizei width, GLenum format, GLenum type, 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);
+ int CubeFaceIndex(GLenum cubeTarget);
+ bool IsTextureTarget(GLenum target);
+ bool CheckTextureFormatType(GLenum format, GLenum type);
+
+ bool IsColorRenderable(GLenum internalformat);
+ bool IsDepthRenderable(GLenum internalformat);
+ bool IsStencilRenderable(GLenum internalformat);
+}
+
+namespace es2sw
+{
+ sw::DepthCompareMode ConvertDepthComparison(GLenum comparison);
+ sw::StencilCompareMode ConvertStencilComparison(GLenum comparison);
+ sw::Color<float> ConvertColor(gl::Color color);
+ sw::BlendFactor ConvertBlendFunc(GLenum blend);
+ sw::BlendOperation ConvertBlendOp(GLenum blendOp);
+ sw::StencilOperation ConvertStencilOp(GLenum stencilOp);
+ sw::AddressingMode ConvertTextureWrap(GLenum wrap);
+ sw::CullMode ConvertCullMode(GLenum cullFace, GLenum frontFace);
+ unsigned int ConvertColorMask(bool red, bool green, bool blue, bool alpha);
+ sw::FilterType ConvertMagFilter(GLenum magFilter);
+ void ConvertMinFilter(GLenum texFilter, sw::FilterType *minFilter, sw::MipmapType *mipFilter, float maxAnisotropy);
+ bool ConvertPrimitiveType(GLenum primitiveType, GLsizei elementCount, gl::PrimitiveType &swPrimitiveType, int &primitiveCount);
+ sw::Format ConvertRenderbufferFormat(GLenum format);
+}
+
+namespace sw2es
+{
+ GLuint GetAlphaSize(sw::Format colorFormat);
+ GLuint GetRedSize(sw::Format colorFormat);
+ GLuint GetGreenSize(sw::Format colorFormat);
+ GLuint GetBlueSize(sw::Format colorFormat);
+ GLuint GetDepthSize(sw::Format depthFormat);
+ GLuint GetStencilSize(sw::Format stencilFormat);
+
+ GLenum ConvertBackBufferFormat(sw::Format format);
+ GLenum ConvertDepthStencilFormat(sw::Format format);
+}
+
+#endif // LIBGLESV2_UTILITIES_H