diff options
Diffstat (limited to 'src/3rdparty/angle/src/libGLESv2/ProgramBinary.cpp')
-rw-r--r-- | src/3rdparty/angle/src/libGLESv2/ProgramBinary.cpp | 3206 |
1 files changed, 1722 insertions, 1484 deletions
diff --git a/src/3rdparty/angle/src/libGLESv2/ProgramBinary.cpp b/src/3rdparty/angle/src/libGLESv2/ProgramBinary.cpp index 13c515a594..9fad5fbfc5 100644 --- a/src/3rdparty/angle/src/libGLESv2/ProgramBinary.cpp +++ b/src/3rdparty/angle/src/libGLESv2/ProgramBinary.cpp @@ -1,6 +1,6 @@ #include "precompiled.h" // -// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // @@ -10,50 +10,182 @@ #include "libGLESv2/BinaryStream.h" #include "libGLESv2/ProgramBinary.h" +#include "libGLESv2/Framebuffer.h" +#include "libGLESv2/Renderbuffer.h" #include "libGLESv2/renderer/ShaderExecutable.h" #include "common/debug.h" #include "common/version.h" -#include "utilities.h" +#include "common/utilities.h" #include "libGLESv2/main.h" #include "libGLESv2/Shader.h" #include "libGLESv2/Program.h" #include "libGLESv2/renderer/Renderer.h" -#include "libGLESv2/renderer/VertexDataManager.h" +#include "libGLESv2/renderer/d3d/VertexDataManager.h" +#include "libGLESv2/Context.h" +#include "libGLESv2/Buffer.h" +#include "libGLESv2/DynamicHLSL.h" +#include "common/blocklayout.h" #undef near #undef far namespace gl { -std::string str(int i) + +namespace +{ + +TextureType GetTextureType(GLenum samplerType) { - char buffer[20]; - snprintf(buffer, sizeof(buffer), "%d", i); - return buffer; + switch (samplerType) + { + case GL_SAMPLER_2D: + case GL_INT_SAMPLER_2D: + case GL_UNSIGNED_INT_SAMPLER_2D: + case GL_SAMPLER_2D_SHADOW: + return TEXTURE_2D; + case GL_SAMPLER_3D: + case GL_INT_SAMPLER_3D: + case GL_UNSIGNED_INT_SAMPLER_3D: + return TEXTURE_3D; + case GL_SAMPLER_CUBE: + case GL_SAMPLER_CUBE_SHADOW: + return TEXTURE_CUBE; + case GL_INT_SAMPLER_CUBE: + case GL_UNSIGNED_INT_SAMPLER_CUBE: + return TEXTURE_CUBE; + case GL_SAMPLER_2D_ARRAY: + case GL_INT_SAMPLER_2D_ARRAY: + case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: + case GL_SAMPLER_2D_ARRAY_SHADOW: + return TEXTURE_2D_ARRAY; + default: UNREACHABLE(); + } + + return TEXTURE_2D; } -static rx::D3DWorkaroundType DiscardWorkaround(bool usesDiscard) +unsigned int ParseAndStripArrayIndex(std::string* name) { - return (usesDiscard ? rx::ANGLE_D3D_WORKAROUND_SM3_OPTIMIZER : rx::ANGLE_D3D_WORKAROUND_NONE); + unsigned int subscript = GL_INVALID_INDEX; + + // 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); + } + + return subscript; } -UniformLocation::UniformLocation(const std::string &name, unsigned int element, unsigned int index) +void GetInputLayoutFromShader(const std::vector<sh::Attribute> &shaderAttributes, VertexFormat inputLayout[MAX_VERTEX_ATTRIBS]) +{ + size_t layoutIndex = 0; + for (size_t attributeIndex = 0; attributeIndex < shaderAttributes.size(); attributeIndex++) + { + ASSERT(layoutIndex < MAX_VERTEX_ATTRIBS); + + const sh::Attribute &shaderAttr = shaderAttributes[attributeIndex]; + + if (shaderAttr.type != GL_NONE) + { + GLenum transposedType = TransposeMatrixType(shaderAttr.type); + + for (size_t rowIndex = 0; static_cast<int>(rowIndex) < VariableRowCount(transposedType); rowIndex++, layoutIndex++) + { + VertexFormat *defaultFormat = &inputLayout[layoutIndex]; + + defaultFormat->mType = VariableComponentType(transposedType); + defaultFormat->mNormalized = false; + defaultFormat->mPureInteger = (defaultFormat->mType != GL_FLOAT); // note: inputs can not be bool + defaultFormat->mComponents = VariableColumnCount(transposedType); + } + } + } +} + +} + +VariableLocation::VariableLocation(const std::string &name, unsigned int element, unsigned int index) : name(name), element(element), index(index) { } -unsigned int ProgramBinary::mCurrentSerial = 1; +ProgramBinary::VertexExecutable::VertexExecutable(const VertexFormat inputLayout[], + const GLenum signature[], + rx::ShaderExecutable *shaderExecutable) + : mShaderExecutable(shaderExecutable) +{ + for (size_t attributeIndex = 0; attributeIndex < gl::MAX_VERTEX_ATTRIBS; attributeIndex++) + { + mInputs[attributeIndex] = inputLayout[attributeIndex]; + mSignature[attributeIndex] = signature[attributeIndex]; + } +} -ProgramBinary::ProgramBinary(rx::Renderer *renderer) : mRenderer(renderer), RefCountObject(0), mSerial(issueSerial()) +ProgramBinary::VertexExecutable::~VertexExecutable() { - mPixelExecutable = NULL; - mVertexExecutable = NULL; - mGeometryExecutable = NULL; + SafeDelete(mShaderExecutable); +} - mValidated = false; +bool ProgramBinary::VertexExecutable::matchesSignature(const GLenum signature[]) const +{ + for (size_t attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++) + { + if (mSignature[attributeIndex] != signature[attributeIndex]) + { + return false; + } + } + + return true; +} + +ProgramBinary::PixelExecutable::PixelExecutable(const std::vector<GLenum> &outputSignature, rx::ShaderExecutable *shaderExecutable) + : mOutputSignature(outputSignature), + mShaderExecutable(shaderExecutable) +{ +} + +ProgramBinary::PixelExecutable::~PixelExecutable() +{ + SafeDelete(mShaderExecutable); +} +LinkedVarying::LinkedVarying() +{ +} + +LinkedVarying::LinkedVarying(const std::string &name, GLenum type, GLsizei size, const std::string &semanticName, + unsigned int semanticIndex, unsigned int semanticIndexCount) + : name(name), type(type), size(size), semanticName(semanticName), semanticIndex(semanticIndex), semanticIndexCount(semanticIndexCount) +{ +} + +unsigned int ProgramBinary::mCurrentSerial = 1; + +ProgramBinary::ProgramBinary(rx::Renderer *renderer) + : RefCountObject(0), + mRenderer(renderer), + mDynamicHLSL(NULL), + mVertexWorkarounds(rx::ANGLE_D3D_WORKAROUND_NONE), + mPixelWorkarounds(rx::ANGLE_D3D_WORKAROUND_NONE), + mGeometryExecutable(NULL), + mUsedVertexSamplerRange(0), + mUsedPixelSamplerRange(0), + mUsesPointSize(false), + mShaderVersion(100), + mDirtySamplerMapping(true), + mVertexUniformStorage(NULL), + mFragmentUniformStorage(NULL), + mValidated(false), + mSerial(issueSerial()) +{ for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++) { mSemanticIndex[index] = -1; @@ -69,27 +201,13 @@ ProgramBinary::ProgramBinary(rx::Renderer *renderer) : mRenderer(renderer), RefC mSamplersVS[index].active = false; } - mUsedVertexSamplerRange = 0; - mUsedPixelSamplerRange = 0; - mUsesPointSize = false; + mDynamicHLSL = new DynamicHLSL(renderer); } ProgramBinary::~ProgramBinary() { - delete mPixelExecutable; - mPixelExecutable = NULL; - - delete mVertexExecutable; - mVertexExecutable = NULL; - - delete mGeometryExecutable; - mGeometryExecutable = NULL; - - while (!mUniforms.empty()) - { - delete mUniforms.back(); - mUniforms.pop_back(); - } + reset(); + SafeDelete(mDynamicHLSL); } unsigned int ProgramBinary::getSerial() const @@ -97,22 +215,108 @@ unsigned int ProgramBinary::getSerial() const return mSerial; } +int ProgramBinary::getShaderVersion() const +{ + return mShaderVersion; +} + unsigned int ProgramBinary::issueSerial() { return mCurrentSerial++; } -rx::ShaderExecutable *ProgramBinary::getPixelExecutable() +rx::ShaderExecutable *ProgramBinary::getPixelExecutableForFramebuffer(const Framebuffer *fbo) { - return mPixelExecutable; + std::vector<GLenum> outputs(IMPLEMENTATION_MAX_DRAW_BUFFERS); + for (size_t outputIndex = 0; outputIndex < IMPLEMENTATION_MAX_DRAW_BUFFERS; outputIndex++) + { + if (fbo->getColorbuffer(outputIndex) != NULL) + { + // Always output floats for now + outputs[outputIndex] = GL_FLOAT; + } + else + { + outputs[outputIndex] = GL_NONE; + } + } + + return getPixelExecutableForOutputLayout(outputs); } -rx::ShaderExecutable *ProgramBinary::getVertexExecutable() +rx::ShaderExecutable *ProgramBinary::getPixelExecutableForOutputLayout(const std::vector<GLenum> &outputSignature) { - return mVertexExecutable; + for (size_t executableIndex = 0; executableIndex < mPixelExecutables.size(); executableIndex++) + { + if (mPixelExecutables[executableIndex]->matchesSignature(outputSignature)) + { + return mPixelExecutables[executableIndex]->shaderExecutable(); + } + } + + std::string finalPixelHLSL = mDynamicHLSL->generatePixelShaderForOutputSignature(mPixelHLSL, mPixelShaderKey, mUsesFragDepth, + outputSignature); + + // Generate new pixel executable + InfoLog tempInfoLog; + rx::ShaderExecutable *pixelExecutable = mRenderer->compileToExecutable(tempInfoLog, finalPixelHLSL.c_str(), rx::SHADER_PIXEL, + mTransformFeedbackLinkedVaryings, + (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS), + mPixelWorkarounds); + + if (!pixelExecutable) + { + std::vector<char> tempCharBuffer(tempInfoLog.getLength() + 3); + tempInfoLog.getLog(tempInfoLog.getLength(), NULL, &tempCharBuffer[0]); + ERR("Error compiling dynamic pixel executable:\n%s\n", &tempCharBuffer[0]); + } + else + { + mPixelExecutables.push_back(new PixelExecutable(outputSignature, pixelExecutable)); + } + + return pixelExecutable; } -rx::ShaderExecutable *ProgramBinary::getGeometryExecutable() +rx::ShaderExecutable *ProgramBinary::getVertexExecutableForInputLayout(const VertexFormat inputLayout[MAX_VERTEX_ATTRIBS]) +{ + GLenum signature[MAX_VERTEX_ATTRIBS]; + mDynamicHLSL->getInputLayoutSignature(inputLayout, signature); + + for (size_t executableIndex = 0; executableIndex < mVertexExecutables.size(); executableIndex++) + { + if (mVertexExecutables[executableIndex]->matchesSignature(signature)) + { + return mVertexExecutables[executableIndex]->shaderExecutable(); + } + } + + // Generate new dynamic layout with attribute conversions + std::string finalVertexHLSL = mDynamicHLSL->generateVertexShaderForInputLayout(mVertexHLSL, inputLayout, mShaderAttributes); + + // Generate new vertex executable + InfoLog tempInfoLog; + rx::ShaderExecutable *vertexExecutable = mRenderer->compileToExecutable(tempInfoLog, finalVertexHLSL.c_str(), + rx::SHADER_VERTEX, + mTransformFeedbackLinkedVaryings, + (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS), + mVertexWorkarounds); + + if (!vertexExecutable) + { + std::vector<char> tempCharBuffer(tempInfoLog.getLength()+3); + tempInfoLog.getLog(tempInfoLog.getLength(), NULL, &tempCharBuffer[0]); + ERR("Error compiling dynamic vertex executable:\n%s\n", &tempCharBuffer[0]); + } + else + { + mVertexExecutables.push_back(new VertexExecutable(inputLayout, signature, vertexExecutable)); + } + + return vertexExecutable; +} + +rx::ShaderExecutable *ProgramBinary::getGeometryExecutable() const { return mGeometryExecutable; } @@ -136,7 +340,7 @@ GLuint ProgramBinary::getAttributeLocation(const char *name) int ProgramBinary::getSemanticIndex(int attributeIndex) { ASSERT(attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS); - + return mSemanticIndex[attributeIndex]; } @@ -179,7 +383,7 @@ GLint ProgramBinary::getSamplerMapping(SamplerType type, unsigned int samplerInd switch (type) { case SAMPLER_PIXEL: - ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0])); + ASSERT(samplerIndex < ArraySize(mSamplersPS)); if (mSamplersPS[samplerIndex].active) { @@ -187,7 +391,7 @@ GLint ProgramBinary::getSamplerMapping(SamplerType type, unsigned int samplerInd } break; case SAMPLER_VERTEX: - ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0])); + ASSERT(samplerIndex < ArraySize(mSamplersVS)); if (mSamplersVS[samplerIndex].active) { @@ -212,11 +416,11 @@ TextureType ProgramBinary::getSamplerTextureType(SamplerType type, unsigned int switch (type) { case SAMPLER_PIXEL: - ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0])); + ASSERT(samplerIndex < ArraySize(mSamplersPS)); ASSERT(mSamplersPS[samplerIndex].active); return mSamplersPS[samplerIndex].textureType; case SAMPLER_VERTEX: - ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0])); + ASSERT(samplerIndex < ArraySize(mSamplersVS)); ASSERT(mSamplersVS[samplerIndex].active); return mSamplersVS[samplerIndex].textureType; default: UNREACHABLE(); @@ -227,402 +431,352 @@ TextureType ProgramBinary::getSamplerTextureType(SamplerType type, unsigned int GLint ProgramBinary::getUniformLocation(std::string name) { - unsigned int subscript = 0; - - // Strip any trailing array operator and retrieve the subscript - size_t open = name.find_last_of('['); - size_t close = name.find_last_of(']'); - if (open != std::string::npos && close == name.length() - 1) - { - subscript = atoi(name.substr(open + 1).c_str()); - name.erase(open); - } + unsigned int subscript = ParseAndStripArrayIndex(&name); unsigned int numUniforms = mUniformIndex.size(); for (unsigned int location = 0; location < numUniforms; location++) { - if (mUniformIndex[location].name == name && - mUniformIndex[location].element == subscript) + if (mUniformIndex[location].name == name) { - return location; + const int index = mUniformIndex[location].index; + const bool isArray = mUniforms[index]->isArray(); + + if ((isArray && mUniformIndex[location].element == subscript) || + (subscript == GL_INVALID_INDEX)) + { + return location; + } } } return -1; } -bool ProgramBinary::setUniform1fv(GLint location, GLsizei count, const GLfloat* v) +GLuint ProgramBinary::getUniformIndex(std::string name) { - if (location < 0 || location >= (int)mUniformIndex.size()) - { - return false; - } - - Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; - targetUniform->dirty = true; - - int elementCount = targetUniform->elementCount(); - - if (elementCount == 1 && count > 1) - return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION + unsigned int subscript = ParseAndStripArrayIndex(&name); - count = std::min(elementCount - (int)mUniformIndex[location].element, count); - - if (targetUniform->type == GL_FLOAT) + // The app is not allowed to specify array indices other than 0 for arrays of basic types + if (subscript != 0 && subscript != GL_INVALID_INDEX) { - GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4; - - for (int i = 0; i < count; i++) - { - target[0] = v[0]; - target[1] = 0; - target[2] = 0; - target[3] = 0; - target += 4; - v += 1; - } + return GL_INVALID_INDEX; } - else if (targetUniform->type == GL_BOOL) - { - GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4; - for (int i = 0; i < count; i++) + unsigned int numUniforms = mUniforms.size(); + for (unsigned int index = 0; index < numUniforms; index++) + { + if (mUniforms[index]->name == name) { - boolParams[0] = (v[0] == 0.0f) ? GL_FALSE : GL_TRUE; - boolParams[1] = GL_FALSE; - boolParams[2] = GL_FALSE; - boolParams[3] = GL_FALSE; - boolParams += 4; - v += 1; + if (mUniforms[index]->isArray() || subscript == GL_INVALID_INDEX) + { + return index; + } } } - else - { - return false; - } - return true; + return GL_INVALID_INDEX; } -bool ProgramBinary::setUniform2fv(GLint location, GLsizei count, const GLfloat *v) +GLuint ProgramBinary::getUniformBlockIndex(std::string name) { - if (location < 0 || location >= (int)mUniformIndex.size()) + unsigned int subscript = ParseAndStripArrayIndex(&name); + + unsigned int numUniformBlocks = mUniformBlocks.size(); + for (unsigned int blockIndex = 0; blockIndex < numUniformBlocks; blockIndex++) { - return false; + const UniformBlock &uniformBlock = *mUniformBlocks[blockIndex]; + if (uniformBlock.name == name) + { + const bool arrayElementZero = (subscript == GL_INVALID_INDEX && uniformBlock.elementIndex == 0); + if (subscript == uniformBlock.elementIndex || arrayElementZero) + { + return blockIndex; + } + } } - Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; - targetUniform->dirty = true; - - int elementCount = targetUniform->elementCount(); + return GL_INVALID_INDEX; +} - if (elementCount == 1 && count > 1) - return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION +UniformBlock *ProgramBinary::getUniformBlockByIndex(GLuint blockIndex) +{ + ASSERT(blockIndex < mUniformBlocks.size()); + return mUniformBlocks[blockIndex]; +} - count = std::min(elementCount - (int)mUniformIndex[location].element, count); +GLint ProgramBinary::getFragDataLocation(const char *name) const +{ + std::string baseName(name); + unsigned int arrayIndex; + arrayIndex = ParseAndStripArrayIndex(&baseName); - if (targetUniform->type == GL_FLOAT_VEC2) + for (auto locationIt = mOutputVariables.begin(); locationIt != mOutputVariables.end(); locationIt++) { - GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4; + const VariableLocation &outputVariable = locationIt->second; - for (int i = 0; i < count; i++) + if (outputVariable.name == baseName && (arrayIndex == GL_INVALID_INDEX || arrayIndex == outputVariable.element)) { - target[0] = v[0]; - target[1] = v[1]; - target[2] = 0; - target[3] = 0; - target += 4; - v += 2; + return static_cast<GLint>(locationIt->first); } } - else if (targetUniform->type == GL_BOOL_VEC2) - { - GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4; - for (int i = 0; i < count; i++) - { - boolParams[0] = (v[0] == 0.0f) ? GL_FALSE : GL_TRUE; - boolParams[1] = (v[1] == 0.0f) ? GL_FALSE : GL_TRUE; - boolParams[2] = GL_FALSE; - boolParams[3] = GL_FALSE; - boolParams += 4; - v += 2; - } - } - else - { - return false; - } + return -1; +} - return true; +size_t ProgramBinary::getTransformFeedbackVaryingCount() const +{ + return mTransformFeedbackLinkedVaryings.size(); } -bool ProgramBinary::setUniform3fv(GLint location, GLsizei count, const GLfloat *v) +const LinkedVarying &ProgramBinary::getTransformFeedbackVarying(size_t idx) const { - if (location < 0 || location >= (int)mUniformIndex.size()) - { - return false; - } + return mTransformFeedbackLinkedVaryings[idx]; +} - Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; - targetUniform->dirty = true; +GLenum ProgramBinary::getTransformFeedbackBufferMode() const +{ + return mTransformFeedbackBufferMode; +} - int elementCount = targetUniform->elementCount(); +template <typename T> +static inline void SetIfDirty(T *dest, const T& source, bool *dirtyFlag) +{ + ASSERT(dest != NULL); + ASSERT(dirtyFlag != NULL); - if (elementCount == 1 && count > 1) - return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION + *dirtyFlag = *dirtyFlag || (memcmp(dest, &source, sizeof(T)) != 0); + *dest = source; +} + +template <typename T> +void ProgramBinary::setUniform(GLint location, GLsizei count, const T* v, GLenum targetUniformType) +{ + const int components = VariableComponentCount(targetUniformType); + const GLenum targetBoolType = VariableBoolVectorType(targetUniformType); + + LinkedUniform *targetUniform = getUniformByLocation(location); + + int elementCount = targetUniform->elementCount(); count = std::min(elementCount - (int)mUniformIndex[location].element, count); - if (targetUniform->type == GL_FLOAT_VEC3) + if (targetUniform->type == targetUniformType) { - GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4; + T *target = (T*)targetUniform->data + mUniformIndex[location].element * 4; for (int i = 0; i < count; i++) { - target[0] = v[0]; - target[1] = v[1]; - target[2] = v[2]; - target[3] = 0; + for (int c = 0; c < components; c++) + { + SetIfDirty(target + c, v[c], &targetUniform->dirty); + } + for (int c = components; c < 4; c++) + { + SetIfDirty(target + c, T(0), &targetUniform->dirty); + } target += 4; - v += 3; + v += components; } } - else if (targetUniform->type == GL_BOOL_VEC3) + else if (targetUniform->type == targetBoolType) { GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4; for (int i = 0; i < count; i++) { - boolParams[0] = (v[0] == 0.0f) ? GL_FALSE : GL_TRUE; - boolParams[1] = (v[1] == 0.0f) ? GL_FALSE : GL_TRUE; - boolParams[2] = (v[2] == 0.0f) ? GL_FALSE : GL_TRUE; - boolParams[3] = GL_FALSE; + for (int c = 0; c < components; c++) + { + SetIfDirty(boolParams + c, (v[c] == static_cast<T>(0)) ? GL_FALSE : GL_TRUE, &targetUniform->dirty); + } + for (int c = components; c < 4; c++) + { + SetIfDirty(boolParams + c, GL_FALSE, &targetUniform->dirty); + } boolParams += 4; - v += 3; + v += components; } } - else - { - return false; - } - - return true; + else UNREACHABLE(); } -bool ProgramBinary::setUniform4fv(GLint location, GLsizei count, const GLfloat *v) +void ProgramBinary::setUniform1fv(GLint location, GLsizei count, const GLfloat* v) { - if (location < 0 || location >= (int)mUniformIndex.size()) - { - return false; - } + setUniform(location, count, v, GL_FLOAT); +} - Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; - targetUniform->dirty = true; +void ProgramBinary::setUniform2fv(GLint location, GLsizei count, const GLfloat *v) +{ + setUniform(location, count, v, GL_FLOAT_VEC2); +} - int elementCount = targetUniform->elementCount(); +void ProgramBinary::setUniform3fv(GLint location, GLsizei count, const GLfloat *v) +{ + setUniform(location, count, v, GL_FLOAT_VEC3); +} - if (elementCount == 1 && count > 1) - return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION +void ProgramBinary::setUniform4fv(GLint location, GLsizei count, const GLfloat *v) +{ + setUniform(location, count, v, GL_FLOAT_VEC4); +} - count = std::min(elementCount - (int)mUniformIndex[location].element, count); +template<typename T> +bool transposeMatrix(T *target, const GLfloat *value, int targetWidth, int targetHeight, int srcWidth, int srcHeight) +{ + bool dirty = false; + int copyWidth = std::min(targetHeight, srcWidth); + int copyHeight = std::min(targetWidth, srcHeight); - if (targetUniform->type == GL_FLOAT_VEC4) + for (int x = 0; x < copyWidth; x++) { - GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4; - - for (int i = 0; i < count; i++) + for (int y = 0; y < copyHeight; y++) { - target[0] = v[0]; - target[1] = v[1]; - target[2] = v[2]; - target[3] = v[3]; - target += 4; - v += 4; + SetIfDirty(target + (x * targetWidth + y), static_cast<T>(value[y * srcWidth + x]), &dirty); } } - else if (targetUniform->type == GL_BOOL_VEC4) + // clear unfilled right side + for (int y = 0; y < copyWidth; y++) { - GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4; - - for (int i = 0; i < count; i++) + for (int x = copyHeight; x < targetWidth; x++) { - boolParams[0] = (v[0] == 0.0f) ? GL_FALSE : GL_TRUE; - boolParams[1] = (v[1] == 0.0f) ? GL_FALSE : GL_TRUE; - boolParams[2] = (v[2] == 0.0f) ? GL_FALSE : GL_TRUE; - boolParams[3] = (v[3] == 0.0f) ? GL_FALSE : GL_TRUE; - boolParams += 4; - v += 4; + SetIfDirty(target + (y * targetWidth + x), static_cast<T>(0), &dirty); } } - else + // clear unfilled bottom. + for (int y = copyWidth; y < targetHeight; y++) { - return false; + for (int x = 0; x < targetWidth; x++) + { + SetIfDirty(target + (y * targetWidth + x), static_cast<T>(0), &dirty); + } } - return true; + return dirty; } -template<typename T, int targetWidth, int targetHeight, int srcWidth, int srcHeight> -void transposeMatrix(T *target, const GLfloat *value) +template<typename T> +bool expandMatrix(T *target, const GLfloat *value, int targetWidth, int targetHeight, int srcWidth, int srcHeight) { + bool dirty = false; int copyWidth = std::min(targetWidth, srcWidth); int copyHeight = std::min(targetHeight, srcHeight); - for (int x = 0; x < copyWidth; x++) + for (int y = 0; y < copyHeight; y++) { - for (int y = 0; y < copyHeight; y++) + for (int x = 0; x < copyWidth; x++) { - target[x * targetWidth + y] = (T)value[y * srcWidth + x]; + SetIfDirty(target + (y * targetWidth + x), static_cast<T>(value[y * srcWidth + x]), &dirty); } } // clear unfilled right side for (int y = 0; y < copyHeight; y++) { - for (int x = srcWidth; x < targetWidth; x++) + for (int x = copyWidth; x < targetWidth; x++) { - target[y * targetWidth + x] = (T)0; + SetIfDirty(target + (y * targetWidth + x), static_cast<T>(0), &dirty); } } // clear unfilled bottom. - for (int y = srcHeight; y < targetHeight; y++) + for (int y = copyHeight; y < targetHeight; y++) { for (int x = 0; x < targetWidth; x++) { - target[y * targetWidth + x] = (T)0; + SetIfDirty(target + (y * targetWidth + x), static_cast<T>(0), &dirty); } } + + return dirty; } -bool ProgramBinary::setUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value) +template <int cols, int rows> +void ProgramBinary::setUniformMatrixfv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value, GLenum targetUniformType) { - if (location < 0 || location >= (int)mUniformIndex.size()) - { - return false; - } - - Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; - targetUniform->dirty = true; - - if (targetUniform->type != GL_FLOAT_MAT2) - { - return false; - } + LinkedUniform *targetUniform = getUniformByLocation(location); int elementCount = targetUniform->elementCount(); - if (elementCount == 1 && count > 1) - return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION - count = std::min(elementCount - (int)mUniformIndex[location].element, count); - GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8; + const unsigned int targetMatrixStride = (4 * rows); + GLfloat *target = (GLfloat*)(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * targetMatrixStride); for (int i = 0; i < count; i++) { - transposeMatrix<GLfloat,4,2,2,2>(target, value); - target += 8; - value += 4; + // Internally store matrices as transposed versions to accomodate HLSL matrix indexing + if (transpose == GL_FALSE) + { + targetUniform->dirty = transposeMatrix<GLfloat>(target, value, 4, rows, rows, cols) || targetUniform->dirty; + } + else + { + targetUniform->dirty = expandMatrix<GLfloat>(target, value, 4, rows, cols, rows) || targetUniform->dirty; + } + target += targetMatrixStride; + value += cols * rows; } - - return true; } -bool ProgramBinary::setUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value) +void ProgramBinary::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { - if (location < 0 || location >= (int)mUniformIndex.size()) - { - return false; - } - - Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; - targetUniform->dirty = true; - - if (targetUniform->type != GL_FLOAT_MAT3) - { - return false; - } - - int elementCount = targetUniform->elementCount(); - - if (elementCount == 1 && count > 1) - return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION - - count = std::min(elementCount - (int)mUniformIndex[location].element, count); - GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12; - - for (int i = 0; i < count; i++) - { - transposeMatrix<GLfloat,4,3,3,3>(target, value); - target += 12; - value += 9; - } - - return true; + setUniformMatrixfv<2, 2>(location, count, transpose, value, GL_FLOAT_MAT2); } - -bool ProgramBinary::setUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value) +void ProgramBinary::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { - if (location < 0 || location >= (int)mUniformIndex.size()) - { - return false; - } - - Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; - targetUniform->dirty = true; + setUniformMatrixfv<3, 3>(location, count, transpose, value, GL_FLOAT_MAT3); +} - if (targetUniform->type != GL_FLOAT_MAT4) - { - return false; - } +void ProgramBinary::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +{ + setUniformMatrixfv<4, 4>(location, count, transpose, value, GL_FLOAT_MAT4); +} - int elementCount = targetUniform->elementCount(); +void ProgramBinary::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +{ + setUniformMatrixfv<2, 3>(location, count, transpose, value, GL_FLOAT_MAT2x3); +} - if (elementCount == 1 && count > 1) - return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION +void ProgramBinary::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +{ + setUniformMatrixfv<3, 2>(location, count, transpose, value, GL_FLOAT_MAT3x2); +} - count = std::min(elementCount - (int)mUniformIndex[location].element, count); - GLfloat *target = (GLfloat*)(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 16); +void ProgramBinary::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +{ + setUniformMatrixfv<2, 4>(location, count, transpose, value, GL_FLOAT_MAT2x4); +} - for (int i = 0; i < count; i++) - { - transposeMatrix<GLfloat,4,4,4,4>(target, value); - target += 16; - value += 16; - } +void ProgramBinary::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +{ + setUniformMatrixfv<4, 2>(location, count, transpose, value, GL_FLOAT_MAT4x2); +} - return true; +void ProgramBinary::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +{ + setUniformMatrixfv<3, 4>(location, count, transpose, value, GL_FLOAT_MAT3x4); } -bool ProgramBinary::setUniform1iv(GLint location, GLsizei count, const GLint *v) +void ProgramBinary::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { - if (location < 0 || location >= (int)mUniformIndex.size()) - { - return false; - } + setUniformMatrixfv<4, 3>(location, count, transpose, value, GL_FLOAT_MAT4x3); +} - Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; - targetUniform->dirty = true; +void ProgramBinary::setUniform1iv(GLint location, GLsizei count, const GLint *v) +{ + LinkedUniform *targetUniform = mUniforms[mUniformIndex[location].index]; int elementCount = targetUniform->elementCount(); - if (elementCount == 1 && count > 1) - return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION - count = std::min(elementCount - (int)mUniformIndex[location].element, count); - if (targetUniform->type == GL_INT || - targetUniform->type == GL_SAMPLER_2D || - targetUniform->type == GL_SAMPLER_CUBE) + if (targetUniform->type == GL_INT || IsSampler(targetUniform->type)) { GLint *target = (GLint*)targetUniform->data + mUniformIndex[location].element * 4; for (int i = 0; i < count; i++) { - target[0] = v[0]; - target[1] = 0; - target[2] = 0; - target[3] = 0; + SetIfDirty(target + 0, v[0], &targetUniform->dirty); + SetIfDirty(target + 1, 0, &targetUniform->dirty); + SetIfDirty(target + 2, 0, &targetUniform->dirty); + SetIfDirty(target + 3, 0, &targetUniform->dirty); target += 4; v += 1; } @@ -633,317 +787,157 @@ bool ProgramBinary::setUniform1iv(GLint location, GLsizei count, const GLint *v) for (int i = 0; i < count; i++) { - boolParams[0] = (v[0] == 0) ? GL_FALSE : GL_TRUE; - boolParams[1] = GL_FALSE; - boolParams[2] = GL_FALSE; - boolParams[3] = GL_FALSE; + SetIfDirty(boolParams + 0, (v[0] == 0) ? GL_FALSE : GL_TRUE, &targetUniform->dirty); + SetIfDirty(boolParams + 1, GL_FALSE, &targetUniform->dirty); + SetIfDirty(boolParams + 2, GL_FALSE, &targetUniform->dirty); + SetIfDirty(boolParams + 3, GL_FALSE, &targetUniform->dirty); boolParams += 4; v += 1; } } - else + else UNREACHABLE(); + + // Set a special flag if we change a sampler uniform + if (IsSampler(targetUniform->type) && + (memcmp(targetUniform->data, v, sizeof(GLint)) != 0)) { - return false; + mDirtySamplerMapping = true; } - - return true; } -bool ProgramBinary::setUniform2iv(GLint location, GLsizei count, const GLint *v) +void ProgramBinary::setUniform2iv(GLint location, GLsizei count, const GLint *v) { - if (location < 0 || location >= (int)mUniformIndex.size()) - { - return false; - } - - Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; - targetUniform->dirty = true; - - int elementCount = targetUniform->elementCount(); - - if (elementCount == 1 && count > 1) - return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION - - count = std::min(elementCount - (int)mUniformIndex[location].element, count); - - if (targetUniform->type == GL_INT_VEC2) - { - GLint *target = (GLint*)targetUniform->data + mUniformIndex[location].element * 4; - - for (int i = 0; i < count; i++) - { - target[0] = v[0]; - target[1] = v[1]; - target[2] = 0; - target[3] = 0; - target += 4; - v += 2; - } - } - else if (targetUniform->type == GL_BOOL_VEC2) - { - GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4; - - for (int i = 0; i < count; i++) - { - boolParams[0] = (v[0] == 0) ? GL_FALSE : GL_TRUE; - boolParams[1] = (v[1] == 0) ? GL_FALSE : GL_TRUE; - boolParams[2] = GL_FALSE; - boolParams[3] = GL_FALSE; - boolParams += 4; - v += 2; - } - } - else - { - return false; - } - - return true; + setUniform(location, count, v, GL_INT_VEC2); } -bool ProgramBinary::setUniform3iv(GLint location, GLsizei count, const GLint *v) +void ProgramBinary::setUniform3iv(GLint location, GLsizei count, const GLint *v) { - if (location < 0 || location >= (int)mUniformIndex.size()) - { - return false; - } - - Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; - targetUniform->dirty = true; - - int elementCount = targetUniform->elementCount(); - - if (elementCount == 1 && count > 1) - return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION - - count = std::min(elementCount - (int)mUniformIndex[location].element, count); - - if (targetUniform->type == GL_INT_VEC3) - { - GLint *target = (GLint*)targetUniform->data + mUniformIndex[location].element * 4; - - for (int i = 0; i < count; i++) - { - target[0] = v[0]; - target[1] = v[1]; - target[2] = v[2]; - target[3] = 0; - target += 4; - v += 3; - } - } - else if (targetUniform->type == GL_BOOL_VEC3) - { - GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4; - - for (int i = 0; i < count; i++) - { - boolParams[0] = (v[0] == 0) ? GL_FALSE : GL_TRUE; - boolParams[1] = (v[1] == 0) ? GL_FALSE : GL_TRUE; - boolParams[2] = (v[2] == 0) ? GL_FALSE : GL_TRUE; - boolParams[3] = GL_FALSE; - boolParams += 4; - v += 3; - } - } - else - { - return false; - } - - return true; + setUniform(location, count, v, GL_INT_VEC3); } -bool ProgramBinary::setUniform4iv(GLint location, GLsizei count, const GLint *v) +void ProgramBinary::setUniform4iv(GLint location, GLsizei count, const GLint *v) { - if (location < 0 || location >= (int)mUniformIndex.size()) - { - return false; - } - - Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; - targetUniform->dirty = true; - - int elementCount = targetUniform->elementCount(); - - if (elementCount == 1 && count > 1) - return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION - - count = std::min(elementCount - (int)mUniformIndex[location].element, count); - - if (targetUniform->type == GL_INT_VEC4) - { - GLint *target = (GLint*)targetUniform->data + mUniformIndex[location].element * 4; + setUniform(location, count, v, GL_INT_VEC4); +} - for (int i = 0; i < count; i++) - { - target[0] = v[0]; - target[1] = v[1]; - target[2] = v[2]; - target[3] = v[3]; - target += 4; - v += 4; - } - } - else if (targetUniform->type == GL_BOOL_VEC4) - { - GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4; +void ProgramBinary::setUniform1uiv(GLint location, GLsizei count, const GLuint *v) +{ + setUniform(location, count, v, GL_UNSIGNED_INT); +} - for (int i = 0; i < count; i++) - { - boolParams[0] = (v[0] == 0) ? GL_FALSE : GL_TRUE; - boolParams[1] = (v[1] == 0) ? GL_FALSE : GL_TRUE; - boolParams[2] = (v[2] == 0) ? GL_FALSE : GL_TRUE; - boolParams[3] = (v[3] == 0) ? GL_FALSE : GL_TRUE; - boolParams += 4; - v += 4; - } - } - else - { - return false; - } +void ProgramBinary::setUniform2uiv(GLint location, GLsizei count, const GLuint *v) +{ + setUniform(location, count, v, GL_UNSIGNED_INT_VEC2); +} - return true; +void ProgramBinary::setUniform3uiv(GLint location, GLsizei count, const GLuint *v) +{ + setUniform(location, count, v, GL_UNSIGNED_INT_VEC3); } -bool ProgramBinary::getUniformfv(GLint location, GLsizei *bufSize, GLfloat *params) +void ProgramBinary::setUniform4uiv(GLint location, GLsizei count, const GLuint *v) { - if (location < 0 || location >= (int)mUniformIndex.size()) - { - return false; - } + setUniform(location, count, v, GL_UNSIGNED_INT_VEC4); +} - Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; +template <typename T> +bool ProgramBinary::getUniformv(GLint location, GLsizei *bufSize, T *params, GLenum uniformType) +{ + LinkedUniform *targetUniform = mUniforms[mUniformIndex[location].index]; // sized queries -- ensure the provided buffer is large enough if (bufSize) { - int requiredBytes = UniformExternalSize(targetUniform->type); + int requiredBytes = VariableExternalSize(targetUniform->type); if (*bufSize < requiredBytes) { return false; } } - switch (targetUniform->type) + if (IsMatrixType(targetUniform->type)) { - case GL_FLOAT_MAT2: - transposeMatrix<GLfloat,2,2,4,2>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8); - break; - case GL_FLOAT_MAT3: - transposeMatrix<GLfloat,3,3,4,3>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12); - break; - case GL_FLOAT_MAT4: - transposeMatrix<GLfloat,4,4,4,4>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 16); - break; - default: + const int rows = VariableRowCount(targetUniform->type); + const int cols = VariableColumnCount(targetUniform->type); + transposeMatrix(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4 * rows, rows, cols, 4, rows); + } + else if (uniformType == VariableComponentType(targetUniform->type)) + { + unsigned int size = VariableComponentCount(targetUniform->type); + memcpy(params, targetUniform->data + mUniformIndex[location].element * 4 * sizeof(T), + size * sizeof(T)); + } + else + { + unsigned int size = VariableComponentCount(targetUniform->type); + switch (VariableComponentType(targetUniform->type)) { - unsigned int size = UniformComponentCount(targetUniform->type); - - switch (UniformComponentType(targetUniform->type)) + case GL_BOOL: { - case GL_BOOL: - { - GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4; + GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4; - for (unsigned int i = 0; i < size; i++) - { - params[i] = (boolParams[i] == GL_FALSE) ? 0.0f : 1.0f; - } - } - break; - case GL_FLOAT: - memcpy(params, targetUniform->data + mUniformIndex[location].element * 4 * sizeof(GLfloat), - size * sizeof(GLfloat)); - break; - case GL_INT: + for (unsigned int i = 0; i < size; i++) { - GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4; - - for (unsigned int i = 0; i < size; i++) - { - params[i] = (float)intParams[i]; - } + params[i] = (boolParams[i] == GL_FALSE) ? static_cast<T>(0) : static_cast<T>(1); } - break; - default: UNREACHABLE(); } - } - } - - return true; -} + break; -bool ProgramBinary::getUniformiv(GLint location, GLsizei *bufSize, GLint *params) -{ - if (location < 0 || location >= (int)mUniformIndex.size()) - { - return false; - } + case GL_FLOAT: + { + GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4; - Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; + for (unsigned int i = 0; i < size; i++) + { + params[i] = static_cast<T>(floatParams[i]); + } + } + break; - // sized queries -- ensure the provided buffer is large enough - if (bufSize) - { - int requiredBytes = UniformExternalSize(targetUniform->type); - if (*bufSize < requiredBytes) - { - return false; - } - } + case GL_INT: + { + GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4; - switch (targetUniform->type) - { - case GL_FLOAT_MAT2: - transposeMatrix<GLint,2,2,4,2>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8); - break; - case GL_FLOAT_MAT3: - transposeMatrix<GLint,3,3,4,3>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12); - break; - case GL_FLOAT_MAT4: - transposeMatrix<GLint,4,4,4,4>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 16); - break; - default: - { - unsigned int size = VariableColumnCount(targetUniform->type); + for (unsigned int i = 0; i < size; i++) + { + params[i] = static_cast<T>(intParams[i]); + } + } + break; - switch (UniformComponentType(targetUniform->type)) + case GL_UNSIGNED_INT: { - case GL_BOOL: - { - GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4; + GLuint *uintParams = (GLuint*)targetUniform->data + mUniformIndex[location].element * 4; - for (unsigned int i = 0; i < size; i++) - { - params[i] = boolParams[i]; - } - } - break; - case GL_FLOAT: + for (unsigned int i = 0; i < size; i++) { - GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4; - - for (unsigned int i = 0; i < size; i++) - { - params[i] = (GLint)floatParams[i]; - } + params[i] = static_cast<T>(uintParams[i]); } - break; - case GL_INT: - memcpy(params, targetUniform->data + mUniformIndex[location].element * 4 * sizeof(GLint), - size * sizeof(GLint)); - break; - default: UNREACHABLE(); } + break; + + default: UNREACHABLE(); } } return true; } +bool ProgramBinary::getUniformfv(GLint location, GLsizei *bufSize, GLfloat *params) +{ + return getUniformv(location, bufSize, params, GL_FLOAT); +} + +bool ProgramBinary::getUniformiv(GLint location, GLsizei *bufSize, GLint *params) +{ + return getUniformv(location, bufSize, params, GL_INT); +} + +bool ProgramBinary::getUniformuiv(GLint location, GLsizei *bufSize, GLuint *params) +{ + return getUniformv(location, bufSize, params, GL_UNSIGNED_INT); +} + void ProgramBinary::dirtyAllUniforms() { unsigned int numUniforms = mUniforms.size(); @@ -953,23 +947,28 @@ void ProgramBinary::dirtyAllUniforms() } } -// Applies all the uniforms set for this program object to the renderer -void ProgramBinary::applyUniforms() +void ProgramBinary::updateSamplerMapping() { + if (!mDirtySamplerMapping) + { + return; + } + + mDirtySamplerMapping = false; + // Retrieve sampler uniform values - for (std::vector<Uniform*>::iterator ub = mUniforms.begin(), ue = mUniforms.end(); ub != ue; ++ub) + for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++) { - Uniform *targetUniform = *ub; + LinkedUniform *targetUniform = mUniforms[uniformIndex]; if (targetUniform->dirty) { - if (targetUniform->type == GL_SAMPLER_2D || - targetUniform->type == GL_SAMPLER_CUBE) + if (IsSampler(targetUniform->type)) { int count = targetUniform->elementCount(); - GLint (*v)[4] = (GLint(*)[4])targetUniform->data; + GLint (*v)[4] = reinterpret_cast<GLint(*)[4]>(targetUniform->data); - if (targetUniform->psRegisterIndex >= 0) + if (targetUniform->isReferencedByFragmentShader()) { unsigned int firstIndex = targetUniform->psRegisterIndex; @@ -985,7 +984,7 @@ void ProgramBinary::applyUniforms() } } - if (targetUniform->vsRegisterIndex >= 0) + if (targetUniform->isReferencedByVertexShader()) { unsigned int firstIndex = targetUniform->vsRegisterIndex; @@ -1003,215 +1002,87 @@ void ProgramBinary::applyUniforms() } } } - - mRenderer->applyUniforms(this, &mUniforms); } -// Packs varyings into generic varying registers, using the algorithm from [OpenGL ES Shading Language 1.00 rev. 17] appendix A section 7 page 111 -// Returns the number of used varying registers, or -1 if unsuccesful -int ProgramBinary::packVaryings(InfoLog &infoLog, const Varying *packing[][4], FragmentShader *fragmentShader) +// Applies all the uniforms set for this program object to the renderer +void ProgramBinary::applyUniforms() { - const int maxVaryingVectors = mRenderer->getMaxVaryingVectors(); + updateSamplerMapping(); - fragmentShader->resetVaryingsRegisterAssignment(); + mRenderer->applyUniforms(*this); - for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++) + for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++) { - int n = VariableRowCount(varying->type) * varying->size; - int m = VariableColumnCount(varying->type); - bool success = false; - - if (m == 2 || m == 3 || m == 4) - { - for (int r = 0; r <= maxVaryingVectors - n && !success; r++) - { - bool available = true; - - for (int y = 0; y < n && available; y++) - { - for (int x = 0; x < m && available; x++) - { - if (packing[r + y][x]) - { - available = false; - } - } - } + mUniforms[uniformIndex]->dirty = false; + } +} - if (available) - { - varying->reg = r; - varying->col = 0; +bool ProgramBinary::applyUniformBuffers(const std::vector<gl::Buffer*> boundBuffers) +{ + const gl::Buffer *vertexUniformBuffers[gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS] = {NULL}; + const gl::Buffer *fragmentUniformBuffers[gl::IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS] = {NULL}; - for (int y = 0; y < n; y++) - { - for (int x = 0; x < m; x++) - { - packing[r + y][x] = &*varying; - } - } + const unsigned int reservedBuffersInVS = mRenderer->getReservedVertexUniformBuffers(); + const unsigned int reservedBuffersInFS = mRenderer->getReservedFragmentUniformBuffers(); - success = true; - } - } + ASSERT(boundBuffers.size() == mUniformBlocks.size()); - if (!success && m == 2) - { - for (int r = maxVaryingVectors - n; r >= 0 && !success; r--) - { - bool available = true; - - for (int y = 0; y < n && available; y++) - { - for (int x = 2; x < 4 && available; x++) - { - if (packing[r + y][x]) - { - available = false; - } - } - } - - if (available) - { - varying->reg = r; - varying->col = 2; + for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); uniformBlockIndex++) + { + UniformBlock *uniformBlock = getUniformBlockByIndex(uniformBlockIndex); + gl::Buffer *uniformBuffer = boundBuffers[uniformBlockIndex]; - for (int y = 0; y < n; y++) - { - for (int x = 2; x < 4; x++) - { - packing[r + y][x] = &*varying; - } - } + ASSERT(uniformBlock && uniformBuffer); - success = true; - } - } - } - } - else if (m == 1) + if (uniformBuffer->getSize() < uniformBlock->dataSize) { - int space[4] = {0}; - - for (int y = 0; y < maxVaryingVectors; y++) - { - for (int x = 0; x < 4; x++) - { - space[x] += packing[y][x] ? 0 : 1; - } - } - - int column = 0; - - for (int x = 0; x < 4; x++) - { - if (space[x] >= n && space[x] < space[column]) - { - column = x; - } - } - - if (space[column] >= n) - { - for (int r = 0; r < maxVaryingVectors; r++) - { - if (!packing[r][column]) - { - varying->reg = r; - - for (int y = r; y < r + n; y++) - { - packing[y][column] = &*varying; - } - - break; - } - } - - varying->col = column; - - success = true; - } + // undefined behaviour + return false; } - else UNREACHABLE(); - if (!success) - { - infoLog.append("Could not pack varying %s", varying->name.c_str()); + ASSERT(uniformBlock->isReferencedByVertexShader() || uniformBlock->isReferencedByFragmentShader()); - return -1; + if (uniformBlock->isReferencedByVertexShader()) + { + unsigned int registerIndex = uniformBlock->vsRegisterIndex - reservedBuffersInVS; + ASSERT(vertexUniformBuffers[registerIndex] == NULL); + ASSERT(registerIndex < mRenderer->getMaxVertexShaderUniformBuffers()); + vertexUniformBuffers[registerIndex] = uniformBuffer; } - } - - // Return the number of used registers - int registers = 0; - for (int r = 0; r < maxVaryingVectors; r++) - { - if (packing[r][0] || packing[r][1] || packing[r][2] || packing[r][3]) + if (uniformBlock->isReferencedByFragmentShader()) { - registers++; + unsigned int registerIndex = uniformBlock->psRegisterIndex - reservedBuffersInFS; + ASSERT(fragmentUniformBuffers[registerIndex] == NULL); + ASSERT(registerIndex < mRenderer->getMaxFragmentShaderUniformBuffers()); + fragmentUniformBuffers[registerIndex] = uniformBuffer; } } - return registers; + return mRenderer->setUniformBuffers(vertexUniformBuffers, fragmentUniformBuffers); } -bool ProgramBinary::linkVaryings(InfoLog &infoLog, int registers, const Varying *packing[][4], - std::string& pixelHLSL, std::string& vertexHLSL, - FragmentShader *fragmentShader, VertexShader *vertexShader) +bool ProgramBinary::linkVaryings(InfoLog &infoLog, FragmentShader *fragmentShader, VertexShader *vertexShader) { - if (pixelHLSL.empty() || vertexHLSL.empty()) - { - return false; - } + std::vector<PackedVarying> &fragmentVaryings = fragmentShader->getVaryings(); + std::vector<PackedVarying> &vertexVaryings = vertexShader->getVaryings(); - bool usesMRT = fragmentShader->mUsesMultipleRenderTargets; - bool usesFragColor = fragmentShader->mUsesFragColor; - bool usesFragData = fragmentShader->mUsesFragData; - if (usesFragColor && usesFragData) - { - infoLog.append("Cannot use both gl_FragColor and gl_FragData in the same fragment shader."); - return false; - } - - // Write the HLSL input/output declarations - const int shaderModel = mRenderer->getMajorShaderModel(); - const int maxVaryingVectors = mRenderer->getMaxVaryingVectors(); - - const int registersNeeded = registers + (fragmentShader->mUsesFragCoord ? 1 : 0) + (fragmentShader->mUsesPointCoord ? 1 : 0); - - // The output color is broadcast to all enabled draw buffers when writing to gl_FragColor - const bool broadcast = fragmentShader->mUsesFragColor; - const unsigned int numRenderTargets = (broadcast || usesMRT ? mRenderer->getMaxRenderTargets() : 1); - - if (registersNeeded > maxVaryingVectors) - { - infoLog.append("No varying registers left to support gl_FragCoord/gl_PointCoord"); - - return false; - } - - vertexShader->resetVaryingsRegisterAssignment(); - - for (VaryingList::iterator input = fragmentShader->mVaryings.begin(); input != fragmentShader->mVaryings.end(); input++) + for (size_t fragVaryingIndex = 0; fragVaryingIndex < fragmentVaryings.size(); fragVaryingIndex++) { + PackedVarying *input = &fragmentVaryings[fragVaryingIndex]; bool matched = false; - for (VaryingList::iterator output = vertexShader->mVaryings.begin(); output != vertexShader->mVaryings.end(); output++) + for (size_t vertVaryingIndex = 0; vertVaryingIndex < vertexVaryings.size(); vertVaryingIndex++) { + PackedVarying *output = &vertexVaryings[vertVaryingIndex]; if (output->name == input->name) { - if (output->type != input->type || output->size != input->size) + if (!linkValidateVariables(infoLog, output->name, *input, *output)) { - infoLog.append("Type of vertex varying %s does not match that of the fragment varying", output->name.c_str()); - return false; } - output->reg = input->reg; - output->col = input->col; + output->registerIndex = input->registerIndex; matched = true; break; @@ -1221,664 +1092,463 @@ bool ProgramBinary::linkVaryings(InfoLog &infoLog, int registers, const Varying if (!matched) { infoLog.append("Fragment varying %s does not match any vertex varying", input->name.c_str()); - return false; } } - mUsesPointSize = vertexShader->mUsesPointSize; - std::string varyingSemantic = (mUsesPointSize && shaderModel == 3) ? "COLOR" : "TEXCOORD"; - std::string targetSemantic = (shaderModel >= 4) ? "SV_Target" : "COLOR"; - std::string positionSemantic = (shaderModel >= 4) ? "SV_Position" : "POSITION"; - std::string depthSemantic = (shaderModel >= 4) ? "SV_Depth" : "DEPTH"; + return true; +} - // special varyings that use reserved registers - int reservedRegisterIndex = registers; - std::string fragCoordSemantic; - std::string pointCoordSemantic; +bool ProgramBinary::load(InfoLog &infoLog, const void *binary, GLsizei length) +{ +#ifdef ANGLE_DISABLE_PROGRAM_BINARY_LOAD + return false; +#else + reset(); - if (fragmentShader->mUsesFragCoord) + BinaryInputStream stream(binary, length); + + int format = stream.readInt<int>(); + if (format != GL_PROGRAM_BINARY_ANGLE) { - fragCoordSemantic = varyingSemantic + str(reservedRegisterIndex++); + infoLog.append("Invalid program binary format."); + return false; } - if (fragmentShader->mUsesPointCoord) + int majorVersion = stream.readInt<int>(); + int minorVersion = stream.readInt<int>(); + if (majorVersion != ANGLE_MAJOR_VERSION || minorVersion != ANGLE_MINOR_VERSION) { - // Shader model 3 uses a special TEXCOORD semantic for point sprite texcoords. - // In DX11 we compute this in the GS. - if (shaderModel == 3) - { - pointCoordSemantic = "TEXCOORD0"; - } - else if (shaderModel >= 4) - { - pointCoordSemantic = varyingSemantic + str(reservedRegisterIndex++); - } + infoLog.append("Invalid program binary version."); + return false; } - vertexHLSL += "struct VS_INPUT\n" - "{\n"; - - int semanticIndex = 0; - for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++) + unsigned char commitString[ANGLE_COMMIT_HASH_SIZE]; + stream.readBytes(commitString, ANGLE_COMMIT_HASH_SIZE); + if (memcmp(commitString, ANGLE_COMMIT_HASH, sizeof(unsigned char) * ANGLE_COMMIT_HASH_SIZE) != 0) { - switch (attribute->type) - { - case GL_FLOAT: vertexHLSL += " float "; break; - case GL_FLOAT_VEC2: vertexHLSL += " float2 "; break; - case GL_FLOAT_VEC3: vertexHLSL += " float3 "; break; - case GL_FLOAT_VEC4: vertexHLSL += " float4 "; break; - case GL_FLOAT_MAT2: vertexHLSL += " float2x2 "; break; - case GL_FLOAT_MAT3: vertexHLSL += " float3x3 "; break; - case GL_FLOAT_MAT4: vertexHLSL += " float4x4 "; break; - default: UNREACHABLE(); - } - - vertexHLSL += decorateAttribute(attribute->name) + " : TEXCOORD" + str(semanticIndex) + ";\n"; - - semanticIndex += VariableRowCount(attribute->type); + infoLog.append("Invalid program binary version."); + return false; } - vertexHLSL += "};\n" - "\n" - "struct VS_OUTPUT\n" - "{\n"; - - if (shaderModel < 4) + int compileFlags = stream.readInt<int>(); + if (compileFlags != ANGLE_COMPILE_OPTIMIZATION_LEVEL) { - vertexHLSL += " float4 gl_Position : " + positionSemantic + ";\n"; + infoLog.append("Mismatched compilation flags."); + return false; } - for (int r = 0; r < registers; r++) + for (int i = 0; i < MAX_VERTEX_ATTRIBS; ++i) { - int registerSize = packing[r][3] ? 4 : (packing[r][2] ? 3 : (packing[r][1] ? 2 : 1)); - - vertexHLSL += " float" + str(registerSize) + " v" + str(r) + " : " + varyingSemantic + str(r) + ";\n"; + stream.readInt(&mLinkedAttribute[i].type); + stream.readString(&mLinkedAttribute[i].name); + stream.readInt(&mShaderAttributes[i].type); + stream.readString(&mShaderAttributes[i].name); + stream.readInt(&mSemanticIndex[i]); } - if (fragmentShader->mUsesFragCoord) + initAttributesByLayout(); + + for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i) { - vertexHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n"; + stream.readBool(&mSamplersPS[i].active); + stream.readInt(&mSamplersPS[i].logicalTextureUnit); + stream.readInt(&mSamplersPS[i].textureType); } - if (vertexShader->mUsesPointSize && shaderModel >= 3) + for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i) { - vertexHLSL += " float gl_PointSize : PSIZE;\n"; + stream.readBool(&mSamplersVS[i].active); + stream.readInt(&mSamplersVS[i].logicalTextureUnit); + stream.readInt(&mSamplersVS[i].textureType); } - if (shaderModel >= 4) + stream.readInt(&mUsedVertexSamplerRange); + stream.readInt(&mUsedPixelSamplerRange); + stream.readBool(&mUsesPointSize); + stream.readInt(&mShaderVersion); + + const unsigned int uniformCount = stream.readInt<unsigned int>(); + if (stream.error()) { - vertexHLSL += " float4 gl_Position : " + positionSemantic + ";\n"; + infoLog.append("Invalid program binary."); + return false; } - vertexHLSL += "};\n" - "\n" - "VS_OUTPUT main(VS_INPUT input)\n" - "{\n"; - - for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++) + mUniforms.resize(uniformCount); + for (unsigned int uniformIndex = 0; uniformIndex < uniformCount; uniformIndex++) { - vertexHLSL += " " + decorateAttribute(attribute->name) + " = "; + GLenum type = stream.readInt<GLenum>(); + GLenum precision = stream.readInt<GLenum>(); + std::string name = stream.readString(); + unsigned int arraySize = stream.readInt<unsigned int>(); + int blockIndex = stream.readInt<int>(); - if (VariableRowCount(attribute->type) > 1) // Matrix - { - vertexHLSL += "transpose"; - } + int offset = stream.readInt<int>(); + int arrayStride = stream.readInt<int>(); + int matrixStride = stream.readInt<int>(); + bool isRowMajorMatrix = stream.readBool(); - vertexHLSL += "(input." + decorateAttribute(attribute->name) + ");\n"; - } + const sh::BlockMemberInfo blockInfo(offset, arrayStride, matrixStride, isRowMajorMatrix); - if (shaderModel >= 4) - { - vertexHLSL += "\n" - " gl_main();\n" - "\n" - " VS_OUTPUT output;\n" - " output.gl_Position.x = gl_Position.x;\n" - " output.gl_Position.y = -gl_Position.y;\n" - " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n" - " output.gl_Position.w = gl_Position.w;\n"; - } - else - { - vertexHLSL += "\n" - " gl_main();\n" - "\n" - " VS_OUTPUT output;\n" - " output.gl_Position.x = gl_Position.x * dx_ViewAdjust.z + dx_ViewAdjust.x * gl_Position.w;\n" - " output.gl_Position.y = -(gl_Position.y * dx_ViewAdjust.w + dx_ViewAdjust.y * gl_Position.w);\n" - " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n" - " output.gl_Position.w = gl_Position.w;\n"; - } + LinkedUniform *uniform = new LinkedUniform(type, precision, name, arraySize, blockIndex, blockInfo); - if (vertexShader->mUsesPointSize && shaderModel >= 3) - { - vertexHLSL += " output.gl_PointSize = gl_PointSize;\n"; + stream.readInt(&uniform->psRegisterIndex); + stream.readInt(&uniform->vsRegisterIndex); + stream.readInt(&uniform->registerCount); + stream.readInt(&uniform->registerElement); + + mUniforms[uniformIndex] = uniform; } - if (fragmentShader->mUsesFragCoord) + unsigned int uniformBlockCount = stream.readInt<unsigned int>(); + if (stream.error()) { - vertexHLSL += " output.gl_FragCoord = gl_Position;\n"; + infoLog.append("Invalid program binary."); + return false; } - for (VaryingList::iterator varying = vertexShader->mVaryings.begin(); varying != vertexShader->mVaryings.end(); varying++) + mUniformBlocks.resize(uniformBlockCount); + for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < uniformBlockCount; ++uniformBlockIndex) { - if (varying->reg >= 0) - { - for (int i = 0; i < varying->size; i++) - { - int rows = VariableRowCount(varying->type); - - for (int j = 0; j < rows; j++) - { - int r = varying->reg + i * rows + j; - vertexHLSL += " output.v" + str(r); - - bool sharedRegister = false; // Register used by multiple varyings - - for (int x = 0; x < 4; x++) - { - if (packing[r][x] && packing[r][x] != packing[r][0]) - { - sharedRegister = true; - break; - } - } + std::string name = stream.readString(); + unsigned int elementIndex = stream.readInt<unsigned int>(); + unsigned int dataSize = stream.readInt<unsigned int>(); - if(sharedRegister) - { - vertexHLSL += "."; - - for (int x = 0; x < 4; x++) - { - if (packing[r][x] == &*varying) - { - switch(x) - { - case 0: vertexHLSL += "x"; break; - case 1: vertexHLSL += "y"; break; - case 2: vertexHLSL += "z"; break; - case 3: vertexHLSL += "w"; break; - } - } - } - } - - vertexHLSL += " = " + varying->name; - - if (varying->array) - { - vertexHLSL += "[" + str(i) + "]"; - } - - if (rows > 1) - { - vertexHLSL += "[" + str(j) + "]"; - } - - vertexHLSL += ";\n"; - } - } - } - } + UniformBlock *uniformBlock = new UniformBlock(name, elementIndex, dataSize); - vertexHLSL += "\n" - " return output;\n" - "}\n"; + stream.readInt(&uniformBlock->psRegisterIndex); + stream.readInt(&uniformBlock->vsRegisterIndex); - pixelHLSL += "struct PS_INPUT\n" - "{\n"; - - for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++) - { - if (varying->reg >= 0) + unsigned int numMembers = stream.readInt<unsigned int>(); + uniformBlock->memberUniformIndexes.resize(numMembers); + for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++) { - for (int i = 0; i < varying->size; i++) - { - int rows = VariableRowCount(varying->type); - for (int j = 0; j < rows; j++) - { - std::string n = str(varying->reg + i * rows + j); - pixelHLSL += " float" + str(VariableColumnCount(varying->type)) + " v" + n + " : " + varyingSemantic + n + ";\n"; - } - } + stream.readInt(&uniformBlock->memberUniformIndexes[blockMemberIndex]); } - else UNREACHABLE(); + + mUniformBlocks[uniformBlockIndex] = uniformBlock; } - if (fragmentShader->mUsesFragCoord) + const unsigned int uniformIndexCount = stream.readInt<unsigned int>(); + if (stream.error()) { - pixelHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n"; + infoLog.append("Invalid program binary."); + return false; } - - if (fragmentShader->mUsesPointCoord && shaderModel >= 3) + + mUniformIndex.resize(uniformIndexCount); + for (unsigned int uniformIndexIndex = 0; uniformIndexIndex < uniformIndexCount; uniformIndexIndex++) { - pixelHLSL += " float2 gl_PointCoord : " + pointCoordSemantic + ";\n"; + stream.readString(&mUniformIndex[uniformIndexIndex].name); + stream.readInt(&mUniformIndex[uniformIndexIndex].element); + stream.readInt(&mUniformIndex[uniformIndexIndex].index); } - // Must consume the PSIZE element if the geometry shader is not active - // We won't know if we use a GS until we draw - if (vertexShader->mUsesPointSize && shaderModel >= 4) + stream.readInt(&mTransformFeedbackBufferMode); + const unsigned int transformFeedbackVaryingCount = stream.readInt<unsigned int>(); + mTransformFeedbackLinkedVaryings.resize(transformFeedbackVaryingCount); + for (unsigned int varyingIndex = 0; varyingIndex < transformFeedbackVaryingCount; varyingIndex++) { - pixelHLSL += " float gl_PointSize : PSIZE;\n"; + LinkedVarying &varying = mTransformFeedbackLinkedVaryings[varyingIndex]; + + stream.readString(&varying.name); + stream.readInt(&varying.type); + stream.readInt(&varying.size); + stream.readString(&varying.semanticName); + stream.readInt(&varying.semanticIndex); + stream.readInt(&varying.semanticIndexCount); } - if (fragmentShader->mUsesFragCoord) + stream.readString(&mVertexHLSL); + + stream.readInt(&mVertexWorkarounds); + + const unsigned int vertexShaderCount = stream.readInt<unsigned int>(); + for (unsigned int vertexShaderIndex = 0; vertexShaderIndex < vertexShaderCount; vertexShaderIndex++) { - if (shaderModel >= 4) + VertexFormat inputLayout[MAX_VERTEX_ATTRIBS]; + + for (size_t inputIndex = 0; inputIndex < MAX_VERTEX_ATTRIBS; inputIndex++) { - pixelHLSL += " float4 dx_VPos : SV_Position;\n"; + VertexFormat *vertexInput = &inputLayout[inputIndex]; + stream.readInt(&vertexInput->mType); + stream.readInt(&vertexInput->mNormalized); + stream.readInt(&vertexInput->mComponents); + stream.readBool(&vertexInput->mPureInteger); } - else if (shaderModel >= 3) + + unsigned int vertexShaderSize = stream.readInt<unsigned int>(); + const unsigned char *vertexShaderFunction = reinterpret_cast<const unsigned char*>(binary) + stream.offset(); + rx::ShaderExecutable *shaderExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(vertexShaderFunction), + vertexShaderSize, rx::SHADER_VERTEX, + mTransformFeedbackLinkedVaryings, + (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS)); + if (!shaderExecutable) { - pixelHLSL += " float2 dx_VPos : VPOS;\n"; + infoLog.append("Could not create vertex shader."); + return false; } - } - pixelHLSL += "};\n" - "\n" - "struct PS_OUTPUT\n" - "{\n"; + // generated converted input layout + GLenum signature[MAX_VERTEX_ATTRIBS]; + mDynamicHLSL->getInputLayoutSignature(inputLayout, signature); - for (unsigned int renderTargetIndex = 0; renderTargetIndex < numRenderTargets; renderTargetIndex++) - { - pixelHLSL += " float4 gl_Color" + str(renderTargetIndex) + " : " + targetSemantic + str(renderTargetIndex) + ";\n"; - } + // add new binary + mVertexExecutables.push_back(new VertexExecutable(inputLayout, signature, shaderExecutable)); - if (fragmentShader->mUsesFragDepth) - { - pixelHLSL += " float gl_Depth : " + depthSemantic + ";\n"; + stream.skip(vertexShaderSize); } - pixelHLSL += "};\n" - "\n"; + stream.readString(&mPixelHLSL); + stream.readInt(&mPixelWorkarounds); + stream.readBool(&mUsesFragDepth); - if (fragmentShader->mUsesFrontFacing) + const size_t pixelShaderKeySize = stream.readInt<unsigned int>(); + mPixelShaderKey.resize(pixelShaderKeySize); + for (size_t pixelShaderKeyIndex = 0; pixelShaderKeyIndex < pixelShaderKeySize; pixelShaderKeyIndex++) { - if (shaderModel >= 4) - { - pixelHLSL += "PS_OUTPUT main(PS_INPUT input, bool isFrontFace : SV_IsFrontFace)\n" - "{\n"; - } - else - { - pixelHLSL += "PS_OUTPUT main(PS_INPUT input, float vFace : VFACE)\n" - "{\n"; - } - } - else - { - pixelHLSL += "PS_OUTPUT main(PS_INPUT input)\n" - "{\n"; + stream.readInt(&mPixelShaderKey[pixelShaderKeyIndex].type); + stream.readString(&mPixelShaderKey[pixelShaderKeyIndex].name); + stream.readString(&mPixelShaderKey[pixelShaderKeyIndex].source); + stream.readInt(&mPixelShaderKey[pixelShaderKeyIndex].outputIndex); } - if (fragmentShader->mUsesFragCoord) + const size_t pixelShaderCount = stream.readInt<unsigned int>(); + for (size_t pixelShaderIndex = 0; pixelShaderIndex < pixelShaderCount; pixelShaderIndex++) { - pixelHLSL += " float rhw = 1.0 / input.gl_FragCoord.w;\n"; - - if (shaderModel >= 4) + const size_t outputCount = stream.readInt<unsigned int>(); + std::vector<GLenum> outputs(outputCount); + for (size_t outputIndex = 0; outputIndex < outputCount; outputIndex++) { - pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x;\n" - " gl_FragCoord.y = input.dx_VPos.y;\n"; + stream.readInt(&outputs[outputIndex]); } - else if (shaderModel >= 3) - { - pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x + 0.5;\n" - " gl_FragCoord.y = input.dx_VPos.y + 0.5;\n"; - } - else + + const size_t pixelShaderSize = stream.readInt<unsigned int>(); + const unsigned char *pixelShaderFunction = reinterpret_cast<const unsigned char*>(binary) + stream.offset(); + rx::ShaderExecutable *shaderExecutable = mRenderer->loadExecutable(pixelShaderFunction, pixelShaderSize, + rx::SHADER_PIXEL, + mTransformFeedbackLinkedVaryings, + (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS)); + if (!shaderExecutable) { - // dx_ViewCoords contains the viewport width/2, height/2, center.x and center.y. See Renderer::setViewport() - pixelHLSL += " gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * dx_ViewCoords.x + dx_ViewCoords.z;\n" - " gl_FragCoord.y = (input.gl_FragCoord.y * rhw) * dx_ViewCoords.y + dx_ViewCoords.w;\n"; + infoLog.append("Could not create pixel shader."); + return false; } - - pixelHLSL += " gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * dx_DepthFront.x + dx_DepthFront.y;\n" - " gl_FragCoord.w = rhw;\n"; - } - if (fragmentShader->mUsesPointCoord && shaderModel >= 3) - { - pixelHLSL += " gl_PointCoord.x = input.gl_PointCoord.x;\n"; - pixelHLSL += " gl_PointCoord.y = 1.0 - input.gl_PointCoord.y;\n"; - } + // add new binary + mPixelExecutables.push_back(new PixelExecutable(outputs, shaderExecutable)); - if (fragmentShader->mUsesFrontFacing) - { - if (shaderModel <= 3) - { - pixelHLSL += " gl_FrontFacing = (vFace * dx_DepthFront.z >= 0.0);\n"; - } - else - { - pixelHLSL += " gl_FrontFacing = isFrontFace;\n"; - } + stream.skip(pixelShaderSize); } - for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++) + unsigned int geometryShaderSize = stream.readInt<unsigned int>(); + + if (geometryShaderSize > 0) { - if (varying->reg >= 0) + const char *geometryShaderFunction = (const char*) binary + stream.offset(); + mGeometryExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(geometryShaderFunction), + geometryShaderSize, rx::SHADER_GEOMETRY, mTransformFeedbackLinkedVaryings, + (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS)); + if (!mGeometryExecutable) { - for (int i = 0; i < varying->size; i++) - { - int rows = VariableRowCount(varying->type); - for (int j = 0; j < rows; j++) - { - std::string n = str(varying->reg + i * rows + j); - pixelHLSL += " " + varying->name; - - if (varying->array) - { - pixelHLSL += "[" + str(i) + "]"; - } - - if (rows > 1) - { - pixelHLSL += "[" + str(j) + "]"; - } - - switch (VariableColumnCount(varying->type)) - { - case 1: pixelHLSL += " = input.v" + n + ".x;\n"; break; - case 2: pixelHLSL += " = input.v" + n + ".xy;\n"; break; - case 3: pixelHLSL += " = input.v" + n + ".xyz;\n"; break; - case 4: pixelHLSL += " = input.v" + n + ";\n"; break; - default: UNREACHABLE(); - } - } - } + infoLog.append("Could not create geometry shader."); + return false; } - else UNREACHABLE(); + stream.skip(geometryShaderSize); } - pixelHLSL += "\n" - " gl_main();\n" - "\n" - " PS_OUTPUT output;\n"; - - for (unsigned int renderTargetIndex = 0; renderTargetIndex < numRenderTargets; renderTargetIndex++) - { - unsigned int sourceColorIndex = broadcast ? 0 : renderTargetIndex; + const char *ptr = (const char*) binary + stream.offset(); - pixelHLSL += " output.gl_Color" + str(renderTargetIndex) + " = gl_Color[" + str(sourceColorIndex) + "];\n"; - } + const GUID *binaryIdentifier = (const GUID *) ptr; + ptr += sizeof(GUID); - if (fragmentShader->mUsesFragDepth) + GUID identifier = mRenderer->getAdapterIdentifier(); + if (memcmp(&identifier, binaryIdentifier, sizeof(GUID)) != 0) { - pixelHLSL += " output.gl_Depth = gl_Depth;\n"; + infoLog.append("Invalid program binary."); + return false; } - pixelHLSL += "\n" - " return output;\n" - "}\n"; + initializeUniformStorage(); return true; +#endif // #ifdef ANGLE_DISABLE_PROGRAM_BINARY_LOAD } -bool ProgramBinary::load(InfoLog &infoLog, const void *binary, GLsizei length) +bool ProgramBinary::save(void* binary, GLsizei bufSize, GLsizei *length) { - BinaryInputStream stream(binary, length); - - int format = 0; - stream.read(&format); - if (format != GL_PROGRAM_BINARY_ANGLE) - { - infoLog.append("Invalid program binary format."); - return false; - } - - int majorVersion = 0; - int minorVersion = 0; - stream.read(&majorVersion); - stream.read(&minorVersion); - if (majorVersion != ANGLE_MAJOR_VERSION || minorVersion != ANGLE_MINOR_VERSION) - { - infoLog.append("Invalid program binary version."); - return false; - } - -#if !defined(ANGLE_ENABLE_UNIVERSAL_BINARY) - unsigned char commitString[ANGLE_COMMIT_HASH_SIZE]; - stream.read(commitString, ANGLE_COMMIT_HASH_SIZE); - if (memcmp(commitString, ANGLE_COMMIT_HASH, sizeof(unsigned char) * ANGLE_COMMIT_HASH_SIZE) != 0) - { - infoLog.append("Invalid program binary version."); - return false; - } + BinaryOutputStream stream; - int compileFlags = 0; - stream.read(&compileFlags); - if (compileFlags != ANGLE_COMPILE_OPTIMIZATION_LEVEL) - { - infoLog.append("Mismatched compilation flags."); - return false; - } -#endif + stream.writeInt(GL_PROGRAM_BINARY_ANGLE); + stream.writeInt(ANGLE_MAJOR_VERSION); + stream.writeInt(ANGLE_MINOR_VERSION); + stream.writeBytes(reinterpret_cast<const unsigned char*>(ANGLE_COMMIT_HASH), ANGLE_COMMIT_HASH_SIZE); + stream.writeInt(ANGLE_COMPILE_OPTIMIZATION_LEVEL); - for (int i = 0; i < MAX_VERTEX_ATTRIBS; ++i) + for (unsigned int i = 0; i < MAX_VERTEX_ATTRIBS; ++i) { - stream.read(&mLinkedAttribute[i].type); - std::string name; - stream.read(&name); - mLinkedAttribute[i].name = name; - stream.read(&mSemanticIndex[i]); + stream.writeInt(mLinkedAttribute[i].type); + stream.writeString(mLinkedAttribute[i].name); + stream.writeInt(mShaderAttributes[i].type); + stream.writeString(mShaderAttributes[i].name); + stream.writeInt(mSemanticIndex[i]); } - initAttributesByLayout(); - for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i) { - stream.read(&mSamplersPS[i].active); - stream.read(&mSamplersPS[i].logicalTextureUnit); - - int textureType; - stream.read(&textureType); - mSamplersPS[i].textureType = (TextureType) textureType; + stream.writeInt(mSamplersPS[i].active); + stream.writeInt(mSamplersPS[i].logicalTextureUnit); + stream.writeInt(mSamplersPS[i].textureType); } for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i) { - stream.read(&mSamplersVS[i].active); - stream.read(&mSamplersVS[i].logicalTextureUnit); - - int textureType; - stream.read(&textureType); - mSamplersVS[i].textureType = (TextureType) textureType; + stream.writeInt(mSamplersVS[i].active); + stream.writeInt(mSamplersVS[i].logicalTextureUnit); + stream.writeInt(mSamplersVS[i].textureType); } - stream.read(&mUsedVertexSamplerRange); - stream.read(&mUsedPixelSamplerRange); - stream.read(&mUsesPointSize); + stream.writeInt(mUsedVertexSamplerRange); + stream.writeInt(mUsedPixelSamplerRange); + stream.writeInt(mUsesPointSize); + stream.writeInt(mShaderVersion); - size_t size; - stream.read(&size); - if (stream.error()) + stream.writeInt(mUniforms.size()); + for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); ++uniformIndex) { - infoLog.append("Invalid program binary."); - return false; - } - - mUniforms.resize(size); - for (unsigned int i = 0; i < size; ++i) - { - GLenum type; - GLenum precision; - std::string name; - unsigned int arraySize; + const LinkedUniform &uniform = *mUniforms[uniformIndex]; - stream.read(&type); - stream.read(&precision); - stream.read(&name); - stream.read(&arraySize); + stream.writeInt(uniform.type); + stream.writeInt(uniform.precision); + stream.writeString(uniform.name); + stream.writeInt(uniform.arraySize); + stream.writeInt(uniform.blockIndex); - mUniforms[i] = new Uniform(type, precision, name, arraySize); - - stream.read(&mUniforms[i]->psRegisterIndex); - stream.read(&mUniforms[i]->vsRegisterIndex); - stream.read(&mUniforms[i]->registerCount); - } + stream.writeInt(uniform.blockInfo.offset); + stream.writeInt(uniform.blockInfo.arrayStride); + stream.writeInt(uniform.blockInfo.matrixStride); + stream.writeInt(uniform.blockInfo.isRowMajorMatrix); - stream.read(&size); - if (stream.error()) - { - infoLog.append("Invalid program binary."); - return false; + stream.writeInt(uniform.psRegisterIndex); + stream.writeInt(uniform.vsRegisterIndex); + stream.writeInt(uniform.registerCount); + stream.writeInt(uniform.registerElement); } - mUniformIndex.resize(size); - for (unsigned int i = 0; i < size; ++i) + stream.writeInt(mUniformBlocks.size()); + for (size_t uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); ++uniformBlockIndex) { - stream.read(&mUniformIndex[i].name); - stream.read(&mUniformIndex[i].element); - stream.read(&mUniformIndex[i].index); - } + const UniformBlock& uniformBlock = *mUniformBlocks[uniformBlockIndex]; - unsigned int pixelShaderSize; - stream.read(&pixelShaderSize); + stream.writeString(uniformBlock.name); + stream.writeInt(uniformBlock.elementIndex); + stream.writeInt(uniformBlock.dataSize); - unsigned int vertexShaderSize; - stream.read(&vertexShaderSize); - - unsigned int geometryShaderSize; - stream.read(&geometryShaderSize); - - const char *ptr = (const char*) binary + stream.offset(); - -#if !defined(ANGLE_ENABLE_UNIVERSAL_BINARY) - const GUID *binaryIdentifier = (const GUID *) ptr; - ptr += sizeof(GUID); + stream.writeInt(uniformBlock.memberUniformIndexes.size()); + for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++) + { + stream.writeInt(uniformBlock.memberUniformIndexes[blockMemberIndex]); + } - GUID identifier = mRenderer->getAdapterIdentifier(); - if (memcmp(&identifier, binaryIdentifier, sizeof(GUID)) != 0) - { - infoLog.append("Invalid program binary."); - return false; + stream.writeInt(uniformBlock.psRegisterIndex); + stream.writeInt(uniformBlock.vsRegisterIndex); } -#endif - - const char *pixelShaderFunction = ptr; - ptr += pixelShaderSize; - - const char *vertexShaderFunction = ptr; - ptr += vertexShaderSize; - const char *geometryShaderFunction = geometryShaderSize > 0 ? ptr : NULL; - ptr += geometryShaderSize; - - mPixelExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(pixelShaderFunction), - pixelShaderSize, rx::SHADER_PIXEL); - if (!mPixelExecutable) + stream.writeInt(mUniformIndex.size()); + for (size_t i = 0; i < mUniformIndex.size(); ++i) { - infoLog.append("Could not create pixel shader."); - return false; + stream.writeString(mUniformIndex[i].name); + stream.writeInt(mUniformIndex[i].element); + stream.writeInt(mUniformIndex[i].index); } - mVertexExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(vertexShaderFunction), - vertexShaderSize, rx::SHADER_VERTEX); - if (!mVertexExecutable) + stream.writeInt(mTransformFeedbackBufferMode); + stream.writeInt(mTransformFeedbackLinkedVaryings.size()); + for (size_t i = 0; i < mTransformFeedbackLinkedVaryings.size(); i++) { - infoLog.append("Could not create vertex shader."); - delete mPixelExecutable; - mPixelExecutable = NULL; - return false; + const LinkedVarying &varying = mTransformFeedbackLinkedVaryings[i]; + + stream.writeString(varying.name); + stream.writeInt(varying.type); + stream.writeInt(varying.size); + stream.writeString(varying.semanticName); + stream.writeInt(varying.semanticIndex); + stream.writeInt(varying.semanticIndexCount); } - if (geometryShaderFunction != NULL && geometryShaderSize > 0) + stream.writeString(mVertexHLSL); + stream.writeInt(mVertexWorkarounds); + + stream.writeInt(mVertexExecutables.size()); + for (size_t vertexExecutableIndex = 0; vertexExecutableIndex < mVertexExecutables.size(); vertexExecutableIndex++) { - mGeometryExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(geometryShaderFunction), - geometryShaderSize, rx::SHADER_GEOMETRY); - if (!mGeometryExecutable) + VertexExecutable *vertexExecutable = mVertexExecutables[vertexExecutableIndex]; + + for (size_t inputIndex = 0; inputIndex < gl::MAX_VERTEX_ATTRIBS; inputIndex++) { - infoLog.append("Could not create geometry shader."); - delete mPixelExecutable; - mPixelExecutable = NULL; - delete mVertexExecutable; - mVertexExecutable = NULL; - return false; + const VertexFormat &vertexInput = vertexExecutable->inputs()[inputIndex]; + stream.writeInt(vertexInput.mType); + stream.writeInt(vertexInput.mNormalized); + stream.writeInt(vertexInput.mComponents); + stream.writeInt(vertexInput.mPureInteger); } - } - else - { - mGeometryExecutable = NULL; - } - return true; -} - -bool ProgramBinary::save(void* binary, GLsizei bufSize, GLsizei *length) -{ - BinaryOutputStream stream; + size_t vertexShaderSize = vertexExecutable->shaderExecutable()->getLength(); + stream.writeInt(vertexShaderSize); - stream.write(GL_PROGRAM_BINARY_ANGLE); - stream.write(ANGLE_MAJOR_VERSION); - stream.write(ANGLE_MINOR_VERSION); -#if !defined(ANGLE_ENABLE_UNIVERSAL_BINARY) - stream.write(ANGLE_COMMIT_HASH, ANGLE_COMMIT_HASH_SIZE); - stream.write(ANGLE_COMPILE_OPTIMIZATION_LEVEL); -#endif - for (unsigned int i = 0; i < MAX_VERTEX_ATTRIBS; ++i) - { - stream.write(mLinkedAttribute[i].type); - stream.write(mLinkedAttribute[i].name); - stream.write(mSemanticIndex[i]); + const uint8_t *vertexBlob = vertexExecutable->shaderExecutable()->getFunction(); + stream.writeBytes(vertexBlob, vertexShaderSize); } - for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i) + stream.writeString(mPixelHLSL); + stream.writeInt(mPixelWorkarounds); + stream.writeInt(mUsesFragDepth); + + stream.writeInt(mPixelShaderKey.size()); + for (size_t pixelShaderKeyIndex = 0; pixelShaderKeyIndex < mPixelShaderKey.size(); pixelShaderKeyIndex++) { - stream.write(mSamplersPS[i].active); - stream.write(mSamplersPS[i].logicalTextureUnit); - stream.write((int) mSamplersPS[i].textureType); + const PixelShaderOuputVariable &variable = mPixelShaderKey[pixelShaderKeyIndex]; + stream.writeInt(variable.type); + stream.writeString(variable.name); + stream.writeString(variable.source); + stream.writeInt(variable.outputIndex); } - for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i) + stream.writeInt(mPixelExecutables.size()); + for (size_t pixelExecutableIndex = 0; pixelExecutableIndex < mPixelExecutables.size(); pixelExecutableIndex++) { - stream.write(mSamplersVS[i].active); - stream.write(mSamplersVS[i].logicalTextureUnit); - stream.write((int) mSamplersVS[i].textureType); - } + PixelExecutable *pixelExecutable = mPixelExecutables[pixelExecutableIndex]; - stream.write(mUsedVertexSamplerRange); - stream.write(mUsedPixelSamplerRange); - stream.write(mUsesPointSize); + const std::vector<GLenum> outputs = pixelExecutable->outputSignature(); + stream.writeInt(outputs.size()); + for (size_t outputIndex = 0; outputIndex < outputs.size(); outputIndex++) + { + stream.writeInt(outputs[outputIndex]); + } - stream.write(mUniforms.size()); - for (unsigned int i = 0; i < mUniforms.size(); ++i) - { - stream.write(mUniforms[i]->type); - stream.write(mUniforms[i]->precision); - stream.write(mUniforms[i]->name); - stream.write(mUniforms[i]->arraySize); + size_t pixelShaderSize = pixelExecutable->shaderExecutable()->getLength(); + stream.writeInt(pixelShaderSize); - stream.write(mUniforms[i]->psRegisterIndex); - stream.write(mUniforms[i]->vsRegisterIndex); - stream.write(mUniforms[i]->registerCount); + const uint8_t *pixelBlob = pixelExecutable->shaderExecutable()->getFunction(); + stream.writeBytes(pixelBlob, pixelShaderSize); } - stream.write(mUniformIndex.size()); - for (unsigned int i = 0; i < mUniformIndex.size(); ++i) + size_t geometryShaderSize = (mGeometryExecutable != NULL) ? mGeometryExecutable->getLength() : 0; + stream.writeInt(geometryShaderSize); + + if (mGeometryExecutable != NULL && geometryShaderSize > 0) { - stream.write(mUniformIndex[i].name); - stream.write(mUniformIndex[i].element); - stream.write(mUniformIndex[i].index); + const uint8_t *geometryBlob = mGeometryExecutable->getFunction(); + stream.writeBytes(geometryBlob, geometryShaderSize); } - UINT pixelShaderSize = mPixelExecutable->getLength(); - stream.write(pixelShaderSize); - - UINT vertexShaderSize = mVertexExecutable->getLength(); - stream.write(vertexShaderSize); - - UINT geometryShaderSize = (mGeometryExecutable != NULL) ? mGeometryExecutable->getLength() : 0; - stream.write(geometryShaderSize); - -#if !defined(ANGLE_ENABLE_UNIVERSAL_BINARY) GUID identifier = mRenderer->getAdapterIdentifier(); -#endif GLsizei streamLength = stream.length(); const void *streamData = stream.data(); - GLsizei totalLength = streamLength + sizeof(GUID) + pixelShaderSize + vertexShaderSize + geometryShaderSize; + GLsizei totalLength = streamLength + sizeof(GUID); if (totalLength > bufSize) { if (length) @@ -1896,22 +1566,8 @@ bool ProgramBinary::save(void* binary, GLsizei bufSize, GLsizei *length) memcpy(ptr, streamData, streamLength); ptr += streamLength; -#if !defined(ANGLE_ENABLE_UNIVERSAL_BINARY) memcpy(ptr, &identifier, sizeof(GUID)); ptr += sizeof(GUID); -#endif - - memcpy(ptr, mPixelExecutable->getFunction(), pixelShaderSize); - ptr += pixelShaderSize; - - memcpy(ptr, mVertexExecutable->getFunction(), vertexShaderSize); - ptr += vertexShaderSize; - - if (mGeometryExecutable != NULL && geometryShaderSize > 0) - { - memcpy(ptr, mGeometryExecutable->getFunction(), geometryShaderSize); - ptr += geometryShaderSize; - } ASSERT(ptr - totalLength == binary); } @@ -1937,7 +1593,8 @@ GLint ProgramBinary::getLength() } } -bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader) +bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader, + const std::vector<std::string>& transformFeedbackVaryings, GLenum transformFeedbackBufferMode) { if (!fragmentShader || !fragmentShader->isCompiled()) { @@ -1949,19 +1606,37 @@ bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBin return false; } - std::string pixelHLSL = fragmentShader->getHLSL(); - std::string vertexHLSL = vertexShader->getHLSL(); + reset(); + + mTransformFeedbackBufferMode = transformFeedbackBufferMode; + + mShaderVersion = vertexShader->getShaderVersion(); + + mPixelHLSL = fragmentShader->getHLSL(); + mPixelWorkarounds = fragmentShader->getD3DWorkarounds(); + + mVertexHLSL = vertexShader->getHLSL(); + mVertexWorkarounds = vertexShader->getD3DWorkarounds(); // Map the varyings to the register file - const Varying *packing[IMPLEMENTATION_MAX_VARYING_VECTORS][4] = {NULL}; - int registers = packVaryings(infoLog, packing, fragmentShader); + VaryingPacking packing = { NULL }; + int registers = mDynamicHLSL->packVaryings(infoLog, packing, fragmentShader, vertexShader, transformFeedbackVaryings); if (registers < 0) { return false; } - if (!linkVaryings(infoLog, registers, packing, pixelHLSL, vertexHLSL, fragmentShader, vertexShader)) + if (!linkVaryings(infoLog, fragmentShader, vertexShader)) + { + return false; + } + + mUsesPointSize = vertexShader->usesPointSize(); + std::vector<LinkedVarying> linkedVaryings; + if (!mDynamicHLSL->generateShaderLinkHLSL(infoLog, registers, packing, mPixelHLSL, mVertexHLSL, + fragmentShader, vertexShader, transformFeedbackVaryings, + &linkedVaryings, &mOutputVariables, &mPixelShaderKey, &mUsesFragDepth)) { return false; } @@ -1973,41 +1648,59 @@ bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBin success = false; } - if (!linkUniforms(infoLog, vertexShader->getUniforms(), fragmentShader->getUniforms())) + if (!linkUniforms(infoLog, *vertexShader, *fragmentShader)) { success = false; } // special case for gl_DepthRange, the only built-in uniform (also a struct) - if (vertexShader->mUsesDepthRange || fragmentShader->mUsesDepthRange) + if (vertexShader->usesDepthRange() || fragmentShader->usesDepthRange()) { - mUniforms.push_back(new Uniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.near", 0)); - mUniforms.push_back(new Uniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.far", 0)); - mUniforms.push_back(new Uniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.diff", 0)); + const sh::BlockMemberInfo &defaultInfo = sh::BlockMemberInfo::getDefaultBlockInfo(); + + mUniforms.push_back(new LinkedUniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.near", 0, -1, defaultInfo)); + mUniforms.push_back(new LinkedUniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.far", 0, -1, defaultInfo)); + mUniforms.push_back(new LinkedUniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.diff", 0, -1, defaultInfo)); + } + + if (!linkUniformBlocks(infoLog, *vertexShader, *fragmentShader)) + { + success = false; + } + + if (!gatherTransformFeedbackLinkedVaryings(infoLog, linkedVaryings, transformFeedbackVaryings, + transformFeedbackBufferMode, &mTransformFeedbackLinkedVaryings)) + { + success = false; } if (success) { - mVertexExecutable = mRenderer->compileToExecutable(infoLog, vertexHLSL.c_str(), rx::SHADER_VERTEX, DiscardWorkaround(vertexShader->mUsesDiscardRewriting)); - mPixelExecutable = mRenderer->compileToExecutable(infoLog, pixelHLSL.c_str(), rx::SHADER_PIXEL, DiscardWorkaround(fragmentShader->mUsesDiscardRewriting)); + VertexFormat defaultInputLayout[MAX_VERTEX_ATTRIBS]; + GetInputLayoutFromShader(vertexShader->activeAttributes(), defaultInputLayout); + rx::ShaderExecutable *defaultVertexExecutable = getVertexExecutableForInputLayout(defaultInputLayout); + + std::vector<GLenum> defaultPixelOutput(IMPLEMENTATION_MAX_DRAW_BUFFERS); + for (size_t i = 0; i < defaultPixelOutput.size(); i++) + { + defaultPixelOutput[i] = (i == 0) ? GL_FLOAT : GL_NONE; + } + rx::ShaderExecutable *defaultPixelExecutable = getPixelExecutableForOutputLayout(defaultPixelOutput); if (usesGeometryShader()) { - std::string geometryHLSL = generateGeometryShaderHLSL(registers, packing, fragmentShader, vertexShader); - mGeometryExecutable = mRenderer->compileToExecutable(infoLog, geometryHLSL.c_str(), rx::SHADER_GEOMETRY, rx::ANGLE_D3D_WORKAROUND_NONE); + std::string geometryHLSL = mDynamicHLSL->generateGeometryShaderHLSL(registers, fragmentShader, vertexShader); + mGeometryExecutable = mRenderer->compileToExecutable(infoLog, geometryHLSL.c_str(), rx::SHADER_GEOMETRY, + mTransformFeedbackLinkedVaryings, + (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS), + rx::ANGLE_D3D_WORKAROUND_NONE); } - if (!mVertexExecutable || !mPixelExecutable || (usesGeometryShader() && !mGeometryExecutable)) + if (!defaultVertexExecutable || !defaultPixelExecutable || (usesGeometryShader() && !mGeometryExecutable)) { infoLog.append("Failed to create D3D shaders."); success = false; - - delete mVertexExecutable; - mVertexExecutable = NULL; - delete mPixelExecutable; - mPixelExecutable = NULL; - delete mGeometryExecutable; - mGeometryExecutable = NULL; + reset(); } } @@ -2018,62 +1711,75 @@ bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBin bool ProgramBinary::linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader) { unsigned int usedLocations = 0; + const std::vector<sh::Attribute> &activeAttributes = vertexShader->activeAttributes(); // Link attributes that have a binding location - for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++) + for (unsigned int attributeIndex = 0; attributeIndex < activeAttributes.size(); attributeIndex++) { - int location = attributeBindings.getAttributeBinding(attribute->name); - - if (location != -1) // Set by glBindAttribLocation - { - if (!mLinkedAttribute[location].name.empty()) - { - // Multiple active attributes bound to the same location; not an error - } + const sh::Attribute &attribute = activeAttributes[attributeIndex]; + const int location = attribute.location == -1 ? attributeBindings.getAttributeBinding(attribute.name) : attribute.location; - mLinkedAttribute[location] = *attribute; + mShaderAttributes[attributeIndex] = attribute; - int rows = VariableRowCount(attribute->type); + if (location != -1) // Set by glBindAttribLocation or by location layout qualifier + { + const int rows = VariableRegisterCount(attribute.type); if (rows + location > MAX_VERTEX_ATTRIBS) { - infoLog.append("Active attribute (%s) at location %d is too big to fit", attribute->name.c_str(), location); + infoLog.append("Active attribute (%s) at location %d is too big to fit", attribute.name.c_str(), location); return false; } - for (int i = 0; i < rows; i++) + for (int row = 0; row < rows; row++) { - usedLocations |= 1 << (location + i); + const int rowLocation = location + row; + sh::ShaderVariable &linkedAttribute = mLinkedAttribute[rowLocation]; + + // In GLSL 3.00, attribute aliasing produces a link error + // In GLSL 1.00, attribute aliasing is allowed + if (mShaderVersion >= 300) + { + if (!linkedAttribute.name.empty()) + { + infoLog.append("Attribute '%s' aliases attribute '%s' at location %d", attribute.name.c_str(), linkedAttribute.name.c_str(), rowLocation); + return false; + } + } + + linkedAttribute = attribute; + usedLocations |= 1 << rowLocation; } } } // Link attributes that don't have a binding location - for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++) + for (unsigned int attributeIndex = 0; attributeIndex < activeAttributes.size(); attributeIndex++) { - int location = attributeBindings.getAttributeBinding(attribute->name); + const sh::Attribute &attribute = activeAttributes[attributeIndex]; + const int location = attribute.location == -1 ? attributeBindings.getAttributeBinding(attribute.name) : attribute.location; - if (location == -1) // Not set by glBindAttribLocation + if (location == -1) // Not set by glBindAttribLocation or by location layout qualifier { - int rows = VariableRowCount(attribute->type); + int rows = VariableRegisterCount(attribute.type); int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS); if (availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS) { - infoLog.append("Too many active attributes (%s)", attribute->name.c_str()); + infoLog.append("Too many active attributes (%s)", attribute.name.c_str()); return false; // Fail to link } - mLinkedAttribute[availableIndex] = *attribute; + mLinkedAttribute[availableIndex] = attribute; } } for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; ) { int index = vertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name); - int rows = std::max(VariableRowCount(mLinkedAttribute[attributeIndex].type), 1); + int rows = VariableRegisterCount(mLinkedAttribute[attributeIndex].type); for (int r = 0; r < rows; r++) { @@ -2086,19 +1792,51 @@ bool ProgramBinary::linkAttributes(InfoLog &infoLog, const AttributeBindings &at return true; } -bool ProgramBinary::linkUniforms(InfoLog &infoLog, const sh::ActiveUniforms &vertexUniforms, const sh::ActiveUniforms &fragmentUniforms) +bool ProgramBinary::linkValidateVariablesBase(InfoLog &infoLog, const std::string &variableName, const sh::ShaderVariable &vertexVariable, + const sh::ShaderVariable &fragmentVariable, bool validatePrecision) { - for (sh::ActiveUniforms::const_iterator uniform = vertexUniforms.begin(); uniform != vertexUniforms.end(); uniform++) + if (vertexVariable.type != fragmentVariable.type) + { + infoLog.append("Types for %s differ between vertex and fragment shaders", variableName.c_str()); + return false; + } + if (vertexVariable.arraySize != fragmentVariable.arraySize) { - if (!defineUniform(GL_VERTEX_SHADER, *uniform, infoLog)) + infoLog.append("Array sizes for %s differ between vertex and fragment shaders", variableName.c_str()); + return false; + } + if (validatePrecision && vertexVariable.precision != fragmentVariable.precision) + { + infoLog.append("Precisions for %s differ between vertex and fragment shaders", variableName.c_str()); + return false; + } + + return true; +} + +template <class ShaderVarType> +bool ProgramBinary::linkValidateFields(InfoLog &infoLog, const std::string &varName, const ShaderVarType &vertexVar, const ShaderVarType &fragmentVar) +{ + if (vertexVar.fields.size() != fragmentVar.fields.size()) + { + infoLog.append("Structure lengths for %s differ between vertex and fragment shaders", varName.c_str()); + return false; + } + const unsigned int numMembers = vertexVar.fields.size(); + for (unsigned int memberIndex = 0; memberIndex < numMembers; memberIndex++) + { + const ShaderVarType &vertexMember = vertexVar.fields[memberIndex]; + const ShaderVarType &fragmentMember = fragmentVar.fields[memberIndex]; + + if (vertexMember.name != fragmentMember.name) { + infoLog.append("Name mismatch for field '%d' of %s: (in vertex: '%s', in fragment: '%s')", + memberIndex, varName.c_str(), vertexMember.name.c_str(), fragmentMember.name.c_str()); return false; } - } - for (sh::ActiveUniforms::const_iterator uniform = fragmentUniforms.begin(); uniform != fragmentUniforms.end(); uniform++) - { - if (!defineUniform(GL_FRAGMENT_SHADER, *uniform, infoLog)) + const std::string memberName = varName.substr(0, varName.length()-1) + "." + vertexVar.name + "'"; + if (!linkValidateVariables(infoLog, memberName, vertexMember, fragmentMember)) { return false; } @@ -2107,274 +1845,571 @@ bool ProgramBinary::linkUniforms(InfoLog &infoLog, const sh::ActiveUniforms &ver return true; } -bool ProgramBinary::defineUniform(GLenum shader, const sh::Uniform &constant, InfoLog &infoLog) +bool ProgramBinary::linkValidateVariables(InfoLog &infoLog, const std::string &uniformName, const sh::Uniform &vertexUniform, const sh::Uniform &fragmentUniform) { - if (constant.type == GL_SAMPLER_2D || - constant.type == GL_SAMPLER_CUBE) + if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, true)) { - unsigned int samplerIndex = constant.registerIndex; - - do - { - if (shader == GL_VERTEX_SHADER) - { - if (samplerIndex < mRenderer->getMaxVertexTextureImageUnits()) - { - mSamplersVS[samplerIndex].active = true; - mSamplersVS[samplerIndex].textureType = (constant.type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D; - mSamplersVS[samplerIndex].logicalTextureUnit = 0; - mUsedVertexSamplerRange = std::max(samplerIndex + 1, mUsedVertexSamplerRange); - } - else - { - infoLog.append("Vertex shader sampler count exceeds the maximum vertex texture units (%d).", mRenderer->getMaxVertexTextureImageUnits()); - return false; - } - } - else if (shader == GL_FRAGMENT_SHADER) - { - if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS) - { - mSamplersPS[samplerIndex].active = true; - mSamplersPS[samplerIndex].textureType = (constant.type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D; - mSamplersPS[samplerIndex].logicalTextureUnit = 0; - mUsedPixelSamplerRange = std::max(samplerIndex + 1, mUsedPixelSamplerRange); - } - else - { - infoLog.append("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", MAX_TEXTURE_IMAGE_UNITS); - return false; - } - } - else UNREACHABLE(); + return false; + } - samplerIndex++; - } - while (samplerIndex < constant.registerIndex + constant.arraySize); + if (!linkValidateFields<sh::Uniform>(infoLog, uniformName, vertexUniform, fragmentUniform)) + { + return false; } - Uniform *uniform = NULL; - GLint location = getUniformLocation(constant.name); + return true; +} - if (location >= 0) // Previously defined, type and precision must match +bool ProgramBinary::linkValidateVariables(InfoLog &infoLog, const std::string &varyingName, const sh::Varying &vertexVarying, const sh::Varying &fragmentVarying) +{ + if (!linkValidateVariablesBase(infoLog, varyingName, vertexVarying, fragmentVarying, false)) { - uniform = mUniforms[mUniformIndex[location].index]; + return false; + } - if (uniform->type != constant.type) - { - infoLog.append("Types for uniform %s do not match between the vertex and fragment shader", uniform->name.c_str()); - return false; - } + if (vertexVarying.interpolation != fragmentVarying.interpolation) + { + infoLog.append("Interpolation types for %s differ between vertex and fragment shaders", varyingName.c_str()); + return false; + } - if (uniform->precision != constant.precision) - { - infoLog.append("Precisions for uniform %s do not match between the vertex and fragment shader", uniform->name.c_str()); - return false; - } + if (!linkValidateFields<sh::Varying>(infoLog, varyingName, vertexVarying, fragmentVarying)) + { + return false; } - else + + return true; +} + +bool ProgramBinary::linkValidateVariables(InfoLog &infoLog, const std::string &uniformName, const sh::InterfaceBlockField &vertexUniform, const sh::InterfaceBlockField &fragmentUniform) +{ + if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, true)) { - uniform = new Uniform(constant.type, constant.precision, constant.name, constant.arraySize); + return false; } - if (!uniform) + if (vertexUniform.isRowMajorMatrix != fragmentUniform.isRowMajorMatrix) { + infoLog.append("Matrix packings for %s differ between vertex and fragment shaders", uniformName.c_str()); return false; } - if (shader == GL_FRAGMENT_SHADER) + if (!linkValidateFields<sh::InterfaceBlockField>(infoLog, uniformName, vertexUniform, fragmentUniform)) { - uniform->psRegisterIndex = constant.registerIndex; + return false; } - else if (shader == GL_VERTEX_SHADER) + + return true; +} + +bool ProgramBinary::linkUniforms(InfoLog &infoLog, const VertexShader &vertexShader, const FragmentShader &fragmentShader) +{ + const std::vector<sh::Uniform> &vertexUniforms = vertexShader.getUniforms(); + const std::vector<sh::Uniform> &fragmentUniforms = fragmentShader.getUniforms(); + + // Check that uniforms defined in the vertex and fragment shaders are identical + typedef std::map<std::string, const sh::Uniform*> UniformMap; + UniformMap linkedUniforms; + + for (unsigned int vertexUniformIndex = 0; vertexUniformIndex < vertexUniforms.size(); vertexUniformIndex++) { - uniform->vsRegisterIndex = constant.registerIndex; + const sh::Uniform &vertexUniform = vertexUniforms[vertexUniformIndex]; + linkedUniforms[vertexUniform.name] = &vertexUniform; + } + + for (unsigned int fragmentUniformIndex = 0; fragmentUniformIndex < fragmentUniforms.size(); fragmentUniformIndex++) + { + const sh::Uniform &fragmentUniform = fragmentUniforms[fragmentUniformIndex]; + UniformMap::const_iterator entry = linkedUniforms.find(fragmentUniform.name); + if (entry != linkedUniforms.end()) + { + const sh::Uniform &vertexUniform = *entry->second; + const std::string &uniformName = "uniform '" + vertexUniform.name + "'"; + if (!linkValidateVariables(infoLog, uniformName, vertexUniform, fragmentUniform)) + { + return false; + } + } } - else UNREACHABLE(); - if (location >= 0) + for (unsigned int uniformIndex = 0; uniformIndex < vertexUniforms.size(); uniformIndex++) { - return uniform->type == constant.type; + const sh::Uniform &uniform = vertexUniforms[uniformIndex]; + defineUniformBase(GL_VERTEX_SHADER, uniform, vertexShader.getUniformRegister(uniform.name)); } - mUniforms.push_back(uniform); - unsigned int uniformIndex = mUniforms.size() - 1; + for (unsigned int uniformIndex = 0; uniformIndex < fragmentUniforms.size(); uniformIndex++) + { + const sh::Uniform &uniform = fragmentUniforms[uniformIndex]; + defineUniformBase(GL_FRAGMENT_SHADER, uniform, fragmentShader.getUniformRegister(uniform.name)); + } - for (unsigned int i = 0; i < uniform->elementCount(); i++) + if (!indexUniforms(infoLog)) { - mUniformIndex.push_back(UniformLocation(constant.name, i, uniformIndex)); + return false; } - if (shader == GL_VERTEX_SHADER) + initializeUniformStorage(); + + return true; +} + +void ProgramBinary::defineUniformBase(GLenum shader, const sh::Uniform &uniform, unsigned int uniformRegister) +{ + ShShaderOutput outputType = Shader::getCompilerOutputType(shader); + sh::HLSLBlockEncoder encoder(sh::HLSLBlockEncoder::GetStrategyFor(outputType)); + encoder.skipRegisters(uniformRegister); + + defineUniform(shader, uniform, uniform.name, &encoder); +} + +void ProgramBinary::defineUniform(GLenum shader, const sh::Uniform &uniform, + const std::string &fullName, sh::HLSLBlockEncoder *encoder) +{ + if (uniform.isStruct()) + { + for (unsigned int elementIndex = 0; elementIndex < uniform.elementCount(); elementIndex++) + { + const std::string &elementString = (uniform.isArray() ? ArrayString(elementIndex) : ""); + + encoder->enterAggregateType(); + + for (size_t fieldIndex = 0; fieldIndex < uniform.fields.size(); fieldIndex++) + { + const sh::Uniform &field = uniform.fields[fieldIndex]; + const std::string &fieldFullName = (fullName + elementString + "." + field.name); + + defineUniform(shader, field, fieldFullName, encoder); + } + + encoder->exitAggregateType(); + } + } + else // Not a struct + { + // Arrays are treated as aggregate types + if (uniform.isArray()) + { + encoder->enterAggregateType(); + } + + LinkedUniform *linkedUniform = getUniformByName(fullName); + + if (!linkedUniform) + { + linkedUniform = new LinkedUniform(uniform.type, uniform.precision, fullName, uniform.arraySize, + -1, sh::BlockMemberInfo::getDefaultBlockInfo()); + ASSERT(linkedUniform); + linkedUniform->registerElement = encoder->getCurrentElement(); + mUniforms.push_back(linkedUniform); + } + + ASSERT(linkedUniform->registerElement == encoder->getCurrentElement()); + + if (shader == GL_FRAGMENT_SHADER) + { + linkedUniform->psRegisterIndex = encoder->getCurrentRegister(); + } + else if (shader == GL_VERTEX_SHADER) + { + linkedUniform->vsRegisterIndex = encoder->getCurrentRegister(); + } + else UNREACHABLE(); + + // Advance the uniform offset, to track registers allocation for structs + encoder->encodeType(uniform.type, uniform.arraySize, false); + + // Arrays are treated as aggregate types + if (uniform.isArray()) + { + encoder->exitAggregateType(); + } + } +} + +bool ProgramBinary::indexSamplerUniform(const LinkedUniform &uniform, InfoLog &infoLog) +{ + ASSERT(IsSampler(uniform.type)); + ASSERT(uniform.vsRegisterIndex != GL_INVALID_INDEX || uniform.psRegisterIndex != GL_INVALID_INDEX); + + if (uniform.vsRegisterIndex != GL_INVALID_INDEX) { - if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedVertexUniformVectors() + mRenderer->getMaxVertexUniformVectors()) + if (!assignSamplers(uniform.vsRegisterIndex, uniform.type, uniform.arraySize, mSamplersVS, + &mUsedVertexSamplerRange, mRenderer->getMaxVertexTextureImageUnits())) + { + infoLog.append("Vertex shader sampler count exceeds the maximum vertex texture units (%d).", + mRenderer->getMaxVertexTextureImageUnits()); + return false; + } + + unsigned int maxVertexVectors = mRenderer->getReservedVertexUniformVectors() + + mRenderer->getMaxVertexUniformVectors(); + if (uniform.vsRegisterIndex + uniform.registerCount > maxVertexVectors) { - infoLog.append("Vertex shader active uniforms exceed GL_MAX_VERTEX_UNIFORM_VECTORS (%u)", mRenderer->getMaxVertexUniformVectors()); + infoLog.append("Vertex shader active uniforms exceed GL_MAX_VERTEX_UNIFORM_VECTORS (%u)", + mRenderer->getMaxVertexUniformVectors()); return false; } } - else if (shader == GL_FRAGMENT_SHADER) + + if (uniform.psRegisterIndex != GL_INVALID_INDEX) { - if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedFragmentUniformVectors() + mRenderer->getMaxFragmentUniformVectors()) + if (!assignSamplers(uniform.psRegisterIndex, uniform.type, uniform.arraySize, mSamplersPS, + &mUsedPixelSamplerRange, MAX_TEXTURE_IMAGE_UNITS)) { - infoLog.append("Fragment shader active uniforms exceed GL_MAX_FRAGMENT_UNIFORM_VECTORS (%u)", mRenderer->getMaxFragmentUniformVectors()); + infoLog.append("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", + MAX_TEXTURE_IMAGE_UNITS); + return false; + } + + unsigned int maxFragmentVectors = mRenderer->getReservedFragmentUniformVectors() + + mRenderer->getMaxFragmentUniformVectors(); + if (uniform.psRegisterIndex + uniform.registerCount > maxFragmentVectors) + { + infoLog.append("Fragment shader active uniforms exceed GL_MAX_FRAGMENT_UNIFORM_VECTORS (%u)", + mRenderer->getMaxFragmentUniformVectors()); return false; } } - else UNREACHABLE(); return true; } -std::string ProgramBinary::generateGeometryShaderHLSL(int registers, const Varying *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const +bool ProgramBinary::indexUniforms(InfoLog &infoLog) { - // for now we only handle point sprite emulation - ASSERT(usesPointSpriteEmulation()); - return generatePointSpriteHLSL(registers, packing, fragmentShader, vertexShader); + for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++) + { + const LinkedUniform &uniform = *mUniforms[uniformIndex]; + + if (IsSampler(uniform.type)) + { + if (!indexSamplerUniform(uniform, infoLog)) + { + return false; + } + } + + for (unsigned int arrayElementIndex = 0; arrayElementIndex < uniform.elementCount(); arrayElementIndex++) + { + mUniformIndex.push_back(VariableLocation(uniform.name, arrayElementIndex, uniformIndex)); + } + } + + return true; } -std::string ProgramBinary::generatePointSpriteHLSL(int registers, const Varying *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const +bool ProgramBinary::assignSamplers(unsigned int startSamplerIndex, + GLenum samplerType, + unsigned int samplerCount, + Sampler *outArray, + GLuint *usedRange, + unsigned int limit) { - ASSERT(registers >= 0); - ASSERT(vertexShader->mUsesPointSize); - ASSERT(mRenderer->getMajorShaderModel() >= 4); + unsigned int samplerIndex = startSamplerIndex; - std::string geomHLSL; + do + { + if (samplerIndex < limit) + { + outArray[samplerIndex].active = true; + outArray[samplerIndex].textureType = GetTextureType(samplerType); + outArray[samplerIndex].logicalTextureUnit = 0; + *usedRange = std::max(samplerIndex + 1, *usedRange); + } + else + { + return false; + } - std::string varyingSemantic = "TEXCOORD"; + samplerIndex++; + } while (samplerIndex < startSamplerIndex + samplerCount); - std::string fragCoordSemantic; - std::string pointCoordSemantic; + return true; +} - int reservedRegisterIndex = registers; +bool ProgramBinary::areMatchingInterfaceBlocks(InfoLog &infoLog, const sh::InterfaceBlock &vertexInterfaceBlock, const sh::InterfaceBlock &fragmentInterfaceBlock) +{ + const char* blockName = vertexInterfaceBlock.name.c_str(); - if (fragmentShader->mUsesFragCoord) + // validate blocks for the same member types + if (vertexInterfaceBlock.fields.size() != fragmentInterfaceBlock.fields.size()) { - fragCoordSemantic = varyingSemantic + str(reservedRegisterIndex++); + infoLog.append("Types for interface block '%s' differ between vertex and fragment shaders", blockName); + return false; } - if (fragmentShader->mUsesPointCoord) + if (vertexInterfaceBlock.arraySize != fragmentInterfaceBlock.arraySize) { - pointCoordSemantic = varyingSemantic + str(reservedRegisterIndex++); + infoLog.append("Array sizes differ for interface block '%s' between vertex and fragment shaders", blockName); + return false; } - geomHLSL += "uniform float4 dx_ViewCoords : register(c1);\n" - "\n" - "struct GS_INPUT\n" - "{\n"; - - for (int r = 0; r < registers; r++) + if (vertexInterfaceBlock.layout != fragmentInterfaceBlock.layout || vertexInterfaceBlock.isRowMajorLayout != fragmentInterfaceBlock.isRowMajorLayout) { - int registerSize = packing[r][3] ? 4 : (packing[r][2] ? 3 : (packing[r][1] ? 2 : 1)); - - geomHLSL += " float" + str(registerSize) + " v" + str(r) + " : " + varyingSemantic + str(r) + ";\n"; + infoLog.append("Layout qualifiers differ for interface block '%s' between vertex and fragment shaders", blockName); + return false; } - if (fragmentShader->mUsesFragCoord) + const unsigned int numBlockMembers = vertexInterfaceBlock.fields.size(); + for (unsigned int blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++) { - geomHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n"; + const sh::InterfaceBlockField &vertexMember = vertexInterfaceBlock.fields[blockMemberIndex]; + const sh::InterfaceBlockField &fragmentMember = fragmentInterfaceBlock.fields[blockMemberIndex]; + + if (vertexMember.name != fragmentMember.name) + { + infoLog.append("Name mismatch for field %d of interface block '%s': (in vertex: '%s', in fragment: '%s')", + blockMemberIndex, blockName, vertexMember.name.c_str(), fragmentMember.name.c_str()); + return false; + } + + std::string uniformName = "interface block '" + vertexInterfaceBlock.name + "' member '" + vertexMember.name + "'"; + if (!linkValidateVariables(infoLog, uniformName, vertexMember, fragmentMember)) + { + return false; + } } - geomHLSL += " float gl_PointSize : PSIZE;\n" - " float4 gl_Position : SV_Position;\n" - "};\n" - "\n" - "struct GS_OUTPUT\n" - "{\n"; + return true; +} + +bool ProgramBinary::linkUniformBlocks(InfoLog &infoLog, const VertexShader &vertexShader, + const FragmentShader &fragmentShader) +{ + const std::vector<sh::InterfaceBlock> &vertexInterfaceBlocks = vertexShader.getInterfaceBlocks(); + const std::vector<sh::InterfaceBlock> &fragmentInterfaceBlocks = fragmentShader.getInterfaceBlocks(); + + // Check that interface blocks defined in the vertex and fragment shaders are identical + typedef std::map<std::string, const sh::InterfaceBlock*> UniformBlockMap; + UniformBlockMap linkedUniformBlocks; - for (int r = 0; r < registers; r++) + for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++) { - int registerSize = packing[r][3] ? 4 : (packing[r][2] ? 3 : (packing[r][1] ? 2 : 1)); + const sh::InterfaceBlock &vertexInterfaceBlock = vertexInterfaceBlocks[blockIndex]; + linkedUniformBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock; + } - geomHLSL += " float" + str(registerSize) + " v" + str(r) + " : " + varyingSemantic + str(r) + ";\n"; + for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++) + { + const sh::InterfaceBlock &fragmentInterfaceBlock = fragmentInterfaceBlocks[blockIndex]; + UniformBlockMap::const_iterator entry = linkedUniformBlocks.find(fragmentInterfaceBlock.name); + if (entry != linkedUniformBlocks.end()) + { + const sh::InterfaceBlock &vertexInterfaceBlock = *entry->second; + if (!areMatchingInterfaceBlocks(infoLog, vertexInterfaceBlock, fragmentInterfaceBlock)) + { + return false; + } + } } - if (fragmentShader->mUsesFragCoord) + for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++) { - geomHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n"; + if (!defineUniformBlock(infoLog, vertexShader, vertexInterfaceBlocks[blockIndex])) + { + return false; + } } - if (fragmentShader->mUsesPointCoord) + for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++) { - geomHLSL += " float2 gl_PointCoord : " + pointCoordSemantic + ";\n"; + if (!defineUniformBlock(infoLog, fragmentShader, fragmentInterfaceBlocks[blockIndex])) + { + return false; + } } - geomHLSL += " float gl_PointSize : PSIZE;\n" - " float4 gl_Position : SV_Position;\n" - "};\n" - "\n" - "static float2 pointSpriteCorners[] = \n" - "{\n" - " float2( 0.5f, -0.5f),\n" - " float2( 0.5f, 0.5f),\n" - " float2(-0.5f, -0.5f),\n" - " float2(-0.5f, 0.5f)\n" - "};\n" - "\n" - "static float2 pointSpriteTexcoords[] = \n" - "{\n" - " float2(1.0f, 1.0f),\n" - " float2(1.0f, 0.0f),\n" - " float2(0.0f, 1.0f),\n" - " float2(0.0f, 0.0f)\n" - "};\n" - "\n" - "static float minPointSize = " + str(ALIASED_POINT_SIZE_RANGE_MIN) + ".0f;\n" - "static float maxPointSize = " + str(mRenderer->getMaxPointSize()) + ".0f;\n" - "\n" - "[maxvertexcount(4)]\n" - "void main(point GS_INPUT input[1], inout TriangleStream<GS_OUTPUT> outStream)\n" - "{\n" - " GS_OUTPUT output = (GS_OUTPUT)0;\n" - " output.gl_PointSize = input[0].gl_PointSize;\n"; + return true; +} + +bool ProgramBinary::gatherTransformFeedbackLinkedVaryings(InfoLog &infoLog, const std::vector<LinkedVarying> &linkedVaryings, + const std::vector<std::string> &transformFeedbackVaryingNames, + GLenum transformFeedbackBufferMode, + std::vector<LinkedVarying> *outTransformFeedbackLinkedVaryings) const +{ + size_t totalComponents = 0; + const size_t maxSeparateComponents = mRenderer->getMaxTransformFeedbackSeparateComponents(); + const size_t maxInterleavedComponents = mRenderer->getMaxTransformFeedbackInterleavedComponents(); - for (int r = 0; r < registers; r++) + // Gather the linked varyings that are used for transform feedback, they should all exist. + outTransformFeedbackLinkedVaryings->clear(); + for (size_t i = 0; i < transformFeedbackVaryingNames.size(); i++) { - geomHLSL += " output.v" + str(r) + " = input[0].v" + str(r) + ";\n"; + bool found = false; + for (size_t j = 0; j < linkedVaryings.size(); j++) + { + if (transformFeedbackVaryingNames[i] == linkedVaryings[j].name) + { + for (size_t k = 0; k < outTransformFeedbackLinkedVaryings->size(); k++) + { + if (outTransformFeedbackLinkedVaryings->at(k).name == linkedVaryings[j].name) + { + infoLog.append("Two transform feedback varyings specify the same output variable (%s).", linkedVaryings[j].name.c_str()); + return false; + } + } + + size_t componentCount = linkedVaryings[j].semanticIndexCount * 4; + if (transformFeedbackBufferMode == GL_SEPARATE_ATTRIBS && + componentCount > maxSeparateComponents) + { + infoLog.append("Transform feedback varying's %s components (%u) exceed the maximum separate components (%u).", + linkedVaryings[j].name.c_str(), componentCount, maxSeparateComponents); + return false; + } + + totalComponents += componentCount; + + outTransformFeedbackLinkedVaryings->push_back(linkedVaryings[j]); + found = true; + break; + } + } + + // All transform feedback varyings are expected to exist since packVaryings checks for them. + ASSERT(found); } - if (fragmentShader->mUsesFragCoord) + if (transformFeedbackBufferMode == GL_INTERLEAVED_ATTRIBS && totalComponents > maxInterleavedComponents) { - geomHLSL += " output.gl_FragCoord = input[0].gl_FragCoord;\n"; + infoLog.append("Transform feedback varying total components (%u) exceed the maximum interleaved components (%u).", + totalComponents, maxInterleavedComponents); + return false; } - geomHLSL += " \n" - " float gl_PointSize = clamp(input[0].gl_PointSize, minPointSize, maxPointSize);\n" - " float4 gl_Position = input[0].gl_Position;\n" - " float2 viewportScale = float2(1.0f / dx_ViewCoords.x, 1.0f / dx_ViewCoords.y) * gl_Position.w;\n"; + return true; +} - for (int corner = 0; corner < 4; corner++) +void ProgramBinary::defineUniformBlockMembers(const std::vector<sh::InterfaceBlockField> &fields, const std::string &prefix, int blockIndex, + sh::BlockLayoutEncoder *encoder, std::vector<unsigned int> *blockUniformIndexes) +{ + for (unsigned int uniformIndex = 0; uniformIndex < fields.size(); uniformIndex++) { - geomHLSL += " \n" - " output.gl_Position = gl_Position + float4(pointSpriteCorners[" + str(corner) + "] * viewportScale * gl_PointSize, 0.0f, 0.0f);\n"; + const sh::InterfaceBlockField &field = fields[uniformIndex]; + const std::string &fieldName = (prefix.empty() ? field.name : prefix + "." + field.name); - if (fragmentShader->mUsesPointCoord) + if (field.isStruct()) { - geomHLSL += " output.gl_PointCoord = pointSpriteTexcoords[" + str(corner) + "];\n"; + for (unsigned int arrayElement = 0; arrayElement < field.elementCount(); arrayElement++) + { + encoder->enterAggregateType(); + + const std::string uniformElementName = fieldName + (field.isArray() ? ArrayString(arrayElement) : ""); + defineUniformBlockMembers(field.fields, uniformElementName, blockIndex, encoder, blockUniformIndexes); + + encoder->exitAggregateType(); + } } + else + { + sh::BlockMemberInfo memberInfo = encoder->encodeInterfaceBlockField(field); + + LinkedUniform *newUniform = new LinkedUniform(field.type, field.precision, fieldName, field.arraySize, + blockIndex, memberInfo); - geomHLSL += " outStream.Append(output);\n"; + // add to uniform list, but not index, since uniform block uniforms have no location + blockUniformIndexes->push_back(mUniforms.size()); + mUniforms.push_back(newUniform); + } } +} + +bool ProgramBinary::defineUniformBlock(InfoLog &infoLog, const Shader &shader, const sh::InterfaceBlock &interfaceBlock) +{ + // create uniform block entries if they do not exist + if (getUniformBlockIndex(interfaceBlock.name) == GL_INVALID_INDEX) + { + std::vector<unsigned int> blockUniformIndexes; + const unsigned int blockIndex = mUniformBlocks.size(); + + // define member uniforms + sh::BlockLayoutEncoder *encoder = NULL; + + if (interfaceBlock.layout == sh::BLOCKLAYOUT_STANDARD) + { + encoder = new sh::Std140BlockEncoder; + } + else + { + encoder = new sh::HLSLBlockEncoder(sh::HLSLBlockEncoder::ENCODE_PACKED); + } + ASSERT(encoder); + + defineUniformBlockMembers(interfaceBlock.fields, "", blockIndex, encoder, &blockUniformIndexes); - geomHLSL += " \n" - " outStream.RestartStrip();\n" - "}\n"; + size_t dataSize = encoder->getBlockSize(); - return geomHLSL; + // create all the uniform blocks + if (interfaceBlock.arraySize > 0) + { + for (unsigned int uniformBlockElement = 0; uniformBlockElement < interfaceBlock.arraySize; uniformBlockElement++) + { + UniformBlock *newUniformBlock = new UniformBlock(interfaceBlock.name, uniformBlockElement, dataSize); + newUniformBlock->memberUniformIndexes = blockUniformIndexes; + mUniformBlocks.push_back(newUniformBlock); + } + } + else + { + UniformBlock *newUniformBlock = new UniformBlock(interfaceBlock.name, GL_INVALID_INDEX, dataSize); + newUniformBlock->memberUniformIndexes = blockUniformIndexes; + mUniformBlocks.push_back(newUniformBlock); + } + } + + // Assign registers to the uniform blocks + const GLuint blockIndex = getUniformBlockIndex(interfaceBlock.name); + const unsigned int elementCount = std::max(1u, interfaceBlock.arraySize); + ASSERT(blockIndex != GL_INVALID_INDEX); + ASSERT(blockIndex + elementCount <= mUniformBlocks.size()); + + unsigned int interfaceBlockRegister = shader.getInterfaceBlockRegister(interfaceBlock.name); + + for (unsigned int uniformBlockElement = 0; uniformBlockElement < elementCount; uniformBlockElement++) + { + UniformBlock *uniformBlock = mUniformBlocks[blockIndex + uniformBlockElement]; + ASSERT(uniformBlock->name == interfaceBlock.name); + + if (!assignUniformBlockRegister(infoLog, uniformBlock, shader.getType(), + interfaceBlockRegister + uniformBlockElement)) + { + return false; + } + } + + return true; } -// This method needs to match OutputHLSL::decorate -std::string ProgramBinary::decorateAttribute(const std::string &name) +bool ProgramBinary::assignUniformBlockRegister(InfoLog &infoLog, UniformBlock *uniformBlock, GLenum shader, unsigned int registerIndex) { - if (name.compare(0, 3, "gl_") != 0 && name.compare(0, 3, "dx_") != 0) + if (shader == GL_VERTEX_SHADER) { - return "_" + name; + uniformBlock->vsRegisterIndex = registerIndex; + unsigned int maximumBlocks = mRenderer->getMaxVertexShaderUniformBuffers(); + + if (registerIndex - mRenderer->getReservedVertexUniformBuffers() >= maximumBlocks) + { + infoLog.append("Vertex shader uniform block count exceed GL_MAX_VERTEX_UNIFORM_BLOCKS (%u)", maximumBlocks); + return false; + } } - - return name; + else if (shader == GL_FRAGMENT_SHADER) + { + uniformBlock->psRegisterIndex = registerIndex; + unsigned int maximumBlocks = mRenderer->getMaxFragmentShaderUniformBuffers(); + + if (registerIndex - mRenderer->getReservedFragmentUniformBuffers() >= maximumBlocks) + { + infoLog.append("Fragment shader uniform block count exceed GL_MAX_FRAGMENT_UNIFORM_BLOCKS (%u)", maximumBlocks); + return false; + } + } + else UNREACHABLE(); + + return true; } -bool ProgramBinary::isValidated() const +bool ProgramBinary::isValidated() const { return mValidated; } @@ -2500,6 +2535,141 @@ GLint ProgramBinary::getActiveUniformMaxLength() const return maxLength; } +GLint ProgramBinary::getActiveUniformi(GLuint index, GLenum pname) const +{ + const gl::LinkedUniform& uniform = *mUniforms[index]; + + switch (pname) + { + case GL_UNIFORM_TYPE: return static_cast<GLint>(uniform.type); + case GL_UNIFORM_SIZE: return static_cast<GLint>(uniform.elementCount()); + case GL_UNIFORM_NAME_LENGTH: return static_cast<GLint>(uniform.name.size() + 1 + (uniform.isArray() ? 3 : 0)); + case GL_UNIFORM_BLOCK_INDEX: return uniform.blockIndex; + + case GL_UNIFORM_OFFSET: return uniform.blockInfo.offset; + case GL_UNIFORM_ARRAY_STRIDE: return uniform.blockInfo.arrayStride; + case GL_UNIFORM_MATRIX_STRIDE: return uniform.blockInfo.matrixStride; + case GL_UNIFORM_IS_ROW_MAJOR: return static_cast<GLint>(uniform.blockInfo.isRowMajorMatrix); + + default: + UNREACHABLE(); + break; + } + return 0; +} + +bool ProgramBinary::isValidUniformLocation(GLint location) const +{ + ASSERT(rx::IsIntegerCastSafe<GLint>(mUniformIndex.size())); + return (location >= 0 && location < static_cast<GLint>(mUniformIndex.size())); +} + +LinkedUniform *ProgramBinary::getUniformByLocation(GLint location) const +{ + ASSERT(location >= 0 && static_cast<size_t>(location) < mUniformIndex.size()); + return mUniforms[mUniformIndex[location].index]; +} + +LinkedUniform *ProgramBinary::getUniformByName(const std::string &name) const +{ + for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++) + { + if (mUniforms[uniformIndex]->name == name) + { + return mUniforms[uniformIndex]; + } + } + + return NULL; +} + +void ProgramBinary::getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const +{ + ASSERT(uniformBlockIndex < mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount() + + const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex]; + + if (bufSize > 0) + { + std::string string = uniformBlock.name; + + if (uniformBlock.isArrayElement()) + { + string += ArrayString(uniformBlock.elementIndex); + } + + strncpy(uniformBlockName, string.c_str(), bufSize); + uniformBlockName[bufSize - 1] = '\0'; + + if (length) + { + *length = strlen(uniformBlockName); + } + } +} + +void ProgramBinary::getActiveUniformBlockiv(GLuint uniformBlockIndex, GLenum pname, GLint *params) const +{ + ASSERT(uniformBlockIndex < mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount() + + const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex]; + + switch (pname) + { + case GL_UNIFORM_BLOCK_DATA_SIZE: + *params = static_cast<GLint>(uniformBlock.dataSize); + break; + case GL_UNIFORM_BLOCK_NAME_LENGTH: + *params = static_cast<GLint>(uniformBlock.name.size() + 1 + (uniformBlock.isArrayElement() ? 3 : 0)); + break; + case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS: + *params = static_cast<GLint>(uniformBlock.memberUniformIndexes.size()); + break; + case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES: + { + for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++) + { + params[blockMemberIndex] = static_cast<GLint>(uniformBlock.memberUniformIndexes[blockMemberIndex]); + } + } + break; + case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER: + *params = static_cast<GLint>(uniformBlock.isReferencedByVertexShader()); + break; + case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER: + *params = static_cast<GLint>(uniformBlock.isReferencedByFragmentShader()); + break; + default: UNREACHABLE(); + } +} + +GLuint ProgramBinary::getActiveUniformBlockCount() const +{ + return mUniformBlocks.size(); +} + +GLuint ProgramBinary::getActiveUniformBlockMaxLength() const +{ + unsigned int maxLength = 0; + + unsigned int numUniformBlocks = mUniformBlocks.size(); + for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < numUniformBlocks; uniformBlockIndex++) + { + const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex]; + if (!uniformBlock.name.empty()) + { + const unsigned int length = uniformBlock.name.length() + 1; + + // Counting in "[0]". + const unsigned int arrayLength = (uniformBlock.isArrayElement() ? 3 : 0); + + maxLength = std::max(length + arrayLength, maxLength); + } + } + + return maxLength; +} + void ProgramBinary::validate(InfoLog &infoLog) { applyUniforms(); @@ -2518,6 +2688,7 @@ bool ProgramBinary::validateSamplers(InfoLog *infoLog) // if any two active samplers in a program are of different types, but refer to the same // texture image unit, and this is the current program, then ValidateProgram will fail, and // DrawArrays and DrawElements will issue the INVALID_OPERATION error. + updateSamplerMapping(); const unsigned int maxCombinedTextureImageUnits = mRenderer->getMaxCombinedTextureImageUnits(); TextureType textureUnitType[IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS]; @@ -2532,7 +2703,7 @@ bool ProgramBinary::validateSamplers(InfoLog *infoLog) if (mSamplersPS[i].active) { unsigned int unit = mSamplersPS[i].logicalTextureUnit; - + if (unit >= maxCombinedTextureImageUnits) { if (infoLog) @@ -2567,7 +2738,7 @@ bool ProgramBinary::validateSamplers(InfoLog *infoLog) if (mSamplersVS[i].active) { unsigned int unit = mSamplersVS[i].logicalTextureUnit; - + if (unit >= maxCombinedTextureImageUnits) { if (infoLog) @@ -2648,4 +2819,71 @@ void ProgramBinary::sortAttributesByLayout(rx::TranslatedAttribute attributes[MA } } +void ProgramBinary::initializeUniformStorage() +{ + // Compute total default block size + unsigned int vertexRegisters = 0; + unsigned int fragmentRegisters = 0; + for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++) + { + const LinkedUniform &uniform = *mUniforms[uniformIndex]; + + if (!IsSampler(uniform.type)) + { + if (uniform.isReferencedByVertexShader()) + { + vertexRegisters = std::max(vertexRegisters, uniform.vsRegisterIndex + uniform.registerCount); + } + if (uniform.isReferencedByFragmentShader()) + { + fragmentRegisters = std::max(fragmentRegisters, uniform.psRegisterIndex + uniform.registerCount); + } + } + } + + mVertexUniformStorage = mRenderer->createUniformStorage(vertexRegisters * 16u); + mFragmentUniformStorage = mRenderer->createUniformStorage(fragmentRegisters * 16u); +} + +void ProgramBinary::reset() +{ + mVertexHLSL.clear(); + mVertexWorkarounds = rx::ANGLE_D3D_WORKAROUND_NONE; + SafeDeleteContainer(mVertexExecutables); + + mPixelHLSL.clear(); + mPixelWorkarounds = rx::ANGLE_D3D_WORKAROUND_NONE; + mUsesFragDepth = false; + mPixelShaderKey.clear(); + SafeDeleteContainer(mPixelExecutables); + + SafeDelete(mGeometryExecutable); + + mTransformFeedbackBufferMode = GL_NONE; + mTransformFeedbackLinkedVaryings.clear(); + + for (size_t i = 0; i < ArraySize(mSamplersPS); i++) + { + mSamplersPS[i] = Sampler(); + } + for (size_t i = 0; i < ArraySize(mSamplersVS); i++) + { + mSamplersVS[i] = Sampler(); + } + mUsedVertexSamplerRange = 0; + mUsedPixelSamplerRange = 0; + mUsesPointSize = false; + mShaderVersion = 0; + mDirtySamplerMapping = true; + + SafeDeleteContainer(mUniforms); + SafeDeleteContainer(mUniformBlocks); + mUniformIndex.clear(); + mOutputVariables.clear(); + SafeDelete(mVertexUniformStorage); + SafeDelete(mFragmentUniformStorage); + + mValidated = false; +} + } |