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)) )); }
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)); }