diff options
Diffstat (limited to 'src/3rdparty/angle/src/libANGLE/renderer/d3d/ProgramD3D.cpp')
-rw-r--r-- | src/3rdparty/angle/src/libANGLE/renderer/d3d/ProgramD3D.cpp | 2357 |
1 files changed, 1346 insertions, 1011 deletions
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/ProgramD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ProgramD3D.cpp index 9ce9a27cd3..72c6f1a1a9 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/ProgramD3D.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ProgramD3D.cpp @@ -8,16 +8,19 @@ #include "libANGLE/renderer/d3d/ProgramD3D.h" +#include "common/BitSetIterator.h" #include "common/utilities.h" #include "libANGLE/Framebuffer.h" #include "libANGLE/FramebufferAttachment.h" #include "libANGLE/Program.h" +#include "libANGLE/VertexArray.h" #include "libANGLE/features.h" #include "libANGLE/renderer/d3d/DynamicHLSL.h" #include "libANGLE/renderer/d3d/FramebufferD3D.h" #include "libANGLE/renderer/d3d/RendererD3D.h" #include "libANGLE/renderer/d3d/ShaderD3D.h" #include "libANGLE/renderer/d3d/ShaderExecutableD3D.h" +#include "libANGLE/renderer/d3d/VaryingPacking.h" #include "libANGLE/renderer/d3d/VertexDataManager.h" namespace rx @@ -26,69 +29,41 @@ namespace rx namespace { -GLenum GetTextureType(GLenum samplerType) -{ - switch (samplerType) - { - case GL_SAMPLER_2D: - case GL_INT_SAMPLER_2D: - case GL_UNSIGNED_INT_SAMPLER_2D: - case GL_SAMPLER_2D_SHADOW: - return GL_TEXTURE_2D; - case GL_SAMPLER_3D: - case GL_INT_SAMPLER_3D: - case GL_UNSIGNED_INT_SAMPLER_3D: - return GL_TEXTURE_3D; - case GL_SAMPLER_CUBE: - case GL_SAMPLER_CUBE_SHADOW: - return GL_TEXTURE_CUBE_MAP; - case GL_INT_SAMPLER_CUBE: - case GL_UNSIGNED_INT_SAMPLER_CUBE: - return GL_TEXTURE_CUBE_MAP; - 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 GL_TEXTURE_2D_ARRAY; - default: UNREACHABLE(); - } - - return GL_TEXTURE_2D; -} - -void GetDefaultInputLayoutFromShader(const std::vector<sh::Attribute> &shaderAttributes, gl::VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS]) +gl::InputLayout GetDefaultInputLayoutFromShader(const gl::Shader *vertexShader) { - size_t layoutIndex = 0; - for (size_t attributeIndex = 0; attributeIndex < shaderAttributes.size(); attributeIndex++) + gl::InputLayout defaultLayout; + for (const sh::Attribute &shaderAttr : vertexShader->getActiveAttributes()) { - ASSERT(layoutIndex < gl::MAX_VERTEX_ATTRIBS); - - const sh::Attribute &shaderAttr = shaderAttributes[attributeIndex]; - if (shaderAttr.type != GL_NONE) { GLenum transposedType = gl::TransposeMatrixType(shaderAttr.type); - for (size_t rowIndex = 0; static_cast<int>(rowIndex) < gl::VariableRowCount(transposedType); rowIndex++, layoutIndex++) + for (size_t rowIndex = 0; + static_cast<int>(rowIndex) < gl::VariableRowCount(transposedType); ++rowIndex) { - gl::VertexFormat *defaultFormat = &inputLayout[layoutIndex]; + GLenum componentType = gl::VariableComponentType(transposedType); + GLuint components = static_cast<GLuint>(gl::VariableColumnCount(transposedType)); + bool pureInt = (componentType != GL_FLOAT); + gl::VertexFormatType defaultType = + gl::GetVertexFormatType(componentType, GL_FALSE, components, pureInt); - defaultFormat->mType = gl::VariableComponentType(transposedType); - defaultFormat->mNormalized = false; - defaultFormat->mPureInteger = (defaultFormat->mType != GL_FLOAT); // note: inputs can not be bool - defaultFormat->mComponents = gl::VariableColumnCount(transposedType); + defaultLayout.push_back(defaultType); } } } + + return defaultLayout; } -std::vector<GLenum> GetDefaultOutputLayoutFromShader(const std::vector<PixelShaderOutputVariable> &shaderOutputVars) +std::vector<GLenum> GetDefaultOutputLayoutFromShader( + const std::vector<PixelShaderOutputVariable> &shaderOutputVars) { std::vector<GLenum> defaultPixelOutput; if (!shaderOutputVars.empty()) { - defaultPixelOutput.push_back(GL_COLOR_ATTACHMENT0 + shaderOutputVars[0].outputIndex); + defaultPixelOutput.push_back(GL_COLOR_ATTACHMENT0 + + static_cast<unsigned int>(shaderOutputVars[0].outputIndex)); } return defaultPixelOutput; @@ -106,7 +81,7 @@ bool IsRowMajorLayout(const sh::ShaderVariable &var) struct AttributeSorter { - AttributeSorter(const ProgramImpl::SemanticIndexArray &semanticIndices) + AttributeSorter(const ProgramD3D::SemanticIndexArray &semanticIndices) : originalIndices(&semanticIndices) { } @@ -116,26 +91,416 @@ struct AttributeSorter int indexA = (*originalIndices)[a]; int indexB = (*originalIndices)[b]; - if (indexA == -1) return false; - if (indexB == -1) return true; + if (indexA == -1) + return false; + if (indexB == -1) + return true; return (indexA < indexB); } - const ProgramImpl::SemanticIndexArray *originalIndices; + const ProgramD3D::SemanticIndexArray *originalIndices; }; +// true if varying x has a higher priority in packing than y +bool ComparePackedVarying(const PackedVarying &x, const PackedVarying &y) +{ + return gl::CompareShaderVar(*x.varying, *y.varying); } -ProgramD3D::VertexExecutable::VertexExecutable(const gl::VertexFormat inputLayout[], - const GLenum signature[], - ShaderExecutableD3D *shaderExecutable) - : mShaderExecutable(shaderExecutable) +std::vector<PackedVarying> MergeVaryings(const gl::Shader &vertexShader, + const gl::Shader &fragmentShader, + const std::vector<std::string> &tfVaryings) +{ + std::vector<PackedVarying> packedVaryings; + + for (const sh::Varying &output : vertexShader.getVaryings()) + { + bool packed = false; + + // Built-in varyings obey special rules + if (output.isBuiltIn()) + { + continue; + } + + for (const sh::Varying &input : fragmentShader.getVaryings()) + { + if (output.name == input.name) + { + if (output.isStruct()) + { + ASSERT(!output.isArray()); + for (const auto &field : output.fields) + { + ASSERT(!field.isStruct() && !field.isArray()); + packedVaryings.push_back( + PackedVarying(field, input.interpolation, input.name)); + } + } + else + { + packedVaryings.push_back(PackedVarying(input, input.interpolation)); + } + packed = true; + break; + } + } + + // Keep Transform FB varyings in the merged list always. + if (!packed) + { + for (const std::string &tfVarying : tfVaryings) + { + if (tfVarying == output.name) + { + // Transform feedback for varying structs is underspecified. + // See Khronos bug 9856. + // TODO(jmadill): Figure out how to be spec-compliant here. + if (!output.isStruct()) + { + packedVaryings.push_back(PackedVarying(output, output.interpolation)); + packedVaryings.back().vertexOnly = true; + } + break; + } + } + } + } + + std::sort(packedVaryings.begin(), packedVaryings.end(), ComparePackedVarying); + + return packedVaryings; +} + +template <typename VarT> +void GetUniformBlockInfo(const std::vector<VarT> &fields, + const std::string &prefix, + sh::BlockLayoutEncoder *encoder, + bool inRowMajorLayout, + std::map<std::string, sh::BlockMemberInfo> *blockInfoOut) +{ + for (const VarT &field : fields) + { + const std::string &fieldName = (prefix.empty() ? field.name : prefix + "." + field.name); + + if (field.isStruct()) + { + bool rowMajorLayout = (inRowMajorLayout || IsRowMajorLayout(field)); + + for (unsigned int arrayElement = 0; arrayElement < field.elementCount(); arrayElement++) + { + encoder->enterAggregateType(); + + const std::string uniformElementName = + fieldName + (field.isArray() ? ArrayString(arrayElement) : ""); + GetUniformBlockInfo(field.fields, uniformElementName, encoder, rowMajorLayout, + blockInfoOut); + + encoder->exitAggregateType(); + } + } + else + { + bool isRowMajorMatrix = (gl::IsMatrixType(field.type) && inRowMajorLayout); + (*blockInfoOut)[fieldName] = + encoder->encodeType(field.type, field.arraySize, isRowMajorMatrix); + } + } +} + +template <typename T> +static inline void SetIfDirty(T *dest, const T &source, bool *dirtyFlag) +{ + ASSERT(dest != NULL); + ASSERT(dirtyFlag != NULL); + + *dirtyFlag = *dirtyFlag || (memcmp(dest, &source, sizeof(T)) != 0); + *dest = source; +} + +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); + + for (int x = 0; x < copyWidth; x++) + { + for (int y = 0; y < copyHeight; y++) + { + SetIfDirty(target + (x * targetWidth + y), static_cast<T>(value[y * srcWidth + x]), + &dirty); + } + } + // clear unfilled right side + for (int y = 0; y < copyWidth; y++) + { + for (int x = copyHeight; x < targetWidth; x++) + { + SetIfDirty(target + (y * targetWidth + x), static_cast<T>(0), &dirty); + } + } + // clear unfilled bottom. + for (int y = copyWidth; y < targetHeight; y++) + { + for (int x = 0; x < targetWidth; x++) + { + SetIfDirty(target + (y * targetWidth + x), static_cast<T>(0), &dirty); + } + } + + return dirty; +} + +template <typename T> +bool ExpandMatrix(T *target, + const GLfloat *value, + int targetWidth, + int targetHeight, + int srcWidth, + int srcHeight) { - for (size_t attributeIndex = 0; attributeIndex < gl::MAX_VERTEX_ATTRIBS; attributeIndex++) + bool dirty = false; + int copyWidth = std::min(targetWidth, srcWidth); + int copyHeight = std::min(targetHeight, srcHeight); + + for (int y = 0; y < copyHeight; y++) + { + for (int x = 0; x < copyWidth; 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++) { - mInputs[attributeIndex] = inputLayout[attributeIndex]; - mSignature[attributeIndex] = signature[attributeIndex]; + for (int x = copyWidth; x < targetWidth; x++) + { + SetIfDirty(target + (y * targetWidth + x), static_cast<T>(0), &dirty); + } } + // clear unfilled bottom. + for (int y = copyHeight; y < targetHeight; y++) + { + for (int x = 0; x < targetWidth; x++) + { + SetIfDirty(target + (y * targetWidth + x), static_cast<T>(0), &dirty); + } + } + + return dirty; +} + +gl::PrimitiveType GetGeometryShaderTypeFromDrawMode(GLenum drawMode) +{ + switch (drawMode) + { + // Uses the point sprite geometry shader. + case GL_POINTS: + return gl::PRIMITIVE_POINTS; + + // All line drawing uses the same geometry shader. + case GL_LINES: + case GL_LINE_STRIP: + case GL_LINE_LOOP: + return gl::PRIMITIVE_LINES; + + // The triangle fan primitive is emulated with strips in D3D11. + case GL_TRIANGLES: + case GL_TRIANGLE_FAN: + return gl::PRIMITIVE_TRIANGLES; + + // Special case for triangle strips. + case GL_TRIANGLE_STRIP: + return gl::PRIMITIVE_TRIANGLE_STRIP; + + default: + UNREACHABLE(); + return gl::PRIMITIVE_TYPE_MAX; + } +} + +} // anonymous namespace + +// D3DUniform Implementation + +D3DUniform::D3DUniform(GLenum typeIn, + const std::string &nameIn, + unsigned int arraySizeIn, + bool defaultBlock) + : type(typeIn), + name(nameIn), + arraySize(arraySizeIn), + data(nullptr), + dirty(true), + vsRegisterIndex(GL_INVALID_INDEX), + psRegisterIndex(GL_INVALID_INDEX), + registerCount(0), + registerElement(0) +{ + // We use data storage for default block uniforms to cache values that are sent to D3D during + // rendering + // Uniform blocks/buffers are treated separately by the Renderer (ES3 path only) + if (defaultBlock) + { + size_t bytes = gl::VariableInternalSize(type) * elementCount(); + data = new uint8_t[bytes]; + memset(data, 0, bytes); + + // TODO(jmadill): is this correct with non-square matrices? + registerCount = gl::VariableRowCount(type) * elementCount(); + } +} + +D3DUniform::~D3DUniform() +{ + SafeDeleteArray(data); +} + +bool D3DUniform::isSampler() const +{ + return gl::IsSamplerType(type); +} + +bool D3DUniform::isReferencedByVertexShader() const +{ + return vsRegisterIndex != GL_INVALID_INDEX; +} + +bool D3DUniform::isReferencedByFragmentShader() const +{ + return psRegisterIndex != GL_INVALID_INDEX; +} + +// D3DVarying Implementation + +D3DVarying::D3DVarying() : semanticIndex(0), componentCount(0), outputSlot(0) +{ +} + +D3DVarying::D3DVarying(const std::string &semanticNameIn, + unsigned int semanticIndexIn, + unsigned int componentCountIn, + unsigned int outputSlotIn) + : semanticName(semanticNameIn), + semanticIndex(semanticIndexIn), + componentCount(componentCountIn), + outputSlot(outputSlotIn) +{ +} + +// ProgramD3DMetadata Implementation + +ProgramD3DMetadata::ProgramD3DMetadata(int rendererMajorShaderModel, + const std::string &shaderModelSuffix, + bool usesInstancedPointSpriteEmulation, + bool usesViewScale, + const ShaderD3D *vertexShader, + const ShaderD3D *fragmentShader) + : mRendererMajorShaderModel(rendererMajorShaderModel), + mShaderModelSuffix(shaderModelSuffix), + mUsesInstancedPointSpriteEmulation(usesInstancedPointSpriteEmulation), + mUsesViewScale(usesViewScale), + mVertexShader(vertexShader), + mFragmentShader(fragmentShader) +{ +} + +int ProgramD3DMetadata::getRendererMajorShaderModel() const +{ + return mRendererMajorShaderModel; +} + +bool ProgramD3DMetadata::usesBroadcast(const gl::Data &data) const +{ + return (mFragmentShader->usesFragColor() && data.clientVersion < 3); +} + +bool ProgramD3DMetadata::usesFragDepth(const gl::Program::Data &programData) const +{ + return mFragmentShader->usesFragDepth(); +} + +bool ProgramD3DMetadata::usesPointCoord() const +{ + return mFragmentShader->usesPointCoord(); +} + +bool ProgramD3DMetadata::usesFragCoord() const +{ + return mFragmentShader->usesFragCoord(); +} + +bool ProgramD3DMetadata::usesPointSize() const +{ + return mVertexShader->usesPointSize(); +} + +bool ProgramD3DMetadata::usesInsertedPointCoordValue() const +{ + return !usesPointSize() && usesPointCoord() && mRendererMajorShaderModel >= 4; +} + +bool ProgramD3DMetadata::usesViewScale() const +{ + return mUsesViewScale; +} + +bool ProgramD3DMetadata::addsPointCoordToVertexShader() const +{ + // Instanced PointSprite emulation requires that gl_PointCoord is present in the vertex shader + // VS_OUTPUT structure to ensure compatibility with the generated PS_INPUT of the pixel shader. + // GeometryShader PointSprite emulation does not require this additional entry because the + // GS_OUTPUT of the Geometry shader contains the pointCoord value and already matches the + // PS_INPUT of the generated pixel shader. The Geometry Shader point sprite implementation needs + // gl_PointSize to be in VS_OUTPUT and GS_INPUT. Instanced point sprites doesn't need + // gl_PointSize in VS_OUTPUT. + return (mUsesInstancedPointSpriteEmulation && usesPointCoord()) || + usesInsertedPointCoordValue(); +} + +bool ProgramD3DMetadata::usesTransformFeedbackGLPosition() const +{ + // gl_Position only needs to be outputted from the vertex shader if transform feedback is + // active. This isn't supported on D3D11 Feature Level 9_3, so we don't output gl_Position from + // the vertex shader in this case. This saves us 1 output vector. + return !(mRendererMajorShaderModel >= 4 && mShaderModelSuffix != ""); +} + +bool ProgramD3DMetadata::usesSystemValuePointSize() const +{ + return !mUsesInstancedPointSpriteEmulation && usesPointSize(); +} + +bool ProgramD3DMetadata::usesMultipleFragmentOuts() const +{ + return mFragmentShader->usesMultipleRenderTargets(); +} + +GLint ProgramD3DMetadata::getMajorShaderVersion() const +{ + return mVertexShader->getData().getShaderVersion(); +} + +const ShaderD3D *ProgramD3DMetadata::getFragmentShader() const +{ + return mFragmentShader; +} + +// ProgramD3D Implementation + +ProgramD3D::VertexExecutable::VertexExecutable(const gl::InputLayout &inputLayout, + const Signature &signature, + ShaderExecutableD3D *shaderExecutable) + : mInputs(inputLayout), mSignature(signature), mShaderExecutable(shaderExecutable) +{ } ProgramD3D::VertexExecutable::~VertexExecutable() @@ -143,22 +508,46 @@ ProgramD3D::VertexExecutable::~VertexExecutable() SafeDelete(mShaderExecutable); } -bool ProgramD3D::VertexExecutable::matchesSignature(const GLenum signature[]) const +// static +void ProgramD3D::VertexExecutable::getSignature(RendererD3D *renderer, + const gl::InputLayout &inputLayout, + Signature *signatureOut) { - for (size_t attributeIndex = 0; attributeIndex < gl::MAX_VERTEX_ATTRIBS; attributeIndex++) + signatureOut->resize(inputLayout.size()); + + for (size_t index = 0; index < inputLayout.size(); ++index) { - if (mSignature[attributeIndex] != signature[attributeIndex]) + gl::VertexFormatType vertexFormatType = inputLayout[index]; + bool converted = false; + if (vertexFormatType != gl::VERTEX_FORMAT_INVALID) { - return false; + VertexConversionType conversionType = + renderer->getVertexConversionType(vertexFormatType); + converted = ((conversionType & VERTEX_CONVERT_GPU) != 0); } + + (*signatureOut)[index] = converted; + } +} + +bool ProgramD3D::VertexExecutable::matchesSignature(const Signature &signature) const +{ + size_t limit = std::max(mSignature.size(), signature.size()); + for (size_t index = 0; index < limit; ++index) + { + // treat undefined indexes as 'not converted' + bool a = index < signature.size() ? signature[index] : false; + bool b = index < mSignature.size() ? mSignature[index] : false; + if (a != b) + return false; } return true; } -ProgramD3D::PixelExecutable::PixelExecutable(const std::vector<GLenum> &outputSignature, ShaderExecutableD3D *shaderExecutable) - : mOutputSignature(outputSignature), - mShaderExecutable(shaderExecutable) +ProgramD3D::PixelExecutable::PixelExecutable(const std::vector<GLenum> &outputSignature, + ShaderExecutableD3D *shaderExecutable) + : mOutputSignature(outputSignature), mShaderExecutable(shaderExecutable) { } @@ -173,19 +562,18 @@ ProgramD3D::Sampler::Sampler() : active(false), logicalTextureUnit(0), textureTy unsigned int ProgramD3D::mCurrentSerial = 1; -ProgramD3D::ProgramD3D(RendererD3D *renderer) - : ProgramImpl(), +ProgramD3D::ProgramD3D(const gl::Program::Data &data, RendererD3D *renderer) + : ProgramImpl(data), mRenderer(renderer), mDynamicHLSL(NULL), - mGeometryExecutable(NULL), + mGeometryExecutables(gl::PRIMITIVE_TYPE_MAX, nullptr), mUsesPointSize(false), + mUsesFlatInterpolation(false), mVertexUniformStorage(NULL), mFragmentUniformStorage(NULL), mUsedVertexSamplerRange(0), mUsedPixelSamplerRange(0), mDirtySamplerMapping(true), - mTextureUnitTypesCache(renderer->getRendererCaps().maxCombinedTextureImageUnits), - mShaderVersion(100), mSerial(issueSerial()) { mDynamicHLSL = new DynamicHLSL(renderer); @@ -202,8 +590,13 @@ bool ProgramD3D::usesPointSpriteEmulation() const return mUsesPointSize && mRenderer->getMajorShaderModel() >= 4; } -bool ProgramD3D::usesGeometryShader() const +bool ProgramD3D::usesGeometryShader(GLenum drawMode) const { + if (drawMode != GL_POINTS) + { + return mUsesFlatInterpolation; + } + return usesPointSpriteEmulation() && !usesInstancedPointSpriteEmulation(); } @@ -212,30 +605,34 @@ bool ProgramD3D::usesInstancedPointSpriteEmulation() const return mRenderer->getWorkarounds().useInstancedPointSpriteEmulation; } -GLint ProgramD3D::getSamplerMapping(gl::SamplerType type, unsigned int samplerIndex, const gl::Caps &caps) const +GLint ProgramD3D::getSamplerMapping(gl::SamplerType type, + unsigned int samplerIndex, + const gl::Caps &caps) const { GLint logicalTextureUnit = -1; switch (type) { - case gl::SAMPLER_PIXEL: - ASSERT(samplerIndex < caps.maxTextureImageUnits); - if (samplerIndex < mSamplersPS.size() && mSamplersPS[samplerIndex].active) - { - logicalTextureUnit = mSamplersPS[samplerIndex].logicalTextureUnit; - } - break; - case gl::SAMPLER_VERTEX: - ASSERT(samplerIndex < caps.maxVertexTextureImageUnits); - if (samplerIndex < mSamplersVS.size() && mSamplersVS[samplerIndex].active) - { - logicalTextureUnit = mSamplersVS[samplerIndex].logicalTextureUnit; - } - break; - default: UNREACHABLE(); + case gl::SAMPLER_PIXEL: + ASSERT(samplerIndex < caps.maxTextureImageUnits); + if (samplerIndex < mSamplersPS.size() && mSamplersPS[samplerIndex].active) + { + logicalTextureUnit = mSamplersPS[samplerIndex].logicalTextureUnit; + } + break; + case gl::SAMPLER_VERTEX: + ASSERT(samplerIndex < caps.maxVertexTextureImageUnits); + if (samplerIndex < mSamplersVS.size() && mSamplersVS[samplerIndex].active) + { + logicalTextureUnit = mSamplersVS[samplerIndex].logicalTextureUnit; + } + break; + default: + UNREACHABLE(); } - if (logicalTextureUnit >= 0 && logicalTextureUnit < static_cast<GLint>(caps.maxCombinedTextureImageUnits)) + if (logicalTextureUnit >= 0 && + logicalTextureUnit < static_cast<GLint>(caps.maxCombinedTextureImageUnits)) { return logicalTextureUnit; } @@ -249,15 +646,16 @@ GLenum ProgramD3D::getSamplerTextureType(gl::SamplerType type, unsigned int samp { switch (type) { - case gl::SAMPLER_PIXEL: - ASSERT(samplerIndex < mSamplersPS.size()); - ASSERT(mSamplersPS[samplerIndex].active); - return mSamplersPS[samplerIndex].textureType; - case gl::SAMPLER_VERTEX: - ASSERT(samplerIndex < mSamplersVS.size()); - ASSERT(mSamplersVS[samplerIndex].active); - return mSamplersVS[samplerIndex].textureType; - default: UNREACHABLE(); + case gl::SAMPLER_PIXEL: + ASSERT(samplerIndex < mSamplersPS.size()); + ASSERT(mSamplersPS[samplerIndex].active); + return mSamplersPS[samplerIndex].textureType; + case gl::SAMPLER_VERTEX: + ASSERT(samplerIndex < mSamplersVS.size()); + ASSERT(mSamplersVS[samplerIndex].active); + return mSamplersVS[samplerIndex].textureType; + default: + UNREACHABLE(); } return GL_TEXTURE_2D; @@ -267,13 +665,13 @@ GLint ProgramD3D::getUsedSamplerRange(gl::SamplerType type) const { switch (type) { - case gl::SAMPLER_PIXEL: - return mUsedPixelSamplerRange; - case gl::SAMPLER_VERTEX: - return mUsedVertexSamplerRange; - default: - UNREACHABLE(); - return 0; + case gl::SAMPLER_PIXEL: + return mUsedPixelSamplerRange; + case gl::SAMPLER_VERTEX: + return mUsedVertexSamplerRange; + default: + UNREACHABLE(); + return 0; } } @@ -287,145 +685,78 @@ void ProgramD3D::updateSamplerMapping() mDirtySamplerMapping = false; // Retrieve sampler uniform values - for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++) + for (const D3DUniform *d3dUniform : mD3DUniforms) { - gl::LinkedUniform *targetUniform = mUniforms[uniformIndex]; - - if (targetUniform->dirty) - { - if (gl::IsSamplerType(targetUniform->type)) - { - int count = targetUniform->elementCount(); - GLint (*v)[4] = reinterpret_cast<GLint(*)[4]>(targetUniform->data); - - if (targetUniform->isReferencedByFragmentShader()) - { - unsigned int firstIndex = targetUniform->psRegisterIndex; - - for (int i = 0; i < count; i++) - { - unsigned int samplerIndex = firstIndex + i; - - if (samplerIndex < mSamplersPS.size()) - { - ASSERT(mSamplersPS[samplerIndex].active); - mSamplersPS[samplerIndex].logicalTextureUnit = v[i][0]; - } - } - } - - if (targetUniform->isReferencedByVertexShader()) - { - unsigned int firstIndex = targetUniform->vsRegisterIndex; - - for (int i = 0; i < count; i++) - { - unsigned int samplerIndex = firstIndex + i; - - if (samplerIndex < mSamplersVS.size()) - { - ASSERT(mSamplersVS[samplerIndex].active); - mSamplersVS[samplerIndex].logicalTextureUnit = v[i][0]; - } - } - } - } - } - } -} + if (!d3dUniform->dirty) + continue; -bool ProgramD3D::validateSamplers(gl::InfoLog *infoLog, const gl::Caps &caps) -{ - // 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(); + if (!d3dUniform->isSampler()) + continue; - std::fill(mTextureUnitTypesCache.begin(), mTextureUnitTypesCache.end(), GL_NONE); + int count = d3dUniform->elementCount(); + const GLint(*v)[4] = reinterpret_cast<const GLint(*)[4]>(d3dUniform->data); - for (unsigned int i = 0; i < mUsedPixelSamplerRange; ++i) - { - if (mSamplersPS[i].active) + if (d3dUniform->isReferencedByFragmentShader()) { - unsigned int unit = mSamplersPS[i].logicalTextureUnit; + unsigned int firstIndex = d3dUniform->psRegisterIndex; - if (unit >= caps.maxCombinedTextureImageUnits) + for (int i = 0; i < count; i++) { - if (infoLog) - { - infoLog->append("Sampler uniform (%d) exceeds GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, caps.maxCombinedTextureImageUnits); - } + unsigned int samplerIndex = firstIndex + i; - return false; - } - - if (mTextureUnitTypesCache[unit] != GL_NONE) - { - if (mSamplersPS[i].textureType != mTextureUnitTypesCache[unit]) + if (samplerIndex < mSamplersPS.size()) { - if (infoLog) - { - infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit); - } - - return false; + ASSERT(mSamplersPS[samplerIndex].active); + mSamplersPS[samplerIndex].logicalTextureUnit = v[i][0]; } } - else - { - mTextureUnitTypesCache[unit] = mSamplersPS[i].textureType; - } } - } - for (unsigned int i = 0; i < mUsedVertexSamplerRange; ++i) - { - if (mSamplersVS[i].active) + if (d3dUniform->isReferencedByVertexShader()) { - unsigned int unit = mSamplersVS[i].logicalTextureUnit; + unsigned int firstIndex = d3dUniform->vsRegisterIndex; - if (unit >= caps.maxCombinedTextureImageUnits) + for (int i = 0; i < count; i++) { - if (infoLog) - { - infoLog->append("Sampler uniform (%d) exceeds GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, caps.maxCombinedTextureImageUnits); - } - - return false; - } + unsigned int samplerIndex = firstIndex + i; - if (mTextureUnitTypesCache[unit] != GL_NONE) - { - if (mSamplersVS[i].textureType != mTextureUnitTypesCache[unit]) + if (samplerIndex < mSamplersVS.size()) { - if (infoLog) - { - infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit); - } - - return false; + ASSERT(mSamplersVS[samplerIndex].active); + mSamplersVS[samplerIndex].logicalTextureUnit = v[i][0]; } } - else - { - mTextureUnitTypesCache[unit] = mSamplersVS[i].textureType; - } } } - - return true; } LinkResult ProgramD3D::load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream) { + reset(); + + DeviceIdentifier binaryDeviceIdentifier = {0}; + stream->readBytes(reinterpret_cast<unsigned char *>(&binaryDeviceIdentifier), + sizeof(DeviceIdentifier)); + + DeviceIdentifier identifier = mRenderer->getAdapterIdentifier(); + if (memcmp(&identifier, &binaryDeviceIdentifier, sizeof(DeviceIdentifier)) != 0) + { + infoLog << "Invalid program binary, device configuration has changed."; + return LinkResult(false, gl::Error(GL_NO_ERROR)); + } + int compileFlags = stream->readInt<int>(); if (compileFlags != ANGLE_COMPILE_OPTIMIZATION_LEVEL) { - infoLog.append("Mismatched compilation flags."); + infoLog << "Mismatched compilation flags."; return LinkResult(false, gl::Error(GL_NO_ERROR)); } - stream->readInt(&mShaderVersion); + // TODO(jmadill): replace MAX_VERTEX_ATTRIBS + for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; ++i) + { + stream->readInt(&mSemanticIndexes[i]); + } const unsigned int psSamplerCount = stream->readInt<unsigned int>(); for (unsigned int i = 0; i < psSamplerCount; ++i) @@ -452,105 +783,69 @@ LinkResult ProgramD3D::load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream) const unsigned int uniformCount = stream->readInt<unsigned int>(); if (stream->error()) { - infoLog.append("Invalid program binary."); + infoLog << "Invalid program binary."; return LinkResult(false, gl::Error(GL_NO_ERROR)); } - mUniforms.resize(uniformCount); + const auto &linkedUniforms = mData.getUniforms(); + ASSERT(mD3DUniforms.empty()); for (unsigned int uniformIndex = 0; uniformIndex < uniformCount; uniformIndex++) { - 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>(); - - int offset = stream->readInt<int>(); - int arrayStride = stream->readInt<int>(); - int matrixStride = stream->readInt<int>(); - bool isRowMajorMatrix = stream->readBool(); - - const sh::BlockMemberInfo blockInfo(offset, arrayStride, matrixStride, isRowMajorMatrix); - - gl::LinkedUniform *uniform = new gl::LinkedUniform(type, precision, name, arraySize, blockIndex, blockInfo); - - stream->readInt(&uniform->psRegisterIndex); - stream->readInt(&uniform->vsRegisterIndex); - stream->readInt(&uniform->registerCount); - stream->readInt(&uniform->registerElement); + const gl::LinkedUniform &linkedUniform = linkedUniforms[uniformIndex]; - mUniforms[uniformIndex] = uniform; - } + D3DUniform *d3dUniform = + new D3DUniform(linkedUniform.type, linkedUniform.name, linkedUniform.arraySize, + linkedUniform.isInDefaultBlock()); + stream->readInt(&d3dUniform->psRegisterIndex); + stream->readInt(&d3dUniform->vsRegisterIndex); + stream->readInt(&d3dUniform->registerCount); + stream->readInt(&d3dUniform->registerElement); - const unsigned int uniformIndexCount = stream->readInt<unsigned int>(); - if (stream->error()) - { - infoLog.append("Invalid program binary."); - return LinkResult(false, gl::Error(GL_NO_ERROR)); - } - - mUniformIndex.resize(uniformIndexCount); - for (unsigned int uniformIndexIndex = 0; uniformIndexIndex < uniformIndexCount; uniformIndexIndex++) - { - stream->readString(&mUniformIndex[uniformIndexIndex].name); - stream->readInt(&mUniformIndex[uniformIndexIndex].element); - stream->readInt(&mUniformIndex[uniformIndexIndex].index); + mD3DUniforms.push_back(d3dUniform); } - unsigned int uniformBlockCount = stream->readInt<unsigned int>(); + const unsigned int blockCount = stream->readInt<unsigned int>(); if (stream->error()) { - infoLog.append("Invalid program binary."); + infoLog << "Invalid program binary."; return LinkResult(false, gl::Error(GL_NO_ERROR)); } - mUniformBlocks.resize(uniformBlockCount); - for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < uniformBlockCount; ++uniformBlockIndex) + ASSERT(mD3DUniformBlocks.empty()); + for (unsigned int blockIndex = 0; blockIndex < blockCount; ++blockIndex) { - std::string name = stream->readString(); - unsigned int elementIndex = stream->readInt<unsigned int>(); - unsigned int dataSize = stream->readInt<unsigned int>(); - - gl::UniformBlock *uniformBlock = new gl::UniformBlock(name, elementIndex, dataSize); - - stream->readInt(&uniformBlock->psRegisterIndex); - stream->readInt(&uniformBlock->vsRegisterIndex); - - unsigned int numMembers = stream->readInt<unsigned int>(); - uniformBlock->memberUniformIndexes.resize(numMembers); - for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++) - { - stream->readInt(&uniformBlock->memberUniformIndexes[blockMemberIndex]); - } - - mUniformBlocks[uniformBlockIndex] = uniformBlock; + D3DUniformBlock uniformBlock; + stream->readInt(&uniformBlock.psRegisterIndex); + stream->readInt(&uniformBlock.vsRegisterIndex); + mD3DUniformBlocks.push_back(uniformBlock); } - stream->readInt(&mTransformFeedbackBufferMode); - const unsigned int transformFeedbackVaryingCount = stream->readInt<unsigned int>(); - mTransformFeedbackLinkedVaryings.resize(transformFeedbackVaryingCount); - for (unsigned int varyingIndex = 0; varyingIndex < transformFeedbackVaryingCount; varyingIndex++) + const unsigned int streamOutVaryingCount = stream->readInt<unsigned int>(); + mStreamOutVaryings.resize(streamOutVaryingCount); + for (unsigned int varyingIndex = 0; varyingIndex < streamOutVaryingCount; ++varyingIndex) { - gl::LinkedVarying &varying = mTransformFeedbackLinkedVaryings[varyingIndex]; + D3DVarying *varying = &mStreamOutVaryings[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); + stream->readString(&varying->semanticName); + stream->readInt(&varying->semanticIndex); + stream->readInt(&varying->componentCount); + stream->readInt(&varying->outputSlot); } stream->readString(&mVertexHLSL); - stream->readBytes(reinterpret_cast<unsigned char*>(&mVertexWorkarounds), sizeof(D3DCompilerWorkarounds)); + stream->readBytes(reinterpret_cast<unsigned char *>(&mVertexWorkarounds), + sizeof(D3DCompilerWorkarounds)); stream->readString(&mPixelHLSL); - stream->readBytes(reinterpret_cast<unsigned char*>(&mPixelWorkarounds), sizeof(D3DCompilerWorkarounds)); + stream->readBytes(reinterpret_cast<unsigned char *>(&mPixelWorkarounds), + sizeof(D3DCompilerWorkarounds)); stream->readBool(&mUsesFragDepth); stream->readBool(&mUsesPointSize); + stream->readBool(&mUsesFlatInterpolation); const size_t pixelShaderKeySize = stream->readInt<unsigned int>(); mPixelShaderKey.resize(pixelShaderKeySize); - for (size_t pixelShaderKeyIndex = 0; pixelShaderKeyIndex < pixelShaderKeySize; pixelShaderKeyIndex++) + for (size_t pixelShaderKeyIndex = 0; pixelShaderKeyIndex < pixelShaderKeySize; + pixelShaderKeyIndex++) { stream->readInt(&mPixelShaderKey[pixelShaderKeyIndex].type); stream->readString(&mPixelShaderKey[pixelShaderKeyIndex].name); @@ -558,31 +853,30 @@ LinkResult ProgramD3D::load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream) stream->readInt(&mPixelShaderKey[pixelShaderKeyIndex].outputIndex); } - const unsigned char* binary = reinterpret_cast<const unsigned char*>(stream->data()); + stream->readString(&mGeometryShaderPreamble); + + const unsigned char *binary = reinterpret_cast<const unsigned char *>(stream->data()); const unsigned int vertexShaderCount = stream->readInt<unsigned int>(); - for (unsigned int vertexShaderIndex = 0; vertexShaderIndex < vertexShaderCount; vertexShaderIndex++) + for (unsigned int vertexShaderIndex = 0; vertexShaderIndex < vertexShaderCount; + vertexShaderIndex++) { - gl::VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS]; + size_t inputLayoutSize = stream->readInt<size_t>(); + gl::InputLayout inputLayout(inputLayoutSize, gl::VERTEX_FORMAT_INVALID); - for (size_t inputIndex = 0; inputIndex < gl::MAX_VERTEX_ATTRIBS; inputIndex++) + for (size_t inputIndex = 0; inputIndex < inputLayoutSize; inputIndex++) { - gl::VertexFormat *vertexInput = &inputLayout[inputIndex]; - stream->readInt(&vertexInput->mType); - stream->readInt(&vertexInput->mNormalized); - stream->readInt(&vertexInput->mComponents); - stream->readBool(&vertexInput->mPureInteger); + inputLayout[inputIndex] = stream->readInt<gl::VertexFormatType>(); } - unsigned int vertexShaderSize = stream->readInt<unsigned int>(); + unsigned int vertexShaderSize = stream->readInt<unsigned int>(); const unsigned char *vertexShaderFunction = binary + stream->offset(); - ShaderExecutableD3D *shaderExecutable = NULL; - gl::Error error = mRenderer->loadExecutable(vertexShaderFunction, vertexShaderSize, - SHADER_VERTEX, - mTransformFeedbackLinkedVaryings, - (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS), - &shaderExecutable); + ShaderExecutableD3D *shaderExecutable = nullptr; + + gl::Error error = mRenderer->loadExecutable( + vertexShaderFunction, vertexShaderSize, SHADER_VERTEX, mStreamOutVaryings, + (mData.getTransformFeedbackBufferMode() == GL_SEPARATE_ATTRIBS), &shaderExecutable); if (error.isError()) { return LinkResult(false, error); @@ -590,16 +884,17 @@ LinkResult ProgramD3D::load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream) if (!shaderExecutable) { - infoLog.append("Could not create vertex shader."); + infoLog << "Could not create vertex shader."; return LinkResult(false, gl::Error(GL_NO_ERROR)); } // generated converted input layout - GLenum signature[gl::MAX_VERTEX_ATTRIBS]; - getInputLayoutSignature(inputLayout, signature); + VertexExecutable::Signature signature; + VertexExecutable::getSignature(mRenderer, inputLayout, &signature); // add new binary - mVertexExecutables.push_back(new VertexExecutable(inputLayout, signature, shaderExecutable)); + mVertexExecutables.push_back( + new VertexExecutable(inputLayout, signature, shaderExecutable)); stream->skip(vertexShaderSize); } @@ -614,13 +909,13 @@ LinkResult ProgramD3D::load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream) stream->readInt(&outputs[outputIndex]); } - const size_t pixelShaderSize = stream->readInt<unsigned int>(); + const size_t pixelShaderSize = stream->readInt<unsigned int>(); const unsigned char *pixelShaderFunction = binary + stream->offset(); - ShaderExecutableD3D *shaderExecutable = NULL; - gl::Error error = mRenderer->loadExecutable(pixelShaderFunction, pixelShaderSize, SHADER_PIXEL, - mTransformFeedbackLinkedVaryings, - (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS), - &shaderExecutable); + ShaderExecutableD3D *shaderExecutable = nullptr; + + gl::Error error = mRenderer->loadExecutable( + pixelShaderFunction, pixelShaderSize, SHADER_PIXEL, mStreamOutVaryings, + (mData.getTransformFeedbackBufferMode() == GL_SEPARATE_ATTRIBS), &shaderExecutable); if (error.isError()) { return LinkResult(false, error); @@ -628,7 +923,7 @@ LinkResult ProgramD3D::load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream) if (!shaderExecutable) { - infoLog.append("Could not create pixel shader."); + infoLog << "Could not create pixel shader."; return LinkResult(false, gl::Error(GL_NO_ERROR)); } @@ -638,38 +933,35 @@ LinkResult ProgramD3D::load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream) stream->skip(pixelShaderSize); } - unsigned int geometryShaderSize = stream->readInt<unsigned int>(); - - if (geometryShaderSize > 0) + for (unsigned int geometryExeIndex = 0; geometryExeIndex < gl::PRIMITIVE_TYPE_MAX; + ++geometryExeIndex) { + unsigned int geometryShaderSize = stream->readInt<unsigned int>(); + if (geometryShaderSize == 0) + { + mGeometryExecutables[geometryExeIndex] = nullptr; + continue; + } + const unsigned char *geometryShaderFunction = binary + stream->offset(); - gl::Error error = mRenderer->loadExecutable(geometryShaderFunction, geometryShaderSize, SHADER_GEOMETRY, - mTransformFeedbackLinkedVaryings, - (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS), - &mGeometryExecutable); + bool splitAttribs = (mData.getTransformFeedbackBufferMode() == GL_SEPARATE_ATTRIBS); + + gl::Error error = mRenderer->loadExecutable( + geometryShaderFunction, geometryShaderSize, SHADER_GEOMETRY, mStreamOutVaryings, + splitAttribs, &mGeometryExecutables[geometryExeIndex]); if (error.isError()) { return LinkResult(false, error); } - if (!mGeometryExecutable) + if (!mGeometryExecutables[geometryExeIndex]) { - infoLog.append("Could not create geometry shader."); + infoLog << "Could not create geometry shader."; return LinkResult(false, gl::Error(GL_NO_ERROR)); } stream->skip(geometryShaderSize); } - GUID binaryIdentifier = {0}; - stream->readBytes(reinterpret_cast<unsigned char*>(&binaryIdentifier), sizeof(GUID)); - - GUID identifier = mRenderer->getAdapterIdentifier(); - if (memcmp(&identifier, &binaryIdentifier, sizeof(GUID)) != 0) - { - infoLog.append("Invalid program binary."); - return LinkResult(false, gl::Error(GL_NO_ERROR)); - } - initializeUniformStorage(); initAttributesByLayout(); @@ -678,9 +970,20 @@ LinkResult ProgramD3D::load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream) gl::Error ProgramD3D::save(gl::BinaryOutputStream *stream) { + // Output the DeviceIdentifier before we output any shader code + // When we load the binary again later, we can validate the device identifier before trying to + // compile any HLSL + DeviceIdentifier binaryIdentifier = mRenderer->getAdapterIdentifier(); + stream->writeBytes(reinterpret_cast<unsigned char *>(&binaryIdentifier), + sizeof(DeviceIdentifier)); + stream->writeInt(ANGLE_COMPILE_OPTIMIZATION_LEVEL); - stream->writeInt(mShaderVersion); + // TODO(jmadill): replace MAX_VERTEX_ATTRIBS + for (unsigned int i = 0; i < gl::MAX_VERTEX_ATTRIBS; ++i) + { + stream->writeInt(mSemanticIndexes[i]); + } stream->writeInt(mSamplersPS.size()); for (unsigned int i = 0; i < mSamplersPS.size(); ++i) @@ -701,79 +1004,46 @@ gl::Error ProgramD3D::save(gl::BinaryOutputStream *stream) stream->writeInt(mUsedVertexSamplerRange); stream->writeInt(mUsedPixelSamplerRange); - stream->writeInt(mUniforms.size()); - for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); ++uniformIndex) + stream->writeInt(mD3DUniforms.size()); + for (const D3DUniform *uniform : mD3DUniforms) { - const gl::LinkedUniform &uniform = *mUniforms[uniformIndex]; - - stream->writeInt(uniform.type); - stream->writeInt(uniform.precision); - stream->writeString(uniform.name); - stream->writeInt(uniform.arraySize); - stream->writeInt(uniform.blockIndex); - - stream->writeInt(uniform.blockInfo.offset); - stream->writeInt(uniform.blockInfo.arrayStride); - stream->writeInt(uniform.blockInfo.matrixStride); - stream->writeInt(uniform.blockInfo.isRowMajorMatrix); - - stream->writeInt(uniform.psRegisterIndex); - stream->writeInt(uniform.vsRegisterIndex); - stream->writeInt(uniform.registerCount); - stream->writeInt(uniform.registerElement); + // Type, name and arraySize are redundant, so aren't stored in the binary. + stream->writeInt(uniform->psRegisterIndex); + stream->writeInt(uniform->vsRegisterIndex); + stream->writeInt(uniform->registerCount); + stream->writeInt(uniform->registerElement); } - stream->writeInt(mUniformIndex.size()); - for (size_t i = 0; i < mUniformIndex.size(); ++i) + stream->writeInt(mD3DUniformBlocks.size()); + for (const D3DUniformBlock &uniformBlock : mD3DUniformBlocks) { - stream->writeString(mUniformIndex[i].name); - stream->writeInt(mUniformIndex[i].element); - stream->writeInt(mUniformIndex[i].index); - } - - stream->writeInt(mUniformBlocks.size()); - for (size_t uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); ++uniformBlockIndex) - { - const gl::UniformBlock& uniformBlock = *mUniformBlocks[uniformBlockIndex]; - - stream->writeString(uniformBlock.name); - stream->writeInt(uniformBlock.elementIndex); - stream->writeInt(uniformBlock.dataSize); - - stream->writeInt(uniformBlock.memberUniformIndexes.size()); - for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++) - { - stream->writeInt(uniformBlock.memberUniformIndexes[blockMemberIndex]); - } - stream->writeInt(uniformBlock.psRegisterIndex); stream->writeInt(uniformBlock.vsRegisterIndex); } - stream->writeInt(mTransformFeedbackBufferMode); - stream->writeInt(mTransformFeedbackLinkedVaryings.size()); - for (size_t i = 0; i < mTransformFeedbackLinkedVaryings.size(); i++) + stream->writeInt(mStreamOutVaryings.size()); + for (const auto &varying : mStreamOutVaryings) { - const gl::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); + stream->writeInt(varying.componentCount); + stream->writeInt(varying.outputSlot); } stream->writeString(mVertexHLSL); - stream->writeBytes(reinterpret_cast<unsigned char*>(&mVertexWorkarounds), sizeof(D3DCompilerWorkarounds)); + stream->writeBytes(reinterpret_cast<unsigned char *>(&mVertexWorkarounds), + sizeof(D3DCompilerWorkarounds)); stream->writeString(mPixelHLSL); - stream->writeBytes(reinterpret_cast<unsigned char*>(&mPixelWorkarounds), sizeof(D3DCompilerWorkarounds)); + stream->writeBytes(reinterpret_cast<unsigned char *>(&mPixelWorkarounds), + sizeof(D3DCompilerWorkarounds)); stream->writeInt(mUsesFragDepth); stream->writeInt(mUsesPointSize); + stream->writeInt(mUsesFlatInterpolation); const std::vector<PixelShaderOutputVariable> &pixelShaderKey = mPixelShaderKey; stream->writeInt(pixelShaderKey.size()); - for (size_t pixelShaderKeyIndex = 0; pixelShaderKeyIndex < pixelShaderKey.size(); pixelShaderKeyIndex++) + for (size_t pixelShaderKeyIndex = 0; pixelShaderKeyIndex < pixelShaderKey.size(); + pixelShaderKeyIndex++) { const PixelShaderOutputVariable &variable = pixelShaderKey[pixelShaderKeyIndex]; stream->writeInt(variable.type); @@ -782,18 +1052,20 @@ gl::Error ProgramD3D::save(gl::BinaryOutputStream *stream) stream->writeInt(variable.outputIndex); } + stream->writeString(mGeometryShaderPreamble); + stream->writeInt(mVertexExecutables.size()); - for (size_t vertexExecutableIndex = 0; vertexExecutableIndex < mVertexExecutables.size(); vertexExecutableIndex++) + for (size_t vertexExecutableIndex = 0; vertexExecutableIndex < mVertexExecutables.size(); + vertexExecutableIndex++) { VertexExecutable *vertexExecutable = mVertexExecutables[vertexExecutableIndex]; - for (size_t inputIndex = 0; inputIndex < gl::MAX_VERTEX_ATTRIBS; inputIndex++) + const auto &inputLayout = vertexExecutable->inputs(); + stream->writeInt(inputLayout.size()); + + for (size_t inputIndex = 0; inputIndex < inputLayout.size(); inputIndex++) { - const gl::VertexFormat &vertexInput = vertexExecutable->inputs()[inputIndex]; - stream->writeInt(vertexInput.mType); - stream->writeInt(vertexInput.mNormalized); - stream->writeInt(vertexInput.mComponents); - stream->writeInt(vertexInput.mPureInteger); + stream->writeInt(inputLayout[inputIndex]); } size_t vertexShaderSize = vertexExecutable->shaderExecutable()->getLength(); @@ -804,7 +1076,8 @@ gl::Error ProgramD3D::save(gl::BinaryOutputStream *stream) } stream->writeInt(mPixelExecutables.size()); - for (size_t pixelExecutableIndex = 0; pixelExecutableIndex < mPixelExecutables.size(); pixelExecutableIndex++) + for (size_t pixelExecutableIndex = 0; pixelExecutableIndex < mPixelExecutables.size(); + pixelExecutableIndex++) { PixelExecutable *pixelExecutable = mPixelExecutables[pixelExecutableIndex]; @@ -822,27 +1095,33 @@ gl::Error ProgramD3D::save(gl::BinaryOutputStream *stream) stream->writeBytes(pixelBlob, pixelShaderSize); } - size_t geometryShaderSize = (mGeometryExecutable != NULL) ? mGeometryExecutable->getLength() : 0; - stream->writeInt(geometryShaderSize); - - if (mGeometryExecutable != NULL && geometryShaderSize > 0) + for (const ShaderExecutableD3D *geometryExe : mGeometryExecutables) { - const uint8_t *geometryBlob = mGeometryExecutable->getFunction(); - stream->writeBytes(geometryBlob, geometryShaderSize); - } + if (geometryExe == nullptr) + { + stream->writeInt(0); + continue; + } - GUID binaryIdentifier = mRenderer->getAdapterIdentifier(); - stream->writeBytes(reinterpret_cast<unsigned char*>(&binaryIdentifier), sizeof(GUID)); + size_t geometryShaderSize = geometryExe->getLength(); + stream->writeInt(geometryShaderSize); + stream->writeBytes(geometryExe->getFunction(), geometryShaderSize); + } return gl::Error(GL_NO_ERROR); } -gl::Error ProgramD3D::getPixelExecutableForFramebuffer(const gl::Framebuffer *fbo, ShaderExecutableD3D **outExecutable) +void ProgramD3D::setBinaryRetrievableHint(bool /* retrievable */) +{ +} + +gl::Error ProgramD3D::getPixelExecutableForFramebuffer(const gl::Framebuffer *fbo, + ShaderExecutableD3D **outExecutable) { mPixelShaderOutputFormatCache.clear(); const FramebufferD3D *fboD3D = GetImplAs<FramebufferD3D>(fbo); - const gl::AttachmentList &colorbuffers = fboD3D->getColorAttachmentsForRender(mRenderer->getWorkarounds()); + const gl::AttachmentList &colorbuffers = fboD3D->getColorAttachmentsForRender(); for (size_t colorAttachment = 0; colorAttachment < colorbuffers.size(); ++colorAttachment) { @@ -850,7 +1129,9 @@ gl::Error ProgramD3D::getPixelExecutableForFramebuffer(const gl::Framebuffer *fb if (colorbuffer) { - mPixelShaderOutputFormatCache.push_back(colorbuffer->getBinding() == GL_BACK ? GL_COLOR_ATTACHMENT0 : colorbuffer->getBinding()); + mPixelShaderOutputFormatCache.push_back(colorbuffer->getBinding() == GL_BACK + ? GL_COLOR_ATTACHMENT0 + : colorbuffer->getBinding()); } else { @@ -874,8 +1155,8 @@ gl::Error ProgramD3D::getPixelExecutableForOutputLayout(const std::vector<GLenum } } - std::string finalPixelHLSL = mDynamicHLSL->generatePixelShaderForOutputSignature(mPixelHLSL, mPixelShaderKey, mUsesFragDepth, - outputSignature); + std::string finalPixelHLSL = mDynamicHLSL->generatePixelShaderForOutputSignature( + mPixelHLSL, mPixelShaderKey, mUsesFragDepth, outputSignature); // Generate new pixel executable ShaderExecutableD3D *pixelExecutable = NULL; @@ -883,10 +1164,10 @@ gl::Error ProgramD3D::getPixelExecutableForOutputLayout(const std::vector<GLenum gl::InfoLog tempInfoLog; gl::InfoLog *currentInfoLog = infoLog ? infoLog : &tempInfoLog; - gl::Error error = mRenderer->compileToExecutable(*currentInfoLog, finalPixelHLSL, SHADER_PIXEL, - mTransformFeedbackLinkedVaryings, - (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS), - mPixelWorkarounds, &pixelExecutable); + gl::Error error = mRenderer->compileToExecutable( + *currentInfoLog, finalPixelHLSL, SHADER_PIXEL, mStreamOutVaryings, + (mData.getTransformFeedbackBufferMode() == GL_SEPARATE_ATTRIBS), mPixelWorkarounds, + &pixelExecutable); if (error.isError()) { return error; @@ -899,7 +1180,7 @@ gl::Error ProgramD3D::getPixelExecutableForOutputLayout(const std::vector<GLenum else if (!infoLog) { std::vector<char> tempCharBuffer(tempInfoLog.getLength() + 3); - tempInfoLog.getLog(tempInfoLog.getLength(), NULL, &tempCharBuffer[0]); + tempInfoLog.getLog(static_cast<GLsizei>(tempInfoLog.getLength()), NULL, &tempCharBuffer[0]); ERR("Error compiling dynamic pixel executable:\n%s\n", &tempCharBuffer[0]); } @@ -907,16 +1188,15 @@ gl::Error ProgramD3D::getPixelExecutableForOutputLayout(const std::vector<GLenum return gl::Error(GL_NO_ERROR); } -gl::Error ProgramD3D::getVertexExecutableForInputLayout(const gl::VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS], +gl::Error ProgramD3D::getVertexExecutableForInputLayout(const gl::InputLayout &inputLayout, ShaderExecutableD3D **outExectuable, gl::InfoLog *infoLog) { - GLenum signature[gl::MAX_VERTEX_ATTRIBS]; - getInputLayoutSignature(inputLayout, signature); + VertexExecutable::getSignature(mRenderer, inputLayout, &mCachedVertexSignature); for (size_t executableIndex = 0; executableIndex < mVertexExecutables.size(); executableIndex++) { - if (mVertexExecutables[executableIndex]->matchesSignature(signature)) + if (mVertexExecutables[executableIndex]->matchesSignature(mCachedVertexSignature)) { *outExectuable = mVertexExecutables[executableIndex]->shaderExecutable(); return gl::Error(GL_NO_ERROR); @@ -924,7 +1204,8 @@ gl::Error ProgramD3D::getVertexExecutableForInputLayout(const gl::VertexFormat i } // Generate new dynamic layout with attribute conversions - std::string finalVertexHLSL = mDynamicHLSL->generateVertexShaderForInputLayout(mVertexHLSL, inputLayout, mShaderAttributes); + std::string finalVertexHLSL = mDynamicHLSL->generateVertexShaderForInputLayout( + mVertexHLSL, inputLayout, mData.getAttributes()); // Generate new vertex executable ShaderExecutableD3D *vertexExecutable = NULL; @@ -932,10 +1213,10 @@ gl::Error ProgramD3D::getVertexExecutableForInputLayout(const gl::VertexFormat i gl::InfoLog tempInfoLog; gl::InfoLog *currentInfoLog = infoLog ? infoLog : &tempInfoLog; - gl::Error error = mRenderer->compileToExecutable(*currentInfoLog, finalVertexHLSL, SHADER_VERTEX, - mTransformFeedbackLinkedVaryings, - (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS), - mVertexWorkarounds, &vertexExecutable); + gl::Error error = mRenderer->compileToExecutable( + *currentInfoLog, finalVertexHLSL, SHADER_VERTEX, mStreamOutVaryings, + (mData.getTransformFeedbackBufferMode() == GL_SEPARATE_ATTRIBS), mVertexWorkarounds, + &vertexExecutable); if (error.isError()) { return error; @@ -943,12 +1224,13 @@ gl::Error ProgramD3D::getVertexExecutableForInputLayout(const gl::VertexFormat i if (vertexExecutable) { - mVertexExecutables.push_back(new VertexExecutable(inputLayout, signature, vertexExecutable)); + mVertexExecutables.push_back( + new VertexExecutable(inputLayout, mCachedVertexSignature, vertexExecutable)); } else if (!infoLog) { std::vector<char> tempCharBuffer(tempInfoLog.getLength() + 3); - tempInfoLog.getLog(tempInfoLog.getLength(), NULL, &tempCharBuffer[0]); + tempInfoLog.getLog(static_cast<GLsizei>(tempInfoLog.getLength()), NULL, &tempCharBuffer[0]); ERR("Error compiling dynamic vertex executable:\n%s\n", &tempCharBuffer[0]); } @@ -956,50 +1238,96 @@ gl::Error ProgramD3D::getVertexExecutableForInputLayout(const gl::VertexFormat i return gl::Error(GL_NO_ERROR); } -LinkResult ProgramD3D::compileProgramExecutables(gl::InfoLog &infoLog, gl::Shader *fragmentShader, gl::Shader *vertexShader, - int registers) +gl::Error ProgramD3D::getGeometryExecutableForPrimitiveType(const gl::Data &data, + GLenum drawMode, + ShaderExecutableD3D **outExecutable, + gl::InfoLog *infoLog) { - ShaderD3D *vertexShaderD3D = ShaderD3D::makeShaderD3D(vertexShader->getImplementation()); - ShaderD3D *fragmentShaderD3D = ShaderD3D::makeShaderD3D(fragmentShader->getImplementation()); + if (outExecutable) + { + *outExecutable = nullptr; + } + + // Return a null shader if the current rendering doesn't use a geometry shader + if (!usesGeometryShader(drawMode)) + { + return gl::Error(GL_NO_ERROR); + } + + gl::PrimitiveType geometryShaderType = GetGeometryShaderTypeFromDrawMode(drawMode); + + if (mGeometryExecutables[geometryShaderType] != nullptr) + { + if (outExecutable) + { + *outExecutable = mGeometryExecutables[geometryShaderType]; + } + return gl::Error(GL_NO_ERROR); + } + + std::string geometryHLSL = mDynamicHLSL->generateGeometryShaderHLSL( + geometryShaderType, data, mData, mRenderer->presentPathFastEnabled(), + mGeometryShaderPreamble); + + gl::InfoLog tempInfoLog; + gl::InfoLog *currentInfoLog = infoLog ? infoLog : &tempInfoLog; + + gl::Error error = mRenderer->compileToExecutable( + *currentInfoLog, geometryHLSL, SHADER_GEOMETRY, mStreamOutVaryings, + (mData.getTransformFeedbackBufferMode() == GL_SEPARATE_ATTRIBS), D3DCompilerWorkarounds(), + &mGeometryExecutables[geometryShaderType]); + + if (!infoLog && error.isError()) + { + std::vector<char> tempCharBuffer(tempInfoLog.getLength() + 3); + tempInfoLog.getLog(static_cast<GLsizei>(tempInfoLog.getLength()), NULL, &tempCharBuffer[0]); + ERR("Error compiling dynamic geometry executable:\n%s\n", &tempCharBuffer[0]); + } + + if (outExecutable) + { + *outExecutable = mGeometryExecutables[geometryShaderType]; + } + return error; +} - gl::VertexFormat defaultInputLayout[gl::MAX_VERTEX_ATTRIBS]; - GetDefaultInputLayoutFromShader(vertexShader->getActiveAttributes(), defaultInputLayout); +LinkResult ProgramD3D::compileProgramExecutables(const gl::Data &data, gl::InfoLog &infoLog) +{ + const gl::InputLayout &defaultInputLayout = + GetDefaultInputLayoutFromShader(mData.getAttachedVertexShader()); ShaderExecutableD3D *defaultVertexExecutable = NULL; - gl::Error error = getVertexExecutableForInputLayout(defaultInputLayout, &defaultVertexExecutable, &infoLog); + gl::Error error = + getVertexExecutableForInputLayout(defaultInputLayout, &defaultVertexExecutable, &infoLog); if (error.isError()) { return LinkResult(false, error); } - std::vector<GLenum> defaultPixelOutput = GetDefaultOutputLayoutFromShader(getPixelShaderKey()); + std::vector<GLenum> defaultPixelOutput = GetDefaultOutputLayoutFromShader(getPixelShaderKey()); ShaderExecutableD3D *defaultPixelExecutable = NULL; - error = getPixelExecutableForOutputLayout(defaultPixelOutput, &defaultPixelExecutable, &infoLog); + error = + getPixelExecutableForOutputLayout(defaultPixelOutput, &defaultPixelExecutable, &infoLog); if (error.isError()) { return LinkResult(false, error); } - if (usesGeometryShader()) + // Auto-generate the geometry shader here, if we expect to be using point rendering in D3D11. + ShaderExecutableD3D *pointGS = nullptr; + if (usesGeometryShader(GL_POINTS)) { - std::string geometryHLSL = mDynamicHLSL->generateGeometryShaderHLSL(registers, fragmentShaderD3D, vertexShaderD3D); - - - error = mRenderer->compileToExecutable(infoLog, geometryHLSL, SHADER_GEOMETRY, mTransformFeedbackLinkedVaryings, - (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS), - D3DCompilerWorkarounds(), &mGeometryExecutable); - if (error.isError()) - { - return LinkResult(false, error); - } + getGeometryExecutableForPrimitiveType(data, GL_POINTS, &pointGS, &infoLog); } -#if ANGLE_SHADER_DEBUG_INFO == ANGLE_ENABLED - if (usesGeometryShader() && mGeometryExecutable) + const ShaderD3D *vertexShaderD3D = GetImplAs<ShaderD3D>(mData.getAttachedVertexShader()); + + if (usesGeometryShader(GL_POINTS) && pointGS) { - // Geometry shaders are currently only used internally, so there is no corresponding shader object at the interface level - // For now the geometry shader debug info is pre-pended to the vertex shader, this is a bit of a clutch + // Geometry shaders are currently only used internally, so there is no corresponding shader + // object at the interface level. For now the geometry shader debug info is prepended to + // the vertex shader. vertexShaderD3D->appendDebugInfo("// GEOMETRY SHADER BEGIN\n\n"); - vertexShaderD3D->appendDebugInfo(mGeometryExecutable->getDebugInfo()); + vertexShaderD3D->appendDebugInfo(pointGS->getDebugInfo()); vertexShaderD3D->appendDebugInfo("\nGEOMETRY SHADER END\n\n\n"); } @@ -1010,200 +1338,316 @@ LinkResult ProgramD3D::compileProgramExecutables(gl::InfoLog &infoLog, gl::Shade if (defaultPixelExecutable) { + const ShaderD3D *fragmentShaderD3D = + GetImplAs<ShaderD3D>(mData.getAttachedFragmentShader()); fragmentShaderD3D->appendDebugInfo(defaultPixelExecutable->getDebugInfo()); } -#endif - bool linkSuccess = (defaultVertexExecutable && defaultPixelExecutable && (!usesGeometryShader() || mGeometryExecutable)); + bool linkSuccess = (defaultVertexExecutable && defaultPixelExecutable && + (!usesGeometryShader(GL_POINTS) || pointGS)); return LinkResult(linkSuccess, gl::Error(GL_NO_ERROR)); } -LinkResult ProgramD3D::link(const gl::Data &data, gl::InfoLog &infoLog, - gl::Shader *fragmentShader, gl::Shader *vertexShader, - const std::vector<std::string> &transformFeedbackVaryings, - GLenum transformFeedbackBufferMode, - int *registers, std::vector<gl::LinkedVarying> *linkedVaryings, - std::map<int, gl::VariableLocation> *outputVariables) +LinkResult ProgramD3D::link(const gl::Data &data, gl::InfoLog &infoLog) { - ShaderD3D *vertexShaderD3D = ShaderD3D::makeShaderD3D(vertexShader->getImplementation()); - ShaderD3D *fragmentShaderD3D = ShaderD3D::makeShaderD3D(fragmentShader->getImplementation()); + reset(); - mSamplersPS.resize(data.caps->maxTextureImageUnits); - mSamplersVS.resize(data.caps->maxVertexTextureImageUnits); + // TODO(jmadill): structures containing samplers + for (const gl::LinkedUniform &linkedUniform : mData.getUniforms()) + { + if (linkedUniform.isSampler() && linkedUniform.isField()) + { + infoLog << "Structures containing samplers not currently supported in D3D."; + return LinkResult(false, gl::Error(GL_NO_ERROR)); + } + } - mTransformFeedbackBufferMode = transformFeedbackBufferMode; + const gl::Shader *vertexShader = mData.getAttachedVertexShader(); + const gl::Shader *fragmentShader = mData.getAttachedFragmentShader(); - mPixelHLSL = fragmentShaderD3D->getTranslatedSource(); - fragmentShaderD3D->generateWorkarounds(&mPixelWorkarounds); + const ShaderD3D *vertexShaderD3D = GetImplAs<ShaderD3D>(vertexShader); + const ShaderD3D *fragmentShaderD3D = GetImplAs<ShaderD3D>(fragmentShader); + + mSamplersVS.resize(data.caps->maxVertexTextureImageUnits); + mSamplersPS.resize(data.caps->maxTextureImageUnits); - mVertexHLSL = vertexShaderD3D->getTranslatedSource(); vertexShaderD3D->generateWorkarounds(&mVertexWorkarounds); - mShaderVersion = vertexShaderD3D->getShaderVersion(); + fragmentShaderD3D->generateWorkarounds(&mPixelWorkarounds); + + if (mRenderer->getRendererLimitations().noFrontFacingSupport) + { + if (fragmentShaderD3D->usesFrontFacing()) + { + infoLog << "The current renderer doesn't support gl_FrontFacing"; + return LinkResult(false, gl::Error(GL_NO_ERROR)); + } + } + + std::vector<PackedVarying> packedVaryings = + MergeVaryings(*vertexShader, *fragmentShader, mData.getTransformFeedbackVaryingNames()); // Map the varyings to the register file - VaryingPacking packing = { NULL }; - *registers = mDynamicHLSL->packVaryings(infoLog, packing, fragmentShaderD3D, vertexShaderD3D, transformFeedbackVaryings); + VaryingPacking varyingPacking(data.caps->maxVaryingVectors); + if (!varyingPacking.packVaryings(infoLog, packedVaryings, + mData.getTransformFeedbackVaryingNames())) + { + return LinkResult(false, gl::Error(GL_NO_ERROR)); + } + + ProgramD3DMetadata metadata(mRenderer->getMajorShaderModel(), mRenderer->getShaderModelSuffix(), + usesInstancedPointSpriteEmulation(), + mRenderer->presentPathFastEnabled(), vertexShaderD3D, + fragmentShaderD3D); - if (*registers < 0) + varyingPacking.enableBuiltins(SHADER_VERTEX, metadata); + varyingPacking.enableBuiltins(SHADER_PIXEL, metadata); + + if (static_cast<GLuint>(varyingPacking.getRegisterCount()) > data.caps->maxVaryingVectors) { + infoLog << "No varying registers left to support gl_FragCoord/gl_PointCoord"; return LinkResult(false, gl::Error(GL_NO_ERROR)); } - if (!gl::Program::linkVaryings(infoLog, fragmentShader, vertexShader)) + // TODO(jmadill): Implement more sophisticated component packing in D3D9. + // We can fail here because we use one semantic per GLSL varying. D3D11 can pack varyings + // intelligently, but D3D9 assumes one semantic per register. + if (mRenderer->getRendererClass() == RENDERER_D3D9 && + varyingPacking.getMaxSemanticIndex() > data.caps->maxVaryingVectors) { + infoLog << "Cannot pack these varyings on D3D9."; return LinkResult(false, gl::Error(GL_NO_ERROR)); } - if (!mDynamicHLSL->generateShaderLinkHLSL(data, infoLog, *registers, packing, mPixelHLSL, mVertexHLSL, - fragmentShaderD3D, vertexShaderD3D, transformFeedbackVaryings, - linkedVaryings, outputVariables, &mPixelShaderKey, &mUsesFragDepth)) + if (!mDynamicHLSL->generateShaderLinkHLSL(data, mData, metadata, varyingPacking, &mPixelHLSL, + &mVertexHLSL)) { return LinkResult(false, gl::Error(GL_NO_ERROR)); } mUsesPointSize = vertexShaderD3D->usesPointSize(); + mDynamicHLSL->getPixelShaderOutputKey(data, mData, metadata, &mPixelShaderKey); + mUsesFragDepth = metadata.usesFragDepth(mData); - initAttributesByLayout(); + // Cache if we use flat shading + mUsesFlatInterpolation = false; + for (const auto &varying : packedVaryings) + { + if (varying.interpolation == sh::INTERPOLATION_FLAT) + { + mUsesFlatInterpolation = true; + break; + } + } + + if (mRenderer->getMajorShaderModel() >= 4) + { + varyingPacking.enableBuiltins(SHADER_GEOMETRY, metadata); + mGeometryShaderPreamble = mDynamicHLSL->generateGeometryShaderPreamble(varyingPacking); + } + + initSemanticIndex(); + + defineUniformsAndAssignRegisters(); + + gatherTransformFeedbackVaryings(varyingPacking); + + LinkResult result = compileProgramExecutables(data, infoLog); + if (result.error.isError() || !result.linkSuccess) + { + infoLog << "Failed to create D3D shaders."; + return result; + } + + initUniformBlockInfo(); return LinkResult(true, gl::Error(GL_NO_ERROR)); } -void ProgramD3D::getInputLayoutSignature(const gl::VertexFormat inputLayout[], GLenum signature[]) const +GLboolean ProgramD3D::validate(const gl::Caps & /*caps*/, gl::InfoLog * /*infoLog*/) { - mDynamicHLSL->getInputLayoutSignature(inputLayout, signature); + // TODO(jmadill): Do something useful here? + return GL_TRUE; +} + +void ProgramD3D::initUniformBlockInfo() +{ + const gl::Shader *vertexShader = mData.getAttachedVertexShader(); + + for (const sh::InterfaceBlock &vertexBlock : vertexShader->getInterfaceBlocks()) + { + if (!vertexBlock.staticUse && vertexBlock.layout == sh::BLOCKLAYOUT_PACKED) + continue; + + if (mBlockDataSizes.count(vertexBlock.name) > 0) + continue; + + size_t dataSize = getUniformBlockInfo(vertexBlock); + mBlockDataSizes[vertexBlock.name] = dataSize; + } + + const gl::Shader *fragmentShader = mData.getAttachedFragmentShader(); + + for (const sh::InterfaceBlock &fragmentBlock : fragmentShader->getInterfaceBlocks()) + { + if (!fragmentBlock.staticUse && fragmentBlock.layout == sh::BLOCKLAYOUT_PACKED) + continue; + + if (mBlockDataSizes.count(fragmentBlock.name) > 0) + continue; + + size_t dataSize = getUniformBlockInfo(fragmentBlock); + mBlockDataSizes[fragmentBlock.name] = dataSize; + } +} + +void ProgramD3D::assignUniformBlockRegisters() +{ + mD3DUniformBlocks.clear(); + + // Assign registers and update sizes. + const ShaderD3D *vertexShaderD3D = GetImplAs<ShaderD3D>(mData.getAttachedVertexShader()); + const ShaderD3D *fragmentShaderD3D = GetImplAs<ShaderD3D>(mData.getAttachedFragmentShader()); + + for (const gl::UniformBlock &uniformBlock : mData.getUniformBlocks()) + { + unsigned int uniformBlockElement = uniformBlock.isArray ? uniformBlock.arrayElement : 0; + + D3DUniformBlock d3dUniformBlock; + + if (uniformBlock.vertexStaticUse) + { + unsigned int baseRegister = + vertexShaderD3D->getInterfaceBlockRegister(uniformBlock.name); + d3dUniformBlock.vsRegisterIndex = baseRegister + uniformBlockElement; + } + + if (uniformBlock.fragmentStaticUse) + { + unsigned int baseRegister = + fragmentShaderD3D->getInterfaceBlockRegister(uniformBlock.name); + d3dUniformBlock.psRegisterIndex = baseRegister + uniformBlockElement; + } + + mD3DUniformBlocks.push_back(d3dUniformBlock); + } } void ProgramD3D::initializeUniformStorage() { // Compute total default block size - unsigned int vertexRegisters = 0; + unsigned int vertexRegisters = 0; unsigned int fragmentRegisters = 0; - for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++) + for (const D3DUniform *d3dUniform : mD3DUniforms) { - const gl::LinkedUniform &uniform = *mUniforms[uniformIndex]; - - if (!gl::IsSamplerType(uniform.type)) + if (!d3dUniform->isSampler()) { - if (uniform.isReferencedByVertexShader()) + if (d3dUniform->isReferencedByVertexShader()) { - vertexRegisters = std::max(vertexRegisters, uniform.vsRegisterIndex + uniform.registerCount); + vertexRegisters = std::max(vertexRegisters, + d3dUniform->vsRegisterIndex + d3dUniform->registerCount); } - if (uniform.isReferencedByFragmentShader()) + if (d3dUniform->isReferencedByFragmentShader()) { - fragmentRegisters = std::max(fragmentRegisters, uniform.psRegisterIndex + uniform.registerCount); + fragmentRegisters = std::max( + fragmentRegisters, d3dUniform->psRegisterIndex + d3dUniform->registerCount); } } } - mVertexUniformStorage = mRenderer->createUniformStorage(vertexRegisters * 16u); + mVertexUniformStorage = mRenderer->createUniformStorage(vertexRegisters * 16u); mFragmentUniformStorage = mRenderer->createUniformStorage(fragmentRegisters * 16u); } -gl::Error ProgramD3D::applyUniforms() +gl::Error ProgramD3D::applyUniforms(GLenum drawMode) { - updateSamplerMapping(); + ASSERT(!mDirtySamplerMapping); - gl::Error error = mRenderer->applyUniforms(*this, mUniforms); + gl::Error error = mRenderer->applyUniforms(*this, drawMode, mD3DUniforms); if (error.isError()) { return error; } - for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++) + for (D3DUniform *d3dUniform : mD3DUniforms) { - mUniforms[uniformIndex]->dirty = false; + d3dUniform->dirty = false; } return gl::Error(GL_NO_ERROR); } -gl::Error ProgramD3D::applyUniformBuffers(const gl::Data &data, GLuint uniformBlockBindings[]) +gl::Error ProgramD3D::applyUniformBuffers(const gl::Data &data) { - GLint vertexUniformBuffers[gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS]; - GLint fragmentUniformBuffers[gl::IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS]; - - for (unsigned int registerIndex = 0; registerIndex < gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS; ++registerIndex) + if (mData.getUniformBlocks().empty()) { - vertexUniformBuffers[registerIndex] = -1; + return gl::Error(GL_NO_ERROR); } - for (unsigned int registerIndex = 0; registerIndex < gl::IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS; ++registerIndex) + // Lazy init. + if (mD3DUniformBlocks.empty()) { - fragmentUniformBuffers[registerIndex] = -1; + assignUniformBlockRegisters(); } + mVertexUBOCache.clear(); + mFragmentUBOCache.clear(); + const unsigned int reservedBuffersInVS = mRenderer->getReservedVertexUniformBuffers(); const unsigned int reservedBuffersInFS = mRenderer->getReservedFragmentUniformBuffers(); - for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); uniformBlockIndex++) + for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < mD3DUniformBlocks.size(); + uniformBlockIndex++) { - gl::UniformBlock *uniformBlock = mUniformBlocks[uniformBlockIndex]; - GLuint blockBinding = uniformBlockBindings[uniformBlockIndex]; - - ASSERT(uniformBlock); + const D3DUniformBlock &uniformBlock = mD3DUniformBlocks[uniformBlockIndex]; + GLuint blockBinding = mData.getUniformBlockBinding(uniformBlockIndex); // Unnecessary to apply an unreferenced standard or shared UBO - if (!uniformBlock->isReferencedByVertexShader() && !uniformBlock->isReferencedByFragmentShader()) + if (!uniformBlock.vertexStaticUse() && !uniformBlock.fragmentStaticUse()) { continue; } - if (uniformBlock->isReferencedByVertexShader()) + if (uniformBlock.vertexStaticUse()) { - unsigned int registerIndex = uniformBlock->vsRegisterIndex - reservedBuffersInVS; - ASSERT(vertexUniformBuffers[registerIndex] == -1); + unsigned int registerIndex = uniformBlock.vsRegisterIndex - reservedBuffersInVS; ASSERT(registerIndex < data.caps->maxVertexUniformBlocks); - vertexUniformBuffers[registerIndex] = blockBinding; + + if (mVertexUBOCache.size() <= registerIndex) + { + mVertexUBOCache.resize(registerIndex + 1, -1); + } + + ASSERT(mVertexUBOCache[registerIndex] == -1); + mVertexUBOCache[registerIndex] = blockBinding; } - if (uniformBlock->isReferencedByFragmentShader()) + if (uniformBlock.fragmentStaticUse()) { - unsigned int registerIndex = uniformBlock->psRegisterIndex - reservedBuffersInFS; - ASSERT(fragmentUniformBuffers[registerIndex] == -1); + unsigned int registerIndex = uniformBlock.psRegisterIndex - reservedBuffersInFS; ASSERT(registerIndex < data.caps->maxFragmentUniformBlocks); - fragmentUniformBuffers[registerIndex] = blockBinding; - } - } - return mRenderer->setUniformBuffers(data, vertexUniformBuffers, fragmentUniformBuffers); -} + if (mFragmentUBOCache.size() <= registerIndex) + { + mFragmentUBOCache.resize(registerIndex + 1, -1); + } -bool ProgramD3D::assignUniformBlockRegister(gl::InfoLog &infoLog, gl::UniformBlock *uniformBlock, GLenum shader, - unsigned int registerIndex, const gl::Caps &caps) -{ - if (shader == GL_VERTEX_SHADER) - { - uniformBlock->vsRegisterIndex = registerIndex; - if (registerIndex - mRenderer->getReservedVertexUniformBuffers() >= caps.maxVertexUniformBlocks) - { - infoLog.append("Vertex shader uniform block count exceed GL_MAX_VERTEX_UNIFORM_BLOCKS (%u)", caps.maxVertexUniformBlocks); - return false; + ASSERT(mFragmentUBOCache[registerIndex] == -1); + mFragmentUBOCache[registerIndex] = blockBinding; } } - else if (shader == GL_FRAGMENT_SHADER) - { - uniformBlock->psRegisterIndex = registerIndex; - if (registerIndex - mRenderer->getReservedFragmentUniformBuffers() >= caps.maxFragmentUniformBlocks) - { - infoLog.append("Fragment shader uniform block count exceed GL_MAX_FRAGMENT_UNIFORM_BLOCKS (%u)", caps.maxFragmentUniformBlocks); - return false; - } - } - else UNREACHABLE(); - return true; + return mRenderer->setUniformBuffers(data, mVertexUBOCache, mFragmentUBOCache); } void ProgramD3D::dirtyAllUniforms() { - unsigned int numUniforms = mUniforms.size(); - for (unsigned int index = 0; index < numUniforms; index++) + for (D3DUniform *d3dUniform : mD3DUniforms) { - mUniforms[index]->dirty = true; + d3dUniform->dirty = true; } } -void ProgramD3D::setUniform1fv(GLint location, GLsizei count, const GLfloat* v) +void ProgramD3D::setUniform1fv(GLint location, GLsizei count, const GLfloat *v) { setUniform(location, count, v, GL_FLOAT); } @@ -1223,47 +1667,74 @@ void ProgramD3D::setUniform4fv(GLint location, GLsizei count, const GLfloat *v) setUniform(location, count, v, GL_FLOAT_VEC4); } -void ProgramD3D::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +void ProgramD3D::setUniformMatrix2fv(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) { setUniformMatrixfv<2, 2>(location, count, transpose, value, GL_FLOAT_MAT2); } -void ProgramD3D::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +void ProgramD3D::setUniformMatrix3fv(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) { setUniformMatrixfv<3, 3>(location, count, transpose, value, GL_FLOAT_MAT3); } -void ProgramD3D::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +void ProgramD3D::setUniformMatrix4fv(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) { setUniformMatrixfv<4, 4>(location, count, transpose, value, GL_FLOAT_MAT4); } -void ProgramD3D::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +void ProgramD3D::setUniformMatrix2x3fv(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) { setUniformMatrixfv<2, 3>(location, count, transpose, value, GL_FLOAT_MAT2x3); } -void ProgramD3D::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +void ProgramD3D::setUniformMatrix3x2fv(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) { setUniformMatrixfv<3, 2>(location, count, transpose, value, GL_FLOAT_MAT3x2); } -void ProgramD3D::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +void ProgramD3D::setUniformMatrix2x4fv(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) { setUniformMatrixfv<2, 4>(location, count, transpose, value, GL_FLOAT_MAT2x4); } -void ProgramD3D::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +void ProgramD3D::setUniformMatrix4x2fv(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) { setUniformMatrixfv<4, 2>(location, count, transpose, value, GL_FLOAT_MAT4x2); } -void ProgramD3D::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +void ProgramD3D::setUniformMatrix3x4fv(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) { setUniformMatrixfv<3, 4>(location, count, transpose, value, GL_FLOAT_MAT3x4); } -void ProgramD3D::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +void ProgramD3D::setUniformMatrix4x3fv(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) { setUniformMatrixfv<4, 3>(location, count, transpose, value, GL_FLOAT_MAT4x3); } @@ -1308,106 +1779,86 @@ void ProgramD3D::setUniform4uiv(GLint location, GLsizei count, const GLuint *v) setUniform(location, count, v, GL_UNSIGNED_INT_VEC4); } -void ProgramD3D::getUniformfv(GLint location, GLfloat *params) +void ProgramD3D::setUniformBlockBinding(GLuint /*uniformBlockIndex*/, + GLuint /*uniformBlockBinding*/) { - getUniformv(location, params, GL_FLOAT); } -void ProgramD3D::getUniformiv(GLint location, GLint *params) +void ProgramD3D::defineUniformsAndAssignRegisters() { - getUniformv(location, params, GL_INT); -} - -void ProgramD3D::getUniformuiv(GLint location, GLuint *params) -{ - getUniformv(location, params, GL_UNSIGNED_INT); -} + D3DUniformMap uniformMap; + const gl::Shader *vertexShader = mData.getAttachedVertexShader(); + for (const sh::Uniform &vertexUniform : vertexShader->getUniforms()) -bool ProgramD3D::linkUniforms(gl::InfoLog &infoLog, const gl::Shader &vertexShader, const gl::Shader &fragmentShader, - const gl::Caps &caps) -{ - const ShaderD3D *vertexShaderD3D = ShaderD3D::makeShaderD3D(vertexShader.getImplementation()); - const ShaderD3D *fragmentShaderD3D = ShaderD3D::makeShaderD3D(fragmentShader.getImplementation()); - - 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++) { - 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()) + if (vertexUniform.staticUse) { - const sh::Uniform &vertexUniform = *entry->second; - const std::string &uniformName = "uniform '" + vertexUniform.name + "'"; - if (!gl::Program::linkValidateUniforms(infoLog, uniformName, vertexUniform, fragmentUniform)) - { - return false; - } + defineUniformBase(vertexShader, vertexUniform, &uniformMap); } } - for (unsigned int uniformIndex = 0; uniformIndex < vertexUniforms.size(); uniformIndex++) + const gl::Shader *fragmentShader = mData.getAttachedFragmentShader(); + for (const sh::Uniform &fragmentUniform : fragmentShader->getUniforms()) { - const sh::Uniform &uniform = vertexUniforms[uniformIndex]; - - if (uniform.staticUse) + if (fragmentUniform.staticUse) { - defineUniformBase(vertexShaderD3D, uniform, vertexShaderD3D->getUniformRegister(uniform.name)); + defineUniformBase(fragmentShader, fragmentUniform, &uniformMap); } } - for (unsigned int uniformIndex = 0; uniformIndex < fragmentUniforms.size(); uniformIndex++) + // Initialize the D3DUniform list to mirror the indexing of the GL layer. + for (const gl::LinkedUniform &glUniform : mData.getUniforms()) { - const sh::Uniform &uniform = fragmentUniforms[uniformIndex]; - - if (uniform.staticUse) - { - defineUniformBase(fragmentShaderD3D, uniform, fragmentShaderD3D->getUniformRegister(uniform.name)); - } - } + if (!glUniform.isInDefaultBlock()) + continue; - if (!indexUniforms(infoLog, caps)) - { - return false; + auto mapEntry = uniformMap.find(glUniform.name); + ASSERT(mapEntry != uniformMap.end()); + mD3DUniforms.push_back(mapEntry->second); } + assignAllSamplerRegisters(); initializeUniformStorage(); +} - // special case for gl_DepthRange, the only built-in uniform (also a struct) - if (vertexShaderD3D->usesDepthRange() || fragmentShaderD3D->usesDepthRange()) +void ProgramD3D::defineUniformBase(const gl::Shader *shader, + const sh::Uniform &uniform, + D3DUniformMap *uniformMap) +{ + if (uniform.isBuiltIn()) { - const sh::BlockMemberInfo &defaultInfo = sh::BlockMemberInfo::getDefaultBlockInfo(); - - mUniforms.push_back(new gl::LinkedUniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.near", 0, -1, defaultInfo)); - mUniforms.push_back(new gl::LinkedUniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.far", 0, -1, defaultInfo)); - mUniforms.push_back(new gl::LinkedUniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.diff", 0, -1, defaultInfo)); + defineUniform(shader->getType(), uniform, uniform.name, nullptr, uniformMap); + return; } - return true; + const ShaderD3D *shaderD3D = GetImplAs<ShaderD3D>(shader); + + unsigned int startRegister = shaderD3D->getUniformRegister(uniform.name); + ShShaderOutput outputType = shaderD3D->getCompilerOutputType(); + sh::HLSLBlockEncoder encoder(sh::HLSLBlockEncoder::GetStrategyFor(outputType)); + encoder.skipRegisters(startRegister); + + defineUniform(shader->getType(), uniform, uniform.name, &encoder, uniformMap); } -void ProgramD3D::defineUniformBase(const ShaderD3D *shader, const sh::Uniform &uniform, unsigned int uniformRegister) +D3DUniform *ProgramD3D::getD3DUniformByName(const std::string &name) { - ShShaderOutput outputType = shader->getCompilerOutputType(); - sh::HLSLBlockEncoder encoder(sh::HLSLBlockEncoder::GetStrategyFor(outputType)); - encoder.skipRegisters(uniformRegister); + for (D3DUniform *d3dUniform : mD3DUniforms) + { + if (d3dUniform->name == name) + { + return d3dUniform; + } + } - defineUniform(shader, uniform, uniform.name, &encoder); + return nullptr; } -void ProgramD3D::defineUniform(const ShaderD3D *shader, const sh::ShaderVariable &uniform, - const std::string &fullName, sh::HLSLBlockEncoder *encoder) +void ProgramD3D::defineUniform(GLenum shaderType, + const sh::ShaderVariable &uniform, + const std::string &fullName, + sh::HLSLBlockEncoder *encoder, + D3DUniformMap *uniformMap) { if (uniform.isStruct()) { @@ -1415,50 +1866,62 @@ void ProgramD3D::defineUniform(const ShaderD3D *shader, const sh::ShaderVariable { const std::string &elementString = (uniform.isArray() ? ArrayString(elementIndex) : ""); - encoder->enterAggregateType(); + if (encoder) + encoder->enterAggregateType(); for (size_t fieldIndex = 0; fieldIndex < uniform.fields.size(); fieldIndex++) { - const sh::ShaderVariable &field = uniform.fields[fieldIndex]; + const sh::ShaderVariable &field = uniform.fields[fieldIndex]; const std::string &fieldFullName = (fullName + elementString + "." + field.name); - defineUniform(shader, field, fieldFullName, encoder); + defineUniform(shaderType, field, fieldFullName, encoder, uniformMap); } - encoder->exitAggregateType(); + if (encoder) + encoder->exitAggregateType(); } + return; } - else // Not a struct + + // Not a struct. Arrays are treated as aggregate types. + if (uniform.isArray() && encoder) { - // Arrays are treated as aggregate types - if (uniform.isArray()) - { - encoder->enterAggregateType(); - } + encoder->enterAggregateType(); + } - gl::LinkedUniform *linkedUniform = getUniformByName(fullName); + // Advance the uniform offset, to track registers allocation for structs + sh::BlockMemberInfo blockInfo = + encoder ? encoder->encodeType(uniform.type, uniform.arraySize, false) + : sh::BlockMemberInfo::getDefaultBlockInfo(); - // Advance the uniform offset, to track registers allocation for structs - sh::BlockMemberInfo blockInfo = encoder->encodeType(uniform.type, uniform.arraySize, false); + auto uniformMapEntry = uniformMap->find(fullName); + D3DUniform *d3dUniform = nullptr; - if (!linkedUniform) - { - linkedUniform = new gl::LinkedUniform(uniform.type, uniform.precision, fullName, uniform.arraySize, - -1, sh::BlockMemberInfo::getDefaultBlockInfo()); - ASSERT(linkedUniform); - linkedUniform->registerElement = sh::HLSLBlockEncoder::getBlockRegisterElement(blockInfo); - mUniforms.push_back(linkedUniform); - } + if (uniformMapEntry != uniformMap->end()) + { + d3dUniform = uniformMapEntry->second; + } + else + { + d3dUniform = new D3DUniform(uniform.type, fullName, uniform.arraySize, true); + (*uniformMap)[fullName] = d3dUniform; + } - if (shader->getShaderType() == GL_FRAGMENT_SHADER) + if (encoder) + { + d3dUniform->registerElement = + static_cast<unsigned int>(sh::HLSLBlockEncoder::getBlockRegisterElement(blockInfo)); + unsigned int reg = + static_cast<unsigned int>(sh::HLSLBlockEncoder::getBlockRegister(blockInfo)); + if (shaderType == GL_FRAGMENT_SHADER) { - linkedUniform->psRegisterIndex = sh::HLSLBlockEncoder::getBlockRegister(blockInfo); + d3dUniform->psRegisterIndex = reg; } - else if (shader->getShaderType() == GL_VERTEX_SHADER) + else { - linkedUniform->vsRegisterIndex = sh::HLSLBlockEncoder::getBlockRegister(blockInfo); + ASSERT(shaderType == GL_VERTEX_SHADER); + d3dUniform->vsRegisterIndex = reg; } - else UNREACHABLE(); // Arrays are treated as aggregate types if (uniform.isArray()) @@ -1469,34 +1932,24 @@ void ProgramD3D::defineUniform(const ShaderD3D *shader, const sh::ShaderVariable } template <typename T> -static inline void SetIfDirty(T *dest, const T& source, bool *dirtyFlag) -{ - ASSERT(dest != NULL); - ASSERT(dirtyFlag != NULL); - - *dirtyFlag = *dirtyFlag || (memcmp(dest, &source, sizeof(T)) != 0); - *dest = source; -} - -template <typename T> -void ProgramD3D::setUniform(GLint location, GLsizei count, const T* v, GLenum targetUniformType) +void ProgramD3D::setUniform(GLint location, GLsizei countIn, const T *v, GLenum targetUniformType) { - const int components = gl::VariableComponentCount(targetUniformType); + const int components = gl::VariableComponentCount(targetUniformType); const GLenum targetBoolType = gl::VariableBoolVectorType(targetUniformType); - gl::LinkedUniform *targetUniform = getUniformByLocation(location); + D3DUniform *targetUniform = getD3DUniformFromLocation(location); - int elementCount = targetUniform->elementCount(); - - count = std::min(elementCount - (int)mUniformIndex[location].element, count); + unsigned int elementCount = targetUniform->elementCount(); + unsigned int arrayElement = mData.getUniformLocations()[location].element; + unsigned int count = std::min(elementCount - arrayElement, static_cast<unsigned int>(countIn)); if (targetUniform->type == targetUniformType) { - T *target = reinterpret_cast<T*>(targetUniform->data) + mUniformIndex[location].element * 4; + T *target = reinterpret_cast<T *>(targetUniform->data) + arrayElement * 4; - for (int i = 0; i < count; i++) + for (unsigned int i = 0; i < count; i++) { - T *dest = target + (i * 4); + T *dest = target + (i * 4); const T *source = v + (i * components); for (int c = 0; c < components; c++) @@ -1511,16 +1964,17 @@ void ProgramD3D::setUniform(GLint location, GLsizei count, const T* v, GLenum ta } else if (targetUniform->type == targetBoolType) { - GLint *boolParams = reinterpret_cast<GLint*>(targetUniform->data) + mUniformIndex[location].element * 4; + GLint *boolParams = reinterpret_cast<GLint *>(targetUniform->data) + arrayElement * 4; - for (int i = 0; i < count; i++) + for (unsigned int i = 0; i < count; i++) { - GLint *dest = boolParams + (i * 4); + GLint *dest = boolParams + (i * 4); const T *source = v + (i * components); for (int c = 0; c < components; c++) { - SetIfDirty(dest + c, (source[c] == static_cast<T>(0)) ? GL_FALSE : GL_TRUE, &targetUniform->dirty); + SetIfDirty(dest + c, (source[c] == static_cast<T>(0)) ? GL_FALSE : GL_TRUE, + &targetUniform->dirty); } for (int c = components; c < 4; c++) { @@ -1528,18 +1982,18 @@ void ProgramD3D::setUniform(GLint location, GLsizei count, const T* v, GLenum ta } } } - else if (gl::IsSamplerType(targetUniform->type)) + else if (targetUniform->isSampler()) { ASSERT(targetUniformType == GL_INT); - GLint *target = reinterpret_cast<GLint*>(targetUniform->data) + mUniformIndex[location].element * 4; + GLint *target = reinterpret_cast<GLint *>(targetUniform->data) + arrayElement * 4; bool wasDirty = targetUniform->dirty; - for (int i = 0; i < count; i++) + for (unsigned int i = 0; i < count; i++) { - GLint *dest = target + (i * 4); - const GLint *source = reinterpret_cast<const GLint*>(v) + (i * components); + GLint *dest = target + (i * 4); + const GLint *source = reinterpret_cast<const GLint *>(v) + (i * components); SetIfDirty(dest + 0, source[0], &targetUniform->dirty); SetIfDirty(dest + 1, 0, &targetUniform->dirty); @@ -1552,404 +2006,142 @@ void ProgramD3D::setUniform(GLint location, GLsizei count, const T* v, GLenum ta mDirtySamplerMapping = true; } } - else UNREACHABLE(); -} - -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); - - for (int x = 0; x < copyWidth; x++) - { - for (int y = 0; y < copyHeight; y++) - { - SetIfDirty(target + (x * targetWidth + y), static_cast<T>(value[y * srcWidth + x]), &dirty); - } - } - // clear unfilled right side - for (int y = 0; y < copyWidth; y++) - { - for (int x = copyHeight; x < targetWidth; x++) - { - SetIfDirty(target + (y * targetWidth + x), static_cast<T>(0), &dirty); - } - } - // clear unfilled bottom. - for (int y = copyWidth; y < targetHeight; y++) - { - for (int x = 0; x < targetWidth; x++) - { - SetIfDirty(target + (y * targetWidth + x), static_cast<T>(0), &dirty); - } - } - - return dirty; -} - -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 y = 0; y < copyHeight; y++) - { - for (int x = 0; x < copyWidth; 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 = copyWidth; x < targetWidth; x++) - { - SetIfDirty(target + (y * targetWidth + x), static_cast<T>(0), &dirty); - } - } - // clear unfilled bottom. - for (int y = copyHeight; y < targetHeight; y++) - { - for (int x = 0; x < targetWidth; x++) - { - SetIfDirty(target + (y * targetWidth + x), static_cast<T>(0), &dirty); - } - } - - return dirty; + else + UNREACHABLE(); } template <int cols, int rows> -void ProgramD3D::setUniformMatrixfv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value, GLenum targetUniformType) +void ProgramD3D::setUniformMatrixfv(GLint location, + GLsizei countIn, + GLboolean transpose, + const GLfloat *value, + GLenum targetUniformType) { - gl::LinkedUniform *targetUniform = getUniformByLocation(location); + D3DUniform *targetUniform = getD3DUniformFromLocation(location); - int elementCount = targetUniform->elementCount(); + unsigned int elementCount = targetUniform->elementCount(); + unsigned int arrayElement = mData.getUniformLocations()[location].element; + unsigned int count = std::min(elementCount - arrayElement, static_cast<unsigned int>(countIn)); - count = std::min(elementCount - (int)mUniformIndex[location].element, count); const unsigned int targetMatrixStride = (4 * rows); - GLfloat *target = (GLfloat*)(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * targetMatrixStride); + GLfloat *target = + (GLfloat *)(targetUniform->data + arrayElement * sizeof(GLfloat) * targetMatrixStride); - for (int i = 0; i < count; i++) + for (unsigned int i = 0; i < count; i++) { // 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; + 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; + targetUniform->dirty = + ExpandMatrix<GLfloat>(target, value, 4, rows, cols, rows) || targetUniform->dirty; } target += targetMatrixStride; value += cols * rows; } } -template <typename T> -void ProgramD3D::getUniformv(GLint location, T *params, GLenum uniformType) +size_t ProgramD3D::getUniformBlockInfo(const sh::InterfaceBlock &interfaceBlock) { - gl::LinkedUniform *targetUniform = mUniforms[mUniformIndex[location].index]; + ASSERT(interfaceBlock.staticUse || interfaceBlock.layout != sh::BLOCKLAYOUT_PACKED); - if (gl::IsMatrixType(targetUniform->type)) - { - const int rows = gl::VariableRowCount(targetUniform->type); - const int cols = gl::VariableColumnCount(targetUniform->type); - transposeMatrix(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4 * rows, rows, cols, 4, rows); - } - else if (uniformType == gl::VariableComponentType(targetUniform->type)) + // define member uniforms + sh::Std140BlockEncoder std140Encoder; + sh::HLSLBlockEncoder hlslEncoder(sh::HLSLBlockEncoder::ENCODE_PACKED); + sh::BlockLayoutEncoder *encoder = nullptr; + + if (interfaceBlock.layout == sh::BLOCKLAYOUT_STANDARD) { - unsigned int size = gl::VariableComponentCount(targetUniform->type); - memcpy(params, targetUniform->data + mUniformIndex[location].element * 4 * sizeof(T), - size * sizeof(T)); + encoder = &std140Encoder; } else { - unsigned int size = gl::VariableComponentCount(targetUniform->type); - switch (gl::VariableComponentType(targetUniform->type)) - { - case GL_BOOL: - { - GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4; - - for (unsigned int i = 0; i < size; i++) - { - params[i] = (boolParams[i] == GL_FALSE) ? static_cast<T>(0) : static_cast<T>(1); - } - } - break; - - case GL_FLOAT: - { - GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4; - - for (unsigned int i = 0; i < size; i++) - { - params[i] = static_cast<T>(floatParams[i]); - } - } - break; - - case GL_INT: - { - GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4; - - for (unsigned int i = 0; i < size; i++) - { - params[i] = static_cast<T>(intParams[i]); - } - } - break; + encoder = &hlslEncoder; + } - case GL_UNSIGNED_INT: - { - GLuint *uintParams = (GLuint*)targetUniform->data + mUniformIndex[location].element * 4; + GetUniformBlockInfo(interfaceBlock.fields, interfaceBlock.fieldPrefix(), encoder, + interfaceBlock.isRowMajorLayout, &mBlockInfo); - for (unsigned int i = 0; i < size; i++) - { - params[i] = static_cast<T>(uintParams[i]); - } - } - break; - - default: UNREACHABLE(); - } - } + return encoder->getBlockSize(); } -template <typename VarT> -void ProgramD3D::defineUniformBlockMembers(const std::vector<VarT> &fields, const std::string &prefix, int blockIndex, - sh::BlockLayoutEncoder *encoder, std::vector<unsigned int> *blockUniformIndexes, - bool inRowMajorLayout) +void ProgramD3D::assignAllSamplerRegisters() { - for (unsigned int uniformIndex = 0; uniformIndex < fields.size(); uniformIndex++) + for (const D3DUniform *d3dUniform : mD3DUniforms) { - const VarT &field = fields[uniformIndex]; - const std::string &fieldName = (prefix.empty() ? field.name : prefix + "." + field.name); - - if (field.isStruct()) - { - bool rowMajorLayout = (inRowMajorLayout || IsRowMajorLayout(field)); - - 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, rowMajorLayout); - - encoder->exitAggregateType(); - } - } - else + if (d3dUniform->isSampler()) { - bool isRowMajorMatrix = (gl::IsMatrixType(field.type) && inRowMajorLayout); - - sh::BlockMemberInfo memberInfo = encoder->encodeType(field.type, field.arraySize, isRowMajorMatrix); - - gl::LinkedUniform *newUniform = new gl::LinkedUniform(field.type, field.precision, fieldName, field.arraySize, - blockIndex, memberInfo); - - // add to uniform list, but not index, since uniform block uniforms have no location - blockUniformIndexes->push_back(mUniforms.size()); - mUniforms.push_back(newUniform); + assignSamplerRegisters(d3dUniform); } } } -bool ProgramD3D::defineUniformBlock(gl::InfoLog &infoLog, const gl::Shader &shader, const sh::InterfaceBlock &interfaceBlock, - const gl::Caps &caps) +void ProgramD3D::assignSamplerRegisters(const D3DUniform *d3dUniform) { - const ShaderD3D* shaderD3D = ShaderD3D::makeShaderD3D(shader.getImplementation()); + ASSERT(d3dUniform->isSampler()); + ASSERT(d3dUniform->vsRegisterIndex != GL_INVALID_INDEX || + d3dUniform->psRegisterIndex != GL_INVALID_INDEX); - // create uniform block entries if they do not exist - if (getUniformBlockIndex(interfaceBlock.name) == GL_INVALID_INDEX) + if (d3dUniform->vsRegisterIndex != 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, interfaceBlock.isRowMajorLayout); - - size_t dataSize = encoder->getBlockSize(); - - // create all the uniform blocks - if (interfaceBlock.arraySize > 0) - { - for (unsigned int uniformBlockElement = 0; uniformBlockElement < interfaceBlock.arraySize; uniformBlockElement++) - { - gl::UniformBlock *newUniformBlock = new gl::UniformBlock(interfaceBlock.name, uniformBlockElement, dataSize); - newUniformBlock->memberUniformIndexes = blockUniformIndexes; - mUniformBlocks.push_back(newUniformBlock); - } - } - else - { - gl::UniformBlock *newUniformBlock = new gl::UniformBlock(interfaceBlock.name, GL_INVALID_INDEX, dataSize); - newUniformBlock->memberUniformIndexes = blockUniformIndexes; - mUniformBlocks.push_back(newUniformBlock); - } + AssignSamplers(d3dUniform->vsRegisterIndex, d3dUniform->type, d3dUniform->arraySize, + mSamplersVS, &mUsedVertexSamplerRange); } - if (interfaceBlock.staticUse) + if (d3dUniform->psRegisterIndex != GL_INVALID_INDEX) { - // 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 = shaderD3D->getInterfaceBlockRegister(interfaceBlock.name); - - for (unsigned int uniformBlockElement = 0; uniformBlockElement < elementCount; uniformBlockElement++) - { - gl::UniformBlock *uniformBlock = mUniformBlocks[blockIndex + uniformBlockElement]; - ASSERT(uniformBlock->name == interfaceBlock.name); - - if (!assignUniformBlockRegister(infoLog, uniformBlock, shader.getType(), - interfaceBlockRegister + uniformBlockElement, caps)) - { - return false; - } - } + AssignSamplers(d3dUniform->psRegisterIndex, d3dUniform->type, d3dUniform->arraySize, + mSamplersPS, &mUsedPixelSamplerRange); } - - return true; } -bool ProgramD3D::assignSamplers(unsigned int startSamplerIndex, - GLenum samplerType, - unsigned int samplerCount, - std::vector<Sampler> &outSamplers, - GLuint *outUsedRange) +// static +void ProgramD3D::AssignSamplers(unsigned int startSamplerIndex, + GLenum samplerType, + unsigned int samplerCount, + std::vector<Sampler> &outSamplers, + GLuint *outUsedRange) { unsigned int samplerIndex = startSamplerIndex; do { - if (samplerIndex < outSamplers.size()) - { - Sampler& sampler = outSamplers[samplerIndex]; - sampler.active = true; - sampler.textureType = GetTextureType(samplerType); - sampler.logicalTextureUnit = 0; - *outUsedRange = std::max(samplerIndex + 1, *outUsedRange); - } - else - { - return false; - } - + ASSERT(samplerIndex < outSamplers.size()); + Sampler *sampler = &outSamplers[samplerIndex]; + sampler->active = true; + sampler->textureType = gl::SamplerTypeToTextureType(samplerType); + sampler->logicalTextureUnit = 0; + *outUsedRange = std::max(samplerIndex + 1, *outUsedRange); samplerIndex++; } while (samplerIndex < startSamplerIndex + samplerCount); - - return true; -} - -bool ProgramD3D::indexSamplerUniform(const gl::LinkedUniform &uniform, gl::InfoLog &infoLog, const gl::Caps &caps) -{ - ASSERT(gl::IsSamplerType(uniform.type)); - ASSERT(uniform.vsRegisterIndex != GL_INVALID_INDEX || uniform.psRegisterIndex != GL_INVALID_INDEX); - - if (uniform.vsRegisterIndex != GL_INVALID_INDEX) - { - if (!assignSamplers(uniform.vsRegisterIndex, uniform.type, uniform.arraySize, mSamplersVS, - &mUsedVertexSamplerRange)) - { - infoLog.append("Vertex shader sampler count exceeds the maximum vertex texture units (%d).", - mSamplersVS.size()); - return false; - } - - unsigned int maxVertexVectors = mRenderer->getReservedVertexUniformVectors() + caps.maxVertexUniformVectors; - if (uniform.vsRegisterIndex + uniform.registerCount > maxVertexVectors) - { - infoLog.append("Vertex shader active uniforms exceed GL_MAX_VERTEX_UNIFORM_VECTORS (%u)", - caps.maxVertexUniformVectors); - return false; - } - } - - if (uniform.psRegisterIndex != GL_INVALID_INDEX) - { - if (!assignSamplers(uniform.psRegisterIndex, uniform.type, uniform.arraySize, mSamplersPS, - &mUsedPixelSamplerRange)) - { - infoLog.append("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", - mSamplersPS.size()); - return false; - } - - unsigned int maxFragmentVectors = mRenderer->getReservedFragmentUniformVectors() + caps.maxFragmentUniformVectors; - if (uniform.psRegisterIndex + uniform.registerCount > maxFragmentVectors) - { - infoLog.append("Fragment shader active uniforms exceed GL_MAX_FRAGMENT_UNIFORM_VECTORS (%u)", - caps.maxFragmentUniformVectors); - return false; - } - } - - return true; -} - -bool ProgramD3D::indexUniforms(gl::InfoLog &infoLog, const gl::Caps &caps) -{ - for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++) - { - const gl::LinkedUniform &uniform = *mUniforms[uniformIndex]; - - if (gl::IsSamplerType(uniform.type)) - { - if (!indexSamplerUniform(uniform, infoLog, caps)) - { - return false; - } - } - - for (unsigned int arrayElementIndex = 0; arrayElementIndex < uniform.elementCount(); arrayElementIndex++) - { - mUniformIndex.push_back(gl::VariableLocation(uniform.name, arrayElementIndex, uniformIndex)); - } - } - - return true; } void ProgramD3D::reset() { - ProgramImpl::reset(); - SafeDeleteContainer(mVertexExecutables); SafeDeleteContainer(mPixelExecutables); - SafeDelete(mGeometryExecutable); - mTransformFeedbackBufferMode = GL_NONE; + for (auto &element : mGeometryExecutables) + { + SafeDelete(element); + } mVertexHLSL.clear(); - mVertexWorkarounds.reset(); - mShaderVersion = 100; + mVertexWorkarounds = D3DCompilerWorkarounds(); mPixelHLSL.clear(); - mPixelWorkarounds.reset(); + mPixelWorkarounds = D3DCompilerWorkarounds(); mUsesFragDepth = false; mPixelShaderKey.clear(); mUsesPointSize = false; + mUsesFlatInterpolation = false; + + SafeDeleteContainer(mD3DUniforms); + mD3DUniformBlocks.clear(); SafeDelete(mVertexUniformStorage); SafeDelete(mFragmentUniformStorage); @@ -1958,10 +2150,15 @@ void ProgramD3D::reset() mSamplersVS.clear(); mUsedVertexSamplerRange = 0; - mUsedPixelSamplerRange = 0; - mDirtySamplerMapping = true; + mUsedPixelSamplerRange = 0; + mDirtySamplerMapping = true; + std::fill(mSemanticIndexes, mSemanticIndexes + ArraySize(mSemanticIndexes), -1); std::fill(mAttributesByLayout, mAttributesByLayout + ArraySize(mAttributesByLayout), -1); + + mStreamOutVaryings.clear(); + + mGeometryShaderPreamble.clear(); } unsigned int ProgramD3D::getSerial() const @@ -1974,6 +2171,27 @@ unsigned int ProgramD3D::issueSerial() return mCurrentSerial++; } +void ProgramD3D::initSemanticIndex() +{ + const gl::Shader *vertexShader = mData.getAttachedVertexShader(); + ASSERT(vertexShader != nullptr); + + // Init semantic index + for (const sh::Attribute &attribute : mData.getAttributes()) + { + int attributeIndex = attribute.location; + int index = vertexShader->getSemanticIndex(attribute.name); + int regs = gl::VariableRegisterCount(attribute.type); + + for (int reg = 0; reg < regs; ++reg) + { + mSemanticIndexes[attributeIndex + reg] = index + reg; + } + } + + initAttributesByLayout(); +} + void ProgramD3D::initAttributesByLayout() { for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) @@ -1981,25 +2199,142 @@ void ProgramD3D::initAttributesByLayout() mAttributesByLayout[i] = i; } - std::sort(&mAttributesByLayout[0], &mAttributesByLayout[gl::MAX_VERTEX_ATTRIBS], AttributeSorter(mSemanticIndex)); + std::sort(&mAttributesByLayout[0], &mAttributesByLayout[gl::MAX_VERTEX_ATTRIBS], + AttributeSorter(mSemanticIndexes)); } -void ProgramD3D::sortAttributesByLayout(rx::TranslatedAttribute attributes[gl::MAX_VERTEX_ATTRIBS], - int sortedSemanticIndices[gl::MAX_VERTEX_ATTRIBS]) const +void ProgramD3D::sortAttributesByLayout( + const std::vector<TranslatedAttribute> &unsortedAttributes, + int sortedSemanticIndicesOut[gl::MAX_VERTEX_ATTRIBS], + const rx::TranslatedAttribute *sortedAttributesOut[gl::MAX_VERTEX_ATTRIBS]) const { - rx::TranslatedAttribute oldTranslatedAttributes[gl::MAX_VERTEX_ATTRIBS]; + for (size_t attribIndex = 0; attribIndex < unsortedAttributes.size(); ++attribIndex) + { + int oldIndex = mAttributesByLayout[attribIndex]; + sortedSemanticIndicesOut[attribIndex] = mSemanticIndexes[oldIndex]; + sortedAttributesOut[attribIndex] = &unsortedAttributes[oldIndex]; + } +} - for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) +void ProgramD3D::updateCachedInputLayout(const gl::State &state) +{ + mCachedInputLayout.clear(); + const auto &vertexAttributes = state.getVertexArray()->getVertexAttributes(); + + for (unsigned int attributeIndex : angle::IterateBitSet(mData.getActiveAttribLocationsMask())) { - oldTranslatedAttributes[i] = attributes[i]; + int semanticIndex = mSemanticIndexes[attributeIndex]; + + if (semanticIndex != -1) + { + if (mCachedInputLayout.size() < static_cast<size_t>(semanticIndex + 1)) + { + mCachedInputLayout.resize(semanticIndex + 1, gl::VERTEX_FORMAT_INVALID); + } + mCachedInputLayout[semanticIndex] = + GetVertexFormatType(vertexAttributes[attributeIndex], + state.getVertexAttribCurrentValue(attributeIndex).Type); + } } +} - for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) +void ProgramD3D::gatherTransformFeedbackVaryings(const VaryingPacking &varyingPacking) +{ + const auto &builtins = varyingPacking.builtins(SHADER_VERTEX); + + const std::string &varyingSemantic = + GetVaryingSemantic(mRenderer->getMajorShaderModel(), usesPointSize()); + + // Gather the linked varyings that are used for transform feedback, they should all exist. + mStreamOutVaryings.clear(); + + const auto &tfVaryingNames = mData.getTransformFeedbackVaryingNames(); + for (unsigned int outputSlot = 0; outputSlot < static_cast<unsigned int>(tfVaryingNames.size()); + ++outputSlot) + { + const auto &tfVaryingName = tfVaryingNames[outputSlot]; + if (tfVaryingName == "gl_Position") + { + if (builtins.glPosition.enabled) + { + mStreamOutVaryings.push_back(D3DVarying(builtins.glPosition.semantic, + builtins.glPosition.index, 4, outputSlot)); + } + } + else if (tfVaryingName == "gl_FragCoord") + { + if (builtins.glFragCoord.enabled) + { + mStreamOutVaryings.push_back(D3DVarying(builtins.glFragCoord.semantic, + builtins.glFragCoord.index, 4, outputSlot)); + } + } + else if (tfVaryingName == "gl_PointSize") + { + if (builtins.glPointSize.enabled) + { + mStreamOutVaryings.push_back(D3DVarying("PSIZE", 0, 1, outputSlot)); + } + } + else + { + for (const PackedVaryingRegister ®isterInfo : varyingPacking.getRegisterList()) + { + const auto &varying = *registerInfo.packedVarying->varying; + GLenum transposedType = gl::TransposeMatrixType(varying.type); + int componentCount = gl::VariableColumnCount(transposedType); + ASSERT(!varying.isBuiltIn()); + + // Transform feedback for varying structs is underspecified. + // See Khronos bug 9856. + // TODO(jmadill): Figure out how to be spec-compliant here. + if (registerInfo.packedVarying->isStructField() || varying.isStruct()) + continue; + + // There can be more than one register assigned to a particular varying, and each + // register needs its own stream out entry. + if (tfVaryingName == varying.name) + { + mStreamOutVaryings.push_back(D3DVarying( + varyingSemantic, registerInfo.semanticIndex, componentCount, outputSlot)); + } + } + } + } +} + +D3DUniform *ProgramD3D::getD3DUniformFromLocation(GLint location) +{ + return mD3DUniforms[mData.getUniformLocations()[location].index]; +} + +bool ProgramD3D::getUniformBlockSize(const std::string &blockName, size_t *sizeOut) const +{ + std::string baseName = blockName; + gl::ParseAndStripArrayIndex(&baseName); + + auto sizeIter = mBlockDataSizes.find(baseName); + if (sizeIter == mBlockDataSizes.end()) { - int oldIndex = mAttributesByLayout[i]; - sortedSemanticIndices[i] = mSemanticIndex[oldIndex]; - attributes[i] = oldTranslatedAttributes[oldIndex]; + *sizeOut = 0; + return false; } + + *sizeOut = sizeIter->second; + return true; } +bool ProgramD3D::getUniformBlockMemberInfo(const std::string &memberUniformName, + sh::BlockMemberInfo *memberInfoOut) const +{ + auto infoIter = mBlockInfo.find(memberUniformName); + if (infoIter == mBlockInfo.end()) + { + *memberInfoOut = sh::BlockMemberInfo::getDefaultBlockInfo(); + return false; + } + + *memberInfoOut = infoIter->second; + return true; +} } |