ptr<ShaderSource> GlslGeneratorInstance::Generate() { // first stage: register all nodes RegisterNode(rootNode); // заголовок файла switch(glslVersion) { case GlslVersions::opengl33: text << "#version 330\n"; break; case GlslVersions::webgl: // version numbers in WebGL are not supported text << "#extension GL_OES_standard_derivatives : enable\n" "#extension GL_EXT_draw_buffers : enable\n" "#ifdef GL_ES\n" "precision highp float;\n" "#endif\n"; break; default: THROW("Unknown GLSL version"); } // вывести атрибуты в качестве входных переменных, если это вершинный шейдер if(shaderType == ShaderTypes::vertex) { const char* prefixStr; switch(glslVersion) { case GlslVersions::opengl33: prefixStr = "in "; break; case GlslVersions::webgl: prefixStr = "attribute "; break; default: THROW("Unknown GLSL version"); } std::sort(attributes.begin(), attributes.end()); for(size_t i = 0; i < attributes.size(); ++i) { AttributeNode* node = attributes[i]; text << prefixStr; DataType valueType = node->GetValueType(); // hack for lack of supporting integer attributes in WebGL // change them to float if(glslVersion == GlslVersions::webgl) valueType = EnforceFloatDataType(valueType); PrintDataType(valueType); text << " a" << node->GetElementIndex() << ";\n"; } } // print transformed nodes if(!transformedNodes.empty()) { if(shaderType != ShaderTypes::pixel) THROW("Only pixel shader may have transformed nodes"); const char* prefixStr; switch(glslVersion) { case GlslVersions::opengl33: prefixStr = "in "; break; case GlslVersions::webgl: prefixStr = "varying "; break; default: THROW("Unknown GLSL version"); } for(size_t i = 0; i < transformedNodes.size(); ++i) { TransformedNode* node = transformedNodes[i]; text << prefixStr; PrintDataType(node->GetValueType()); text << " v" << node->GetSemantic() << ";\n"; } } // print interpolate nodes if(!interpolateNodes.empty()) { if(shaderType != ShaderTypes::vertex) THROW("Only vertex shader may have interpolate nodes"); const char* prefixStr; switch(glslVersion) { case GlslVersions::opengl33: prefixStr = "out "; break; case GlslVersions::webgl: prefixStr = "varying "; break; default: THROW("Unknown GLSL version"); } for(size_t i = 0; i < interpolateNodes.size(); ++i) { InterpolateNode* node = interpolateNodes[i]; text << prefixStr; PrintDataType(node->GetValueType()); text << " v" << node->GetSemantic() << ";\n"; } } // вывести пиксельные переменные, если это пиксельный шейдер, и это нужно if(shaderType == ShaderTypes::pixel && glslVersion == GlslVersions::opengl33) { for(int i = 0; i < fragmentTargetsCount; ++i) { text << "out "; PrintDataType(DataTypes::_vec4); text << " r" << i << ";\n"; } } // print uniforms PrintUniforms(); // samplers for(size_t i = 0; i < samplers.size(); ++i) { SamplerNode* samplerNode = samplers[i]; // строка, описывающая основной тип семпла const char* valueTypeStr; switch(samplerNode->GetValueType()) { case DataTypes::_float: case DataTypes::_vec2: case DataTypes::_vec3: case DataTypes::_vec4: valueTypeStr = ""; break; case DataTypes::_uint: case DataTypes::_uvec2: case DataTypes::_uvec3: case DataTypes::_uvec4: valueTypeStr = glslVersion == GlslVersions::webgl ? "i" : "u"; break; case DataTypes::_int: case DataTypes::_ivec2: case DataTypes::_ivec3: case DataTypes::_ivec4: valueTypeStr = "i"; break; default: THROW("Invalid sampler value type"); } // строка, описывающая размерность const char* dimensionStr; switch(samplerNode->GetCoordType()) { case SamplerNode::_1D: dimensionStr = "1D"; break; case SamplerNode::_2D: dimensionStr = "2D"; break; case SamplerNode::_3D: dimensionStr = "3D"; break; case SamplerNode::_Cube: dimensionStr = "Cube"; break; default: THROW("Invalid sampler coord type"); } // вывести семплер int slot = samplerNode->GetSlot(); text << "uniform " << valueTypeStr << "sampler" << dimensionStr << ' ' << samplerPrefix << slot << ";\n"; } //** заголовок функции шейдера text << "void main()\n{\n"; // shader code for(size_t i = 0; i < nodeInits.size(); ++i) PrintNodeInit(i); // завершение шейдера text << "}\n"; // make list of uniform variable bindings GlShaderBindings::UniformBindings uniformBindings; if(!supportUniformBuffers) { uniformBindings.resize(uniforms.size()); for(size_t i = 0; i < uniforms.size(); ++i) { UniformNode* node = uniforms[i].second; GlShaderBindings::UniformBinding& uniformBinding = uniformBindings[i]; uniformBinding.dataType = node->GetValueType(); uniformBinding.count = node->GetCount(); uniformBinding.slot = uniforms[i].first->GetSlot(); uniformBinding.offset = node->GetOffset(); std::ostringstream ss; ss << uniformPrefix << uniformBinding.slot << '_' << uniformBinding.offset; uniformBinding.name = ss.str(); } } // make list of uniform block bindings GlShaderBindings::Bindings uniformBlockBindings; if(supportUniformBuffers) { uniformBlockBindings.resize(uniforms.size()); for(size_t i = 0; i < uniforms.size(); ++i) { int slot = uniforms[i].first->GetSlot(); char name[16]; sprintf(name, "%s%d", uniformBufferPrefix, slot); uniformBlockBindings[i].first = name; uniformBlockBindings[i].second = slot; } // remove duplicates std::sort(uniformBlockBindings.begin(), uniformBlockBindings.end()); uniformBlockBindings.resize(std::unique(uniformBlockBindings.begin(), uniformBlockBindings.end()) - uniformBlockBindings.begin()); } // сформировать список привязок семплеров GlShaderBindings::Bindings samplerBindings(samplers.size()); for(size_t i = 0; i < samplers.size(); ++i) { int slot = samplers[i]->GetSlot(); char name[16]; sprintf(name, "%s%d", samplerPrefix, slot); samplerBindings[i].first = name; samplerBindings[i].second = slot; } // сформировать список привязок атрибутов GlShaderBindings::Bindings attributeBindings(attributes.size()); for(size_t i = 0; i < attributes.size(); ++i) { int index = attributes[i]->GetElementIndex(); char name[16]; sprintf(name, "a%d", index); attributeBindings[i].first = name; attributeBindings[i].second = index; } // make a target variables list GlShaderBindings::Bindings targetBindings; switch(glslVersion) { case GlslVersions::opengl33: targetBindings.resize(fragmentTargetsCount); for(int i = 0; i < fragmentTargetsCount; ++i) { char name[16]; sprintf(name, "r%d", i); targetBindings[i].first = name; targetBindings[i].second = i; } break; case GlslVersions::webgl: // no bindings needed, because of use of gl_FragColor/gl_FragData break; } return NEW(GlslSource( Strings::String2File(text.str()), NEW(GlShaderBindings(uniformBindings, uniformBlockBindings, samplerBindings, attributeBindings, targetBindings, dualFragmentTarget)) )); }
void GlslGeneratorInstance::PrintNodeInit(size_t nodeIndex) { Node* node = nodeInits[nodeIndex]; switch(node->GetType()) { case Node::typeFloatConst: PrintNodeInitBegin(nodeIndex); text << std::fixed << std::setprecision(10) << fast_cast<FloatConstNode*>(node)->GetValue();// << 'f'; PrintNodeInitEnd(); break; case Node::typeIntConst: PrintNodeInitBegin(nodeIndex); text << fast_cast<IntConstNode*>(node)->GetValue(); PrintNodeInitEnd(); break; case Node::typeAttribute: { AttributeNode* attributeNode = fast_cast<AttributeNode*>(node); PrintNodeInitBegin(nodeIndex); // WebGL hack for integer attributes // (only for case of using another hack - changing integer attributes to float) bool intConversion = false; if(glslVersion == GlslVersions::webgl) intConversion = PrintWebGLConversionToIntegerBegin(attributeNode->GetValueType()); text << "a" << attributeNode->GetElementIndex(); if(intConversion) PrintWebGLConversionToIntegerEnd(); PrintNodeInitEnd(); } break; case Node::typeUniform: // uniform doesn't have initialization break; case Node::typeSampler: // sampler doesn't have initialization break; case Node::typeReadUniform: { PrintNodeInitBegin(nodeIndex); ReadUniformNode* readUniformNode = fast_cast<ReadUniformNode*>(node); PrintUniform(readUniformNode->GetUniformNode()); PrintNodeInitEnd(); } break; case Node::typeIndexUniformArray: { PrintNodeInitBegin(nodeIndex); IndexUniformArrayNode* indexUniformArrayNode = fast_cast<IndexUniformArrayNode*>(node); PrintUniform(indexUniformArrayNode->GetUniformNode()); text << '['; PrintNode(indexUniformArrayNode->GetIndexNode()); text << ']'; PrintNodeInitEnd(); } break; case Node::typeTransformed: PrintNodeInitBegin(nodeIndex); text << "v" << fast_cast<TransformedNode*>(node)->GetSemantic(); PrintNodeInitEnd(); break; case Node::typeInterpolate: { InterpolateNode* interpolateNode = fast_cast<InterpolateNode*>(node); text << "\tv" << interpolateNode->GetSemantic() << " = "; PrintNode(interpolateNode->GetNode()); PrintNodeInitEnd(); } break; case Node::typeSequence: // sequence node doesn't have initialization break; case Node::typeSwizzle: { PrintNodeInitBegin(nodeIndex); SwizzleNode* swizzleNode = fast_cast<SwizzleNode*>(node); PrintNode(swizzleNode->GetA()); text << '.' << swizzleNode->GetMap(); PrintNodeInitEnd(); } break; case Node::typeOperation: PrintNodeInitBegin(nodeIndex); PrintOperationNodeInit(fast_cast<OperationNode*>(node)); PrintNodeInitEnd(); break; case Node::typeAction: PrintActionNodeInit(fast_cast<ActionNode*>(node)); break; case Node::typeSample: { PrintNodeInitBegin(nodeIndex); SampleNode* sampleNode = fast_cast<SampleNode*>(node); int slot = sampleNode->GetSamplerNode()->GetSlot(); ValueNode* coordsNode = sampleNode->GetCoordsNode(); ValueNode* offsetNode = sampleNode->GetOffsetNode(); ValueNode* lodNode = sampleNode->GetLodNode(); ValueNode* biasNode = sampleNode->GetBiasNode(); ValueNode* gradXNode = sampleNode->GetGradXNode(); ValueNode* gradYNode = sampleNode->GetGradYNode(); auto printOffsetNode = [&]() { // offset node is required to be constant expression, // but AMD driver requires it also to be compile-time expression // so HACK: print value inline, only for known node // PrintNode(offsetNode); if(offsetNode->GetType() != Node::typeOperation) THROW("wrong offset node"); OperationNode* offsetOperationNode = fast_cast<OperationNode*>(offsetNode); if( offsetOperationNode->GetOperation() != OperationNode::operationInt11to2 || offsetOperationNode->GetA()->GetType() != Node::typeIntConst || offsetOperationNode->GetB()->GetType() != Node::typeIntConst ) THROW("wrong offset node"); text << "ivec2(" << offsetOperationNode->GetA().FastCast<IntConstNode>()->GetValue() << ", " << offsetOperationNode->GetB().FastCast<IntConstNode>()->GetValue() << ")"; }; if(lodNode) { text << "textureLod"; if(offsetNode) text << "Offset"; text << '(' << samplerPrefix << slot << ", "; PrintNode(coordsNode); text << ", "; PrintNode(lodNode); if(offsetNode) { text << ", "; printOffsetNode(); } } else if(biasNode) { text << "texture"; if(offsetNode) text << "Offset"; text << '(' << samplerPrefix << slot << ", "; PrintNode(coordsNode); if(offsetNode) { text << ", "; printOffsetNode(); } text << ", "; PrintNode(biasNode); } else if(gradXNode && gradYNode) { text << "textureGrad"; if(offsetNode) text << "Offset"; text << '(' << samplerPrefix << slot << ", "; PrintNode(coordsNode); text << ", "; PrintNode(gradXNode); text << ", "; PrintNode(gradYNode); if(offsetNode) { text << ", "; printOffsetNode(); } } else { text << (glslVersion == GlslVersions::webgl ? "texture2D" : "texture"); if(offsetNode && glslVersion != GlslVersions::webgl) text << "Offset"; text << '(' << samplerPrefix << slot << ", "; PrintNode(coordsNode); if(offsetNode && glslVersion != GlslVersions::webgl) { text << ", "; printOffsetNode(); } } // close sample call text << ')'; // sample always returns four-component vector, so make some swizzle if needed int valueSize = GetVectorDataTypeDimensions(sampleNode->GetValueType()); if(valueSize < 4) { text << '.'; for(int i = 0; i < valueSize; ++i) text << "xyzw"[i]; } PrintNodeInitEnd(); } break; case Node::typeFragment: { FragmentNode* fragmentNode = fast_cast<FragmentNode*>(node); switch(glslVersion) { case GlslVersions::opengl33: text << "\tr" << fragmentNode->GetTarget(); break; case GlslVersions::webgl: if(fragmentTargetsCount > 1) text << "gl_FragData[" << fragmentNode->GetTarget() << ']'; else text << "gl_FragColor"; break; } text << " = "; PrintNode(fragmentNode->GetNode()); PrintNodeInitEnd(); } break; case Node::typeDualFragment: { DualFragmentNode* dualFragmentNode = fast_cast<DualFragmentNode*>(node); switch(glslVersion) { case GlslVersions::opengl33: text << "\tr0 = "; PrintNode(dualFragmentNode->GetNode0()); PrintNodeInitEnd(); text << "\tr1 = "; PrintNode(dualFragmentNode->GetNode1()); PrintNodeInitEnd(); break; case GlslVersions::webgl: text << "\tgl_FragData[0] = "; PrintNode(dualFragmentNode->GetNode0()); PrintNodeInitEnd(); text << "\tgl_FragData[1] = "; PrintNode(dualFragmentNode->GetNode1()); PrintNodeInitEnd(); break; } } break; case Node::typeCast: { PrintNodeInitBegin(nodeIndex); CastNode* castNode = fast_cast<CastNode*>(node); PrintDataType(castNode->GetValueType()); text << '('; PrintNode(castNode->GetA()); text << ')'; PrintNodeInitEnd(); } break; default: THROW("Unknown node type"); } }
ptr<ShaderSource> Hlsl11GeneratorInstance::Generate() { // first stage: register all nodes RegisterNode(rootNode); // find out if we need instance id for(size_t i = 0; i < nodeInits.size(); ++i) { Node* node = nodeInits[i]; if(node->GetType() == Node::typeOperation) { OperationNode* operationNode = fast_cast<OperationNode*>(node); if(operationNode->GetOperation() == OperationNode::operationGetInstanceID) needInstanceID = true; } } // выборы в зависимости от типа шейдера const char* mainFunctionName; const char* inputTypeName; const char* inputName; const char* outputTypeName; const char* outputName; const char* profile; switch(shaderType) { case ShaderTypes::vertex: mainFunctionName = "VS"; inputTypeName = "A"; inputName = "a"; outputTypeName = "V"; outputName = "v"; profile = "vs_4_0"; break; case ShaderTypes::pixel: mainFunctionName = "PS"; inputTypeName = "V"; inputName = "v"; outputTypeName = "R"; outputName = "r"; profile = "ps_4_0"; break; default: THROW("Unknown shader type"); } // вывести атрибуты, если вершинный шейдер if(shaderType == ShaderTypes::vertex) { text << "struct A\n{\n"; struct IndexSorter { bool operator()(AttributeNode* a, AttributeNode* b) const { return a->GetElementIndex() < b->GetElementIndex(); } }; std::sort(attributes.begin(), attributes.end(), IndexSorter()); for(size_t i = 0; i < attributes.size(); ++i) { AttributeNode* node = attributes[i]; text << '\t'; PrintDataType(node->GetValueType()); int index = node->GetElementIndex(); text << " a" << index << " : " << Dx11System::GetSemanticString(index) << ";\n"; } text << "};\n"; } // print transformed nodes if(shaderType == ShaderTypes::pixel) { text << "struct V\n{\n"; struct SemanticSorter { bool operator()(TransformedNode* a, TransformedNode* b) const { return a->GetSemantic() < b->GetSemantic(); } }; std::sort(transformedNodes.begin(), transformedNodes.end(), SemanticSorter()); for(size_t i = 0; i < transformedNodes.size(); ++i) { TransformedNode* node = transformedNodes[i]; text << '\t'; PrintDataType(node->GetValueType()); int semantic = node->GetSemantic(); text << " v" << semantic << " : " << Dx11System::GetSemanticString(semantic) << ";\n"; } text << "};\n"; } // print interpolate nodes if(shaderType == ShaderTypes::vertex) { text << "struct V\n{\n"; struct SemanticSorter { bool operator()(InterpolateNode* a, InterpolateNode* b) const { return a->GetSemantic() < b->GetSemantic(); } }; std::sort(interpolateNodes.begin(), interpolateNodes.end(), SemanticSorter()); for(size_t i = 0; i < interpolateNodes.size(); ++i) { InterpolateNode* node = interpolateNodes[i]; text << '\t'; PrintDataType(node->GetValueType()); int semantic = node->GetSemantic(); text << " v" << semantic << " : " << Dx11System::GetSemanticString(semantic) << ";\n"; } // вывести SV_Position text << "\tfloat4 vTP : SV_Position;\n"; text << "};\n"; } // вывести пиксельные переменные, если это пиксельный шейдер if(shaderType == ShaderTypes::pixel) { text << "struct R\n{\n"; for(int i = 0; i < fragmentTargetsCount; ++i) { text << '\t'; PrintDataType(DataTypes::_vec4); text << " r" << i << " : SV_Target" << i << ";\n"; } text << "};\n"; } // вывести uniform-буферы PrintUniforms(); // семплеры struct SamplerSlotSorter { bool operator()(SamplerNode* a, SamplerNode* b) const { return a->GetSlot() < b->GetSlot(); } }; std::sort(samplers.begin(), samplers.end(), SamplerSlotSorter()); for(size_t i = 0; i < samplers.size(); ++i) { SamplerNode* samplerNode = samplers[i]; const char* textureStr; switch(samplerNode->GetCoordType()) { case SamplerNode::_1D: textureStr = "Texture1D"; break; case SamplerNode::_2D: textureStr = "Texture2D"; break; case SamplerNode::_3D: textureStr = "Texture3D"; break; case SamplerNode::_Cube: textureStr = "TextureCube"; break; default: THROW("Invalid sampler coord type"); } // текстура text << textureStr << '<'; PrintDataType(samplerNode->GetValueType()); int slot = samplerNode->GetSlot(); text << "> t" << slot << " : register(t" << slot << ");\n"; // семплер text << "SamplerState s" << slot << " : register(s" << slot << ");\n"; } //** заголовок функции шейдера text << outputTypeName << ' ' << mainFunctionName << '(' << inputTypeName << ' ' << inputName; // если шейдер использует instance ID, добавить аргумент if(needInstanceID) text << ", uint sI : SV_InstanceID"; // завершить заголовок text << ")\n{\n\t" << outputTypeName << ' ' << outputName << ";\n"; // shader code for(size_t i = 0; i < nodeInits.size(); ++i) PrintNodeInit(i); // завершение шейдера text << "\treturn " << outputName << ";\n}\n"; // получить маски ресурсов int uniformBuffersMask = 0; for(size_t i = 0; i < uniforms.size(); ++i) uniformBuffersMask |= 1 << uniforms[i].first->GetSlot(); int samplersMask = 0; for(size_t i = 0; i < samplers.size(); ++i) samplersMask |= 1 << samplers[i]->GetSlot(); Dx11ShaderResources resources(uniformBuffersMask, samplersMask); return NEW(Hlsl11Source(Strings::String2File(text.str()), mainFunctionName, profile, resources)); }