diff --git a/pxr/imaging/hdSt/codeGen.cpp b/pxr/imaging/hdSt/codeGen.cpp index 2f41936567..331964c96b 100644 --- a/pxr/imaging/hdSt/codeGen.cpp +++ b/pxr/imaging/hdSt/codeGen.cpp @@ -166,6 +166,7 @@ HdSt_CodeGen::HdSt_CodeGen( , _hasCS(false) , _hasPTCS(false) , _hasPTVS(false) + , _hasTESWithNoGS(false) , _hasClipPlanes(false) { TF_VERIFY(geometricShader); @@ -187,6 +188,7 @@ HdSt_CodeGen::HdSt_CodeGen( , _hasCS(false) , _hasPTCS(false) , _hasPTVS(false) + , _hasTESWithNoGS(false) , _hasClipPlanes(false) { TF_VERIFY(_metaData, @@ -1902,6 +1904,7 @@ HdSt_CodeGen::Compile(HdStResourceRegistry*const registry) _hasGS = (!geometryShader.empty()) && !metalTessellationEnabled; _hasFS = (!fragmentShader.empty()); _hasCS = (!computeShader.empty()); + _hasTESWithNoGS = _hasTES && !_hasGS; // Initialize source buckets _genDefines.str(""); _genDecl.str(""); _genAccessors.str(""); @@ -2186,13 +2189,14 @@ HdSt_CodeGen::Compile(HdStResourceRegistry*const registry) } } - // We plumb the evaluated position in patch from PTVS to FS since this + // We plumb the evaluated position in patch from PTVS or TES to FS since this // is more consistent than using built-in barycentric coords and can be // used even when builtin barycentric coords are not available. We pass // only the first two components between stages and provide an accessor // which can reconstruct the full three component barycentric form. - if (_hasPTVS) { - _AddInterstageElement(&_resPTVS, + if (_hasPTVS || _hasTESWithNoGS) { + auto& resTess = _hasPTVS ? _resPTVS : _resTES; + _AddInterstageElement(&resTess, HioGlslfxResourceLayout::InOut::STAGE_OUT, /*name=*/_tokens->hd_tessCoord, /*dataType=*/_tokens->vec2); @@ -2326,8 +2330,9 @@ HdSt_CodeGen::Compile(HdStResourceRegistry*const registry) } } - if (_hasPTVS) { - _procPTVSOut << " hd_tessCoord = gl_TessCoord.xy;\n"; + if (_hasPTVS || _hasTESWithNoGS) { + auto& procTess = _hasPTVS ? _procPTVSOut : _procTES; + procTess << " hd_tessCoord = gl_TessCoord.xy;\n"; } if (requiresPrimitiveIdEmulation) { @@ -2375,6 +2380,9 @@ HdSt_CodeGen::Compile(HdStResourceRegistry*const registry) } if (_hasTES) { _genTES << shader->GetSource(HdShaderTokens->tessEvalShader); + if (_hasTESWithNoGS) { + _genTES << shader->GetSource(HdShaderTokens->displacementShader); + } } if (_hasPTCS) { _genPTCS << shader->GetSource( @@ -2690,6 +2698,14 @@ HdSt_CodeGen::_CompileWithGeneratedGLSLResources( resourceGen._GenerateGLSLResources(&desc, resDecl, HdShaderTokens->tessEvalShader, _resTES, _GetMetaData()); + // material in TES + if (_hasTESWithNoGS) { + resourceGen._GenerateGLSLResources(&desc, resDecl, + HdShaderTokens->tessEvalShader, _resMaterial, _GetMetaData()); + resourceGen._GenerateGLSLTextureResources(resDecl, + HdShaderTokens->tessEvalShader, _resTextures, _GetMetaData()); + } + std::string const declarations = _genDefines.str() + _osd.str(); std::string const source = @@ -2901,6 +2917,14 @@ HdSt_CodeGen::_CompileWithGeneratedHgiResources( resourceGen._GenerateHgiResources(registry->GetHgi(), &tesDesc, HdShaderTokens->tessEvalShader, _resTES, _GetMetaData()); + // material in TES + if (_hasTESWithNoGS) { + resourceGen._GenerateHgiResources(registry->GetHgi(), &tesDesc, + HdShaderTokens->tessEvalShader, _resMaterial, _GetMetaData()); + resourceGen._GenerateHgiTextureResources(&tesDesc, + HdShaderTokens->tessEvalShader, _resTextures, _GetMetaData()); + } + std::string const declarations = _genDefines.str() + _genDecl.str() + _osd.str(); std::string const source = _genAccessors.str() + _genTES.str(); @@ -6857,6 +6881,9 @@ HdSt_CodeGen::_GenerateShaderParameters(bool bindlessTextureEnabled) _genGS << accessors.str(); _genFS << accessors.str(); + if (_hasTESWithNoGS) { + _genTES << accessors.str(); + } _genPTCS << accessors.str(); _genPTVS << accessors.str(); } diff --git a/pxr/imaging/hdSt/codeGen.h b/pxr/imaging/hdSt/codeGen.h index fef9b6d2d4..c0d0feeee0 100644 --- a/pxr/imaging/hdSt/codeGen.h +++ b/pxr/imaging/hdSt/codeGen.h @@ -222,6 +222,7 @@ class HdSt_CodeGen bool _hasCS; bool _hasPTCS; bool _hasPTVS; + bool _hasTESWithNoGS; bool _hasClipPlanes; }; diff --git a/pxr/imaging/hdSt/meshShaderKey.cpp b/pxr/imaging/hdSt/meshShaderKey.cpp index 7de6b26a85..692d99cdb7 100644 --- a/pxr/imaging/hdSt/meshShaderKey.cpp +++ b/pxr/imaging/hdSt/meshShaderKey.cpp @@ -93,8 +93,10 @@ TF_DEFINE_PRIVATE_TOKENS( ((mainPatchCommonTCS, "Mesh.TessControl.PatchCommon")) ((mainBSplineQuadTCS, "Mesh.TessControl.BSplineQuad")) ((mainBezierQuadTES, "Mesh.TessEval.BezierQuad")) + ((mainBezierQuadNoGSTES, "Mesh.TessEval.BezierQuadNoGS")) ((mainBoxSplineTriangleTCS, "Mesh.TessControl.BoxSplineTriangle")) ((mainBezierTriangleTES, "Mesh.TessEval.BezierTriangle")) + ((mainBezierTriangleNoGSTES, "Mesh.TessEval.BezierTriangleNoGS")) ((mainVaryingInterpTES, "Mesh.TessEval.VaryingInterpolation")) ((mainTrianglePTVS, "Mesh.PostTessVertex.Triangle")) ((mainQuadPTVS, "Mesh.PostTessVertex.Quad")) @@ -123,6 +125,8 @@ TF_DEFINE_PRIVATE_TOKENS( ((instancing, "Instancing.Transform")) // terminals + ((customDisplacementTES, "TessEval.CustomDisplacement")) + ((noCustomDisplacementTES, "TessEval.NoCustomDisplacement")) ((customDisplacementGS, "Geometry.CustomDisplacement")) ((noCustomDisplacementGS, "Geometry.NoCustomDisplacement")) ((commonFS, "Fragment.CommonTerminals")) @@ -346,28 +350,82 @@ HdSt_MeshShaderKey::HdSt_MeshShaderKey( } bool const ptvsStageEnabled = !PTVS[0].IsEmpty(); + bool finalTesStageEnabled = false; - // tessellation control shader if (isPrimTypePatches && !ptvsStageEnabled) { - TCS[0] = _tokens->instancing; - TCS[1] = _tokens->mainPatchCommonTCS; - TCS[2] = isPrimTypePatchesBSpline + + // Tessellation control shader. + uint8_t tcsIndex = 0; + TCS[tcsIndex++] = _tokens->instancing; + TCS[tcsIndex++] = _tokens->mainPatchCommonTCS; + TCS[tcsIndex++] = isPrimTypePatchesBSpline ? _tokens->mainBSplineQuadTCS : _tokens->mainBoxSplineTriangleTCS; - TCS[3] = TfToken(); - - // tessellation evaluation shader - TES[0] = _tokens->instancing; - TES[1] = isPrimTypePatchesBSpline - ? _tokens->mainBezierQuadTES - : _tokens->mainBezierTriangleTES; - TES[2] = _tokens->mainVaryingInterpTES; - TES[3] = TfToken(); + TCS[tcsIndex++] = TfToken(); + + // Tessellation evaluation shader + uint8_t tesIndex = 0; + TES[tesIndex++] = _tokens->instancing; + + if (geomStyle == HdMeshGeomStyleEdgeOnSurf) { + + // TES configuration with a geometry shader. + TES[tesIndex++] = isPrimTypePatchesBSpline ? _tokens->mainBezierQuadTES + : _tokens->mainBezierTriangleTES; + TES[tesIndex++] = _tokens->mainVaryingInterpTES; + TES[tesIndex++] = TfToken(); + } + else { + + // TES configuration without a geometry shader. + if (ptvsGeometricNormals) { + TES[tesIndex++] = _tokens->normalsGeometryFlat; + } + else { + TES[tesIndex++] = _tokens->normalsGeometryNoFlat; + } + + // Now handle the vs style normals + if (normalsSource == NormalSourceFlat) { + TES[tesIndex++] = _tokens->normalsFlat; + } + else if (normalsSource == NormalSourceSmooth) { + TES[tesIndex++] = _tokens->normalsSmooth; + } + else if (vsSceneNormals) { + TES[tesIndex++] = _tokens->normalsScene; + } + else if (gsSceneNormals && isPrimTypePatches) { + TES[tesIndex++] = _tokens->normalsScenePatches; + } + else { + TES[tesIndex++] = _tokens->normalsPass; + } + + TES[tesIndex++] = _tokens->mainVaryingInterpTES; + + if (hasCustomDisplacement) { + TES[tesIndex++] = _tokens->customDisplacementTES; + } + else { + TES[tesIndex++] = _tokens->noCustomDisplacementTES; + } + + TES[tesIndex++] = isPrimTypePatchesBSpline + ? _tokens->mainBezierQuadNoGSTES + : _tokens->mainBezierTriangleNoGSTES; + TES[tesIndex++] = TfToken(); + finalTesStageEnabled = true; + } + } else { + TCS[0] = TfToken(); TES[0] = TfToken(); } + bool const tessOnlyEnabled = finalTesStageEnabled || ptvsStageEnabled; + // geometry shader uint8_t gsIndex = 0; GS[gsIndex++] = _tokens->instancing; @@ -398,7 +456,7 @@ HdSt_MeshShaderKey::HdSt_MeshShaderKey( // Optimization : See if we can skip the geometry shader. bool const canSkipGS = - ptvsStageEnabled || + tessOnlyEnabled || // Whether we can skip executing the displacement shading terminal (!hasCustomDisplacement && (normalsSource != NormalSourceLimit) @@ -603,7 +661,7 @@ HdSt_MeshShaderKey::HdSt_MeshShaderKey( FS[fsIndex++] = _tokens->mainPatchCoordTriQuadFS; // Patches - } else if (isPrimTypePatches && ptvsStageEnabled) { + } else if (isPrimTypePatches && tessOnlyEnabled) { FS[fsIndex++] = _tokens->mainPatchCoordTessFS; // Points/No GS } else if (isPrimTypePoints || canSkipGS) { diff --git a/pxr/imaging/hdSt/meshShaderKey.h b/pxr/imaging/hdSt/meshShaderKey.h index b82af19b13..4ca4e1d522 100644 --- a/pxr/imaging/hdSt/meshShaderKey.h +++ b/pxr/imaging/hdSt/meshShaderKey.h @@ -103,7 +103,7 @@ struct HdSt_MeshShaderKey : public HdSt_ShaderKey TfToken glslfx; TfToken VS[7]; TfToken TCS[4]; - TfToken TES[4]; + TfToken TES[12]; TfToken PTCS[4]; TfToken PTVS[12]; TfToken GS[10]; diff --git a/pxr/imaging/hdSt/shaders/mesh.glslfx b/pxr/imaging/hdSt/shaders/mesh.glslfx index 55bd9e871c..f5f91604b2 100644 --- a/pxr/imaging/hdSt/shaders/mesh.glslfx +++ b/pxr/imaging/hdSt/shaders/mesh.glslfx @@ -425,6 +425,67 @@ void main(void) ProcessPrimvarsOut(basis, 5, 6, 9, 10, UV); } +--- -------------------------------------------------------------------------- +-- layout Mesh.TessEval.BezierQuadNoGS + +# XXX: due to NVIDIA shader compiler bug (filed as 1687344) +# we can't put patchCoord into interface block. +[ + ["in", "quads"], + ["in", "vec4", "tessOuterLo", "patch"], + ["in", "vec4", "tessOuterHi", "patch"], + ["in block array", "VertexDataTess", "inpt", "gl_MaxPatchVertices", + ["OsdPerPatchVertexBezier", "v"] + ], + ["out block", "VertexData", "outData", + ["vec4", "Peye"], + ["vec3", "Neye"] + ], + ["out", "vec4", "tesPatchCoord"], + ["out", "vec2", "tesTessCoord"] +] + +--- -------------------------------------------------------------------------- +-- glsl Mesh.TessEval.BezierQuadNoGS + +void main(void) +{ + OsdPerPatchVertexBezier cv[16]; + for (int i = 0; i < 16; ++i) { + cv[i] = inpt[i].v; + } + vec2 UV = OsdGetTessParameterization(gl_TessCoord.xy, + tessOuterLo, + tessOuterHi); + + vec3 P = vec3(0), dPu = vec3(0), dPv = vec3(0); + vec3 N = vec3(0), dNu = vec3(0), dNv = vec3(0); + + ivec3 patchParam = inpt[0].v.patchParam; + OsdEvalPatchBezier(patchParam, UV, cv, P, dPu, dPv, N, dNu, dNv); + + tesPatchCoord = OsdInterpolatePatchCoord(UV, patchParam); + tesTessCoord = UV; + + // Bilinear basis + vec4 basis = vec4( + (1.0-UV.x) * (1.0-UV.y), UV.x * (1.0-UV.y), + (1.0-UV.x) * UV.y, UV.x * UV.y ); + + bool isFlipped = IsFlipped(); // consider handedness AND negative-scale + vec3 Neye = isFlipped ? -N : N; + + vec3 point = DisplacementTerminal(5, 6, 9, 10, P, Neye, basis, UV); + + outData.Peye = vec4(point, 1.0); + outData.Neye = Neye; // normalized + + gl_Position = vec4(GetProjectionMatrix() * outData.Peye); + ApplyClipPlanes(outData.Peye); + + ProcessPrimvarsOut(basis, 5, 6, 9, 10, UV); +} + --- -------------------------------------------------------------------------- -- layout Mesh.TessControl.BoxSplineTriangle @@ -537,6 +598,67 @@ void main(void) ProcessPrimvarsOut(basis, 4, 5, 8, 0, UV); } +--- -------------------------------------------------------------------------- +-- layout Mesh.TessEval.BezierTriangleNoGS + +# XXX: due to NVIDIA shader compiler bug (filed as 1687344) +# we can't put patchCoord into interface block. +[ + ["in", "triangles"], + ["in", "vec4", "tessOuterLo", "patch"], + ["in", "vec4", "tessOuterHi", "patch"], + ["in block array", "VertexDataTess", "inpt", "gl_MaxPatchVertices", + ["OsdPerPatchVertexBezier", "v"] + ], + ["out block", "VertexData", "outData", + ["vec4", "Peye"], + ["vec3", "Neye"] + ], + ["out", "vec4", "tesPatchCoord"], + ["out", "vec2", "tesTessCoord"] +] + +--- -------------------------------------------------------------------------- +-- glsl Mesh.TessEval.BezierTriangleNoGS + +void main(void) +{ + OsdPerPatchVertexBezier cv[15]; + for (int i = 0; i < 15; ++i) { + cv[i] = inpt[i].v; + } + vec2 UV = OsdGetTessParameterizationTriangle(gl_TessCoord.xyz, + tessOuterLo, + tessOuterHi); + + vec3 P = vec3(0), dPu = vec3(0), dPv = vec3(0); + vec3 N = vec3(0), dNu = vec3(0), dNv = vec3(0); + + ivec3 patchParam = inpt[0].v.patchParam; + OsdEvalPatchBezierTriangle(patchParam, UV, cv, P, dPu, dPv, N, dNu, dNv); + + tesPatchCoord = OsdInterpolatePatchCoordTriangle(UV, patchParam); + tesTessCoord = UV; + + // Barycentric basis + vec4 basis = vec4( + (1.0f-UV.x-UV.y), UV.x, UV.y, 0.0f); + + bool isFlipped = IsFlipped(); // consider handedness AND negative-scale + vec3 Neye = isFlipped ? -N : N; + + vec3 point = DisplacementTerminal(4, 5, 8, 0, P, Neye, basis, UV); + + outData.Peye = vec4(P, 1); + outData.Neye = Neye; // normalized + + gl_Position = vec4(GetProjectionMatrix() * outData.Peye); + ApplyClipPlanes(outData.Peye); + + ProcessPrimvarsOut(basis, 4, 5, 8, 0, UV); +} + + --- -------------------------------------------------------------------------- -- glsl Mesh.PostTessControl.PatchCommon diff --git a/pxr/imaging/hdSt/shaders/terminals.glslfx b/pxr/imaging/hdSt/shaders/terminals.glslfx index 8ceea5acea..979ece1080 100644 --- a/pxr/imaging/hdSt/shaders/terminals.glslfx +++ b/pxr/imaging/hdSt/shaders/terminals.glslfx @@ -10,6 +10,25 @@ --- This is what an import might look like. --- #import $TOOLS/hdSt/shaders/terminals.glslfx +--- -------------------------------------------------------------------------- +-- glsl TessEval.CustomDisplacement +vec3 DisplacementTerminal(int i0, int i1, int i2, int i3, vec3 Peye, vec3 Neye, vec4 basis, vec2 uv) +{ + vec2 t0 = HdGet_st(i0); + vec2 t1 = HdGet_st(i1); + vec2 t2 = HdGet_st(i2); + vec2 t3 = HdGet_st(i3); + vec2 t = InterpolatePrimvar(t0, t1, t2, t3, basis, uv); + return Peye + Neye * HdGet_displacement(t); +} + +--- -------------------------------------------------------------------------- +-- glsl TessEval.NoCustomDisplacement +vec3 DisplacementTerminal(int i0, int i1, int i2, int i3, vec3 Peye, vec3 Neye, vec4 basis, vec2 uv) +{ + return Peye; +} + --- -------------------------------------------------------------------------- -- glsl Geometry.CustomDisplacement diff --git a/pxr/imaging/hdSt/testenv/testHdStCodeGen_GL/baseline/codegen_curves_indirect.out b/pxr/imaging/hdSt/testenv/testHdStCodeGen_GL/baseline/codegen_curves_indirect.out index 955e677491..2bf47ce21a 100644 --- a/pxr/imaging/hdSt/testenv/testHdStCodeGen_GL/baseline/codegen_curves_indirect.out +++ b/pxr/imaging/hdSt/testenv/testHdStCodeGen_GL/baseline/codegen_curves_indirect.out @@ -1336,6 +1336,7 @@ in CurveVertexData { out CurveVertexData { vec4 Peye; } outData; +out vec2 hd_tessCoord; in flat ivec4 tcs_interstageDrawingCoord0[gl_MaxPatchVertices]; out flat ivec4 tes_interstageDrawingCoord0; in flat ivec4 tcs_interstageDrawingCoord1[gl_MaxPatchVertices]; @@ -1453,6 +1454,8 @@ vec3 HdGet_normals(int localIndex) { vec3 HdGet_normals() { return HdGet_normals(0); } float HdGetScalar_normals(int localIndex) { return HdGet_normals(localIndex).x; } float HdGetScalar_normals() { return HdGet_normals(0).x; } +void ProcessSamplingTransforms(MAT4 instanceModelViewInverse) { +} // //////// Codegen Proc TES //////// float InterpolatePrimvar(float inPv0, float inPv1, float inPv2, float inPv3, vec4 basis, vec2 uv); @@ -1460,6 +1463,7 @@ vec2 InterpolatePrimvar(vec2 inPv0, vec2 inPv1, vec2 inPv2, vec2 inPv3, vec4 bas vec3 InterpolatePrimvar(vec3 inPv0, vec3 inPv1, vec3 inPv2, vec3 inPv3, vec4 basis, vec2 uv); vec4 InterpolatePrimvar(vec4 inPv0, vec4 inPv1, vec4 inPv3, vec4 inPv3, vec4 basis, vec2 uv); void ProcessPrimvarsOut(vec4 basis, int i0, int i1, int i2, int i3, vec2 uv) { + hd_tessCoord = gl_TessCoord.xy; hd_drawingCoord dc = GetDrawingCoord(); tes_interstageDrawingCoord0[0] = dc.modelCoord; tes_interstageDrawingCoord0[1] = dc.constantCoord; @@ -1619,6 +1623,12 @@ void ApplyClipPlanes(vec4 Peye) #endif } +// line 42 "fallbackMaterialNetwork.glslfx" + +vec4 displacementShader(int index, vec4 Peye, vec3 Neye, vec4 patchCoord) +{ + return Peye; +} struct Coeffs @@ -2086,6 +2096,7 @@ in CurveVertexData { vec4 Peye; } inData; layout (location = 0) out vec4 colorOut; +in vec2 hd_tessCoord; in flat ivec4 tes_interstageDrawingCoord0; in flat ivec4 tes_interstageDrawingCoord1; in flat ivec4 tes_interstageDrawingCoord2; @@ -2133,6 +2144,12 @@ float HdGetScalar_widths() { return HdGet_widths(0); } vec3 GetBarycentricCoord() { return vec3(0); } +vec2 GetTessCoord() { + return hd_tessCoord; +} +vec3 GetTessCoordTriangle() { + return vec3(hd_tessCoord.x, hd_tessCoord.y, 1 - hd_tessCoord.x - hd_tessCoord.y); +} int GetPrimitiveID() { return gl_PrimitiveID; }