diff --git a/hlslang/GLSLCodeGen/glslOutput.cpp b/hlslang/GLSLCodeGen/glslOutput.cpp index 123db82..9774428 100644 --- a/hlslang/GLSLCodeGen/glslOutput.cpp +++ b/hlslang/GLSLCodeGen/glslOutput.cpp @@ -239,11 +239,13 @@ void TGlslOutputTraverser::outputLineDirective (int line) -TGlslOutputTraverser::TGlslOutputTraverser(TInfoSink& i, std::vector &funcList, std::vector &sList, bool usePrecision) +TGlslOutputTraverser::TGlslOutputTraverser(TInfoSink& i, std::vector &funcList, std::vector &sList, bool usePrecision, bool transposeMatrixSwizzles) : infoSink(i) , generatingCode(true) , functionList(funcList) , structList(sList) +, transposeMatrixSwizzles(transposeMatrixSwizzles) +, swizzleAssignTempCounter(0) , m_UsePrecision(usePrecision) , m_LastLineOutput(-1) { @@ -622,7 +624,7 @@ bool TGlslOutputTraverser::traverseBinary( bool preVisit, TIntermBinary *node, T goit->generatingCode = true; return false; - case EOpMatrixSwizzle: + case EOpMatrixSwizzle: current->beginStatement(); // This presently only works for swizzles as rhs operators goit->visitConstantUnion = TGlslOutputTraverser::traverseImmediateConstant; @@ -636,8 +638,13 @@ bool TGlslOutputTraverser::traverseBinary( bool preVisit, TIntermBinary *node, T for (int ii = 0; ii < (int)goit->indexList.size(); ii++) { int val = goit->indexList[ii]; - collumn[ii] = val/4; - row[ii] = val%4; + if (goit->transposeMatrixSwizzles) { + collumn[ii] = val%4; + row[ii] = val/4; + } else { + collumn[ii] = val/4; + row[ii] = val%4; + } } bool sameCollumn = true; for (int ii = 1; ii < (int)goit->indexList.size(); ii++) @@ -662,7 +669,7 @@ bool TGlslOutputTraverser::traverseBinary( bool preVisit, TIntermBinary *node, T // Might need to account for different types here assert( (int)goit->indexList.size() != 1); //should have hit same collumn case - out << "vec" << (int)goit->indexList.size() << "( "; + out << "vec" << (int)goit->indexList.size() << "("; const char fields[] = "xyzw"; if (node->getLeft()) node->getLeft()->traverse(goit); @@ -736,6 +743,50 @@ bool TGlslOutputTraverser::traverseBinary( bool preVisit, TIntermBinary *node, T if (infix) { + // special case for swizzled matrix assignment + if (node->getLeft() && node->getRight()) { + TIntermBinary* lval = node->getLeft()->getAsBinaryNode(); + + if (lval && lval->getOp() == EOpMatrixSwizzle) { + static const char* vec_swizzles = "xyzw"; + TIntermTyped* rval = node->getRight(); + TIntermTyped* lexp = lval->getLeft(); + + goit->visitConstantUnion = TGlslOutputTraverser::traverseImmediateConstant; + goit->generatingCode = false; + + lval->getRight()->traverse(goit); + + goit->visitConstantUnion = TGlslOutputTraverser::traverseConstantUnion; + goit->generatingCode = true; + + std::vector swizzles = goit->indexList; + goit->indexList.clear(); + + char temp_rval[128]; + snprintf(temp_rval, 128, "xlat_swiztemp%d", goit->swizzleAssignTempCounter++); + unsigned n_swizzles = swizzles.size(); + current->beginStatement(); + out << "vec" << n_swizzles << " " << temp_rval << " = "; + + rval->traverse(goit); + current->endStatement(); + + for (unsigned i = 0; i != n_swizzles; ++i) { + unsigned a = swizzles[i] / 4, b = swizzles[i] % 4; + unsigned col = goit->transposeMatrixSwizzles ? a : b; + unsigned row = goit->transposeMatrixSwizzles ? b : a; + + current->beginStatement(); + lexp->traverse(goit); + out << "[" << row << "][" << col << "] = " << temp_rval << "." << vec_swizzles[i]; + current->endStatement(); + } + + return false; + } + } + if (needsParens) out << '('; @@ -751,7 +802,7 @@ bool TGlslOutputTraverser::traverseBinary( bool preVisit, TIntermBinary *node, T else { if (assign) - { + { // Need to traverse the left child twice to allow for the assign and the op // This is OK, because we know it is an lvalue if (node->getLeft()) diff --git a/hlslang/GLSLCodeGen/glslOutput.h b/hlslang/GLSLCodeGen/glslOutput.h index 14ebac6..733cdbc 100644 --- a/hlslang/GLSLCodeGen/glslOutput.h +++ b/hlslang/GLSLCodeGen/glslOutput.h @@ -32,7 +32,7 @@ private: void outputLineDirective (int line); public: - TGlslOutputTraverser (TInfoSink& i, std::vector &funcList, std::vector &sList, bool usePrecision); + TGlslOutputTraverser (TInfoSink& i, std::vector &funcList, std::vector &sList, bool usePrecision, bool transposeMatrixSwizzles); GlslStruct *createStructFromType( TType *type ); bool parseInitializer( TIntermBinary *node ); @@ -59,7 +59,9 @@ public: // Persistent data for collecting indices std::vector indexList; - + + bool transposeMatrixSwizzles; + unsigned swizzleAssignTempCounter; bool m_UsePrecision; int m_LastLineOutput; }; diff --git a/hlslang/GLSLCodeGen/hlslCrossCompiler.cpp b/hlslang/GLSLCodeGen/hlslCrossCompiler.cpp index 4a07e70..c4275b7 100644 --- a/hlslang/GLSLCodeGen/hlslCrossCompiler.cpp +++ b/hlslang/GLSLCodeGen/hlslCrossCompiler.cpp @@ -40,9 +40,9 @@ void HlslCrossCompiler::TransformAST (TIntermNode *root) PropagateMutableUniforms (root, infoSink); } -void HlslCrossCompiler::ProduceGLSL (TIntermNode *root, bool usePrecision) +void HlslCrossCompiler::ProduceGLSL (TIntermNode *root, bool usePrecision, bool transposeMatSwizzles) { m_GlslProduced = true; - TGlslOutputTraverser glslTraverse (infoSink, functionList, structList, usePrecision); + TGlslOutputTraverser glslTraverse (infoSink, functionList, structList, usePrecision, transposeMatSwizzles); root->traverse(&glslTraverse); } diff --git a/hlslang/GLSLCodeGen/hlslCrossCompiler.h b/hlslang/GLSLCodeGen/hlslCrossCompiler.h index 83c8e47..d36714e 100644 --- a/hlslang/GLSLCodeGen/hlslCrossCompiler.h +++ b/hlslang/GLSLCodeGen/hlslCrossCompiler.h @@ -24,7 +24,7 @@ public: TInfoSink& getInfoSink() { return infoSink; } void TransformAST (TIntermNode* root); - void ProduceGLSL (TIntermNode* root, bool usePrecision); + void ProduceGLSL (TIntermNode* root, bool usePrecision, bool transposeMatSwizzles); bool IsASTTransformed() const { return m_ASTTransformed; } bool IsGlslProduced() const { return m_GlslProduced; } diff --git a/hlslang/MachineIndependent/HLSL2GLSL.cpp b/hlslang/MachineIndependent/HLSL2GLSL.cpp index 218b11e..27c3e93 100644 --- a/hlslang/MachineIndependent/HLSL2GLSL.cpp +++ b/hlslang/MachineIndependent/HLSL2GLSL.cpp @@ -267,7 +267,7 @@ int C_DECL Hlsl2Glsl_Parse( const ShHandle handle, intermediate.outputTree(parseContext.treeRoot); compiler->TransformAST (parseContext.treeRoot); - compiler->ProduceGLSL (parseContext.treeRoot, (options & ETranslateOpUsePrecision) ? true : false); + compiler->ProduceGLSL (parseContext.treeRoot, (options & ETranslateOpUsePrecision) ? true : false, (options & ETranslateOpTransposeMatrixSwizzles) ? true : false); } else if (!success) { diff --git a/include/hlsl2glsl.h b/include/hlsl2glsl.h index 9631a78..ba104eb 100644 --- a/include/hlsl2glsl.h +++ b/include/hlsl2glsl.h @@ -121,6 +121,7 @@ enum TTranslateOptions ETranslateOpNone = 0, ETranslateOpIntermediate = (1<<0), ETranslateOpUsePrecision = (1<<1), + ETranslateOpTransposeMatrixSwizzles = (1<<2), }; diff --git a/tests/combined/index-matrix-assignment-fragment-out.txt b/tests/combined/index-matrix-assignment-fragment-out.txt new file mode 100644 index 0000000..6294bd4 --- /dev/null +++ b/tests/combined/index-matrix-assignment-fragment-out.txt @@ -0,0 +1,29 @@ + +#line 12 +struct PS_INPUT { + vec4 position; + vec2 uv; +}; +#line 7 +struct VS_INPUT { + vec4 position; + vec2 uv; +}; +uniform sampler2D diffuse_map; +vec4 ps_main( in PS_INPUT xlat_var_input ); +#line 29 +vec4 ps_main( in PS_INPUT xlat_var_input ) { + vec4 c = vec4(1.00000, 1.00000, 1.00000, 1.00000); + #line 30 + c = texture2D( diffuse_map, xlat_var_input.uv); + return c; +} +varying vec2 xlv_TEXCOORD0; +void main() { + vec4 xl_retval; + PS_INPUT xlt_xlat_var_input; + xlt_xlat_var_input.position = vec4(0.0); + xlt_xlat_var_input.uv = vec2( xlv_TEXCOORD0); + xl_retval = ps_main( xlt_xlat_var_input); + gl_FragData[0] = vec4( xl_retval); +} diff --git a/tests/combined/index-matrix-assignment-fragment-outES.txt b/tests/combined/index-matrix-assignment-fragment-outES.txt new file mode 100644 index 0000000..9c61c7a --- /dev/null +++ b/tests/combined/index-matrix-assignment-fragment-outES.txt @@ -0,0 +1,29 @@ + +#line 12 +struct PS_INPUT { + highp vec4 position; + highp vec2 uv; +}; +#line 7 +struct VS_INPUT { + highp vec4 position; + highp vec2 uv; +}; +uniform sampler2D diffuse_map; +mediump vec4 ps_main( in PS_INPUT xlat_var_input ); +#line 29 +mediump vec4 ps_main( in PS_INPUT xlat_var_input ) { + mediump vec4 c = vec4(1.00000, 1.00000, 1.00000, 1.00000); + #line 30 + c = texture2D( diffuse_map, xlat_var_input.uv); + return c; +} +varying highp vec2 xlv_TEXCOORD0; +void main() { + mediump vec4 xl_retval; + PS_INPUT xlt_xlat_var_input; + xlt_xlat_var_input.position = vec4(0.0); + xlt_xlat_var_input.uv = vec2( xlv_TEXCOORD0); + xl_retval = ps_main( xlt_xlat_var_input); + gl_FragData[0] = vec4( xl_retval); +} diff --git a/tests/combined/index-matrix-assignment-in.txt b/tests/combined/index-matrix-assignment-in.txt new file mode 100644 index 0000000..7d9b394 --- /dev/null +++ b/tests/combined/index-matrix-assignment-in.txt @@ -0,0 +1,33 @@ +float4x4 world; +float4x4 view; +float4x4 proj; + +sampler2D diffuse_map; + +struct VS_INPUT { + float4 position : POSITION; + float2 uv : TEXCOORD0; +}; + +struct PS_INPUT { + float4 position : POSITION; + float2 uv : TEXCOORD0; +}; + +PS_INPUT vs_main(VS_INPUT input) { + PS_INPUT o; + float4 wp = mul(input.position, world); + + view._m30_m31_m32 = world._m30_m31_m32; + + o.position = mul(mul(wp, view), proj); + o.uv = input.uv; + + return o; +} + +half4 ps_main(PS_INPUT input) : COLOR0 { + half4 c = half4(1, 1, 1, 1); + c = tex2D(diffuse_map, input.uv); + return c; +} diff --git a/tests/combined/index-matrix-assignment-vertex-out.txt b/tests/combined/index-matrix-assignment-vertex-out.txt new file mode 100644 index 0000000..960dc73 --- /dev/null +++ b/tests/combined/index-matrix-assignment-vertex-out.txt @@ -0,0 +1,42 @@ + +#line 12 +struct PS_INPUT { + vec4 position; + vec2 uv; +}; +#line 7 +struct VS_INPUT { + vec4 position; + vec2 uv; +}; +uniform mat4 proj; +uniform mat4 world; +uniform mat4 view; +mat4 xlat_mutable_view; +PS_INPUT vs_main( in VS_INPUT xlat_var_input ); +#line 17 +PS_INPUT vs_main( in VS_INPUT xlat_var_input ) { + vec4 wp; + PS_INPUT o; + wp = (xlat_var_input.position * world); + #line 21 + vec3 xlat_swiztemp0 = world[3].xyz; + xlat_mutable_view[3][0] = xlat_swiztemp0.x; + xlat_mutable_view[3][1] = xlat_swiztemp0.y; + xlat_mutable_view[3][2] = xlat_swiztemp0.z; + o.position = ((wp * xlat_mutable_view) * proj); + o.uv = xlat_var_input.uv; + #line 26 + return o; +} +varying vec2 xlv_TEXCOORD0; +void main() { + PS_INPUT xl_retval; + xlat_mutable_view = view; + VS_INPUT xlt_xlat_var_input; + xlt_xlat_var_input.position = vec4( gl_Vertex); + xlt_xlat_var_input.uv = vec2( gl_MultiTexCoord0); + xl_retval = vs_main( xlt_xlat_var_input); + gl_Position = vec4( xl_retval.position); + xlv_TEXCOORD0 = vec2( xl_retval.uv); +} diff --git a/tests/combined/index-matrix-assignment-vertex-outES.txt b/tests/combined/index-matrix-assignment-vertex-outES.txt new file mode 100644 index 0000000..54e6dd4 --- /dev/null +++ b/tests/combined/index-matrix-assignment-vertex-outES.txt @@ -0,0 +1,42 @@ + +#line 12 +struct PS_INPUT { + highp vec4 position; + highp vec2 uv; +}; +#line 7 +struct VS_INPUT { + highp vec4 position; + highp vec2 uv; +}; +uniform highp mat4 proj; +uniform highp mat4 world; +uniform highp mat4 view; +highp mat4 xlat_mutable_view; +PS_INPUT vs_main( in VS_INPUT xlat_var_input ); +#line 17 +PS_INPUT vs_main( in VS_INPUT xlat_var_input ) { + highp vec4 wp; + PS_INPUT o; + wp = (xlat_var_input.position * world); + #line 21 + vec3 xlat_swiztemp0 = world[3].xyz; + xlat_mutable_view[3][0] = xlat_swiztemp0.x; + xlat_mutable_view[3][1] = xlat_swiztemp0.y; + xlat_mutable_view[3][2] = xlat_swiztemp0.z; + o.position = ((wp * xlat_mutable_view) * proj); + o.uv = xlat_var_input.uv; + #line 26 + return o; +} +varying highp vec2 xlv_TEXCOORD0; +void main() { + PS_INPUT xl_retval; + xlat_mutable_view = view; + VS_INPUT xlt_xlat_var_input; + xlt_xlat_var_input.position = vec4( gl_Vertex); + xlt_xlat_var_input.uv = vec2( gl_MultiTexCoord0); + xl_retval = vs_main( xlt_xlat_var_input); + gl_Position = vec4( xl_retval.position); + xlv_TEXCOORD0 = vec2( xl_retval.uv); +} diff --git a/tests/hlsl2glsltest/hlsl2glsltest.cpp b/tests/hlsl2glsltest/hlsl2glsltest.cpp index 53ffac0..f13927b 100644 --- a/tests/hlsl2glsltest/hlsl2glsltest.cpp +++ b/tests/hlsl2glsltest/hlsl2glsltest.cpp @@ -212,11 +212,13 @@ static bool CheckGLSL (bool vertex, const char* source) return res; } -static bool TestFile (bool vertex, - const std::string& inputPath, - const std::string& outputPath, - bool usePrecision, - bool doCheckGLSL) +enum TestRun { VERTEX, FRAGMENT, BOTH, NUM_RUN_TYPES }; +static bool TestFile (TestRun type, + const std::string& inputPath, + const std::string& outputPath, + const char* entryPoint, + bool usePrecision, + bool doCheckGLSL) { std::string input; if (!ReadStringFromFile (inputPath.c_str(), input)) @@ -224,8 +226,9 @@ static bool TestFile (bool vertex, printf (" failed to read input file\n"); return false; } - - ShHandle parser = Hlsl2Glsl_ConstructCompiler (vertex ? EShLangVertex : EShLangFragment); + + static const EShLanguage langs[] = {EShLangVertex, EShLangFragment}; + ShHandle parser = Hlsl2Glsl_ConstructCompiler (langs[type]); const char* sourceStr = input.c_str(); @@ -255,12 +258,13 @@ static bool TestFile (bool vertex, }; Hlsl2Glsl_SetUserAttributeNames (parser, kAttribSemantic, kAttribString, 1); Hlsl2Glsl_UseUserVaryings (parser, true); - int translateOk = Hlsl2Glsl_Translate (parser, "main", options); + + int translateOk = Hlsl2Glsl_Translate (parser, entryPoint, options); const char* infoLog = Hlsl2Glsl_GetInfoLog( parser ); if (translateOk) { std::string text = Hlsl2Glsl_GetShader (parser); - + std::string output; ReadStringFromFile (outputPath.c_str(), output); @@ -273,7 +277,7 @@ static bool TestFile (bool vertex, printf (" does not match expected output\n"); res = false; } - if (doCheckGLSL && !CheckGLSL (vertex, text.c_str())) + if (doCheckGLSL && !CheckGLSL (type == VERTEX, text.c_str())) { res = false; } @@ -295,6 +299,39 @@ static bool TestFile (bool vertex, return res; } +static bool TestCombinedFile(const std::string& inputPath, + bool usePrecision, + bool checkGL) +{ + std::string outname = inputPath.substr (0,inputPath.size()-7); + std::string frag_out, vert_out; + + if (usePrecision) { + vert_out = outname + "-vertex-outES.txt"; + frag_out = outname + "-fragment-outES.txt"; + } else { + vert_out = outname + "-vertex-out.txt"; + frag_out = outname + "-fragment-out.txt"; + } + + bool res = TestFile(VERTEX, inputPath, vert_out, "vs_main", usePrecision, !usePrecision && checkGL); + return res & TestFile(FRAGMENT, inputPath, frag_out, "ps_main", usePrecision, !usePrecision && checkGL); +} + +static bool TestFile (TestRun type, + const std::string& inputPath, + bool usePrecision, + bool checkGL) +{ + std::string outname = inputPath.substr (0,inputPath.size()-7); + + if (usePrecision) { + return TestFile(type, inputPath, outname + "-outES.txt", "main", true, false); + } else { + return TestFile(type, inputPath, outname + "-out.txt", "main", false, checkGL); + } +} + int main (int argc, const char** argv) { @@ -312,10 +349,10 @@ int main (int argc, const char** argv) std::string baseFolder = argv[1]; - static const char* kTypeName[2] = { "vertex", "fragment" }; + static const char* kTypeName[NUM_RUN_TYPES] = { "vertex", "fragment", "combined" }; size_t tests = 0; size_t errors = 0; - for (int type = 0; type < 2; ++type) + for (int type = 0; type < NUM_RUN_TYPES; ++type) { printf ("testing %s...\n", kTypeName[type]); std::string testFolder = baseFolder + "/" + kTypeName[type]; @@ -326,26 +363,22 @@ int main (int argc, const char** argv) for (size_t i = 0; i < n; ++i) { std::string inname = inputFiles[i]; + bool ok = true; + printf ("test %s\n", inname.c_str()); - std::string outname = inname.substr (0,inname.size()-7) + "-out.txt"; - std::string outnameES = inname.substr (0,inname.size()-7) + "-outES.txt"; - bool ok = TestFile (type==0, - testFolder + "/" + inname, - testFolder + "/" + outname, - false, - hasOpenGL); - if (ok) - { - ok = TestFile (type==0, - testFolder + "/" + inname, - testFolder + "/" + outnameES, - true, - false); + + if (type == BOTH) { + ok = TestCombinedFile(testFolder + "/" + inname, false, hasOpenGL); + if (ok) + ok = TestCombinedFile(testFolder + "/" + inname, true, false); + } else { + ok = TestFile(TestRun(type), testFolder + "/" + inname, false, hasOpenGL); + if (ok) + ok = TestFile(TestRun(type), testFolder + "/" + inname, true, false); } + if (!ok) - { ++errors; - } } } clock_t time1 = clock();