std::string DynamicHLSL::generateAttributeConversionHLSL( gl::VertexFormatType vertexFormatType, const sh::ShaderVariable &shaderAttrib) const { const gl::VertexFormat &vertexFormat = gl::GetVertexFormatFromType(vertexFormatType); std::string attribString = "input." + decorateVariable(shaderAttrib.name); // Matrix if (IsMatrixType(shaderAttrib.type)) { return "transpose(" + attribString + ")"; } GLenum shaderComponentType = VariableComponentType(shaderAttrib.type); int shaderComponentCount = VariableComponentCount(shaderAttrib.type); // Perform integer to float conversion (if necessary) bool requiresTypeConversion = (shaderComponentType == GL_FLOAT && vertexFormat.type != GL_FLOAT); if (requiresTypeConversion) { // TODO: normalization for 32-bit integer formats ASSERT(!vertexFormat.normalized && !vertexFormat.pureInteger); return "float" + Str(shaderComponentCount) + "(" + attribString + ")"; } // No conversion necessary return attribString; }
std::string DynamicHLSL::generateVertexShaderForInputLayout( const std::string &sourceShader, const InputLayout &inputLayout, const std::vector<sh::Attribute> &shaderAttributes) const { std::stringstream structStream; std::stringstream initStream; structStream << "struct VS_INPUT\n" << "{\n"; int semanticIndex = 0; unsigned int inputIndex = 0; // If gl_PointSize is used in the shader then pointsprites rendering is expected. // If the renderer does not support Geometry shaders then Instanced PointSprite emulation // must be used. bool usesPointSize = sourceShader.find("GL_USES_POINT_SIZE") != std::string::npos; bool useInstancedPointSpriteEmulation = usesPointSize && mRenderer->getWorkarounds().useInstancedPointSpriteEmulation; // Instanced PointSprite emulation requires additional entries in the // VS_INPUT structure to support the vertices that make up the quad vertices. // These values must be in sync with the cooresponding values added during inputlayout creation // in InputLayoutCache::applyVertexBuffers(). // // The additional entries must appear first in the VS_INPUT layout because // Windows Phone 8 era devices require per vertex data to physically come // before per instance data in the shader. if (useInstancedPointSpriteEmulation) { structStream << " float3 spriteVertexPos : SPRITEPOSITION0;\n" << " float2 spriteTexCoord : SPRITETEXCOORD0;\n"; } for (size_t attributeIndex = 0; attributeIndex < shaderAttributes.size(); ++attributeIndex) { const sh::Attribute &shaderAttribute = shaderAttributes[attributeIndex]; if (!shaderAttribute.name.empty()) { ASSERT(inputIndex < MAX_VERTEX_ATTRIBS); VertexFormatType vertexFormatType = inputIndex < inputLayout.size() ? inputLayout[inputIndex] : VERTEX_FORMAT_INVALID; // HLSL code for input structure if (IsMatrixType(shaderAttribute.type)) { // Matrix types are always transposed structStream << " " << HLSLMatrixTypeString(TransposeMatrixType(shaderAttribute.type)); } else { GLenum componentType = mRenderer->getVertexComponentType(vertexFormatType); if (shaderAttribute.name == "gl_InstanceID" || shaderAttribute.name == "gl_VertexID") { // The input types of the instance ID and vertex ID in HLSL (uint) differs from // the ones in ESSL (int). structStream << " uint"; } else { structStream << " " << HLSLComponentTypeString( componentType, VariableComponentCount(shaderAttribute.type)); } } structStream << " " << decorateVariable(shaderAttribute.name) << " : "; if (shaderAttribute.name == "gl_InstanceID") { structStream << "SV_InstanceID"; } else if (shaderAttribute.name == "gl_VertexID") { structStream << "SV_VertexID"; } else { structStream << "TEXCOORD" << semanticIndex; semanticIndex += VariableRegisterCount(shaderAttribute.type); } structStream << ";\n"; // HLSL code for initialization initStream << " " << decorateVariable(shaderAttribute.name) << " = "; // Mismatched vertex attribute to vertex input may result in an undefined // data reinterpretation (eg for pure integer->float, float->pure integer) // TODO: issue warning with gl debug info extension, when supported if (IsMatrixType(shaderAttribute.type) || (mRenderer->getVertexConversionType(vertexFormatType) & VERTEX_CONVERT_GPU) != 0) { initStream << generateAttributeConversionHLSL(vertexFormatType, shaderAttribute); } else { initStream << "input." << decorateVariable(shaderAttribute.name); } initStream << ";\n"; inputIndex += VariableRowCount(TransposeMatrixType(shaderAttribute.type)); } } structStream << "};\n" "\n" "void initAttributes(VS_INPUT input)\n" "{\n" << initStream.str() << "}\n"; std::string vertexHLSL(sourceShader); size_t copyInsertionPos = vertexHLSL.find(VERTEX_ATTRIBUTE_STUB_STRING); vertexHLSL.replace(copyInsertionPos, VERTEX_ATTRIBUTE_STUB_STRING.length(), structStream.str()); return vertexHLSL; }
int VariableRegisterCount(GLenum type) { return IsMatrixType(type) ? VariableColumnCount(type) : 1; }
int MatrixComponentCount(GLenum type, bool isRowMajorMatrix) { ASSERT(IsMatrixType(type)); return isRowMajorMatrix ? VariableColumnCount(type) : VariableRowCount(type); }