michael@0: #include "precompiled.h" michael@0: // michael@0: // Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. michael@0: // Use of this source code is governed by a BSD-style license that can be michael@0: // found in the LICENSE file. michael@0: // michael@0: michael@0: // Program.cpp: Implements the gl::Program class. Implements GL program objects michael@0: // and related functionality. [OpenGL ES 2.0.24] section 2.10.3 page 28. michael@0: michael@0: #include "libGLESv2/BinaryStream.h" michael@0: #include "libGLESv2/ProgramBinary.h" michael@0: #include "libGLESv2/renderer/ShaderExecutable.h" michael@0: michael@0: #include "common/debug.h" michael@0: #include "common/version.h" michael@0: #include "utilities.h" michael@0: michael@0: #include "libGLESv2/main.h" michael@0: #include "libGLESv2/Shader.h" michael@0: #include "libGLESv2/Program.h" michael@0: #include "libGLESv2/renderer/Renderer.h" michael@0: #include "libGLESv2/renderer/VertexDataManager.h" michael@0: michael@0: #include michael@0: michael@0: #undef near michael@0: #undef far michael@0: michael@0: namespace gl michael@0: { michael@0: std::string str(int i) michael@0: { michael@0: char buffer[20]; michael@0: snprintf(buffer, sizeof(buffer), "%d", i); michael@0: return buffer; michael@0: } michael@0: michael@0: UniformLocation::UniformLocation(const std::string &name, unsigned int element, unsigned int index) michael@0: : name(name), element(element), index(index) michael@0: { michael@0: } michael@0: michael@0: unsigned int ProgramBinary::mCurrentSerial = 1; michael@0: michael@0: ProgramBinary::ProgramBinary(rx::Renderer *renderer) : mRenderer(renderer), RefCountObject(0), mSerial(issueSerial()) michael@0: { michael@0: mPixelExecutable = NULL; michael@0: mVertexExecutable = NULL; michael@0: mGeometryExecutable = NULL; michael@0: michael@0: mValidated = false; michael@0: michael@0: for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++) michael@0: { michael@0: mSemanticIndex[index] = -1; michael@0: } michael@0: michael@0: for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++) michael@0: { michael@0: mSamplersPS[index].active = false; michael@0: } michael@0: michael@0: for (int index = 0; index < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; index++) michael@0: { michael@0: mSamplersVS[index].active = false; michael@0: } michael@0: michael@0: mUsedVertexSamplerRange = 0; michael@0: mUsedPixelSamplerRange = 0; michael@0: mUsesPointSize = false; michael@0: } michael@0: michael@0: ProgramBinary::~ProgramBinary() michael@0: { michael@0: delete mPixelExecutable; michael@0: mPixelExecutable = NULL; michael@0: michael@0: delete mVertexExecutable; michael@0: mVertexExecutable = NULL; michael@0: michael@0: delete mGeometryExecutable; michael@0: mGeometryExecutable = NULL; michael@0: michael@0: while (!mUniforms.empty()) michael@0: { michael@0: delete mUniforms.back(); michael@0: mUniforms.pop_back(); michael@0: } michael@0: } michael@0: michael@0: unsigned int ProgramBinary::getSerial() const michael@0: { michael@0: return mSerial; michael@0: } michael@0: michael@0: unsigned int ProgramBinary::issueSerial() michael@0: { michael@0: return mCurrentSerial++; michael@0: } michael@0: michael@0: rx::ShaderExecutable *ProgramBinary::getPixelExecutable() michael@0: { michael@0: return mPixelExecutable; michael@0: } michael@0: michael@0: rx::ShaderExecutable *ProgramBinary::getVertexExecutable() michael@0: { michael@0: return mVertexExecutable; michael@0: } michael@0: michael@0: rx::ShaderExecutable *ProgramBinary::getGeometryExecutable() michael@0: { michael@0: return mGeometryExecutable; michael@0: } michael@0: michael@0: GLuint ProgramBinary::getAttributeLocation(const char *name) michael@0: { michael@0: if (name) michael@0: { michael@0: for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++) michael@0: { michael@0: if (mLinkedAttribute[index].name == std::string(name)) michael@0: { michael@0: return index; michael@0: } michael@0: } michael@0: } michael@0: michael@0: return -1; michael@0: } michael@0: michael@0: int ProgramBinary::getSemanticIndex(int attributeIndex) michael@0: { michael@0: ASSERT(attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS); michael@0: michael@0: return mSemanticIndex[attributeIndex]; michael@0: } michael@0: michael@0: // Returns one more than the highest sampler index used. michael@0: GLint ProgramBinary::getUsedSamplerRange(SamplerType type) michael@0: { michael@0: switch (type) michael@0: { michael@0: case SAMPLER_PIXEL: michael@0: return mUsedPixelSamplerRange; michael@0: case SAMPLER_VERTEX: michael@0: return mUsedVertexSamplerRange; michael@0: default: michael@0: UNREACHABLE(); michael@0: return 0; michael@0: } michael@0: } michael@0: michael@0: bool ProgramBinary::usesPointSize() const michael@0: { michael@0: return mUsesPointSize; michael@0: } michael@0: michael@0: bool ProgramBinary::usesPointSpriteEmulation() const michael@0: { michael@0: return mUsesPointSize && mRenderer->getMajorShaderModel() >= 4; michael@0: } michael@0: michael@0: bool ProgramBinary::usesGeometryShader() const michael@0: { michael@0: return usesPointSpriteEmulation(); michael@0: } michael@0: michael@0: // Returns the index of the texture image unit (0-19) corresponding to a Direct3D 9 sampler michael@0: // index (0-15 for the pixel shader and 0-3 for the vertex shader). michael@0: GLint ProgramBinary::getSamplerMapping(SamplerType type, unsigned int samplerIndex) michael@0: { michael@0: GLint logicalTextureUnit = -1; michael@0: michael@0: switch (type) michael@0: { michael@0: case SAMPLER_PIXEL: michael@0: ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0])); michael@0: michael@0: if (mSamplersPS[samplerIndex].active) michael@0: { michael@0: logicalTextureUnit = mSamplersPS[samplerIndex].logicalTextureUnit; michael@0: } michael@0: break; michael@0: case SAMPLER_VERTEX: michael@0: ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0])); michael@0: michael@0: if (mSamplersVS[samplerIndex].active) michael@0: { michael@0: logicalTextureUnit = mSamplersVS[samplerIndex].logicalTextureUnit; michael@0: } michael@0: break; michael@0: default: UNREACHABLE(); michael@0: } michael@0: michael@0: if (logicalTextureUnit >= 0 && logicalTextureUnit < (GLint)mRenderer->getMaxCombinedTextureImageUnits()) michael@0: { michael@0: return logicalTextureUnit; michael@0: } michael@0: michael@0: return -1; michael@0: } michael@0: michael@0: // Returns the texture type for a given Direct3D 9 sampler type and michael@0: // index (0-15 for the pixel shader and 0-3 for the vertex shader). michael@0: TextureType ProgramBinary::getSamplerTextureType(SamplerType type, unsigned int samplerIndex) michael@0: { michael@0: switch (type) michael@0: { michael@0: case SAMPLER_PIXEL: michael@0: ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0])); michael@0: ASSERT(mSamplersPS[samplerIndex].active); michael@0: return mSamplersPS[samplerIndex].textureType; michael@0: case SAMPLER_VERTEX: michael@0: ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0])); michael@0: ASSERT(mSamplersVS[samplerIndex].active); michael@0: return mSamplersVS[samplerIndex].textureType; michael@0: default: UNREACHABLE(); michael@0: } michael@0: michael@0: return TEXTURE_2D; michael@0: } michael@0: michael@0: GLint ProgramBinary::getUniformLocation(std::string name) michael@0: { michael@0: unsigned int subscript = 0; michael@0: michael@0: // Strip any trailing array operator and retrieve the subscript michael@0: size_t open = name.find_last_of('['); michael@0: size_t close = name.find_last_of(']'); michael@0: if (open != std::string::npos && close == name.length() - 1) michael@0: { michael@0: subscript = atoi(name.substr(open + 1).c_str()); michael@0: name.erase(open); michael@0: } michael@0: michael@0: unsigned int numUniforms = mUniformIndex.size(); michael@0: for (unsigned int location = 0; location < numUniforms; location++) michael@0: { michael@0: if (mUniformIndex[location].name == name && michael@0: mUniformIndex[location].element == subscript) michael@0: { michael@0: return location; michael@0: } michael@0: } michael@0: michael@0: return -1; michael@0: } michael@0: michael@0: bool ProgramBinary::setUniform1fv(GLint location, GLsizei count, const GLfloat* v) michael@0: { michael@0: if (location < 0 || location >= (int)mUniformIndex.size()) michael@0: { michael@0: return false; michael@0: } michael@0: michael@0: Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; michael@0: targetUniform->dirty = true; michael@0: michael@0: int elementCount = targetUniform->elementCount(); michael@0: michael@0: if (elementCount == 1 && count > 1) michael@0: return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION michael@0: michael@0: count = std::min(elementCount - (int)mUniformIndex[location].element, count); michael@0: michael@0: if (targetUniform->type == GL_FLOAT) michael@0: { michael@0: GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4; michael@0: michael@0: for (int i = 0; i < count; i++) michael@0: { michael@0: target[0] = v[0]; michael@0: target[1] = 0; michael@0: target[2] = 0; michael@0: target[3] = 0; michael@0: target += 4; michael@0: v += 1; michael@0: } michael@0: } michael@0: else if (targetUniform->type == GL_BOOL) michael@0: { michael@0: GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4; michael@0: michael@0: for (int i = 0; i < count; i++) michael@0: { michael@0: boolParams[0] = (v[0] == 0.0f) ? GL_FALSE : GL_TRUE; michael@0: boolParams[1] = GL_FALSE; michael@0: boolParams[2] = GL_FALSE; michael@0: boolParams[3] = GL_FALSE; michael@0: boolParams += 4; michael@0: v += 1; michael@0: } michael@0: } michael@0: else michael@0: { michael@0: return false; michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool ProgramBinary::setUniform2fv(GLint location, GLsizei count, const GLfloat *v) michael@0: { michael@0: if (location < 0 || location >= (int)mUniformIndex.size()) michael@0: { michael@0: return false; michael@0: } michael@0: michael@0: Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; michael@0: targetUniform->dirty = true; michael@0: michael@0: int elementCount = targetUniform->elementCount(); michael@0: michael@0: if (elementCount == 1 && count > 1) michael@0: return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION michael@0: michael@0: count = std::min(elementCount - (int)mUniformIndex[location].element, count); michael@0: michael@0: if (targetUniform->type == GL_FLOAT_VEC2) michael@0: { michael@0: GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4; michael@0: michael@0: for (int i = 0; i < count; i++) michael@0: { michael@0: target[0] = v[0]; michael@0: target[1] = v[1]; michael@0: target[2] = 0; michael@0: target[3] = 0; michael@0: target += 4; michael@0: v += 2; michael@0: } michael@0: } michael@0: else if (targetUniform->type == GL_BOOL_VEC2) michael@0: { michael@0: GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4; michael@0: michael@0: for (int i = 0; i < count; i++) michael@0: { michael@0: boolParams[0] = (v[0] == 0.0f) ? GL_FALSE : GL_TRUE; michael@0: boolParams[1] = (v[1] == 0.0f) ? GL_FALSE : GL_TRUE; michael@0: boolParams[2] = GL_FALSE; michael@0: boolParams[3] = GL_FALSE; michael@0: boolParams += 4; michael@0: v += 2; michael@0: } michael@0: } michael@0: else michael@0: { michael@0: return false; michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool ProgramBinary::setUniform3fv(GLint location, GLsizei count, const GLfloat *v) michael@0: { michael@0: if (location < 0 || location >= (int)mUniformIndex.size()) michael@0: { michael@0: return false; michael@0: } michael@0: michael@0: Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; michael@0: targetUniform->dirty = true; michael@0: michael@0: int elementCount = targetUniform->elementCount(); michael@0: michael@0: if (elementCount == 1 && count > 1) michael@0: return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION michael@0: michael@0: count = std::min(elementCount - (int)mUniformIndex[location].element, count); michael@0: michael@0: if (targetUniform->type == GL_FLOAT_VEC3) michael@0: { michael@0: GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4; michael@0: michael@0: for (int i = 0; i < count; i++) michael@0: { michael@0: target[0] = v[0]; michael@0: target[1] = v[1]; michael@0: target[2] = v[2]; michael@0: target[3] = 0; michael@0: target += 4; michael@0: v += 3; michael@0: } michael@0: } michael@0: else if (targetUniform->type == GL_BOOL_VEC3) michael@0: { michael@0: GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4; michael@0: michael@0: for (int i = 0; i < count; i++) michael@0: { michael@0: boolParams[0] = (v[0] == 0.0f) ? GL_FALSE : GL_TRUE; michael@0: boolParams[1] = (v[1] == 0.0f) ? GL_FALSE : GL_TRUE; michael@0: boolParams[2] = (v[2] == 0.0f) ? GL_FALSE : GL_TRUE; michael@0: boolParams[3] = GL_FALSE; michael@0: boolParams += 4; michael@0: v += 3; michael@0: } michael@0: } michael@0: else michael@0: { michael@0: return false; michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool ProgramBinary::setUniform4fv(GLint location, GLsizei count, const GLfloat *v) michael@0: { michael@0: if (location < 0 || location >= (int)mUniformIndex.size()) michael@0: { michael@0: return false; michael@0: } michael@0: michael@0: Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; michael@0: targetUniform->dirty = true; michael@0: michael@0: int elementCount = targetUniform->elementCount(); michael@0: michael@0: if (elementCount == 1 && count > 1) michael@0: return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION michael@0: michael@0: count = std::min(elementCount - (int)mUniformIndex[location].element, count); michael@0: michael@0: if (targetUniform->type == GL_FLOAT_VEC4) michael@0: { michael@0: GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4; michael@0: michael@0: for (int i = 0; i < count; i++) michael@0: { michael@0: target[0] = v[0]; michael@0: target[1] = v[1]; michael@0: target[2] = v[2]; michael@0: target[3] = v[3]; michael@0: target += 4; michael@0: v += 4; michael@0: } michael@0: } michael@0: else if (targetUniform->type == GL_BOOL_VEC4) michael@0: { michael@0: GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4; michael@0: michael@0: for (int i = 0; i < count; i++) michael@0: { michael@0: boolParams[0] = (v[0] == 0.0f) ? GL_FALSE : GL_TRUE; michael@0: boolParams[1] = (v[1] == 0.0f) ? GL_FALSE : GL_TRUE; michael@0: boolParams[2] = (v[2] == 0.0f) ? GL_FALSE : GL_TRUE; michael@0: boolParams[3] = (v[3] == 0.0f) ? GL_FALSE : GL_TRUE; michael@0: boolParams += 4; michael@0: v += 4; michael@0: } michael@0: } michael@0: else michael@0: { michael@0: return false; michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: template michael@0: void transposeMatrix(T *target, const GLfloat *value) michael@0: { michael@0: int copyWidth = std::min(targetWidth, srcWidth); michael@0: int copyHeight = std::min(targetHeight, srcHeight); michael@0: michael@0: for (int x = 0; x < copyWidth; x++) michael@0: { michael@0: for (int y = 0; y < copyHeight; y++) michael@0: { michael@0: target[x * targetWidth + y] = (T)value[y * srcWidth + x]; michael@0: } michael@0: } michael@0: // clear unfilled right side michael@0: for (int y = 0; y < copyHeight; y++) michael@0: { michael@0: for (int x = srcWidth; x < targetWidth; x++) michael@0: { michael@0: target[y * targetWidth + x] = (T)0; michael@0: } michael@0: } michael@0: // clear unfilled bottom. michael@0: for (int y = srcHeight; y < targetHeight; y++) michael@0: { michael@0: for (int x = 0; x < targetWidth; x++) michael@0: { michael@0: target[y * targetWidth + x] = (T)0; michael@0: } michael@0: } michael@0: } michael@0: michael@0: bool ProgramBinary::setUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value) michael@0: { michael@0: if (location < 0 || location >= (int)mUniformIndex.size()) michael@0: { michael@0: return false; michael@0: } michael@0: michael@0: Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; michael@0: targetUniform->dirty = true; michael@0: michael@0: if (targetUniform->type != GL_FLOAT_MAT2) michael@0: { michael@0: return false; michael@0: } michael@0: michael@0: int elementCount = targetUniform->elementCount(); michael@0: michael@0: if (elementCount == 1 && count > 1) michael@0: return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION michael@0: michael@0: count = std::min(elementCount - (int)mUniformIndex[location].element, count); michael@0: GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8; michael@0: michael@0: for (int i = 0; i < count; i++) michael@0: { michael@0: transposeMatrix(target, value); michael@0: target += 8; michael@0: value += 4; michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool ProgramBinary::setUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value) michael@0: { michael@0: if (location < 0 || location >= (int)mUniformIndex.size()) michael@0: { michael@0: return false; michael@0: } michael@0: michael@0: Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; michael@0: targetUniform->dirty = true; michael@0: michael@0: if (targetUniform->type != GL_FLOAT_MAT3) michael@0: { michael@0: return false; michael@0: } michael@0: michael@0: int elementCount = targetUniform->elementCount(); michael@0: michael@0: if (elementCount == 1 && count > 1) michael@0: return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION michael@0: michael@0: count = std::min(elementCount - (int)mUniformIndex[location].element, count); michael@0: GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12; michael@0: michael@0: for (int i = 0; i < count; i++) michael@0: { michael@0: transposeMatrix(target, value); michael@0: target += 12; michael@0: value += 9; michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: michael@0: bool ProgramBinary::setUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value) michael@0: { michael@0: if (location < 0 || location >= (int)mUniformIndex.size()) michael@0: { michael@0: return false; michael@0: } michael@0: michael@0: Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; michael@0: targetUniform->dirty = true; michael@0: michael@0: if (targetUniform->type != GL_FLOAT_MAT4) michael@0: { michael@0: return false; michael@0: } michael@0: michael@0: int elementCount = targetUniform->elementCount(); michael@0: michael@0: if (elementCount == 1 && count > 1) michael@0: return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION michael@0: michael@0: count = std::min(elementCount - (int)mUniformIndex[location].element, count); michael@0: GLfloat *target = (GLfloat*)(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 16); michael@0: michael@0: for (int i = 0; i < count; i++) michael@0: { michael@0: transposeMatrix(target, value); michael@0: target += 16; michael@0: value += 16; michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool ProgramBinary::setUniform1iv(GLint location, GLsizei count, const GLint *v) michael@0: { michael@0: if (location < 0 || location >= (int)mUniformIndex.size()) michael@0: { michael@0: return false; michael@0: } michael@0: michael@0: Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; michael@0: targetUniform->dirty = true; michael@0: michael@0: int elementCount = targetUniform->elementCount(); michael@0: michael@0: if (elementCount == 1 && count > 1) michael@0: return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION michael@0: michael@0: count = std::min(elementCount - (int)mUniformIndex[location].element, count); michael@0: michael@0: if (targetUniform->type == GL_INT || michael@0: targetUniform->type == GL_SAMPLER_2D || michael@0: targetUniform->type == GL_SAMPLER_CUBE) michael@0: { michael@0: GLint *target = (GLint*)targetUniform->data + mUniformIndex[location].element * 4; michael@0: michael@0: for (int i = 0; i < count; i++) michael@0: { michael@0: target[0] = v[0]; michael@0: target[1] = 0; michael@0: target[2] = 0; michael@0: target[3] = 0; michael@0: target += 4; michael@0: v += 1; michael@0: } michael@0: } michael@0: else if (targetUniform->type == GL_BOOL) michael@0: { michael@0: GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4; michael@0: michael@0: for (int i = 0; i < count; i++) michael@0: { michael@0: boolParams[0] = (v[0] == 0) ? GL_FALSE : GL_TRUE; michael@0: boolParams[1] = GL_FALSE; michael@0: boolParams[2] = GL_FALSE; michael@0: boolParams[3] = GL_FALSE; michael@0: boolParams += 4; michael@0: v += 1; michael@0: } michael@0: } michael@0: else michael@0: { michael@0: return false; michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool ProgramBinary::setUniform2iv(GLint location, GLsizei count, const GLint *v) michael@0: { michael@0: if (location < 0 || location >= (int)mUniformIndex.size()) michael@0: { michael@0: return false; michael@0: } michael@0: michael@0: Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; michael@0: targetUniform->dirty = true; michael@0: michael@0: int elementCount = targetUniform->elementCount(); michael@0: michael@0: if (elementCount == 1 && count > 1) michael@0: return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION michael@0: michael@0: count = std::min(elementCount - (int)mUniformIndex[location].element, count); michael@0: michael@0: if (targetUniform->type == GL_INT_VEC2) michael@0: { michael@0: GLint *target = (GLint*)targetUniform->data + mUniformIndex[location].element * 4; michael@0: michael@0: for (int i = 0; i < count; i++) michael@0: { michael@0: target[0] = v[0]; michael@0: target[1] = v[1]; michael@0: target[2] = 0; michael@0: target[3] = 0; michael@0: target += 4; michael@0: v += 2; michael@0: } michael@0: } michael@0: else if (targetUniform->type == GL_BOOL_VEC2) michael@0: { michael@0: GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4; michael@0: michael@0: for (int i = 0; i < count; i++) michael@0: { michael@0: boolParams[0] = (v[0] == 0) ? GL_FALSE : GL_TRUE; michael@0: boolParams[1] = (v[1] == 0) ? GL_FALSE : GL_TRUE; michael@0: boolParams[2] = GL_FALSE; michael@0: boolParams[3] = GL_FALSE; michael@0: boolParams += 4; michael@0: v += 2; michael@0: } michael@0: } michael@0: else michael@0: { michael@0: return false; michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool ProgramBinary::setUniform3iv(GLint location, GLsizei count, const GLint *v) michael@0: { michael@0: if (location < 0 || location >= (int)mUniformIndex.size()) michael@0: { michael@0: return false; michael@0: } michael@0: michael@0: Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; michael@0: targetUniform->dirty = true; michael@0: michael@0: int elementCount = targetUniform->elementCount(); michael@0: michael@0: if (elementCount == 1 && count > 1) michael@0: return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION michael@0: michael@0: count = std::min(elementCount - (int)mUniformIndex[location].element, count); michael@0: michael@0: if (targetUniform->type == GL_INT_VEC3) michael@0: { michael@0: GLint *target = (GLint*)targetUniform->data + mUniformIndex[location].element * 4; michael@0: michael@0: for (int i = 0; i < count; i++) michael@0: { michael@0: target[0] = v[0]; michael@0: target[1] = v[1]; michael@0: target[2] = v[2]; michael@0: target[3] = 0; michael@0: target += 4; michael@0: v += 3; michael@0: } michael@0: } michael@0: else if (targetUniform->type == GL_BOOL_VEC3) michael@0: { michael@0: GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4; michael@0: michael@0: for (int i = 0; i < count; i++) michael@0: { michael@0: boolParams[0] = (v[0] == 0) ? GL_FALSE : GL_TRUE; michael@0: boolParams[1] = (v[1] == 0) ? GL_FALSE : GL_TRUE; michael@0: boolParams[2] = (v[2] == 0) ? GL_FALSE : GL_TRUE; michael@0: boolParams[3] = GL_FALSE; michael@0: boolParams += 4; michael@0: v += 3; michael@0: } michael@0: } michael@0: else michael@0: { michael@0: return false; michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool ProgramBinary::setUniform4iv(GLint location, GLsizei count, const GLint *v) michael@0: { michael@0: if (location < 0 || location >= (int)mUniformIndex.size()) michael@0: { michael@0: return false; michael@0: } michael@0: michael@0: Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; michael@0: targetUniform->dirty = true; michael@0: michael@0: int elementCount = targetUniform->elementCount(); michael@0: michael@0: if (elementCount == 1 && count > 1) michael@0: return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION michael@0: michael@0: count = std::min(elementCount - (int)mUniformIndex[location].element, count); michael@0: michael@0: if (targetUniform->type == GL_INT_VEC4) michael@0: { michael@0: GLint *target = (GLint*)targetUniform->data + mUniformIndex[location].element * 4; michael@0: michael@0: for (int i = 0; i < count; i++) michael@0: { michael@0: target[0] = v[0]; michael@0: target[1] = v[1]; michael@0: target[2] = v[2]; michael@0: target[3] = v[3]; michael@0: target += 4; michael@0: v += 4; michael@0: } michael@0: } michael@0: else if (targetUniform->type == GL_BOOL_VEC4) michael@0: { michael@0: GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4; michael@0: michael@0: for (int i = 0; i < count; i++) michael@0: { michael@0: boolParams[0] = (v[0] == 0) ? GL_FALSE : GL_TRUE; michael@0: boolParams[1] = (v[1] == 0) ? GL_FALSE : GL_TRUE; michael@0: boolParams[2] = (v[2] == 0) ? GL_FALSE : GL_TRUE; michael@0: boolParams[3] = (v[3] == 0) ? GL_FALSE : GL_TRUE; michael@0: boolParams += 4; michael@0: v += 4; michael@0: } michael@0: } michael@0: else michael@0: { michael@0: return false; michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool ProgramBinary::getUniformfv(GLint location, GLsizei *bufSize, GLfloat *params) michael@0: { michael@0: if (location < 0 || location >= (int)mUniformIndex.size()) michael@0: { michael@0: return false; michael@0: } michael@0: michael@0: Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; michael@0: michael@0: // sized queries -- ensure the provided buffer is large enough michael@0: if (bufSize) michael@0: { michael@0: int requiredBytes = UniformExternalSize(targetUniform->type); michael@0: if (*bufSize < requiredBytes) michael@0: { michael@0: return false; michael@0: } michael@0: } michael@0: michael@0: switch (targetUniform->type) michael@0: { michael@0: case GL_FLOAT_MAT2: michael@0: transposeMatrix(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8); michael@0: break; michael@0: case GL_FLOAT_MAT3: michael@0: transposeMatrix(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12); michael@0: break; michael@0: case GL_FLOAT_MAT4: michael@0: transposeMatrix(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 16); michael@0: break; michael@0: default: michael@0: { michael@0: unsigned int size = UniformComponentCount(targetUniform->type); michael@0: michael@0: switch (UniformComponentType(targetUniform->type)) michael@0: { michael@0: case GL_BOOL: michael@0: { michael@0: GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4; michael@0: michael@0: for (unsigned int i = 0; i < size; i++) michael@0: { michael@0: params[i] = (boolParams[i] == GL_FALSE) ? 0.0f : 1.0f; michael@0: } michael@0: } michael@0: break; michael@0: case GL_FLOAT: michael@0: memcpy(params, targetUniform->data + mUniformIndex[location].element * 4 * sizeof(GLfloat), michael@0: size * sizeof(GLfloat)); michael@0: break; michael@0: case GL_INT: michael@0: { michael@0: GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4; michael@0: michael@0: for (unsigned int i = 0; i < size; i++) michael@0: { michael@0: params[i] = (float)intParams[i]; michael@0: } michael@0: } michael@0: break; michael@0: default: UNREACHABLE(); michael@0: } michael@0: } michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool ProgramBinary::getUniformiv(GLint location, GLsizei *bufSize, GLint *params) michael@0: { michael@0: if (location < 0 || location >= (int)mUniformIndex.size()) michael@0: { michael@0: return false; michael@0: } michael@0: michael@0: Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; michael@0: michael@0: // sized queries -- ensure the provided buffer is large enough michael@0: if (bufSize) michael@0: { michael@0: int requiredBytes = UniformExternalSize(targetUniform->type); michael@0: if (*bufSize < requiredBytes) michael@0: { michael@0: return false; michael@0: } michael@0: } michael@0: michael@0: switch (targetUniform->type) michael@0: { michael@0: case GL_FLOAT_MAT2: michael@0: transposeMatrix(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8); michael@0: break; michael@0: case GL_FLOAT_MAT3: michael@0: transposeMatrix(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12); michael@0: break; michael@0: case GL_FLOAT_MAT4: michael@0: transposeMatrix(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 16); michael@0: break; michael@0: default: michael@0: { michael@0: unsigned int size = VariableColumnCount(targetUniform->type); michael@0: michael@0: switch (UniformComponentType(targetUniform->type)) michael@0: { michael@0: case GL_BOOL: michael@0: { michael@0: GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4; michael@0: michael@0: for (unsigned int i = 0; i < size; i++) michael@0: { michael@0: params[i] = boolParams[i]; michael@0: } michael@0: } michael@0: break; michael@0: case GL_FLOAT: michael@0: { michael@0: GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4; michael@0: michael@0: for (unsigned int i = 0; i < size; i++) michael@0: { michael@0: params[i] = (GLint)floatParams[i]; michael@0: } michael@0: } michael@0: break; michael@0: case GL_INT: michael@0: memcpy(params, targetUniform->data + mUniformIndex[location].element * 4 * sizeof(GLint), michael@0: size * sizeof(GLint)); michael@0: break; michael@0: default: UNREACHABLE(); michael@0: } michael@0: } michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: void ProgramBinary::dirtyAllUniforms() michael@0: { michael@0: unsigned int numUniforms = mUniforms.size(); michael@0: for (unsigned int index = 0; index < numUniforms; index++) michael@0: { michael@0: mUniforms[index]->dirty = true; michael@0: } michael@0: } michael@0: michael@0: // Applies all the uniforms set for this program object to the renderer michael@0: void ProgramBinary::applyUniforms() michael@0: { michael@0: // Retrieve sampler uniform values michael@0: for (std::vector::iterator ub = mUniforms.begin(), ue = mUniforms.end(); ub != ue; ++ub) michael@0: { michael@0: Uniform *targetUniform = *ub; michael@0: michael@0: if (targetUniform->dirty) michael@0: { michael@0: if (targetUniform->type == GL_SAMPLER_2D || michael@0: targetUniform->type == GL_SAMPLER_CUBE) michael@0: { michael@0: int count = targetUniform->elementCount(); michael@0: GLint (*v)[4] = (GLint(*)[4])targetUniform->data; michael@0: michael@0: if (targetUniform->psRegisterIndex >= 0) michael@0: { michael@0: unsigned int firstIndex = targetUniform->psRegisterIndex; michael@0: michael@0: for (int i = 0; i < count; i++) michael@0: { michael@0: unsigned int samplerIndex = firstIndex + i; michael@0: michael@0: if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS) michael@0: { michael@0: ASSERT(mSamplersPS[samplerIndex].active); michael@0: mSamplersPS[samplerIndex].logicalTextureUnit = v[i][0]; michael@0: } michael@0: } michael@0: } michael@0: michael@0: if (targetUniform->vsRegisterIndex >= 0) michael@0: { michael@0: unsigned int firstIndex = targetUniform->vsRegisterIndex; michael@0: michael@0: for (int i = 0; i < count; i++) michael@0: { michael@0: unsigned int samplerIndex = firstIndex + i; michael@0: michael@0: if (samplerIndex < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS) michael@0: { michael@0: ASSERT(mSamplersVS[samplerIndex].active); michael@0: mSamplersVS[samplerIndex].logicalTextureUnit = v[i][0]; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: mRenderer->applyUniforms(this, &mUniforms); michael@0: } michael@0: michael@0: // Packs varyings into generic varying registers, using the algorithm from [OpenGL ES Shading Language 1.00 rev. 17] appendix A section 7 page 111 michael@0: // Returns the number of used varying registers, or -1 if unsuccesful michael@0: int ProgramBinary::packVaryings(InfoLog &infoLog, const Varying *packing[][4], FragmentShader *fragmentShader) michael@0: { michael@0: const int maxVaryingVectors = mRenderer->getMaxVaryingVectors(); michael@0: michael@0: fragmentShader->resetVaryingsRegisterAssignment(); michael@0: michael@0: for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++) michael@0: { michael@0: int n = VariableRowCount(varying->type) * varying->size; michael@0: int m = VariableColumnCount(varying->type); michael@0: bool success = false; michael@0: michael@0: if (m == 2 || m == 3 || m == 4) michael@0: { michael@0: for (int r = 0; r <= maxVaryingVectors - n && !success; r++) michael@0: { michael@0: bool available = true; michael@0: michael@0: for (int y = 0; y < n && available; y++) michael@0: { michael@0: for (int x = 0; x < m && available; x++) michael@0: { michael@0: if (packing[r + y][x]) michael@0: { michael@0: available = false; michael@0: } michael@0: } michael@0: } michael@0: michael@0: if (available) michael@0: { michael@0: varying->reg = r; michael@0: varying->col = 0; michael@0: michael@0: for (int y = 0; y < n; y++) michael@0: { michael@0: for (int x = 0; x < m; x++) michael@0: { michael@0: packing[r + y][x] = &*varying; michael@0: } michael@0: } michael@0: michael@0: success = true; michael@0: } michael@0: } michael@0: michael@0: if (!success && m == 2) michael@0: { michael@0: for (int r = maxVaryingVectors - n; r >= 0 && !success; r--) michael@0: { michael@0: bool available = true; michael@0: michael@0: for (int y = 0; y < n && available; y++) michael@0: { michael@0: for (int x = 2; x < 4 && available; x++) michael@0: { michael@0: if (packing[r + y][x]) michael@0: { michael@0: available = false; michael@0: } michael@0: } michael@0: } michael@0: michael@0: if (available) michael@0: { michael@0: varying->reg = r; michael@0: varying->col = 2; michael@0: michael@0: for (int y = 0; y < n; y++) michael@0: { michael@0: for (int x = 2; x < 4; x++) michael@0: { michael@0: packing[r + y][x] = &*varying; michael@0: } michael@0: } michael@0: michael@0: success = true; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: else if (m == 1) michael@0: { michael@0: int space[4] = {0}; michael@0: michael@0: for (int y = 0; y < maxVaryingVectors; y++) michael@0: { michael@0: for (int x = 0; x < 4; x++) michael@0: { michael@0: space[x] += packing[y][x] ? 0 : 1; michael@0: } michael@0: } michael@0: michael@0: int column = 0; michael@0: michael@0: for (int x = 0; x < 4; x++) michael@0: { michael@0: if (space[x] >= n && space[x] < space[column]) michael@0: { michael@0: column = x; michael@0: } michael@0: } michael@0: michael@0: if (space[column] >= n) michael@0: { michael@0: for (int r = 0; r < maxVaryingVectors; r++) michael@0: { michael@0: if (!packing[r][column]) michael@0: { michael@0: varying->reg = r; michael@0: michael@0: for (int y = r; y < r + n; y++) michael@0: { michael@0: packing[y][column] = &*varying; michael@0: } michael@0: michael@0: break; michael@0: } michael@0: } michael@0: michael@0: varying->col = column; michael@0: michael@0: success = true; michael@0: } michael@0: } michael@0: else UNREACHABLE(); michael@0: michael@0: if (!success) michael@0: { michael@0: infoLog.append("Could not pack varying %s", varying->name.c_str()); michael@0: michael@0: return -1; michael@0: } michael@0: } michael@0: michael@0: // Return the number of used registers michael@0: int registers = 0; michael@0: michael@0: for (int r = 0; r < maxVaryingVectors; r++) michael@0: { michael@0: if (packing[r][0] || packing[r][1] || packing[r][2] || packing[r][3]) michael@0: { michael@0: registers++; michael@0: } michael@0: } michael@0: michael@0: return registers; michael@0: } michael@0: michael@0: bool ProgramBinary::linkVaryings(InfoLog &infoLog, int registers, const Varying *packing[][4], michael@0: std::string& pixelHLSL, std::string& vertexHLSL, michael@0: FragmentShader *fragmentShader, VertexShader *vertexShader) michael@0: { michael@0: if (pixelHLSL.empty() || vertexHLSL.empty()) michael@0: { michael@0: return false; michael@0: } michael@0: michael@0: bool usesMRT = fragmentShader->mUsesMultipleRenderTargets; michael@0: bool usesFragColor = fragmentShader->mUsesFragColor; michael@0: bool usesFragData = fragmentShader->mUsesFragData; michael@0: if (usesFragColor && usesFragData) michael@0: { michael@0: infoLog.append("Cannot use both gl_FragColor and gl_FragData in the same fragment shader."); michael@0: return false; michael@0: } michael@0: michael@0: // Write the HLSL input/output declarations michael@0: const int shaderModel = mRenderer->getMajorShaderModel(); michael@0: const int maxVaryingVectors = mRenderer->getMaxVaryingVectors(); michael@0: michael@0: const int registersNeeded = registers + (fragmentShader->mUsesFragCoord ? 1 : 0) + (fragmentShader->mUsesPointCoord ? 1 : 0); michael@0: michael@0: // The output color is broadcast to all enabled draw buffers when writing to gl_FragColor michael@0: const bool broadcast = fragmentShader->mUsesFragColor; michael@0: const unsigned int numRenderTargets = (broadcast || usesMRT ? mRenderer->getMaxRenderTargets() : 1); michael@0: michael@0: if (registersNeeded > maxVaryingVectors) michael@0: { michael@0: infoLog.append("No varying registers left to support gl_FragCoord/gl_PointCoord"); michael@0: michael@0: return false; michael@0: } michael@0: michael@0: vertexShader->resetVaryingsRegisterAssignment(); michael@0: michael@0: for (VaryingList::iterator input = fragmentShader->mVaryings.begin(); input != fragmentShader->mVaryings.end(); input++) michael@0: { michael@0: bool matched = false; michael@0: michael@0: for (VaryingList::iterator output = vertexShader->mVaryings.begin(); output != vertexShader->mVaryings.end(); output++) michael@0: { michael@0: if (output->name == input->name) michael@0: { michael@0: if (output->type != input->type || output->size != input->size) michael@0: { michael@0: infoLog.append("Type of vertex varying %s does not match that of the fragment varying", output->name.c_str()); michael@0: michael@0: return false; michael@0: } michael@0: michael@0: output->reg = input->reg; michael@0: output->col = input->col; michael@0: michael@0: matched = true; michael@0: break; michael@0: } michael@0: } michael@0: michael@0: if (!matched) michael@0: { michael@0: infoLog.append("Fragment varying %s does not match any vertex varying", input->name.c_str()); michael@0: michael@0: return false; michael@0: } michael@0: } michael@0: michael@0: mUsesPointSize = vertexShader->mUsesPointSize; michael@0: std::string varyingSemantic = (mUsesPointSize && shaderModel == 3) ? "COLOR" : "TEXCOORD"; michael@0: std::string targetSemantic = (shaderModel >= 4) ? "SV_Target" : "COLOR"; michael@0: std::string positionSemantic = (shaderModel >= 4) ? "SV_Position" : "POSITION"; michael@0: std::string depthSemantic = (shaderModel >= 4) ? "SV_Depth" : "DEPTH"; michael@0: michael@0: // special varyings that use reserved registers michael@0: int reservedRegisterIndex = registers; michael@0: std::string fragCoordSemantic; michael@0: std::string pointCoordSemantic; michael@0: michael@0: if (fragmentShader->mUsesFragCoord) michael@0: { michael@0: fragCoordSemantic = varyingSemantic + str(reservedRegisterIndex++); michael@0: } michael@0: michael@0: if (fragmentShader->mUsesPointCoord) michael@0: { michael@0: // Shader model 3 uses a special TEXCOORD semantic for point sprite texcoords. michael@0: // In DX11 we compute this in the GS. michael@0: if (shaderModel == 3) michael@0: { michael@0: pointCoordSemantic = "TEXCOORD0"; michael@0: } michael@0: else if (shaderModel >= 4) michael@0: { michael@0: pointCoordSemantic = varyingSemantic + str(reservedRegisterIndex++); michael@0: } michael@0: } michael@0: michael@0: vertexHLSL += "struct VS_INPUT\n" michael@0: "{\n"; michael@0: michael@0: int semanticIndex = 0; michael@0: for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++) michael@0: { michael@0: switch (attribute->type) michael@0: { michael@0: case GL_FLOAT: vertexHLSL += " float "; break; michael@0: case GL_FLOAT_VEC2: vertexHLSL += " float2 "; break; michael@0: case GL_FLOAT_VEC3: vertexHLSL += " float3 "; break; michael@0: case GL_FLOAT_VEC4: vertexHLSL += " float4 "; break; michael@0: case GL_FLOAT_MAT2: vertexHLSL += " float2x2 "; break; michael@0: case GL_FLOAT_MAT3: vertexHLSL += " float3x3 "; break; michael@0: case GL_FLOAT_MAT4: vertexHLSL += " float4x4 "; break; michael@0: default: UNREACHABLE(); michael@0: } michael@0: michael@0: vertexHLSL += decorateAttribute(attribute->name) + " : TEXCOORD" + str(semanticIndex) + ";\n"; michael@0: michael@0: semanticIndex += VariableRowCount(attribute->type); michael@0: } michael@0: michael@0: vertexHLSL += "};\n" michael@0: "\n" michael@0: "struct VS_OUTPUT\n" michael@0: "{\n"; michael@0: michael@0: if (shaderModel < 4) michael@0: { michael@0: vertexHLSL += " float4 gl_Position : " + positionSemantic + ";\n"; michael@0: } michael@0: michael@0: for (int r = 0; r < registers; r++) michael@0: { michael@0: int registerSize = packing[r][3] ? 4 : (packing[r][2] ? 3 : (packing[r][1] ? 2 : 1)); michael@0: michael@0: vertexHLSL += " float" + str(registerSize) + " v" + str(r) + " : " + varyingSemantic + str(r) + ";\n"; michael@0: } michael@0: michael@0: if (fragmentShader->mUsesFragCoord) michael@0: { michael@0: vertexHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n"; michael@0: } michael@0: michael@0: if (vertexShader->mUsesPointSize && shaderModel >= 3) michael@0: { michael@0: vertexHLSL += " float gl_PointSize : PSIZE;\n"; michael@0: } michael@0: michael@0: if (shaderModel >= 4) michael@0: { michael@0: vertexHLSL += " float4 gl_Position : " + positionSemantic + ";\n"; michael@0: } michael@0: michael@0: vertexHLSL += "};\n" michael@0: "\n" michael@0: "VS_OUTPUT main(VS_INPUT input)\n" michael@0: "{\n"; michael@0: michael@0: for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++) michael@0: { michael@0: vertexHLSL += " " + decorateAttribute(attribute->name) + " = "; michael@0: michael@0: if (VariableRowCount(attribute->type) > 1) // Matrix michael@0: { michael@0: vertexHLSL += "transpose"; michael@0: } michael@0: michael@0: vertexHLSL += "(input." + decorateAttribute(attribute->name) + ");\n"; michael@0: } michael@0: michael@0: if (shaderModel >= 4) michael@0: { michael@0: vertexHLSL += "\n" michael@0: " gl_main();\n" michael@0: "\n" michael@0: " VS_OUTPUT output;\n" michael@0: " output.gl_Position.x = gl_Position.x;\n" michael@0: " output.gl_Position.y = -gl_Position.y;\n" michael@0: " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n" michael@0: " output.gl_Position.w = gl_Position.w;\n"; michael@0: } michael@0: else michael@0: { michael@0: vertexHLSL += "\n" michael@0: " gl_main();\n" michael@0: "\n" michael@0: " VS_OUTPUT output;\n" michael@0: " output.gl_Position.x = gl_Position.x * dx_ViewAdjust.z + dx_ViewAdjust.x * gl_Position.w;\n" michael@0: " output.gl_Position.y = -(gl_Position.y * dx_ViewAdjust.w + dx_ViewAdjust.y * gl_Position.w);\n" michael@0: " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n" michael@0: " output.gl_Position.w = gl_Position.w;\n"; michael@0: } michael@0: michael@0: if (vertexShader->mUsesPointSize && shaderModel >= 3) michael@0: { michael@0: vertexHLSL += " output.gl_PointSize = gl_PointSize;\n"; michael@0: } michael@0: michael@0: if (fragmentShader->mUsesFragCoord) michael@0: { michael@0: vertexHLSL += " output.gl_FragCoord = gl_Position;\n"; michael@0: } michael@0: michael@0: for (VaryingList::iterator varying = vertexShader->mVaryings.begin(); varying != vertexShader->mVaryings.end(); varying++) michael@0: { michael@0: if (varying->reg >= 0) michael@0: { michael@0: for (int i = 0; i < varying->size; i++) michael@0: { michael@0: int rows = VariableRowCount(varying->type); michael@0: michael@0: for (int j = 0; j < rows; j++) michael@0: { michael@0: int r = varying->reg + i * rows + j; michael@0: vertexHLSL += " output.v" + str(r); michael@0: michael@0: bool sharedRegister = false; // Register used by multiple varyings michael@0: michael@0: for (int x = 0; x < 4; x++) michael@0: { michael@0: if (packing[r][x] && packing[r][x] != packing[r][0]) michael@0: { michael@0: sharedRegister = true; michael@0: break; michael@0: } michael@0: } michael@0: michael@0: if(sharedRegister) michael@0: { michael@0: vertexHLSL += "."; michael@0: michael@0: for (int x = 0; x < 4; x++) michael@0: { michael@0: if (packing[r][x] == &*varying) michael@0: { michael@0: switch(x) michael@0: { michael@0: case 0: vertexHLSL += "x"; break; michael@0: case 1: vertexHLSL += "y"; break; michael@0: case 2: vertexHLSL += "z"; break; michael@0: case 3: vertexHLSL += "w"; break; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: vertexHLSL += " = " + varying->name; michael@0: michael@0: if (varying->array) michael@0: { michael@0: vertexHLSL += "[" + str(i) + "]"; michael@0: } michael@0: michael@0: if (rows > 1) michael@0: { michael@0: vertexHLSL += "[" + str(j) + "]"; michael@0: } michael@0: michael@0: vertexHLSL += ";\n"; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: vertexHLSL += "\n" michael@0: " return output;\n" michael@0: "}\n"; michael@0: michael@0: pixelHLSL += "struct PS_INPUT\n" michael@0: "{\n"; michael@0: michael@0: for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++) michael@0: { michael@0: if (varying->reg >= 0) michael@0: { michael@0: for (int i = 0; i < varying->size; i++) michael@0: { michael@0: int rows = VariableRowCount(varying->type); michael@0: for (int j = 0; j < rows; j++) michael@0: { michael@0: std::string n = str(varying->reg + i * rows + j); michael@0: pixelHLSL += " float" + str(VariableColumnCount(varying->type)) + " v" + n + " : " + varyingSemantic + n + ";\n"; michael@0: } michael@0: } michael@0: } michael@0: else UNREACHABLE(); michael@0: } michael@0: michael@0: if (fragmentShader->mUsesFragCoord) michael@0: { michael@0: pixelHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n"; michael@0: } michael@0: michael@0: if (fragmentShader->mUsesPointCoord && shaderModel >= 3) michael@0: { michael@0: pixelHLSL += " float2 gl_PointCoord : " + pointCoordSemantic + ";\n"; michael@0: } michael@0: michael@0: // Must consume the PSIZE element if the geometry shader is not active michael@0: // We won't know if we use a GS until we draw michael@0: if (vertexShader->mUsesPointSize && shaderModel >= 4) michael@0: { michael@0: pixelHLSL += " float gl_PointSize : PSIZE;\n"; michael@0: } michael@0: michael@0: if (fragmentShader->mUsesFragCoord) michael@0: { michael@0: if (shaderModel >= 4) michael@0: { michael@0: pixelHLSL += " float4 dx_VPos : SV_Position;\n"; michael@0: } michael@0: else if (shaderModel >= 3) michael@0: { michael@0: pixelHLSL += " float2 dx_VPos : VPOS;\n"; michael@0: } michael@0: } michael@0: michael@0: pixelHLSL += "};\n" michael@0: "\n" michael@0: "struct PS_OUTPUT\n" michael@0: "{\n"; michael@0: michael@0: for (unsigned int renderTargetIndex = 0; renderTargetIndex < numRenderTargets; renderTargetIndex++) michael@0: { michael@0: pixelHLSL += " float4 gl_Color" + str(renderTargetIndex) + " : " + targetSemantic + str(renderTargetIndex) + ";\n"; michael@0: } michael@0: michael@0: if (fragmentShader->mUsesFragDepth) michael@0: { michael@0: pixelHLSL += " float gl_Depth : " + depthSemantic + ";\n"; michael@0: } michael@0: michael@0: pixelHLSL += "};\n" michael@0: "\n"; michael@0: michael@0: if (fragmentShader->mUsesFrontFacing) michael@0: { michael@0: if (shaderModel >= 4) michael@0: { michael@0: pixelHLSL += "PS_OUTPUT main(PS_INPUT input, bool isFrontFace : SV_IsFrontFace)\n" michael@0: "{\n"; michael@0: } michael@0: else michael@0: { michael@0: pixelHLSL += "PS_OUTPUT main(PS_INPUT input, float vFace : VFACE)\n" michael@0: "{\n"; michael@0: } michael@0: } michael@0: else michael@0: { michael@0: pixelHLSL += "PS_OUTPUT main(PS_INPUT input)\n" michael@0: "{\n"; michael@0: } michael@0: michael@0: if (fragmentShader->mUsesFragCoord) michael@0: { michael@0: pixelHLSL += " float rhw = 1.0 / input.gl_FragCoord.w;\n"; michael@0: michael@0: if (shaderModel >= 4) michael@0: { michael@0: pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x;\n" michael@0: " gl_FragCoord.y = input.dx_VPos.y;\n"; michael@0: } michael@0: else if (shaderModel >= 3) michael@0: { michael@0: pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x + 0.5;\n" michael@0: " gl_FragCoord.y = input.dx_VPos.y + 0.5;\n"; michael@0: } michael@0: else michael@0: { michael@0: // dx_ViewCoords contains the viewport width/2, height/2, center.x and center.y. See Renderer::setViewport() michael@0: pixelHLSL += " gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * dx_ViewCoords.x + dx_ViewCoords.z;\n" michael@0: " gl_FragCoord.y = (input.gl_FragCoord.y * rhw) * dx_ViewCoords.y + dx_ViewCoords.w;\n"; michael@0: } michael@0: michael@0: pixelHLSL += " gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * dx_DepthFront.x + dx_DepthFront.y;\n" michael@0: " gl_FragCoord.w = rhw;\n"; michael@0: } michael@0: michael@0: if (fragmentShader->mUsesPointCoord && shaderModel >= 3) michael@0: { michael@0: pixelHLSL += " gl_PointCoord.x = input.gl_PointCoord.x;\n"; michael@0: pixelHLSL += " gl_PointCoord.y = 1.0 - input.gl_PointCoord.y;\n"; michael@0: } michael@0: michael@0: if (fragmentShader->mUsesFrontFacing) michael@0: { michael@0: if (shaderModel <= 3) michael@0: { michael@0: pixelHLSL += " gl_FrontFacing = (vFace * dx_DepthFront.z >= 0.0);\n"; michael@0: } michael@0: else michael@0: { michael@0: pixelHLSL += " gl_FrontFacing = isFrontFace;\n"; michael@0: } michael@0: } michael@0: michael@0: for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++) michael@0: { michael@0: if (varying->reg >= 0) michael@0: { michael@0: for (int i = 0; i < varying->size; i++) michael@0: { michael@0: int rows = VariableRowCount(varying->type); michael@0: for (int j = 0; j < rows; j++) michael@0: { michael@0: std::string n = str(varying->reg + i * rows + j); michael@0: pixelHLSL += " " + varying->name; michael@0: michael@0: if (varying->array) michael@0: { michael@0: pixelHLSL += "[" + str(i) + "]"; michael@0: } michael@0: michael@0: if (rows > 1) michael@0: { michael@0: pixelHLSL += "[" + str(j) + "]"; michael@0: } michael@0: michael@0: switch (VariableColumnCount(varying->type)) michael@0: { michael@0: case 1: pixelHLSL += " = input.v" + n + ".x;\n"; break; michael@0: case 2: pixelHLSL += " = input.v" + n + ".xy;\n"; break; michael@0: case 3: pixelHLSL += " = input.v" + n + ".xyz;\n"; break; michael@0: case 4: pixelHLSL += " = input.v" + n + ";\n"; break; michael@0: default: UNREACHABLE(); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: else UNREACHABLE(); michael@0: } michael@0: michael@0: pixelHLSL += "\n" michael@0: " gl_main();\n" michael@0: "\n" michael@0: " PS_OUTPUT output;\n"; michael@0: michael@0: for (unsigned int renderTargetIndex = 0; renderTargetIndex < numRenderTargets; renderTargetIndex++) michael@0: { michael@0: unsigned int sourceColorIndex = broadcast ? 0 : renderTargetIndex; michael@0: michael@0: pixelHLSL += " output.gl_Color" + str(renderTargetIndex) + " = gl_Color[" + str(sourceColorIndex) + "];\n"; michael@0: } michael@0: michael@0: if (fragmentShader->mUsesFragDepth) michael@0: { michael@0: pixelHLSL += " output.gl_Depth = gl_Depth;\n"; michael@0: } michael@0: michael@0: pixelHLSL += "\n" michael@0: " return output;\n" michael@0: "}\n"; michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool ProgramBinary::load(InfoLog &infoLog, const void *binary, GLsizei length) michael@0: { michael@0: BinaryInputStream stream(binary, length); michael@0: michael@0: int format = 0; michael@0: stream.read(&format); michael@0: if (format != GL_PROGRAM_BINARY_ANGLE) michael@0: { michael@0: infoLog.append("Invalid program binary format."); michael@0: return false; michael@0: } michael@0: michael@0: int version = 0; michael@0: stream.read(&version); michael@0: if (version != VERSION_DWORD) michael@0: { michael@0: infoLog.append("Invalid program binary version."); michael@0: return false; michael@0: } michael@0: michael@0: int compileFlags = 0; michael@0: stream.read(&compileFlags); michael@0: if (compileFlags != ANGLE_COMPILE_OPTIMIZATION_LEVEL) michael@0: { michael@0: infoLog.append("Mismatched compilation flags."); michael@0: return false; michael@0: } michael@0: michael@0: for (int i = 0; i < MAX_VERTEX_ATTRIBS; ++i) michael@0: { michael@0: stream.read(&mLinkedAttribute[i].type); michael@0: std::string name; michael@0: stream.read(&name); michael@0: mLinkedAttribute[i].name = name; michael@0: stream.read(&mSemanticIndex[i]); michael@0: } michael@0: michael@0: for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i) michael@0: { michael@0: stream.read(&mSamplersPS[i].active); michael@0: stream.read(&mSamplersPS[i].logicalTextureUnit); michael@0: michael@0: int textureType; michael@0: stream.read(&textureType); michael@0: mSamplersPS[i].textureType = (TextureType) textureType; michael@0: } michael@0: michael@0: for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i) michael@0: { michael@0: stream.read(&mSamplersVS[i].active); michael@0: stream.read(&mSamplersVS[i].logicalTextureUnit); michael@0: michael@0: int textureType; michael@0: stream.read(&textureType); michael@0: mSamplersVS[i].textureType = (TextureType) textureType; michael@0: } michael@0: michael@0: stream.read(&mUsedVertexSamplerRange); michael@0: stream.read(&mUsedPixelSamplerRange); michael@0: stream.read(&mUsesPointSize); michael@0: michael@0: size_t size; michael@0: stream.read(&size); michael@0: if (stream.error()) michael@0: { michael@0: infoLog.append("Invalid program binary."); michael@0: return false; michael@0: } michael@0: michael@0: mUniforms.resize(size); michael@0: for (unsigned int i = 0; i < size; ++i) michael@0: { michael@0: GLenum type; michael@0: GLenum precision; michael@0: std::string name; michael@0: unsigned int arraySize; michael@0: michael@0: stream.read(&type); michael@0: stream.read(&precision); michael@0: stream.read(&name); michael@0: stream.read(&arraySize); michael@0: michael@0: mUniforms[i] = new Uniform(type, precision, name, arraySize); michael@0: michael@0: stream.read(&mUniforms[i]->psRegisterIndex); michael@0: stream.read(&mUniforms[i]->vsRegisterIndex); michael@0: stream.read(&mUniforms[i]->registerCount); michael@0: } michael@0: michael@0: stream.read(&size); michael@0: if (stream.error()) michael@0: { michael@0: infoLog.append("Invalid program binary."); michael@0: return false; michael@0: } michael@0: michael@0: mUniformIndex.resize(size); michael@0: for (unsigned int i = 0; i < size; ++i) michael@0: { michael@0: stream.read(&mUniformIndex[i].name); michael@0: stream.read(&mUniformIndex[i].element); michael@0: stream.read(&mUniformIndex[i].index); michael@0: } michael@0: michael@0: unsigned int pixelShaderSize; michael@0: stream.read(&pixelShaderSize); michael@0: michael@0: unsigned int vertexShaderSize; michael@0: stream.read(&vertexShaderSize); michael@0: michael@0: unsigned int geometryShaderSize; michael@0: stream.read(&geometryShaderSize); michael@0: michael@0: const char *ptr = (const char*) binary + stream.offset(); michael@0: michael@0: const GUID *binaryIdentifier = (const GUID *) ptr; michael@0: ptr += sizeof(GUID); michael@0: michael@0: GUID identifier = mRenderer->getAdapterIdentifier(); michael@0: if (memcmp(&identifier, binaryIdentifier, sizeof(GUID)) != 0) michael@0: { michael@0: infoLog.append("Invalid program binary."); michael@0: return false; michael@0: } michael@0: michael@0: const char *pixelShaderFunction = ptr; michael@0: ptr += pixelShaderSize; michael@0: michael@0: const char *vertexShaderFunction = ptr; michael@0: ptr += vertexShaderSize; michael@0: michael@0: const char *geometryShaderFunction = geometryShaderSize > 0 ? ptr : NULL; michael@0: ptr += geometryShaderSize; michael@0: michael@0: mPixelExecutable = mRenderer->loadExecutable(reinterpret_cast(pixelShaderFunction), michael@0: pixelShaderSize, rx::SHADER_PIXEL); michael@0: if (!mPixelExecutable) michael@0: { michael@0: infoLog.append("Could not create pixel shader."); michael@0: return false; michael@0: } michael@0: michael@0: mVertexExecutable = mRenderer->loadExecutable(reinterpret_cast(vertexShaderFunction), michael@0: vertexShaderSize, rx::SHADER_VERTEX); michael@0: if (!mVertexExecutable) michael@0: { michael@0: infoLog.append("Could not create vertex shader."); michael@0: delete mPixelExecutable; michael@0: mPixelExecutable = NULL; michael@0: return false; michael@0: } michael@0: michael@0: if (geometryShaderFunction != NULL && geometryShaderSize > 0) michael@0: { michael@0: mGeometryExecutable = mRenderer->loadExecutable(reinterpret_cast(geometryShaderFunction), michael@0: geometryShaderSize, rx::SHADER_GEOMETRY); michael@0: if (!mGeometryExecutable) michael@0: { michael@0: infoLog.append("Could not create geometry shader."); michael@0: delete mPixelExecutable; michael@0: mPixelExecutable = NULL; michael@0: delete mVertexExecutable; michael@0: mVertexExecutable = NULL; michael@0: return false; michael@0: } michael@0: } michael@0: else michael@0: { michael@0: mGeometryExecutable = NULL; michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool ProgramBinary::save(void* binary, GLsizei bufSize, GLsizei *length) michael@0: { michael@0: BinaryOutputStream stream; michael@0: michael@0: stream.write(GL_PROGRAM_BINARY_ANGLE); michael@0: stream.write(VERSION_DWORD); michael@0: stream.write(ANGLE_COMPILE_OPTIMIZATION_LEVEL); michael@0: michael@0: for (unsigned int i = 0; i < MAX_VERTEX_ATTRIBS; ++i) michael@0: { michael@0: stream.write(mLinkedAttribute[i].type); michael@0: stream.write(mLinkedAttribute[i].name); michael@0: stream.write(mSemanticIndex[i]); michael@0: } michael@0: michael@0: for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i) michael@0: { michael@0: stream.write(mSamplersPS[i].active); michael@0: stream.write(mSamplersPS[i].logicalTextureUnit); michael@0: stream.write((int) mSamplersPS[i].textureType); michael@0: } michael@0: michael@0: for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i) michael@0: { michael@0: stream.write(mSamplersVS[i].active); michael@0: stream.write(mSamplersVS[i].logicalTextureUnit); michael@0: stream.write((int) mSamplersVS[i].textureType); michael@0: } michael@0: michael@0: stream.write(mUsedVertexSamplerRange); michael@0: stream.write(mUsedPixelSamplerRange); michael@0: stream.write(mUsesPointSize); michael@0: michael@0: stream.write(mUniforms.size()); michael@0: for (unsigned int i = 0; i < mUniforms.size(); ++i) michael@0: { michael@0: stream.write(mUniforms[i]->type); michael@0: stream.write(mUniforms[i]->precision); michael@0: stream.write(mUniforms[i]->name); michael@0: stream.write(mUniforms[i]->arraySize); michael@0: michael@0: stream.write(mUniforms[i]->psRegisterIndex); michael@0: stream.write(mUniforms[i]->vsRegisterIndex); michael@0: stream.write(mUniforms[i]->registerCount); michael@0: } michael@0: michael@0: stream.write(mUniformIndex.size()); michael@0: for (unsigned int i = 0; i < mUniformIndex.size(); ++i) michael@0: { michael@0: stream.write(mUniformIndex[i].name); michael@0: stream.write(mUniformIndex[i].element); michael@0: stream.write(mUniformIndex[i].index); michael@0: } michael@0: michael@0: UINT pixelShaderSize = mPixelExecutable->getLength(); michael@0: stream.write(pixelShaderSize); michael@0: michael@0: UINT vertexShaderSize = mVertexExecutable->getLength(); michael@0: stream.write(vertexShaderSize); michael@0: michael@0: UINT geometryShaderSize = (mGeometryExecutable != NULL) ? mGeometryExecutable->getLength() : 0; michael@0: stream.write(geometryShaderSize); michael@0: michael@0: GUID identifier = mRenderer->getAdapterIdentifier(); michael@0: michael@0: GLsizei streamLength = stream.length(); michael@0: const void *streamData = stream.data(); michael@0: michael@0: GLsizei totalLength = streamLength + sizeof(GUID) + pixelShaderSize + vertexShaderSize + geometryShaderSize; michael@0: if (totalLength > bufSize) michael@0: { michael@0: if (length) michael@0: { michael@0: *length = 0; michael@0: } michael@0: michael@0: return false; michael@0: } michael@0: michael@0: if (binary) michael@0: { michael@0: char *ptr = (char*) binary; michael@0: michael@0: memcpy(ptr, streamData, streamLength); michael@0: ptr += streamLength; michael@0: michael@0: memcpy(ptr, &identifier, sizeof(GUID)); michael@0: ptr += sizeof(GUID); michael@0: michael@0: memcpy(ptr, mPixelExecutable->getFunction(), pixelShaderSize); michael@0: ptr += pixelShaderSize; michael@0: michael@0: memcpy(ptr, mVertexExecutable->getFunction(), vertexShaderSize); michael@0: ptr += vertexShaderSize; michael@0: michael@0: if (mGeometryExecutable != NULL && geometryShaderSize > 0) michael@0: { michael@0: memcpy(ptr, mGeometryExecutable->getFunction(), geometryShaderSize); michael@0: ptr += geometryShaderSize; michael@0: } michael@0: michael@0: ASSERT(ptr - totalLength == binary); michael@0: } michael@0: michael@0: if (length) michael@0: { michael@0: *length = totalLength; michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: GLint ProgramBinary::getLength() michael@0: { michael@0: GLint length; michael@0: if (save(NULL, INT_MAX, &length)) michael@0: { michael@0: return length; michael@0: } michael@0: else michael@0: { michael@0: return 0; michael@0: } michael@0: } michael@0: michael@0: bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader) michael@0: { michael@0: if (!fragmentShader || !fragmentShader->isCompiled()) michael@0: { michael@0: return false; michael@0: } michael@0: michael@0: if (!vertexShader || !vertexShader->isCompiled()) michael@0: { michael@0: return false; michael@0: } michael@0: michael@0: std::string pixelHLSL = fragmentShader->getHLSL(); michael@0: std::string vertexHLSL = vertexShader->getHLSL(); michael@0: michael@0: // Map the varyings to the register file michael@0: const Varying *packing[IMPLEMENTATION_MAX_VARYING_VECTORS][4] = {NULL}; michael@0: int registers = packVaryings(infoLog, packing, fragmentShader); michael@0: michael@0: if (registers < 0) michael@0: { michael@0: return false; michael@0: } michael@0: michael@0: if (!linkVaryings(infoLog, registers, packing, pixelHLSL, vertexHLSL, fragmentShader, vertexShader)) michael@0: { michael@0: return false; michael@0: } michael@0: michael@0: bool success = true; michael@0: michael@0: if (!linkAttributes(infoLog, attributeBindings, fragmentShader, vertexShader)) michael@0: { michael@0: success = false; michael@0: } michael@0: michael@0: if (!linkUniforms(infoLog, vertexShader->getUniforms(), fragmentShader->getUniforms())) michael@0: { michael@0: success = false; michael@0: } michael@0: michael@0: // special case for gl_DepthRange, the only built-in uniform (also a struct) michael@0: if (vertexShader->mUsesDepthRange || fragmentShader->mUsesDepthRange) michael@0: { michael@0: mUniforms.push_back(new Uniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.near", 0)); michael@0: mUniforms.push_back(new Uniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.far", 0)); michael@0: mUniforms.push_back(new Uniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.diff", 0)); michael@0: } michael@0: michael@0: if (success) michael@0: { michael@0: mVertexExecutable = mRenderer->compileToExecutable(infoLog, vertexHLSL.c_str(), rx::SHADER_VERTEX); michael@0: mPixelExecutable = mRenderer->compileToExecutable(infoLog, pixelHLSL.c_str(), rx::SHADER_PIXEL); michael@0: michael@0: if (usesGeometryShader()) michael@0: { michael@0: std::string geometryHLSL = generateGeometryShaderHLSL(registers, packing, fragmentShader, vertexShader); michael@0: mGeometryExecutable = mRenderer->compileToExecutable(infoLog, geometryHLSL.c_str(), rx::SHADER_GEOMETRY); michael@0: } michael@0: michael@0: if (!mVertexExecutable || !mPixelExecutable || (usesGeometryShader() && !mGeometryExecutable)) michael@0: { michael@0: infoLog.append("Failed to create D3D shaders."); michael@0: success = false; michael@0: michael@0: delete mVertexExecutable; michael@0: mVertexExecutable = NULL; michael@0: delete mPixelExecutable; michael@0: mPixelExecutable = NULL; michael@0: delete mGeometryExecutable; michael@0: mGeometryExecutable = NULL; michael@0: } michael@0: } michael@0: michael@0: return success; michael@0: } michael@0: michael@0: // Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices michael@0: bool ProgramBinary::linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader) michael@0: { michael@0: unsigned int usedLocations = 0; michael@0: michael@0: // Link attributes that have a binding location michael@0: for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++) michael@0: { michael@0: int location = attributeBindings.getAttributeBinding(attribute->name); michael@0: michael@0: if (location != -1) // Set by glBindAttribLocation michael@0: { michael@0: if (!mLinkedAttribute[location].name.empty()) michael@0: { michael@0: // Multiple active attributes bound to the same location; not an error michael@0: } michael@0: michael@0: mLinkedAttribute[location] = *attribute; michael@0: michael@0: int rows = VariableRowCount(attribute->type); michael@0: michael@0: if (rows + location > MAX_VERTEX_ATTRIBS) michael@0: { michael@0: infoLog.append("Active attribute (%s) at location %d is too big to fit", attribute->name.c_str(), location); michael@0: michael@0: return false; michael@0: } michael@0: michael@0: for (int i = 0; i < rows; i++) michael@0: { michael@0: usedLocations |= 1 << (location + i); michael@0: } michael@0: } michael@0: } michael@0: michael@0: // Link attributes that don't have a binding location michael@0: for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++) michael@0: { michael@0: int location = attributeBindings.getAttributeBinding(attribute->name); michael@0: michael@0: if (location == -1) // Not set by glBindAttribLocation michael@0: { michael@0: int rows = VariableRowCount(attribute->type); michael@0: int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS); michael@0: michael@0: if (availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS) michael@0: { michael@0: infoLog.append("Too many active attributes (%s)", attribute->name.c_str()); michael@0: michael@0: return false; // Fail to link michael@0: } michael@0: michael@0: mLinkedAttribute[availableIndex] = *attribute; michael@0: } michael@0: } michael@0: michael@0: for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; ) michael@0: { michael@0: int index = vertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name); michael@0: int rows = std::max(VariableRowCount(mLinkedAttribute[attributeIndex].type), 1); michael@0: michael@0: for (int r = 0; r < rows; r++) michael@0: { michael@0: mSemanticIndex[attributeIndex++] = index++; michael@0: } michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool ProgramBinary::linkUniforms(InfoLog &infoLog, const sh::ActiveUniforms &vertexUniforms, const sh::ActiveUniforms &fragmentUniforms) michael@0: { michael@0: for (sh::ActiveUniforms::const_iterator uniform = vertexUniforms.begin(); uniform != vertexUniforms.end(); uniform++) michael@0: { michael@0: if (!defineUniform(GL_VERTEX_SHADER, *uniform, infoLog)) michael@0: { michael@0: return false; michael@0: } michael@0: } michael@0: michael@0: for (sh::ActiveUniforms::const_iterator uniform = fragmentUniforms.begin(); uniform != fragmentUniforms.end(); uniform++) michael@0: { michael@0: if (!defineUniform(GL_FRAGMENT_SHADER, *uniform, infoLog)) michael@0: { michael@0: return false; michael@0: } michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool ProgramBinary::defineUniform(GLenum shader, const sh::Uniform &constant, InfoLog &infoLog) michael@0: { michael@0: if (constant.type == GL_SAMPLER_2D || michael@0: constant.type == GL_SAMPLER_CUBE) michael@0: { michael@0: unsigned int samplerIndex = constant.registerIndex; michael@0: michael@0: do michael@0: { michael@0: if (shader == GL_VERTEX_SHADER) michael@0: { michael@0: if (samplerIndex < mRenderer->getMaxVertexTextureImageUnits()) michael@0: { michael@0: mSamplersVS[samplerIndex].active = true; michael@0: mSamplersVS[samplerIndex].textureType = (constant.type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D; michael@0: mSamplersVS[samplerIndex].logicalTextureUnit = 0; michael@0: mUsedVertexSamplerRange = std::max(samplerIndex + 1, mUsedVertexSamplerRange); michael@0: } michael@0: else michael@0: { michael@0: infoLog.append("Vertex shader sampler count exceeds the maximum vertex texture units (%d).", mRenderer->getMaxVertexTextureImageUnits()); michael@0: return false; michael@0: } michael@0: } michael@0: else if (shader == GL_FRAGMENT_SHADER) michael@0: { michael@0: if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS) michael@0: { michael@0: mSamplersPS[samplerIndex].active = true; michael@0: mSamplersPS[samplerIndex].textureType = (constant.type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D; michael@0: mSamplersPS[samplerIndex].logicalTextureUnit = 0; michael@0: mUsedPixelSamplerRange = std::max(samplerIndex + 1, mUsedPixelSamplerRange); michael@0: } michael@0: else michael@0: { michael@0: infoLog.append("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", MAX_TEXTURE_IMAGE_UNITS); michael@0: return false; michael@0: } michael@0: } michael@0: else UNREACHABLE(); michael@0: michael@0: samplerIndex++; michael@0: } michael@0: while (samplerIndex < constant.registerIndex + constant.arraySize); michael@0: } michael@0: michael@0: Uniform *uniform = NULL; michael@0: GLint location = getUniformLocation(constant.name); michael@0: michael@0: if (location >= 0) // Previously defined, type and precision must match michael@0: { michael@0: uniform = mUniforms[mUniformIndex[location].index]; michael@0: michael@0: if (uniform->type != constant.type) michael@0: { michael@0: infoLog.append("Types for uniform %s do not match between the vertex and fragment shader", uniform->name.c_str()); michael@0: return false; michael@0: } michael@0: michael@0: if (uniform->precision != constant.precision) michael@0: { michael@0: infoLog.append("Precisions for uniform %s do not match between the vertex and fragment shader", uniform->name.c_str()); michael@0: return false; michael@0: } michael@0: } michael@0: else michael@0: { michael@0: uniform = new Uniform(constant.type, constant.precision, constant.name, constant.arraySize); michael@0: } michael@0: michael@0: if (!uniform) michael@0: { michael@0: return false; michael@0: } michael@0: michael@0: if (shader == GL_FRAGMENT_SHADER) michael@0: { michael@0: uniform->psRegisterIndex = constant.registerIndex; michael@0: } michael@0: else if (shader == GL_VERTEX_SHADER) michael@0: { michael@0: uniform->vsRegisterIndex = constant.registerIndex; michael@0: } michael@0: else UNREACHABLE(); michael@0: michael@0: if (location >= 0) michael@0: { michael@0: return uniform->type == constant.type; michael@0: } michael@0: michael@0: mUniforms.push_back(uniform); michael@0: unsigned int uniformIndex = mUniforms.size() - 1; michael@0: michael@0: for (unsigned int i = 0; i < uniform->elementCount(); i++) michael@0: { michael@0: mUniformIndex.push_back(UniformLocation(constant.name, i, uniformIndex)); michael@0: } michael@0: michael@0: if (shader == GL_VERTEX_SHADER) michael@0: { michael@0: if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedVertexUniformVectors() + mRenderer->getMaxVertexUniformVectors()) michael@0: { michael@0: infoLog.append("Vertex shader active uniforms exceed GL_MAX_VERTEX_UNIFORM_VECTORS (%u)", mRenderer->getMaxVertexUniformVectors()); michael@0: return false; michael@0: } michael@0: } michael@0: else if (shader == GL_FRAGMENT_SHADER) michael@0: { michael@0: if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedFragmentUniformVectors() + mRenderer->getMaxFragmentUniformVectors()) michael@0: { michael@0: infoLog.append("Fragment shader active uniforms exceed GL_MAX_FRAGMENT_UNIFORM_VECTORS (%u)", mRenderer->getMaxFragmentUniformVectors()); michael@0: return false; michael@0: } michael@0: } michael@0: else UNREACHABLE(); michael@0: michael@0: return true; michael@0: } michael@0: michael@0: std::string ProgramBinary::generateGeometryShaderHLSL(int registers, const Varying *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const michael@0: { michael@0: // for now we only handle point sprite emulation michael@0: ASSERT(usesPointSpriteEmulation()); michael@0: return generatePointSpriteHLSL(registers, packing, fragmentShader, vertexShader); michael@0: } michael@0: michael@0: std::string ProgramBinary::generatePointSpriteHLSL(int registers, const Varying *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const michael@0: { michael@0: ASSERT(registers >= 0); michael@0: ASSERT(vertexShader->mUsesPointSize); michael@0: ASSERT(mRenderer->getMajorShaderModel() >= 4); michael@0: michael@0: std::string geomHLSL; michael@0: michael@0: std::string varyingSemantic = "TEXCOORD"; michael@0: michael@0: std::string fragCoordSemantic; michael@0: std::string pointCoordSemantic; michael@0: michael@0: int reservedRegisterIndex = registers; michael@0: michael@0: if (fragmentShader->mUsesFragCoord) michael@0: { michael@0: fragCoordSemantic = varyingSemantic + str(reservedRegisterIndex++); michael@0: } michael@0: michael@0: if (fragmentShader->mUsesPointCoord) michael@0: { michael@0: pointCoordSemantic = varyingSemantic + str(reservedRegisterIndex++); michael@0: } michael@0: michael@0: geomHLSL += "uniform float4 dx_ViewCoords : register(c1);\n" michael@0: "\n" michael@0: "struct GS_INPUT\n" michael@0: "{\n"; michael@0: michael@0: for (int r = 0; r < registers; r++) michael@0: { michael@0: int registerSize = packing[r][3] ? 4 : (packing[r][2] ? 3 : (packing[r][1] ? 2 : 1)); michael@0: michael@0: geomHLSL += " float" + str(registerSize) + " v" + str(r) + " : " + varyingSemantic + str(r) + ";\n"; michael@0: } michael@0: michael@0: if (fragmentShader->mUsesFragCoord) michael@0: { michael@0: geomHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n"; michael@0: } michael@0: michael@0: geomHLSL += " float gl_PointSize : PSIZE;\n" michael@0: " float4 gl_Position : SV_Position;\n" michael@0: "};\n" michael@0: "\n" michael@0: "struct GS_OUTPUT\n" michael@0: "{\n"; michael@0: michael@0: for (int r = 0; r < registers; r++) michael@0: { michael@0: int registerSize = packing[r][3] ? 4 : (packing[r][2] ? 3 : (packing[r][1] ? 2 : 1)); michael@0: michael@0: geomHLSL += " float" + str(registerSize) + " v" + str(r) + " : " + varyingSemantic + str(r) + ";\n"; michael@0: } michael@0: michael@0: if (fragmentShader->mUsesFragCoord) michael@0: { michael@0: geomHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n"; michael@0: } michael@0: michael@0: if (fragmentShader->mUsesPointCoord) michael@0: { michael@0: geomHLSL += " float2 gl_PointCoord : " + pointCoordSemantic + ";\n"; michael@0: } michael@0: michael@0: geomHLSL += " float gl_PointSize : PSIZE;\n" michael@0: " float4 gl_Position : SV_Position;\n" michael@0: "};\n" michael@0: "\n" michael@0: "static float2 pointSpriteCorners[] = \n" michael@0: "{\n" michael@0: " float2( 0.5f, -0.5f),\n" michael@0: " float2( 0.5f, 0.5f),\n" michael@0: " float2(-0.5f, -0.5f),\n" michael@0: " float2(-0.5f, 0.5f)\n" michael@0: "};\n" michael@0: "\n" michael@0: "static float2 pointSpriteTexcoords[] = \n" michael@0: "{\n" michael@0: " float2(1.0f, 1.0f),\n" michael@0: " float2(1.0f, 0.0f),\n" michael@0: " float2(0.0f, 1.0f),\n" michael@0: " float2(0.0f, 0.0f)\n" michael@0: "};\n" michael@0: "\n" michael@0: "static float minPointSize = " + str(ALIASED_POINT_SIZE_RANGE_MIN) + ".0f;\n" michael@0: "static float maxPointSize = " + str(mRenderer->getMaxPointSize()) + ".0f;\n" michael@0: "\n" michael@0: "[maxvertexcount(4)]\n" michael@0: "void main(point GS_INPUT input[1], inout TriangleStream outStream)\n" michael@0: "{\n" michael@0: " GS_OUTPUT output = (GS_OUTPUT)0;\n" michael@0: " output.gl_PointSize = input[0].gl_PointSize;\n"; michael@0: michael@0: for (int r = 0; r < registers; r++) michael@0: { michael@0: geomHLSL += " output.v" + str(r) + " = input[0].v" + str(r) + ";\n"; michael@0: } michael@0: michael@0: if (fragmentShader->mUsesFragCoord) michael@0: { michael@0: geomHLSL += " output.gl_FragCoord = input[0].gl_FragCoord;\n"; michael@0: } michael@0: michael@0: geomHLSL += " \n" michael@0: " float gl_PointSize = clamp(input[0].gl_PointSize, minPointSize, maxPointSize);\n" michael@0: " float4 gl_Position = input[0].gl_Position;\n" michael@0: " float2 viewportScale = float2(1.0f / dx_ViewCoords.x, 1.0f / dx_ViewCoords.y) * gl_Position.w;\n"; michael@0: michael@0: for (int corner = 0; corner < 4; corner++) michael@0: { michael@0: geomHLSL += " \n" michael@0: " output.gl_Position = gl_Position + float4(pointSpriteCorners[" + str(corner) + "] * viewportScale * gl_PointSize, 0.0f, 0.0f);\n"; michael@0: michael@0: if (fragmentShader->mUsesPointCoord) michael@0: { michael@0: geomHLSL += " output.gl_PointCoord = pointSpriteTexcoords[" + str(corner) + "];\n"; michael@0: } michael@0: michael@0: geomHLSL += " outStream.Append(output);\n"; michael@0: } michael@0: michael@0: geomHLSL += " \n" michael@0: " outStream.RestartStrip();\n" michael@0: "}\n"; michael@0: michael@0: return geomHLSL; michael@0: } michael@0: michael@0: // This method needs to match OutputHLSL::decorate michael@0: std::string ProgramBinary::decorateAttribute(const std::string &name) michael@0: { michael@0: if (name.compare(0, 3, "gl_") != 0 && name.compare(0, 3, "dx_") != 0) michael@0: { michael@0: return "_" + name; michael@0: } michael@0: michael@0: return name; michael@0: } michael@0: michael@0: bool ProgramBinary::isValidated() const michael@0: { michael@0: return mValidated; michael@0: } michael@0: michael@0: void ProgramBinary::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const michael@0: { michael@0: // Skip over inactive attributes michael@0: unsigned int activeAttribute = 0; michael@0: unsigned int attribute; michael@0: for (attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++) michael@0: { michael@0: if (mLinkedAttribute[attribute].name.empty()) michael@0: { michael@0: continue; michael@0: } michael@0: michael@0: if (activeAttribute == index) michael@0: { michael@0: break; michael@0: } michael@0: michael@0: activeAttribute++; michael@0: } michael@0: michael@0: if (bufsize > 0) michael@0: { michael@0: const char *string = mLinkedAttribute[attribute].name.c_str(); michael@0: michael@0: strncpy(name, string, bufsize); michael@0: name[bufsize - 1] = '\0'; michael@0: michael@0: if (length) michael@0: { michael@0: *length = strlen(name); michael@0: } michael@0: } michael@0: michael@0: *size = 1; // Always a single 'type' instance michael@0: michael@0: *type = mLinkedAttribute[attribute].type; michael@0: } michael@0: michael@0: GLint ProgramBinary::getActiveAttributeCount() const michael@0: { michael@0: int count = 0; michael@0: michael@0: for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++) michael@0: { michael@0: if (!mLinkedAttribute[attributeIndex].name.empty()) michael@0: { michael@0: count++; michael@0: } michael@0: } michael@0: michael@0: return count; michael@0: } michael@0: michael@0: GLint ProgramBinary::getActiveAttributeMaxLength() const michael@0: { michael@0: int maxLength = 0; michael@0: michael@0: for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++) michael@0: { michael@0: if (!mLinkedAttribute[attributeIndex].name.empty()) michael@0: { michael@0: maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength); michael@0: } michael@0: } michael@0: michael@0: return maxLength; michael@0: } michael@0: michael@0: void ProgramBinary::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const michael@0: { michael@0: ASSERT(index < mUniforms.size()); // index must be smaller than getActiveUniformCount() michael@0: michael@0: if (bufsize > 0) michael@0: { michael@0: std::string string = mUniforms[index]->name; michael@0: michael@0: if (mUniforms[index]->isArray()) michael@0: { michael@0: string += "[0]"; michael@0: } michael@0: michael@0: strncpy(name, string.c_str(), bufsize); michael@0: name[bufsize - 1] = '\0'; michael@0: michael@0: if (length) michael@0: { michael@0: *length = strlen(name); michael@0: } michael@0: } michael@0: michael@0: *size = mUniforms[index]->elementCount(); michael@0: michael@0: *type = mUniforms[index]->type; michael@0: } michael@0: michael@0: GLint ProgramBinary::getActiveUniformCount() const michael@0: { michael@0: return mUniforms.size(); michael@0: } michael@0: michael@0: GLint ProgramBinary::getActiveUniformMaxLength() const michael@0: { michael@0: int maxLength = 0; michael@0: michael@0: unsigned int numUniforms = mUniforms.size(); michael@0: for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++) michael@0: { michael@0: if (!mUniforms[uniformIndex]->name.empty()) michael@0: { michael@0: int length = (int)(mUniforms[uniformIndex]->name.length() + 1); michael@0: if (mUniforms[uniformIndex]->isArray()) michael@0: { michael@0: length += 3; // Counting in "[0]". michael@0: } michael@0: maxLength = std::max(length, maxLength); michael@0: } michael@0: } michael@0: michael@0: return maxLength; michael@0: } michael@0: michael@0: void ProgramBinary::validate(InfoLog &infoLog) michael@0: { michael@0: applyUniforms(); michael@0: if (!validateSamplers(&infoLog)) michael@0: { michael@0: mValidated = false; michael@0: } michael@0: else michael@0: { michael@0: mValidated = true; michael@0: } michael@0: } michael@0: michael@0: bool ProgramBinary::validateSamplers(InfoLog *infoLog) michael@0: { michael@0: // if any two active samplers in a program are of different types, but refer to the same michael@0: // texture image unit, and this is the current program, then ValidateProgram will fail, and michael@0: // DrawArrays and DrawElements will issue the INVALID_OPERATION error. michael@0: michael@0: const unsigned int maxCombinedTextureImageUnits = mRenderer->getMaxCombinedTextureImageUnits(); michael@0: TextureType textureUnitType[IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS]; michael@0: michael@0: for (unsigned int i = 0; i < IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS; ++i) michael@0: { michael@0: textureUnitType[i] = TEXTURE_UNKNOWN; michael@0: } michael@0: michael@0: for (unsigned int i = 0; i < mUsedPixelSamplerRange; ++i) michael@0: { michael@0: if (mSamplersPS[i].active) michael@0: { michael@0: unsigned int unit = mSamplersPS[i].logicalTextureUnit; michael@0: michael@0: if (unit >= maxCombinedTextureImageUnits) michael@0: { michael@0: if (infoLog) michael@0: { michael@0: infoLog->append("Sampler uniform (%d) exceeds IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits); michael@0: } michael@0: michael@0: return false; michael@0: } michael@0: michael@0: if (textureUnitType[unit] != TEXTURE_UNKNOWN) michael@0: { michael@0: if (mSamplersPS[i].textureType != textureUnitType[unit]) michael@0: { michael@0: if (infoLog) michael@0: { michael@0: infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit); michael@0: } michael@0: michael@0: return false; michael@0: } michael@0: } michael@0: else michael@0: { michael@0: textureUnitType[unit] = mSamplersPS[i].textureType; michael@0: } michael@0: } michael@0: } michael@0: michael@0: for (unsigned int i = 0; i < mUsedVertexSamplerRange; ++i) michael@0: { michael@0: if (mSamplersVS[i].active) michael@0: { michael@0: unsigned int unit = mSamplersVS[i].logicalTextureUnit; michael@0: michael@0: if (unit >= maxCombinedTextureImageUnits) michael@0: { michael@0: if (infoLog) michael@0: { michael@0: infoLog->append("Sampler uniform (%d) exceeds IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits); michael@0: } michael@0: michael@0: return false; michael@0: } michael@0: michael@0: if (textureUnitType[unit] != TEXTURE_UNKNOWN) michael@0: { michael@0: if (mSamplersVS[i].textureType != textureUnitType[unit]) michael@0: { michael@0: if (infoLog) michael@0: { michael@0: infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit); michael@0: } michael@0: michael@0: return false; michael@0: } michael@0: } michael@0: else michael@0: { michael@0: textureUnitType[unit] = mSamplersVS[i].textureType; michael@0: } michael@0: } michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: ProgramBinary::Sampler::Sampler() : active(false), logicalTextureUnit(0), textureType(TEXTURE_2D) michael@0: { michael@0: } michael@0: michael@0: struct AttributeSorter michael@0: { michael@0: AttributeSorter(const int (&semanticIndices)[MAX_VERTEX_ATTRIBS]) michael@0: : originalIndices(semanticIndices) michael@0: { michael@0: for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++) michael@0: { michael@0: indices[i] = i; michael@0: } michael@0: michael@0: std::sort(&indices[0], &indices[MAX_VERTEX_ATTRIBS], *this); michael@0: } michael@0: michael@0: bool operator()(int a, int b) michael@0: { michael@0: return originalIndices[a] == -1 ? false : originalIndices[a] < originalIndices[b]; michael@0: } michael@0: michael@0: int indices[MAX_VERTEX_ATTRIBS]; michael@0: const int (&originalIndices)[MAX_VERTEX_ATTRIBS]; michael@0: }; michael@0: michael@0: void ProgramBinary::sortAttributesByLayout(rx::TranslatedAttribute attributes[MAX_VERTEX_ATTRIBS], int sortedSemanticIndices[MAX_VERTEX_ATTRIBS]) const michael@0: { michael@0: AttributeSorter sorter(mSemanticIndex); michael@0: michael@0: int oldIndices[MAX_VERTEX_ATTRIBS]; michael@0: rx::TranslatedAttribute oldTranslatedAttributes[MAX_VERTEX_ATTRIBS]; michael@0: michael@0: for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++) michael@0: { michael@0: oldIndices[i] = mSemanticIndex[i]; michael@0: oldTranslatedAttributes[i] = attributes[i]; michael@0: } michael@0: michael@0: for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++) michael@0: { michael@0: int oldIndex = sorter.indices[i]; michael@0: sortedSemanticIndices[i] = oldIndices[oldIndex]; michael@0: attributes[i] = oldTranslatedAttributes[oldIndex]; michael@0: } michael@0: } michael@0: michael@0: }