diff --git a/Package.swift b/Package.swift index 9ec83531ee..b1281c4be9 100644 --- a/Package.swift +++ b/Package.swift @@ -196,6 +196,10 @@ let package = Package( name: "Glf", targets: ["Glf"] ), + .library( + name: "GeomUtil", + targets: ["GeomUtil"] + ), // ----- Pixar.UsdImaging ----- .library( name: "UsdShaders", @@ -377,6 +381,11 @@ let package = Package( type: .dynamic, targets: ["PyGlf"] ), + .library( + name: "PyGeomUtil", + type: .dynamic, + targets: ["PyGeomUtil"] + ), // ----------------- Apps ----- .executable( name: "UsdView", @@ -424,6 +433,7 @@ let package = Package( "PyCameraUtil", "PyPxOsd", "PyGarch", + "PyGeomUtil", "PyGlf", "PyUsdShaders", ] @@ -1421,6 +1431,23 @@ let package = Package( ] ), + .target( + name: "GeomUtil", + dependencies: [ + .target(name: "Arch"), + .target(name: "Tf"), + .target(name: "Gf"), + .target(name: "Vt"), + .target(name: "PxOsd"), + ], + cxxSettings: [ + .define("MFB_PACKAGE_NAME", to: "GeomUtil"), + .define("MFB_ALT_PACKAGE_NAME", to: "GeomUtil"), + .define("MFB_PACKAGE_MODULE", to: "GeomUtil"), + .define("GEOMUTIL_EXPORTS", to: "1"), + ] + ), + .target( name: "PyTf", dependencies: [ @@ -2017,6 +2044,23 @@ let package = Package( ] ), + .target( + name: "PyGeomUtil", + dependencies: [ + .target(name: "PixarUSD"), + ], + path: "Python/PyGeomUtil", + resources: [ + .process("Resources"), + ], + publicHeadersPath: "include", + cxxSettings: [ + .define("MFB_PACKAGE_NAME", to: "GeomUtil"), + .define("MFB_ALT_PACKAGE_NAME", to: "GeomUtil"), + .define("MFB_PACKAGE_MODULE", to: "GeomUtil"), + ] + ), + .executableTarget( name: "UsdView", dependencies: [ @@ -2119,6 +2163,7 @@ let package = Package( .target(name: "HgiInterop"), .target(name: "Hio"), .target(name: "Glf"), + .target(name: "GeomUtil"), // --- usd imaging. ------ .target(name: "UsdShaders"), // -------- macros. ------ diff --git a/Sources/OpenUSD/imaging/geomUtil/__init__.py b/Python/PyGeomUtil/Resources/__init__.py similarity index 100% rename from Sources/OpenUSD/imaging/geomUtil/__init__.py rename to Python/PyGeomUtil/Resources/__init__.py diff --git a/Python/PyGeomUtil/include/PyGeomUtil/PyGeomUtil.h b/Python/PyGeomUtil/include/PyGeomUtil/PyGeomUtil.h new file mode 100644 index 0000000000..073f46757c --- /dev/null +++ b/Python/PyGeomUtil/include/PyGeomUtil/PyGeomUtil.h @@ -0,0 +1,6 @@ +#ifndef __PXR_IMAGING_PY_GEOM_UTIL_H__ +#define __PXR_IMAGING_PY_GEOM_UTIL_H__ + +/* no includes. */ + +#endif // __PXR_IMAGING_PY_GEOM_UTIL_H__ diff --git a/Sources/OpenUSD/imaging/geomUtil/module.cpp b/Python/PyGeomUtil/module.cpp similarity index 83% rename from Sources/OpenUSD/imaging/geomUtil/module.cpp rename to Python/PyGeomUtil/module.cpp index 0fd58ee758..cd412fd055 100644 --- a/Sources/OpenUSD/imaging/geomUtil/module.cpp +++ b/Python/PyGeomUtil/module.cpp @@ -21,16 +21,16 @@ // KIND, either express or implied. See the Apache License for the specific // language governing permissions and limitations under the Apache License. // -#include "pxr/pxr.h" -#include "pxr/base/tf/pyModule.h" +#include "pxr/pxrns.h" +#include "Tf/pyModule.h" PXR_NAMESPACE_USING_DIRECTIVE TF_WRAP_MODULE { - TF_WRAP(CapsuleMeshGenerator); - TF_WRAP(ConeMeshGenerator); - TF_WRAP(CuboidMeshGenerator); - TF_WRAP(CylinderMeshGenerator); - TF_WRAP(SphereMeshGenerator); + TF_WRAP(CapsuleMeshGenerator); + TF_WRAP(ConeMeshGenerator); + TF_WRAP(CuboidMeshGenerator); + TF_WRAP(CylinderMeshGenerator); + TF_WRAP(SphereMeshGenerator); } diff --git a/Sources/OpenUSD/imaging/geomUtil/moduleDeps.cpp b/Python/PyGeomUtil/moduleDeps.cpp similarity index 70% rename from Sources/OpenUSD/imaging/geomUtil/moduleDeps.cpp rename to Python/PyGeomUtil/moduleDeps.cpp index a06c6233cb..0ff0090052 100644 --- a/Sources/OpenUSD/imaging/geomUtil/moduleDeps.cpp +++ b/Python/PyGeomUtil/moduleDeps.cpp @@ -23,28 +23,25 @@ // //////////////////////////////////////////////////////////////////////// -#include "pxr/pxr.h" -#include "pxr/base/tf/registryManager.h" -#include "pxr/base/tf/scriptModuleLoader.h" -#include "pxr/base/tf/token.h" +#include "pxr/pxrns.h" +#include "Tf/registryManager.h" +#include "Tf/scriptModuleLoader.h" +#include "Tf/token.h" #include PXR_NAMESPACE_OPEN_SCOPE -TF_REGISTRY_FUNCTION(TfScriptModuleLoader) { - // List of direct dependencies for this library. - const std::vector reqs = { - TfToken("arch"), - TfToken("gf"), - TfToken("pxOsd"), - TfToken("tf"), - TfToken("vt") - }; - TfScriptModuleLoader::GetInstance(). - RegisterLibrary(TfToken("geomUtil"), TfToken("pxr.GeomUtil"), reqs); +TF_REGISTRY_FUNCTION(TfScriptModuleLoader) +{ + // List of direct dependencies for this library. + const std::vector reqs = { + TfToken("arch"), + TfToken("gf"), + TfToken("pxOsd"), + TfToken("tf"), + TfToken("vt")}; + TfScriptModuleLoader::GetInstance().RegisterLibrary(TfToken("geomUtil"), TfToken("pxr.GeomUtil"), reqs); } PXR_NAMESPACE_CLOSE_SCOPE - - diff --git a/Sources/OpenUSD/imaging/geomUtil/wrapCapsuleMeshGenerator.cpp b/Python/PyGeomUtil/wrapCapsuleMeshGenerator.cpp similarity index 51% rename from Sources/OpenUSD/imaging/geomUtil/wrapCapsuleMeshGenerator.cpp rename to Python/PyGeomUtil/wrapCapsuleMeshGenerator.cpp index a7c6c218eb..daa26b06a1 100644 --- a/Sources/OpenUSD/imaging/geomUtil/wrapCapsuleMeshGenerator.cpp +++ b/Python/PyGeomUtil/wrapCapsuleMeshGenerator.cpp @@ -21,11 +21,11 @@ // KIND, either express or implied. See the Apache License for the specific // language governing permissions and limitations under the Apache License. // -#include "pxr/imaging/geomUtil/capsuleMeshGenerator.h" +#include "GeomUtil/capsuleMeshGenerator.h" -#include "pxr/imaging/pxOsd/meshTopology.h" +#include "PxOsd/meshTopology.h" -#include "pxr/base/vt/types.h" +#include "Vt/types.h" #include @@ -40,40 +40,40 @@ _WrapGeneratePoints( const float radius, const float height) { - const size_t numPoints = - GeomUtilCapsuleMeshGenerator::ComputeNumPoints(numRadial, numCapAxial); - if (numPoints == 0) { - return VtVec3fArray(); - } + const size_t numPoints = + GeomUtilCapsuleMeshGenerator::ComputeNumPoints(numRadial, numCapAxial); + if (numPoints == 0) + { + return VtVec3fArray(); + } - VtVec3fArray points(numPoints); - GeomUtilCapsuleMeshGenerator::GeneratePoints( - points.begin(), numRadial, numCapAxial, radius, height); + VtVec3fArray points(numPoints); + GeomUtilCapsuleMeshGenerator::GeneratePoints( + points.begin(), numRadial, numCapAxial, radius, height); - return points; + return points; } void wrapCapsuleMeshGenerator() { - using This = GeomUtilCapsuleMeshGenerator; + using This = GeomUtilCapsuleMeshGenerator; - // Pull the constexpr values into variables so boost can odr-use them. - static constexpr size_t minNumRadial = This::minNumRadial; - static constexpr size_t minNumCapAxial = This::minNumCapAxial; + // Pull the constexpr values into variables so boost can odr-use them. + static constexpr size_t minNumRadial = This::minNumRadial; + static constexpr size_t minNumCapAxial = This::minNumCapAxial; - // Note: These are only "classes" for name scoping, and are uninstantiable; - // hence no need to bother declaring bases. - class_("CapsuleMeshGenerator", no_init) - .def_readonly("minNumRadial", minNumRadial) - .def_readonly("minNumCapAxial", minNumCapAxial) + // Note: These are only "classes" for name scoping, and are uninstantiable; + // hence no need to bother declaring bases. + class_("CapsuleMeshGenerator", no_init) + .def_readonly("minNumRadial", minNumRadial) + .def_readonly("minNumCapAxial", minNumCapAxial) - .def("ComputeNumPoints", &This::ComputeNumPoints) - .staticmethod("ComputeNumPoints") + .def("ComputeNumPoints", &This::ComputeNumPoints) + .staticmethod("ComputeNumPoints") - .def("GenerateTopology", &This::GenerateTopology) - .staticmethod("GenerateTopology") + .def("GenerateTopology", &This::GenerateTopology) + .staticmethod("GenerateTopology") - .def("GeneratePoints", &_WrapGeneratePoints) - .staticmethod("GeneratePoints") - ; + .def("GeneratePoints", &_WrapGeneratePoints) + .staticmethod("GeneratePoints"); } \ No newline at end of file diff --git a/Sources/OpenUSD/imaging/geomUtil/wrapConeMeshGenerator.cpp b/Python/PyGeomUtil/wrapConeMeshGenerator.cpp similarity index 53% rename from Sources/OpenUSD/imaging/geomUtil/wrapConeMeshGenerator.cpp rename to Python/PyGeomUtil/wrapConeMeshGenerator.cpp index 94e041b9da..ecd7566903 100644 --- a/Sources/OpenUSD/imaging/geomUtil/wrapConeMeshGenerator.cpp +++ b/Python/PyGeomUtil/wrapConeMeshGenerator.cpp @@ -21,11 +21,11 @@ // KIND, either express or implied. See the Apache License for the specific // language governing permissions and limitations under the Apache License. // -#include "pxr/imaging/geomUtil/coneMeshGenerator.h" +#include "GeomUtil/coneMeshGenerator.h" -#include "pxr/imaging/pxOsd/meshTopology.h" +#include "PxOsd/meshTopology.h" -#include "pxr/base/vt/types.h" +#include "Vt/types.h" #include @@ -39,38 +39,38 @@ _WrapGeneratePoints( const float radius, const float height) { - const size_t numPoints = - GeomUtilConeMeshGenerator::ComputeNumPoints(numRadial); - if (numPoints == 0) { - return VtVec3fArray(); - } + const size_t numPoints = + GeomUtilConeMeshGenerator::ComputeNumPoints(numRadial); + if (numPoints == 0) + { + return VtVec3fArray(); + } - VtVec3fArray points(numPoints); - GeomUtilConeMeshGenerator::GeneratePoints( - points.begin(), numRadial, radius, height); + VtVec3fArray points(numPoints); + GeomUtilConeMeshGenerator::GeneratePoints( + points.begin(), numRadial, radius, height); - return points; + return points; } void wrapConeMeshGenerator() { - using This = GeomUtilConeMeshGenerator; + using This = GeomUtilConeMeshGenerator; - // Pull the constexpr values into variables so boost can odr-use them. - static constexpr size_t minNumRadial = This::minNumRadial; + // Pull the constexpr values into variables so boost can odr-use them. + static constexpr size_t minNumRadial = This::minNumRadial; - // Note: These are only "classes" for name scoping, and are uninstantiable; - // hence no need to bother declaring bases. - class_("ConeMeshGenerator", no_init) - .def_readonly("minNumRadial", minNumRadial) + // Note: These are only "classes" for name scoping, and are uninstantiable; + // hence no need to bother declaring bases. + class_("ConeMeshGenerator", no_init) + .def_readonly("minNumRadial", minNumRadial) - .def("ComputeNumPoints", &This::ComputeNumPoints) - .staticmethod("ComputeNumPoints") + .def("ComputeNumPoints", &This::ComputeNumPoints) + .staticmethod("ComputeNumPoints") - .def("GenerateTopology", &This::GenerateTopology) - .staticmethod("GenerateTopology") + .def("GenerateTopology", &This::GenerateTopology) + .staticmethod("GenerateTopology") - .def("GeneratePoints", &_WrapGeneratePoints) - .staticmethod("GeneratePoints") - ; + .def("GeneratePoints", &_WrapGeneratePoints) + .staticmethod("GeneratePoints"); } \ No newline at end of file diff --git a/Sources/OpenUSD/imaging/geomUtil/wrapCuboidMeshGenerator.cpp b/Python/PyGeomUtil/wrapCuboidMeshGenerator.cpp similarity index 58% rename from Sources/OpenUSD/imaging/geomUtil/wrapCuboidMeshGenerator.cpp rename to Python/PyGeomUtil/wrapCuboidMeshGenerator.cpp index 1ec5f9430a..7f727845b2 100644 --- a/Sources/OpenUSD/imaging/geomUtil/wrapCuboidMeshGenerator.cpp +++ b/Python/PyGeomUtil/wrapCuboidMeshGenerator.cpp @@ -21,11 +21,11 @@ // KIND, either express or implied. See the Apache License for the specific // language governing permissions and limitations under the Apache License. // -#include "pxr/imaging/geomUtil/cuboidMeshGenerator.h" +#include "GeomUtil/cuboidMeshGenerator.h" -#include "pxr/imaging/pxOsd/meshTopology.h" +#include "PxOsd/meshTopology.h" -#include "pxr/base/vt/types.h" +#include "Vt/types.h" #include @@ -39,34 +39,34 @@ _WrapGeneratePoints( const float yLength, const float zLength) { - const size_t numPoints = - GeomUtilCuboidMeshGenerator::ComputeNumPoints(); - if (numPoints == 0) { - return VtVec3fArray(); - } + const size_t numPoints = + GeomUtilCuboidMeshGenerator::ComputeNumPoints(); + if (numPoints == 0) + { + return VtVec3fArray(); + } - VtVec3fArray points(numPoints); - GeomUtilCuboidMeshGenerator::GeneratePoints( - points.begin(), xLength, yLength, zLength); + VtVec3fArray points(numPoints); + GeomUtilCuboidMeshGenerator::GeneratePoints( + points.begin(), xLength, yLength, zLength); - return points; + return points; } void wrapCuboidMeshGenerator() { - using This = GeomUtilCuboidMeshGenerator; + using This = GeomUtilCuboidMeshGenerator; - // Note: These are only "classes" for name scoping, and are uninstantiable; - // hence no need to bother declaring bases. - class_("CuboidMeshGenerator", no_init) + // Note: These are only "classes" for name scoping, and are uninstantiable; + // hence no need to bother declaring bases. + class_("CuboidMeshGenerator", no_init) - .def("ComputeNumPoints", &This::ComputeNumPoints) - .staticmethod("ComputeNumPoints") + .def("ComputeNumPoints", &This::ComputeNumPoints) + .staticmethod("ComputeNumPoints") - .def("GenerateTopology", &This::GenerateTopology) - .staticmethod("GenerateTopology") + .def("GenerateTopology", &This::GenerateTopology) + .staticmethod("GenerateTopology") - .def("GeneratePoints", &_WrapGeneratePoints) - .staticmethod("GeneratePoints") - ; + .def("GeneratePoints", &_WrapGeneratePoints) + .staticmethod("GeneratePoints"); } \ No newline at end of file diff --git a/Sources/OpenUSD/imaging/geomUtil/wrapCylinderMeshGenerator.cpp b/Python/PyGeomUtil/wrapCylinderMeshGenerator.cpp similarity index 53% rename from Sources/OpenUSD/imaging/geomUtil/wrapCylinderMeshGenerator.cpp rename to Python/PyGeomUtil/wrapCylinderMeshGenerator.cpp index ed77b14178..e9f3ce4ed9 100644 --- a/Sources/OpenUSD/imaging/geomUtil/wrapCylinderMeshGenerator.cpp +++ b/Python/PyGeomUtil/wrapCylinderMeshGenerator.cpp @@ -21,11 +21,11 @@ // KIND, either express or implied. See the Apache License for the specific // language governing permissions and limitations under the Apache License. // -#include "pxr/imaging/geomUtil/cylinderMeshGenerator.h" +#include "GeomUtil/cylinderMeshGenerator.h" -#include "pxr/imaging/pxOsd/meshTopology.h" +#include "PxOsd/meshTopology.h" -#include "pxr/base/vt/types.h" +#include "Vt/types.h" #include @@ -39,38 +39,38 @@ _WrapGeneratePoints( const float radius, const float height) { - const size_t numPoints = - GeomUtilCylinderMeshGenerator::ComputeNumPoints(numRadial); - if (numPoints == 0) { - return VtVec3fArray(); - } + const size_t numPoints = + GeomUtilCylinderMeshGenerator::ComputeNumPoints(numRadial); + if (numPoints == 0) + { + return VtVec3fArray(); + } - VtVec3fArray points(numPoints); - GeomUtilCylinderMeshGenerator::GeneratePoints( - points.begin(), numRadial, radius, height); + VtVec3fArray points(numPoints); + GeomUtilCylinderMeshGenerator::GeneratePoints( + points.begin(), numRadial, radius, height); - return points; + return points; } void wrapCylinderMeshGenerator() { - using This = GeomUtilCylinderMeshGenerator; + using This = GeomUtilCylinderMeshGenerator; - // Pull the constexpr values into variables so boost can odr-use them. - static constexpr size_t minNumRadial = This::minNumRadial; + // Pull the constexpr values into variables so boost can odr-use them. + static constexpr size_t minNumRadial = This::minNumRadial; - // Note: These are only "classes" for name scoping, and are uninstantiable; - // hence no need to bother declaring bases. - class_("CylinderMeshGenerator", no_init) - .def_readonly("minNumRadial", minNumRadial) + // Note: These are only "classes" for name scoping, and are uninstantiable; + // hence no need to bother declaring bases. + class_("CylinderMeshGenerator", no_init) + .def_readonly("minNumRadial", minNumRadial) - .def("ComputeNumPoints", &This::ComputeNumPoints) - .staticmethod("ComputeNumPoints") + .def("ComputeNumPoints", &This::ComputeNumPoints) + .staticmethod("ComputeNumPoints") - .def("GenerateTopology", &This::GenerateTopology) - .staticmethod("GenerateTopology") + .def("GenerateTopology", &This::GenerateTopology) + .staticmethod("GenerateTopology") - .def("GeneratePoints", &_WrapGeneratePoints) - .staticmethod("GeneratePoints") - ; + .def("GeneratePoints", &_WrapGeneratePoints) + .staticmethod("GeneratePoints"); } \ No newline at end of file diff --git a/Sources/OpenUSD/imaging/geomUtil/wrapSphereMeshGenerator.cpp b/Python/PyGeomUtil/wrapSphereMeshGenerator.cpp similarity index 51% rename from Sources/OpenUSD/imaging/geomUtil/wrapSphereMeshGenerator.cpp rename to Python/PyGeomUtil/wrapSphereMeshGenerator.cpp index 15c58de4a5..3a254a3519 100644 --- a/Sources/OpenUSD/imaging/geomUtil/wrapSphereMeshGenerator.cpp +++ b/Python/PyGeomUtil/wrapSphereMeshGenerator.cpp @@ -21,11 +21,11 @@ // KIND, either express or implied. See the Apache License for the specific // language governing permissions and limitations under the Apache License. // -#include "pxr/imaging/geomUtil/sphereMeshGenerator.h" +#include "GeomUtil/sphereMeshGenerator.h" -#include "pxr/imaging/pxOsd/meshTopology.h" +#include "PxOsd/meshTopology.h" -#include "pxr/base/vt/types.h" +#include "Vt/types.h" #include @@ -39,40 +39,40 @@ _WrapGeneratePoints( const size_t numAxial, const float radius) { - const size_t numPoints = - GeomUtilSphereMeshGenerator::ComputeNumPoints(numRadial, numAxial); - if (numPoints == 0) { - return VtVec3fArray(); - } + const size_t numPoints = + GeomUtilSphereMeshGenerator::ComputeNumPoints(numRadial, numAxial); + if (numPoints == 0) + { + return VtVec3fArray(); + } - VtVec3fArray points(numPoints); - GeomUtilSphereMeshGenerator::GeneratePoints( - points.begin(), numRadial, numAxial, radius); + VtVec3fArray points(numPoints); + GeomUtilSphereMeshGenerator::GeneratePoints( + points.begin(), numRadial, numAxial, radius); - return points; + return points; } void wrapSphereMeshGenerator() { - using This = GeomUtilSphereMeshGenerator; + using This = GeomUtilSphereMeshGenerator; - // Pull the constexpr values into variables so boost can odr-use them. - static constexpr size_t minNumRadial = This::minNumRadial; - static constexpr size_t minNumAxial = This::minNumAxial; + // Pull the constexpr values into variables so boost can odr-use them. + static constexpr size_t minNumRadial = This::minNumRadial; + static constexpr size_t minNumAxial = This::minNumAxial; - // Note: These are only "classes" for name scoping, and are uninstantiable; - // hence no need to bother declaring bases. - class_("SphereMeshGenerator", no_init) - .def_readonly("minNumRadial", minNumRadial) - .def_readonly("minNumAxial", minNumAxial) + // Note: These are only "classes" for name scoping, and are uninstantiable; + // hence no need to bother declaring bases. + class_("SphereMeshGenerator", no_init) + .def_readonly("minNumRadial", minNumRadial) + .def_readonly("minNumAxial", minNumAxial) - .def("ComputeNumPoints", &This::ComputeNumPoints) - .staticmethod("ComputeNumPoints") + .def("ComputeNumPoints", &This::ComputeNumPoints) + .staticmethod("ComputeNumPoints") - .def("GenerateTopology", &This::GenerateTopology) - .staticmethod("GenerateTopology") + .def("GenerateTopology", &This::GenerateTopology) + .staticmethod("GenerateTopology") - .def("GeneratePoints", &_WrapGeneratePoints) - .staticmethod("GeneratePoints") - ; + .def("GeneratePoints", &_WrapGeneratePoints) + .staticmethod("GeneratePoints"); } \ No newline at end of file diff --git a/Sources/OpenUSD/imaging/geomUtil/capsuleMeshGenerator.cpp b/Sources/GeomUtil/capsuleMeshGenerator.cpp similarity index 89% rename from Sources/OpenUSD/imaging/geomUtil/capsuleMeshGenerator.cpp rename to Sources/GeomUtil/capsuleMeshGenerator.cpp index d43fbc48f0..777d9299fc 100644 --- a/Sources/OpenUSD/imaging/geomUtil/capsuleMeshGenerator.cpp +++ b/Sources/GeomUtil/capsuleMeshGenerator.cpp @@ -21,13 +21,13 @@ // KIND, either express or implied. See the Apache License for the specific // language governing permissions and limitations under the Apache License. // -#include "pxr/imaging/geomUtil/capsuleMeshGenerator.h" +#include "GeomUtil/capsuleMeshGenerator.h" -#include "pxr/imaging/pxOsd/meshTopology.h" -#include "pxr/imaging/pxOsd/tokens.h" +#include "PxOsd/meshTopology.h" +#include "PxOsd/tokens.h" -#include "pxr/base/arch/pxrmath.h" -#include "pxr/base/vt/types.h" +#include "Arch/pxrmath.h" +#include "Vt/types.h" #include #include @@ -38,8 +38,10 @@ PXR_NAMESPACE_OPEN_SCOPE // static size_t GeomUtilCapsuleMeshGenerator::ComputeNumPoints(const size_t numRadial, const size_t numCapAxial, - const bool closedSweep) { - if ((numRadial < minNumRadial) || (numCapAxial < minNumCapAxial)) { + const bool closedSweep) +{ + if ((numRadial < minNumRadial) || (numCapAxial < minNumCapAxial)) + { return 0; } @@ -51,8 +53,10 @@ size_t GeomUtilCapsuleMeshGenerator::ComputeNumPoints(const size_t numRadial, // static PxOsdMeshTopology GeomUtilCapsuleMeshGenerator::GenerateTopology( - const size_t numRadial, const size_t numCapAxial, const bool closedSweep) { - if ((numRadial < minNumRadial) || (numCapAxial < minNumCapAxial)) { + const size_t numRadial, const size_t numCapAxial, const bool closedSweep) +{ + if ((numRadial < minNumRadial) || (numCapAxial < minNumCapAxial)) + { return PxOsdMeshTopology(); } @@ -73,10 +77,12 @@ void GeomUtilCapsuleMeshGenerator::_GeneratePointsImpl( const typename PointType::ScalarType bottomCapHeight, const typename PointType::ScalarType topCapHeight, const typename PointType::ScalarType sweepDegrees, - const _PointWriter &ptWriter) { + const _PointWriter &ptWriter) +{ using ScalarType = typename PointType::ScalarType; - if ((numRadial < minNumRadial) || (numCapAxial < minNumCapAxial)) { + if ((numRadial < minNumRadial) || (numCapAxial < minNumCapAxial)) + { return; } @@ -90,7 +96,8 @@ void GeomUtilCapsuleMeshGenerator::_GeneratePointsImpl( _ComputeNumRadialPoints(numRadial, closedSweep); std::vector> ringXY(numRadialPoints); - for (size_t radIdx = 0; radIdx < numRadialPoints; ++radIdx) { + for (size_t radIdx = 0; radIdx < numRadialPoints; ++radIdx) + { // Longitude range: [0, sweep] const ScalarType longAngle = (ScalarType(radIdx) / ScalarType(numRadial)) * sweepRadians; @@ -102,7 +109,8 @@ void GeomUtilCapsuleMeshGenerator::_GeneratePointsImpl( ptWriter.Write(PointType(0.0, 0.0, -(bottomCapHeight + (0.5 * height)))); // Bottom hemisphere latitude rings: - for (size_t axIdx = 1; axIdx < (numCapAxial + 1); ++axIdx) { + for (size_t axIdx = 1; axIdx < (numCapAxial + 1); ++axIdx) + { // Latitude range: (-0.5pi, 0] const ScalarType latAngle = ((ScalarType(axIdx) / ScalarType(numCapAxial)) - 1.0) * (0.5 * M_PI); @@ -111,7 +119,8 @@ void GeomUtilCapsuleMeshGenerator::_GeneratePointsImpl( const ScalarType latitude = -(0.5 * height) + (bottomCapHeight * sin(latAngle)); - for (size_t radIdx = 0; radIdx < numRadialPoints; ++radIdx) { + for (size_t radIdx = 0; radIdx < numRadialPoints; ++radIdx) + { ptWriter.Write(PointType(radScale * bottomRadius * ringXY[radIdx][0], radScale * bottomRadius * ringXY[radIdx][1], latitude)); @@ -119,7 +128,8 @@ void GeomUtilCapsuleMeshGenerator::_GeneratePointsImpl( } // Top hemisphere latitude rings: - for (size_t axIdx = 0; axIdx < numCapAxial; ++axIdx) { + for (size_t axIdx = 0; axIdx < numCapAxial; ++axIdx) + { // Latitude range: [0, 0.5pi) const ScalarType latAngle = (ScalarType(axIdx) / ScalarType(numCapAxial)) * (0.5 * M_PI); @@ -127,7 +137,8 @@ void GeomUtilCapsuleMeshGenerator::_GeneratePointsImpl( const ScalarType radScale = cos(latAngle); const ScalarType latitude = (0.5 * height) + (topCapHeight * sin(latAngle)); - for (size_t radIdx = 0; radIdx < numRadialPoints; ++radIdx) { + for (size_t radIdx = 0; radIdx < numRadialPoints; ++radIdx) + { ptWriter.Write(PointType(radScale * topRadius * ringXY[radIdx][0], radScale * topRadius * ringXY[radIdx][1], latitude)); diff --git a/Sources/OpenUSD/imaging/geomUtil/coneMeshGenerator.cpp b/Sources/GeomUtil/coneMeshGenerator.cpp similarity index 87% rename from Sources/OpenUSD/imaging/geomUtil/coneMeshGenerator.cpp rename to Sources/GeomUtil/coneMeshGenerator.cpp index 56bb97697c..3b0cb6a933 100644 --- a/Sources/OpenUSD/imaging/geomUtil/coneMeshGenerator.cpp +++ b/Sources/GeomUtil/coneMeshGenerator.cpp @@ -21,13 +21,13 @@ // KIND, either express or implied. See the Apache License for the specific // language governing permissions and limitations under the Apache License. // -#include "pxr/imaging/geomUtil/coneMeshGenerator.h" +#include "GeomUtil/coneMeshGenerator.h" -#include "pxr/imaging/pxOsd/meshTopology.h" -#include "pxr/imaging/pxOsd/tokens.h" +#include "PxOsd/meshTopology.h" +#include "PxOsd/tokens.h" -#include "pxr/base/arch/pxrmath.h" -#include "pxr/base/vt/types.h" +#include "Arch/pxrmath.h" +#include "Vt/types.h" #include #include @@ -38,8 +38,10 @@ PXR_NAMESPACE_OPEN_SCOPE // static size_t GeomUtilConeMeshGenerator::ComputeNumPoints(const size_t numRadial, - const bool closedSweep) { - if (numRadial < minNumRadial) { + const bool closedSweep) +{ + if (numRadial < minNumRadial) + { return 0; } @@ -52,8 +54,10 @@ size_t GeomUtilConeMeshGenerator::ComputeNumPoints(const size_t numRadial, // static PxOsdMeshTopology GeomUtilConeMeshGenerator::GenerateTopology(const size_t numRadial, - const bool closedSweep) { - if (numRadial < minNumRadial) { + const bool closedSweep) +{ + if (numRadial < minNumRadial) + { return PxOsdMeshTopology(); } @@ -70,10 +74,12 @@ void GeomUtilConeMeshGenerator::_GeneratePointsImpl( const size_t numRadial, const typename PointType::ScalarType radius, const typename PointType::ScalarType height, const typename PointType::ScalarType sweepDegrees, - const _PointWriter &ptWriter) { + const _PointWriter &ptWriter) +{ using ScalarType = typename PointType::ScalarType; - if (numRadial < minNumRadial) { + if (numRadial < minNumRadial) + { return; } @@ -87,7 +93,8 @@ void GeomUtilConeMeshGenerator::_GeneratePointsImpl( _ComputeNumRadialPoints(numRadial, closedSweep); std::vector> ringXY(numRadialPoints); - for (size_t radIdx = 0; radIdx < numRadialPoints; ++radIdx) { + for (size_t radIdx = 0; radIdx < numRadialPoints; ++radIdx) + { // Longitude range: [0, 2pi) const ScalarType longAngle = (ScalarType(radIdx) / ScalarType(numRadial)) * sweepRadians; @@ -104,8 +111,10 @@ void GeomUtilConeMeshGenerator::_GeneratePointsImpl( // Bottom rings; two consecutive rings at the same point locations, the // first for the bottom triangle fan and the second for the main // cone quads (for normals reasons the bottom "edge" is not shared): - for (size_t ringIdx = 0; ringIdx < 2; ++ringIdx) { - for (size_t radIdx = 0; radIdx < numRadialPoints; ++radIdx) { + for (size_t ringIdx = 0; ringIdx < 2; ++ringIdx) + { + for (size_t radIdx = 0; radIdx < numRadialPoints; ++radIdx) + { ptWriter.Write(PointType(ringXY[radIdx][0], ringXY[radIdx][1], zMin)); } } @@ -114,7 +123,8 @@ void GeomUtilConeMeshGenerator::_GeneratePointsImpl( // quads, so edges between left/right faces generate smooth normals but // there's no continuity over the top "point" as would happen with a // triangle fan. - for (size_t radIdx = 0; radIdx < numRadialPoints; ++radIdx) { + for (size_t radIdx = 0; radIdx < numRadialPoints; ++radIdx) + { ptWriter.Write(PointType(0.0, 0.0, zMax)); } } diff --git a/Sources/OpenUSD/imaging/geomUtil/cuboidMeshGenerator.cpp b/Sources/GeomUtil/cuboidMeshGenerator.cpp similarity index 55% rename from Sources/OpenUSD/imaging/geomUtil/cuboidMeshGenerator.cpp rename to Sources/GeomUtil/cuboidMeshGenerator.cpp index 19b16b8a58..0a71e7e8ec 100644 --- a/Sources/OpenUSD/imaging/geomUtil/cuboidMeshGenerator.cpp +++ b/Sources/GeomUtil/cuboidMeshGenerator.cpp @@ -21,64 +21,62 @@ // KIND, either express or implied. See the Apache License for the specific // language governing permissions and limitations under the Apache License. // -#include "pxr/imaging/geomUtil/cuboidMeshGenerator.h" +#include "GeomUtil/cuboidMeshGenerator.h" -#include "pxr/imaging/pxOsd/meshTopology.h" -#include "pxr/imaging/pxOsd/tokens.h" +#include "PxOsd/meshTopology.h" +#include "PxOsd/tokens.h" -#include "pxr/base/vt/types.h" +#include "Vt/types.h" PXR_NAMESPACE_OPEN_SCOPE - // static size_t GeomUtilCuboidMeshGenerator::ComputeNumPoints() { - return 8; + return 8; } // static PxOsdMeshTopology GeomUtilCuboidMeshGenerator::GenerateTopology() { - // These never vary, we might as well share a single copy via VtArray. - static const VtIntArray countsArray{ 4, 4, 4, 4, 4, 4 }; - static const VtIntArray indicesArray{ 0, 1, 2, 3, - 4, 5, 6, 7, - 0, 6, 5, 1, - 4, 7, 3, 2, - 0, 3, 7, 6, - 4, 2, 1, 5 }; - return PxOsdMeshTopology( - PxOsdOpenSubdivTokens->bilinear, - PxOsdOpenSubdivTokens->rightHanded, - countsArray, indicesArray); + // These never vary, we might as well share a single copy via VtArray. + static const VtIntArray countsArray{4, 4, 4, 4, 4, 4}; + static const VtIntArray indicesArray{0, 1, 2, 3, + 4, 5, 6, 7, + 0, 6, 5, 1, + 4, 7, 3, 2, + 0, 3, 7, 6, + 4, 2, 1, 5}; + return PxOsdMeshTopology( + PxOsdOpenSubdivTokens->bilinear, + PxOsdOpenSubdivTokens->rightHanded, + countsArray, indicesArray); } // static -template -void -GeomUtilCuboidMeshGenerator::_GeneratePointsImpl( +template +void GeomUtilCuboidMeshGenerator::_GeneratePointsImpl( const typename PointType::ScalarType xLength, const typename PointType::ScalarType yLength, const typename PointType::ScalarType zLength, - const _PointWriter& ptWriter) + const _PointWriter &ptWriter) { - using ScalarType = typename PointType::ScalarType; + using ScalarType = typename PointType::ScalarType; - const ScalarType x = 0.5 * xLength; - const ScalarType y = 0.5 * yLength; - const ScalarType z = 0.5 * zLength; + const ScalarType x = 0.5 * xLength; + const ScalarType y = 0.5 * yLength; + const ScalarType z = 0.5 * zLength; - ptWriter.Write(PointType( x, y, z)); - ptWriter.Write(PointType(-x, y, z)); - ptWriter.Write(PointType(-x, -y, z)); - ptWriter.Write(PointType( x, -y, z)); - ptWriter.Write(PointType(-x, -y, -z)); - ptWriter.Write(PointType(-x, y, -z)); - ptWriter.Write(PointType( x, y, -z)); - ptWriter.Write(PointType( x, -y, -z)); + ptWriter.Write(PointType(x, y, z)); + ptWriter.Write(PointType(-x, y, z)); + ptWriter.Write(PointType(-x, -y, z)); + ptWriter.Write(PointType(x, -y, z)); + ptWriter.Write(PointType(-x, -y, -z)); + ptWriter.Write(PointType(-x, y, -z)); + ptWriter.Write(PointType(x, y, -z)); + ptWriter.Write(PointType(x, -y, -z)); } // Force-instantiate _GeneratePointsImpl for the supported point types. Only @@ -86,11 +84,10 @@ GeomUtilCuboidMeshGenerator::_GeneratePointsImpl( // calling method template (the public GeneratePoints, in the header). template GEOMUTIL_API void GeomUtilCuboidMeshGenerator::_GeneratePointsImpl( const float, const float, const float, - const GeomUtilCuboidMeshGenerator::_PointWriter&); + const GeomUtilCuboidMeshGenerator::_PointWriter &); template GEOMUTIL_API void GeomUtilCuboidMeshGenerator::_GeneratePointsImpl( const double, const double, const double, - const GeomUtilCuboidMeshGenerator::_PointWriter&); - + const GeomUtilCuboidMeshGenerator::_PointWriter &); PXR_NAMESPACE_CLOSE_SCOPE \ No newline at end of file diff --git a/Sources/OpenUSD/imaging/geomUtil/cylinderMeshGenerator.cpp b/Sources/GeomUtil/cylinderMeshGenerator.cpp similarity index 86% rename from Sources/OpenUSD/imaging/geomUtil/cylinderMeshGenerator.cpp rename to Sources/GeomUtil/cylinderMeshGenerator.cpp index a2cfa971c6..6f7b64867d 100644 --- a/Sources/OpenUSD/imaging/geomUtil/cylinderMeshGenerator.cpp +++ b/Sources/GeomUtil/cylinderMeshGenerator.cpp @@ -21,13 +21,13 @@ // KIND, either express or implied. See the Apache License for the specific // language governing permissions and limitations under the Apache License. // -#include "pxr/imaging/geomUtil/cylinderMeshGenerator.h" +#include "GeomUtil/cylinderMeshGenerator.h" -#include "pxr/imaging/pxOsd/meshTopology.h" -#include "pxr/imaging/pxOsd/tokens.h" +#include "PxOsd/meshTopology.h" +#include "PxOsd/tokens.h" -#include "pxr/base/arch/pxrmath.h" -#include "pxr/base/vt/types.h" +#include "Arch/pxrmath.h" +#include "Vt/types.h" #include #include @@ -38,8 +38,10 @@ PXR_NAMESPACE_OPEN_SCOPE // static size_t GeomUtilCylinderMeshGenerator::ComputeNumPoints(const size_t numRadial, - const bool closedSweep) { - if (numRadial < minNumRadial) { + const bool closedSweep) +{ + if (numRadial < minNumRadial) + { return 0; } @@ -52,8 +54,10 @@ size_t GeomUtilCylinderMeshGenerator::ComputeNumPoints(const size_t numRadial, // static PxOsdMeshTopology GeomUtilCylinderMeshGenerator::GenerateTopology(const size_t numRadial, - const bool closedSweep) { - if (numRadial < minNumRadial) { + const bool closedSweep) +{ + if (numRadial < minNumRadial) + { return PxOsdMeshTopology(); } @@ -71,10 +75,12 @@ void GeomUtilCylinderMeshGenerator::_GeneratePointsImpl( const typename PointType::ScalarType topRadius, const typename PointType::ScalarType height, const typename PointType::ScalarType sweepDegrees, - const _PointWriter &ptWriter) { + const _PointWriter &ptWriter) +{ using ScalarType = typename PointType::ScalarType; - if (numRadial < minNumRadial) { + if (numRadial < minNumRadial) + { return; } @@ -88,7 +94,8 @@ void GeomUtilCylinderMeshGenerator::_GeneratePointsImpl( _ComputeNumRadialPoints(numRadial, closedSweep); std::vector> ringXY(numRadialPoints); - for (size_t radIdx = 0; radIdx < numRadialPoints; ++radIdx) { + for (size_t radIdx = 0; radIdx < numRadialPoints; ++radIdx) + { // Longitude range: [0, sweep] const ScalarType longAngle = (ScalarType(radIdx) / ScalarType(numRadial)) * (sweepRadians); @@ -105,16 +112,20 @@ void GeomUtilCylinderMeshGenerator::_GeneratePointsImpl( // Bottom rings; two consecutive rings at the same point locations, the // first for the bottom triangle fan and the second for the main // cylinder quads (for normals reasons the bottom "edge" is not shared): - for (size_t ringIdx = 0; ringIdx < 2; ++ringIdx) { - for (size_t radIdx = 0; radIdx < numRadialPoints; ++radIdx) { + for (size_t ringIdx = 0; ringIdx < 2; ++ringIdx) + { + for (size_t radIdx = 0; radIdx < numRadialPoints; ++radIdx) + { ptWriter.Write(PointType(bottomRadius * ringXY[radIdx][0], bottomRadius * ringXY[radIdx][1], zMin)); } } // And another two rings, for the top edge. - for (size_t ringIdx = 0; ringIdx < 2; ++ringIdx) { - for (size_t radIdx = 0; radIdx < numRadialPoints; ++radIdx) { + for (size_t ringIdx = 0; ringIdx < 2; ++ringIdx) + { + for (size_t radIdx = 0; radIdx < numRadialPoints; ++radIdx) + { ptWriter.Write(PointType(topRadius * ringXY[radIdx][0], topRadius * ringXY[radIdx][1], zMax)); } diff --git a/Sources/GeomUtil/include/GeomUtil/GeomUtil.h b/Sources/GeomUtil/include/GeomUtil/GeomUtil.h new file mode 100644 index 0000000000..a04d223d3f --- /dev/null +++ b/Sources/GeomUtil/include/GeomUtil/GeomUtil.h @@ -0,0 +1,12 @@ +#ifndef __PXR_IMAGING_GEOM_UTIL_H__ +#define __PXR_IMAGING_GEOM_UTIL_H__ + +#include +#include +#include +#include +#include +#include +#include + +#endif // __PXR_IMAGING_GEOM_UTIL_H__ diff --git a/Sources/OpenUSD/include/imaging/geomUtil/api.h b/Sources/GeomUtil/include/GeomUtil/api.h similarity index 63% rename from Sources/OpenUSD/include/imaging/geomUtil/api.h rename to Sources/GeomUtil/include/GeomUtil/api.h index 8c5f208116..5a1d9cc08c 100644 --- a/Sources/OpenUSD/include/imaging/geomUtil/api.h +++ b/Sources/GeomUtil/include/GeomUtil/api.h @@ -24,24 +24,24 @@ #ifndef PXR_IMAGING_GEOM_UTIL_API_H #define PXR_IMAGING_GEOM_UTIL_API_H -#include "pxr/base/arch/export.h" +#include "Arch/export.h" #if defined(PXR_STATIC) -# define GEOMUTIL_API -# define GEOMUTIL_API_TEMPLATE_CLASS(...) -# define GEOMUTIL_API_TEMPLATE_STRUCT(...) -# define GEOMUTIL_LOCAL +#define GEOMUTIL_API +#define GEOMUTIL_API_TEMPLATE_CLASS(...) +#define GEOMUTIL_API_TEMPLATE_STRUCT(...) +#define GEOMUTIL_LOCAL #else -# if defined(GEOMUTIL_EXPORTS) -# define GEOMUTIL_API ARCH_EXPORT -# define GEOMUTIL_API_TEMPLATE_CLASS(...) ARCH_EXPORT_TEMPLATE(class, __VA_ARGS__) -# define GEOMUTIL_API_TEMPLATE_STRUCT(...) ARCH_EXPORT_TEMPLATE(struct, __VA_ARGS__) -# else -# define GEOMUTIL_API ARCH_IMPORT -# define GEOMUTIL_API_TEMPLATE_CLASS(...) ARCH_IMPORT_TEMPLATE(class, __VA_ARGS__) -# define GEOMUTIL_API_TEMPLATE_STRUCT(...) ARCH_IMPORT_TEMPLATE(struct, __VA_ARGS__) -# endif -# define GEOMUTIL_LOCAL ARCH_HIDDEN +#if defined(GEOMUTIL_EXPORTS) +#define GEOMUTIL_API ARCH_EXPORT +#define GEOMUTIL_API_TEMPLATE_CLASS(...) ARCH_EXPORT_TEMPLATE(class, __VA_ARGS__) +#define GEOMUTIL_API_TEMPLATE_STRUCT(...) ARCH_EXPORT_TEMPLATE(struct, __VA_ARGS__) +#else +#define GEOMUTIL_API ARCH_IMPORT +#define GEOMUTIL_API_TEMPLATE_CLASS(...) ARCH_IMPORT_TEMPLATE(class, __VA_ARGS__) +#define GEOMUTIL_API_TEMPLATE_STRUCT(...) ARCH_IMPORT_TEMPLATE(struct, __VA_ARGS__) +#endif +#define GEOMUTIL_LOCAL ARCH_HIDDEN #endif #endif // PXR_IMAGING_GEOM_UTIL_API_H diff --git a/Sources/OpenUSD/include/imaging/geomUtil/capsuleMeshGenerator.h b/Sources/GeomUtil/include/GeomUtil/capsuleMeshGenerator.h similarity index 52% rename from Sources/OpenUSD/include/imaging/geomUtil/capsuleMeshGenerator.h rename to Sources/GeomUtil/include/GeomUtil/capsuleMeshGenerator.h index 0d8ef696e3..770f319955 100644 --- a/Sources/OpenUSD/include/imaging/geomUtil/capsuleMeshGenerator.h +++ b/Sources/GeomUtil/include/GeomUtil/capsuleMeshGenerator.h @@ -24,10 +24,10 @@ #ifndef PXR_IMAGING_GEOM_UTIL_CAPSULE_MESH_GENERATOR_H #define PXR_IMAGING_GEOM_UTIL_CAPSULE_MESH_GENERATOR_H -#include "pxr/imaging/geomUtil/api.h" -#include "pxr/imaging/geomUtil/meshGeneratorBase.h" +#include "GeomUtil/api.h" +#include "GeomUtil/meshGeneratorBase.h" -#include "pxr/pxr.h" +#include "pxr/pxrns.h" PXR_NAMESPACE_OPEN_SCOPE @@ -36,7 +36,7 @@ class PxOsdMeshTopology; /// This class provides an implementation for generating topology and point /// positions on a capsule. The simplest form takes a radius and height and is -/// a cylinder capped by two hemispheres that is centered at the origin. The +/// a cylinder capped by two hemispheres that is centered at the origin. The /// generated capsule is made up of circular cross-sections in the XY plane. /// Each cross-section has numRadial segments. Successive cross-sections for /// each of the hemispheres are generated at numCapAxial locations along the Z @@ -70,83 +70,83 @@ class GeomUtilCapsuleMeshGenerator final : public GeomUtilMeshGeneratorBase { public: - static constexpr size_t minNumRadial = 3; - static constexpr size_t minNumCapAxial = 1; + static constexpr size_t minNumRadial = 3; + static constexpr size_t minNumCapAxial = 1; - GEOMUTIL_API - static size_t ComputeNumPoints( - const size_t numRadial, - const size_t numCapAxial, - const bool closedSweep = true); + GEOMUTIL_API + static size_t ComputeNumPoints( + const size_t numRadial, + const size_t numCapAxial, + const bool closedSweep = true); - GEOMUTIL_API - static PxOsdMeshTopology GenerateTopology( - const size_t numRadial, - const size_t numCapAxial, - const bool closedSweep = true); + GEOMUTIL_API + static PxOsdMeshTopology GenerateTopology( + const size_t numRadial, + const size_t numCapAxial, + const bool closedSweep = true); - template::type> - static void GeneratePoints( - PointIterType iter, - const size_t numRadial, - const size_t numCapAxial, - const ScalarType radius, - const ScalarType height, - const GfMatrix4d* framePtr = nullptr) - { - constexpr ScalarType sweep = 360; + static void GeneratePoints( + PointIterType iter, + const size_t numRadial, + const size_t numCapAxial, + const ScalarType radius, + const ScalarType height, + const GfMatrix4d *framePtr = nullptr) + { + constexpr ScalarType sweep = 360; - GeneratePoints(iter, numRadial, numCapAxial, - /* bottomRadius = */ radius, - /* topRadius = */ radius, - height, - /* bottomCapHeight = */ radius, - /* topCapHeight = */ radius, - sweep, framePtr); - } + GeneratePoints(iter, numRadial, numCapAxial, + /* bottomRadius = */ radius, + /* topRadius = */ radius, + height, + /* bottomCapHeight = */ radius, + /* topCapHeight = */ radius, + sweep, framePtr); + } - template::type> - static void GeneratePoints( - PointIterType iter, - const size_t numRadial, - const size_t numCapAxial, - const ScalarType bottomRadius, - const ScalarType topRadius, - const ScalarType height, - const ScalarType bottomCapHeight, - const ScalarType topCapHeight, - const ScalarType sweepDegrees, - const GfMatrix4d* framePtr = nullptr) - { - using PointType = - typename std::iterator_traits::value_type; + static void GeneratePoints( + PointIterType iter, + const size_t numRadial, + const size_t numCapAxial, + const ScalarType bottomRadius, + const ScalarType topRadius, + const ScalarType height, + const ScalarType bottomCapHeight, + const ScalarType topCapHeight, + const ScalarType sweepDegrees, + const GfMatrix4d *framePtr = nullptr) + { + using PointType = + typename std::iterator_traits::value_type; - _GeneratePointsImpl(numRadial, numCapAxial, bottomRadius, topRadius, - height, bottomCapHeight, topCapHeight, sweepDegrees, - framePtr ? _PointWriter(iter, framePtr) - : _PointWriter(iter)); - } + _GeneratePointsImpl(numRadial, numCapAxial, bottomRadius, topRadius, + height, bottomCapHeight, topCapHeight, sweepDegrees, + framePtr ? _PointWriter(iter, framePtr) + : _PointWriter(iter)); + } - using GeomUtilMeshGeneratorBase::GeneratePoints; + using GeomUtilMeshGeneratorBase::GeneratePoints; private: - template - static void _GeneratePointsImpl( - const size_t numRadial, - const size_t numCapAxial, - const typename PointType::ScalarType bottomRadius, - const typename PointType::ScalarType topRadius, - const typename PointType::ScalarType height, - const typename PointType::ScalarType bottomCapHeight, - const typename PointType::ScalarType topCapHeight, - const typename PointType::ScalarType sweep, - const _PointWriter& ptWriter); + template + static void _GeneratePointsImpl( + const size_t numRadial, + const size_t numCapAxial, + const typename PointType::ScalarType bottomRadius, + const typename PointType::ScalarType topRadius, + const typename PointType::ScalarType height, + const typename PointType::ScalarType bottomCapHeight, + const typename PointType::ScalarType topCapHeight, + const typename PointType::ScalarType sweep, + const _PointWriter &ptWriter); }; PXR_NAMESPACE_CLOSE_SCOPE diff --git a/Sources/OpenUSD/include/imaging/geomUtil/coneMeshGenerator.h b/Sources/GeomUtil/include/GeomUtil/coneMeshGenerator.h similarity index 58% rename from Sources/OpenUSD/include/imaging/geomUtil/coneMeshGenerator.h rename to Sources/GeomUtil/include/GeomUtil/coneMeshGenerator.h index 522a1fc55e..c1d1e7de45 100644 --- a/Sources/OpenUSD/include/imaging/geomUtil/coneMeshGenerator.h +++ b/Sources/GeomUtil/include/GeomUtil/coneMeshGenerator.h @@ -24,10 +24,10 @@ #ifndef PXR_IMAGING_GEOM_UTIL_CONE_MESH_GENERATOR_H #define PXR_IMAGING_GEOM_UTIL_CONE_MESH_GENERATOR_H -#include "pxr/imaging/geomUtil/api.h" -#include "pxr/imaging/geomUtil/meshGeneratorBase.h" +#include "GeomUtil/api.h" +#include "GeomUtil/meshGeneratorBase.h" -#include "pxr/pxr.h" +#include "pxr/pxrns.h" PXR_NAMESPACE_OPEN_SCOPE @@ -44,7 +44,7 @@ class PxOsdMeshTopology; /// cone as necessary (e.g., whose height is along the Y axis) . /// /// An additional overload of GeneratePoints is provided to specify the sweep -/// angle for the cone about the +Z axis. When the sweep is less than 360 +/// angle for the cone about the +Z axis. When the sweep is less than 360 /// degrees, the generated geometry is not closed. /// /// Usage: @@ -66,64 +66,63 @@ class GeomUtilConeMeshGenerator final : public GeomUtilMeshGeneratorBase { public: - static constexpr size_t minNumRadial = 3; + static constexpr size_t minNumRadial = 3; - GEOMUTIL_API - static size_t ComputeNumPoints( - const size_t numRadial, - const bool closedSweep = true); + GEOMUTIL_API + static size_t ComputeNumPoints( + const size_t numRadial, + const bool closedSweep = true); - GEOMUTIL_API - static PxOsdMeshTopology GenerateTopology( - const size_t numRadial, - const bool closedSweep = true); + GEOMUTIL_API + static PxOsdMeshTopology GenerateTopology( + const size_t numRadial, + const bool closedSweep = true); - template::type> - static void GeneratePoints( - PointIterType iter, - const size_t numRadial, - const ScalarType radius, - const ScalarType height, - const GfMatrix4d* framePtr = nullptr) - { - constexpr ScalarType sweep = 360; - GeneratePoints(iter, numRadial, radius, height, sweep, framePtr); - } + static void GeneratePoints( + PointIterType iter, + const size_t numRadial, + const ScalarType radius, + const ScalarType height, + const GfMatrix4d *framePtr = nullptr) + { + constexpr ScalarType sweep = 360; + GeneratePoints(iter, numRadial, radius, height, sweep, framePtr); + } - template::type> - static void GeneratePoints( - PointIterType iter, - const size_t numRadial, - const ScalarType radius, - const ScalarType height, - const ScalarType sweepDegrees, - const GfMatrix4d* framePtr = nullptr) - { - using PointType = - typename std::iterator_traits::value_type; + static void GeneratePoints( + PointIterType iter, + const size_t numRadial, + const ScalarType radius, + const ScalarType height, + const ScalarType sweepDegrees, + const GfMatrix4d *framePtr = nullptr) + { + using PointType = + typename std::iterator_traits::value_type; - _GeneratePointsImpl(numRadial, radius, height, sweepDegrees, - framePtr ? _PointWriter(iter, framePtr) - : _PointWriter(iter)); - } + _GeneratePointsImpl(numRadial, radius, height, sweepDegrees, + framePtr ? _PointWriter(iter, framePtr) + : _PointWriter(iter)); + } - using GeomUtilMeshGeneratorBase::GeneratePoints; + using GeomUtilMeshGeneratorBase::GeneratePoints; private: - - template - static void _GeneratePointsImpl( - const size_t numRadial, - const typename PointType::ScalarType radius, - const typename PointType::ScalarType height, - const typename PointType::ScalarType sweepDegrees, - const _PointWriter& ptWriter); + template + static void _GeneratePointsImpl( + const size_t numRadial, + const typename PointType::ScalarType radius, + const typename PointType::ScalarType height, + const typename PointType::ScalarType sweepDegrees, + const _PointWriter &ptWriter); }; PXR_NAMESPACE_CLOSE_SCOPE diff --git a/Sources/OpenUSD/include/imaging/geomUtil/cuboidMeshGenerator.h b/Sources/GeomUtil/include/GeomUtil/cuboidMeshGenerator.h similarity index 64% rename from Sources/OpenUSD/include/imaging/geomUtil/cuboidMeshGenerator.h rename to Sources/GeomUtil/include/GeomUtil/cuboidMeshGenerator.h index 29c2260a38..9179983d80 100644 --- a/Sources/OpenUSD/include/imaging/geomUtil/cuboidMeshGenerator.h +++ b/Sources/GeomUtil/include/GeomUtil/cuboidMeshGenerator.h @@ -24,10 +24,10 @@ #ifndef PXR_IMAGING_GEOM_UTIL_CUBOID_MESH_GENERATOR_H #define PXR_IMAGING_GEOM_UTIL_CUBOID_MESH_GENERATOR_H -#include "pxr/imaging/geomUtil/api.h" -#include "pxr/imaging/geomUtil/meshGeneratorBase.h" +#include "GeomUtil/api.h" +#include "GeomUtil/meshGeneratorBase.h" -#include "pxr/pxr.h" +#include "pxr/pxrns.h" PXR_NAMESPACE_OPEN_SCOPE @@ -37,7 +37,7 @@ class PxOsdMeshTopology; /// This class provides an implementation for generating topology and point /// positions on a rectangular cuboid given the dimensions along the X, Y and Z /// axes. The generated cuboid is centered at the origin. -/// +/// /// An optional transform may be provided to GeneratePoints to orient the /// cuboid as necessary. /// @@ -59,41 +59,40 @@ class GeomUtilCuboidMeshGenerator final : public GeomUtilMeshGeneratorBase { public: - GEOMUTIL_API - static size_t ComputeNumPoints(); + GEOMUTIL_API + static size_t ComputeNumPoints(); - GEOMUTIL_API - static PxOsdMeshTopology GenerateTopology(); + GEOMUTIL_API + static PxOsdMeshTopology GenerateTopology(); - template::type> - static void GeneratePoints( - PointIterType iter, - const ScalarType xLength, - const ScalarType yLength, - const ScalarType zLength, - const GfMatrix4d* framePtr = nullptr) - { - using PointType = - typename std::iterator_traits::value_type; + static void GeneratePoints( + PointIterType iter, + const ScalarType xLength, + const ScalarType yLength, + const ScalarType zLength, + const GfMatrix4d *framePtr = nullptr) + { + using PointType = + typename std::iterator_traits::value_type; - _GeneratePointsImpl(xLength, yLength, zLength, - framePtr ? _PointWriter(iter, framePtr) - : _PointWriter(iter)); - } + _GeneratePointsImpl(xLength, yLength, zLength, + framePtr ? _PointWriter(iter, framePtr) + : _PointWriter(iter)); + } - using GeomUtilMeshGeneratorBase::GeneratePoints; + using GeomUtilMeshGeneratorBase::GeneratePoints; private: - - template - static void _GeneratePointsImpl( - const typename PointType::ScalarType xLength, - const typename PointType::ScalarType yLength, - const typename PointType::ScalarType zLength, - const _PointWriter& ptWriter); + template + static void _GeneratePointsImpl( + const typename PointType::ScalarType xLength, + const typename PointType::ScalarType yLength, + const typename PointType::ScalarType zLength, + const _PointWriter &ptWriter); }; PXR_NAMESPACE_CLOSE_SCOPE diff --git a/Sources/OpenUSD/include/imaging/geomUtil/cylinderMeshGenerator.h b/Sources/GeomUtil/include/GeomUtil/cylinderMeshGenerator.h similarity index 57% rename from Sources/OpenUSD/include/imaging/geomUtil/cylinderMeshGenerator.h rename to Sources/GeomUtil/include/GeomUtil/cylinderMeshGenerator.h index 33cd7a4516..b1a6e1901f 100644 --- a/Sources/OpenUSD/include/imaging/geomUtil/cylinderMeshGenerator.h +++ b/Sources/GeomUtil/include/GeomUtil/cylinderMeshGenerator.h @@ -24,10 +24,10 @@ #ifndef PXR_IMAGING_GEOM_UTIL_CYLINDER_MESH_GENERATOR_H #define PXR_IMAGING_GEOM_UTIL_CYLINDER_MESH_GENERATOR_H -#include "pxr/imaging/geomUtil/api.h" -#include "pxr/imaging/geomUtil/meshGeneratorBase.h" +#include "GeomUtil/api.h" +#include "GeomUtil/meshGeneratorBase.h" -#include "pxr/pxr.h" +#include "pxr/pxrns.h" PXR_NAMESPACE_OPEN_SCOPE @@ -45,7 +45,7 @@ class PxOsdMeshTopology; /// /// An additional overload of GeneratePoints is provided to specify different /// radii for the bottom and top discs of the cylinder and a sweep angle for -/// cylinder about the +Z axis. When the sweep is less than 360 degrees, the +/// cylinder about the +Z axis. When the sweep is less than 360 degrees, the /// generated geometry is not closed. /// /// \note Setting one radius to 0 in order to get a cone is inefficient and @@ -71,71 +71,70 @@ class GeomUtilCylinderMeshGenerator final : public GeomUtilMeshGeneratorBase { public: - static constexpr size_t minNumRadial = 3; + static constexpr size_t minNumRadial = 3; - GEOMUTIL_API - static size_t ComputeNumPoints( - const size_t numRadial, - const bool closedSweep = true); + GEOMUTIL_API + static size_t ComputeNumPoints( + const size_t numRadial, + const bool closedSweep = true); - GEOMUTIL_API - static PxOsdMeshTopology GenerateTopology( - const size_t numRadial, - const bool closedSweep = true); + GEOMUTIL_API + static PxOsdMeshTopology GenerateTopology( + const size_t numRadial, + const bool closedSweep = true); - template::type> - static void GeneratePoints( - PointIterType iter, - const size_t numRadial, - const ScalarType radius, - const ScalarType height, - const GfMatrix4d* framePtr = nullptr) - { - constexpr ScalarType sweep = 360; + static void GeneratePoints( + PointIterType iter, + const size_t numRadial, + const ScalarType radius, + const ScalarType height, + const GfMatrix4d *framePtr = nullptr) + { + constexpr ScalarType sweep = 360; - GeneratePoints(iter, numRadial, - /* bottomRadius = */ radius, - /* topRadius = */ radius, - height, sweep, framePtr); - } + GeneratePoints(iter, numRadial, + /* bottomRadius = */ radius, + /* topRadius = */ radius, + height, sweep, framePtr); + } - template::type> - static void GeneratePoints( - PointIterType iter, - const size_t numRadial, - const ScalarType bottomRadius, - const ScalarType topRadius, - const ScalarType height, - const ScalarType sweepDegrees, - const GfMatrix4d* framePtr = nullptr) - { - using PointType = - typename std::iterator_traits::value_type; + static void GeneratePoints( + PointIterType iter, + const size_t numRadial, + const ScalarType bottomRadius, + const ScalarType topRadius, + const ScalarType height, + const ScalarType sweepDegrees, + const GfMatrix4d *framePtr = nullptr) + { + using PointType = + typename std::iterator_traits::value_type; - _GeneratePointsImpl(numRadial, bottomRadius, topRadius, height, - sweepDegrees, - framePtr ? _PointWriter(iter, framePtr) - : _PointWriter(iter)); - } + _GeneratePointsImpl(numRadial, bottomRadius, topRadius, height, + sweepDegrees, + framePtr ? _PointWriter(iter, framePtr) + : _PointWriter(iter)); + } - using GeomUtilMeshGeneratorBase::GeneratePoints; + using GeomUtilMeshGeneratorBase::GeneratePoints; private: - - template - static void _GeneratePointsImpl( - const size_t numRadial, - const typename PointType::ScalarType bottomRadius, - const typename PointType::ScalarType topRadius, - const typename PointType::ScalarType height, - const typename PointType::ScalarType sweep, - const _PointWriter& ptWriter); + template + static void _GeneratePointsImpl( + const size_t numRadial, + const typename PointType::ScalarType bottomRadius, + const typename PointType::ScalarType topRadius, + const typename PointType::ScalarType height, + const typename PointType::ScalarType sweep, + const _PointWriter &ptWriter); }; PXR_NAMESPACE_CLOSE_SCOPE diff --git a/Sources/GeomUtil/include/GeomUtil/meshGeneratorBase.h b/Sources/GeomUtil/include/GeomUtil/meshGeneratorBase.h new file mode 100644 index 0000000000..8a3cee612a --- /dev/null +++ b/Sources/GeomUtil/include/GeomUtil/meshGeneratorBase.h @@ -0,0 +1,244 @@ +// +// Copyright 2022 Pixar +// +// Licensed under the Apache License, Version 2.0 (the "Apache License") +// with the following modification; you may not use this file except in +// compliance with the Apache License and the following modification to it: +// Section 6. Trademarks. is deleted and replaced with: +// +// 6. Trademarks. This License does not grant permission to use the trade +// names, trademarks, service marks, or product names of the Licensor +// and its affiliates, except as required to comply with Section 4(c) of +// the License and to reproduce the content of the NOTICE file. +// +// You may obtain a copy of the Apache License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the Apache License with the above modification is +// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the Apache License for the specific +// language governing permissions and limitations under the Apache License. +// +#ifndef PXR_IMAGING_GEOM_UTIL_MESH_GENERATOR_BASE_H +#define PXR_IMAGING_GEOM_UTIL_MESH_GENERATOR_BASE_H + +#include "GeomUtil/api.h" + +#include "Gf/matrix4d.h" +#include "Gf/vec3d.h" +#include "Gf/vec3f.h" + +#include "pxr/pxrns.h" + +#include +#include + +PXR_NAMESPACE_OPEN_SCOPE + +class PxOsdMeshTopology; + +/// This class provides common implementation for the different mesh generator +/// classes in GeomUtil. As the mesh generators are entirely implemented as +/// static functions, this "base class" is more of a grouping and access control +/// mechanism than a base class in the polymorphic sense. +/// +/// The mesh generator subclasses all follow a common pattern, providing static +/// methods for generating topology and point positions for their specific +/// geometric primitive. The data produced by these classes is only guaranteed +/// to be suitable for imaging the described surface; it is only one of many +/// possible interpretations of the surface, and should not be relied upon for +/// any other use. The generators may e.g. change the topology or ordering of +/// the produced data at any time. In short: these utilities are meant only to +/// be used to produce a blob of semi-blind data, for feeding to an imager that +/// supports PxOsdMeshTopology. +/// +/// The generators make use of templates and SFINAE to allow clients to pass any +/// output iterator that dereferences to either a GfVec3f or GfVec3d to their +/// GeneratePoints(...) method, and internally perform compile-time type erasure +/// in order to allow the implementations of their algorithms to be private +/// implementation detail, not defined in the headers. Although it's expected +/// that clients will typically want their point data in VtVec3fArray, the +/// described implementation was chosen to minimize the chance that any +/// prospective client with unusual data management requirements would be unable +/// to make use of the generators, or would be forced to resort to a container +/// copy in order to do so. +/// +/// The only public API on this class is a static GeneratePoints(...) template +/// method, intended to be added by subclasses to their GeneratePoints(...) +/// overload sets. It serves as the "error case" for callers that attempt to +/// pass iterators of unsupported types to the GeneratePoints(...) methods each +/// subclass declares. As all generator subclasses have this possibility and +/// the implementation requires SFINAE, it's implemented here and shared between +/// all subclasses. However, it's important that subclasses explicitly include +/// a "using" statement for the fallback to be included in overload resolution. +/// +class GeomUtilMeshGeneratorBase +{ +private: + // Delete the implicit default c'tor. This class and its subclasses are + // only for grouping; there's never any need to make instances. + GeomUtilMeshGeneratorBase() = delete; + +protected: + // SFINAE helper types, for more compact and readable template shenanigans + // in the subclasses. + template + struct _IsGfVec3Iterator + { + using PointType = typename std::iterator_traits::value_type; + static constexpr bool value = + std::is_same::value || + std::is_same::value; + }; + + template + struct _EnableIfGfVec3Iterator + : public std::enable_if<_IsGfVec3Iterator::value, void> + { + }; + + template + struct _EnableIfNotGfVec3Iterator + : public std::enable_if::value, void> + { + }; + + // Helper struct to provide iterator type erasure, allowing subclasses to + // implement their GeneratePoints methods privately. Usage doesn't require + // any heap allocation or virtual dispatch/runtime typing. In addition to + // erasing the iterator type, this also provides a convenient way to allow + // subclasses to offer GeneratePoints methods that can apply an additional + // frame transform without having to actually plumb that detail into the + // guts of their point generator code. + // + // Note: Ensuring the interoperability of the PointType with the IterType + // used at construction is the responsibility of the client. It's typically + // guaranteed by the client deriving PointType from IterType; see subclass + // use for examples and how they guarantee IterType dereferences to a + // supportable point type. + template + struct _PointWriter + { + template + _PointWriter( + IterType &iter) + : _writeFnPtr(&_PointWriter::_WritePoint), _untypedIterPtr(static_cast(&iter)) + { + } + + template + _PointWriter( + IterType &iter, + const GfMatrix4d *const framePtr) + : _writeFnPtr( + &_PointWriter::_TransformAndWritePoint), + _untypedIterPtr(static_cast(&iter)), _framePtr(framePtr) + { + } + + void Write( + const PointType &pt) const + { + (this->*_writeFnPtr)(pt); + } + + private: + template + void _WritePoint( + const PointType &pt) const + { + IterType &iter = *static_cast(_untypedIterPtr); + *iter = pt; + ++iter; + } + + template + void _TransformAndWritePoint( + const PointType &pt) const + { + IterType &iter = *static_cast(_untypedIterPtr); + *iter = _framePtr->Transform(pt); + ++iter; + } + + using _WriteFnPtr = + void (_PointWriter::*)(const PointType &) const; + _WriteFnPtr _writeFnPtr; + void *_untypedIterPtr; + const GfMatrix4d *_framePtr; + }; + + // Common topology helper method. + // + // Several of the subclasses make use of a common topology, specifically "a + // triangle fan around a 'bottom' point, some number of quad strips forming + // rings with shared edges, and another triangle fan surrounding a 'top' + // point." The two triangle fans can be considered "caps" on a "tube" of + // linked quad strips. This triangle fans + quad strips topology also + // describes the latitude/longitude topology of the globe, as another + // example. + // + // Because we currently rely on downstream machinery to infer surface + // normals from the topology, we sometimes want the "caps" to share their + // edge-ring with the adjacent quad strip, and other times need that edge- + // ring to not be shared between the "cap" and "body" surfaces. The edges + // are coincident in space but the surface is not continuous across that + // edge. + // + // Subclasses specify the "cap" conditions they require to support the + // surface-continuity condition described above, and other uses where a + // "cap" is not needed (e.g. the point-end of a cone). + // + // Subclasses also specify whether the surface is closed or open. This + // is typically exposed via a sweep parameter, wherein a sweep of a multiple + // of 2 * pi results in a "closed" surface. The generated points and by + // extension, the generated topology, differs for "open" and "closed" + // surfaces. + // + enum _CapStyle + { + CapStyleNone, + CapStyleSharedEdge, + CapStyleSeparateEdge + }; + + static PxOsdMeshTopology _GenerateCappedQuadTopology( + const size_t numRadial, + const size_t numQuadStrips, + const _CapStyle bottomCapStyle, + const _CapStyle topCapStyle, + const bool closedSweep); + + // Subclasses that use the topology helper method above generate one or more + // circular arcs during point generation. The number of radial points on + // each arc depends on the number of radial segments and whether the arc + // is fully swept (i.e., a ring). + static size_t _ComputeNumRadialPoints( + const size_t numRadial, + const bool closedSweep); + +public: + // This template provides a "fallback" for GeneratePoints(...) calls that + // do not meet the SFINAE requirement that the given point-container- + // iterator must dereference to a GfVec3f or GfVec3d. This version + // generates a helpful compile time assertion in such a scenario. As noted + // earlier, subclasses should explicitly add a "using" statement with + // this method to include it in overload resolution. + // + template ::type> + static void GeneratePoints( + PointIterType iter, ...) + { + static_assert(_IsGfVec3Iterator::value, + "This function only supports iterators to GfVec3f or GfVec3d " + "objects."); + } +}; + +PXR_NAMESPACE_CLOSE_SCOPE + +#endif // PXR_IMAGING_GEOM_UTIL_MESH_GENERATOR_BASE_H diff --git a/Sources/OpenUSD/include/imaging/geomUtil/sphereMeshGenerator.h b/Sources/GeomUtil/include/GeomUtil/sphereMeshGenerator.h similarity index 57% rename from Sources/OpenUSD/include/imaging/geomUtil/sphereMeshGenerator.h rename to Sources/GeomUtil/include/GeomUtil/sphereMeshGenerator.h index 8393fd842c..97954e4b86 100644 --- a/Sources/OpenUSD/include/imaging/geomUtil/sphereMeshGenerator.h +++ b/Sources/GeomUtil/include/GeomUtil/sphereMeshGenerator.h @@ -24,10 +24,10 @@ #ifndef PXR_IMAGING_GEOM_UTIL_SPHERE_MESH_GENERATOR_H #define PXR_IMAGING_GEOM_UTIL_SPHERE_MESH_GENERATOR_H -#include "pxr/imaging/geomUtil/api.h" -#include "pxr/imaging/geomUtil/meshGeneratorBase.h" +#include "GeomUtil/api.h" +#include "GeomUtil/meshGeneratorBase.h" -#include "pxr/pxr.h" +#include "pxr/pxrns.h" PXR_NAMESPACE_OPEN_SCOPE @@ -37,7 +37,7 @@ class PxOsdMeshTopology; /// This class provides an implementation for generating topology and point /// positions on a sphere with a given radius. The sphere is made up of /// circular cross-sections in the XY plane and is centered at the origin. -/// Each cross-section has numRadial segments. Successive cross-sections are +/// Each cross-section has numRadial segments. Successive cross-sections are /// generated at numAxial locations along the Z axis, with the bottom of the /// sphere at Z = -r and top at Z = r. /// @@ -45,7 +45,7 @@ class PxOsdMeshTopology; /// sphere as necessary (e.g., cross-sections in the YZ plane). /// /// An additional overload of GeneratePoints is provided to specify a sweep -/// angle for the sphere about the +Z axis. When the sweep is less than 360 +/// angle for the sphere about the +Z axis. When the sweep is less than 360 /// degrees, the generated geometry is not closed. /// /// Usage: @@ -67,67 +67,66 @@ class GeomUtilSphereMeshGenerator final : public GeomUtilMeshGeneratorBase { public: - static constexpr size_t minNumRadial = 3; - static constexpr size_t minNumAxial = 2; + static constexpr size_t minNumRadial = 3; + static constexpr size_t minNumAxial = 2; - GEOMUTIL_API - static size_t ComputeNumPoints( - const size_t numRadial, - const size_t numAxial, - const bool closedSweep = true); + GEOMUTIL_API + static size_t ComputeNumPoints( + const size_t numRadial, + const size_t numAxial, + const bool closedSweep = true); - GEOMUTIL_API - static PxOsdMeshTopology GenerateTopology( - const size_t numRadial, - const size_t numAxial, - const bool closedSweep = true); + GEOMUTIL_API + static PxOsdMeshTopology GenerateTopology( + const size_t numRadial, + const size_t numAxial, + const bool closedSweep = true); - template::type> - static void GeneratePoints( - PointIterType iter, - const size_t numRadial, - const size_t numAxial, - const ScalarType radius, - const GfMatrix4d* framePtr = nullptr) - { - constexpr ScalarType sweep = 360; - GeneratePoints(iter, numRadial, numAxial, radius, sweep, framePtr); - } + static void GeneratePoints( + PointIterType iter, + const size_t numRadial, + const size_t numAxial, + const ScalarType radius, + const GfMatrix4d *framePtr = nullptr) + { + constexpr ScalarType sweep = 360; + GeneratePoints(iter, numRadial, numAxial, radius, sweep, framePtr); + } - template::type> - static void GeneratePoints( - PointIterType iter, - const size_t numRadial, - const size_t numAxial, - const ScalarType radius, - const ScalarType sweepDegrees, - const GfMatrix4d* framePtr = nullptr) - { - using PointType = - typename std::iterator_traits::value_type; + static void GeneratePoints( + PointIterType iter, + const size_t numRadial, + const size_t numAxial, + const ScalarType radius, + const ScalarType sweepDegrees, + const GfMatrix4d *framePtr = nullptr) + { + using PointType = + typename std::iterator_traits::value_type; - _GeneratePointsImpl(numRadial, numAxial, radius, sweepDegrees, - framePtr ? _PointWriter(iter, framePtr) - : _PointWriter(iter)); - } + _GeneratePointsImpl(numRadial, numAxial, radius, sweepDegrees, + framePtr ? _PointWriter(iter, framePtr) + : _PointWriter(iter)); + } - using GeomUtilMeshGeneratorBase::GeneratePoints; + using GeomUtilMeshGeneratorBase::GeneratePoints; private: - - template - static void _GeneratePointsImpl( - const size_t numRadial, - const size_t numAxial, - const typename PointType::ScalarType radius, - const typename PointType::ScalarType sweepDegrees, - const _PointWriter& ptWriter); + template + static void _GeneratePointsImpl( + const size_t numRadial, + const size_t numAxial, + const typename PointType::ScalarType radius, + const typename PointType::ScalarType sweepDegrees, + const _PointWriter &ptWriter); }; PXR_NAMESPACE_CLOSE_SCOPE diff --git a/Sources/GeomUtil/meshGeneratorBase.cpp b/Sources/GeomUtil/meshGeneratorBase.cpp new file mode 100644 index 0000000000..71b2c17866 --- /dev/null +++ b/Sources/GeomUtil/meshGeneratorBase.cpp @@ -0,0 +1,135 @@ +// +// Copyright 2022 Pixar +// +// Licensed under the Apache License, Version 2.0 (the "Apache License") +// with the following modification; you may not use this file except in +// compliance with the Apache License and the following modification to it: +// Section 6. Trademarks. is deleted and replaced with: +// +// 6. Trademarks. This License does not grant permission to use the trade +// names, trademarks, service marks, or product names of the Licensor +// and its affiliates, except as required to comply with Section 4(c) of +// the License and to reproduce the content of the NOTICE file. +// +// You may obtain a copy of the Apache License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the Apache License with the above modification is +// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the Apache License for the specific +// language governing permissions and limitations under the Apache License. +// +#include "GeomUtil/meshGeneratorBase.h" + +#include "PxOsd/meshTopology.h" +#include "PxOsd/tokens.h" + +#include "Tf/diagnostic.h" +#include "Vt/types.h" + +PXR_NAMESPACE_OPEN_SCOPE + +// static +PxOsdMeshTopology +GeomUtilMeshGeneratorBase::_GenerateCappedQuadTopology( + const size_t numRadial, + const size_t numQuadStrips, + const GeomUtilMeshGeneratorBase::_CapStyle bottomCapStyle, + const GeomUtilMeshGeneratorBase::_CapStyle topCapStyle, + const bool closedSweep) +{ + if (numRadial < 3) + { + TF_CODING_ERROR("Invalid topology requested."); + return PxOsdMeshTopology(); + } + + const size_t numTriStrips = + (bottomCapStyle != CapStyleNone) + (topCapStyle != CapStyleNone); + const size_t numTris = numTriStrips * numRadial; + const size_t numQuads = numQuadStrips * numRadial; + + VtIntArray countsArray(numQuads + numTris); + VtIntArray indicesArray((4 * numQuads) + (3 * numTris)); + + // NOTE: When the surface is closed (sweep of 360 degrees), we ensure that + // the start and end points of each circular ring point are the same + // topologically. This in turn means that the number of points on a + // (closed) ring is one less than an (open) arc. + const size_t numRadialPts = _ComputeNumRadialPoints(numRadial, closedSweep); + size_t ptIdx = 0; + int *countsIt = countsArray.data(); + int *indicesIt = indicesArray.data(); + + // Bottom triangle fan, if requested: + if (bottomCapStyle != CapStyleNone) + { + size_t bottomPtIdx = ptIdx++; + for (size_t radIdx = 0; radIdx < numRadial; ++radIdx) + { + *countsIt++ = 3; + *indicesIt++ = ptIdx + ((radIdx + 1) % numRadialPts); + *indicesIt++ = ptIdx + radIdx; + *indicesIt++ = bottomPtIdx; + } + // Adjust the point index cursor if the edge isn't to be shared with the + // following quad strip. + if (bottomCapStyle == CapStyleSeparateEdge) + { + ptIdx += numRadialPts; + } + } + + // Middle quads: + for (size_t stripIdx = 0; stripIdx < numQuadStrips; ++stripIdx) + { + for (size_t radIdx = 0; radIdx < numRadial; ++radIdx) + { + *countsIt++ = 4; + *indicesIt++ = ptIdx + radIdx; + *indicesIt++ = ptIdx + ((radIdx + 1) % numRadialPts); + *indicesIt++ = ptIdx + ((radIdx + 1) % numRadialPts) + numRadialPts; + *indicesIt++ = ptIdx + radIdx + numRadialPts; + } + ptIdx += numRadialPts; + } + + // Top triangle fan, if requested: + if (topCapStyle != CapStyleNone) + { + // Adjust the point index cursor if the edge isn't to be shared with the + // preceeding quad strip. + if (topCapStyle == CapStyleSeparateEdge) + { + ptIdx += numRadialPts; + } + size_t topPtIdx = ptIdx + numRadialPts; + for (size_t radIdx = 0; radIdx < numRadial; ++radIdx) + { + *countsIt++ = 3; + *indicesIt++ = ptIdx + radIdx; + *indicesIt++ = ptIdx + ((radIdx + 1) % numRadialPts); + *indicesIt++ = topPtIdx; + } + } + + return PxOsdMeshTopology( + PxOsdOpenSubdivTokens->catmullClark, + PxOsdOpenSubdivTokens->rightHanded, + countsArray, indicesArray); +} + +// static +size_t +GeomUtilMeshGeneratorBase::_ComputeNumRadialPoints( + const size_t numRadial, + const bool closedSweep) +{ + // For a ring, the first and last points are the same. For topological + // correctness, do not regenerate the same point. + return closedSweep ? numRadial : numRadial + 1; +} + +PXR_NAMESPACE_CLOSE_SCOPE \ No newline at end of file diff --git a/Sources/OpenUSD/imaging/geomUtil/sphereMeshGenerator.cpp b/Sources/GeomUtil/sphereMeshGenerator.cpp similarity index 86% rename from Sources/OpenUSD/imaging/geomUtil/sphereMeshGenerator.cpp rename to Sources/GeomUtil/sphereMeshGenerator.cpp index 1c435623ba..2c372f283f 100644 --- a/Sources/OpenUSD/imaging/geomUtil/sphereMeshGenerator.cpp +++ b/Sources/GeomUtil/sphereMeshGenerator.cpp @@ -21,13 +21,13 @@ // KIND, either express or implied. See the Apache License for the specific // language governing permissions and limitations under the Apache License. // -#include "pxr/imaging/geomUtil/sphereMeshGenerator.h" +#include "GeomUtil/sphereMeshGenerator.h" -#include "pxr/imaging/pxOsd/meshTopology.h" -#include "pxr/imaging/pxOsd/tokens.h" +#include "PxOsd/meshTopology.h" +#include "PxOsd/tokens.h" -#include "pxr/base/arch/pxrmath.h" -#include "pxr/base/vt/types.h" +#include "Arch/pxrmath.h" +#include "Vt/types.h" #include #include @@ -39,8 +39,10 @@ PXR_NAMESPACE_OPEN_SCOPE // static size_t GeomUtilSphereMeshGenerator::ComputeNumPoints(const size_t numRadial, const size_t numAxial, - const bool closedSweep) { - if ((numRadial < minNumRadial) || (numAxial < minNumAxial)) { + const bool closedSweep) +{ + if ((numRadial < minNumRadial) || (numAxial < minNumAxial)) + { return 0; } @@ -52,8 +54,10 @@ size_t GeomUtilSphereMeshGenerator::ComputeNumPoints(const size_t numRadial, // static PxOsdMeshTopology GeomUtilSphereMeshGenerator::GenerateTopology( - const size_t numRadial, const size_t numAxial, const bool closedSweep) { - if ((numRadial < minNumRadial) || (numAxial < minNumAxial)) { + const size_t numRadial, const size_t numAxial, const bool closedSweep) +{ + if ((numRadial < minNumRadial) || (numAxial < minNumAxial)) + { return PxOsdMeshTopology(); } @@ -70,10 +74,12 @@ void GeomUtilSphereMeshGenerator::_GeneratePointsImpl( const size_t numRadial, const size_t numAxial, const typename PointType::ScalarType radius, const typename PointType::ScalarType sweepDegrees, - const _PointWriter &ptWriter) { + const _PointWriter &ptWriter) +{ using ScalarType = typename PointType::ScalarType; - if ((numRadial < minNumRadial) || (numAxial < minNumAxial)) { + if ((numRadial < minNumRadial) || (numAxial < minNumAxial)) + { return; } @@ -87,7 +93,8 @@ void GeomUtilSphereMeshGenerator::_GeneratePointsImpl( _ComputeNumRadialPoints(numRadial, closedSweep); std::vector> ringXY(numRadialPoints); - for (size_t radIdx = 0; radIdx < numRadialPoints; ++radIdx) { + for (size_t radIdx = 0; radIdx < numRadialPoints; ++radIdx) + { // Longitude range: [0, sweep] const ScalarType longAngle = (ScalarType(radIdx) / ScalarType(numRadial)) * sweepRadians; @@ -99,7 +106,8 @@ void GeomUtilSphereMeshGenerator::_GeneratePointsImpl( ptWriter.Write(PointType(0.0, 0.0, -radius)); // Latitude rings: - for (size_t axIdx = 1; axIdx < numAxial; ++axIdx) { + for (size_t axIdx = 1; axIdx < numAxial; ++axIdx) + { // Latitude range: (-0.5pi, 0.5pi) const ScalarType latAngle = ((ScalarType(axIdx) / ScalarType(numAxial)) - 0.5) * M_PI; @@ -107,7 +115,8 @@ void GeomUtilSphereMeshGenerator::_GeneratePointsImpl( const ScalarType radScale = cos(latAngle); const ScalarType latitude = radius * sin(latAngle); - for (size_t radIdx = 0; radIdx < numRadialPoints; ++radIdx) { + for (size_t radIdx = 0; radIdx < numRadialPoints; ++radIdx) + { ptWriter.Write(PointType(radScale * ringXY[radIdx][0], radScale * ringXY[radIdx][1], latitude)); } diff --git a/Sources/OpenUSD/imaging/geomUtil/CMakeLists.txt b/Sources/OpenUSD/imaging/geomUtil/CMakeLists.txt deleted file mode 100644 index 0c1fefab9d..0000000000 --- a/Sources/OpenUSD/imaging/geomUtil/CMakeLists.txt +++ /dev/null @@ -1,57 +0,0 @@ -set(PXR_PREFIX pxr/imaging) -set(PXR_PACKAGE geomUtil) - -pxr_library(geomUtil - LIBRARIES - arch - gf - tf - vt - pxOsd - - PUBLIC_CLASSES - capsuleMeshGenerator - coneMeshGenerator - cuboidMeshGenerator - cylinderMeshGenerator - meshGeneratorBase - sphereMeshGenerator - - PYTHON_CPPFILES - moduleDeps.cpp - - PUBLIC_HEADERS - api.h - - PYMODULE_CPPFILES - module.cpp - wrapCapsuleMeshGenerator.cpp - wrapConeMeshGenerator.cpp - wrapCuboidMeshGenerator.cpp - wrapCylinderMeshGenerator.cpp - wrapSphereMeshGenerator.cpp - - PYMODULE_FILES - __init__.py -) - -pxr_build_test(testMeshGenerators - LIBRARIES - gf - tf - vt - geomUtil - pxOsd - CPPFILES - testenv/testMeshGenerators.cpp -) - -pxr_install_test_dir( - SRC testenv/testMeshGenerators - DEST testMeshGenerators -) - -pxr_register_test(testMeshGenerators - COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testMeshGenerators" - DIFF_COMPARE generatedMeshes_closed.txt generatedMeshes_open.txt -) \ No newline at end of file diff --git a/Sources/OpenUSD/imaging/geomUtil/meshGeneratorBase.cpp b/Sources/OpenUSD/imaging/geomUtil/meshGeneratorBase.cpp deleted file mode 100644 index 7b486b077d..0000000000 --- a/Sources/OpenUSD/imaging/geomUtil/meshGeneratorBase.cpp +++ /dev/null @@ -1,127 +0,0 @@ -// -// Copyright 2022 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#include "pxr/imaging/geomUtil/meshGeneratorBase.h" - -#include "pxr/imaging/pxOsd/meshTopology.h" -#include "pxr/imaging/pxOsd/tokens.h" - -#include "pxr/base/tf/diagnostic.h" -#include "pxr/base/vt/types.h" - -PXR_NAMESPACE_OPEN_SCOPE - - -// static -PxOsdMeshTopology -GeomUtilMeshGeneratorBase::_GenerateCappedQuadTopology( - const size_t numRadial, - const size_t numQuadStrips, - const GeomUtilMeshGeneratorBase::_CapStyle bottomCapStyle, - const GeomUtilMeshGeneratorBase::_CapStyle topCapStyle, - const bool closedSweep) -{ - if (numRadial < 3) { - TF_CODING_ERROR("Invalid topology requested."); - return PxOsdMeshTopology(); - } - - const size_t numTriStrips = - (bottomCapStyle != CapStyleNone) + (topCapStyle != CapStyleNone); - const size_t numTris = numTriStrips * numRadial; - const size_t numQuads = numQuadStrips * numRadial; - - VtIntArray countsArray(numQuads + numTris); - VtIntArray indicesArray((4 * numQuads) + (3 * numTris)); - - // NOTE: When the surface is closed (sweep of 360 degrees), we ensure that - // the start and end points of each circular ring point are the same - // topologically. This in turn means that the number of points on a - // (closed) ring is one less than an (open) arc. - const size_t numRadialPts = _ComputeNumRadialPoints(numRadial, closedSweep); - size_t ptIdx = 0; - int* countsIt = countsArray.data(); - int* indicesIt = indicesArray.data(); - - // Bottom triangle fan, if requested: - if (bottomCapStyle != CapStyleNone) { - size_t bottomPtIdx = ptIdx++; - for (size_t radIdx = 0; radIdx < numRadial; ++radIdx) { - *countsIt++ = 3; - *indicesIt++ = ptIdx + ((radIdx + 1) % numRadialPts); - *indicesIt++ = ptIdx + radIdx; - *indicesIt++ = bottomPtIdx; - } - // Adjust the point index cursor if the edge isn't to be shared with the - // following quad strip. - if (bottomCapStyle == CapStyleSeparateEdge) { - ptIdx += numRadialPts; - } - } - - // Middle quads: - for (size_t stripIdx = 0; stripIdx < numQuadStrips; ++stripIdx) { - for (size_t radIdx = 0; radIdx < numRadial; ++radIdx) { - *countsIt++ = 4; - *indicesIt++ = ptIdx + radIdx; - *indicesIt++ = ptIdx + ((radIdx + 1) % numRadialPts); - *indicesIt++ = ptIdx + ((radIdx + 1) % numRadialPts) + numRadialPts; - *indicesIt++ = ptIdx + radIdx + numRadialPts; - } - ptIdx += numRadialPts; - } - - // Top triangle fan, if requested: - if (topCapStyle != CapStyleNone) { - // Adjust the point index cursor if the edge isn't to be shared with the - // preceeding quad strip. - if (topCapStyle == CapStyleSeparateEdge) { - ptIdx += numRadialPts; - } - size_t topPtIdx = ptIdx + numRadialPts; - for (size_t radIdx = 0; radIdx < numRadial; ++radIdx) { - *countsIt++ = 3; - *indicesIt++ = ptIdx + radIdx; - *indicesIt++ = ptIdx + ((radIdx + 1) % numRadialPts); - *indicesIt++ = topPtIdx; - } - } - - return PxOsdMeshTopology( - PxOsdOpenSubdivTokens->catmullClark, - PxOsdOpenSubdivTokens->rightHanded, - countsArray, indicesArray); -} - -// static -size_t -GeomUtilMeshGeneratorBase::_ComputeNumRadialPoints( - const size_t numRadial, - const bool closedSweep) -{ - // For a ring, the first and last points are the same. For topological - // correctness, do not regenerate the same point. - return closedSweep? numRadial : numRadial + 1; -} - -PXR_NAMESPACE_CLOSE_SCOPE \ No newline at end of file diff --git a/Sources/OpenUSD/imaging/hdMtlx/hdMtlx.cpp b/Sources/OpenUSD/imaging/hdMtlx/hdMtlx.cpp index d8db347f63..6232378016 100644 --- a/Sources/OpenUSD/imaging/hdMtlx/hdMtlx.cpp +++ b/Sources/OpenUSD/imaging/hdMtlx/hdMtlx.cpp @@ -32,7 +32,7 @@ #include "pxr/usd/sdf/path.h" #include "pxr/usd/sdr/registry.h" -#include "pxr/base/arch/fileSystem.h" +#include "Arch/fileSystem.h" #include "pxr/base/tf/diagnostic.h" #include "pxr/base/tf/getenv.h" #include "pxr/base/tf/token.h" @@ -50,237 +50,263 @@ PXR_NAMESPACE_OPEN_SCOPE TF_DEFINE_PRIVATE_TOKENS( _tokens, - (index) -); + (index)); static mx::FileSearchPath _ComputeSearchPaths() { - mx::FileSearchPath searchPaths; - static const NdrStringVec searchPathStrings = UsdMtlxSearchPaths(); - for (auto path : searchPathStrings) { - searchPaths.append(mx::FilePath(path)); - } - return searchPaths; + mx::FileSearchPath searchPaths; + static const NdrStringVec searchPathStrings = UsdMtlxSearchPaths(); + for (auto path : searchPathStrings) + { + searchPaths.append(mx::FilePath(path)); + } + return searchPaths; } -const mx::FileSearchPath& +const mx::FileSearchPath & HdMtlxSearchPaths() { - static const mx::FileSearchPath searchPaths = _ComputeSearchPaths(); - return searchPaths; + static const mx::FileSearchPath searchPaths = _ComputeSearchPaths(); + return searchPaths; } // Return the MaterialX Node string with the namespace prepended when present static std::string -_GetMxNodeString(mx::NodeDefPtr const& mxNodeDef) -{ - // If the nodedef is in a namespace, add it to the node string - return mxNodeDef->hasNamespace() - ? mxNodeDef->getNamespace() + ":" + mxNodeDef->getNodeString() - : mxNodeDef->getNodeString(); +_GetMxNodeString(mx::NodeDefPtr const &mxNodeDef) +{ + // If the nodedef is in a namespace, add it to the node string + return mxNodeDef->hasNamespace() + ? mxNodeDef->getNamespace() + ":" + mxNodeDef->getNodeString() + : mxNodeDef->getNodeString(); } -// Return the MaterialX Node Type based on the corresponding NodeDef name, -// which is stored as the hdNodeType. +// Return the MaterialX Node Type based on the corresponding NodeDef name, +// which is stored as the hdNodeType. static TfToken -_GetMxNodeType(mx::DocumentPtr const& mxDoc, TfToken const& hdNodeType) +_GetMxNodeType(mx::DocumentPtr const &mxDoc, TfToken const &hdNodeType) { - mx::NodeDefPtr mxNodeDef = mxDoc->getNodeDef(hdNodeType.GetString()); - if (!mxNodeDef){ - TF_WARN("Unsupported node type '%s' cannot find the associated NodeDef.", - hdNodeType.GetText()); - return TfToken(); - } - - return TfToken(_GetMxNodeString(mxNodeDef)); + mx::NodeDefPtr mxNodeDef = mxDoc->getNodeDef(hdNodeType.GetString()); + if (!mxNodeDef) + { + TF_WARN("Unsupported node type '%s' cannot find the associated NodeDef.", + hdNodeType.GetText()); + return TfToken(); + } + + return TfToken(_GetMxNodeString(mxNodeDef)); } -// Add the mxNode to the mxNodeGraph, or get the mxNode from the NodeGraph +// Add the mxNode to the mxNodeGraph, or get the mxNode from the NodeGraph static mx::NodePtr _AddNodeToNodeGraph( - std::string const& mxNodeName, - std::string const& mxNodeCategory, - std::string const& mxNodeType, - mx::NodeGraphPtr const& mxNodeGraph, - mx::StringSet * addedNodeNames) + std::string const &mxNodeName, + std::string const &mxNodeCategory, + std::string const &mxNodeType, + mx::NodeGraphPtr const &mxNodeGraph, + mx::StringSet *addedNodeNames) { - // Add the node to the mxNodeGraph if needed - if (addedNodeNames->find(mxNodeName) == addedNodeNames->end()) { - addedNodeNames->insert(mxNodeName); - return mxNodeGraph->addNode(mxNodeCategory, mxNodeName, mxNodeType); - } - // Otherwise get the existing node from the mxNodeGraph - return mxNodeGraph->getNode(mxNodeName); + // Add the node to the mxNodeGraph if needed + if (addedNodeNames->find(mxNodeName) == addedNodeNames->end()) + { + addedNodeNames->insert(mxNodeName); + return mxNodeGraph->addNode(mxNodeCategory, mxNodeName, mxNodeType); + } + // Otherwise get the existing node from the mxNodeGraph + return mxNodeGraph->getNode(mxNodeName); } // Convert the HdParameterValue to a string MaterialX can understand -std::string -HdMtlxConvertToString(VtValue const& hdParameterValue) +std::string +HdMtlxConvertToString(VtValue const &hdParameterValue) { - std::ostringstream valStream; - if (hdParameterValue.IsHolding()) { - return hdParameterValue.UncheckedGet() ? "true" : "false"; - } - else if (hdParameterValue.IsHolding() || - hdParameterValue.IsHolding()) { - valStream << hdParameterValue; - return valStream.str(); - } - else if (hdParameterValue.IsHolding()) { - const GfVec2f & value = hdParameterValue.UncheckedGet(); - valStream << value.data()[0] << ", " << value.data()[1]; - return valStream.str(); - } - else if (hdParameterValue.IsHolding()) { - const GfVec3f & value = hdParameterValue.UncheckedGet(); - valStream << value.data()[0] << ", " << value.data()[1] << ", " - << value.data()[2]; - return valStream.str(); - } - else if (hdParameterValue.IsHolding()) { - const GfVec4f & value = hdParameterValue.UncheckedGet(); - valStream << value.data()[0] << ", " << value.data()[1] << ", " - << value.data()[2] << ", " << value.data()[3]; - return valStream.str(); - } - else if (hdParameterValue.IsHolding()) { - const GfMatrix3d & value = hdParameterValue.UncheckedGet(); - valStream << value[0][0] << ", " << value[0][1] << ", " - << value[0][2] << ", " - << value[1][0] << ", " << value[1][1] << ", " - << value[1][2] << ", " - << value[2][0] << ", " << value[2][1] << ", " - << value[2][2] << ", "; - return valStream.str(); - } - else if (hdParameterValue.IsHolding()) { - const GfMatrix4d & value = hdParameterValue.UncheckedGet(); - valStream << value[0][0] << ", " << value[0][1] << ", " - << value[0][2] << ", " << value[0][3] << ", " - << value[1][0] << ", " << value[1][1] << ", " - << value[1][2] << ", " << value[1][3] << ", " - << value[2][0] << ", " << value[2][1] << ", " - << value[2][2] << ", " << value[2][3] << ", " - << value[3][0] << ", " << value[3][1] << ", " - << value[3][2] << ", " << value[3][3] << ", "; - return valStream.str(); - } - else if (hdParameterValue.IsHolding()) { - return hdParameterValue.UncheckedGet().GetAssetPath(); - } - else if (hdParameterValue.IsHolding()) { - return hdParameterValue.UncheckedGet(); - } - else { - TF_WARN("Unsupported Parameter Type '%s'", - hdParameterValue.GetTypeName().c_str()); - return mx::EMPTY_STRING; - } + std::ostringstream valStream; + if (hdParameterValue.IsHolding()) + { + return hdParameterValue.UncheckedGet() ? "true" : "false"; + } + else if (hdParameterValue.IsHolding() || + hdParameterValue.IsHolding()) + { + valStream << hdParameterValue; + return valStream.str(); + } + else if (hdParameterValue.IsHolding()) + { + const GfVec2f &value = hdParameterValue.UncheckedGet(); + valStream << value.data()[0] << ", " << value.data()[1]; + return valStream.str(); + } + else if (hdParameterValue.IsHolding()) + { + const GfVec3f &value = hdParameterValue.UncheckedGet(); + valStream << value.data()[0] << ", " << value.data()[1] << ", " + << value.data()[2]; + return valStream.str(); + } + else if (hdParameterValue.IsHolding()) + { + const GfVec4f &value = hdParameterValue.UncheckedGet(); + valStream << value.data()[0] << ", " << value.data()[1] << ", " + << value.data()[2] << ", " << value.data()[3]; + return valStream.str(); + } + else if (hdParameterValue.IsHolding()) + { + const GfMatrix3d &value = hdParameterValue.UncheckedGet(); + valStream << value[0][0] << ", " << value[0][1] << ", " + << value[0][2] << ", " + << value[1][0] << ", " << value[1][1] << ", " + << value[1][2] << ", " + << value[2][0] << ", " << value[2][1] << ", " + << value[2][2] << ", "; + return valStream.str(); + } + else if (hdParameterValue.IsHolding()) + { + const GfMatrix4d &value = hdParameterValue.UncheckedGet(); + valStream << value[0][0] << ", " << value[0][1] << ", " + << value[0][2] << ", " << value[0][3] << ", " + << value[1][0] << ", " << value[1][1] << ", " + << value[1][2] << ", " << value[1][3] << ", " + << value[2][0] << ", " << value[2][1] << ", " + << value[2][2] << ", " << value[2][3] << ", " + << value[3][0] << ", " << value[3][1] << ", " + << value[3][2] << ", " << value[3][3] << ", "; + return valStream.str(); + } + else if (hdParameterValue.IsHolding()) + { + return hdParameterValue.UncheckedGet().GetAssetPath(); + } + else if (hdParameterValue.IsHolding()) + { + return hdParameterValue.UncheckedGet(); + } + else + { + TF_WARN("Unsupported Parameter Type '%s'", + hdParameterValue.GetTypeName().c_str()); + return mx::EMPTY_STRING; + } } static bool -_ContainsTexcoordNode(mx::NodeDefPtr const& mxNodeDef) +_ContainsTexcoordNode(mx::NodeDefPtr const &mxNodeDef) { - mx::InterfaceElementPtr impl = mxNodeDef->getImplementation(); - if (impl && impl->isA()) { - mx::NodeGraphPtr nodegraph = impl->asA(); - if (nodegraph->getNodes("texcoord").size() != 0) { - return true; - } - } - return false; + mx::InterfaceElementPtr impl = mxNodeDef->getImplementation(); + if (impl && impl->isA()) + { + mx::NodeGraphPtr nodegraph = impl->asA(); + if (nodegraph->getNodes("texcoord").size() != 0) + { + return true; + } + } + return false; } // Add a MaterialX version of the hdNode to the mxDoc/mxNodeGraph -static mx::NodePtr +static mx::NodePtr _AddMaterialXNode( HdMaterialNetworkInterface *netInterface, - TfToken const& hdNodeName, - mx::DocumentPtr const& mxDoc, - mx::NodeGraphPtr const& mxNodeGraph, + TfToken const &hdNodeName, + mx::DocumentPtr const &mxDoc, + mx::NodeGraphPtr const &mxNodeGraph, mx::StringSet *addedNodeNames, - std::string const& connectionName, + std::string const &connectionName, HdMtlxTexturePrimvarData *mxHdData) { - // Get the mxNode information - TfToken hdNodeType = netInterface->GetNodeType(hdNodeName); - mx::NodeDefPtr mxNodeDef = mxDoc->getNodeDef(hdNodeType.GetString()); - if (!mxNodeDef) { - TF_WARN("NodeDef not found for Node '%s'", hdNodeType.GetText()); - return mx::NodePtr(); - } - const SdfPath hdNodePath(hdNodeName.GetString()); - const std::string mxNodeCategory = _GetMxNodeString(mxNodeDef); - const std::string &mxNodeType = mxNodeDef->getType(); - const std::string &mxNodeName = hdNodePath.GetName(); - - // Add the mxNode to the mxNodeGraph - mx::NodePtr mxNode = - _AddNodeToNodeGraph(mxNodeName, mxNodeCategory, - mxNodeType, mxNodeGraph, addedNodeNames); - - if (mxNode->getNodeDef()) { - // Sometimes mxNode->getNodeDef() starts failing. - // It seems to happen when there are connections with mismatched types. - // Explicitly setting the node def string appparently fixes the problem. - // If we don't do this code gen may fail. - if (mxNode->getNodeDefString().empty()) { - mxNode->setNodeDefString(hdNodeType.GetText()); - } - } - - // For each of the HdNode parameters add the corresponding parameter/input - // to the mxNode - TfTokenVector hdNodeParamNames = - netInterface->GetAuthoredNodeParameterNames(hdNodeName); - for (TfToken const ¶mName : hdNodeParamNames) { - // Get the MaterialX Parameter info - const std::string &mxInputName = paramName.GetString(); - std::string mxInputType; - mx::InputPtr mxInput = mxNodeDef->getActiveInput(mxInputName); - if (mxInput) { - mxInputType = mxInput->getType(); - } - std::string mxInputValue = HdMtlxConvertToString( - netInterface->GetNodeParameterValue(hdNodeName, paramName)); - - mxNode->setInputValue(mxInputName, mxInputValue, mxInputType); - } - - // MaterialX nodes that use textures are assumed to have a filename input - if (mxNodeDef->getNodeGroup() == "texture2d") { - if (mxHdData) { - // Save the corresponding MaterialX and Hydra names for ShaderGen - mxHdData->mxHdTextureMap[mxNodeName] = connectionName; - // Save the path to adjust parameters after traversing the network - mxHdData->hdTextureNodes.insert(hdNodePath); - } - } - - // MaterialX primvar node - if (mxNodeCategory == "geompropvalue") { - if (mxHdData) { - // Save the path to have the primvarName declared in ShaderGen - mxHdData->hdPrimvarNodes.insert(hdNodePath); - } - } - - // Stdlib MaterialX texture coordinate node or a custom node that - // uses a texture coordinate node - if (mxNodeCategory == "texcoord" || _ContainsTexcoordNode(mxNodeDef)) { - if (mxHdData) { - // Make sure it has the index parameter set. - if (std::find(hdNodeParamNames.begin(), hdNodeParamNames.end(), - _tokens->index) == hdNodeParamNames.end()) { - netInterface->SetNodeParameterValue( - hdNodeName, _tokens->index, VtValue(0)); - } - // Save the path to have the textureCoord name declared in ShaderGen - mxHdData->hdPrimvarNodes.insert(hdNodePath); - } - } - return mxNode; + // Get the mxNode information + TfToken hdNodeType = netInterface->GetNodeType(hdNodeName); + mx::NodeDefPtr mxNodeDef = mxDoc->getNodeDef(hdNodeType.GetString()); + if (!mxNodeDef) + { + TF_WARN("NodeDef not found for Node '%s'", hdNodeType.GetText()); + return mx::NodePtr(); + } + const SdfPath hdNodePath(hdNodeName.GetString()); + const std::string mxNodeCategory = _GetMxNodeString(mxNodeDef); + const std::string &mxNodeType = mxNodeDef->getType(); + const std::string &mxNodeName = hdNodePath.GetName(); + + // Add the mxNode to the mxNodeGraph + mx::NodePtr mxNode = + _AddNodeToNodeGraph(mxNodeName, mxNodeCategory, + mxNodeType, mxNodeGraph, addedNodeNames); + + if (mxNode->getNodeDef()) + { + // Sometimes mxNode->getNodeDef() starts failing. + // It seems to happen when there are connections with mismatched types. + // Explicitly setting the node def string appparently fixes the problem. + // If we don't do this code gen may fail. + if (mxNode->getNodeDefString().empty()) + { + mxNode->setNodeDefString(hdNodeType.GetText()); + } + } + + // For each of the HdNode parameters add the corresponding parameter/input + // to the mxNode + TfTokenVector hdNodeParamNames = + netInterface->GetAuthoredNodeParameterNames(hdNodeName); + for (TfToken const ¶mName : hdNodeParamNames) + { + // Get the MaterialX Parameter info + const std::string &mxInputName = paramName.GetString(); + std::string mxInputType; + mx::InputPtr mxInput = mxNodeDef->getActiveInput(mxInputName); + if (mxInput) + { + mxInputType = mxInput->getType(); + } + std::string mxInputValue = HdMtlxConvertToString( + netInterface->GetNodeParameterValue(hdNodeName, paramName)); + + mxNode->setInputValue(mxInputName, mxInputValue, mxInputType); + } + + // MaterialX nodes that use textures are assumed to have a filename input + if (mxNodeDef->getNodeGroup() == "texture2d") + { + if (mxHdData) + { + // Save the corresponding MaterialX and Hydra names for ShaderGen + mxHdData->mxHdTextureMap[mxNodeName] = connectionName; + // Save the path to adjust parameters after traversing the network + mxHdData->hdTextureNodes.insert(hdNodePath); + } + } + + // MaterialX primvar node + if (mxNodeCategory == "geompropvalue") + { + if (mxHdData) + { + // Save the path to have the primvarName declared in ShaderGen + mxHdData->hdPrimvarNodes.insert(hdNodePath); + } + } + + // Stdlib MaterialX texture coordinate node or a custom node that + // uses a texture coordinate node + if (mxNodeCategory == "texcoord" || _ContainsTexcoordNode(mxNodeDef)) + { + if (mxHdData) + { + // Make sure it has the index parameter set. + if (std::find(hdNodeParamNames.begin(), hdNodeParamNames.end(), + _tokens->index) == hdNodeParamNames.end()) + { + netInterface->SetNodeParameterValue( + hdNodeName, _tokens->index, VtValue(0)); + } + // Save the path to have the textureCoord name declared in ShaderGen + mxHdData->hdPrimvarNodes.insert(hdNodePath); + } + } + return mxNode; } static void @@ -293,22 +319,25 @@ _AddInput( mx::NodePtr const &mxNextNode, mx::InputPtr *mxInput) { - // If the currNode is connected to a multi-output node, the input on the - // currNode needs to get the output type and indicate the output name. - if (mxNextNode->isMultiOutputType()) { - TfToken hdNextType = netInterface->GetNodeType(conn.upstreamNodeName); - mx::NodeDefPtr mxNextNodeDef = mxDoc->getNodeDef(hdNextType.GetString()); - if (mxNextNodeDef) { - mx::OutputPtr mxConnOutput = mxNextNodeDef->getOutput( - conn.upstreamOutputName.GetString()); - // Add input with the connected Ouptut type and set the output name - *mxInput = mxCurrNode->addInput(inputName, mxConnOutput->getType()); - (*mxInput)->setConnectedOutput(mxConnOutput); - } - } - else { - *mxInput = mxCurrNode->addInput(inputName, mxNextNode->getType()); - } + // If the currNode is connected to a multi-output node, the input on the + // currNode needs to get the output type and indicate the output name. + if (mxNextNode->isMultiOutputType()) + { + TfToken hdNextType = netInterface->GetNodeType(conn.upstreamNodeName); + mx::NodeDefPtr mxNextNodeDef = mxDoc->getNodeDef(hdNextType.GetString()); + if (mxNextNodeDef) + { + mx::OutputPtr mxConnOutput = mxNextNodeDef->getOutput( + conn.upstreamOutputName.GetString()); + // Add input with the connected Ouptut type and set the output name + *mxInput = mxCurrNode->addInput(inputName, mxConnOutput->getType()); + (*mxInput)->setConnectedOutput(mxConnOutput); + } + } + else + { + *mxInput = mxCurrNode->addInput(inputName, mxNextNode->getType()); + } } static void @@ -321,24 +350,27 @@ _AddNodeGraphOutput( mx::NodePtr const &mxNextNode, mx::OutputPtr *mxOutput) { - // If the mxNodeGraph output is connected to a multi-output node, the - // output on the mxNodegraph needs to get the output type from that - // connected node and indicate the output name. - if (mxNextNode->isMultiOutputType()) { - TfToken hdNextType = netInterface->GetNodeType(conn.upstreamNodeName); - mx::NodeDefPtr mxNextNodeDef = mxDoc->getNodeDef(hdNextType.GetString()); - if (mxNextNodeDef) { - mx::OutputPtr mxConnOutput = mxNextNodeDef->getOutput( - conn.upstreamOutputName.GetString()); - // Add output with the connected Ouptut type and set the output name - *mxOutput = mxNodeGraph->addOutput( - outputName, mxConnOutput->getType()); - (*mxOutput)->setOutputString(mxConnOutput->getName()); - } - } - else { - *mxOutput = mxNodeGraph->addOutput(outputName, mxNextNode->getType()); - } + // If the mxNodeGraph output is connected to a multi-output node, the + // output on the mxNodegraph needs to get the output type from that + // connected node and indicate the output name. + if (mxNextNode->isMultiOutputType()) + { + TfToken hdNextType = netInterface->GetNodeType(conn.upstreamNodeName); + mx::NodeDefPtr mxNextNodeDef = mxDoc->getNodeDef(hdNextType.GetString()); + if (mxNextNodeDef) + { + mx::OutputPtr mxConnOutput = mxNextNodeDef->getOutput( + conn.upstreamOutputName.GetString()); + // Add output with the connected Ouptut type and set the output name + *mxOutput = mxNodeGraph->addOutput( + outputName, mxConnOutput->getType()); + (*mxOutput)->setOutputString(mxConnOutput->getName()); + } + } + else + { + *mxOutput = mxNodeGraph->addOutput(outputName, mxNextNode->getType()); + } } // Recursively traverse the material n/w and gather the nodes in the MaterialX @@ -346,92 +378,99 @@ _AddNodeGraphOutput( static void _GatherUpstreamNodes( HdMaterialNetworkInterface *netInterface, - HdMaterialNetworkInterface::InputConnection const& hdConnection, - mx::DocumentPtr const& mxDoc, + HdMaterialNetworkInterface::InputConnection const &hdConnection, + mx::DocumentPtr const &mxDoc, mx::NodeGraphPtr *mxNodeGraph, mx::StringSet *addedNodeNames, mx::NodePtr *mxUpstreamNode, - std::string const& connectionName, + std::string const &connectionName, HdMtlxTexturePrimvarData *mxHdData) { - TfToken const &hdNodeName = hdConnection.upstreamNodeName; - if (netInterface->GetNodeType(hdNodeName).IsEmpty()) { - TF_WARN("Could not find the connected Node '%s'", - hdConnection.upstreamNodeName.GetText()); - return; - } - - // Initilize the mxNodeGraph if needed - if (!(*mxNodeGraph)) { - const std::string nodeGraphName = mxDoc->createValidChildName( - SdfPath(hdNodeName).GetParentPath().GetName()); - *mxNodeGraph = mxDoc->addNodeGraph(nodeGraphName); - } - - // Add the node to the mxNodeGraph/mxDoc. - mx::NodePtr mxCurrNode = - _AddMaterialXNode(netInterface, hdNodeName, mxDoc, *mxNodeGraph, - addedNodeNames, connectionName, mxHdData); - - if (!mxCurrNode) { - return; - } - - TfTokenVector hdConnectionNames = - netInterface->GetNodeInputConnectionNames(hdNodeName); - - // Continue traversing the upsteam connections to create the mxNodeGraph - for (TfToken connName : hdConnectionNames) { - const auto inputConnections = - netInterface->GetNodeInputConnection(hdNodeName, connName); - for (const auto& currConnection : inputConnections) { - // Gather the nodes uptream from the mxCurrNode - _GatherUpstreamNodes( - netInterface, currConnection, mxDoc, mxNodeGraph, - addedNodeNames, mxUpstreamNode, connName.GetString(), mxHdData); - - // Connect mxCurrNode to the mxUpstreamNode - mx::NodePtr mxNextNode = *mxUpstreamNode; - if (!mxNextNode) { - continue; - } - - // Make sure to not add the same input twice - mx::InputPtr mxInput = mxCurrNode->getInput(connName); - if (!mxInput) { - _AddInput(netInterface, currConnection, connName, - mxDoc, mxCurrNode, mxNextNode, &mxInput); - } - mxInput->setConnectedNode(mxNextNode); - } - } - - *mxUpstreamNode = mxCurrNode; + TfToken const &hdNodeName = hdConnection.upstreamNodeName; + if (netInterface->GetNodeType(hdNodeName).IsEmpty()) + { + TF_WARN("Could not find the connected Node '%s'", + hdConnection.upstreamNodeName.GetText()); + return; + } + + // Initilize the mxNodeGraph if needed + if (!(*mxNodeGraph)) + { + const std::string nodeGraphName = mxDoc->createValidChildName( + SdfPath(hdNodeName).GetParentPath().GetName()); + *mxNodeGraph = mxDoc->addNodeGraph(nodeGraphName); + } + + // Add the node to the mxNodeGraph/mxDoc. + mx::NodePtr mxCurrNode = + _AddMaterialXNode(netInterface, hdNodeName, mxDoc, *mxNodeGraph, + addedNodeNames, connectionName, mxHdData); + + if (!mxCurrNode) + { + return; + } + + TfTokenVector hdConnectionNames = + netInterface->GetNodeInputConnectionNames(hdNodeName); + + // Continue traversing the upsteam connections to create the mxNodeGraph + for (TfToken connName : hdConnectionNames) + { + const auto inputConnections = + netInterface->GetNodeInputConnection(hdNodeName, connName); + for (const auto &currConnection : inputConnections) + { + // Gather the nodes uptream from the mxCurrNode + _GatherUpstreamNodes( + netInterface, currConnection, mxDoc, mxNodeGraph, + addedNodeNames, mxUpstreamNode, connName.GetString(), mxHdData); + + // Connect mxCurrNode to the mxUpstreamNode + mx::NodePtr mxNextNode = *mxUpstreamNode; + if (!mxNextNode) + { + continue; + } + + // Make sure to not add the same input twice + mx::InputPtr mxInput = mxCurrNode->getInput(connName); + if (!mxInput) + { + _AddInput(netInterface, currConnection, connName, + mxDoc, mxCurrNode, mxNextNode, &mxInput); + } + mxInput->setConnectedNode(mxNextNode); + } + } + + *mxUpstreamNode = mxCurrNode; } // Create a MaterialX Document from the given HdMaterialNetwork2 -mx::DocumentPtr +mx::DocumentPtr HdMtlxCreateMtlxDocumentFromHdNetwork( - HdMaterialNetwork2 const& hdNetwork, - HdMaterialNode2 const& hdMaterialXNode, - SdfPath const& hdMaterialXNodePath, - SdfPath const& materialPath, - mx::DocumentPtr const& libraries, - HdMtlxTexturePrimvarData* mxHdData) + HdMaterialNetwork2 const &hdNetwork, + HdMaterialNode2 const &hdMaterialXNode, + SdfPath const &hdMaterialXNodePath, + SdfPath const &materialPath, + mx::DocumentPtr const &libraries, + HdMtlxTexturePrimvarData *mxHdData) { - // XXX Unfortunate but necessary to cast away constness even though - // hdNetwork isn't modified. - HdMaterialNetwork2Interface netInterface( - materialPath, const_cast(&hdNetwork)); - - TfToken terminalNodeName = hdMaterialXNodePath.GetAsToken(); - - return HdMtlxCreateMtlxDocumentFromHdMaterialNetworkInterface( - &netInterface, - terminalNodeName, - netInterface.GetNodeInputConnectionNames(terminalNodeName), - libraries, - mxHdData); + // XXX Unfortunate but necessary to cast away constness even though + // hdNetwork isn't modified. + HdMaterialNetwork2Interface netInterface( + materialPath, const_cast(&hdNetwork)); + + TfToken terminalNodeName = hdMaterialXNodePath.GetAsToken(); + + return HdMtlxCreateMtlxDocumentFromHdMaterialNetworkInterface( + &netInterface, + terminalNodeName, + netInterface.GetNodeInputConnectionNames(terminalNodeName), + libraries, + mxHdData); } // Add parameter inputs for the terminal node (which is a StandardSurface or @@ -439,124 +478,132 @@ HdMtlxCreateMtlxDocumentFromHdNetwork( static void _AddParameterInputsToTerminalNode( HdMaterialNetworkInterface *netInterface, - TfToken const& terminalNodeName, - TfToken const& mxType, - mx::NodePtr const& mxShaderNode) + TfToken const &terminalNodeName, + TfToken const &mxType, + mx::NodePtr const &mxShaderNode) { - TfTokenVector paramNames = - netInterface->GetAuthoredNodeParameterNames(terminalNodeName); - - mx::NodeDefPtr mxNodeDef = mxShaderNode->getNodeDef(); - if (!mxNodeDef){ - TF_WARN("NodeDef not found for Node '%s'", mxType.GetText()); - return; - } - - for (TfToken const ¶mName : paramNames) { - // Get the MaterialX Parameter info - const std::string &mxInputName = paramName.GetString(); - std::string mxInputType; - mx::InputPtr mxInput = mxNodeDef->getActiveInput(mxInputName); - if (mxInput) { - mxInputType = mxInput->getType(); - } - std::string mxInputValue = HdMtlxConvertToString( - netInterface->GetNodeParameterValue(terminalNodeName, paramName)); - - mxShaderNode->setInputValue(mxInputName, mxInputValue, mxInputType); - } + TfTokenVector paramNames = + netInterface->GetAuthoredNodeParameterNames(terminalNodeName); + + mx::NodeDefPtr mxNodeDef = mxShaderNode->getNodeDef(); + if (!mxNodeDef) + { + TF_WARN("NodeDef not found for Node '%s'", mxType.GetText()); + return; + } + + for (TfToken const ¶mName : paramNames) + { + // Get the MaterialX Parameter info + const std::string &mxInputName = paramName.GetString(); + std::string mxInputType; + mx::InputPtr mxInput = mxNodeDef->getActiveInput(mxInputName); + if (mxInput) + { + mxInputType = mxInput->getType(); + } + std::string mxInputValue = HdMtlxConvertToString( + netInterface->GetNodeParameterValue(terminalNodeName, paramName)); + + mxShaderNode->setInputValue(mxInputName, mxInputValue, mxInputType); + } } // Updates mxDoc from traversing the node graph leading into the terminal node. static void _CreateMtlxNodeGraphFromTerminalNodeConnections( HdMaterialNetworkInterface *netInterface, - TfToken const& terminalNodeName, - TfTokenVector const& terminalNodeConnectionNames, - mx::DocumentPtr const& mxDoc, - mx::NodePtr const& mxShaderNode, - HdMtlxTexturePrimvarData * mxHdData) + TfToken const &terminalNodeName, + TfTokenVector const &terminalNodeConnectionNames, + mx::DocumentPtr const &mxDoc, + mx::NodePtr const &mxShaderNode, + HdMtlxTexturePrimvarData *mxHdData) { - mx::NodeGraphPtr mxNodeGraph; - mx::StringSet addedNodeNames; // Set of NodeNames in the mxNodeGraph - for (TfToken const &cName : terminalNodeConnectionNames) { - const std::string & mxNodeGraphOutput = cName.GetString(); - const auto inputConnections = - netInterface->GetNodeInputConnection(terminalNodeName, cName); - for (const auto &currConnection : inputConnections) { - // Gather the nodes uptream from the hdMaterialXNode - mx::NodePtr mxUpstreamNode; - - _GatherUpstreamNodes( - netInterface, currConnection, mxDoc, &mxNodeGraph, - &addedNodeNames, &mxUpstreamNode, mxNodeGraphOutput, mxHdData); - - if (!mxUpstreamNode) { - continue; - } - - // Connect currNode to the upstream Node - std::string fullOutputName = mxNodeGraphOutput + "_" + - currConnection.upstreamOutputName.GetString(); - mx::OutputPtr mxOutput; - _AddNodeGraphOutput(netInterface, currConnection, fullOutputName, - mxDoc, mxNodeGraph, mxUpstreamNode, &mxOutput); - mxOutput->setConnectedNode(mxUpstreamNode); - - // Connect NodeGraph Output to the ShaderNode - mx::InputPtr mxInput; - _AddInput(netInterface, currConnection, cName, - mxDoc, mxShaderNode, mxUpstreamNode, &mxInput); - mxInput->setConnectedOutput(mxOutput); - } - } + mx::NodeGraphPtr mxNodeGraph; + mx::StringSet addedNodeNames; // Set of NodeNames in the mxNodeGraph + for (TfToken const &cName : terminalNodeConnectionNames) + { + const std::string &mxNodeGraphOutput = cName.GetString(); + const auto inputConnections = + netInterface->GetNodeInputConnection(terminalNodeName, cName); + for (const auto &currConnection : inputConnections) + { + // Gather the nodes uptream from the hdMaterialXNode + mx::NodePtr mxUpstreamNode; + + _GatherUpstreamNodes( + netInterface, currConnection, mxDoc, &mxNodeGraph, + &addedNodeNames, &mxUpstreamNode, mxNodeGraphOutput, mxHdData); + + if (!mxUpstreamNode) + { + continue; + } + + // Connect currNode to the upstream Node + std::string fullOutputName = mxNodeGraphOutput + "_" + + currConnection.upstreamOutputName.GetString(); + mx::OutputPtr mxOutput; + _AddNodeGraphOutput(netInterface, currConnection, fullOutputName, + mxDoc, mxNodeGraph, mxUpstreamNode, &mxOutput); + mxOutput->setConnectedNode(mxUpstreamNode); + + // Connect NodeGraph Output to the ShaderNode + mx::InputPtr mxInput; + _AddInput(netInterface, currConnection, cName, + mxDoc, mxShaderNode, mxUpstreamNode, &mxInput); + mxInput->setConnectedOutput(mxOutput); + } + } } MaterialX::DocumentPtr HdMtlxCreateMtlxDocumentFromHdMaterialNetworkInterface( HdMaterialNetworkInterface *netInterface, - TfToken const& terminalNodeName, - TfTokenVector const& terminalNodeConnectionNames, - MaterialX::DocumentPtr const& libraries, + TfToken const &terminalNodeName, + TfTokenVector const &terminalNodeConnectionNames, + MaterialX::DocumentPtr const &libraries, HdMtlxTexturePrimvarData *mxHdData) { - if (!netInterface) { - return nullptr; - } - - // Initialize a MaterialX Document - mx::DocumentPtr mxDoc = mx::createDocument(); - mxDoc->importLibrary(libraries); - - // Create a material that instantiates the shader - SdfPath materialPath = netInterface->GetMaterialPrimPath(); - const std::string & materialName = materialPath.GetName(); - TfToken mxType = - _GetMxNodeType(mxDoc, netInterface->GetNodeType(terminalNodeName)); - mx::NodePtr mxShaderNode = mxDoc->addNode(mxType.GetString(), - "Surface", - "surfaceshader"); - mx::NodePtr mxMaterial = mxDoc->addMaterialNode( - mxDoc->createValidChildName(materialName), mxShaderNode); - - _CreateMtlxNodeGraphFromTerminalNodeConnections( - netInterface, terminalNodeName, terminalNodeConnectionNames, - mxDoc, mxShaderNode, mxHdData); - - _AddParameterInputsToTerminalNode( - netInterface, - terminalNodeName, - mxType, - mxShaderNode); - - // Validate the MaterialX Document. - std::string message; - if (!mxDoc->validate(&message)) { - TF_WARN("Validation warnings for generated MaterialX file.\n%s\n", - message.c_str()); - } - - return mxDoc; + if (!netInterface) + { + return nullptr; + } + + // Initialize a MaterialX Document + mx::DocumentPtr mxDoc = mx::createDocument(); + mxDoc->importLibrary(libraries); + + // Create a material that instantiates the shader + SdfPath materialPath = netInterface->GetMaterialPrimPath(); + const std::string &materialName = materialPath.GetName(); + TfToken mxType = + _GetMxNodeType(mxDoc, netInterface->GetNodeType(terminalNodeName)); + mx::NodePtr mxShaderNode = mxDoc->addNode(mxType.GetString(), + "Surface", + "surfaceshader"); + mx::NodePtr mxMaterial = mxDoc->addMaterialNode( + mxDoc->createValidChildName(materialName), mxShaderNode); + + _CreateMtlxNodeGraphFromTerminalNodeConnections( + netInterface, terminalNodeName, terminalNodeConnectionNames, + mxDoc, mxShaderNode, mxHdData); + + _AddParameterInputsToTerminalNode( + netInterface, + terminalNodeName, + mxType, + mxShaderNode); + + // Validate the MaterialX Document. + std::string message; + if (!mxDoc->validate(&message)) + { + TF_WARN("Validation warnings for generated MaterialX file.\n%s\n", + message.c_str()); + } + + return mxDoc; } PXR_NAMESPACE_CLOSE_SCOPE diff --git a/Sources/OpenUSD/imaging/hdSt/basisCurves.cpp b/Sources/OpenUSD/imaging/hdSt/basisCurves.cpp index a53ac97030..081c4ea3e0 100644 --- a/Sources/OpenUSD/imaging/hdSt/basisCurves.cpp +++ b/Sources/OpenUSD/imaging/hdSt/basisCurves.cpp @@ -40,7 +40,7 @@ #include "pxr/imaging/hdSt/resourceRegistry.h" #include "pxr/imaging/hdSt/tokens.h" -#include "pxr/base/arch/hash.h" +#include "Arch/hash.h" #include "pxr/base/gf/matrix4d.h" #include "pxr/base/gf/matrix4f.h" @@ -54,1230 +54,1326 @@ PXR_NAMESPACE_OPEN_SCOPE -HdStBasisCurves::HdStBasisCurves(SdfPath const& id) - : HdBasisCurves(id) - , _topology() - , _topologyId(0) - , _customDirtyBitsInUse(0) - , _refineLevel(0) - , _displayOpacity(false) - , _occludedSelectionShowsThrough(false) - , _pointsShadingEnabled(false) +HdStBasisCurves::HdStBasisCurves(SdfPath const &id) + : HdBasisCurves(id), _topology(), _topologyId(0), _customDirtyBitsInUse(0), _refineLevel(0), _displayOpacity(false), _occludedSelectionShowsThrough(false), _pointsShadingEnabled(false) { - /*NOTHING*/ + /*NOTHING*/ } - HdStBasisCurves::~HdStBasisCurves() = default; -void -HdStBasisCurves::UpdateRenderTag(HdSceneDelegate *delegate, - HdRenderParam *renderParam) +void HdStBasisCurves::UpdateRenderTag(HdSceneDelegate *delegate, + HdRenderParam *renderParam) { - HdStUpdateRenderTag(delegate, renderParam, this); -} - - -void -HdStBasisCurves::Sync(HdSceneDelegate *delegate, - HdRenderParam *renderParam, - HdDirtyBits *dirtyBits, - TfToken const &reprToken) -{ - _UpdateVisibility(delegate, dirtyBits); - - bool updateMaterialTags = false; - if (*dirtyBits & HdChangeTracker::DirtyMaterialId) { - HdStSetMaterialId(delegate, renderParam, this); - updateMaterialTags = true; - } - if (*dirtyBits & (HdChangeTracker::DirtyDisplayStyle| - HdChangeTracker::NewRepr)) { - updateMaterialTags = true; - } - - // Check if either the material or geometric shaders need updating for - // draw items of all the reprs. - bool updateMaterialNetworkShader = false; - if (*dirtyBits & (HdChangeTracker::DirtyMaterialId | - HdChangeTracker::NewRepr)) { - updateMaterialNetworkShader = true; - } - - bool updateGeometricShader = false; - if (*dirtyBits & (HdChangeTracker::DirtyDisplayStyle | - HdChangeTracker::DirtyMaterialId | - HdChangeTracker::DirtyTopology| // topological visibility - HdChangeTracker::NewRepr)) { - updateGeometricShader = true; - } - - bool displayOpacity = _displayOpacity; - _UpdateRepr(delegate, renderParam, reprToken, dirtyBits); - - if (updateMaterialTags || - (GetMaterialId().IsEmpty() && displayOpacity != _displayOpacity)) { - _UpdateMaterialTagsForAllReprs(delegate, renderParam); - } - - if (updateMaterialNetworkShader || updateGeometricShader) { - _UpdateShadersForAllReprs(delegate, renderParam, - updateMaterialNetworkShader, updateGeometricShader); - } - - - // This clears all the non-custom dirty bits. This ensures that the rprim - // doesn't have pending dirty bits that add it to the dirty list every - // frame. - // XXX: GetInitialDirtyBitsMask sets certain dirty bits that aren't - // reset (e.g. DirtyExtent, DirtyPrimID) that make this necessary. - *dirtyBits &= ~HdChangeTracker::AllSceneDirtyBits; + HdStUpdateRenderTag(delegate, renderParam, this); } -void -HdStBasisCurves::Finalize(HdRenderParam *renderParam) +void HdStBasisCurves::Sync(HdSceneDelegate *delegate, + HdRenderParam *renderParam, + HdDirtyBits *dirtyBits, + TfToken const &reprToken) { - HdStMarkGarbageCollectionNeeded(renderParam); - - HdStRenderParam * const stRenderParam = - static_cast(renderParam); - - // Decrement material tag counts for each draw item material tag - for (auto const& reprPair : _reprs) { - const TfToken &reprToken = reprPair.first; - _BasisCurvesReprConfig::DescArray const &descs = - _GetReprDesc(reprToken); - HdReprSharedPtr repr = reprPair.second; - int drawItemIndex = 0; - for (size_t descIdx = 0; descIdx < descs.size(); ++descIdx) { - if (descs[descIdx].geomStyle == HdBasisCurvesGeomStyleInvalid) { - continue; - } - HdStDrawItem *drawItem = static_cast( - repr->GetDrawItem(drawItemIndex++)); - stRenderParam->DecreaseMaterialTagCount(drawItem->GetMaterialTag()); - } - } - stRenderParam->DecreaseRenderTagCount(GetRenderTag()); + _UpdateVisibility(delegate, dirtyBits); + + bool updateMaterialTags = false; + if (*dirtyBits & HdChangeTracker::DirtyMaterialId) + { + HdStSetMaterialId(delegate, renderParam, this); + updateMaterialTags = true; + } + if (*dirtyBits & (HdChangeTracker::DirtyDisplayStyle | + HdChangeTracker::NewRepr)) + { + updateMaterialTags = true; + } + + // Check if either the material or geometric shaders need updating for + // draw items of all the reprs. + bool updateMaterialNetworkShader = false; + if (*dirtyBits & (HdChangeTracker::DirtyMaterialId | + HdChangeTracker::NewRepr)) + { + updateMaterialNetworkShader = true; + } + + bool updateGeometricShader = false; + if (*dirtyBits & (HdChangeTracker::DirtyDisplayStyle | + HdChangeTracker::DirtyMaterialId | + HdChangeTracker::DirtyTopology | // topological visibility + HdChangeTracker::NewRepr)) + { + updateGeometricShader = true; + } + + bool displayOpacity = _displayOpacity; + _UpdateRepr(delegate, renderParam, reprToken, dirtyBits); + + if (updateMaterialTags || + (GetMaterialId().IsEmpty() && displayOpacity != _displayOpacity)) + { + _UpdateMaterialTagsForAllReprs(delegate, renderParam); + } + + if (updateMaterialNetworkShader || updateGeometricShader) + { + _UpdateShadersForAllReprs(delegate, renderParam, + updateMaterialNetworkShader, updateGeometricShader); + } + + // This clears all the non-custom dirty bits. This ensures that the rprim + // doesn't have pending dirty bits that add it to the dirty list every + // frame. + // XXX: GetInitialDirtyBitsMask sets certain dirty bits that aren't + // reset (e.g. DirtyExtent, DirtyPrimID) that make this necessary. + *dirtyBits &= ~HdChangeTracker::AllSceneDirtyBits; } -void -HdStBasisCurves::_UpdateDrawItem(HdSceneDelegate *sceneDelegate, - HdRenderParam *renderParam, - HdStDrawItem *drawItem, - HdDirtyBits *dirtyBits, - const HdBasisCurvesReprDesc &desc) +void HdStBasisCurves::Finalize(HdRenderParam *renderParam) { - HD_TRACE_FUNCTION(); - HF_MALLOC_TAG_FUNCTION(); + HdStMarkGarbageCollectionNeeded(renderParam); - SdfPath const& id = GetId(); + HdStRenderParam *const stRenderParam = + static_cast(renderParam); - /* MATERIAL SHADER (may affect subsequent primvar population) */ - if ((*dirtyBits & HdChangeTracker::NewRepr) || - HdChangeTracker::IsAnyPrimvarDirty(*dirtyBits, id)) { - drawItem->SetMaterialNetworkShader( - HdStGetMaterialNetworkShader(this, sceneDelegate)); + // Decrement material tag counts for each draw item material tag + for (auto const &reprPair : _reprs) + { + const TfToken &reprToken = reprPair.first; + _BasisCurvesReprConfig::DescArray const &descs = + _GetReprDesc(reprToken); + HdReprSharedPtr repr = reprPair.second; + int drawItemIndex = 0; + for (size_t descIdx = 0; descIdx < descs.size(); ++descIdx) + { + if (descs[descIdx].geomStyle == HdBasisCurvesGeomStyleInvalid) + { + continue; + } + HdStDrawItem *drawItem = static_cast( + repr->GetDrawItem(drawItemIndex++)); + stRenderParam->DecreaseMaterialTagCount(drawItem->GetMaterialTag()); } + } + stRenderParam->DecreaseRenderTagCount(GetRenderTag()); +} - // Reset value of _displayOpacity - if (HdChangeTracker::IsAnyPrimvarDirty(*dirtyBits, id)) { - _displayOpacity = false; - } +void HdStBasisCurves::_UpdateDrawItem(HdSceneDelegate *sceneDelegate, + HdRenderParam *renderParam, + HdStDrawItem *drawItem, + HdDirtyBits *dirtyBits, + const HdBasisCurvesReprDesc &desc) +{ + HD_TRACE_FUNCTION(); + HF_MALLOC_TAG_FUNCTION(); + + SdfPath const &id = GetId(); + + /* MATERIAL SHADER (may affect subsequent primvar population) */ + if ((*dirtyBits & HdChangeTracker::NewRepr) || + HdChangeTracker::IsAnyPrimvarDirty(*dirtyBits, id)) + { + drawItem->SetMaterialNetworkShader( + HdStGetMaterialNetworkShader(this, sceneDelegate)); + } + + // Reset value of _displayOpacity + if (HdChangeTracker::IsAnyPrimvarDirty(*dirtyBits, id)) + { + _displayOpacity = false; + } + + /* INSTANCE PRIMVARS */ + _UpdateInstancer(sceneDelegate, dirtyBits); + HdStUpdateInstancerData(sceneDelegate->GetRenderIndex(), + renderParam, + this, + drawItem, + &_sharedData, + *dirtyBits); + + _displayOpacity = _displayOpacity || + HdStIsInstancePrimvarExistentAndValid( + sceneDelegate->GetRenderIndex(), this, HdTokens->displayOpacity); + + /* CONSTANT PRIMVARS, TRANSFORM, EXTENT AND PRIMID */ + if (HdStShouldPopulateConstantPrimvars(dirtyBits, id)) + { + HdPrimvarDescriptorVector constantPrimvars = + HdStGetPrimvarDescriptors(this, drawItem, sceneDelegate, + HdInterpolationConstant); - /* INSTANCE PRIMVARS */ - _UpdateInstancer(sceneDelegate, dirtyBits); - HdStUpdateInstancerData(sceneDelegate->GetRenderIndex(), - renderParam, - this, - drawItem, - &_sharedData, - *dirtyBits); + HdStPopulateConstantPrimvars(this, + &_sharedData, + sceneDelegate, + renderParam, + drawItem, + dirtyBits, + constantPrimvars); _displayOpacity = _displayOpacity || - HdStIsInstancePrimvarExistentAndValid( - sceneDelegate->GetRenderIndex(), this, HdTokens->displayOpacity); - - /* CONSTANT PRIMVARS, TRANSFORM, EXTENT AND PRIMID */ - if (HdStShouldPopulateConstantPrimvars(dirtyBits, id)) { - HdPrimvarDescriptorVector constantPrimvars = - HdStGetPrimvarDescriptors(this, drawItem, sceneDelegate, - HdInterpolationConstant); - - HdStPopulateConstantPrimvars(this, - &_sharedData, - sceneDelegate, - renderParam, - drawItem, - dirtyBits, - constantPrimvars); - - _displayOpacity = _displayOpacity || - HdStIsPrimvarExistentAndValid(this, sceneDelegate, - constantPrimvars, HdTokens->displayOpacity); - } - - /* TOPOLOGY */ - // XXX: _PopulateTopology should be split into two phase - // for scene dirtybits and for repr dirtybits. - if (*dirtyBits & (HdChangeTracker::DirtyTopology - | HdChangeTracker::DirtyDisplayStyle - | DirtyIndices - | DirtyHullIndices - | DirtyPointsIndices)) { - _PopulateTopology( - sceneDelegate, renderParam, drawItem, dirtyBits, desc); - } - - /* PRIMVAR */ - if (HdChangeTracker::IsAnyPrimvarDirty(*dirtyBits, id)) { - // XXX: curves don't use refined vertex primvars, however, - // the refined renderpass masks the dirtiness of non-refined vertex - // primvars, so we need to see refined dirty for updating coarse - // vertex primvars if there is only refined reprs being updated. - // we'll fix the change tracking in order to address this craziness. - _PopulateVertexPrimvars( - sceneDelegate, renderParam, drawItem, dirtyBits); - _PopulateVaryingPrimvars( - sceneDelegate, renderParam, drawItem, dirtyBits); - _PopulateElementPrimvars( - sceneDelegate, renderParam, drawItem, dirtyBits); - } - - // When we have multiple drawitems for the same prim we need to clean the - // bits for all the data fields touched in this function, otherwise it - // will try to extract topology (for instance) twice, and this won't - // work with delegates that don't keep information around once extracted. - *dirtyBits &= ~HdChangeTracker::AllSceneDirtyBits; - - // Topology and VertexPrimvar may be null, if the curve has zero line - // segments. - TF_VERIFY(drawItem->GetConstantPrimvarRange()); + HdStIsPrimvarExistentAndValid(this, sceneDelegate, + constantPrimvars, HdTokens->displayOpacity); + } + + /* TOPOLOGY */ + // XXX: _PopulateTopology should be split into two phase + // for scene dirtybits and for repr dirtybits. + if (*dirtyBits & (HdChangeTracker::DirtyTopology | HdChangeTracker::DirtyDisplayStyle | DirtyIndices | DirtyHullIndices | DirtyPointsIndices)) + { + _PopulateTopology( + sceneDelegate, renderParam, drawItem, dirtyBits, desc); + } + + /* PRIMVAR */ + if (HdChangeTracker::IsAnyPrimvarDirty(*dirtyBits, id)) + { + // XXX: curves don't use refined vertex primvars, however, + // the refined renderpass masks the dirtiness of non-refined vertex + // primvars, so we need to see refined dirty for updating coarse + // vertex primvars if there is only refined reprs being updated. + // we'll fix the change tracking in order to address this craziness. + _PopulateVertexPrimvars( + sceneDelegate, renderParam, drawItem, dirtyBits); + _PopulateVaryingPrimvars( + sceneDelegate, renderParam, drawItem, dirtyBits); + _PopulateElementPrimvars( + sceneDelegate, renderParam, drawItem, dirtyBits); + } + + // When we have multiple drawitems for the same prim we need to clean the + // bits for all the data fields touched in this function, otherwise it + // will try to extract topology (for instance) twice, and this won't + // work with delegates that don't keep information around once extracted. + *dirtyBits &= ~HdChangeTracker::AllSceneDirtyBits; + + // Topology and VertexPrimvar may be null, if the curve has zero line + // segments. + TF_VERIFY(drawItem->GetConstantPrimvarRange()); } -static const char* -HdSt_PrimTypeToString(HdSt_GeometricShader::PrimitiveType type) { - switch (type) - { - case HdSt_GeometricShader::PrimitiveType::PRIM_POINTS: - return "points"; - case HdSt_GeometricShader::PrimitiveType::PRIM_BASIS_CURVES_LINES: - return "lines"; - case HdSt_GeometricShader::PrimitiveType::PRIM_BASIS_CURVES_LINEAR_PATCHES: - return "patches[linear]"; - case HdSt_GeometricShader::PrimitiveType::PRIM_BASIS_CURVES_CUBIC_PATCHES: - return "patches[cubic]"; - default: - TF_WARN("Unknown type"); - return "unknown"; - } +static const char * +HdSt_PrimTypeToString(HdSt_GeometricShader::PrimitiveType type) +{ + switch (type) + { + case HdSt_GeometricShader::PrimitiveType::PRIM_POINTS: + return "points"; + case HdSt_GeometricShader::PrimitiveType::PRIM_BASIS_CURVES_LINES: + return "lines"; + case HdSt_GeometricShader::PrimitiveType::PRIM_BASIS_CURVES_LINEAR_PATCHES: + return "patches[linear]"; + case HdSt_GeometricShader::PrimitiveType::PRIM_BASIS_CURVES_CUBIC_PATCHES: + return "patches[cubic]"; + default: + TF_WARN("Unknown type"); + return "unknown"; + } } -void -HdStBasisCurves::_UpdateDrawItemGeometricShader( - HdSceneDelegate *sceneDelegate, - HdRenderParam *renderParam, - HdStDrawItem *drawItem, - const HdBasisCurvesReprDesc &desc) +void HdStBasisCurves::_UpdateDrawItemGeometricShader( + HdSceneDelegate *sceneDelegate, + HdRenderParam *renderParam, + HdStDrawItem *drawItem, + const HdBasisCurvesReprDesc &desc) { - if (!TF_VERIFY(_topology)) return; - - HdRenderIndex &renderIndex = sceneDelegate->GetRenderIndex(); - - HdStResourceRegistrySharedPtr resourceRegistry = - std::static_pointer_cast( - renderIndex.GetResourceRegistry()); - - TfToken curveType = _topology->GetCurveType(); - TfToken curveBasis = _topology->GetCurveBasis(); - bool supportsRefinement = _SupportsRefinement(_refineLevel); - if (!supportsRefinement) { - // XXX: Rendering non-linear (i.e., cubic) curves as linear segments - // when unrefined can be confusing. Should we continue to do this? - TF_DEBUG(HD_RPRIM_UPDATED). - Msg("HdStBasisCurves(%s) - Downcasting curve type to linear because" - " refinement is disabled.\n", GetId().GetText()); - curveType = HdTokens->linear; - curveBasis = TfToken(); - } - - HdSt_BasisCurvesShaderKey::DrawStyle drawStyle = - HdSt_BasisCurvesShaderKey::WIRE; - HdSt_BasisCurvesShaderKey::NormalStyle normalStyle = - HdSt_BasisCurvesShaderKey::HAIR; - switch (desc.geomStyle) { - case HdBasisCurvesGeomStylePoints: + if (!TF_VERIFY(_topology)) + return; + + HdRenderIndex &renderIndex = sceneDelegate->GetRenderIndex(); + + HdStResourceRegistrySharedPtr resourceRegistry = + std::static_pointer_cast( + renderIndex.GetResourceRegistry()); + + TfToken curveType = _topology->GetCurveType(); + TfToken curveBasis = _topology->GetCurveBasis(); + bool supportsRefinement = _SupportsRefinement(_refineLevel); + if (!supportsRefinement) + { + // XXX: Rendering non-linear (i.e., cubic) curves as linear segments + // when unrefined can be confusing. Should we continue to do this? + TF_DEBUG(HD_RPRIM_UPDATED).Msg("HdStBasisCurves(%s) - Downcasting curve type to linear because" + " refinement is disabled.\n", + GetId().GetText()); + curveType = HdTokens->linear; + curveBasis = TfToken(); + } + + HdSt_BasisCurvesShaderKey::DrawStyle drawStyle = + HdSt_BasisCurvesShaderKey::WIRE; + HdSt_BasisCurvesShaderKey::NormalStyle normalStyle = + HdSt_BasisCurvesShaderKey::HAIR; + switch (desc.geomStyle) + { + case HdBasisCurvesGeomStylePoints: + { + drawStyle = HdSt_BasisCurvesShaderKey::POINTS; + normalStyle = HdSt_BasisCurvesShaderKey::HAIR; + break; + } + case HdBasisCurvesGeomStyleWire: + { + drawStyle = HdSt_BasisCurvesShaderKey::WIRE; + normalStyle = HdSt_BasisCurvesShaderKey::HAIR; + break; + } + case HdBasisCurvesGeomStylePatch: + { + if (_SupportsRefinement(_refineLevel) && + _SupportsUserWidths(drawItem)) { - drawStyle = HdSt_BasisCurvesShaderKey::POINTS; - normalStyle = HdSt_BasisCurvesShaderKey::HAIR; - break; - } - case HdBasisCurvesGeomStyleWire: - { - drawStyle = HdSt_BasisCurvesShaderKey::WIRE; - normalStyle = HdSt_BasisCurvesShaderKey::HAIR; - break; - } - case HdBasisCurvesGeomStylePatch: - { - if (_SupportsRefinement(_refineLevel) && - _SupportsUserWidths(drawItem)) { - if (_SupportsUserNormals(drawItem)){ - drawStyle = HdSt_BasisCurvesShaderKey::RIBBON; - normalStyle = HdSt_BasisCurvesShaderKey::ORIENTED; - } - else{ - if (_refineLevel > 2){ - normalStyle = HdSt_BasisCurvesShaderKey::ROUND; - drawStyle = HdSt_BasisCurvesShaderKey::HALFTUBE; - } - else if (_refineLevel > 1){ - normalStyle = HdSt_BasisCurvesShaderKey::ROUND; - drawStyle = HdSt_BasisCurvesShaderKey::RIBBON; - } - else{ - drawStyle = HdSt_BasisCurvesShaderKey::RIBBON; - normalStyle = HdSt_BasisCurvesShaderKey::HAIR; - } - } + if (_SupportsUserNormals(drawItem)) + { + drawStyle = HdSt_BasisCurvesShaderKey::RIBBON; + normalStyle = HdSt_BasisCurvesShaderKey::ORIENTED; + } + else + { + if (_refineLevel > 2) + { + normalStyle = HdSt_BasisCurvesShaderKey::ROUND; + drawStyle = HdSt_BasisCurvesShaderKey::HALFTUBE; } - break; + else if (_refineLevel > 1) + { + normalStyle = HdSt_BasisCurvesShaderKey::ROUND; + drawStyle = HdSt_BasisCurvesShaderKey::RIBBON; + } + else + { + drawStyle = HdSt_BasisCurvesShaderKey::RIBBON; + normalStyle = HdSt_BasisCurvesShaderKey::HAIR; + } + } } - default: + break; + } + default: + { + TF_CODING_ERROR("Invalid geomstyle in basis curve %s repr desc.", + GetId().GetText()); + } + } + + TF_DEBUG(HD_RPRIM_UPDATED).Msg("HdStBasisCurves(%s) - Building shader with keys: %s, %s, %s, %s, %s, %s\n", GetId().GetText(), curveType.GetText(), curveBasis.GetText(), TfEnum::GetName(drawStyle).c_str(), TfEnum::GetName(normalStyle).c_str(), _basisWidthInterpolation ? "basis widths" : "linear widths", _basisNormalInterpolation ? "basis normals" : "linear normals"); + + bool hasAuthoredTopologicalVisiblity = + (bool)drawItem->GetTopologyVisibilityRange(); + + // Process shadingTerminal (including shadingStyle) + TfToken shadingTerminal = desc.shadingTerminal; + if (shadingTerminal == HdBasisCurvesReprDescTokens->surfaceShader) + { + TfToken shadingStyle = + sceneDelegate->GetShadingStyle(GetId()).GetWithDefault(); + if (shadingStyle == HdStTokens->constantLighting) { - TF_CODING_ERROR("Invalid geomstyle in basis curve %s repr desc.", - GetId().GetText()); - } - } - - TF_DEBUG(HD_RPRIM_UPDATED). - Msg("HdStBasisCurves(%s) - Building shader with keys: %s, %s, %s, %s, %s, %s\n", - GetId().GetText(), curveType.GetText(), - curveBasis.GetText(), - TfEnum::GetName(drawStyle).c_str(), - TfEnum::GetName(normalStyle).c_str(), - _basisWidthInterpolation ? "basis widths" : "linear widths", - _basisNormalInterpolation ? "basis normals" : "linear normals"); - - bool hasAuthoredTopologicalVisiblity = - (bool) drawItem->GetTopologyVisibilityRange(); - - // Process shadingTerminal (including shadingStyle) - TfToken shadingTerminal = desc.shadingTerminal; - if (shadingTerminal == HdBasisCurvesReprDescTokens->surfaceShader) { - TfToken shadingStyle = - sceneDelegate->GetShadingStyle(GetId()).GetWithDefault(); - if (shadingStyle == HdStTokens->constantLighting) { - shadingTerminal = HdBasisCurvesReprDescTokens->surfaceShaderUnlit; - } + shadingTerminal = HdBasisCurvesReprDescTokens->surfaceShaderUnlit; } + } - bool const hasMetalTessellation = - resourceRegistry->GetHgi()->GetCapabilities()-> - IsSet(HgiDeviceCapabilitiesBitsMetalTessellation); + bool const hasMetalTessellation = + resourceRegistry->GetHgi()->GetCapabilities()->IsSet(HgiDeviceCapabilitiesBitsMetalTessellation); - HdSt_BasisCurvesShaderKey shaderKey(curveType, - curveBasis, - drawStyle, - normalStyle, - _basisWidthInterpolation, - _basisNormalInterpolation, - shadingTerminal, - hasAuthoredTopologicalVisiblity, - _pointsShadingEnabled, - hasMetalTessellation); + HdSt_BasisCurvesShaderKey shaderKey(curveType, + curveBasis, + drawStyle, + normalStyle, + _basisWidthInterpolation, + _basisNormalInterpolation, + shadingTerminal, + hasAuthoredTopologicalVisiblity, + _pointsShadingEnabled, + hasMetalTessellation); - TF_DEBUG(HD_RPRIM_UPDATED). - Msg("HdStBasisCurves(%s) - Shader Key PrimType: %s\n ", - GetId().GetText(), HdSt_PrimTypeToString(shaderKey.primType)); + TF_DEBUG(HD_RPRIM_UPDATED).Msg("HdStBasisCurves(%s) - Shader Key PrimType: %s\n ", GetId().GetText(), HdSt_PrimTypeToString(shaderKey.primType)); - HdSt_GeometricShaderSharedPtr geomShader = - HdSt_GeometricShader::Create(shaderKey, resourceRegistry); + HdSt_GeometricShaderSharedPtr geomShader = + HdSt_GeometricShader::Create(shaderKey, resourceRegistry); - TF_VERIFY(geomShader); + TF_VERIFY(geomShader); - if (geomShader != drawItem->GetGeometricShader()) - { - drawItem->SetGeometricShader(geomShader); + if (geomShader != drawItem->GetGeometricShader()) + { + drawItem->SetGeometricShader(geomShader); - // If the gometric shader changes, we need to do a deep validation of - // batches, so they can be rebuilt if necessary. - HdStMarkDrawBatchesDirty(renderParam); + // If the gometric shader changes, we need to do a deep validation of + // batches, so they can be rebuilt if necessary. + HdStMarkDrawBatchesDirty(renderParam); - TF_DEBUG(HD_RPRIM_UPDATED).Msg( - "%s: Marking all batches dirty to trigger deep validation because" - " the geometric shader was updated.\n", GetId().GetText()); - } + TF_DEBUG(HD_RPRIM_UPDATED).Msg("%s: Marking all batches dirty to trigger deep validation because" + " the geometric shader was updated.\n", + GetId().GetText()); + } } HdDirtyBits HdStBasisCurves::_PropagateDirtyBits(HdDirtyBits bits) const { - // propagate scene-based dirtyBits into rprim-custom dirtyBits - if (bits & HdChangeTracker::DirtyTopology) { - bits |= _customDirtyBitsInUse & - (DirtyIndices|DirtyHullIndices|DirtyPointsIndices| - HdChangeTracker::DirtyPrimvar); - } - - return bits; -} - -void -HdStBasisCurves::_InitRepr(TfToken const &reprToken, HdDirtyBits *dirtyBits) -{ - _ReprVector::iterator it = std::find_if(_reprs.begin(), _reprs.end(), - _ReprComparator(reprToken)); - bool isNew = it == _reprs.end(); - if (isNew) { - _BasisCurvesReprConfig::DescArray descs = _GetReprDesc(reprToken); - - // add new repr - _reprs.emplace_back(reprToken, std::make_shared()); - HdReprSharedPtr &repr = _reprs.back().second; - - *dirtyBits |= HdChangeTracker::NewRepr; - - // allocate all draw items - for (size_t descIdx = 0; descIdx < descs.size(); ++descIdx) { - const HdBasisCurvesReprDesc &desc = descs[descIdx]; - - if (desc.geomStyle == HdBasisCurvesGeomStyleInvalid) { - continue; - } - - HdRepr::DrawItemUniquePtr drawItem = - std::make_unique(&_sharedData); - HdDrawingCoord *drawingCoord = drawItem->GetDrawingCoord(); - repr->AddDrawItem(std::move(drawItem)); - if (desc.geomStyle == HdBasisCurvesGeomStyleWire) { - // Why does geom style require this change? - drawingCoord->SetTopologyIndex(HdStBasisCurves::HullTopology); - if (!(_customDirtyBitsInUse & DirtyHullIndices)) { - _customDirtyBitsInUse |= DirtyHullIndices; - *dirtyBits |= DirtyHullIndices; - } - } else if (desc.geomStyle == HdBasisCurvesGeomStylePoints) { - drawingCoord->SetTopologyIndex(HdStBasisCurves::PointsTopology); - if (!(_customDirtyBitsInUse & DirtyPointsIndices)) { - _customDirtyBitsInUse |= DirtyPointsIndices; - *dirtyBits |= DirtyPointsIndices; - } - } else { - if (!(_customDirtyBitsInUse & DirtyIndices)) { - _customDirtyBitsInUse |= DirtyIndices; - *dirtyBits |= DirtyIndices; - } - } - - // Set up drawing coord instance primvars. - drawingCoord->SetInstancePrimvarBaseIndex( - HdStBasisCurves::InstancePrimvar); - } - } + // propagate scene-based dirtyBits into rprim-custom dirtyBits + if (bits & HdChangeTracker::DirtyTopology) + { + bits |= _customDirtyBitsInUse & + (DirtyIndices | DirtyHullIndices | DirtyPointsIndices | + HdChangeTracker::DirtyPrimvar); + } + + return bits; } -void -HdStBasisCurves::_UpdateRepr(HdSceneDelegate *sceneDelegate, - HdRenderParam *renderParam, - TfToken const &reprToken, - HdDirtyBits *dirtyBits) +void HdStBasisCurves::_InitRepr(TfToken const &reprToken, HdDirtyBits *dirtyBits) { - HD_TRACE_FUNCTION(); - HF_MALLOC_TAG_FUNCTION(); + _ReprVector::iterator it = std::find_if(_reprs.begin(), _reprs.end(), + _ReprComparator(reprToken)); + bool isNew = it == _reprs.end(); + if (isNew) + { + _BasisCurvesReprConfig::DescArray descs = _GetReprDesc(reprToken); - HdReprSharedPtr const &curRepr = _GetRepr(reprToken); - if (!curRepr) { - return; - } - - // Filter custom dirty bits to only those in use. - *dirtyBits &= (_customDirtyBitsInUse | - HdChangeTracker::AllSceneDirtyBits | - HdChangeTracker::NewRepr); + // add new repr + _reprs.emplace_back(reprToken, std::make_shared()); + HdReprSharedPtr &repr = _reprs.back().second; - if (TfDebug::IsEnabled(HD_RPRIM_UPDATED)) { - TfDebug::Helper().Msg( - "HdStBasisCurves::_UpdateRepr for %s : Repr = %s\n", - GetId().GetText(), reprToken.GetText()); - HdChangeTracker::DumpDirtyBits(*dirtyBits); - } + *dirtyBits |= HdChangeTracker::NewRepr; - _BasisCurvesReprConfig::DescArray const &reprDescs = - _GetReprDesc(reprToken); - - int drawItemIndex = 0; - for (size_t descIdx = 0; descIdx < reprDescs.size(); ++descIdx) { - // curves don't have multiple draw items (for now) - const HdBasisCurvesReprDesc &desc = reprDescs[descIdx]; - - if (desc.geomStyle != HdBasisCurvesGeomStyleInvalid) { - HdStDrawItem *drawItem = static_cast( - curRepr->GetDrawItem(drawItemIndex++)); - - if (HdChangeTracker::IsDirty(*dirtyBits)) { - _UpdateDrawItem(sceneDelegate, renderParam, - drawItem, dirtyBits, desc); - } + // allocate all draw items + for (size_t descIdx = 0; descIdx < descs.size(); ++descIdx) + { + const HdBasisCurvesReprDesc &desc = descs[descIdx]; + + if (desc.geomStyle == HdBasisCurvesGeomStyleInvalid) + { + continue; + } + + HdRepr::DrawItemUniquePtr drawItem = + std::make_unique(&_sharedData); + HdDrawingCoord *drawingCoord = drawItem->GetDrawingCoord(); + repr->AddDrawItem(std::move(drawItem)); + if (desc.geomStyle == HdBasisCurvesGeomStyleWire) + { + // Why does geom style require this change? + drawingCoord->SetTopologyIndex(HdStBasisCurves::HullTopology); + if (!(_customDirtyBitsInUse & DirtyHullIndices)) + { + _customDirtyBitsInUse |= DirtyHullIndices; + *dirtyBits |= DirtyHullIndices; } - } - + } + else if (desc.geomStyle == HdBasisCurvesGeomStylePoints) + { + drawingCoord->SetTopologyIndex(HdStBasisCurves::PointsTopology); + if (!(_customDirtyBitsInUse & DirtyPointsIndices)) + { + _customDirtyBitsInUse |= DirtyPointsIndices; + *dirtyBits |= DirtyPointsIndices; + } + } + else + { + if (!(_customDirtyBitsInUse & DirtyIndices)) + { + _customDirtyBitsInUse |= DirtyIndices; + *dirtyBits |= DirtyIndices; + } + } - *dirtyBits &= ~HdChangeTracker::NewRepr; + // Set up drawing coord instance primvars. + drawingCoord->SetInstancePrimvarBaseIndex( + HdStBasisCurves::InstancePrimvar); + } + } } -void -HdStBasisCurves::_UpdateShadersForAllReprs(HdSceneDelegate *sceneDelegate, - HdRenderParam *renderParam, - bool updateMaterialNetworkShader, - bool updateGeometricShader) +void HdStBasisCurves::_UpdateRepr(HdSceneDelegate *sceneDelegate, + HdRenderParam *renderParam, + TfToken const &reprToken, + HdDirtyBits *dirtyBits) { - TF_DEBUG(HD_RPRIM_UPDATED). Msg( - "(%s) - Updating geometric and material shaders for draw " - "items of all reprs.\n", GetId().GetText()); - - HdSt_MaterialNetworkShaderSharedPtr materialNetworkShader; - if (updateMaterialNetworkShader) { - materialNetworkShader = - HdStGetMaterialNetworkShader(this, sceneDelegate); + HD_TRACE_FUNCTION(); + HF_MALLOC_TAG_FUNCTION(); + + HdReprSharedPtr const &curRepr = _GetRepr(reprToken); + if (!curRepr) + { + return; + } + + // Filter custom dirty bits to only those in use. + *dirtyBits &= (_customDirtyBitsInUse | + HdChangeTracker::AllSceneDirtyBits | + HdChangeTracker::NewRepr); + + if (TfDebug::IsEnabled(HD_RPRIM_UPDATED)) + { + TfDebug::Helper().Msg( + "HdStBasisCurves::_UpdateRepr for %s : Repr = %s\n", + GetId().GetText(), reprToken.GetText()); + HdChangeTracker::DumpDirtyBits(*dirtyBits); + } + + _BasisCurvesReprConfig::DescArray const &reprDescs = + _GetReprDesc(reprToken); + + int drawItemIndex = 0; + for (size_t descIdx = 0; descIdx < reprDescs.size(); ++descIdx) + { + // curves don't have multiple draw items (for now) + const HdBasisCurvesReprDesc &desc = reprDescs[descIdx]; + + if (desc.geomStyle != HdBasisCurvesGeomStyleInvalid) + { + HdStDrawItem *drawItem = static_cast( + curRepr->GetDrawItem(drawItemIndex++)); + + if (HdChangeTracker::IsDirty(*dirtyBits)) + { + _UpdateDrawItem(sceneDelegate, renderParam, + drawItem, dirtyBits, desc); + } } + } - const bool materialIsFinal = GetDisplayStyle(sceneDelegate).materialIsFinal; - bool materialIsFinalChanged = false; - for (auto const& reprPair : _reprs) { - const TfToken &reprToken = reprPair.first; - _BasisCurvesReprConfig::DescArray const &descs = - _GetReprDesc(reprToken); - HdReprSharedPtr repr = reprPair.second; - int drawItemIndex = 0; - for (size_t descIdx = 0; descIdx < descs.size(); ++descIdx) { - if (descs[descIdx].geomStyle == HdBasisCurvesGeomStyleInvalid) { - continue; - } - - HdStDrawItem *drawItem = static_cast( - repr->GetDrawItem(drawItemIndex++)); - if (materialIsFinal != drawItem->GetMaterialIsFinal()) { - materialIsFinalChanged = true; - } - drawItem->SetMaterialIsFinal(materialIsFinal); - - if (updateMaterialNetworkShader) { - drawItem->SetMaterialNetworkShader(materialNetworkShader); - } - if (updateGeometricShader) { - _UpdateDrawItemGeometricShader( - sceneDelegate, renderParam, drawItem, descs[descIdx]); - } - } - } + *dirtyBits &= ~HdChangeTracker::NewRepr; +} - if (materialIsFinalChanged) { - HdStMarkDrawBatchesDirty(renderParam); - TF_DEBUG(HD_RPRIM_UPDATED).Msg( - "%s: Marking all batches dirty to trigger deep validation because " - "the materialIsFinal was updated.\n", GetId().GetText()); +void HdStBasisCurves::_UpdateShadersForAllReprs(HdSceneDelegate *sceneDelegate, + HdRenderParam *renderParam, + bool updateMaterialNetworkShader, + bool updateGeometricShader) +{ + TF_DEBUG(HD_RPRIM_UPDATED).Msg("(%s) - Updating geometric and material shaders for draw " + "items of all reprs.\n", + GetId().GetText()); + + HdSt_MaterialNetworkShaderSharedPtr materialNetworkShader; + if (updateMaterialNetworkShader) + { + materialNetworkShader = + HdStGetMaterialNetworkShader(this, sceneDelegate); + } + + const bool materialIsFinal = GetDisplayStyle(sceneDelegate).materialIsFinal; + bool materialIsFinalChanged = false; + for (auto const &reprPair : _reprs) + { + const TfToken &reprToken = reprPair.first; + _BasisCurvesReprConfig::DescArray const &descs = + _GetReprDesc(reprToken); + HdReprSharedPtr repr = reprPair.second; + int drawItemIndex = 0; + for (size_t descIdx = 0; descIdx < descs.size(); ++descIdx) + { + if (descs[descIdx].geomStyle == HdBasisCurvesGeomStyleInvalid) + { + continue; + } + + HdStDrawItem *drawItem = static_cast( + repr->GetDrawItem(drawItemIndex++)); + if (materialIsFinal != drawItem->GetMaterialIsFinal()) + { + materialIsFinalChanged = true; + } + drawItem->SetMaterialIsFinal(materialIsFinal); + + if (updateMaterialNetworkShader) + { + drawItem->SetMaterialNetworkShader(materialNetworkShader); + } + if (updateGeometricShader) + { + _UpdateDrawItemGeometricShader( + sceneDelegate, renderParam, drawItem, descs[descIdx]); + } } + } + + if (materialIsFinalChanged) + { + HdStMarkDrawBatchesDirty(renderParam); + TF_DEBUG(HD_RPRIM_UPDATED).Msg("%s: Marking all batches dirty to trigger deep validation because " + "the materialIsFinal was updated.\n", + GetId().GetText()); + } } -void -HdStBasisCurves::_UpdateMaterialTagsForAllReprs(HdSceneDelegate *sceneDelegate, - HdRenderParam *renderParam) +void HdStBasisCurves::_UpdateMaterialTagsForAllReprs(HdSceneDelegate *sceneDelegate, + HdRenderParam *renderParam) { - TF_DEBUG(HD_RPRIM_UPDATED). Msg( - "(%s) - Updating material tags for draw items of all reprs.\n", - GetId().GetText()); - - for (auto const& reprPair : _reprs) { - const TfToken &reprToken = reprPair.first; - _BasisCurvesReprConfig::DescArray const &descs = - _GetReprDesc(reprToken); - HdReprSharedPtr repr = reprPair.second; - int drawItemIndex = 0; - for (size_t descIdx = 0; descIdx < descs.size(); ++descIdx) { - if (descs[descIdx].geomStyle == HdBasisCurvesGeomStyleInvalid) { - continue; - } - HdStDrawItem *drawItem = static_cast( - repr->GetDrawItem(drawItemIndex++)); - - HdStSetMaterialTag(sceneDelegate, renderParam, drawItem, - this->GetMaterialId(), _displayOpacity, - _occludedSelectionShowsThrough); - } + TF_DEBUG(HD_RPRIM_UPDATED).Msg("(%s) - Updating material tags for draw items of all reprs.\n", GetId().GetText()); + + for (auto const &reprPair : _reprs) + { + const TfToken &reprToken = reprPair.first; + _BasisCurvesReprConfig::DescArray const &descs = + _GetReprDesc(reprToken); + HdReprSharedPtr repr = reprPair.second; + int drawItemIndex = 0; + for (size_t descIdx = 0; descIdx < descs.size(); ++descIdx) + { + if (descs[descIdx].geomStyle == HdBasisCurvesGeomStyleInvalid) + { + continue; + } + HdStDrawItem *drawItem = static_cast( + repr->GetDrawItem(drawItemIndex++)); + + HdStSetMaterialTag(sceneDelegate, renderParam, drawItem, + this->GetMaterialId(), _displayOpacity, + _occludedSelectionShowsThrough); } + } } -void -HdStBasisCurves::_PopulateTopology(HdSceneDelegate *sceneDelegate, - HdRenderParam *renderParam, - HdStDrawItem *drawItem, - HdDirtyBits *dirtyBits, - const HdBasisCurvesReprDesc &desc) +void HdStBasisCurves::_PopulateTopology(HdSceneDelegate *sceneDelegate, + HdRenderParam *renderParam, + HdStDrawItem *drawItem, + HdDirtyBits *dirtyBits, + const HdBasisCurvesReprDesc &desc) { - HD_TRACE_FUNCTION(); - HF_MALLOC_TAG_FUNCTION(); - - SdfPath const& id = GetId(); - HdStResourceRegistrySharedPtr const& resourceRegistry = - std::static_pointer_cast( - sceneDelegate->GetRenderIndex().GetResourceRegistry()); - HdChangeTracker &changeTracker = - sceneDelegate->GetRenderIndex().GetChangeTracker(); - - if (*dirtyBits & HdChangeTracker::DirtyDisplayStyle) { - HdDisplayStyle ds = GetDisplayStyle(sceneDelegate); - _refineLevel = ds.refineLevel; - _occludedSelectionShowsThrough = ds.occludedSelectionShowsThrough; - _pointsShadingEnabled = ds.pointsShadingEnabled; + HD_TRACE_FUNCTION(); + HF_MALLOC_TAG_FUNCTION(); + + SdfPath const &id = GetId(); + HdStResourceRegistrySharedPtr const &resourceRegistry = + std::static_pointer_cast( + sceneDelegate->GetRenderIndex().GetResourceRegistry()); + HdChangeTracker &changeTracker = + sceneDelegate->GetRenderIndex().GetChangeTracker(); + + if (*dirtyBits & HdChangeTracker::DirtyDisplayStyle) + { + HdDisplayStyle ds = GetDisplayStyle(sceneDelegate); + _refineLevel = ds.refineLevel; + _occludedSelectionShowsThrough = ds.occludedSelectionShowsThrough; + _pointsShadingEnabled = ds.pointsShadingEnabled; + } + + // XXX: is it safe to get topology even if it's not dirty? + bool dirtyTopology = HdChangeTracker::IsTopologyDirty(*dirtyBits, id); + + if (dirtyTopology || HdChangeTracker::IsDisplayStyleDirty(*dirtyBits, id)) + { + + const HdBasisCurvesTopology &srcTopology = + GetBasisCurvesTopology(sceneDelegate); + + // Topological visibility (of points, curves) comes in as DirtyTopology. + // We encode this information in a separate BAR. + if (dirtyTopology) + { + // The points primvar is permitted to be larger than the number of + // CVs implied by the topology. So here we allow for + // invisiblePoints being larger as well. + size_t minInvisiblePointsCapacity = srcTopology.GetNumPoints(); + + HdStProcessTopologyVisibility( + srcTopology.GetInvisibleCurves(), + srcTopology.GetNumCurves(), + srcTopology.GetInvisiblePoints(), + minInvisiblePointsCapacity, + &_sharedData, + drawItem, + renderParam, + &changeTracker, + resourceRegistry, + id); } - // XXX: is it safe to get topology even if it's not dirty? - bool dirtyTopology = HdChangeTracker::IsTopologyDirty(*dirtyBits, id); - - if (dirtyTopology || HdChangeTracker::IsDisplayStyleDirty(*dirtyBits, id)) { - - const HdBasisCurvesTopology &srcTopology = - GetBasisCurvesTopology(sceneDelegate); - - // Topological visibility (of points, curves) comes in as DirtyTopology. - // We encode this information in a separate BAR. - if (dirtyTopology) { - // The points primvar is permitted to be larger than the number of - // CVs implied by the topology. So here we allow for - // invisiblePoints being larger as well. - size_t minInvisiblePointsCapacity = srcTopology.GetNumPoints(); - - HdStProcessTopologyVisibility( - srcTopology.GetInvisibleCurves(), - srcTopology.GetNumCurves(), - srcTopology.GetInvisiblePoints(), - minInvisiblePointsCapacity, - &_sharedData, - drawItem, - renderParam, - &changeTracker, - resourceRegistry, - id); - } - - // compute id. - _topologyId = srcTopology.ComputeHash(); - bool refined = (_refineLevel>0); - _topologyId = ArchHash64((const char*)&refined, sizeof(refined), - _topologyId); + // compute id. + _topologyId = srcTopology.ComputeHash(); + bool refined = (_refineLevel > 0); + _topologyId = ArchHash64((const char *)&refined, sizeof(refined), + _topologyId); - // ask the registry if there is a sharable basisCurves topology - HdInstance topologyInstance = - resourceRegistry->RegisterBasisCurvesTopology(_topologyId); + // ask the registry if there is a sharable basisCurves topology + HdInstance topologyInstance = + resourceRegistry->RegisterBasisCurvesTopology(_topologyId); - if (topologyInstance.IsFirstInstance()) { - // if this is the first instance, create a new stream topology - // representation and use that. - HdSt_BasisCurvesTopologySharedPtr topology = - HdSt_BasisCurvesTopology::New(srcTopology); - - topologyInstance.SetValue(topology); - } - - _topology = topologyInstance.GetValue(); - TF_VERIFY(_topology); + if (topologyInstance.IsFirstInstance()) + { + // if this is the first instance, create a new stream topology + // representation and use that. + HdSt_BasisCurvesTopologySharedPtr topology = + HdSt_BasisCurvesTopology::New(srcTopology); - // hash collision check - if (TfDebug::IsEnabled(HD_SAFE_MODE)) { - TF_VERIFY(srcTopology == *_topology); - } + topologyInstance.SetValue(topology); } - // bail out if the index bar is already synced - TfToken indexToken; - if (drawItem->GetDrawingCoord()->GetTopologyIndex() - == HdStBasisCurves::HullTopology) { - if ((*dirtyBits & DirtyHullIndices) == 0) return; - *dirtyBits &= ~DirtyHullIndices; - indexToken = HdTokens->hullIndices; - } else if (drawItem->GetDrawingCoord()->GetTopologyIndex() - == HdStBasisCurves::PointsTopology) { - if ((*dirtyBits & DirtyPointsIndices) == 0) return; - *dirtyBits &= ~DirtyPointsIndices; - indexToken = HdTokens->pointsIndices; - } else { - if ((*dirtyBits & DirtyIndices) == 0) return; - *dirtyBits &= ~DirtyIndices; - indexToken = HdTokens->indices; - } + _topology = topologyInstance.GetValue(); + TF_VERIFY(_topology); + // hash collision check + if (TfDebug::IsEnabled(HD_SAFE_MODE)) { - HdInstance rangeInstance = - resourceRegistry->RegisterBasisCurvesIndexRange( - _topologyId, indexToken); - - if(rangeInstance.IsFirstInstance()) { - HdBufferSourceSharedPtrVector sources; - HdBufferSpecVector bufferSpecs; - - if (desc.geomStyle == HdBasisCurvesGeomStylePoints) { - sources.push_back( - _topology->GetPointsIndexBuilderComputation()); - } else { - sources.push_back(_topology->GetIndexBuilderComputation( - !_SupportsRefinement(_refineLevel))); - } - - HdBufferSpec::GetBufferSpecs(sources, &bufferSpecs); - - // Set up the usage hints to mark topology as varying if - // there is a previously set range. - HdBufferArrayUsageHint usageHint; - usageHint.bits.sizeVarying = drawItem->GetTopologyRange()? 1 : 0; - - // allocate new range - HdBufferArrayRangeSharedPtr range - = resourceRegistry->AllocateNonUniformBufferArrayRange( - HdTokens->topology, bufferSpecs, usageHint); - - // add sources to update queue - resourceRegistry->AddSources(range, std::move(sources)); - rangeInstance.SetValue(range); - } + TF_VERIFY(srcTopology == *_topology); + } + } + + // bail out if the index bar is already synced + TfToken indexToken; + if (drawItem->GetDrawingCoord()->GetTopologyIndex() == HdStBasisCurves::HullTopology) + { + if ((*dirtyBits & DirtyHullIndices) == 0) + return; + *dirtyBits &= ~DirtyHullIndices; + indexToken = HdTokens->hullIndices; + } + else if (drawItem->GetDrawingCoord()->GetTopologyIndex() == HdStBasisCurves::PointsTopology) + { + if ((*dirtyBits & DirtyPointsIndices) == 0) + return; + *dirtyBits &= ~DirtyPointsIndices; + indexToken = HdTokens->pointsIndices; + } + else + { + if ((*dirtyBits & DirtyIndices) == 0) + return; + *dirtyBits &= ~DirtyIndices; + indexToken = HdTokens->indices; + } + + { + HdInstance rangeInstance = + resourceRegistry->RegisterBasisCurvesIndexRange( + _topologyId, indexToken); + + if (rangeInstance.IsFirstInstance()) + { + HdBufferSourceSharedPtrVector sources; + HdBufferSpecVector bufferSpecs; + + if (desc.geomStyle == HdBasisCurvesGeomStylePoints) + { + sources.push_back( + _topology->GetPointsIndexBuilderComputation()); + } + else + { + sources.push_back(_topology->GetIndexBuilderComputation( + !_SupportsRefinement(_refineLevel))); + } + + HdBufferSpec::GetBufferSpecs(sources, &bufferSpecs); + + // Set up the usage hints to mark topology as varying if + // there is a previously set range. + HdBufferArrayUsageHint usageHint; + usageHint.bits.sizeVarying = drawItem->GetTopologyRange() ? 1 : 0; + + // allocate new range + HdBufferArrayRangeSharedPtr range = resourceRegistry->AllocateNonUniformBufferArrayRange( + HdTokens->topology, bufferSpecs, usageHint); + + // add sources to update queue + resourceRegistry->AddSources(range, std::move(sources)); + rangeInstance.SetValue(range); + } - HdBufferArrayRangeSharedPtr const& newRange = rangeInstance.GetValue(); + HdBufferArrayRangeSharedPtr const &newRange = rangeInstance.GetValue(); - HdStUpdateDrawItemBAR( - newRange, - drawItem->GetDrawingCoord()->GetTopologyIndex(), - &_sharedData, - renderParam, - &changeTracker); - } + HdStUpdateDrawItemBAR( + newRange, + drawItem->GetDrawingCoord()->GetTopologyIndex(), + &_sharedData, + renderParam, + &changeTracker); + } } -namespace { +namespace +{ -template -void -AddVertexOrVaryingPrimvarSource(const SdfPath &id, const TfToken &name, - HdInterpolation interpolation, const VtValue &value, - HdSt_BasisCurvesTopologySharedPtr topology, - HdBufferSourceSharedPtrVector *sources, T fallbackValue) { + template + void + AddVertexOrVaryingPrimvarSource(const SdfPath &id, const TfToken &name, + HdInterpolation interpolation, const VtValue &value, + HdSt_BasisCurvesTopologySharedPtr topology, + HdBufferSourceSharedPtrVector *sources, T fallbackValue) + { VtArray array = value.Get>(); // Empty primvar arrays are ignored, except for points - if (!array.empty() || name == HdTokens->points) { - sources->push_back( - std::make_shared>( - topology, array, id, name, interpolation, fallbackValue, - HdGetValueTupleType(VtValue(array)).type)); + if (!array.empty() || name == HdTokens->points) + { + sources->push_back( + std::make_shared>( + topology, array, id, name, interpolation, fallbackValue, + HdGetValueTupleType(VtValue(array)).type)); } -} - -void ProcessVertexOrVaryingPrimvar( - const SdfPath &id, const TfToken &name, HdInterpolation interpolation, - const VtValue &value, HdSt_BasisCurvesTopologySharedPtr topology, - HdBufferSourceSharedPtrVector *sources) { - if (value.IsHolding()) { - AddVertexOrVaryingPrimvarSource( - id, name, interpolation, value, topology, sources, 1); - } else if (value.IsHolding()) { - AddVertexOrVaryingPrimvarSource( - id, name, interpolation, value, topology, sources, 1); - } else if (value.IsHolding()) { - AddVertexOrVaryingPrimvarSource( - id, name, interpolation, value, topology, sources, GfVec2f(1, 0)); - } else if (value.IsHolding()) { - AddVertexOrVaryingPrimvarSource( - id, name, interpolation, value, topology, sources, GfVec3f(1, 0, 0)); - } else if (value.IsHolding()) { - AddVertexOrVaryingPrimvarSource( - id, name, interpolation, value, topology, sources, GfVec4f(1, 0, 0, 1)); - } else if (value.IsHolding()) { - AddVertexOrVaryingPrimvarSource( - id, name, interpolation, value, topology, sources, 1); - } else if (value.IsHolding()) { - AddVertexOrVaryingPrimvarSource( - id, name, interpolation, value, topology, sources, GfVec2d(1, 0)); - } else if (value.IsHolding()) { - AddVertexOrVaryingPrimvarSource( - id, name, interpolation, value, topology, sources, GfVec3d(1, 0, 0)); - } else if (value.IsHolding()) { - AddVertexOrVaryingPrimvarSource( - id, name, interpolation, value, topology, sources, GfVec4d(1, 0, 0, 1)); - } else if (value.IsHolding()) { - AddVertexOrVaryingPrimvarSource( - id, name, interpolation, value, topology, sources, 1); - } else if (value.IsHolding()) { - AddVertexOrVaryingPrimvarSource( - id, name, interpolation, value, topology, sources, GfVec2i(1, 0)); - } else if (value.IsHolding()) { - AddVertexOrVaryingPrimvarSource( - id, name, interpolation, value, topology, sources, GfVec3i(1, 0, 0)); - } else if (value.IsHolding()) { - AddVertexOrVaryingPrimvarSource( - id, name, interpolation, value, topology, sources, GfVec4i(1, 0, 0, 1)); - } else if (value.IsHolding()) { - AddVertexOrVaryingPrimvarSource( - id, name, interpolation, value, topology, sources, GfVec4i(1, 0, 0, 1)); - } else if (value.IsHolding()) { - AddVertexOrVaryingPrimvarSource( - id, name, interpolation, value, topology, sources, GfVec4i(1, 0, 0, 1)); - } else if (value.IsHolding>()) { - AddVertexOrVaryingPrimvarSource( - id, name, interpolation, value, topology, sources, 1); - } else if (value.IsHolding>()) { - AddVertexOrVaryingPrimvarSource( - id, name, interpolation, value, topology, sources, 1); - } else if (value.IsHolding>()) { - AddVertexOrVaryingPrimvarSource( - id, name, interpolation, value, topology, sources, 1); - } else if (value.IsHolding>()) { - AddVertexOrVaryingPrimvarSource( - id, name, interpolation, value, topology, sources, 1); - } else { - TF_WARN("HdStBasisCurves(%s) - Type of vertex or varying primvar %s" - " not yet fully supported", id.GetText(), name.GetText()); - sources->push_back(std::make_shared(name, value)); + } + + void ProcessVertexOrVaryingPrimvar( + const SdfPath &id, const TfToken &name, HdInterpolation interpolation, + const VtValue &value, HdSt_BasisCurvesTopologySharedPtr topology, + HdBufferSourceSharedPtrVector *sources) + { + if (value.IsHolding()) + { + AddVertexOrVaryingPrimvarSource( + id, name, interpolation, value, topology, sources, 1); } -} -} // anonymous namespace - -void -HdStBasisCurves::_PopulateVertexPrimvars(HdSceneDelegate *sceneDelegate, - HdRenderParam *renderParam, - HdStDrawItem *drawItem, - HdDirtyBits *dirtyBits) -{ - HD_TRACE_FUNCTION(); - HF_MALLOC_TAG_FUNCTION(); - - SdfPath const& id = GetId(); - HdStResourceRegistrySharedPtr const& resourceRegistry = - std::static_pointer_cast( - sceneDelegate->GetRenderIndex().GetResourceRegistry()); - - // The "points" attribute is expected to be in this list. - HdPrimvarDescriptorVector primvars = - HdStGetPrimvarDescriptors(this, drawItem, sceneDelegate, - HdInterpolationVertex); - - HdExtComputationPrimvarDescriptorVector compPrimvars = - sceneDelegate->GetExtComputationPrimvarDescriptors(id, - HdInterpolationVertex); - - HdBufferSourceSharedPtrVector sources; - HdBufferSourceSharedPtrVector reserveOnlySources; - HdBufferSourceSharedPtrVector separateComputationSources; - HdStComputationComputeQueuePairVector computations; - sources.reserve(primvars.size()); - - HdSt_GetExtComputationPrimvarsComputations( - id, - sceneDelegate, - compPrimvars, - *dirtyBits, - &sources, - &reserveOnlySources, - &separateComputationSources, - &computations); - - for (HdPrimvarDescriptor const& primvar: primvars) { - if (!HdChangeTracker::IsPrimvarDirty(*dirtyBits, id, primvar.name)) - continue; - - // TODO: We don't need to pull primvar metadata every time a value - // changes, but we need support from the delegate. - - // Having a null topology is possible, but shouldn't happen when there - // are points - if (!_topology) { - if (primvar.name == HdTokens->points) { - TF_CODING_ERROR("No topology set for BasisCurve %s", - id.GetName().c_str()); - break; - } - continue; - } - - //assert name not in range.bufferArray.GetResources() - VtValue value = GetPrimvar(sceneDelegate, primvar.name); - if (!value.IsEmpty()) { - ProcessVertexOrVaryingPrimvar(id, primvar.name, - HdInterpolationVertex, value, _topology, &sources); - - if (primvar.name == HdTokens->displayOpacity) { - _displayOpacity = true; - } - } + else if (value.IsHolding()) + { + AddVertexOrVaryingPrimvarSource( + id, name, interpolation, value, topology, sources, 1); } - - HdBufferArrayRangeSharedPtr const& bar = drawItem->GetVertexPrimvarRange(); - - if (HdStCanSkipBARAllocationOrUpdate(sources, computations, bar, - *dirtyBits)) { - return; + else if (value.IsHolding()) + { + AddVertexOrVaryingPrimvarSource( + id, name, interpolation, value, topology, sources, GfVec2f(1, 0)); } - - // XXX: This should be based off the DirtyPrimvarDesc bit. - bool hasDirtyPrimvarDesc = (*dirtyBits & HdChangeTracker::DirtyPrimvar); - HdBufferSpecVector removedSpecs; - if (hasDirtyPrimvarDesc) { - TfTokenVector internallyGeneratedPrimvars; // none - removedSpecs = HdStGetRemovedPrimvarBufferSpecs(bar, primvars, - compPrimvars, internallyGeneratedPrimvars, id); + else if (value.IsHolding()) + { + AddVertexOrVaryingPrimvarSource( + id, name, interpolation, value, topology, sources, GfVec3f(1, 0, 0)); } - - HdBufferSpecVector bufferSpecs; - HdBufferSpec::GetBufferSpecs(sources, &bufferSpecs); - HdBufferSpec::GetBufferSpecs(reserveOnlySources, &bufferSpecs); - HdStGetBufferSpecsFromCompuations(computations, &bufferSpecs); - - HdBufferArrayRangeSharedPtr range = - resourceRegistry->UpdateNonUniformBufferArrayRange( - HdTokens->primvar, bar, bufferSpecs, removedSpecs, - HdBufferArrayUsageHint()); - - HdStUpdateDrawItemBAR( - range, - drawItem->GetDrawingCoord()->GetVertexPrimvarIndex(), - &_sharedData, - renderParam, - &(sceneDelegate->GetRenderIndex().GetChangeTracker())); - - if (!sources.empty() || !computations.empty()) { - // If sources or computations are to be queued against the resulting - // BAR, we expect it to be valid. - if (!TF_VERIFY(drawItem->GetVertexPrimvarRange()->IsValid())) { - return; - } + else if (value.IsHolding()) + { + AddVertexOrVaryingPrimvarSource( + id, name, interpolation, value, topology, sources, GfVec4f(1, 0, 0, 1)); } - - // add sources to update queue - if (!sources.empty()) { - resourceRegistry->AddSources(drawItem->GetVertexPrimvarRange(), - std::move(sources)); + else if (value.IsHolding()) + { + AddVertexOrVaryingPrimvarSource( + id, name, interpolation, value, topology, sources, 1); } - // add gpu computations to queue. - for (auto const& compQueuePair : computations) { - HdStComputationSharedPtr const& comp = compQueuePair.first; - HdStComputeQueue queue = compQueuePair.second; - resourceRegistry->AddComputation( - drawItem->GetVertexPrimvarRange(), comp, queue); + else if (value.IsHolding()) + { + AddVertexOrVaryingPrimvarSource( + id, name, interpolation, value, topology, sources, GfVec2d(1, 0)); } - if (!separateComputationSources.empty()) { - TF_FOR_ALL(it, separateComputationSources) { - resourceRegistry->AddSource(*it); - } + else if (value.IsHolding()) + { + AddVertexOrVaryingPrimvarSource( + id, name, interpolation, value, topology, sources, GfVec3d(1, 0, 0)); } -} + else if (value.IsHolding()) + { + AddVertexOrVaryingPrimvarSource( + id, name, interpolation, value, topology, sources, GfVec4d(1, 0, 0, 1)); + } + else if (value.IsHolding()) + { + AddVertexOrVaryingPrimvarSource( + id, name, interpolation, value, topology, sources, 1); + } + else if (value.IsHolding()) + { + AddVertexOrVaryingPrimvarSource( + id, name, interpolation, value, topology, sources, GfVec2i(1, 0)); + } + else if (value.IsHolding()) + { + AddVertexOrVaryingPrimvarSource( + id, name, interpolation, value, topology, sources, GfVec3i(1, 0, 0)); + } + else if (value.IsHolding()) + { + AddVertexOrVaryingPrimvarSource( + id, name, interpolation, value, topology, sources, GfVec4i(1, 0, 0, 1)); + } + else if (value.IsHolding()) + { + AddVertexOrVaryingPrimvarSource( + id, name, interpolation, value, topology, sources, GfVec4i(1, 0, 0, 1)); + } + else if (value.IsHolding()) + { + AddVertexOrVaryingPrimvarSource( + id, name, interpolation, value, topology, sources, GfVec4i(1, 0, 0, 1)); + } + else if (value.IsHolding>()) + { + AddVertexOrVaryingPrimvarSource( + id, name, interpolation, value, topology, sources, 1); + } + else if (value.IsHolding>()) + { + AddVertexOrVaryingPrimvarSource( + id, name, interpolation, value, topology, sources, 1); + } + else if (value.IsHolding>()) + { + AddVertexOrVaryingPrimvarSource( + id, name, interpolation, value, topology, sources, 1); + } + else if (value.IsHolding>()) + { + AddVertexOrVaryingPrimvarSource( + id, name, interpolation, value, topology, sources, 1); + } + else + { + TF_WARN("HdStBasisCurves(%s) - Type of vertex or varying primvar %s" + " not yet fully supported", + id.GetText(), name.GetText()); + sources->push_back(std::make_shared(name, value)); + } + } +} // anonymous namespace -void -HdStBasisCurves::_PopulateVaryingPrimvars(HdSceneDelegate *sceneDelegate, - HdRenderParam *renderParam, - HdStDrawItem *drawItem, - HdDirtyBits *dirtyBits) +void HdStBasisCurves::_PopulateVertexPrimvars(HdSceneDelegate *sceneDelegate, + HdRenderParam *renderParam, + HdStDrawItem *drawItem, + HdDirtyBits *dirtyBits) { - HD_TRACE_FUNCTION(); - HF_MALLOC_TAG_FUNCTION(); - - SdfPath const& id = GetId(); - HdStResourceRegistrySharedPtr const& resourceRegistry = - std::static_pointer_cast( - sceneDelegate->GetRenderIndex().GetResourceRegistry()); - - // Gather varying primvars - HdPrimvarDescriptorVector primvars = - HdStGetPrimvarDescriptors(this, drawItem, sceneDelegate, - HdInterpolationVarying); - - _basisWidthInterpolation = true; - // If we don't find varying normals, then we are assuming - // implicit normals or prescribed basis normals. (For implicit - // normals, varying might be the right fallback behavior, but - // leaving as basis for now to preserve the current behavior - // until we get can do a better pass on curve normals.) - _basisNormalInterpolation = true; - - if (primvars.empty()) { - return; + HD_TRACE_FUNCTION(); + HF_MALLOC_TAG_FUNCTION(); + + SdfPath const &id = GetId(); + HdStResourceRegistrySharedPtr const &resourceRegistry = + std::static_pointer_cast( + sceneDelegate->GetRenderIndex().GetResourceRegistry()); + + // The "points" attribute is expected to be in this list. + HdPrimvarDescriptorVector primvars = + HdStGetPrimvarDescriptors(this, drawItem, sceneDelegate, + HdInterpolationVertex); + + HdExtComputationPrimvarDescriptorVector compPrimvars = + sceneDelegate->GetExtComputationPrimvarDescriptors(id, + HdInterpolationVertex); + + HdBufferSourceSharedPtrVector sources; + HdBufferSourceSharedPtrVector reserveOnlySources; + HdBufferSourceSharedPtrVector separateComputationSources; + HdStComputationComputeQueuePairVector computations; + sources.reserve(primvars.size()); + + HdSt_GetExtComputationPrimvarsComputations( + id, + sceneDelegate, + compPrimvars, + *dirtyBits, + &sources, + &reserveOnlySources, + &separateComputationSources, + &computations); + + for (HdPrimvarDescriptor const &primvar : primvars) + { + if (!HdChangeTracker::IsPrimvarDirty(*dirtyBits, id, primvar.name)) + continue; + + // TODO: We don't need to pull primvar metadata every time a value + // changes, but we need support from the delegate. + + // Having a null topology is possible, but shouldn't happen when there + // are points + if (!_topology) + { + if (primvar.name == HdTokens->points) + { + TF_CODING_ERROR("No topology set for BasisCurve %s", + id.GetName().c_str()); + break; + } + continue; } - - HdBufferSourceSharedPtrVector sources; - sources.reserve(primvars.size()); - - for (HdPrimvarDescriptor const& primvar: primvars) { - if (primvar.name == HdTokens->widths) { - _basisWidthInterpolation = false; - } else if (primvar.name == HdTokens->normals) { - _basisNormalInterpolation = false; - } - - if (!HdChangeTracker::IsPrimvarDirty(*dirtyBits, id, primvar.name)) { - continue; - } - - // TODO: We don't need to pull primvar metadata every time a value - // changes, but we need support from the delegate. - //assert name not in range.bufferArray.GetResources() - VtValue value = GetPrimvar(sceneDelegate, primvar.name); - if (!value.IsEmpty()) { - ProcessVertexOrVaryingPrimvar(id, primvar.name, - HdInterpolationVarying, value, _topology, &sources); + // assert name not in range.bufferArray.GetResources() + VtValue value = GetPrimvar(sceneDelegate, primvar.name); + if (!value.IsEmpty()) + { + ProcessVertexOrVaryingPrimvar(id, primvar.name, + HdInterpolationVertex, value, _topology, &sources); - if (primvar.name == HdTokens->displayOpacity) { - _displayOpacity = true; - } - } + if (primvar.name == HdTokens->displayOpacity) + { + _displayOpacity = true; + } } - - HdBufferArrayRangeSharedPtr const& bar = drawItem->GetVaryingPrimvarRange(); - - if (HdStCanSkipBARAllocationOrUpdate(sources, bar, *dirtyBits)) { - return; + } + + HdBufferArrayRangeSharedPtr const &bar = drawItem->GetVertexPrimvarRange(); + + if (HdStCanSkipBARAllocationOrUpdate(sources, computations, bar, + *dirtyBits)) + { + return; + } + + // XXX: This should be based off the DirtyPrimvarDesc bit. + bool hasDirtyPrimvarDesc = (*dirtyBits & HdChangeTracker::DirtyPrimvar); + HdBufferSpecVector removedSpecs; + if (hasDirtyPrimvarDesc) + { + TfTokenVector internallyGeneratedPrimvars; // none + removedSpecs = HdStGetRemovedPrimvarBufferSpecs(bar, primvars, + compPrimvars, internallyGeneratedPrimvars, id); + } + + HdBufferSpecVector bufferSpecs; + HdBufferSpec::GetBufferSpecs(sources, &bufferSpecs); + HdBufferSpec::GetBufferSpecs(reserveOnlySources, &bufferSpecs); + HdStGetBufferSpecsFromCompuations(computations, &bufferSpecs); + + HdBufferArrayRangeSharedPtr range = + resourceRegistry->UpdateNonUniformBufferArrayRange( + HdTokens->primvar, bar, bufferSpecs, removedSpecs, + HdBufferArrayUsageHint()); + + HdStUpdateDrawItemBAR( + range, + drawItem->GetDrawingCoord()->GetVertexPrimvarIndex(), + &_sharedData, + renderParam, + &(sceneDelegate->GetRenderIndex().GetChangeTracker())); + + if (!sources.empty() || !computations.empty()) + { + // If sources or computations are to be queued against the resulting + // BAR, we expect it to be valid. + if (!TF_VERIFY(drawItem->GetVertexPrimvarRange()->IsValid())) + { + return; } + } + + // add sources to update queue + if (!sources.empty()) + { + resourceRegistry->AddSources(drawItem->GetVertexPrimvarRange(), + std::move(sources)); + } + // add gpu computations to queue. + for (auto const &compQueuePair : computations) + { + HdStComputationSharedPtr const &comp = compQueuePair.first; + HdStComputeQueue queue = compQueuePair.second; + resourceRegistry->AddComputation( + drawItem->GetVertexPrimvarRange(), comp, queue); + } + if (!separateComputationSources.empty()) + { + TF_FOR_ALL(it, separateComputationSources) + { + resourceRegistry->AddSource(*it); + } + } +} - // XXX: This should be based off the DirtyPrimvarDesc bit. - bool hasDirtyPrimvarDesc = (*dirtyBits & HdChangeTracker::DirtyPrimvar); - HdBufferSpecVector removedSpecs; - if (hasDirtyPrimvarDesc) { - TfTokenVector internallyGeneratedPrimvars; // none - removedSpecs = HdStGetRemovedPrimvarBufferSpecs(bar, primvars, - internallyGeneratedPrimvars, id); +void HdStBasisCurves::_PopulateVaryingPrimvars(HdSceneDelegate *sceneDelegate, + HdRenderParam *renderParam, + HdStDrawItem *drawItem, + HdDirtyBits *dirtyBits) +{ + HD_TRACE_FUNCTION(); + HF_MALLOC_TAG_FUNCTION(); + + SdfPath const &id = GetId(); + HdStResourceRegistrySharedPtr const &resourceRegistry = + std::static_pointer_cast( + sceneDelegate->GetRenderIndex().GetResourceRegistry()); + + // Gather varying primvars + HdPrimvarDescriptorVector primvars = + HdStGetPrimvarDescriptors(this, drawItem, sceneDelegate, + HdInterpolationVarying); + + _basisWidthInterpolation = true; + // If we don't find varying normals, then we are assuming + // implicit normals or prescribed basis normals. (For implicit + // normals, varying might be the right fallback behavior, but + // leaving as basis for now to preserve the current behavior + // until we get can do a better pass on curve normals.) + _basisNormalInterpolation = true; + + if (primvars.empty()) + { + return; + } + + HdBufferSourceSharedPtrVector sources; + sources.reserve(primvars.size()); + + for (HdPrimvarDescriptor const &primvar : primvars) + { + if (primvar.name == HdTokens->widths) + { + _basisWidthInterpolation = false; + } + else if (primvar.name == HdTokens->normals) + { + _basisNormalInterpolation = false; } - HdBufferSpecVector bufferSpecs; - HdBufferSpec::GetBufferSpecs(sources, &bufferSpecs); + if (!HdChangeTracker::IsPrimvarDirty(*dirtyBits, id, primvar.name)) + { + continue; + } - HdBufferArrayRangeSharedPtr range = - resourceRegistry->UpdateNonUniformBufferArrayRange( - HdTokens->primvar, bar, bufferSpecs, removedSpecs, - HdBufferArrayUsageHint()); + // TODO: We don't need to pull primvar metadata every time a value + // changes, but we need support from the delegate. - HdStUpdateDrawItemBAR( - range, - drawItem->GetDrawingCoord()->GetVaryingPrimvarIndex(), - &_sharedData, - renderParam, - &(sceneDelegate->GetRenderIndex().GetChangeTracker())); + // assert name not in range.bufferArray.GetResources() + VtValue value = GetPrimvar(sceneDelegate, primvar.name); + if (!value.IsEmpty()) + { + ProcessVertexOrVaryingPrimvar(id, primvar.name, + HdInterpolationVarying, value, _topology, &sources); - // add sources to update queue - if (!sources.empty()) { - if (!TF_VERIFY(drawItem->GetVaryingPrimvarRange()->IsValid())) { - return; - } - resourceRegistry->AddSources(drawItem->GetVaryingPrimvarRange(), - std::move(sources)); + if (primvar.name == HdTokens->displayOpacity) + { + _displayOpacity = true; + } + } + } + + HdBufferArrayRangeSharedPtr const &bar = drawItem->GetVaryingPrimvarRange(); + + if (HdStCanSkipBARAllocationOrUpdate(sources, bar, *dirtyBits)) + { + return; + } + + // XXX: This should be based off the DirtyPrimvarDesc bit. + bool hasDirtyPrimvarDesc = (*dirtyBits & HdChangeTracker::DirtyPrimvar); + HdBufferSpecVector removedSpecs; + if (hasDirtyPrimvarDesc) + { + TfTokenVector internallyGeneratedPrimvars; // none + removedSpecs = HdStGetRemovedPrimvarBufferSpecs(bar, primvars, + internallyGeneratedPrimvars, id); + } + + HdBufferSpecVector bufferSpecs; + HdBufferSpec::GetBufferSpecs(sources, &bufferSpecs); + + HdBufferArrayRangeSharedPtr range = + resourceRegistry->UpdateNonUniformBufferArrayRange( + HdTokens->primvar, bar, bufferSpecs, removedSpecs, + HdBufferArrayUsageHint()); + + HdStUpdateDrawItemBAR( + range, + drawItem->GetDrawingCoord()->GetVaryingPrimvarIndex(), + &_sharedData, + renderParam, + &(sceneDelegate->GetRenderIndex().GetChangeTracker())); + + // add sources to update queue + if (!sources.empty()) + { + if (!TF_VERIFY(drawItem->GetVaryingPrimvarRange()->IsValid())) + { + return; } + resourceRegistry->AddSources(drawItem->GetVaryingPrimvarRange(), + std::move(sources)); + } } -void -HdStBasisCurves::_PopulateElementPrimvars(HdSceneDelegate *sceneDelegate, - HdRenderParam *renderParam, - HdStDrawItem *drawItem, - HdDirtyBits *dirtyBits) +void HdStBasisCurves::_PopulateElementPrimvars(HdSceneDelegate *sceneDelegate, + HdRenderParam *renderParam, + HdStDrawItem *drawItem, + HdDirtyBits *dirtyBits) { - HD_TRACE_FUNCTION(); - HF_MALLOC_TAG_FUNCTION(); + HD_TRACE_FUNCTION(); + HF_MALLOC_TAG_FUNCTION(); - SdfPath const& id = GetId(); - HdRenderIndex &renderIndex = sceneDelegate->GetRenderIndex(); - HdStResourceRegistrySharedPtr const& resourceRegistry = - std::static_pointer_cast( - renderIndex.GetResourceRegistry()); + SdfPath const &id = GetId(); + HdRenderIndex &renderIndex = sceneDelegate->GetRenderIndex(); + HdStResourceRegistrySharedPtr const &resourceRegistry = + std::static_pointer_cast( + renderIndex.GetResourceRegistry()); - HdPrimvarDescriptorVector uniformPrimvars = - HdStGetPrimvarDescriptors(this, drawItem, sceneDelegate, - HdInterpolationUniform); - - HdBufferSourceSharedPtrVector sources; - sources.reserve(uniformPrimvars.size()); - - const size_t numCurves = _topology ? _topology->GetNumCurves() : 0; - - for (HdPrimvarDescriptor const& primvar: uniformPrimvars) { - if (!HdChangeTracker::IsPrimvarDirty(*dirtyBits, id, primvar.name)) - continue; - - VtValue value = GetPrimvar(sceneDelegate, primvar.name); - if (!value.IsEmpty()) { - HdBufferSourceSharedPtr source = - std::make_shared(primvar.name, value); - - // verify primvar length - if (source->GetNumElements() != numCurves) { - HF_VALIDATION_WARN(id, - "# of curves mismatch (%d != %d) for uniform primvar %s", - (int)source->GetNumElements(), (int)numCurves, - primvar.name.GetText()); - continue; - } - - sources.push_back(source); - - if (primvar.name == HdTokens->displayOpacity) { - _displayOpacity = true; - } - } - } - - HdBufferArrayRangeSharedPtr const& bar = drawItem->GetElementPrimvarRange(); - - if (HdStCanSkipBARAllocationOrUpdate(sources, bar, *dirtyBits)) { - return; - } - - // XXX: This should be based off the DirtyPrimvarDesc bit. - bool hasDirtyPrimvarDesc = (*dirtyBits & HdChangeTracker::DirtyPrimvar); - HdBufferSpecVector removedSpecs; - if (hasDirtyPrimvarDesc) { - TfTokenVector internallyGeneratedPrimvars; // none - removedSpecs = HdStGetRemovedPrimvarBufferSpecs(bar, uniformPrimvars, - internallyGeneratedPrimvars, id); - } + HdPrimvarDescriptorVector uniformPrimvars = + HdStGetPrimvarDescriptors(this, drawItem, sceneDelegate, + HdInterpolationUniform); - HdBufferSpecVector bufferSpecs; - HdBufferSpec::GetBufferSpecs(sources, &bufferSpecs); - - HdBufferArrayRangeSharedPtr range = - resourceRegistry->UpdateNonUniformBufferArrayRange( - HdTokens->primvar, bar, bufferSpecs, removedSpecs, - HdBufferArrayUsageHint()); - - HdStUpdateDrawItemBAR( - range, - drawItem->GetDrawingCoord()->GetElementPrimvarIndex(), - &_sharedData, - renderParam, - &(sceneDelegate->GetRenderIndex().GetChangeTracker())); + HdBufferSourceSharedPtrVector sources; + sources.reserve(uniformPrimvars.size()); + const size_t numCurves = _topology ? _topology->GetNumCurves() : 0; - if (!sources.empty()) { - // If sources are to be queued against the resulting BAR, we expect it - // to be valid. - if (!TF_VERIFY(drawItem->GetElementPrimvarRange()->IsValid())) { - return; - } - resourceRegistry->AddSources(drawItem->GetElementPrimvarRange(), - std::move(sources)); - } -} + for (HdPrimvarDescriptor const &primvar : uniformPrimvars) + { + if (!HdChangeTracker::IsPrimvarDirty(*dirtyBits, id, primvar.name)) + continue; -static bool -HdSt_HasResource(HdStDrawItem* drawItem, const TfToken& resourceToken){ - // Check for authored resource, we could leverage dirtyBits here as an - // optimization, however the BAR is the ground truth, so until there is a - // known peformance issue, we just check them explicitly. - bool hasAuthoredResouce = false; - - typedef HdBufferArrayRangeSharedPtr HdBarPtr; - if (HdBarPtr const& bar = drawItem->GetConstantPrimvarRange()){ - HdStBufferArrayRangeSharedPtr bar_ = - std::static_pointer_cast (bar); - hasAuthoredResouce |= bool(bar_->GetResource(resourceToken)); - } - if (HdBarPtr const& bar = drawItem->GetVertexPrimvarRange()) { - HdStBufferArrayRangeSharedPtr bar_ = - std::static_pointer_cast (bar); - hasAuthoredResouce |= bool(bar_->GetResource(resourceToken)); + VtValue value = GetPrimvar(sceneDelegate, primvar.name); + if (!value.IsEmpty()) + { + HdBufferSourceSharedPtr source = + std::make_shared(primvar.name, value); + + // verify primvar length + if (source->GetNumElements() != numCurves) + { + HF_VALIDATION_WARN(id, + "# of curves mismatch (%d != %d) for uniform primvar %s", + (int)source->GetNumElements(), (int)numCurves, + primvar.name.GetText()); + continue; + } + + sources.push_back(source); + + if (primvar.name == HdTokens->displayOpacity) + { + _displayOpacity = true; + } } - if (HdBarPtr const& bar = drawItem->GetVaryingPrimvarRange()){ - HdStBufferArrayRangeSharedPtr bar_ = - std::static_pointer_cast (bar); - - hasAuthoredResouce |= bool(bar_->GetResource(resourceToken)); + } + + HdBufferArrayRangeSharedPtr const &bar = drawItem->GetElementPrimvarRange(); + + if (HdStCanSkipBARAllocationOrUpdate(sources, bar, *dirtyBits)) + { + return; + } + + // XXX: This should be based off the DirtyPrimvarDesc bit. + bool hasDirtyPrimvarDesc = (*dirtyBits & HdChangeTracker::DirtyPrimvar); + HdBufferSpecVector removedSpecs; + if (hasDirtyPrimvarDesc) + { + TfTokenVector internallyGeneratedPrimvars; // none + removedSpecs = HdStGetRemovedPrimvarBufferSpecs(bar, uniformPrimvars, + internallyGeneratedPrimvars, id); + } + + HdBufferSpecVector bufferSpecs; + HdBufferSpec::GetBufferSpecs(sources, &bufferSpecs); + + HdBufferArrayRangeSharedPtr range = + resourceRegistry->UpdateNonUniformBufferArrayRange( + HdTokens->primvar, bar, bufferSpecs, removedSpecs, + HdBufferArrayUsageHint()); + + HdStUpdateDrawItemBAR( + range, + drawItem->GetDrawingCoord()->GetElementPrimvarIndex(), + &_sharedData, + renderParam, + &(sceneDelegate->GetRenderIndex().GetChangeTracker())); + + if (!sources.empty()) + { + // If sources are to be queued against the resulting BAR, we expect it + // to be valid. + if (!TF_VERIFY(drawItem->GetElementPrimvarRange()->IsValid())) + { + return; } - if (HdBarPtr const& bar = drawItem->GetElementPrimvarRange()){ - HdStBufferArrayRangeSharedPtr bar_ = - std::static_pointer_cast (bar); + resourceRegistry->AddSources(drawItem->GetElementPrimvarRange(), + std::move(sources)); + } +} - hasAuthoredResouce |= bool(bar_->GetResource(resourceToken)); - } - int instanceNumLevels = drawItem->GetInstancePrimvarNumLevels(); - for (int i = 0; i < instanceNumLevels; ++i) { - if (HdBarPtr const& bar = drawItem->GetInstancePrimvarRange(i)) { - HdStBufferArrayRangeSharedPtr bar_ = - std::static_pointer_cast (bar); +static bool +HdSt_HasResource(HdStDrawItem *drawItem, const TfToken &resourceToken) +{ + // Check for authored resource, we could leverage dirtyBits here as an + // optimization, however the BAR is the ground truth, so until there is a + // known peformance issue, we just check them explicitly. + bool hasAuthoredResouce = false; + + typedef HdBufferArrayRangeSharedPtr HdBarPtr; + if (HdBarPtr const &bar = drawItem->GetConstantPrimvarRange()) + { + HdStBufferArrayRangeSharedPtr bar_ = + std::static_pointer_cast(bar); + hasAuthoredResouce |= bool(bar_->GetResource(resourceToken)); + } + if (HdBarPtr const &bar = drawItem->GetVertexPrimvarRange()) + { + HdStBufferArrayRangeSharedPtr bar_ = + std::static_pointer_cast(bar); + hasAuthoredResouce |= bool(bar_->GetResource(resourceToken)); + } + if (HdBarPtr const &bar = drawItem->GetVaryingPrimvarRange()) + { + HdStBufferArrayRangeSharedPtr bar_ = + std::static_pointer_cast(bar); + + hasAuthoredResouce |= bool(bar_->GetResource(resourceToken)); + } + if (HdBarPtr const &bar = drawItem->GetElementPrimvarRange()) + { + HdStBufferArrayRangeSharedPtr bar_ = + std::static_pointer_cast(bar); + + hasAuthoredResouce |= bool(bar_->GetResource(resourceToken)); + } + int instanceNumLevels = drawItem->GetInstancePrimvarNumLevels(); + for (int i = 0; i < instanceNumLevels; ++i) + { + if (HdBarPtr const &bar = drawItem->GetInstancePrimvarRange(i)) + { + HdStBufferArrayRangeSharedPtr bar_ = + std::static_pointer_cast(bar); - hasAuthoredResouce |= bool(bar_->GetResource(resourceToken)); - } + hasAuthoredResouce |= bool(bar_->GetResource(resourceToken)); } - return hasAuthoredResouce; + } + return hasAuthoredResouce; } -bool -HdStBasisCurves::_SupportsRefinement(int refineLevel) +bool HdStBasisCurves::_SupportsRefinement(int refineLevel) { - if(!_topology) { - TF_CODING_ERROR("Calling _SupportsRefinement before topology is set"); - return false; - } + if (!_topology) + { + TF_CODING_ERROR("Calling _SupportsRefinement before topology is set"); + return false; + } - return refineLevel > 0 || IsEnabledForceRefinedCurves(); + return refineLevel > 0 || IsEnabledForceRefinedCurves(); } -bool -HdStBasisCurves::_SupportsUserWidths(HdStDrawItem* drawItem){ - return HdSt_HasResource(drawItem, HdTokens->widths); +bool HdStBasisCurves::_SupportsUserWidths(HdStDrawItem *drawItem) +{ + return HdSt_HasResource(drawItem, HdTokens->widths); } -bool -HdStBasisCurves::_SupportsUserNormals(HdStDrawItem* drawItem){ - return HdSt_HasResource(drawItem, HdTokens->normals); +bool HdStBasisCurves::_SupportsUserNormals(HdStDrawItem *drawItem) +{ + return HdSt_HasResource(drawItem, HdTokens->normals); } HdDirtyBits HdStBasisCurves::GetInitialDirtyBitsMask() const { - HdDirtyBits mask = HdChangeTracker::Clean - | HdChangeTracker::InitRepr - | HdChangeTracker::DirtyExtent - | HdChangeTracker::DirtyNormals - | HdChangeTracker::DirtyPoints - | HdChangeTracker::DirtyPrimID - | HdChangeTracker::DirtyPrimvar - | HdChangeTracker::DirtyDisplayStyle - | HdChangeTracker::DirtyRepr - | HdChangeTracker::DirtyMaterialId - | HdChangeTracker::DirtyTopology - | HdChangeTracker::DirtyTransform - | HdChangeTracker::DirtyVisibility - | HdChangeTracker::DirtyWidths - | HdChangeTracker::DirtyComputationPrimvarDesc - | HdChangeTracker::DirtyInstancer - ; - - return mask; + HdDirtyBits mask = HdChangeTracker::Clean | HdChangeTracker::InitRepr | HdChangeTracker::DirtyExtent | HdChangeTracker::DirtyNormals | HdChangeTracker::DirtyPoints | HdChangeTracker::DirtyPrimID | HdChangeTracker::DirtyPrimvar | HdChangeTracker::DirtyDisplayStyle | HdChangeTracker::DirtyRepr | HdChangeTracker::DirtyMaterialId | HdChangeTracker::DirtyTopology | HdChangeTracker::DirtyTransform | HdChangeTracker::DirtyVisibility | HdChangeTracker::DirtyWidths | HdChangeTracker::DirtyComputationPrimvarDesc | HdChangeTracker::DirtyInstancer; + + return mask; } /*override*/ TfTokenVector const & HdStBasisCurves::GetBuiltinPrimvarNames() const { - // screenSpaceWidths toggles the interpretation of widths to be in - // screen-space pixels. We expect this to be useful for implementing guides - // or other UI elements drawn with BasisCurves. The pointsSizeScale primvar - // similarly is intended to give clients a way to emphasize or supress - // certain points by scaling their default size. - - // minScreenSpaceWidth gives a minimum screen space width in pixels for - // BasisCurves when rendered as tubes or camera-facing ribbons. We expect - // this to be useful for preventing thin curves such as hair from - // undesirably aliasing when their screen space width would otherwise dip - // below one pixel. - - // pointSizeScale, screenSpaceWidths, and minScreenSpaceWidths are - // explicitly claimed here as "builtin" primvar names because they are - // consumed in the low-level baisCurves.glslfx rather than declared as - // inputs in any material shader's metadata. Mentioning them here means - // they will always survive primvar filtering. - - auto _ComputePrimvarNames = [this](){ - TfTokenVector primvarNames = - this->HdBasisCurves::GetBuiltinPrimvarNames(); - primvarNames.push_back(HdStTokens->pointSizeScale); - primvarNames.push_back(HdStTokens->screenSpaceWidths); - primvarNames.push_back(HdStTokens->minScreenSpaceWidths); - return primvarNames; - }; - static TfTokenVector primvarNames = _ComputePrimvarNames(); + // screenSpaceWidths toggles the interpretation of widths to be in + // screen-space pixels. We expect this to be useful for implementing guides + // or other UI elements drawn with BasisCurves. The pointsSizeScale primvar + // similarly is intended to give clients a way to emphasize or supress + // certain points by scaling their default size. + + // minScreenSpaceWidth gives a minimum screen space width in pixels for + // BasisCurves when rendered as tubes or camera-facing ribbons. We expect + // this to be useful for preventing thin curves such as hair from + // undesirably aliasing when their screen space width would otherwise dip + // below one pixel. + + // pointSizeScale, screenSpaceWidths, and minScreenSpaceWidths are + // explicitly claimed here as "builtin" primvar names because they are + // consumed in the low-level baisCurves.glslfx rather than declared as + // inputs in any material shader's metadata. Mentioning them here means + // they will always survive primvar filtering. + + auto _ComputePrimvarNames = [this]() + { + TfTokenVector primvarNames = + this->HdBasisCurves::GetBuiltinPrimvarNames(); + primvarNames.push_back(HdStTokens->pointSizeScale); + primvarNames.push_back(HdStTokens->screenSpaceWidths); + primvarNames.push_back(HdStTokens->minScreenSpaceWidths); return primvarNames; + }; + static TfTokenVector primvarNames = _ComputePrimvarNames(); + return primvarNames; } PXR_NAMESPACE_CLOSE_SCOPE diff --git a/Sources/OpenUSD/imaging/hdSt/extCompComputeShader.cpp b/Sources/OpenUSD/imaging/hdSt/extCompComputeShader.cpp index 9b17b6d895..c8e56a0d2f 100644 --- a/Sources/OpenUSD/imaging/hdSt/extCompComputeShader.cpp +++ b/Sources/OpenUSD/imaging/hdSt/extCompComputeShader.cpp @@ -28,17 +28,15 @@ #include "pxr/imaging/hd/tokens.h" -#include "pxr/base/arch/hash.h" +#include "Arch/hash.h" #include PXR_NAMESPACE_OPEN_SCOPE - - HdSt_ExtCompComputeShader::HdSt_ExtCompComputeShader( HdExtComputation const *extComp) - : _extComp(extComp) + : _extComp(extComp) { } @@ -52,62 +50,63 @@ HdSt_ExtCompComputeShader::~HdSt_ExtCompComputeShader() = default; std::string HdSt_ExtCompComputeShader::GetSource(TfToken const &shaderStageKey) const { - if (shaderStageKey == HdShaderTokens->computeShader) { - if (TF_VERIFY(_extComp)) { - return _extComp->GetGpuKernelSource(); - } + if (shaderStageKey == HdShaderTokens->computeShader) + { + if (TF_VERIFY(_extComp)) + { + return _extComp->GetGpuKernelSource(); } + } - return std::string(); + return std::string(); } /*virtual*/ -void -HdSt_ExtCompComputeShader::BindResources(const int program, - HdSt_ResourceBinder const &binder) +void HdSt_ExtCompComputeShader::BindResources(const int program, + HdSt_ResourceBinder const &binder) { - // Compute shaders currently serve GPU ExtComputations, wherein - // resource binding is managed explicitly. - // See HdStExtCompGpuComputationResource::Resolve() and - // HdStExtCompGpuComputation::Execute(..) + // Compute shaders currently serve GPU ExtComputations, wherein + // resource binding is managed explicitly. + // See HdStExtCompGpuComputationResource::Resolve() and + // HdStExtCompGpuComputation::Execute(..) } /*virtual*/ -void -HdSt_ExtCompComputeShader::UnbindResources(const int program, - HdSt_ResourceBinder const &binder) +void HdSt_ExtCompComputeShader::UnbindResources(const int program, + HdSt_ResourceBinder const &binder) { - // Resource binding is managed explicitly. See above comment. + // Resource binding is managed explicitly. See above comment. } /*virtual*/ -void -HdSt_ExtCompComputeShader::AddBindings(HdStBindingRequestVector *customBindings) +void HdSt_ExtCompComputeShader::AddBindings(HdStBindingRequestVector *customBindings) { - // Resource binding is managed explicitly. See above comment. + // Resource binding is managed explicitly. See above comment. } /*virtual*/ HdStShaderCode::ID HdSt_ExtCompComputeShader::ComputeHash() const { - if (!TF_VERIFY(_extComp)) { - return 0; - } - - size_t hash = 0; - std::string const & kernel = _extComp->GetGpuKernelSource(); - boost::hash_combine(hash, ArchHash(kernel.c_str(), kernel.size())); - return hash; + if (!TF_VERIFY(_extComp)) + { + return 0; + } + + size_t hash = 0; + std::string const &kernel = _extComp->GetGpuKernelSource(); + boost::hash_combine(hash, ArchHash(kernel.c_str(), kernel.size())); + return hash; } -SdfPath const& +SdfPath const & HdSt_ExtCompComputeShader::GetExtComputationId() const { - if (!TF_VERIFY(_extComp)) { - return SdfPath::EmptyPath(); - } - return _extComp->GetId(); + if (!TF_VERIFY(_extComp)) + { + return SdfPath::EmptyPath(); + } + return _extComp->GetId(); } PXR_NAMESPACE_CLOSE_SCOPE diff --git a/Sources/OpenUSD/imaging/hdSt/extComputation.cpp b/Sources/OpenUSD/imaging/hdSt/extComputation.cpp index d1ad2e278d..d4dcbfc582 100644 --- a/Sources/OpenUSD/imaging/hdSt/extComputation.cpp +++ b/Sources/OpenUSD/imaging/hdSt/extComputation.cpp @@ -35,14 +35,12 @@ #include "pxr/imaging/hgi/capabilities.h" -#include "pxr/base/arch/hash.h" +#include "Arch/hash.h" PXR_NAMESPACE_OPEN_SCOPE - HdStExtComputation::HdStExtComputation(SdfPath const &id) - : HdExtComputation(id) - , _inputRange() + : HdExtComputation(id), _inputRange() { } @@ -57,185 +55,189 @@ HdStExtComputation::~HdStExtComputation() = default; // mutated. If that changes, then we will have to deal with // migrating shared data to a non-shared buffer so that it // can be modified safely. -// +// static uint64_t _ComputeSharedComputationInputId(uint64_t baseId, HdBufferSourceSharedPtrVector const &sources) { - size_t inputId = baseId; - for (HdBufferSourceSharedPtr const &bufferSource : sources) { - size_t sourceId = bufferSource->ComputeHash(); - inputId = ArchHash64((const char*)&sourceId, - sizeof(sourceId), inputId); - } - return inputId; + size_t inputId = baseId; + for (HdBufferSourceSharedPtr const &bufferSource : sources) + { + size_t sourceId = bufferSource->ComputeHash(); + inputId = ArchHash64((const char *)&sourceId, + sizeof(sourceId), inputId); + } + return inputId; } static HdBufferArrayRangeSharedPtr _AllocateComputationDataRange( - HdBufferSourceSharedPtrVector && inputs, - HdStResourceRegistrySharedPtr const & resourceRegistry) + HdBufferSourceSharedPtrVector &&inputs, + HdStResourceRegistrySharedPtr const &resourceRegistry) { - HdBufferSpecVector bufferSpecs; - HdBufferSpec::GetBufferSpecs(inputs, &bufferSpecs); + HdBufferSpecVector bufferSpecs; + HdBufferSpec::GetBufferSpecs(inputs, &bufferSpecs); - HdBufferArrayRangeSharedPtr inputRange = - resourceRegistry->AllocateShaderStorageBufferArrayRange( - HdPrimTypeTokens->extComputation, - bufferSpecs, - HdBufferArrayUsageHint()); - resourceRegistry->AddSources(inputRange, std::move(inputs)); + HdBufferArrayRangeSharedPtr inputRange = + resourceRegistry->AllocateShaderStorageBufferArrayRange( + HdPrimTypeTokens->extComputation, + bufferSpecs, + HdBufferArrayUsageHint()); + resourceRegistry->AddSources(inputRange, std::move(inputs)); - return inputRange; + return inputRange; } -void -HdStExtComputation::Sync(HdSceneDelegate *sceneDelegate, - HdRenderParam *renderParam, - HdDirtyBits *dirtyBits) +void HdStExtComputation::Sync(HdSceneDelegate *sceneDelegate, + HdRenderParam *renderParam, + HdDirtyBits *dirtyBits) { - HD_TRACE_FUNCTION(); - HF_MALLOC_TAG_FUNCTION(); - - HdExtComputation::_Sync(sceneDelegate, renderParam, dirtyBits); - - TF_DEBUG(HD_EXT_COMPUTATION_UPDATED).Msg( - "HdStExtComputation::Sync for %s (dirty bits = 0x%x)\n", - GetId().GetText(), *dirtyBits); - - // During Sprim sync, we only commit GPU resources when directly executing a - // GPU computation or when aggregating inputs for a downstream computation. - // Note: For CPU computations, we pull the inputs when we create the - // HdStExtCompCpuComputation, which happens during Rprim sync. - if (GetGpuKernelSource().empty() && !IsInputAggregation()) { - return; + HD_TRACE_FUNCTION(); + HF_MALLOC_TAG_FUNCTION(); + + HdExtComputation::_Sync(sceneDelegate, renderParam, dirtyBits); + + TF_DEBUG(HD_EXT_COMPUTATION_UPDATED).Msg("HdStExtComputation::Sync for %s (dirty bits = 0x%x)\n", GetId().GetText(), *dirtyBits); + + // During Sprim sync, we only commit GPU resources when directly executing a + // GPU computation or when aggregating inputs for a downstream computation. + // Note: For CPU computations, we pull the inputs when we create the + // HdStExtCompCpuComputation, which happens during Rprim sync. + if (GetGpuKernelSource().empty() && !IsInputAggregation()) + { + return; + } + + if (!(*dirtyBits & DirtySceneInput)) + { + // No scene inputs to sync. All other computation dirty bits (barring + // DirtyCompInput) are sync'd in HdExtComputation::_Sync. + return; + } + + HdRenderIndex &renderIndex = sceneDelegate->GetRenderIndex(); + HdStResourceRegistrySharedPtr const &resourceRegistry = + std::dynamic_pointer_cast( + renderIndex.GetResourceRegistry()); + + HgiCapabilities const *capabilities = + resourceRegistry->GetHgi()->GetCapabilities(); + bool const doublesSupported = + capabilities->IsSet(HgiDeviceCapabilitiesBitsShaderDoublePrecision); + + HdBufferSourceSharedPtrVector inputs; + for (TfToken const &inputName : GetSceneInputNames()) + { + VtValue inputValue = sceneDelegate->GetExtComputationInput( + GetId(), inputName); + size_t arraySize = + inputValue.IsArrayValued() ? inputValue.GetArraySize() : 1; + HdBufferSourceSharedPtr const inputSource = + std::make_shared(inputName, inputValue, + arraySize, doublesSupported); + if (inputSource->IsValid()) + { + inputs.push_back(inputSource); } - - if (!(*dirtyBits & DirtySceneInput)) { - // No scene inputs to sync. All other computation dirty bits (barring - // DirtyCompInput) are sync'd in HdExtComputation::_Sync. - return; + else + { + TF_WARN("Unsupported type %s for source %s in extComputation %s.", + inputValue.GetType().GetTypeName().c_str(), + inputName.GetText(), GetId().GetText()); } - - HdRenderIndex &renderIndex = sceneDelegate->GetRenderIndex(); - HdStResourceRegistrySharedPtr const & resourceRegistry = - std::dynamic_pointer_cast( - renderIndex.GetResourceRegistry()); - - HgiCapabilities const * capabilities = - resourceRegistry->GetHgi()->GetCapabilities(); - bool const doublesSupported = - capabilities->IsSet(HgiDeviceCapabilitiesBitsShaderDoublePrecision); - - HdBufferSourceSharedPtrVector inputs; - for (TfToken const & inputName: GetSceneInputNames()) { - VtValue inputValue = sceneDelegate->GetExtComputationInput( - GetId(), inputName); - size_t arraySize = - inputValue.IsArrayValued() ? inputValue.GetArraySize() : 1; - HdBufferSourceSharedPtr const inputSource = - std::make_shared(inputName, inputValue, - arraySize, doublesSupported); - if (inputSource->IsValid()) { - inputs.push_back(inputSource); - } else { - TF_WARN("Unsupported type %s for source %s in extComputation %s.", - inputValue.GetType().GetTypeName().c_str(), - inputName.GetText(), GetId().GetText()); - } + } + + // Store the current range to know if garbage collection is necessary. + HdBufferArrayRangeSharedPtr const prevRange = _inputRange; + + if (!inputs.empty()) + { + if (_IsEnabledSharedExtComputationData() && IsInputAggregation()) + { + uint64_t inputId = _ComputeSharedComputationInputId(0, inputs); + + HdInstance barInstance = + resourceRegistry->RegisterExtComputationDataRange(inputId); + + if (barInstance.IsFirstInstance()) + { + // Allocate the first buffer range for this input key + _inputRange = _AllocateComputationDataRange(std::move(inputs), + resourceRegistry); + barInstance.SetValue(_inputRange); + + TF_DEBUG(HD_SHARED_EXT_COMPUTATION_DATA).Msg("Allocated shared ExtComputation buffer range: %s: %p\n", GetId().GetText(), (void *)_inputRange.get()); + } + else + { + // Share the existing buffer range for this input key + _inputRange = barInstance.GetValue(); + + TF_DEBUG(HD_SHARED_EXT_COMPUTATION_DATA).Msg("Reused shared ExtComputation buffer range: %s: %p\n", GetId().GetText(), (void *)_inputRange.get()); + } } - - // Store the current range to know if garbage collection is necessary. - HdBufferArrayRangeSharedPtr const prevRange = _inputRange; - - if (!inputs.empty()) { - if (_IsEnabledSharedExtComputationData() && IsInputAggregation()) { - uint64_t inputId = _ComputeSharedComputationInputId(0, inputs); - - HdInstance barInstance = - resourceRegistry->RegisterExtComputationDataRange(inputId); - - if (barInstance.IsFirstInstance()) { - // Allocate the first buffer range for this input key - _inputRange = _AllocateComputationDataRange(std::move(inputs), - resourceRegistry); - barInstance.SetValue(_inputRange); - - TF_DEBUG(HD_SHARED_EXT_COMPUTATION_DATA).Msg( - "Allocated shared ExtComputation buffer range: %s: %p\n", - GetId().GetText(), (void *)_inputRange.get()); - } else { - // Share the existing buffer range for this input key - _inputRange = barInstance.GetValue(); - - TF_DEBUG(HD_SHARED_EXT_COMPUTATION_DATA).Msg( - "Reused shared ExtComputation buffer range: %s: %p\n", - GetId().GetText(), (void *)_inputRange.get()); - } - - } else { - // We're not sharing. - - // We don't yet have the ability to track dirtiness per scene input. - // Each time DirtySceneInput is set, we pull and upload _all_ the - // scene inputs. - // This means that BAR migration isn't necessary, and so we avoid - // using the Update*BufferArrayRange flavor of methods in - // HdStResourceRegistry and handle allocation/upload manually. - - if (!_inputRange || !_inputRange->IsValid()) { - // Allocate a new BAR if we haven't already. - _inputRange = _AllocateComputationDataRange( - std::move(inputs), resourceRegistry); - TF_DEBUG(HD_SHARED_EXT_COMPUTATION_DATA).Msg( - "Allocated unshared ExtComputation buffer range: %s: %p\n", - GetId().GetText(), (void *)_inputRange.get()); - - } else { - HdBufferSpecVector inputSpecs; - HdBufferSpec::GetBufferSpecs(inputs, &inputSpecs); - HdBufferSpecVector barSpecs; - _inputRange->GetBufferSpecs(&barSpecs); - - bool useExistingRange = - HdBufferSpec::IsSubset(/*subset*/inputSpecs, - /*superset*/barSpecs); - if (useExistingRange) { - resourceRegistry->AddSources( - _inputRange, std::move(inputs)); - - TF_DEBUG(HD_SHARED_EXT_COMPUTATION_DATA).Msg( - "Reused unshared ExtComputation buffer range: " - "%s: %p\n", - GetId().GetText(), (void *)_inputRange.get()); - - } else { - _inputRange = _AllocateComputationDataRange( - std::move(inputs), resourceRegistry); - TF_DEBUG(HD_SHARED_EXT_COMPUTATION_DATA).Msg( - "Couldn't reuse existing unshared range. Allocated a " - "new one.%s: %p\n", - GetId().GetText(), (void *)_inputRange.get()); - } - } + else + { + // We're not sharing. + + // We don't yet have the ability to track dirtiness per scene input. + // Each time DirtySceneInput is set, we pull and upload _all_ the + // scene inputs. + // This means that BAR migration isn't necessary, and so we avoid + // using the Update*BufferArrayRange flavor of methods in + // HdStResourceRegistry and handle allocation/upload manually. + + if (!_inputRange || !_inputRange->IsValid()) + { + // Allocate a new BAR if we haven't already. + _inputRange = _AllocateComputationDataRange( + std::move(inputs), resourceRegistry); + TF_DEBUG(HD_SHARED_EXT_COMPUTATION_DATA).Msg("Allocated unshared ExtComputation buffer range: %s: %p\n", GetId().GetText(), (void *)_inputRange.get()); + } + else + { + HdBufferSpecVector inputSpecs; + HdBufferSpec::GetBufferSpecs(inputs, &inputSpecs); + HdBufferSpecVector barSpecs; + _inputRange->GetBufferSpecs(&barSpecs); + + bool useExistingRange = + HdBufferSpec::IsSubset(/*subset*/ inputSpecs, + /*superset*/ barSpecs); + if (useExistingRange) + { + resourceRegistry->AddSources( + _inputRange, std::move(inputs)); + + TF_DEBUG(HD_SHARED_EXT_COMPUTATION_DATA).Msg("Reused unshared ExtComputation buffer range: " + "%s: %p\n", + GetId().GetText(), (void *)_inputRange.get()); } - - if (prevRange && (prevRange != _inputRange)) { - // Make sure that we also release any stale input range data - HdStMarkGarbageCollectionNeeded(renderParam); + else + { + _inputRange = _AllocateComputationDataRange( + std::move(inputs), resourceRegistry); + TF_DEBUG(HD_SHARED_EXT_COMPUTATION_DATA).Msg("Couldn't reuse existing unshared range. Allocated a " + "new one.%s: %p\n", + GetId().GetText(), (void *)_inputRange.get()); } + } } - *dirtyBits &= ~DirtySceneInput; + if (prevRange && (prevRange != _inputRange)) + { + // Make sure that we also release any stale input range data + HdStMarkGarbageCollectionNeeded(renderParam); + } + } + + *dirtyBits &= ~DirtySceneInput; } -void -HdStExtComputation::Finalize(HdRenderParam *renderParam) +void HdStExtComputation::Finalize(HdRenderParam *renderParam) { - // Release input range data. - HdStMarkGarbageCollectionNeeded(renderParam); + // Release input range data. + HdStMarkGarbageCollectionNeeded(renderParam); } - PXR_NAMESPACE_CLOSE_SCOPE - diff --git a/Sources/OpenUSD/imaging/hdSt/glslProgram.cpp b/Sources/OpenUSD/imaging/hdSt/glslProgram.cpp index 4eda9bf323..647fede1e4 100644 --- a/Sources/OpenUSD/imaging/hdSt/glslProgram.cpp +++ b/Sources/OpenUSD/imaging/hdSt/glslProgram.cpp @@ -29,7 +29,7 @@ #include "pxr/imaging/hdSt/package.h" #include "pxr/imaging/hdSt/glslProgram.h" #include "pxr/imaging/hdSt/resourceRegistry.h" -#include "pxr/base/arch/hash.h" +#include "Arch/hash.h" #include "pxr/base/tf/diagnostic.h" #include @@ -40,46 +40,51 @@ PXR_NAMESPACE_OPEN_SCOPE - // Get the line number from the compilation error message, and return a boolean // indicating success/failure of parsing. // Note: This has been tested only on nVidia. static bool _ParseLineNumberOfError(std::string const &error, unsigned int *lineNum) { - if (!lineNum) { - return false; - } - // sample error on nVidia: - // 0(279) : error C1031: swizzle mask element not present in operand "xyz" - // 279 is the line number here. - std::string::size_type start = error.find('('); - std::string::size_type end = error.find(')'); - if (start != std::string::npos && end != std::string::npos) { - std::string lineNumStr = error.substr(start+1, end-1); - unsigned long num = strtoul(lineNumStr.c_str(), nullptr, 10); - *lineNum = (unsigned int) num; - if (num == ULONG_MAX || num == 0) { - // Out of range, or no valid conversion could be performed. - return false; - } - return true; - } else { - // Error message isn't formatted as expected. - return false; + if (!lineNum) + { + return false; + } + // sample error on nVidia: + // 0(279) : error C1031: swizzle mask element not present in operand "xyz" + // 279 is the line number here. + std::string::size_type start = error.find('('); + std::string::size_type end = error.find(')'); + if (start != std::string::npos && end != std::string::npos) + { + std::string lineNumStr = error.substr(start + 1, end - 1); + unsigned long num = strtoul(lineNumStr.c_str(), nullptr, 10); + *lineNum = (unsigned int)num; + if (num == ULONG_MAX || num == 0) + { + // Out of range, or no valid conversion could be performed. + return false; } + return true; + } + else + { + // Error message isn't formatted as expected. + return false; + } } // Return the substring for the inclusive range given the start and end indices. static std::string -_GetSubstring(std::string const& str, +_GetSubstring(std::string const &str, std::string::size_type startPos, std::string::size_type endPos) { - if (endPos == std::string::npos) { - return str.substr(startPos, endPos); - } - return str.substr(startPos, endPos - startPos + 1); + if (endPos == std::string::npos) + { + return str.substr(startPos, endPos); + } + return str.substr(startPos, endPos - startPos + 1); } // It's helpful to have a few more lines around the erroring line when logging @@ -90,95 +95,107 @@ _GetCompileErrorCodeContext(std::string const &shader, unsigned int lineNum, unsigned int contextSize) { - unsigned int numLinesToSkip = - std::max(0, lineNum - contextSize - 1); - std::string::size_type i = 0; - for (unsigned int line = 0; line < numLinesToSkip && i != std::string::npos; - line++) { - i = shader.find('\n', i+1); // find the next occurrance - } - - if (i == std::string::npos) return std::string(); - - // Copy context before the error line. - std::string::size_type start = i; - for (unsigned int line = 0; line < contextSize && i != std::string::npos; - line++) { - i = shader.find('\n', i+1); - } - - std::string context = _GetSubstring(shader, start, i); - - // Copy error line with annotation. - start = i+1; - i = shader.find('\n', start); - context += _GetSubstring(shader, start, i-1) + " <<< ERROR!\n"; - - // Copy context after error line. - start = i+1; - for (unsigned int line = 0; line < contextSize && i != std::string::npos; - line++) { - i = shader.find('\n', i+1); - } - context += _GetSubstring(shader, start, i); - - return context; + unsigned int numLinesToSkip = + std::max(0, lineNum - contextSize - 1); + std::string::size_type i = 0; + for (unsigned int line = 0; line < numLinesToSkip && i != std::string::npos; + line++) + { + i = shader.find('\n', i + 1); // find the next occurrance + } + + if (i == std::string::npos) + return std::string(); + + // Copy context before the error line. + std::string::size_type start = i; + for (unsigned int line = 0; line < contextSize && i != std::string::npos; + line++) + { + i = shader.find('\n', i + 1); + } + + std::string context = _GetSubstring(shader, start, i); + + // Copy error line with annotation. + start = i + 1; + i = shader.find('\n', start); + context += _GetSubstring(shader, start, i - 1) + " <<< ERROR!\n"; + + // Copy context after error line. + start = i + 1; + for (unsigned int line = 0; line < contextSize && i != std::string::npos; + line++) + { + i = shader.find('\n', i + 1); + } + context += _GetSubstring(shader, start, i); + + return context; } -static const char* +static const char * _GetShaderType(HgiShaderStage stage) { - switch(stage) { - case HgiShaderStageCompute: - return "COMPUTE_SHADER"; - case HgiShaderStageVertex: - return "VERTEX_SHADER"; - case HgiShaderStageFragment: - return "FRAGMENT_SHADER"; - case HgiShaderStageGeometry: - return "GEOMETRY_SHADER"; - case HgiShaderStageTessellationControl: - return "TESS_CONTROL_SHADER"; - case HgiShaderStageTessellationEval: - return "TESS_EVALUATION_SHADER"; - case HgiShaderStagePostTessellationControl: - return "POST_TESS_CONTROL_SHADER"; - case HgiShaderStagePostTessellationVertex: - return "POST_TESS_VERTEX_SHADER"; - default: - return nullptr; - } + switch (stage) + { + case HgiShaderStageCompute: + return "COMPUTE_SHADER"; + case HgiShaderStageVertex: + return "VERTEX_SHADER"; + case HgiShaderStageFragment: + return "FRAGMENT_SHADER"; + case HgiShaderStageGeometry: + return "GEOMETRY_SHADER"; + case HgiShaderStageTessellationControl: + return "TESS_CONTROL_SHADER"; + case HgiShaderStageTessellationEval: + return "TESS_EVALUATION_SHADER"; + case HgiShaderStagePostTessellationControl: + return "POST_TESS_CONTROL_SHADER"; + case HgiShaderStagePostTessellationVertex: + return "POST_TESS_VERTEX_SHADER"; + default: + return nullptr; + } } static void _DumpShaderSource(const char *shaderType, std::string const &shaderSource) { - std::cout << "--------- " << shaderType << " ----------\n" - << shaderSource - << "---------------------------\n" - << std::flush; + std::cout << "--------- " << shaderType << " ----------\n" + << shaderSource + << "---------------------------\n" + << std::flush; } static void _DumpShaderSource(HgiShaderFunctionDesc const &desc) { - const char *shaderType = _GetShaderType(desc.shaderStage); - - std::cout << "--------- " << shaderType << " ----------\n"; - - if (desc.shaderCodeDeclarations) { - std::cout << desc.shaderCodeDeclarations; - } else { - std::cout << "(shaderCodeDeclarations empty)\n"; - } - - if (TF_VERIFY(desc.shaderCode)) { - std::cout << desc.shaderCode; - } else { - std::cout << "(shaderCode empty)\n"; - } - - std::cout << "---------------------------\n" << std::flush; + const char *shaderType = _GetShaderType(desc.shaderStage); + + std::cout << "--------- " << shaderType << " ----------\n"; + + if (desc.shaderCodeDeclarations) + { + std::cout << desc.shaderCodeDeclarations; + } + else + { + std::cout << "(shaderCodeDeclarations empty)\n"; + } + + if (TF_VERIFY(desc.shaderCode)) + { + std::cout << desc.shaderCode; + } + else + { + std::cout << "(shaderCode empty)\n"; + } + + std::cout << "---------------------------\n" + << std::flush; } static bool @@ -188,297 +205,319 @@ _ValidateCompilation( std::string const &shaderSource, size_t debugID) { - std::string fname; - if (TfDebug::IsEnabled(HDST_DUMP_SHADER_SOURCEFILE) || - ( TfDebug::IsEnabled(HDST_DUMP_FAILING_SHADER_SOURCEFILE) && - !shaderFn->IsValid())) { - std::stringstream fnameStream; - static size_t debugShaderID = 0; - fnameStream << "program" << debugID << "_shader" << debugShaderID++ + std::string fname; + if (TfDebug::IsEnabled(HDST_DUMP_SHADER_SOURCEFILE) || + (TfDebug::IsEnabled(HDST_DUMP_FAILING_SHADER_SOURCEFILE) && + !shaderFn->IsValid())) + { + std::stringstream fnameStream; + static size_t debugShaderID = 0; + fnameStream << "program" << debugID << "_shader" << debugShaderID++ << "_" << shaderType << ".glsl"; - fname = fnameStream.str(); - std::fstream output(fname.c_str(), std::ios::out); - output << shaderSource; - output.close(); - - std::cout << "Write " << fname - << " (size=" << shaderSource.size() << ")\n"; - } - - if (!shaderFn->IsValid()) { - std::string logString = shaderFn->GetCompileErrors(); - unsigned int lineNum = 0; - if (_ParseLineNumberOfError(logString, &lineNum)) { - // Get lines surrounding the erroring line for context. - std::string errorContext = - _GetCompileErrorCodeContext(shaderSource, lineNum, 3); - if (!errorContext.empty()) { - // erase the \0 if present. - if (logString.back() == '\0') { - logString.erase(logString.end() - 1, logString.end()); - } - logString.append("\nError Context:\n"); - logString.append(errorContext); - } + fname = fnameStream.str(); + std::fstream output(fname.c_str(), std::ios::out); + output << shaderSource; + output.close(); + + std::cout << "Write " << fname + << " (size=" << shaderSource.size() << ")\n"; + } + + if (!shaderFn->IsValid()) + { + std::string logString = shaderFn->GetCompileErrors(); + unsigned int lineNum = 0; + if (_ParseLineNumberOfError(logString, &lineNum)) + { + // Get lines surrounding the erroring line for context. + std::string errorContext = + _GetCompileErrorCodeContext(shaderSource, lineNum, 3); + if (!errorContext.empty()) + { + // erase the \0 if present. + if (logString.back() == '\0') + { + logString.erase(logString.end() - 1, logString.end()); } + logString.append("\nError Context:\n"); + logString.append(errorContext); + } + } - const char * const programName = - fname.empty() ? shaderType : fname.c_str(); - TF_WARN("Failed to compile shader (%s): %s", - programName, logString.c_str()); - - if (TfDebug::IsEnabled(HDST_DUMP_FAILING_SHADER_SOURCE)) { - _DumpShaderSource(shaderType, shaderSource); - } + const char *const programName = + fname.empty() ? shaderType : fname.c_str(); + TF_WARN("Failed to compile shader (%s): %s", + programName, logString.c_str()); - return false; + if (TfDebug::IsEnabled(HDST_DUMP_FAILING_SHADER_SOURCE)) + { + _DumpShaderSource(shaderType, shaderSource); } - return true; + + return false; + } + return true; } HdStGLSLProgram::HdStGLSLProgram( TfToken const &role, HdStResourceRegistry *const registry) - :_registry(registry) - , _role(role) + : _registry(registry), _role(role) { - static size_t globalDebugID = 0; - _debugID = globalDebugID++; + static size_t globalDebugID = 0; + _debugID = globalDebugID++; } HdStGLSLProgram::~HdStGLSLProgram() { - Hgi *const hgi = _registry->GetHgi(); + Hgi *const hgi = _registry->GetHgi(); - if (_program) { - for (HgiShaderFunctionHandle fn : _program->GetShaderFunctions()) { - hgi->DestroyShaderFunction(&fn); - } - hgi->DestroyShaderProgram(&_program); + if (_program) + { + for (HgiShaderFunctionHandle fn : _program->GetShaderFunctions()) + { + hgi->DestroyShaderFunction(&fn); } + hgi->DestroyShaderProgram(&_program); + } } /* static */ -static -HdStGLSLProgram::ID +static HdStGLSLProgram::ID _ComputeHash(TfToken const &sourceFile, std::string const &defines = std::string()) { - HD_TRACE_FUNCTION(); + HD_TRACE_FUNCTION(); - uint32_t hash = 0; - std::string const &filename = sourceFile.GetString(); - hash = ArchHash(filename.c_str(), filename.size(), hash); - hash = ArchHash(defines.c_str(), defines.size(), hash); + uint32_t hash = 0; + std::string const &filename = sourceFile.GetString(); + hash = ArchHash(filename.c_str(), filename.size(), hash); + hash = ArchHash(defines.c_str(), defines.size(), hash); - return hash; + return hash; } -bool -HdStGLSLProgram::CompileShader( +bool HdStGLSLProgram::CompileShader( HgiShaderStage stage, std::string const &shaderSource) { - HD_TRACE_FUNCTION(); - HF_MALLOC_TAG_FUNCTION(); - - // early out for empty source. - // this may not be an error, since glslfx gives empty string - // for undefined shader stages (i.e. null geometry shader) - if (shaderSource.empty()) { - return false; - } - - const char *shaderType = _GetShaderType(stage); - if (!shaderType) { - TF_CODING_ERROR("Invalid shader type %d\n", stage); - return false; - } - - if (TfDebug::IsEnabled(HDST_DUMP_SHADER_SOURCE)) { - _DumpShaderSource(shaderType, shaderSource); - } - - Hgi *const hgi = _registry->GetHgi(); - - // Create a shader, compile it - HgiShaderFunctionDesc shaderFnDesc; - shaderFnDesc.shaderCode = shaderSource.c_str(); - shaderFnDesc.shaderStage = stage; - - std::string generatedCode; - shaderFnDesc.generatedShaderCodeOut = &generatedCode; - - HgiShaderFunctionHandle shaderFn = hgi->CreateShaderFunction(shaderFnDesc); - - if (!_ValidateCompilation(shaderFn, shaderType, generatedCode, _debugID)) { - // shader is no longer needed. - hgi->DestroyShaderFunction(&shaderFn); - - return false; - } - - // Store the shader function in the program descriptor so it can be used - // during Link time. - _programDesc.shaderFunctions.push_back(shaderFn); - - return true; + HD_TRACE_FUNCTION(); + HF_MALLOC_TAG_FUNCTION(); + + // early out for empty source. + // this may not be an error, since glslfx gives empty string + // for undefined shader stages (i.e. null geometry shader) + if (shaderSource.empty()) + { + return false; + } + + const char *shaderType = _GetShaderType(stage); + if (!shaderType) + { + TF_CODING_ERROR("Invalid shader type %d\n", stage); + return false; + } + + if (TfDebug::IsEnabled(HDST_DUMP_SHADER_SOURCE)) + { + _DumpShaderSource(shaderType, shaderSource); + } + + Hgi *const hgi = _registry->GetHgi(); + + // Create a shader, compile it + HgiShaderFunctionDesc shaderFnDesc; + shaderFnDesc.shaderCode = shaderSource.c_str(); + shaderFnDesc.shaderStage = stage; + + std::string generatedCode; + shaderFnDesc.generatedShaderCodeOut = &generatedCode; + + HgiShaderFunctionHandle shaderFn = hgi->CreateShaderFunction(shaderFnDesc); + + if (!_ValidateCompilation(shaderFn, shaderType, generatedCode, _debugID)) + { + // shader is no longer needed. + hgi->DestroyShaderFunction(&shaderFn); + + return false; + } + + // Store the shader function in the program descriptor so it can be used + // during Link time. + _programDesc.shaderFunctions.push_back(shaderFn); + + return true; } -bool -HdStGLSLProgram::CompileShader(HgiShaderFunctionDesc const &desc) +bool HdStGLSLProgram::CompileShader(HgiShaderFunctionDesc const &desc) { - HD_TRACE_FUNCTION(); - HF_MALLOC_TAG_FUNCTION(); - - // early out for empty source. - // this may not be an error, since glslfx gives empty string - // for undefined shader stages (i.e. null geometry shader) - if (!desc.shaderCode) return false; - - const char *shaderType = _GetShaderType(desc.shaderStage); - if (!shaderType) { - TF_CODING_ERROR("Invalid shader type %d\n", desc.shaderStage); - return false; - } + HD_TRACE_FUNCTION(); + HF_MALLOC_TAG_FUNCTION(); - if (TfDebug::IsEnabled(HDST_DUMP_SHADER_SOURCE)) { - _DumpShaderSource(desc); - } + // early out for empty source. + // this may not be an error, since glslfx gives empty string + // for undefined shader stages (i.e. null geometry shader) + if (!desc.shaderCode) + return false; - // Create a shader, compile it - Hgi *const hgi = _registry->GetHgi(); + const char *shaderType = _GetShaderType(desc.shaderStage); + if (!shaderType) + { + TF_CODING_ERROR("Invalid shader type %d\n", desc.shaderStage); + return false; + } - // Optionally, capture generated shader code for diagnostic output. - std::string *generatedCode = desc.generatedShaderCodeOut; + if (TfDebug::IsEnabled(HDST_DUMP_SHADER_SOURCE)) + { + _DumpShaderSource(desc); + } - HgiShaderFunctionHandle shaderFn = hgi->CreateShaderFunction(desc); + // Create a shader, compile it + Hgi *const hgi = _registry->GetHgi(); - if (!_ValidateCompilation(shaderFn, shaderType, *generatedCode, _debugID)) { - // shader is no longer needed. - hgi->DestroyShaderFunction(&shaderFn); + // Optionally, capture generated shader code for diagnostic output. + std::string *generatedCode = desc.generatedShaderCodeOut; - return false; - } + HgiShaderFunctionHandle shaderFn = hgi->CreateShaderFunction(desc); - // Store the shader function in the program descriptor so it can be used - // during Link time. - _programDesc.shaderFunctions.push_back(shaderFn); + if (!_ValidateCompilation(shaderFn, shaderType, *generatedCode, _debugID)) + { + // shader is no longer needed. + hgi->DestroyShaderFunction(&shaderFn); - return true; + return false; + } + + // Store the shader function in the program descriptor so it can be used + // during Link time. + _programDesc.shaderFunctions.push_back(shaderFn); + + return true; } static std::string -_DebugLinkSource(HgiShaderProgramHandle const& program) +_DebugLinkSource(HgiShaderProgramHandle const &program) { - std::string result; - result = TfStringPrintf("==== Source Program ID=%p\nBEGIN_DUMP\n", - program.Get()); - - for (HgiShaderFunctionHandle fn : program->GetShaderFunctions()) { - HgiShaderFunctionDesc const& desc = fn->GetDescriptor(); - result.append("--------"); - result.append(_GetShaderType(desc.shaderStage)); - result.append("--------\n"); - if (TF_VERIFY(desc.shaderCode)) { - result.append(desc.shaderCode); - } else { - result.append("(shaderCode empty)\n"); - } + std::string result; + result = TfStringPrintf("==== Source Program ID=%p\nBEGIN_DUMP\n", + program.Get()); + + for (HgiShaderFunctionHandle fn : program->GetShaderFunctions()) + { + HgiShaderFunctionDesc const &desc = fn->GetDescriptor(); + result.append("--------"); + result.append(_GetShaderType(desc.shaderStage)); + result.append("--------\n"); + if (TF_VERIFY(desc.shaderCode)) + { + result.append(desc.shaderCode); } + else + { + result.append("(shaderCode empty)\n"); + } + } - result += "END DUMP\n"; + result += "END DUMP\n"; - return result; + return result; } -bool -HdStGLSLProgram::Link() +bool HdStGLSLProgram::Link() { - HD_TRACE_FUNCTION(); - HF_MALLOC_TAG_FUNCTION(); - - if (_programDesc.shaderFunctions.empty()) { - TF_CODING_ERROR("At least one shader has to be compiled before linking."); - return false; - } - - Hgi *const hgi = _registry->GetHgi(); - - // Create the shader program. - if (_program) { - hgi->DestroyShaderProgram(&_program); - } - _program = hgi->CreateShaderProgram(_programDesc); - - bool success = _program->IsValid(); - if (!success) { - std::string const& logString = _program->GetCompileErrors(); - TF_WARN("Failed to link shader: %s", logString.c_str()); - - if (TfDebug::IsEnabled(HDST_DUMP_FAILING_SHADER_SOURCE)) { - std::cout << _DebugLinkSource(_program) << std::flush; - } + HD_TRACE_FUNCTION(); + HF_MALLOC_TAG_FUNCTION(); + + if (_programDesc.shaderFunctions.empty()) + { + TF_CODING_ERROR("At least one shader has to be compiled before linking."); + return false; + } + + Hgi *const hgi = _registry->GetHgi(); + + // Create the shader program. + if (_program) + { + hgi->DestroyShaderProgram(&_program); + } + _program = hgi->CreateShaderProgram(_programDesc); + + bool success = _program->IsValid(); + if (!success) + { + std::string const &logString = _program->GetCompileErrors(); + TF_WARN("Failed to link shader: %s", logString.c_str()); + + if (TfDebug::IsEnabled(HDST_DUMP_FAILING_SHADER_SOURCE)) + { + std::cout << _DebugLinkSource(_program) << std::flush; } + } - return success; + return success; } -bool -HdStGLSLProgram::Validate() const +bool HdStGLSLProgram::Validate() const { - if (!_program || !_program->IsValid()) { - return false; - } + if (!_program || !_program->IsValid()) + { + return false; + } - return true; + return true; } HdStGLSLProgramSharedPtr HdStGLSLProgram::GetComputeProgram( - TfToken const &shaderToken, - HdStResourceRegistry *resourceRegistry) + TfToken const &shaderToken, + HdStResourceRegistry *resourceRegistry) { - return GetComputeProgram(HdStPackageComputeShader(), shaderToken, - resourceRegistry); + return GetComputeProgram(HdStPackageComputeShader(), shaderToken, + resourceRegistry); } HdStGLSLProgramSharedPtr HdStGLSLProgram::GetComputeProgram( - TfToken const &shaderFileName, - TfToken const &shaderToken, - HdStResourceRegistry *resourceRegistry) + TfToken const &shaderFileName, + TfToken const &shaderToken, + HdStResourceRegistry *resourceRegistry) { - // Find the program from registry - HdInstance programInstance = - resourceRegistry->RegisterGLSLProgram( - _ComputeHash(shaderToken)); - - if (programInstance.IsFirstInstance()) { - // if not exists, create new one - HdStGLSLProgramSharedPtr newProgram = - std::make_shared( - HdTokens->computeShader, resourceRegistry); - - HioGlslfx glslfx(shaderFileName); - std::string errorString; - if (!glslfx.IsValid(&errorString)){ - TF_CODING_ERROR("Failed to parse " + shaderFileName.GetString() - + ": " + errorString); - return nullptr; - } - if (!newProgram->CompileShader( - HgiShaderStageCompute, glslfx.GetSource(shaderToken))) { - TF_CODING_ERROR("Fail to compile " + shaderToken.GetString()); - return nullptr; - } - if (!newProgram->Link()) { - TF_CODING_ERROR("Fail to link " + shaderToken.GetString()); - return nullptr; - } - programInstance.SetValue(newProgram); + // Find the program from registry + HdInstance programInstance = + resourceRegistry->RegisterGLSLProgram( + _ComputeHash(shaderToken)); + + if (programInstance.IsFirstInstance()) + { + // if not exists, create new one + HdStGLSLProgramSharedPtr newProgram = + std::make_shared( + HdTokens->computeShader, resourceRegistry); + + HioGlslfx glslfx(shaderFileName); + std::string errorString; + if (!glslfx.IsValid(&errorString)) + { + TF_CODING_ERROR("Failed to parse " + shaderFileName.GetString() + ": " + errorString); + return nullptr; } - return programInstance.GetValue(); + if (!newProgram->CompileShader( + HgiShaderStageCompute, glslfx.GetSource(shaderToken))) + { + TF_CODING_ERROR("Fail to compile " + shaderToken.GetString()); + return nullptr; + } + if (!newProgram->Link()) + { + TF_CODING_ERROR("Fail to link " + shaderToken.GetString()); + return nullptr; + } + programInstance.SetValue(newProgram); + } + return programInstance.GetValue(); } HdStGLSLProgramSharedPtr @@ -487,10 +526,10 @@ HdStGLSLProgram::GetComputeProgram( HdStResourceRegistry *resourceRegistry, PopulateDescriptorCallback populateDescriptor) { - return GetComputeProgram(shaderToken, - std::string(), - resourceRegistry, - populateDescriptor); + return GetComputeProgram(shaderToken, + std::string(), + resourceRegistry, + populateDescriptor); } HdStGLSLProgramSharedPtr @@ -500,11 +539,11 @@ HdStGLSLProgram::GetComputeProgram( HdStResourceRegistry *resourceRegistry, PopulateDescriptorCallback populateDescriptor) { - return GetComputeProgram(HdStPackageComputeShader(), - shaderToken, - defines, - resourceRegistry, - populateDescriptor); + return GetComputeProgram(HdStPackageComputeShader(), + shaderToken, + defines, + resourceRegistry, + populateDescriptor); } HdStGLSLProgramSharedPtr @@ -515,57 +554,58 @@ HdStGLSLProgram::GetComputeProgram( HdStResourceRegistry *resourceRegistry, PopulateDescriptorCallback populateDescriptor) { - // Find the program from registry - HdInstance programInstance = - resourceRegistry->RegisterGLSLProgram( - _ComputeHash(shaderToken, defines)); - - if (programInstance.IsFirstInstance()) { - // If program does not exist, create new one - const HioGlslfx glslfx(shaderFileName, HioGlslfxTokens->defVal); - std::string errorString; - if (!glslfx.IsValid(&errorString)){ - TF_CODING_ERROR("Failed to parse " + shaderFileName.GetString() - + ": " + errorString); - return nullptr; - } + // Find the program from registry + HdInstance programInstance = + resourceRegistry->RegisterGLSLProgram( + _ComputeHash(shaderToken, defines)); + + if (programInstance.IsFirstInstance()) + { + // If program does not exist, create new one + const HioGlslfx glslfx(shaderFileName, HioGlslfxTokens->defVal); + std::string errorString; + if (!glslfx.IsValid(&errorString)) + { + TF_CODING_ERROR("Failed to parse " + shaderFileName.GetString() + ": " + errorString); + return nullptr; + } - Hgi *hgi = resourceRegistry->GetHgi(); + Hgi *hgi = resourceRegistry->GetHgi(); - HgiShaderFunctionDesc computeDesc; - populateDescriptor(computeDesc); + HgiShaderFunctionDesc computeDesc; + populateDescriptor(computeDesc); - const std::string sourceCode = defines + glslfx.GetSource(shaderToken); - computeDesc.shaderCode = sourceCode.c_str(); + const std::string sourceCode = defines + glslfx.GetSource(shaderToken); + computeDesc.shaderCode = sourceCode.c_str(); - std::string generatedCode; - computeDesc.generatedShaderCodeOut = &generatedCode; + std::string generatedCode; + computeDesc.generatedShaderCodeOut = &generatedCode; - HgiShaderFunctionHandle computeFn = - hgi->CreateShaderFunction(computeDesc); + HgiShaderFunctionHandle computeFn = + hgi->CreateShaderFunction(computeDesc); - static const char *shaderType = "GL_COMPUTE_SHADER"; + static const char *shaderType = "GL_COMPUTE_SHADER"; - if (!_ValidateCompilation(computeFn, shaderType, generatedCode, 0)) { - // shader is no longer needed. - hgi->DestroyShaderFunction(&computeFn); - return nullptr; - } + if (!_ValidateCompilation(computeFn, shaderType, generatedCode, 0)) + { + // shader is no longer needed. + hgi->DestroyShaderFunction(&computeFn); + return nullptr; + } - HdStGLSLProgramSharedPtr newProgram = - std::make_shared( - HdTokens->computeShader, resourceRegistry); + HdStGLSLProgramSharedPtr newProgram = + std::make_shared( + HdTokens->computeShader, resourceRegistry); - newProgram->_programDesc.shaderFunctions.push_back(computeFn); - if (!newProgram->Link()) { - TF_CODING_ERROR("Fail to link " + shaderToken.GetString()); - return nullptr; - } - programInstance.SetValue(newProgram); + newProgram->_programDesc.shaderFunctions.push_back(computeFn); + if (!newProgram->Link()) + { + TF_CODING_ERROR("Fail to link " + shaderToken.GetString()); + return nullptr; } - return programInstance.GetValue(); + programInstance.SetValue(newProgram); + } + return programInstance.GetValue(); } - PXR_NAMESPACE_CLOSE_SCOPE - diff --git a/Sources/OpenUSD/imaging/hdSt/interleavedMemoryManager.cpp b/Sources/OpenUSD/imaging/hdSt/interleavedMemoryManager.cpp index c6bc147105..914e1282d6 100644 --- a/Sources/OpenUSD/imaging/hdSt/interleavedMemoryManager.cpp +++ b/Sources/OpenUSD/imaging/hdSt/interleavedMemoryManager.cpp @@ -34,7 +34,7 @@ #include "pxr/imaging/hgi/buffer.h" #include "pxr/imaging/hgi/capabilities.h" -#include "pxr/base/arch/hash.h" +#include "Arch/hash.h" #include "pxr/base/tf/diagnostic.h" #include "pxr/base/tf/enum.h" #include "pxr/base/tf/iterator.h" @@ -56,56 +56,61 @@ PXR_NAMESPACE_OPEN_SCOPE HdBufferArrayRangeSharedPtr HdStInterleavedMemoryManager::CreateBufferArrayRange() { - return std::make_shared<_StripedInterleavedBufferRange>(_resourceRegistry); + return std::make_shared<_StripedInterleavedBufferRange>(_resourceRegistry); } /// Returns the buffer specs from a given buffer array -HdBufferSpecVector +HdBufferSpecVector HdStInterleavedMemoryManager::GetBufferSpecs( HdBufferArraySharedPtr const &bufferArray) const { - _StripedInterleavedBufferSharedPtr bufferArray_ = - std::static_pointer_cast<_StripedInterleavedBuffer> (bufferArray); - return bufferArray_->GetBufferSpecs(); + _StripedInterleavedBufferSharedPtr bufferArray_ = + std::static_pointer_cast<_StripedInterleavedBuffer>(bufferArray); + return bufferArray_->GetBufferSpecs(); } /// Returns the size of the GPU memory used by the passed buffer array -size_t +size_t HdStInterleavedMemoryManager::GetResourceAllocation( - HdBufferArraySharedPtr const &bufferArray, - VtDictionary &result) const -{ - std::set idSet; - size_t gpuMemoryUsed = 0; + HdBufferArraySharedPtr const &bufferArray, + VtDictionary &result) const +{ + std::set idSet; + size_t gpuMemoryUsed = 0; - _StripedInterleavedBufferSharedPtr bufferArray_ = - std::static_pointer_cast<_StripedInterleavedBuffer> (bufferArray); + _StripedInterleavedBufferSharedPtr bufferArray_ = + std::static_pointer_cast<_StripedInterleavedBuffer>(bufferArray); - TF_FOR_ALL(resIt, bufferArray_->GetResources()) { - HdStBufferResourceSharedPtr const & resource = resIt->second; + TF_FOR_ALL(resIt, bufferArray_->GetResources()) + { + HdStBufferResourceSharedPtr const &resource = resIt->second; - HgiBufferHandle buffer = resource->GetHandle(); + HgiBufferHandle buffer = resource->GetHandle(); - // XXX avoid double counting of resources shared within a buffer - uint64_t id = buffer ? buffer->GetRawResource() : 0; - if (idSet.count(id) == 0) { - idSet.insert(id); + // XXX avoid double counting of resources shared within a buffer + uint64_t id = buffer ? buffer->GetRawResource() : 0; + if (idSet.count(id) == 0) + { + idSet.insert(id); - std::string const & role = resource->GetRole().GetString(); - size_t size = size_t(resource->GetSize()); + std::string const &role = resource->GetRole().GetString(); + size_t size = size_t(resource->GetSize()); - if (result.count(role)) { - size_t currentSize = result[role].Get(); - result[role] = VtValue(currentSize + size); - } else { - result[role] = VtValue(size); - } + if (result.count(role)) + { + size_t currentSize = result[role].Get(); + result[role] = VtValue(currentSize + size); + } + else + { + result[role] = VtValue(size); + } - gpuMemoryUsed += size; - } + gpuMemoryUsed += size; } + } - return gpuMemoryUsed; + return gpuMemoryUsed; } // --------------------------------------------------------------------------- @@ -117,22 +122,20 @@ HdStInterleavedUBOMemoryManager::CreateBufferArray( HdBufferSpecVector const &bufferSpecs, HdBufferArrayUsageHint usageHint) { - const int uniformBufferOffsetAlignment = _resourceRegistry->GetHgi()-> - GetCapabilities()->GetUniformBufferOffsetAlignment(); - const int maxUniformBlockSize = _resourceRegistry->GetHgi()-> - GetCapabilities()->GetMaxUniformBlockSize(); + const int uniformBufferOffsetAlignment = _resourceRegistry->GetHgi()->GetCapabilities()->GetUniformBufferOffsetAlignment(); + const int maxUniformBlockSize = _resourceRegistry->GetHgi()->GetCapabilities()->GetMaxUniformBlockSize(); - return std::make_shared< - HdStInterleavedMemoryManager::_StripedInterleavedBuffer>( - this, - _resourceRegistry, - role, - bufferSpecs, - usageHint, - uniformBufferOffsetAlignment, - /*structAlignment=*/sizeof(float)*4, - maxUniformBlockSize, - HdPerfTokens->garbageCollectedUbo); + return std::make_shared< + HdStInterleavedMemoryManager::_StripedInterleavedBuffer>( + this, + _resourceRegistry, + role, + bufferSpecs, + usageHint, + uniformBufferOffsetAlignment, + /*structAlignment=*/sizeof(float) * 4, + maxUniformBlockSize, + HdPerfTokens->garbageCollectedUbo); } HdStAggregationStrategy::AggregationId @@ -140,15 +143,16 @@ HdStInterleavedUBOMemoryManager::ComputeAggregationId( HdBufferSpecVector const &bufferSpecs, HdBufferArrayUsageHint usageHint) const { - static size_t salt = ArchHash(__FUNCTION__, sizeof(__FUNCTION__)); - size_t result = salt; - for (HdBufferSpec const &spec : bufferSpecs) { - boost::hash_combine(result, spec.Hash()); - } - boost::hash_combine(result, usageHint.value); + static size_t salt = ArchHash(__FUNCTION__, sizeof(__FUNCTION__)); + size_t result = salt; + for (HdBufferSpec const &spec : bufferSpecs) + { + boost::hash_combine(result, spec.Hash()); + } + boost::hash_combine(result, usageHint.value); - // promote to size_t - return (AggregationId)result; + // promote to size_t + return (AggregationId)result; } // --------------------------------------------------------------------------- @@ -160,20 +164,19 @@ HdStInterleavedSSBOMemoryManager::CreateBufferArray( HdBufferSpecVector const &bufferSpecs, HdBufferArrayUsageHint usageHint) { - const int maxShaderStorageBlockSize = _resourceRegistry->GetHgi()-> - GetCapabilities()->GetMaxShaderStorageBlockSize(); + const int maxShaderStorageBlockSize = _resourceRegistry->GetHgi()->GetCapabilities()->GetMaxShaderStorageBlockSize(); - return std::make_shared< - HdStInterleavedMemoryManager::_StripedInterleavedBuffer>( - this, - _resourceRegistry, - role, - bufferSpecs, - usageHint, - /*bufferOffsetAlignment=*/0, - /*structAlignment=*/0, - maxShaderStorageBlockSize, - HdPerfTokens->garbageCollectedSsbo); + return std::make_shared< + HdStInterleavedMemoryManager::_StripedInterleavedBuffer>( + this, + _resourceRegistry, + role, + bufferSpecs, + usageHint, + /*bufferOffsetAlignment=*/0, + /*structAlignment=*/0, + maxShaderStorageBlockSize, + HdPerfTokens->garbageCollectedSsbo); } HdStAggregationStrategy::AggregationId @@ -181,14 +184,15 @@ HdStInterleavedSSBOMemoryManager::ComputeAggregationId( HdBufferSpecVector const &bufferSpecs, HdBufferArrayUsageHint usageHint) const { - static size_t salt = ArchHash(__FUNCTION__, sizeof(__FUNCTION__)); - size_t result = salt; - for (HdBufferSpec const &spec : bufferSpecs) { - boost::hash_combine(result, spec.Hash()); - } - boost::hash_combine(result, usageHint.value); + static size_t salt = ArchHash(__FUNCTION__, sizeof(__FUNCTION__)); + size_t result = salt; + for (HdBufferSpec const &spec : bufferSpecs) + { + boost::hash_combine(result, spec.Hash()); + } + boost::hash_combine(result, usageHint.value); - return result; + return result; } // --------------------------------------------------------------------------- @@ -198,42 +202,43 @@ HdStInterleavedSSBOMemoryManager::ComputeAggregationId( static inline size_t _ComputePadding(int alignment, size_t currentOffset) { - return ((alignment - (currentOffset & (alignment - 1))) & (alignment - 1)); + return ((alignment - (currentOffset & (alignment - 1))) & (alignment - 1)); } static inline size_t _ComputeAlignment(HdTupleType tupleType) { - const HdType componentType = HdGetComponentType(tupleType.type); - const size_t numComponents = HdGetComponentCount(tupleType.type); - const size_t componentSize = HdDataSizeOfType(componentType); - - // This is simplified to treat arrays of int and floats - // as vectors. The padding rules state that if we have - // an array of 2 ints, it would get aligned to the size - // of a vec4, where as a vec2 of ints or floats is aligned - // to the size of a vec2. Since we don't know if something is - // an array or vector, we are treating them as vectors. - // - // XXX:Arrays: Now that we do know whether a value is an array - // or vector, we can update this to do the right thing. - - // Matrices are treated as an array of vec4s, so the - // max num components we are looking at is 4 - size_t alignComponents = std::min(numComponents, size_t(4)); - - // single elements and vec2's are allowed, but - // vec3's get rounded up to vec4's - if(alignComponents == 3) { - alignComponents = 4; - } + const HdType componentType = HdGetComponentType(tupleType.type); + const size_t numComponents = HdGetComponentCount(tupleType.type); + const size_t componentSize = HdDataSizeOfType(componentType); + + // This is simplified to treat arrays of int and floats + // as vectors. The padding rules state that if we have + // an array of 2 ints, it would get aligned to the size + // of a vec4, where as a vec2 of ints or floats is aligned + // to the size of a vec2. Since we don't know if something is + // an array or vector, we are treating them as vectors. + // + // XXX:Arrays: Now that we do know whether a value is an array + // or vector, we can update this to do the right thing. + + // Matrices are treated as an array of vec4s, so the + // max num components we are looking at is 4 + size_t alignComponents = std::min(numComponents, size_t(4)); - return componentSize * alignComponents; + // single elements and vec2's are allowed, but + // vec3's get rounded up to vec4's + if (alignComponents == 3) + { + alignComponents = 4; + } + + return componentSize * alignComponents; } HdStInterleavedMemoryManager::_StripedInterleavedBuffer::_StripedInterleavedBuffer( - HdStInterleavedMemoryManager* mgr, - HdStResourceRegistry* resourceRegistry, + HdStInterleavedMemoryManager *mgr, + HdStResourceRegistry *resourceRegistry, TfToken const &role, HdBufferSpecVector const &bufferSpecs, HdBufferArrayUsageHint usageHint, @@ -250,382 +255,414 @@ HdStInterleavedMemoryManager::_StripedInterleavedBuffer::_StripedInterleavedBuff _maxSize(maxSize) { - HD_TRACE_FUNCTION(); - HF_MALLOC_TAG_FUNCTION(); - - /* - interleaved uniform buffer layout (for example) - - .--range["color"].offset - v - .--------------------------------------------------. - | Xf : Color || Xf : Color || ...| - '--------------------------------------------------' - ^------- stride ------^ - ^---- one element ----^ - */ - - /* - do std140/std430 packing (GL spec section 7.6.2.2) - When using the "std430" storage layout, shader storage - blocks will be laid out in buffer storage identically to uniform and - shader storage blocks using the "std140" layout, except that the base - alignment of arrays of scalars and vectors in rule (4) and of structures - in rule (9) are not rounded up a multiple of the base alignment of a vec4. - - ***Unless we're using Metal, and then we use C++ alignment padding rules. - */ - const bool useCppShaderPadding = _resourceRegistry->GetHgi()-> - GetCapabilities()->IsSet(HgiDeviceCapabilitiesBitsCppShaderPadding); - - TF_FOR_ALL(it, bufferSpecs) { - // Figure out the alignment we need for this type of data - const size_t alignment = _ComputeAlignment(it->tupleType); - _stride += _ComputePadding(alignment, _stride); - - // We need to save the max alignment size for later because the - // stride for our struct needs to be aligned to this - structAlignment = std::max(size_t(structAlignment), alignment); - - _stride += HdDataSizeOfTupleType(it->tupleType); - - if (useCppShaderPadding) { - _stride += _ComputePadding(alignment, _stride); - } - } - - // Our struct stride needs to be aligned to the max alignment needed within - // our struct. - _stride += _ComputePadding(structAlignment, _stride); - - _elementStride = _stride; - - // and also aligned if bufferOffsetAlignment exists (for UBO binding) - if (_bufferOffsetAlignment > 0) { - _stride += _ComputePadding(_bufferOffsetAlignment, _stride); - } - - if (_stride > _maxSize) { - TF_WARN("Computed stride = %zu of interleaved buffer is larger than max" - " size %zu, cannot create buffer.", _stride, _maxSize); - _SetMaxNumRanges(0); - return; - } - if (_stride == 0) { - TF_WARN("Computed stride = %zu of interleaved buffer is 0, cannot " - " create buffer.", _stride); - _SetMaxNumRanges(0); - return; - } + HD_TRACE_FUNCTION(); + HF_MALLOC_TAG_FUNCTION(); + + /* + interleaved uniform buffer layout (for example) + + .--range["color"].offset + v + .--------------------------------------------------. + | Xf : Color || Xf : Color || ...| + '--------------------------------------------------' + ^------- stride ------^ + ^---- one element ----^ + */ + + /* + do std140/std430 packing (GL spec section 7.6.2.2) + When using the "std430" storage layout, shader storage + blocks will be laid out in buffer storage identically to uniform and + shader storage blocks using the "std140" layout, except that the base + alignment of arrays of scalars and vectors in rule (4) and of structures + in rule (9) are not rounded up a multiple of the base alignment of a vec4. + + ***Unless we're using Metal, and then we use C++ alignment padding rules. + */ + const bool useCppShaderPadding = _resourceRegistry->GetHgi()->GetCapabilities()->IsSet(HgiDeviceCapabilitiesBitsCppShaderPadding); + + TF_FOR_ALL(it, bufferSpecs) + { + // Figure out the alignment we need for this type of data + const size_t alignment = _ComputeAlignment(it->tupleType); + _stride += _ComputePadding(alignment, _stride); + + // We need to save the max alignment size for later because the + // stride for our struct needs to be aligned to this + structAlignment = std::max(size_t(structAlignment), alignment); + + _stride += HdDataSizeOfTupleType(it->tupleType); + + if (useCppShaderPadding) + { + _stride += _ComputePadding(alignment, _stride); + } + } + + // Our struct stride needs to be aligned to the max alignment needed within + // our struct. + _stride += _ComputePadding(structAlignment, _stride); + + _elementStride = _stride; + + // and also aligned if bufferOffsetAlignment exists (for UBO binding) + if (_bufferOffsetAlignment > 0) + { + _stride += _ComputePadding(_bufferOffsetAlignment, _stride); + } + + if (_stride > _maxSize) + { + TF_WARN("Computed stride = %zu of interleaved buffer is larger than max" + " size %zu, cannot create buffer.", + _stride, _maxSize); + _SetMaxNumRanges(0); + return; + } + if (_stride == 0) + { + TF_WARN("Computed stride = %zu of interleaved buffer is 0, cannot " + " create buffer.", + _stride); + _SetMaxNumRanges(0); + return; + } + + TF_DEBUG_MSG(HD_BUFFER_ARRAY_INFO, + "Create interleaved buffer array: stride = %zu\n", _stride); + + // populate BufferResources, interleaved + size_t offset = 0; + TF_FOR_ALL(it, bufferSpecs) + { + // Figure out alignment for this data member + const size_t alignment = _ComputeAlignment(it->tupleType); + // Add any needed padding to fixup alignment + offset += _ComputePadding(alignment, offset); + + _AddResource(it->name, it->tupleType, offset, _stride); TF_DEBUG_MSG(HD_BUFFER_ARRAY_INFO, - "Create interleaved buffer array: stride = %zu\n", _stride); - - // populate BufferResources, interleaved - size_t offset = 0; - TF_FOR_ALL(it, bufferSpecs) { - // Figure out alignment for this data member - const size_t alignment = _ComputeAlignment(it->tupleType); - // Add any needed padding to fixup alignment - offset += _ComputePadding(alignment, offset); - - _AddResource(it->name, it->tupleType, offset, _stride); - - TF_DEBUG_MSG(HD_BUFFER_ARRAY_INFO, - " %s : offset = %zu, alignment = %zu\n", - it->name.GetText(), offset, alignment); - - const size_t thisSize = HdDataSizeOfTupleType(it->tupleType); - offset += thisSize; - if (useCppShaderPadding) { - offset += _ComputePadding(alignment, thisSize); - } + " %s : offset = %zu, alignment = %zu\n", + it->name.GetText(), offset, alignment); + + const size_t thisSize = HdDataSizeOfTupleType(it->tupleType); + offset += thisSize; + if (useCppShaderPadding) + { + offset += _ComputePadding(alignment, thisSize); } + } - _SetMaxNumRanges(_maxSize / _stride); + _SetMaxNumRanges(_maxSize / _stride); - TF_VERIFY(_stride + offset); + TF_VERIFY(_stride + offset); } HdStBufferResourceSharedPtr HdStInterleavedMemoryManager::_StripedInterleavedBuffer::_AddResource( - TfToken const& name, + TfToken const &name, HdTupleType tupleType, int offset, int stride) { - HD_TRACE_FUNCTION(); + HD_TRACE_FUNCTION(); - if (TfDebug::IsEnabled(HD_SAFE_MODE)) { - // duplication check - HdStBufferResourceSharedPtr bufferRes = GetResource(name); - if (!TF_VERIFY(!bufferRes)) { - return bufferRes; - } + if (TfDebug::IsEnabled(HD_SAFE_MODE)) + { + // duplication check + HdStBufferResourceSharedPtr bufferRes = GetResource(name); + if (!TF_VERIFY(!bufferRes)) + { + return bufferRes; } + } - HdStBufferResourceSharedPtr bufferRes = std::make_shared - (GetRole(), tupleType, offset, stride); + HdStBufferResourceSharedPtr bufferRes = std::make_shared(GetRole(), tupleType, offset, stride); - _resourceList.emplace_back(name, bufferRes); - return bufferRes; + _resourceList.emplace_back(name, bufferRes); + return bufferRes; } - HdStInterleavedMemoryManager::_StripedInterleavedBuffer::~_StripedInterleavedBuffer() { - HD_TRACE_FUNCTION(); - HF_MALLOC_TAG_FUNCTION(); + HD_TRACE_FUNCTION(); + HF_MALLOC_TAG_FUNCTION(); - // invalidate buffer array ranges in range list - // (these ranges may still be held by drawItems) - size_t rangeCount = GetRangeCount(); - for (size_t rangeIdx = 0; rangeIdx < rangeCount; ++rangeIdx) { - _StripedInterleavedBufferRangeSharedPtr range = _GetRangeSharedPtr(rangeIdx); + // invalidate buffer array ranges in range list + // (these ranges may still be held by drawItems) + size_t rangeCount = GetRangeCount(); + for (size_t rangeIdx = 0; rangeIdx < rangeCount; ++rangeIdx) + { + _StripedInterleavedBufferRangeSharedPtr range = _GetRangeSharedPtr(rangeIdx); - if (range) - { - range->Invalidate(); - } + if (range) + { + range->Invalidate(); } + } } -bool -HdStInterleavedMemoryManager::_StripedInterleavedBuffer::GarbageCollect() +bool HdStInterleavedMemoryManager::_StripedInterleavedBuffer::GarbageCollect() { - HD_TRACE_FUNCTION(); - HF_MALLOC_TAG_FUNCTION(); + HD_TRACE_FUNCTION(); + HF_MALLOC_TAG_FUNCTION(); - if (_needsCompaction) { - RemoveUnusedRanges(); + if (_needsCompaction) + { + RemoveUnusedRanges(); - std::vector ranges; - size_t rangeCount = GetRangeCount(); - ranges.reserve(rangeCount); - for (size_t i = 0; i < rangeCount; ++i) { - HdBufferArrayRangeSharedPtr range = GetRange(i).lock(); - if (range) - ranges.push_back(range); - } - Reallocate(ranges, shared_from_this()); - } - - if (GetRangeCount() == 0) { - _DeallocateResources(); - return true; - } + std::vector ranges; + size_t rangeCount = GetRangeCount(); + ranges.reserve(rangeCount); + for (size_t i = 0; i < rangeCount; ++i) + { + HdBufferArrayRangeSharedPtr range = GetRange(i).lock(); + if (range) + ranges.push_back(range); + } + Reallocate(ranges, shared_from_this()); + } + + if (GetRangeCount() == 0) + { + _DeallocateResources(); + return true; + } - return false; + return false; } -void -HdStInterleavedMemoryManager::_StripedInterleavedBuffer::Reallocate( +void HdStInterleavedMemoryManager::_StripedInterleavedBuffer::Reallocate( std::vector const &ranges, HdBufferArraySharedPtr const &curRangeOwner) { - HD_TRACE_FUNCTION(); - HF_MALLOC_TAG_FUNCTION(); + HD_TRACE_FUNCTION(); + HF_MALLOC_TAG_FUNCTION(); - HgiBlitCmds* blitCmds = _resourceRegistry->GetGlobalBlitCmds(); - blitCmds->PushDebugGroup(__ARCH_PRETTY_FUNCTION__); + HgiBlitCmds *blitCmds = _resourceRegistry->GetGlobalBlitCmds(); + blitCmds->PushDebugGroup(__ARCH_PRETTY_FUNCTION__); - HD_PERF_COUNTER_INCR(HdPerfTokens->vboRelocated); + HD_PERF_COUNTER_INCR(HdPerfTokens->vboRelocated); - // Calculate element count - size_t elementCount = 0; - TF_FOR_ALL (it, ranges) { - HdBufferArrayRangeSharedPtr const &range = *it; - if (!range) { - TF_CODING_ERROR("Expired range found in the reallocation list"); - } - elementCount += (*it)->GetNumElements(); + // Calculate element count + size_t elementCount = 0; + TF_FOR_ALL(it, ranges) + { + HdBufferArrayRangeSharedPtr const &range = *it; + if (!range) + { + TF_CODING_ERROR("Expired range found in the reallocation list"); } - size_t totalSize = elementCount * _stride; + elementCount += (*it)->GetNumElements(); + } + size_t totalSize = elementCount * _stride; - // update range list (should be done before early exit) - _SetRangeList(ranges); + // update range list (should be done before early exit) + _SetRangeList(ranges); - // resize each BufferResource - // all HdBufferSources are sharing same VBO + // resize each BufferResource + // all HdBufferSources are sharing same VBO - // allocate new one - // curBuf and oldBuf will be different when we are adopting ranges - // from another buffer array. - HgiBufferHandle& oldBuf = GetResources().begin()->second->GetHandle(); + // allocate new one + // curBuf and oldBuf will be different when we are adopting ranges + // from another buffer array. + HgiBufferHandle &oldBuf = GetResources().begin()->second->GetHandle(); - _StripedInterleavedBufferSharedPtr curRangeOwner_ = - std::static_pointer_cast<_StripedInterleavedBuffer> (curRangeOwner); + _StripedInterleavedBufferSharedPtr curRangeOwner_ = + std::static_pointer_cast<_StripedInterleavedBuffer>(curRangeOwner); - HgiBufferHandle const& curBuf = - curRangeOwner_->GetResources().begin()->second->GetHandle(); - HgiBufferHandle newBuf; + HgiBufferHandle const &curBuf = + curRangeOwner_->GetResources().begin()->second->GetHandle(); + HgiBufferHandle newBuf; - Hgi* hgi = _resourceRegistry->GetHgi(); + Hgi *hgi = _resourceRegistry->GetHgi(); - // Skip buffers of zero size. - if (totalSize > 0) { - HgiBufferDesc bufDesc; - bufDesc.byteSize = totalSize; - bufDesc.usage = HgiBufferUsageUniform; - newBuf = hgi->CreateBuffer(bufDesc); - } + // Skip buffers of zero size. + if (totalSize > 0) + { + HgiBufferDesc bufDesc; + bufDesc.byteSize = totalSize; + bufDesc.usage = HgiBufferUsageUniform; + newBuf = hgi->CreateBuffer(bufDesc); + } - // if old and new buffer exist, copy unchanged data - if (curBuf && newBuf) { - int index = 0; - - size_t rangeCount = GetRangeCount(); - - // pre-pass to combine consecutive buffer range relocation - HdStBufferRelocator relocator(curBuf, newBuf); - for (size_t rangeIdx = 0; rangeIdx < rangeCount; ++rangeIdx) { - _StripedInterleavedBufferRangeSharedPtr range = _GetRangeSharedPtr(rangeIdx); - - if (!range) { - TF_CODING_ERROR("_StripedInterleavedBufferRange expired " - "unexpectedly."); - continue; - } - int oldIndex = range->GetElementOffset(); - if (oldIndex >= 0) { - // copy old data - ptrdiff_t readOffset = oldIndex * _stride; - ptrdiff_t writeOffset = index * _stride; - - int const oldSize = range->GetCapacity(); - int const newSize = range->GetNumElements(); - ptrdiff_t copySize = _stride * std::min(oldSize, newSize); - - relocator.AddRange(readOffset, writeOffset, copySize); - } - - range->SetIndex(index); - index += range->GetNumElements(); - } - - // buffer copy - relocator.Commit(blitCmds); - - } else { - // just set index - int index = 0; - - size_t rangeCount = GetRangeCount(); - for (size_t rangeIdx = 0; rangeIdx < rangeCount; ++rangeIdx) { - _StripedInterleavedBufferRangeSharedPtr range = _GetRangeSharedPtr(rangeIdx); - if (!range) { - TF_CODING_ERROR("_StripedInterleavedBufferRange expired " - "unexpectedly."); - continue; - } - - range->SetIndex(index); - index += range->GetNumElements(); - } - } - if (oldBuf) { - // delete old buffer - hgi->DestroyBuffer(&oldBuf); - } + // if old and new buffer exist, copy unchanged data + if (curBuf && newBuf) + { + int index = 0; + + size_t rangeCount = GetRangeCount(); + + // pre-pass to combine consecutive buffer range relocation + HdStBufferRelocator relocator(curBuf, newBuf); + for (size_t rangeIdx = 0; rangeIdx < rangeCount; ++rangeIdx) + { + _StripedInterleavedBufferRangeSharedPtr range = _GetRangeSharedPtr(rangeIdx); + + if (!range) + { + TF_CODING_ERROR("_StripedInterleavedBufferRange expired " + "unexpectedly."); + continue; + } + int oldIndex = range->GetElementOffset(); + if (oldIndex >= 0) + { + // copy old data + ptrdiff_t readOffset = oldIndex * _stride; + ptrdiff_t writeOffset = index * _stride; + + int const oldSize = range->GetCapacity(); + int const newSize = range->GetNumElements(); + ptrdiff_t copySize = _stride * std::min(oldSize, newSize); + + relocator.AddRange(readOffset, writeOffset, copySize); + } + + range->SetIndex(index); + index += range->GetNumElements(); + } + + // buffer copy + relocator.Commit(blitCmds); + } + else + { + // just set index + int index = 0; - // update allocation to all buffer resources - TF_FOR_ALL(it, GetResources()) { - it->second->SetAllocation(newBuf, totalSize); + size_t rangeCount = GetRangeCount(); + for (size_t rangeIdx = 0; rangeIdx < rangeCount; ++rangeIdx) + { + _StripedInterleavedBufferRangeSharedPtr range = _GetRangeSharedPtr(rangeIdx); + if (!range) + { + TF_CODING_ERROR("_StripedInterleavedBufferRange expired " + "unexpectedly."); + continue; + } + + range->SetIndex(index); + index += range->GetNumElements(); } + } + if (oldBuf) + { + // delete old buffer + hgi->DestroyBuffer(&oldBuf); + } + + // update allocation to all buffer resources + TF_FOR_ALL(it, GetResources()) + { + it->second->SetAllocation(newBuf, totalSize); + } - // update ranges - for (size_t idx = 0; idx < ranges.size(); ++idx) { - _StripedInterleavedBufferRangeSharedPtr range = - std::static_pointer_cast<_StripedInterleavedBufferRange>( - ranges[idx]); - if (!range) { - TF_CODING_ERROR( - "_StripedInterleavedBufferRange expired unexpectedly."); - continue; - } - range->SetCapacity(range->GetNumElements()); + // update ranges + for (size_t idx = 0; idx < ranges.size(); ++idx) + { + _StripedInterleavedBufferRangeSharedPtr range = + std::static_pointer_cast<_StripedInterleavedBufferRange>( + ranges[idx]); + if (!range) + { + TF_CODING_ERROR( + "_StripedInterleavedBufferRange expired unexpectedly."); + continue; } + range->SetCapacity(range->GetNumElements()); + } - blitCmds->PopDebugGroup(); + blitCmds->PopDebugGroup(); - _needsReallocation = false; - _needsCompaction = false; + _needsReallocation = false; + _needsCompaction = false; - // increment version to rebuild dispatch buffers. - IncrementVersion(); + // increment version to rebuild dispatch buffers. + IncrementVersion(); } -void -HdStInterleavedMemoryManager::_StripedInterleavedBuffer::_DeallocateResources() +void HdStInterleavedMemoryManager::_StripedInterleavedBuffer::_DeallocateResources() { - HdStBufferResourceSharedPtr resource = GetResource(); - if (resource) { - _resourceRegistry->GetHgi()->DestroyBuffer(&resource->GetHandle()); - } + HdStBufferResourceSharedPtr resource = GetResource(); + if (resource) + { + _resourceRegistry->GetHgi()->DestroyBuffer(&resource->GetHandle()); + } } -void -HdStInterleavedMemoryManager::_StripedInterleavedBuffer::DebugDump(std::ostream &out) const +void HdStInterleavedMemoryManager::_StripedInterleavedBuffer::DebugDump(std::ostream &out) const { - out << " HdStInterleavedMemoryManager\n"; - out << " Range entries " << GetRangeCount() << ":\n"; + out << " HdStInterleavedMemoryManager\n"; + out << " Range entries " << GetRangeCount() << ":\n"; - size_t rangeCount = GetRangeCount(); - for (size_t rangeIdx = 0; rangeIdx < rangeCount; ++rangeIdx) { - _StripedInterleavedBufferRangeSharedPtr range = _GetRangeSharedPtr(rangeIdx); + size_t rangeCount = GetRangeCount(); + for (size_t rangeIdx = 0; rangeIdx < rangeCount; ++rangeIdx) + { + _StripedInterleavedBufferRangeSharedPtr range = _GetRangeSharedPtr(rangeIdx); - if (range) { - out << " " << rangeIdx << *range; - } + if (range) + { + out << " " << rangeIdx << *range; } + } } HdStBufferResourceSharedPtr HdStInterleavedMemoryManager::_StripedInterleavedBuffer::GetResource() const { - HD_TRACE_FUNCTION(); + HD_TRACE_FUNCTION(); - if (_resourceList.empty()) return HdStBufferResourceSharedPtr(); + if (_resourceList.empty()) + return HdStBufferResourceSharedPtr(); - if (TfDebug::IsEnabled(HD_SAFE_MODE)) { - // make sure this buffer array has only one resource. - HgiBufferHandle const& buffer = - _resourceList.begin()->second->GetHandle(); - TF_FOR_ALL (it, _resourceList) { - if (it->second->GetHandle() != buffer) { - TF_CODING_ERROR("GetResource(void) called on" - "HdBufferArray having multiple GL resources"); - } - } + if (TfDebug::IsEnabled(HD_SAFE_MODE)) + { + // make sure this buffer array has only one resource. + HgiBufferHandle const &buffer = + _resourceList.begin()->second->GetHandle(); + TF_FOR_ALL(it, _resourceList) + { + if (it->second->GetHandle() != buffer) + { + TF_CODING_ERROR("GetResource(void) called on" + "HdBufferArray having multiple GL resources"); + } } + } - // returns the first item - return _resourceList.begin()->second; + // returns the first item + return _resourceList.begin()->second; } HdStBufferResourceSharedPtr -HdStInterleavedMemoryManager::_StripedInterleavedBuffer::GetResource(TfToken const& name) +HdStInterleavedMemoryManager::_StripedInterleavedBuffer::GetResource(TfToken const &name) { - HD_TRACE_FUNCTION(); + HD_TRACE_FUNCTION(); - // linear search. - // The number of buffer resources should be small (<10 or so). - for (HdStBufferResourceNamedList::iterator it = _resourceList.begin(); - it != _resourceList.end(); ++it) { - if (it->first == name) return it->second; - } - return HdStBufferResourceSharedPtr(); + // linear search. + // The number of buffer resources should be small (<10 or so). + for (HdStBufferResourceNamedList::iterator it = _resourceList.begin(); + it != _resourceList.end(); ++it) + { + if (it->first == name) + return it->second; + } + return HdStBufferResourceSharedPtr(); } HdBufferSpecVector HdStInterleavedMemoryManager::_StripedInterleavedBuffer::GetBufferSpecs() const { - HdBufferSpecVector result; - result.reserve(_resourceList.size()); - TF_FOR_ALL (it, _resourceList) { - result.emplace_back(it->first, it->second->GetTupleType()); - } - return result; + HdBufferSpecVector result; + result.reserve(_resourceList.size()); + TF_FOR_ALL(it, _resourceList) + { + result.emplace_back(it->first, it->second->GetTupleType()); + } + return result; } // --------------------------------------------------------------------------- @@ -633,231 +670,235 @@ HdStInterleavedMemoryManager::_StripedInterleavedBuffer::GetBufferSpecs() const // --------------------------------------------------------------------------- HdStInterleavedMemoryManager::_StripedInterleavedBufferRange::~_StripedInterleavedBufferRange() { - // Notify that hosting buffer array needs to be garbage collected. - // - // Don't do any substantial work here. - // - if (_stripedBuffer) { - _stripedBuffer->SetNeedsCompaction(); - } + // Notify that hosting buffer array needs to be garbage collected. + // + // Don't do any substantial work here. + // + if (_stripedBuffer) + { + _stripedBuffer->SetNeedsCompaction(); + } } - -bool -HdStInterleavedMemoryManager::_StripedInterleavedBufferRange::IsAssigned() const +bool HdStInterleavedMemoryManager::_StripedInterleavedBufferRange::IsAssigned() const { - return (_stripedBuffer != nullptr); + return (_stripedBuffer != nullptr); } -bool -HdStInterleavedMemoryManager::_StripedInterleavedBufferRange::IsImmutable() const +bool HdStInterleavedMemoryManager::_StripedInterleavedBufferRange::IsImmutable() const { - return (_stripedBuffer != nullptr) - && _stripedBuffer->IsImmutable(); + return (_stripedBuffer != nullptr) && _stripedBuffer->IsImmutable(); } -bool -HdStInterleavedMemoryManager::_StripedInterleavedBufferRange::RequiresStaging() const +bool HdStInterleavedMemoryManager::_StripedInterleavedBufferRange::RequiresStaging() const { - return true; + return true; } -bool -HdStInterleavedMemoryManager::_StripedInterleavedBufferRange::Resize(int numElements) +bool HdStInterleavedMemoryManager::_StripedInterleavedBufferRange::Resize(int numElements) { - HD_TRACE_FUNCTION(); - HF_MALLOC_TAG_FUNCTION(); + HD_TRACE_FUNCTION(); + HF_MALLOC_TAG_FUNCTION(); - if (!TF_VERIFY(_stripedBuffer)) return false; + if (!TF_VERIFY(_stripedBuffer)) + return false; - // XXX Some tests rely on an interleaved buffer being valid, even if given - // no data. - if (numElements == 0) { - numElements = 1; - } + // XXX Some tests rely on an interleaved buffer being valid, even if given + // no data. + if (numElements == 0) + { + numElements = 1; + } - bool needsReallocation = false; + bool needsReallocation = false; - if (_capacity != numElements) { - const size_t numMaxElements = GetMaxNumElements(); + if (_capacity != numElements) + { + const size_t numMaxElements = GetMaxNumElements(); - if (static_cast(numElements) > numMaxElements) { - TF_WARN("Attempting to resize the BAR with 0x%x elements when the " - "max number of elements in the buffer array is 0x%lx. " - "Clamping BAR size to the latter.", - numElements, numMaxElements); + if (static_cast(numElements) > numMaxElements) + { + TF_WARN("Attempting to resize the BAR with 0x%x elements when the " + "max number of elements in the buffer array is 0x%lx. " + "Clamping BAR size to the latter.", + numElements, numMaxElements); - numElements = numMaxElements; - } - _stripedBuffer->SetNeedsReallocation(); - needsReallocation = true; + numElements = numMaxElements; } + _stripedBuffer->SetNeedsReallocation(); + needsReallocation = true; + } - _numElements = numElements; - return needsReallocation; + _numElements = numElements; + return needsReallocation; } -void -HdStInterleavedMemoryManager::_StripedInterleavedBufferRange::CopyData( +void HdStInterleavedMemoryManager::_StripedInterleavedBufferRange::CopyData( HdBufferSourceSharedPtr const &bufferSource) { - HD_TRACE_FUNCTION(); - HF_MALLOC_TAG_FUNCTION(); - - if (!TF_VERIFY(_stripedBuffer)) return; - - HdStBufferResourceSharedPtr VBO = - _stripedBuffer->GetResource(bufferSource->GetName()); - - if (!VBO || !VBO->GetHandle()) { - TF_CODING_ERROR("VBO doesn't exist for %s", - bufferSource->GetName().GetText()); - return; - } - - // overrun check - // XXX:Arrays: Note that we only check tuple type here, not arity. - // This code allows N-tuples and N-element arrays to be interchanged. - // It would seem better to have upstream buffers adjust their tuple - // arity as needed. - if (!TF_VERIFY( - bufferSource->GetTupleType().type == VBO->GetTupleType().type, - "'%s': (%s (%i) x %zu) != (%s (%i) x %zu)\n", - bufferSource->GetName().GetText(), - TfEnum::GetName(bufferSource->GetTupleType().type).c_str(), - bufferSource->GetTupleType().type, - bufferSource->GetTupleType().count, - TfEnum::GetName(VBO->GetTupleType().type).c_str(), - VBO->GetTupleType().type, - VBO->GetTupleType().count)) { - return; - } - - int vboStride = VBO->GetStride(); - size_t vboOffset = VBO->GetOffset() + vboStride * _index; - int dataSize = HdDataSizeOfTupleType(VBO->GetTupleType()); - size_t const elementStride = _stripedBuffer->GetElementStride(); - - const unsigned char *data = - (const unsigned char*)bufferSource->GetData(); - - HgiBufferCpuToGpuOp blitOp; - blitOp.gpuDestinationBuffer = VBO->GetHandle(); - blitOp.sourceByteOffset = 0; - blitOp.byteSize = dataSize; - - HdStStagingBuffer *stagingBuffer = - GetResourceRegistry()->GetStagingBuffer(); - - for (size_t i = 0; i < _numElements; ++i) { - blitOp.cpuSourceBuffer = data; - blitOp.destinationByteOffset = vboOffset; - - stagingBuffer->StageCopy(blitOp); - - vboOffset += elementStride; - data += dataSize; - } - - HD_PERF_COUNTER_ADD(HdStPerfTokens->copyBufferCpuToGpu, - (double)_numElements); + HD_TRACE_FUNCTION(); + HF_MALLOC_TAG_FUNCTION(); + + if (!TF_VERIFY(_stripedBuffer)) + return; + + HdStBufferResourceSharedPtr VBO = + _stripedBuffer->GetResource(bufferSource->GetName()); + + if (!VBO || !VBO->GetHandle()) + { + TF_CODING_ERROR("VBO doesn't exist for %s", + bufferSource->GetName().GetText()); + return; + } + + // overrun check + // XXX:Arrays: Note that we only check tuple type here, not arity. + // This code allows N-tuples and N-element arrays to be interchanged. + // It would seem better to have upstream buffers adjust their tuple + // arity as needed. + if (!TF_VERIFY( + bufferSource->GetTupleType().type == VBO->GetTupleType().type, + "'%s': (%s (%i) x %zu) != (%s (%i) x %zu)\n", + bufferSource->GetName().GetText(), + TfEnum::GetName(bufferSource->GetTupleType().type).c_str(), + bufferSource->GetTupleType().type, + bufferSource->GetTupleType().count, + TfEnum::GetName(VBO->GetTupleType().type).c_str(), + VBO->GetTupleType().type, + VBO->GetTupleType().count)) + { + return; + } + + int vboStride = VBO->GetStride(); + size_t vboOffset = VBO->GetOffset() + vboStride * _index; + int dataSize = HdDataSizeOfTupleType(VBO->GetTupleType()); + size_t const elementStride = _stripedBuffer->GetElementStride(); + + const unsigned char *data = + (const unsigned char *)bufferSource->GetData(); + + HgiBufferCpuToGpuOp blitOp; + blitOp.gpuDestinationBuffer = VBO->GetHandle(); + blitOp.sourceByteOffset = 0; + blitOp.byteSize = dataSize; + + HdStStagingBuffer *stagingBuffer = + GetResourceRegistry()->GetStagingBuffer(); + + for (size_t i = 0; i < _numElements; ++i) + { + blitOp.cpuSourceBuffer = data; + blitOp.destinationByteOffset = vboOffset; + + stagingBuffer->StageCopy(blitOp); + + vboOffset += elementStride; + data += dataSize; + } + + HD_PERF_COUNTER_ADD(HdStPerfTokens->copyBufferCpuToGpu, + (double)_numElements); } VtValue HdStInterleavedMemoryManager::_StripedInterleavedBufferRange::ReadData( TfToken const &name) const { - HD_TRACE_FUNCTION(); - HF_MALLOC_TAG_FUNCTION(); + HD_TRACE_FUNCTION(); + HF_MALLOC_TAG_FUNCTION(); - VtValue result; - if (!TF_VERIFY(_stripedBuffer)) return result; + VtValue result; + if (!TF_VERIFY(_stripedBuffer)) + return result; - HdStBufferResourceSharedPtr VBO = _stripedBuffer->GetResource(name); + HdStBufferResourceSharedPtr VBO = _stripedBuffer->GetResource(name); - if (!VBO || !VBO->GetHandle()) { - TF_CODING_ERROR("VBO doesn't exist for %s", name.GetText()); - return result; - } + if (!VBO || !VBO->GetHandle()) + { + TF_CODING_ERROR("VBO doesn't exist for %s", name.GetText()); + return result; + } - result = HdStReadBuffer(VBO->GetHandle(), - VBO->GetTupleType(), - VBO->GetOffset() + VBO->GetStride() * _index, - VBO->GetStride(), - _numElements, - _stripedBuffer->GetElementStride(), - GetResourceRegistry()); + result = HdStReadBuffer(VBO->GetHandle(), + VBO->GetTupleType(), + VBO->GetOffset() + VBO->GetStride() * _index, + VBO->GetStride(), + _numElements, + _stripedBuffer->GetElementStride(), + GetResourceRegistry()); - return result; + return result; } size_t HdStInterleavedMemoryManager::_StripedInterleavedBufferRange::GetMaxNumElements() const { - return _stripedBuffer->GetMaxNumElements(); + return _stripedBuffer->GetMaxNumElements(); } HdBufferArrayUsageHint HdStInterleavedMemoryManager:: -_StripedInterleavedBufferRange::GetUsageHint() const + _StripedInterleavedBufferRange::GetUsageHint() const { - if (!TF_VERIFY(_stripedBuffer)) { - return HdBufferArrayUsageHint(); - } + if (!TF_VERIFY(_stripedBuffer)) + { + return HdBufferArrayUsageHint(); + } - return _stripedBuffer->GetUsageHint(); + return _stripedBuffer->GetUsageHint(); } HdStBufferResourceSharedPtr HdStInterleavedMemoryManager::_StripedInterleavedBufferRange::GetResource() const { - if (!TF_VERIFY(_stripedBuffer)) return HdStBufferResourceSharedPtr(); + if (!TF_VERIFY(_stripedBuffer)) + return HdStBufferResourceSharedPtr(); - return _stripedBuffer->GetResource(); + return _stripedBuffer->GetResource(); } HdStBufferResourceSharedPtr HdStInterleavedMemoryManager::_StripedInterleavedBufferRange::GetResource( - TfToken const& name) + TfToken const &name) { - if (!TF_VERIFY(_stripedBuffer)) - return HdStBufferResourceSharedPtr(); + if (!TF_VERIFY(_stripedBuffer)) + return HdStBufferResourceSharedPtr(); - // don't use GetResource(void) as a shortcut even an interleaved buffer - // is sharing one underlying GL resource. We may need an appropriate - // offset depending on name. - return _stripedBuffer->GetResource(name); + // don't use GetResource(void) as a shortcut even an interleaved buffer + // is sharing one underlying GL resource. We may need an appropriate + // offset depending on name. + return _stripedBuffer->GetResource(name); } -HdStBufferResourceNamedList const& +HdStBufferResourceNamedList const & HdStInterleavedMemoryManager::_StripedInterleavedBufferRange::GetResources() const { - if (!TF_VERIFY(_stripedBuffer)) { - static HdStBufferResourceNamedList empty; - return empty; - } - return _stripedBuffer->GetResources(); + if (!TF_VERIFY(_stripedBuffer)) + { + static HdStBufferResourceNamedList empty; + return empty; + } + return _stripedBuffer->GetResources(); } -void -HdStInterleavedMemoryManager::_StripedInterleavedBufferRange::SetBufferArray(HdBufferArray *bufferArray) +void HdStInterleavedMemoryManager::_StripedInterleavedBufferRange::SetBufferArray(HdBufferArray *bufferArray) { - _stripedBuffer = static_cast<_StripedInterleavedBuffer *>(bufferArray); + _stripedBuffer = static_cast<_StripedInterleavedBuffer *>(bufferArray); } -void -HdStInterleavedMemoryManager::_StripedInterleavedBufferRange::DebugDump( +void HdStInterleavedMemoryManager::_StripedInterleavedBufferRange::DebugDump( std::ostream &out) const { - out << "[StripedIBR] index = " << _index - << "\n"; + out << "[StripedIBR] index = " << _index + << "\n"; } const void * HdStInterleavedMemoryManager::_StripedInterleavedBufferRange::_GetAggregation() const { - return _stripedBuffer; + return _stripedBuffer; } PXR_NAMESPACE_CLOSE_SCOPE - diff --git a/Sources/OpenUSD/imaging/hdSt/materialNetworkShader.cpp b/Sources/OpenUSD/imaging/hdSt/materialNetworkShader.cpp index c9b5842298..909cf11358 100644 --- a/Sources/OpenUSD/imaging/hdSt/materialNetworkShader.cpp +++ b/Sources/OpenUSD/imaging/hdSt/materialNetworkShader.cpp @@ -36,58 +36,50 @@ #include "pxr/imaging/hgi/capabilities.h" -#include "pxr/base/arch/hash.h" +#include "Arch/hash.h" #include "pxr/base/tf/envSetting.h" #include PXR_NAMESPACE_OPEN_SCOPE - TF_DEFINE_ENV_SETTING(HDST_ENABLE_MATERIAL_PRIMVAR_FILTERING, true, - "Enables filtering of primvar signals by material binding."); + "Enables filtering of primvar signals by material binding."); static bool -_IsEnabledMaterialPrimvarFiltering() { - return TfGetEnvSetting(HDST_ENABLE_MATERIAL_PRIMVAR_FILTERING); +_IsEnabledMaterialPrimvarFiltering() +{ + return TfGetEnvSetting(HDST_ENABLE_MATERIAL_PRIMVAR_FILTERING); } static TfTokenVector _CollectPrimvarNames(const HdSt_MaterialParamVector ¶ms); HdSt_MaterialNetworkShader::HdSt_MaterialNetworkShader() - : HdStShaderCode() - , _fragmentSource() - , _geometrySource() - , _params() - , _paramSpec() - , _paramArray() - , _primvarNames(_CollectPrimvarNames(_params)) - , _isEnabledPrimvarFiltering(_IsEnabledMaterialPrimvarFiltering()) - , _computedHash(0) - , _isValidComputedHash(false) - , _computedTextureSourceHash(0) - , _isValidComputedTextureSourceHash(false) - , _materialTag() + : HdStShaderCode(), _fragmentSource(), _geometrySource(), _params(), _paramSpec(), _paramArray(), _primvarNames(_CollectPrimvarNames(_params)), _isEnabledPrimvarFiltering(_IsEnabledMaterialPrimvarFiltering()), _computedHash(0), _isValidComputedHash(false), _computedTextureSourceHash(0), _isValidComputedTextureSourceHash(false), _materialTag() { } HdSt_MaterialNetworkShader::~HdSt_MaterialNetworkShader() = default; -void -HdSt_MaterialNetworkShader::_SetSource( - TfToken const &shaderStageKey, std::string const &source) +void HdSt_MaterialNetworkShader::_SetSource( + TfToken const &shaderStageKey, std::string const &source) { - if (shaderStageKey == HdShaderTokens->fragmentShader) { - _fragmentSource = source; - _isValidComputedHash = false; - } else if (shaderStageKey == HdShaderTokens->geometryShader) { - _geometrySource = source; - _isValidComputedHash = false; - } else if (shaderStageKey == HdShaderTokens->displacementShader) { - _displacementSource = source; - _isValidComputedHash = false; - } + if (shaderStageKey == HdShaderTokens->fragmentShader) + { + _fragmentSource = source; + _isValidComputedHash = false; + } + else if (shaderStageKey == HdShaderTokens->geometryShader) + { + _geometrySource = source; + _isValidComputedHash = false; + } + else if (shaderStageKey == HdShaderTokens->displacementShader) + { + _displacementSource = source; + _isValidComputedHash = false; + } } // -------------------------------------------------------------------------- // @@ -98,70 +90,70 @@ HdSt_MaterialNetworkShader::_SetSource( std::string HdSt_MaterialNetworkShader::GetSource(TfToken const &shaderStageKey) const { - if (shaderStageKey == HdShaderTokens->fragmentShader) { - return _fragmentSource; - } else if (shaderStageKey == HdShaderTokens->geometryShader) { - return _geometrySource; - } else if (shaderStageKey == HdShaderTokens->displacementShader) { - return _displacementSource; - } - - return std::string(); + if (shaderStageKey == HdShaderTokens->fragmentShader) + { + return _fragmentSource; + } + else if (shaderStageKey == HdShaderTokens->geometryShader) + { + return _geometrySource; + } + else if (shaderStageKey == HdShaderTokens->displacementShader) + { + return _displacementSource; + } + + return std::string(); } /*virtual*/ -HdSt_MaterialParamVector const& +HdSt_MaterialParamVector const & HdSt_MaterialNetworkShader::GetParams() const { - return _params; + return _params; } -void -HdSt_MaterialNetworkShader::SetEnabledPrimvarFiltering(bool enabled) +void HdSt_MaterialNetworkShader::SetEnabledPrimvarFiltering(bool enabled) { - _isEnabledPrimvarFiltering = - enabled && _IsEnabledMaterialPrimvarFiltering(); + _isEnabledPrimvarFiltering = + enabled && _IsEnabledMaterialPrimvarFiltering(); } /* virtual */ -bool -HdSt_MaterialNetworkShader::IsEnabledPrimvarFiltering() const +bool HdSt_MaterialNetworkShader::IsEnabledPrimvarFiltering() const { - return _isEnabledPrimvarFiltering; + return _isEnabledPrimvarFiltering; } /*virtual*/ -TfTokenVector const& +TfTokenVector const & HdSt_MaterialNetworkShader::GetPrimvarNames() const { - return _primvarNames; + return _primvarNames; } /*virtual*/ -HdBufferArrayRangeSharedPtr const& +HdBufferArrayRangeSharedPtr const & HdSt_MaterialNetworkShader::GetShaderData() const { - return _paramArray; + return _paramArray; } HdStShaderCode::NamedTextureHandleVector const & HdSt_MaterialNetworkShader::GetNamedTextureHandles() const { - return _namedTextureHandles; + return _namedTextureHandles; } /*virtual*/ -void -HdSt_MaterialNetworkShader::BindResources(const int program, - HdSt_ResourceBinder const &binder) +void HdSt_MaterialNetworkShader::BindResources(const int program, + HdSt_ResourceBinder const &binder) { - HdSt_TextureBinder::BindResources(binder, _namedTextureHandles); + HdSt_TextureBinder::BindResources(binder, _namedTextureHandles); } /*virtual*/ -void -HdSt_MaterialNetworkShader::UnbindResources(const int program, - HdSt_ResourceBinder const &binder) +void HdSt_MaterialNetworkShader::UnbindResources(const int program, + HdSt_ResourceBinder const &binder) { - HdSt_TextureBinder::UnbindResources(binder, _namedTextureHandles); + HdSt_TextureBinder::UnbindResources(binder, _namedTextureHandles); } /*virtual*/ -void -HdSt_MaterialNetworkShader::AddBindings( +void HdSt_MaterialNetworkShader::AddBindings( HdStBindingRequestVector *customBindings) { } @@ -170,317 +162,326 @@ HdSt_MaterialNetworkShader::AddBindings( HdStShaderCode::ID HdSt_MaterialNetworkShader::ComputeHash() const { - // All mutator methods that might affect the hash must reset this (fragile). - if (!_isValidComputedHash) { - _computedHash = _ComputeHash(); - _isValidComputedHash = true; - } - return _computedHash; + // All mutator methods that might affect the hash must reset this (fragile). + if (!_isValidComputedHash) + { + _computedHash = _ComputeHash(); + _isValidComputedHash = true; + } + return _computedHash; } /*virtual*/ HdStShaderCode::ID HdSt_MaterialNetworkShader::ComputeTextureSourceHash() const { - // To avoid excessive plumbing and checking of HgiCapabilities in order to - // determine if bindless textures are enabled, we make things a little - // easier for ourselves by having this function check and return 0 if - // using bindless textures. - const bool useBindlessHandles = _namedTextureHandles.empty() ? false : - _namedTextureHandles[0].handle->UseBindlessHandles(); - - if (useBindlessHandles) { - return 0; - } - - if (!_isValidComputedTextureSourceHash) { - _computedTextureSourceHash = _ComputeTextureSourceHash(); - _isValidComputedTextureSourceHash = true; - } - return _computedTextureSourceHash; + // To avoid excessive plumbing and checking of HgiCapabilities in order to + // determine if bindless textures are enabled, we make things a little + // easier for ourselves by having this function check and return 0 if + // using bindless textures. + const bool useBindlessHandles = _namedTextureHandles.empty() ? false : _namedTextureHandles[0].handle->UseBindlessHandles(); + + if (useBindlessHandles) + { + return 0; + } + + if (!_isValidComputedTextureSourceHash) + { + _computedTextureSourceHash = _ComputeTextureSourceHash(); + _isValidComputedTextureSourceHash = true; + } + return _computedTextureSourceHash; } HdStShaderCode::ID HdSt_MaterialNetworkShader::_ComputeHash() const { - size_t hash = HdSt_MaterialParam::ComputeHash(_params); - - boost::hash_combine(hash, - ArchHash(_fragmentSource.c_str(), _fragmentSource.size())); - boost::hash_combine(hash, - ArchHash(_geometrySource.c_str(), _geometrySource.size())); - boost::hash_combine(hash, - ArchHash(_displacementSource.c_str(), _displacementSource.size())); - - // Codegen is inspecting the shader bar spec to generate some - // of the struct's, so we should probably use _paramSpec - // in the hash computation as well. - // - // In practise, _paramSpec is generated from the - // HdSt_MaterialParam's so the above is sufficient. - - return hash; + size_t hash = HdSt_MaterialParam::ComputeHash(_params); + + boost::hash_combine(hash, + ArchHash(_fragmentSource.c_str(), _fragmentSource.size())); + boost::hash_combine(hash, + ArchHash(_geometrySource.c_str(), _geometrySource.size())); + boost::hash_combine(hash, + ArchHash(_displacementSource.c_str(), _displacementSource.size())); + + // Codegen is inspecting the shader bar spec to generate some + // of the struct's, so we should probably use _paramSpec + // in the hash computation as well. + // + // In practise, _paramSpec is generated from the + // HdSt_MaterialParam's so the above is sufficient. + + return hash; } HdStShaderCode::ID HdSt_MaterialNetworkShader::_ComputeTextureSourceHash() const { - TRACE_FUNCTION(); + TRACE_FUNCTION(); - size_t hash = 0; + size_t hash = 0; - for (const HdStShaderCode::NamedTextureHandle &namedHandle : - _namedTextureHandles) { + for (const HdStShaderCode::NamedTextureHandle &namedHandle : + _namedTextureHandles) + { - // Use name, texture object and sampling parameters. - boost::hash_combine(hash, namedHandle.name); - boost::hash_combine(hash, namedHandle.hash); - } - - return hash; + // Use name, texture object and sampling parameters. + boost::hash_combine(hash, namedHandle.name); + boost::hash_combine(hash, namedHandle.hash); + } + + return hash; } -void -HdSt_MaterialNetworkShader::SetFragmentSource(const std::string &source) +void HdSt_MaterialNetworkShader::SetFragmentSource(const std::string &source) { - _fragmentSource = source; - _isValidComputedHash = false; + _fragmentSource = source; + _isValidComputedHash = false; } -void -HdSt_MaterialNetworkShader::SetGeometrySource(const std::string &source) +void HdSt_MaterialNetworkShader::SetGeometrySource(const std::string &source) { - _geometrySource = source; - _isValidComputedHash = false; + _geometrySource = source; + _isValidComputedHash = false; } -void -HdSt_MaterialNetworkShader::SetDisplacementSource(const std::string &source) +void HdSt_MaterialNetworkShader::SetDisplacementSource(const std::string &source) { - _displacementSource = source; - _isValidComputedHash = false; + _displacementSource = source; + _isValidComputedHash = false; } -void -HdSt_MaterialNetworkShader::SetParams(const HdSt_MaterialParamVector ¶ms) +void HdSt_MaterialNetworkShader::SetParams(const HdSt_MaterialParamVector ¶ms) { - _params = params; - _primvarNames = _CollectPrimvarNames(_params); - _isValidComputedHash = false; + _params = params; + _primvarNames = _CollectPrimvarNames(_params); + _isValidComputedHash = false; } -void -HdSt_MaterialNetworkShader::SetNamedTextureHandles( +void HdSt_MaterialNetworkShader::SetNamedTextureHandles( const NamedTextureHandleVector &namedTextureHandles) { - _namedTextureHandles = namedTextureHandles; - _isValidComputedTextureSourceHash = false; + _namedTextureHandles = namedTextureHandles; + _isValidComputedTextureSourceHash = false; } -void -HdSt_MaterialNetworkShader::SetBufferSources( +void HdSt_MaterialNetworkShader::SetBufferSources( HdBufferSpecVector const &bufferSpecs, HdBufferSourceSharedPtrVector &&bufferSources, HdStResourceRegistrySharedPtr const &resourceRegistry) { - if (bufferSpecs.empty()) { - if (!_paramSpec.empty()) { - _isValidComputedHash = false; - } + if (bufferSpecs.empty()) + { + if (!_paramSpec.empty()) + { + _isValidComputedHash = false; + } - _paramSpec.clear(); + _paramSpec.clear(); + _paramArray.reset(); + } + else + { + if (!_paramArray || _paramSpec != bufferSpecs) + { + _paramSpec = bufferSpecs; + + // establish a buffer range + HdBufferArrayRangeSharedPtr range = + resourceRegistry->AllocateShaderStorageBufferArrayRange( + HdTokens->materialParams, + bufferSpecs, + HdBufferArrayUsageHint()); + + if (!TF_VERIFY(range->IsValid())) + { _paramArray.reset(); - } else { - if (!_paramArray || _paramSpec != bufferSpecs) { - _paramSpec = bufferSpecs; - - // establish a buffer range - HdBufferArrayRangeSharedPtr range = - resourceRegistry->AllocateShaderStorageBufferArrayRange( - HdTokens->materialParams, - bufferSpecs, - HdBufferArrayUsageHint()); - - if (!TF_VERIFY(range->IsValid())) { - _paramArray.reset(); - } else { - _paramArray = range; - } - _isValidComputedHash = false; - } - - if (_paramArray->IsValid()) { - if (!bufferSources.empty()) { - resourceRegistry->AddSources(_paramArray, - std::move(bufferSources)); - } - } + } + else + { + _paramArray = range; + } + _isValidComputedHash = false; + } + + if (_paramArray->IsValid()) + { + if (!bufferSources.empty()) + { + resourceRegistry->AddSources(_paramArray, + std::move(bufferSources)); + } } + } } TfToken HdSt_MaterialNetworkShader::GetMaterialTag() const { - return _materialTag; + return _materialTag; } -void -HdSt_MaterialNetworkShader::SetMaterialTag(TfToken const &tag) +void HdSt_MaterialNetworkShader::SetMaterialTag(TfToken const &tag) { - _materialTag = tag; - _isValidComputedHash = false; + _materialTag = tag; + _isValidComputedHash = false; } /// If the prim is based on asset, reload that asset. -void -HdSt_MaterialNetworkShader::Reload() +void HdSt_MaterialNetworkShader::Reload() { - // Nothing to do, this shader's sources are externally managed. + // Nothing to do, this shader's sources are externally managed. } /*static*/ -bool -HdSt_MaterialNetworkShader::CanAggregate(HdStShaderCodeSharedPtr const &shaderA, - HdStShaderCodeSharedPtr const &shaderB) +bool HdSt_MaterialNetworkShader::CanAggregate(HdStShaderCodeSharedPtr const &shaderA, + HdStShaderCodeSharedPtr const &shaderB) { - // Can aggregate if the shaders are identical. - if (shaderA == shaderB) { - return true; - } + // Can aggregate if the shaders are identical. + if (shaderA == shaderB) + { + return true; + } - HdBufferArrayRangeSharedPtr dataA = shaderA->GetShaderData(); - HdBufferArrayRangeSharedPtr dataB = shaderB->GetShaderData(); + HdBufferArrayRangeSharedPtr dataA = shaderA->GetShaderData(); + HdBufferArrayRangeSharedPtr dataB = shaderB->GetShaderData(); - bool dataIsAggregated = (dataA == dataB) || - (dataA && dataA->IsAggregatedWith(dataB)); + bool dataIsAggregated = (dataA == dataB) || + (dataA && dataA->IsAggregatedWith(dataB)); - // We can't aggregate if the shaders have data buffers that aren't - // aggregated or if the shaders don't match. - if (!dataIsAggregated || shaderA->ComputeHash() != shaderB->ComputeHash()) { - return false; - } + // We can't aggregate if the shaders have data buffers that aren't + // aggregated or if the shaders don't match. + if (!dataIsAggregated || shaderA->ComputeHash() != shaderB->ComputeHash()) + { + return false; + } - if (shaderA->ComputeTextureSourceHash() != - shaderB->ComputeTextureSourceHash()) { - return false; - } + if (shaderA->ComputeTextureSourceHash() != + shaderB->ComputeTextureSourceHash()) + { + return false; + } - return true; + return true; } TF_DEFINE_PRIVATE_TOKENS( _tokens, - (ptexFaceOffset) // geometric shader + (ptexFaceOffset) // geometric shader - (displayMetallic) // simple lighting shader - (displayRoughness) // simple lighting shader + (displayMetallic) // simple lighting shader + (displayRoughness) // simple lighting shader - (hullColor) // terminal shader - (hullOpacity) // terminal shader - (scalarOverride) // terminal shader - (scalarOverrideColorRamp) // terminal shader - (selectedWeight) // terminal shader + (hullColor) // terminal shader + (hullOpacity) // terminal shader + (scalarOverride) // terminal shader + (scalarOverrideColorRamp) // terminal shader + (selectedWeight) // terminal shader - (indicatorColor) // renderPass shader - (indicatorWeight) // renderPass shader - (overrideColor) // renderPass shader - (overrideWireframeColor) // renderPass shader - (maskColor) // renderPass shader - (maskWeight) // renderPass shader - (wireframeColor) // renderPass shader + (indicatorColor) // renderPass shader + (indicatorWeight) // renderPass shader + (overrideColor) // renderPass shader + (overrideWireframeColor) // renderPass shader + (maskColor) // renderPass shader + (maskWeight) // renderPass shader + (wireframeColor) // renderPass shader ); static TfTokenVector const & _GetExtraIncludedShaderPrimvarNames() { - static const TfTokenVector primvarNames = { - HdTokens->displayColor, - HdTokens->displayOpacity, - - // Include a few ad hoc primvar names that - // are used by the built-in material shading system. - - _tokens->ptexFaceOffset, - - _tokens->displayMetallic, - _tokens->displayRoughness, - - _tokens->hullColor, - _tokens->hullOpacity, - _tokens->scalarOverride, - _tokens->scalarOverrideColorRamp, - _tokens->selectedWeight, - - _tokens->indicatorColor, - _tokens->indicatorWeight, - _tokens->overrideColor, - _tokens->overrideWireframeColor, - _tokens->maskColor, - _tokens->maskWeight, - _tokens->wireframeColor - }; - return primvarNames; + static const TfTokenVector primvarNames = { + HdTokens->displayColor, + HdTokens->displayOpacity, + + // Include a few ad hoc primvar names that + // are used by the built-in material shading system. + + _tokens->ptexFaceOffset, + + _tokens->displayMetallic, + _tokens->displayRoughness, + + _tokens->hullColor, + _tokens->hullOpacity, + _tokens->scalarOverride, + _tokens->scalarOverrideColorRamp, + _tokens->selectedWeight, + + _tokens->indicatorColor, + _tokens->indicatorWeight, + _tokens->overrideColor, + _tokens->overrideWireframeColor, + _tokens->maskColor, + _tokens->maskWeight, + _tokens->wireframeColor}; + return primvarNames; } static TfTokenVector _CollectPrimvarNames(const HdSt_MaterialParamVector ¶ms) { - TfTokenVector primvarNames = _GetExtraIncludedShaderPrimvarNames(); - - for (HdSt_MaterialParam const ¶m: params) { - if (param.IsPrimvarRedirect()) { - primvarNames.push_back(param.name); - // primvar redirect connections are encoded as sampler coords - primvarNames.insert(primvarNames.end(), - param.samplerCoords.begin(), - param.samplerCoords.end()); - } else if (param.IsTexture()) { - // include sampler coords for textures - primvarNames.insert(primvarNames.end(), - param.samplerCoords.begin(), - param.samplerCoords.end()); - } else if (param.IsAdditionalPrimvar()) { - primvarNames.push_back(param.name); - } + TfTokenVector primvarNames = _GetExtraIncludedShaderPrimvarNames(); + + for (HdSt_MaterialParam const ¶m : params) + { + if (param.IsPrimvarRedirect()) + { + primvarNames.push_back(param.name); + // primvar redirect connections are encoded as sampler coords + primvarNames.insert(primvarNames.end(), + param.samplerCoords.begin(), + param.samplerCoords.end()); + } + else if (param.IsTexture()) + { + // include sampler coords for textures + primvarNames.insert(primvarNames.end(), + param.samplerCoords.begin(), + param.samplerCoords.end()); } - return primvarNames; + else if (param.IsAdditionalPrimvar()) + { + primvarNames.push_back(param.name); + } + } + return primvarNames; } -void -HdSt_MaterialNetworkShader::AddResourcesFromTextures(ResourceContext &ctx) const +void HdSt_MaterialNetworkShader::AddResourcesFromTextures(ResourceContext &ctx) const { - const bool doublesSupported = ctx.GetResourceRegistry()->GetHgi()-> - GetCapabilities()->IsSet( - HgiDeviceCapabilitiesBitsShaderDoublePrecision); - - // Add buffer sources for bindless texture handles (and - // other texture metadata such as the sampling transform for - // a field texture). - HdBufferSourceSharedPtrVector result; - HdSt_TextureBinder::ComputeBufferSources( - GetNamedTextureHandles(), &result, doublesSupported); - - if (!result.empty()) { - ctx.AddSources(GetShaderData(), std::move(result)); - } + const bool doublesSupported = ctx.GetResourceRegistry()->GetHgi()->GetCapabilities()->IsSet( + HgiDeviceCapabilitiesBitsShaderDoublePrecision); + + // Add buffer sources for bindless texture handles (and + // other texture metadata such as the sampling transform for + // a field texture). + HdBufferSourceSharedPtrVector result; + HdSt_TextureBinder::ComputeBufferSources( + GetNamedTextureHandles(), &result, doublesSupported); + + if (!result.empty()) + { + ctx.AddSources(GetShaderData(), std::move(result)); + } } -void -HdSt_MaterialNetworkShader::AddFallbackValueToSpecsAndSources( +void HdSt_MaterialNetworkShader::AddFallbackValueToSpecsAndSources( const HdSt_MaterialParam ¶m, - HdBufferSpecVector * const specs, - HdBufferSourceSharedPtrVector * const sources) + HdBufferSpecVector *const specs, + HdBufferSourceSharedPtrVector *const sources) { - const TfToken sourceName( - param.name.GetString() - + HdSt_ResourceBindingSuffixTokens->fallback.GetString()); - - HdBufferSourceSharedPtr const source = - std::make_shared( - sourceName, param.fallbackValue); - source->GetBufferSpecs(specs); - sources->push_back(std::move(source)); + const TfToken sourceName( + param.name.GetString() + HdSt_ResourceBindingSuffixTokens->fallback.GetString()); + + HdBufferSourceSharedPtr const source = + std::make_shared( + sourceName, param.fallbackValue); + source->GetBufferSpecs(specs); + sources->push_back(std::move(source)); } PXR_NAMESPACE_CLOSE_SCOPE diff --git a/Sources/OpenUSD/imaging/hdSt/mesh.cpp b/Sources/OpenUSD/imaging/hdSt/mesh.cpp index b92b67434e..86409c0d24 100644 --- a/Sources/OpenUSD/imaging/hdSt/mesh.cpp +++ b/Sources/OpenUSD/imaging/hdSt/mesh.cpp @@ -45,7 +45,7 @@ #include "pxr/imaging/hgi/capabilities.h" -#include "pxr/base/arch/hash.h" +#include "Arch/hash.h" #include "pxr/base/gf/matrix4d.h" #include "pxr/base/gf/matrix4f.h" @@ -61,7 +61,7 @@ #include "pxr/imaging/hf/diagnostic.h" -#include "pxr/imaging/pxOsd/tokens.h" +#include "PxOsd/tokens.h" #include "pxr/base/vt/value.h" diff --git a/Sources/OpenUSD/imaging/hdSt/pipelineDrawBatch.cpp b/Sources/OpenUSD/imaging/hdSt/pipelineDrawBatch.cpp index 07f6a11492..8d24cd4e52 100644 --- a/Sources/OpenUSD/imaging/hdSt/pipelineDrawBatch.cpp +++ b/Sources/OpenUSD/imaging/hdSt/pipelineDrawBatch.cpp @@ -53,7 +53,7 @@ #include "pxr/base/gf/matrix4f.h" -#include "pxr/base/arch/hash.h" +#include "Arch/hash.h" #include "pxr/base/tf/diagnostic.h" #include "pxr/base/tf/envSetting.h" @@ -69,159 +69,136 @@ TF_DEFINE_PRIVATE_TOKENS( (constantPrimvars) - (dispatchBuffer) - (drawCullInput) + (dispatchBuffer)(drawCullInput) - (drawIndirect) - (drawIndirectCull) - (drawIndirectResult) - - (ulocCullParams) -); + (drawIndirect)(drawIndirectCull)(drawIndirectResult) + (ulocCullParams)); TF_DEFINE_ENV_SETTING(HDST_ENABLE_PIPELINE_DRAW_BATCH_GPU_FRUSTUM_CULLING, true, "Enable pipeline draw batching GPU frustum culling"); HdSt_PipelineDrawBatch::HdSt_PipelineDrawBatch( - HdStDrawItemInstance * drawItemInstance, + HdStDrawItemInstance *drawItemInstance, bool const allowGpuFrustumCulling, bool const allowIndirectCommandEncoding) - : HdSt_DrawBatch(drawItemInstance) - , _drawCommandBufferDirty(false) - , _bufferArraysHash(0) - , _barElementOffsetsHash(0) - , _numVisibleItems(0) - , _numTotalVertices(0) - , _numTotalElements(0) - /* The following two values are set before draw by - * SetEnableTinyPrimCulling(). */ - , _useTinyPrimCulling(false) - , _dirtyCullingProgram(false) - /* The following four values are initialized in _Init(). */ - , _useDrawIndexed(true) - , _useInstancing(false) - , _useGpuCulling(false) - , _useInstanceCulling(false) - , _allowGpuFrustumCulling(allowGpuFrustumCulling) - , _allowIndirectCommandEncoding(allowIndirectCommandEncoding) - , _instanceCountOffset(0) - , _cullInstanceCountOffset(0) - , _drawCoordOffset(0) - , _patchBaseVertexByteOffset(0) + : HdSt_DrawBatch(drawItemInstance), _drawCommandBufferDirty(false), _bufferArraysHash(0), _barElementOffsetsHash(0), _numVisibleItems(0), _numTotalVertices(0), _numTotalElements(0) + /* The following two values are set before draw by + * SetEnableTinyPrimCulling(). */ + , + _useTinyPrimCulling(false), _dirtyCullingProgram(false) + /* The following four values are initialized in _Init(). */ + , + _useDrawIndexed(true), _useInstancing(false), _useGpuCulling(false), _useInstanceCulling(false), _allowGpuFrustumCulling(allowGpuFrustumCulling), _allowIndirectCommandEncoding(allowIndirectCommandEncoding), _instanceCountOffset(0), _cullInstanceCountOffset(0), _drawCoordOffset(0), _patchBaseVertexByteOffset(0) { - _Init(drawItemInstance); + _Init(drawItemInstance); } HdSt_PipelineDrawBatch::~HdSt_PipelineDrawBatch() = default; /*virtual*/ -void -HdSt_PipelineDrawBatch::_Init(HdStDrawItemInstance * drawItemInstance) +void HdSt_PipelineDrawBatch::_Init(HdStDrawItemInstance *drawItemInstance) { - HdSt_DrawBatch::_Init(drawItemInstance); - drawItemInstance->SetBatchIndex(0); - drawItemInstance->SetBatch(this); - - // remember buffer arrays version for dispatch buffer updating - HdStDrawItem const * drawItem = drawItemInstance->GetDrawItem(); - _bufferArraysHash = drawItem->GetBufferArraysHash(); - // _barElementOffsetsHash is updated during _CompileBatch - _barElementOffsetsHash = 0; - - // determine drawing and culling config according to the first drawitem - _useDrawIndexed = static_cast(drawItem->GetTopologyRange()); - _useInstancing = static_cast(drawItem->GetInstanceIndexRange()); - _useGpuCulling = _allowGpuFrustumCulling && IsEnabledGPUFrustumCulling(); - - // note: _useInstancing condition is not necessary. it can be removed - // if we decide always to use instance culling. - _useInstanceCulling = _useInstancing && - _useGpuCulling && IsEnabledGPUInstanceFrustumCulling(); - - if (_useGpuCulling) { - _cullingProgram.Initialize( - _useDrawIndexed, _useInstanceCulling, _bufferArraysHash); - } - - TF_DEBUG(HDST_DRAW_BATCH).Msg( - " Resetting dispatch buffer.\n"); - _dispatchBuffer.reset(); + HdSt_DrawBatch::_Init(drawItemInstance); + drawItemInstance->SetBatchIndex(0); + drawItemInstance->SetBatch(this); + + // remember buffer arrays version for dispatch buffer updating + HdStDrawItem const *drawItem = drawItemInstance->GetDrawItem(); + _bufferArraysHash = drawItem->GetBufferArraysHash(); + // _barElementOffsetsHash is updated during _CompileBatch + _barElementOffsetsHash = 0; + + // determine drawing and culling config according to the first drawitem + _useDrawIndexed = static_cast(drawItem->GetTopologyRange()); + _useInstancing = static_cast(drawItem->GetInstanceIndexRange()); + _useGpuCulling = _allowGpuFrustumCulling && IsEnabledGPUFrustumCulling(); + + // note: _useInstancing condition is not necessary. it can be removed + // if we decide always to use instance culling. + _useInstanceCulling = _useInstancing && + _useGpuCulling && IsEnabledGPUInstanceFrustumCulling(); + + if (_useGpuCulling) + { + _cullingProgram.Initialize( + _useDrawIndexed, _useInstanceCulling, _bufferArraysHash); + } + + TF_DEBUG(HDST_DRAW_BATCH).Msg(" Resetting dispatch buffer.\n"); + _dispatchBuffer.reset(); } -void -HdSt_PipelineDrawBatch::SetEnableTinyPrimCulling(bool tinyPrimCulling) +void HdSt_PipelineDrawBatch::SetEnableTinyPrimCulling(bool tinyPrimCulling) { - if (_useTinyPrimCulling != tinyPrimCulling) { - _useTinyPrimCulling = tinyPrimCulling; - _dirtyCullingProgram = true; - } + if (_useTinyPrimCulling != tinyPrimCulling) + { + _useTinyPrimCulling = tinyPrimCulling; + _dirtyCullingProgram = true; + } } /* static */ -bool -HdSt_PipelineDrawBatch::IsEnabled(HgiCapabilities const *hgiCapabilities) +bool HdSt_PipelineDrawBatch::IsEnabled(HgiCapabilities const *hgiCapabilities) { - // We require Hgi resource generation. - return HdSt_CodeGen::IsEnabledHgiResourceGeneration(hgiCapabilities); + // We require Hgi resource generation. + return HdSt_CodeGen::IsEnabledHgiResourceGeneration(hgiCapabilities); } /* static */ -bool -HdSt_PipelineDrawBatch::IsEnabledGPUFrustumCulling() +bool HdSt_PipelineDrawBatch::IsEnabledGPUFrustumCulling() { - // Allow GPU frustum culling for PipelineDrawBatch to be disabled even - // when other GPU frustum culling is enabled. Both switches must be true - // for PipelineDrawBatch to use GPU frustum culling. - static bool isEnabled = - TfGetEnvSetting(HDST_ENABLE_PIPELINE_DRAW_BATCH_GPU_FRUSTUM_CULLING); - return isEnabled && HdSt_IndirectDrawBatch::IsEnabledGPUFrustumCulling(); + // Allow GPU frustum culling for PipelineDrawBatch to be disabled even + // when other GPU frustum culling is enabled. Both switches must be true + // for PipelineDrawBatch to use GPU frustum culling. + static bool isEnabled = + TfGetEnvSetting(HDST_ENABLE_PIPELINE_DRAW_BATCH_GPU_FRUSTUM_CULLING); + return isEnabled && HdSt_IndirectDrawBatch::IsEnabledGPUFrustumCulling(); } /* static */ -bool -HdSt_PipelineDrawBatch::IsEnabledGPUCountVisibleInstances() +bool HdSt_PipelineDrawBatch::IsEnabledGPUCountVisibleInstances() { - return HdSt_IndirectDrawBatch::IsEnabledGPUCountVisibleInstances(); + return HdSt_IndirectDrawBatch::IsEnabledGPUCountVisibleInstances(); } /* static */ -bool -HdSt_PipelineDrawBatch::IsEnabledGPUInstanceFrustumCulling() +bool HdSt_PipelineDrawBatch::IsEnabledGPUInstanceFrustumCulling() { - return HdSt_IndirectDrawBatch::IsEnabledGPUInstanceFrustumCulling(); + return HdSt_IndirectDrawBatch::IsEnabledGPUInstanceFrustumCulling(); } //////////////////////////////////////////////////////////// // GPU Command Buffer Preparation //////////////////////////////////////////////////////////// -namespace { - -// Draw command dispatch buffers are built as arrays of uint32_t, but -// we use these struct definitions to reason consistently about element -// access and offsets. -// -// The _DrawingCoord struct defines bundles of element offsets into buffers -// which together represent the drawing coordinate input to the shader. -// These must be kept in sync with codeGen. For instanced culling we need -// only a subset of the drawing coord. It might be beneficial to rearrange -// the drawing coord tuples. -// -// Note: _Draw*Command structs are layed out such that the first elements -// match the layout of Vulkan and GL and D3D indirect draw parameters. -// -// Note: Metal Patch drawing uses a different encoding than Vulkan and GL -// and D3D. Also, there is no base vertex offset in the indexed draw encoding, -// so we need to manually step vertex buffer binding offsets while encoding -// draw commands. -// -// Note: GL specifies baseVertex as 'int' and other as 'uint', but -// we never set negative baseVertex in our use cases. - -// DrawingCoord 10 integers (+ numInstanceLevels) -struct _DrawingCoord +namespace { + + // Draw command dispatch buffers are built as arrays of uint32_t, but + // we use these struct definitions to reason consistently about element + // access and offsets. + // + // The _DrawingCoord struct defines bundles of element offsets into buffers + // which together represent the drawing coordinate input to the shader. + // These must be kept in sync with codeGen. For instanced culling we need + // only a subset of the drawing coord. It might be beneficial to rearrange + // the drawing coord tuples. + // + // Note: _Draw*Command structs are layed out such that the first elements + // match the layout of Vulkan and GL and D3D indirect draw parameters. + // + // Note: Metal Patch drawing uses a different encoding than Vulkan and GL + // and D3D. Also, there is no base vertex offset in the indexed draw encoding, + // so we need to manually step vertex buffer binding offsets while encoding + // draw commands. + // + // Note: GL specifies baseVertex as 'int' and other as 'uint', but + // we never set negative baseVertex in our use cases. + + // DrawingCoord 10 integers (+ numInstanceLevels) + struct _DrawingCoord + { // drawingCoord0 (ivec4 for drawing and culling) uint32_t modelDC; uint32_t constantDC; @@ -240,45 +217,51 @@ struct _DrawingCoord // drawingCoordI (int32[] for drawing and culling) // uint32_t instanceDC[numInstanceLevels]; -}; + }; -// DrawNonIndexed + non-instance culling : 14 integers (+ numInstanceLevels) -struct _DrawNonIndexedCommand -{ - union { - struct { - uint32_t count; - uint32_t instanceCount; - uint32_t baseVertex; - uint32_t baseInstance; - } common; - struct { - uint32_t patchCount; - uint32_t instanceCount; - uint32_t patchStart; - uint32_t baseInstance; - } metalPatch; + // DrawNonIndexed + non-instance culling : 14 integers (+ numInstanceLevels) + struct _DrawNonIndexedCommand + { + union + { + struct + { + uint32_t count; + uint32_t instanceCount; + uint32_t baseVertex; + uint32_t baseInstance; + } common; + struct + { + uint32_t patchCount; + uint32_t instanceCount; + uint32_t patchStart; + uint32_t baseInstance; + } metalPatch; }; _DrawingCoord drawingCoord; -}; + }; -// DrawNonIndexed + Instance culling : 18 integers (+ numInstanceLevels) -struct _DrawNonIndexedInstanceCullCommand -{ - union { - struct { - uint32_t count; - uint32_t instanceCount; - uint32_t baseVertex; - uint32_t baseInstance; - } common; - struct { - uint32_t patchCount; - uint32_t instanceCount; - uint32_t patchStart; - uint32_t baseInstance; - } metalPatch; + // DrawNonIndexed + Instance culling : 18 integers (+ numInstanceLevels) + struct _DrawNonIndexedInstanceCullCommand + { + union + { + struct + { + uint32_t count; + uint32_t instanceCount; + uint32_t baseVertex; + uint32_t baseInstance; + } common; + struct + { + uint32_t patchCount; + uint32_t instanceCount; + uint32_t patchStart; + uint32_t baseInstance; + } metalPatch; }; uint32_t cullCount; @@ -287,49 +270,55 @@ struct _DrawNonIndexedInstanceCullCommand uint32_t cullBaseInstance; _DrawingCoord drawingCoord; -}; + }; -// DrawIndexed + non-instance culling : 15 integers (+ numInstanceLevels) -struct _DrawIndexedCommand -{ - union { - struct { - uint32_t count; - uint32_t instanceCount; - uint32_t baseIndex; - uint32_t baseVertex; - uint32_t baseInstance; - } common; - struct { - uint32_t patchCount; - uint32_t instanceCount; - uint32_t patchStart; - uint32_t baseInstance; - uint32_t baseVertex; - } metalPatch; + // DrawIndexed + non-instance culling : 15 integers (+ numInstanceLevels) + struct _DrawIndexedCommand + { + union + { + struct + { + uint32_t count; + uint32_t instanceCount; + uint32_t baseIndex; + uint32_t baseVertex; + uint32_t baseInstance; + } common; + struct + { + uint32_t patchCount; + uint32_t instanceCount; + uint32_t patchStart; + uint32_t baseInstance; + uint32_t baseVertex; + } metalPatch; }; _DrawingCoord drawingCoord; -}; + }; -// DrawIndexed + Instance culling : 19 integers (+ numInstanceLevels) -struct _DrawIndexedInstanceCullCommand -{ - union { - struct { - uint32_t count; - uint32_t instanceCount; - uint32_t baseIndex; - uint32_t baseVertex; - uint32_t baseInstance; - } common; - struct { - uint32_t patchCount; - uint32_t instanceCount; - uint32_t patchStart; - uint32_t baseInstance; - uint32_t baseVertex; - } metalPatch; + // DrawIndexed + Instance culling : 19 integers (+ numInstanceLevels) + struct _DrawIndexedInstanceCullCommand + { + union + { + struct + { + uint32_t count; + uint32_t instanceCount; + uint32_t baseIndex; + uint32_t baseVertex; + uint32_t baseInstance; + } common; + struct + { + uint32_t patchCount; + uint32_t instanceCount; + uint32_t patchStart; + uint32_t baseInstance; + uint32_t baseVertex; + } metalPatch; }; uint32_t cullCount; @@ -338,11 +327,11 @@ struct _DrawIndexedInstanceCullCommand uint32_t cullBaseInstance; _DrawingCoord drawingCoord; -}; + }; -// These traits capture sizes and offsets for the _Draw*Command structs -struct _DrawCommandTraits -{ + // These traits capture sizes and offsets for the _Draw*Command structs + struct _DrawCommandTraits + { // Since the underlying buffer is an array of uint32_t, we capture // the size of the struct as the number of uint32_t elements. size_t numUInt32; @@ -365,26 +354,28 @@ struct _DrawCommandTraits size_t drawingCoordI_offset; size_t patchBaseVertex_offset; -}; + }; -template -void _SetDrawCommandTraits(_DrawCommandTraits * traits, - int const instancerNumLevels, - size_t const uint32Alignment) -{ + template + void _SetDrawCommandTraits(_DrawCommandTraits *traits, + int const instancerNumLevels, + size_t const uint32Alignment) + { // Number of uint32_t in the command struct // followed by instanceDC[instancerNumLevals] - traits->numUInt32 = sizeof(CmdType) / sizeof(uint32_t) - + instancerNumLevels; - - if (uint32Alignment > 0) { - size_t const alignMask = uint32Alignment - 1; - size_t const alignedNumUInt32 = - (traits->numUInt32 + alignMask) & ~alignMask; - traits->numUInt32Padding = alignedNumUInt32 - traits->numUInt32; - traits->numUInt32 = alignedNumUInt32; - } else { - traits->numUInt32Padding = 0; + traits->numUInt32 = sizeof(CmdType) / sizeof(uint32_t) + instancerNumLevels; + + if (uint32Alignment > 0) + { + size_t const alignMask = uint32Alignment - 1; + size_t const alignedNumUInt32 = + (traits->numUInt32 + alignMask) & ~alignMask; + traits->numUInt32Padding = alignedNumUInt32 - traits->numUInt32; + traits->numUInt32 = alignedNumUInt32; + } + else + { + traits->numUInt32Padding = 0; } traits->instancerNumLevels = instancerNumLevels; @@ -397,18 +388,18 @@ void _SetDrawCommandTraits(_DrawCommandTraits * traits, // These are different only for instanced culling. traits->cullCount_offset = traits->count_offset; traits->cullInstanceCount_offset = traits->instanceCount_offset; -} + } -template -void _SetInstanceCullTraits(_DrawCommandTraits * traits) -{ + template + void _SetInstanceCullTraits(_DrawCommandTraits *traits) + { traits->cullCount_offset = offsetof(CmdType, cullCount); traits->cullInstanceCount_offset = offsetof(CmdType, cullInstanceCount); -} + } -template -void _SetDrawingCoordTraits(_DrawCommandTraits * traits) -{ + template + void _SetDrawingCoordTraits(_DrawCommandTraits *traits) + { // drawingCoord bundles are located by the offsets to their first elements traits->drawingCoord0_offset = offsetof(CmdType, drawingCoord) + offsetof(_DrawingCoord, modelDC); @@ -423,49 +414,58 @@ void _SetDrawingCoordTraits(_DrawCommandTraits * traits) // needed to step vertex buffer binding offsets for Metal tessellation traits->patchBaseVertex_offset = offsetof(CmdType, drawingCoord) + offsetof(_DrawingCoord, vertexDC); -} - -_DrawCommandTraits -_GetDrawCommandTraits(int const instancerNumLevels, - bool const useDrawIndexed, - bool const useInstanceCulling, - size_t const uint32Alignment) -{ + } + + _DrawCommandTraits + _GetDrawCommandTraits(int const instancerNumLevels, + bool const useDrawIndexed, + bool const useInstanceCulling, + size_t const uint32Alignment) + { _DrawCommandTraits traits; - if (!useDrawIndexed) { - if (useInstanceCulling) { - using CmdType = _DrawNonIndexedInstanceCullCommand; - _SetDrawCommandTraits(&traits, instancerNumLevels, - uint32Alignment); - _SetInstanceCullTraits(&traits); - _SetDrawingCoordTraits(&traits); - } else { - using CmdType = _DrawNonIndexedCommand; - _SetDrawCommandTraits(&traits, instancerNumLevels, - uint32Alignment); - _SetDrawingCoordTraits(&traits); - } - } else { - if (useInstanceCulling) { - using CmdType = _DrawIndexedInstanceCullCommand; - _SetDrawCommandTraits(&traits, instancerNumLevels, - uint32Alignment); - _SetInstanceCullTraits(&traits); - _SetDrawingCoordTraits(&traits); - } else { - using CmdType = _DrawIndexedCommand; - _SetDrawCommandTraits(&traits, instancerNumLevels, - uint32Alignment); - _SetDrawingCoordTraits(&traits); - } + if (!useDrawIndexed) + { + if (useInstanceCulling) + { + using CmdType = _DrawNonIndexedInstanceCullCommand; + _SetDrawCommandTraits(&traits, instancerNumLevels, + uint32Alignment); + _SetInstanceCullTraits(&traits); + _SetDrawingCoordTraits(&traits); + } + else + { + using CmdType = _DrawNonIndexedCommand; + _SetDrawCommandTraits(&traits, instancerNumLevels, + uint32Alignment); + _SetDrawingCoordTraits(&traits); + } + } + else + { + if (useInstanceCulling) + { + using CmdType = _DrawIndexedInstanceCullCommand; + _SetDrawCommandTraits(&traits, instancerNumLevels, + uint32Alignment); + _SetInstanceCullTraits(&traits); + _SetDrawingCoordTraits(&traits); + } + else + { + using CmdType = _DrawIndexedCommand; + _SetDrawCommandTraits(&traits, instancerNumLevels, + uint32Alignment); + _SetDrawingCoordTraits(&traits); + } } return traits; -} + } -void -_AddDrawResourceViews(HdStDispatchBufferSharedPtr const & dispatchBuffer, - _DrawCommandTraits const & traits) -{ + void + _AddDrawResourceViews(HdStDispatchBufferSharedPtr const &dispatchBuffer, + _DrawCommandTraits const &traits) + { // draw indirect command dispatchBuffer->AddBufferResourceView( HdTokens->drawDispatch, {HdTypeInt32, 1}, @@ -483,48 +483,50 @@ _AddDrawResourceViews(HdStDispatchBufferSharedPtr const & dispatchBuffer, HdTokens->drawingCoord2, {HdTypeInt32Vec2, 1}, traits.drawingCoord2_offset); // instance drawing coords - if (traits.instancerNumLevels > 0) { - dispatchBuffer->AddBufferResourceView( - HdTokens->drawingCoordI, {HdTypeInt32, traits.instancerNumLevels}, - traits.drawingCoordI_offset); + if (traits.instancerNumLevels > 0) + { + dispatchBuffer->AddBufferResourceView( + HdTokens->drawingCoordI, {HdTypeInt32, traits.instancerNumLevels}, + traits.drawingCoordI_offset); } -} + } -HdBufferArrayRangeSharedPtr -_GetShaderBar(HdSt_MaterialNetworkShaderSharedPtr const & shader) -{ + HdBufferArrayRangeSharedPtr + _GetShaderBar(HdSt_MaterialNetworkShaderSharedPtr const &shader) + { return shader ? shader->GetShaderData() : nullptr; -} + } -// Collection of resources for a drawItem -struct _DrawItemState -{ - explicit _DrawItemState(HdStDrawItem const * drawItem) + // Collection of resources for a drawItem + struct _DrawItemState + { + explicit _DrawItemState(HdStDrawItem const *drawItem) : constantBar(std::static_pointer_cast( - drawItem->GetConstantPrimvarRange())) - , indexBar(std::static_pointer_cast( - drawItem->GetTopologyRange())) - , topVisBar(std::static_pointer_cast( - drawItem->GetTopologyVisibilityRange())) - , elementBar(std::static_pointer_cast( - drawItem->GetElementPrimvarRange())) - , fvarBar(std::static_pointer_cast( - drawItem->GetFaceVaryingPrimvarRange())) - , varyingBar(std::static_pointer_cast( - drawItem->GetVaryingPrimvarRange())) - , vertexBar(std::static_pointer_cast( - drawItem->GetVertexPrimvarRange())) - , shaderBar(std::static_pointer_cast( - _GetShaderBar(drawItem->GetMaterialNetworkShader()))) - , instanceIndexBar(std::static_pointer_cast( - drawItem->GetInstanceIndexRange())) + drawItem->GetConstantPrimvarRange())), + indexBar(std::static_pointer_cast( + drawItem->GetTopologyRange())), + topVisBar(std::static_pointer_cast( + drawItem->GetTopologyVisibilityRange())), + elementBar(std::static_pointer_cast( + drawItem->GetElementPrimvarRange())), + fvarBar(std::static_pointer_cast( + drawItem->GetFaceVaryingPrimvarRange())), + varyingBar(std::static_pointer_cast( + drawItem->GetVaryingPrimvarRange())), + vertexBar(std::static_pointer_cast( + drawItem->GetVertexPrimvarRange())), + shaderBar(std::static_pointer_cast( + _GetShaderBar(drawItem->GetMaterialNetworkShader()))), + instanceIndexBar(std::static_pointer_cast( + drawItem->GetInstanceIndexRange())) { - instancePrimvarBars.resize(drawItem->GetInstancePrimvarNumLevels()); - for (size_t i = 0; i < instancePrimvarBars.size(); ++i) { - instancePrimvarBars[i] = - std::static_pointer_cast( - drawItem->GetInstancePrimvarRange(i)); - } + instancePrimvarBars.resize(drawItem->GetInstancePrimvarNumLevels()); + for (size_t i = 0; i < instancePrimvarBars.size(); ++i) + { + instancePrimvarBars[i] = + std::static_pointer_cast( + drawItem->GetInstancePrimvarRange(i)); + } } HdStBufferArrayRangeSharedPtr constantBar; @@ -537,25 +539,25 @@ struct _DrawItemState HdStBufferArrayRangeSharedPtr shaderBar; HdStBufferArrayRangeSharedPtr instanceIndexBar; std::vector instancePrimvarBars; -}; + }; -uint32_t -_GetElementOffset(HdBufferArrayRangeSharedPtr const & range) -{ + uint32_t + _GetElementOffset(HdBufferArrayRangeSharedPtr const &range) + { return range ? range->GetElementOffset() : 0; -} + } -uint32_t -_GetElementCount(HdBufferArrayRangeSharedPtr const & range) -{ + uint32_t + _GetElementCount(HdBufferArrayRangeSharedPtr const &range) + { return range ? range->GetNumElements() : 0; -} + } -uint32_t -_GetInstanceCount(HdStDrawItemInstance const * drawItemInstance, - HdBufferArrayRangeSharedPtr const & instanceIndexBar, - int const instanceIndexWidth) -{ + uint32_t + _GetInstanceCount(HdStDrawItemInstance const *drawItemInstance, + HdBufferArrayRangeSharedPtr const &instanceIndexBar, + int const instanceIndexWidth) + { // It's possible to have an instanceIndexBar which exists but is empty, // i.e. GetNumElements() == 0, and no instancePrimvars. // In that case instanceCount should be 0, instead of 1, otherwise the @@ -566,26 +568,38 @@ _GetInstanceCount(HdStDrawItemInstance const * drawItemInstance, uint32_t const instanceCount = drawItemInstance->IsVisible() ? (numInstances / instanceIndexWidth) : 0; return instanceCount; -} - -HdStBufferResourceSharedPtr -_AllocateTessFactorsBuffer( - HdStDrawItem const * drawItem, - HdStResourceRegistrySharedPtr const & resourceRegistry) -{ - if (!drawItem) { return nullptr; } + } + + HdStBufferResourceSharedPtr + _AllocateTessFactorsBuffer( + HdStDrawItem const *drawItem, + HdStResourceRegistrySharedPtr const &resourceRegistry) + { + if (!drawItem) + { + return nullptr; + } HdStBufferArrayRangeSharedPtr indexBar( std::static_pointer_cast( - drawItem->GetTopologyRange())); - if (!indexBar) { return nullptr; } + drawItem->GetTopologyRange())); + if (!indexBar) + { + return nullptr; + } HdStBufferResourceSharedPtr indexBuffer = - indexBar->GetResource(HdTokens->indices); - if (!indexBuffer) { return nullptr; } + indexBar->GetResource(HdTokens->indices); + if (!indexBuffer) + { + return nullptr; + } - HgiBufferHandle const & indexBufferHandle = indexBuffer->GetHandle(); - if (!indexBufferHandle) { return nullptr; } + HgiBufferHandle const &indexBufferHandle = indexBuffer->GetHandle(); + if (!indexBufferHandle) + { + return nullptr; + } size_t const byteSizeOfTuple = HdDataSizeOfTupleType(indexBuffer->GetTupleType()); @@ -597,463 +611,488 @@ _AllocateTessFactorsBuffer( return resourceRegistry->RegisterBufferResource( HdTokens->tessFactors, - HdTupleType{HdTypeHalfFloat, numElements*numTessFactorsPerElement}); -} + HdTupleType{HdTypeHalfFloat, numElements * numTessFactorsPerElement}); + } } // annonymous namespace -void -HdSt_PipelineDrawBatch::_CompileBatch( - HdStResourceRegistrySharedPtr const & resourceRegistry) +void HdSt_PipelineDrawBatch::_CompileBatch( + HdStResourceRegistrySharedPtr const &resourceRegistry) { - TRACE_FUNCTION(); - HF_MALLOC_TAG_FUNCTION(); + TRACE_FUNCTION(); + HF_MALLOC_TAG_FUNCTION(); + + if (_drawItemInstances.empty()) + return; + + size_t const numDrawItemInstances = _drawItemInstances.size(); + + size_t const instancerNumLevels = + _drawItemInstances[0]->GetDrawItem()->GetInstancePrimvarNumLevels(); + + bool const useMetalTessellation = + _drawItemInstances[0]->GetDrawItem()->GetGeometricShader()->GetUseMetalTessellation(); + + // Align drawing commands to 32 bytes for Metal. + size_t const uint32Alignment = useMetalTessellation ? 8 : 0; + + // Get the layout of the command buffer we are building. + _DrawCommandTraits const traits = + _GetDrawCommandTraits(instancerNumLevels, + _useDrawIndexed, + _useInstanceCulling, + uint32Alignment); + + TF_DEBUG(HDST_DRAW).Msg("\nCompile Dispatch Buffer\n"); + TF_DEBUG(HDST_DRAW).Msg(" - numUInt32: %zd\n", traits.numUInt32); + TF_DEBUG(HDST_DRAW).Msg(" - useDrawIndexed: %d\n", _useDrawIndexed); + TF_DEBUG(HDST_DRAW).Msg(" - useInstanceCulling: %d\n", _useInstanceCulling); + TF_DEBUG(HDST_DRAW).Msg(" - num draw items: %zu\n", numDrawItemInstances); + + _drawCommandBuffer.resize(numDrawItemInstances * traits.numUInt32); + std::vector::iterator cmdIt = _drawCommandBuffer.begin(); + + // Count the number of visible items. We may actually draw fewer + // items than this when GPU frustum culling is active. + _numVisibleItems = 0; + _numTotalElements = 0; + _numTotalVertices = 0; + + TF_DEBUG(HDST_DRAW).Msg(" - Processing Items:\n"); + _barElementOffsetsHash = 0; + for (size_t item = 0; item < numDrawItemInstances; ++item) + { + HdStDrawItemInstance const *drawItemInstance = _drawItemInstances[item]; + HdStDrawItem const *drawItem = drawItemInstance->GetDrawItem(); + + _barElementOffsetsHash = + TfHash::Combine(_barElementOffsetsHash, + drawItem->GetElementOffsetsHash()); + + _DrawItemState const dc(drawItem); + + // drawing coordinates. + uint32_t const modelDC = 0; // reserved for future extension + uint32_t const constantDC = _GetElementOffset(dc.constantBar); + uint32_t const vertexDC = _GetElementOffset(dc.vertexBar); + uint32_t const topVisDC = _GetElementOffset(dc.topVisBar); + uint32_t const elementDC = _GetElementOffset(dc.elementBar); + uint32_t const primitiveDC = _GetElementOffset(dc.indexBar); + uint32_t const fvarDC = _GetElementOffset(dc.fvarBar); + uint32_t const instanceIndexDC = _GetElementOffset(dc.instanceIndexBar); + uint32_t const shaderDC = _GetElementOffset(dc.shaderBar); + uint32_t const varyingDC = _GetElementOffset(dc.varyingBar); + + // 3 for triangles, 4 for quads, 6 for triquads, n for patches + uint32_t const numIndicesPerPrimitive = + drawItem->GetGeometricShader()->GetPrimitiveIndexSize(); + + uint32_t const baseVertex = vertexDC; + uint32_t const vertexCount = _GetElementCount(dc.vertexBar); + + // if delegate fails to get vertex primvars, it could be empty. + // skip the drawitem to prevent drawing uninitialized vertices. + uint32_t const numElements = + vertexCount != 0 ? _GetElementCount(dc.indexBar) : 0; + + uint32_t const baseIndex = primitiveDC * numIndicesPerPrimitive; + uint32_t const indexCount = numElements * numIndicesPerPrimitive; - if (_drawItemInstances.empty()) return; + uint32_t const instanceCount = + _GetInstanceCount(drawItemInstance, + dc.instanceIndexBar, + traits.instanceIndexWidth); - size_t const numDrawItemInstances = _drawItemInstances.size(); + // tessellated patches are encoded differently for Metal. + uint32_t const patchStart = primitiveDC; + uint32_t const patchCount = numElements; - size_t const instancerNumLevels = - _drawItemInstances[0]->GetDrawItem()->GetInstancePrimvarNumLevels(); + uint32_t const baseInstance = (uint32_t)item; - bool const useMetalTessellation = - _drawItemInstances[0]->GetDrawItem()-> - GetGeometricShader()->GetUseMetalTessellation(); - - // Align drawing commands to 32 bytes for Metal. - size_t const uint32Alignment = useMetalTessellation ? 8 : 0; - - // Get the layout of the command buffer we are building. - _DrawCommandTraits const traits = - _GetDrawCommandTraits(instancerNumLevels, - _useDrawIndexed, - _useInstanceCulling, - uint32Alignment); - - TF_DEBUG(HDST_DRAW).Msg("\nCompile Dispatch Buffer\n"); - TF_DEBUG(HDST_DRAW).Msg(" - numUInt32: %zd\n", traits.numUInt32); - TF_DEBUG(HDST_DRAW).Msg(" - useDrawIndexed: %d\n", _useDrawIndexed); - TF_DEBUG(HDST_DRAW).Msg(" - useInstanceCulling: %d\n", _useInstanceCulling); - TF_DEBUG(HDST_DRAW).Msg(" - num draw items: %zu\n", numDrawItemInstances); - - _drawCommandBuffer.resize(numDrawItemInstances * traits.numUInt32); - std::vector::iterator cmdIt = _drawCommandBuffer.begin(); - - // Count the number of visible items. We may actually draw fewer - // items than this when GPU frustum culling is active. - _numVisibleItems = 0; - _numTotalElements = 0; - _numTotalVertices = 0; - - TF_DEBUG(HDST_DRAW).Msg(" - Processing Items:\n"); - _barElementOffsetsHash = 0; - for (size_t item = 0; item < numDrawItemInstances; ++item) { - HdStDrawItemInstance const *drawItemInstance = _drawItemInstances[item]; - HdStDrawItem const *drawItem = drawItemInstance->GetDrawItem(); - - _barElementOffsetsHash = - TfHash::Combine(_barElementOffsetsHash, - drawItem->GetElementOffsetsHash()); - - _DrawItemState const dc(drawItem); - - // drawing coordinates. - uint32_t const modelDC = 0; // reserved for future extension - uint32_t const constantDC = _GetElementOffset(dc.constantBar); - uint32_t const vertexDC = _GetElementOffset(dc.vertexBar); - uint32_t const topVisDC = _GetElementOffset(dc.topVisBar); - uint32_t const elementDC = _GetElementOffset(dc.elementBar); - uint32_t const primitiveDC = _GetElementOffset(dc.indexBar); - uint32_t const fvarDC = _GetElementOffset(dc.fvarBar); - uint32_t const instanceIndexDC = _GetElementOffset(dc.instanceIndexBar); - uint32_t const shaderDC = _GetElementOffset(dc.shaderBar); - uint32_t const varyingDC = _GetElementOffset(dc.varyingBar); - - // 3 for triangles, 4 for quads, 6 for triquads, n for patches - uint32_t const numIndicesPerPrimitive = - drawItem->GetGeometricShader()->GetPrimitiveIndexSize(); - - uint32_t const baseVertex = vertexDC; - uint32_t const vertexCount = _GetElementCount(dc.vertexBar); - - // if delegate fails to get vertex primvars, it could be empty. - // skip the drawitem to prevent drawing uninitialized vertices. - uint32_t const numElements = - vertexCount != 0 ? _GetElementCount(dc.indexBar) : 0; - - uint32_t const baseIndex = primitiveDC * numIndicesPerPrimitive; - uint32_t const indexCount = numElements * numIndicesPerPrimitive; - - uint32_t const instanceCount = - _GetInstanceCount(drawItemInstance, - dc.instanceIndexBar, - traits.instanceIndexWidth); - - // tessellated patches are encoded differently for Metal. - uint32_t const patchStart = primitiveDC; - uint32_t const patchCount = numElements; - - uint32_t const baseInstance = (uint32_t)item; - - // draw command - if (!_useDrawIndexed) { - if (_useInstanceCulling) { - // _DrawNonIndexedInstanceCullCommand - if (useMetalTessellation) { - *cmdIt++ = patchCount; - *cmdIt++ = instanceCount; - *cmdIt++ = patchStart; - *cmdIt++ = baseInstance; - - *cmdIt++ = 1; /* cullCount (always 1) */ - *cmdIt++ = instanceCount; /* cullInstanceCount */ - *cmdIt++ = 0; /* cullBaseVertex (not used)*/ - *cmdIt++ = baseInstance; /* cullBaseInstance */ - } else { - *cmdIt++ = vertexCount; - *cmdIt++ = instanceCount; - *cmdIt++ = baseVertex; - *cmdIt++ = baseInstance; - - *cmdIt++ = 1; /* cullCount (always 1) */ - *cmdIt++ = instanceCount; /* cullInstanceCount */ - *cmdIt++ = 0; /* cullBaseVertex (not used)*/ - *cmdIt++ = baseInstance; /* cullBaseInstance */ - } - } else { - // _DrawNonIndexedCommand - if (useMetalTessellation) { - *cmdIt++ = patchCount; - *cmdIt++ = instanceCount; - *cmdIt++ = patchStart; - *cmdIt++ = baseInstance; - } else { - *cmdIt++ = vertexCount; - *cmdIt++ = instanceCount; - *cmdIt++ = baseVertex; - *cmdIt++ = baseInstance; - } - } - } else { - if (_useInstanceCulling) { - // _DrawIndexedInstanceCullCommand - if (useMetalTessellation) { - *cmdIt++ = patchCount; - *cmdIt++ = instanceCount; - *cmdIt++ = patchStart; - *cmdIt++ = baseInstance; - *cmdIt++ = baseVertex; - - *cmdIt++ = 1; /* cullCount (always 1) */ - *cmdIt++ = instanceCount; /* cullInstanceCount */ - *cmdIt++ = 0; /* cullBaseVertex (not used)*/ - *cmdIt++ = baseInstance; /* cullBaseInstance */ - } else { - *cmdIt++ = indexCount; - *cmdIt++ = instanceCount; - *cmdIt++ = baseIndex; - *cmdIt++ = baseVertex; - *cmdIt++ = baseInstance; - - *cmdIt++ = 1; /* cullCount (always 1) */ - *cmdIt++ = instanceCount; /* cullInstanceCount */ - *cmdIt++ = 0; /* cullBaseVertex (not used)*/ - *cmdIt++ = baseInstance; /* cullBaseInstance */ - } - } else { - // _DrawIndexedCommand - if (useMetalTessellation) { - *cmdIt++ = patchCount; - *cmdIt++ = instanceCount; - *cmdIt++ = patchStart; - *cmdIt++ = baseInstance; - *cmdIt++ = baseVertex; - } else { - *cmdIt++ = indexCount; - *cmdIt++ = instanceCount; - *cmdIt++ = baseIndex; - *cmdIt++ = baseVertex; - *cmdIt++ = baseInstance; - } - } + // draw command + if (!_useDrawIndexed) + { + if (_useInstanceCulling) + { + // _DrawNonIndexedInstanceCullCommand + if (useMetalTessellation) + { + *cmdIt++ = patchCount; + *cmdIt++ = instanceCount; + *cmdIt++ = patchStart; + *cmdIt++ = baseInstance; + + *cmdIt++ = 1; /* cullCount (always 1) */ + *cmdIt++ = instanceCount; /* cullInstanceCount */ + *cmdIt++ = 0; /* cullBaseVertex (not used)*/ + *cmdIt++ = baseInstance; /* cullBaseInstance */ } - - // drawingCoord0 - *cmdIt++ = modelDC; - *cmdIt++ = constantDC; - *cmdIt++ = elementDC; - *cmdIt++ = primitiveDC; - - // drawingCoord1 - *cmdIt++ = fvarDC; - *cmdIt++ = instanceIndexDC; - *cmdIt++ = shaderDC; - *cmdIt++ = vertexDC; - - // drawingCoord2 - *cmdIt++ = topVisDC; - *cmdIt++ = varyingDC; - - // drawingCoordI - for (size_t i = 0; i < dc.instancePrimvarBars.size(); ++i) { - uint32_t instanceDC = _GetElementOffset(dc.instancePrimvarBars[i]); - *cmdIt++ = instanceDC; + else + { + *cmdIt++ = vertexCount; + *cmdIt++ = instanceCount; + *cmdIt++ = baseVertex; + *cmdIt++ = baseInstance; + + *cmdIt++ = 1; /* cullCount (always 1) */ + *cmdIt++ = instanceCount; /* cullInstanceCount */ + *cmdIt++ = 0; /* cullBaseVertex (not used)*/ + *cmdIt++ = baseInstance; /* cullBaseInstance */ } - - // add padding and clear to 0 - for (size_t i = 0; i < traits.numUInt32Padding; ++i) { - *cmdIt++ = 0; + } + else + { + // _DrawNonIndexedCommand + if (useMetalTessellation) + { + *cmdIt++ = patchCount; + *cmdIt++ = instanceCount; + *cmdIt++ = patchStart; + *cmdIt++ = baseInstance; } - - if (TfDebug::IsEnabled(HDST_DRAW)) { - std::vector::iterator cmdIt2 = cmdIt - traits.numUInt32; - std::cout << " - "; - while (cmdIt2 != cmdIt) { - std::cout << *cmdIt2 << " "; - cmdIt2++; - } - std::cout << std::endl; + else + { + *cmdIt++ = vertexCount; + *cmdIt++ = instanceCount; + *cmdIt++ = baseVertex; + *cmdIt++ = baseInstance; } - - _numVisibleItems += instanceCount; - _numTotalElements += numElements; - _numTotalVertices += vertexCount; + } + } + else + { + if (_useInstanceCulling) + { + // _DrawIndexedInstanceCullCommand + if (useMetalTessellation) + { + *cmdIt++ = patchCount; + *cmdIt++ = instanceCount; + *cmdIt++ = patchStart; + *cmdIt++ = baseInstance; + *cmdIt++ = baseVertex; + + *cmdIt++ = 1; /* cullCount (always 1) */ + *cmdIt++ = instanceCount; /* cullInstanceCount */ + *cmdIt++ = 0; /* cullBaseVertex (not used)*/ + *cmdIt++ = baseInstance; /* cullBaseInstance */ + } + else + { + *cmdIt++ = indexCount; + *cmdIt++ = instanceCount; + *cmdIt++ = baseIndex; + *cmdIt++ = baseVertex; + *cmdIt++ = baseInstance; + + *cmdIt++ = 1; /* cullCount (always 1) */ + *cmdIt++ = instanceCount; /* cullInstanceCount */ + *cmdIt++ = 0; /* cullBaseVertex (not used)*/ + *cmdIt++ = baseInstance; /* cullBaseInstance */ + } + } + else + { + // _DrawIndexedCommand + if (useMetalTessellation) + { + *cmdIt++ = patchCount; + *cmdIt++ = instanceCount; + *cmdIt++ = patchStart; + *cmdIt++ = baseInstance; + *cmdIt++ = baseVertex; + } + else + { + *cmdIt++ = indexCount; + *cmdIt++ = instanceCount; + *cmdIt++ = baseIndex; + *cmdIt++ = baseVertex; + *cmdIt++ = baseInstance; + } + } } - TF_DEBUG(HDST_DRAW).Msg(" - Num Visible: %zu\n", _numVisibleItems); - TF_DEBUG(HDST_DRAW).Msg(" - Total Elements: %zu\n", _numTotalElements); - TF_DEBUG(HDST_DRAW).Msg(" - Total Verts: %zu\n", _numTotalVertices); - - // make sure we filled all - TF_VERIFY(cmdIt == _drawCommandBuffer.end()); - - // cache the location of instanceCount and cullInstanceCount, - // to be used during DrawItemInstanceChanged(). - _instanceCountOffset = traits.instanceCount_offset/sizeof(uint32_t); - _cullInstanceCountOffset = traits.cullInstanceCount_offset/sizeof(uint32_t); + // drawingCoord0 + *cmdIt++ = modelDC; + *cmdIt++ = constantDC; + *cmdIt++ = elementDC; + *cmdIt++ = primitiveDC; - // cache the offset needed for compute culling. - _drawCoordOffset = traits.drawingCoord0_offset / sizeof(uint32_t); + // drawingCoord1 + *cmdIt++ = fvarDC; + *cmdIt++ = instanceIndexDC; + *cmdIt++ = shaderDC; + *cmdIt++ = vertexDC; - // cache the location of patchBaseVertex for tessellated patch drawing. - _patchBaseVertexByteOffset = traits.patchBaseVertex_offset; + // drawingCoord2 + *cmdIt++ = topVisDC; + *cmdIt++ = varyingDC; - // allocate draw dispatch buffer - _dispatchBuffer = - resourceRegistry->RegisterDispatchBuffer(_tokens->drawIndirect, - numDrawItemInstances, - traits.numUInt32); + // drawingCoordI + for (size_t i = 0; i < dc.instancePrimvarBars.size(); ++i) + { + uint32_t instanceDC = _GetElementOffset(dc.instancePrimvarBars[i]); + *cmdIt++ = instanceDC; + } - // allocate tessFactors buffer for Metal tessellation - if (useMetalTessellation && - _drawItemInstances[0]->GetDrawItem()-> - GetGeometricShader()->IsPrimTypePatches()) { + // add padding and clear to 0 + for (size_t i = 0; i < traits.numUInt32Padding; ++i) + { + *cmdIt++ = 0; + } - _tessFactorsBuffer = _AllocateTessFactorsBuffer( - _drawItemInstances[0]->GetDrawItem(), - resourceRegistry); + if (TfDebug::IsEnabled(HDST_DRAW)) + { + std::vector::iterator cmdIt2 = cmdIt - traits.numUInt32; + std::cout << " - "; + while (cmdIt2 != cmdIt) + { + std::cout << *cmdIt2 << " "; + cmdIt2++; + } + std::cout << std::endl; } - // add drawing resource views - _AddDrawResourceViews(_dispatchBuffer, traits); + _numVisibleItems += instanceCount; + _numTotalElements += numElements; + _numTotalVertices += vertexCount; + } + + TF_DEBUG(HDST_DRAW).Msg(" - Num Visible: %zu\n", _numVisibleItems); + TF_DEBUG(HDST_DRAW).Msg(" - Total Elements: %zu\n", _numTotalElements); + TF_DEBUG(HDST_DRAW).Msg(" - Total Verts: %zu\n", _numTotalVertices); + + // make sure we filled all + TF_VERIFY(cmdIt == _drawCommandBuffer.end()); + + // cache the location of instanceCount and cullInstanceCount, + // to be used during DrawItemInstanceChanged(). + _instanceCountOffset = traits.instanceCount_offset / sizeof(uint32_t); + _cullInstanceCountOffset = traits.cullInstanceCount_offset / sizeof(uint32_t); + + // cache the offset needed for compute culling. + _drawCoordOffset = traits.drawingCoord0_offset / sizeof(uint32_t); + + // cache the location of patchBaseVertex for tessellated patch drawing. + _patchBaseVertexByteOffset = traits.patchBaseVertex_offset; + + // allocate draw dispatch buffer + _dispatchBuffer = + resourceRegistry->RegisterDispatchBuffer(_tokens->drawIndirect, + numDrawItemInstances, + traits.numUInt32); + + // allocate tessFactors buffer for Metal tessellation + if (useMetalTessellation && + _drawItemInstances[0]->GetDrawItem()->GetGeometricShader()->IsPrimTypePatches()) + { + + _tessFactorsBuffer = _AllocateTessFactorsBuffer( + _drawItemInstances[0]->GetDrawItem(), + resourceRegistry); + } + + // add drawing resource views + _AddDrawResourceViews(_dispatchBuffer, traits); + + // copy data + _dispatchBuffer->CopyData(_drawCommandBuffer); + + if (_useGpuCulling) + { + // Make a duplicate of the draw dispatch buffer to use as an input + // for GPU frustum culling (a single buffer cannot be bound for + // both reading and writing). We use only the instanceCount + // and drawingCoord parameters, but it is simplest to just make + // a copy. + _dispatchBufferCullInput = + resourceRegistry->RegisterDispatchBuffer(_tokens->drawIndirectCull, + numDrawItemInstances, + traits.numUInt32); // copy data - _dispatchBuffer->CopyData(_drawCommandBuffer); - - if (_useGpuCulling) { - // Make a duplicate of the draw dispatch buffer to use as an input - // for GPU frustum culling (a single buffer cannot be bound for - // both reading and writing). We use only the instanceCount - // and drawingCoord parameters, but it is simplest to just make - // a copy. - _dispatchBufferCullInput = - resourceRegistry->RegisterDispatchBuffer(_tokens->drawIndirectCull, - numDrawItemInstances, - traits.numUInt32); - - // copy data - _dispatchBufferCullInput->CopyData(_drawCommandBuffer); - } + _dispatchBufferCullInput->CopyData(_drawCommandBuffer); + } } HdSt_DrawBatch::ValidationResult HdSt_PipelineDrawBatch::Validate(bool deepValidation) { - if (!TF_VERIFY(!_drawItemInstances.empty())) { - return ValidationResult::RebuildAllBatches; - } + if (!TF_VERIFY(!_drawItemInstances.empty())) + { + return ValidationResult::RebuildAllBatches; + } + + TF_DEBUG(HDST_DRAW_BATCH).Msg("Validating pipeline draw batch %p (deep validation = %d)...\n", (void *)(this), deepValidation); + + // check the hash to see they've been reallocated/migrated or not. + // note that we just need to compare the hash of the first item, + // since drawitems are aggregated and ensure that they are sharing + // same buffer arrays. + HdStDrawItem const *batchItem = _drawItemInstances.front()->GetDrawItem(); + size_t const bufferArraysHash = batchItem->GetBufferArraysHash(); + + if (_bufferArraysHash != bufferArraysHash) + { + _bufferArraysHash = bufferArraysHash; + TF_DEBUG(HDST_DRAW_BATCH).Msg(" Buffer arrays hash changed. Need to rebuild batch.\n"); + return ValidationResult::RebuildBatch; + } + + // Deep validation is flagged explicitly when a drawItem has changes to + // its BARs (e.g. buffer spec, aggregation, element offsets) or when its + // material network shader or geometric shader changes. + if (deepValidation) + { + TRACE_SCOPE("Pipeline draw batch deep validation"); + // look through all draw items to be still compatible + + size_t numDrawItemInstances = _drawItemInstances.size(); + size_t barElementOffsetsHash = 0; + + for (size_t item = 0; item < numDrawItemInstances; ++item) + { + HdStDrawItem const *drawItem = + _drawItemInstances[item]->GetDrawItem(); - TF_DEBUG(HDST_DRAW_BATCH).Msg( - "Validating pipeline draw batch %p (deep validation = %d)...\n", - (void*)(this), deepValidation); - - // check the hash to see they've been reallocated/migrated or not. - // note that we just need to compare the hash of the first item, - // since drawitems are aggregated and ensure that they are sharing - // same buffer arrays. - HdStDrawItem const * batchItem = _drawItemInstances.front()->GetDrawItem(); - size_t const bufferArraysHash = batchItem->GetBufferArraysHash(); - - if (_bufferArraysHash != bufferArraysHash) { - _bufferArraysHash = bufferArraysHash; - TF_DEBUG(HDST_DRAW_BATCH).Msg( - " Buffer arrays hash changed. Need to rebuild batch.\n"); - return ValidationResult::RebuildBatch; - } + if (!TF_VERIFY(drawItem->GetGeometricShader())) + { + return ValidationResult::RebuildAllBatches; + } - // Deep validation is flagged explicitly when a drawItem has changes to - // its BARs (e.g. buffer spec, aggregation, element offsets) or when its - // material network shader or geometric shader changes. - if (deepValidation) { - TRACE_SCOPE("Pipeline draw batch deep validation"); - // look through all draw items to be still compatible - - size_t numDrawItemInstances = _drawItemInstances.size(); - size_t barElementOffsetsHash = 0; - - for (size_t item = 0; item < numDrawItemInstances; ++item) { - HdStDrawItem const * drawItem = - _drawItemInstances[item]->GetDrawItem(); - - if (!TF_VERIFY(drawItem->GetGeometricShader())) { - return ValidationResult::RebuildAllBatches; - } - - if (!_IsAggregated(batchItem, drawItem)) { - TF_DEBUG(HDST_DRAW_BATCH).Msg( - " Deep validation: Found draw item that fails aggregation" - " test. Need to rebuild all batches.\n"); - return ValidationResult::RebuildAllBatches; - } - - barElementOffsetsHash = TfHash::Combine(barElementOffsetsHash, - drawItem->GetElementOffsetsHash()); - } + if (!_IsAggregated(batchItem, drawItem)) + { + TF_DEBUG(HDST_DRAW_BATCH).Msg(" Deep validation: Found draw item that fails aggregation" + " test. Need to rebuild all batches.\n"); + return ValidationResult::RebuildAllBatches; + } - if (_barElementOffsetsHash != barElementOffsetsHash) { - TF_DEBUG(HDST_DRAW_BATCH).Msg( - " Deep validation: Element offsets hash mismatch." - " Rebuilding batch (even though only the dispatch buffer" - " needs to be updated)\n."); - return ValidationResult::RebuildBatch; - } + barElementOffsetsHash = TfHash::Combine(barElementOffsetsHash, + drawItem->GetElementOffsetsHash()); + } + if (_barElementOffsetsHash != barElementOffsetsHash) + { + TF_DEBUG(HDST_DRAW_BATCH).Msg(" Deep validation: Element offsets hash mismatch." + " Rebuilding batch (even though only the dispatch buffer" + " needs to be updated)\n."); + return ValidationResult::RebuildBatch; } + } - TF_DEBUG(HDST_DRAW_BATCH).Msg( - " Validation passed. No need to rebuild batch.\n"); - return ValidationResult::ValidBatch; + TF_DEBUG(HDST_DRAW_BATCH).Msg(" Validation passed. No need to rebuild batch.\n"); + return ValidationResult::ValidBatch; } -bool -HdSt_PipelineDrawBatch::_HasNothingToDraw() const +bool HdSt_PipelineDrawBatch::_HasNothingToDraw() const { - return ( _useDrawIndexed && _numTotalElements == 0) || - (!_useDrawIndexed && _numTotalVertices == 0); + return (_useDrawIndexed && _numTotalElements == 0) || + (!_useDrawIndexed && _numTotalVertices == 0); } -void -HdSt_PipelineDrawBatch::PrepareDraw( +void HdSt_PipelineDrawBatch::PrepareDraw( HgiGraphicsCmds *gfxCmds, - HdStRenderPassStateSharedPtr const & renderPassState, - HdStResourceRegistrySharedPtr const & resourceRegistry) + HdStRenderPassStateSharedPtr const &renderPassState, + HdStResourceRegistrySharedPtr const &resourceRegistry) { - TRACE_FUNCTION(); - - if (!_dispatchBuffer) { - _CompileBatch(resourceRegistry); - } - - if (_HasNothingToDraw()) return; - - // Do we have to update our dispatch buffer because drawitem instance - // data has changed? - // On the first time through, after batches have just been compiled, - // the flag will be false because the resource registry will have already - // uploaded the buffer. - bool const updateBufferData = _drawCommandBufferDirty; - if (updateBufferData) { - _dispatchBuffer->CopyData(_drawCommandBuffer); - _drawCommandBufferDirty = false; - } - - if (_useGpuCulling) { - // Ignore passed in gfxCmds for now since GPU frustum culling - // may still require multiple command buffer submissions. - _ExecuteFrustumCull(updateBufferData, - renderPassState, resourceRegistry); - } + TRACE_FUNCTION(); + + if (!_dispatchBuffer) + { + _CompileBatch(resourceRegistry); + } + + if (_HasNothingToDraw()) + return; + + // Do we have to update our dispatch buffer because drawitem instance + // data has changed? + // On the first time through, after batches have just been compiled, + // the flag will be false because the resource registry will have already + // uploaded the buffer. + bool const updateBufferData = _drawCommandBufferDirty; + if (updateBufferData) + { + _dispatchBuffer->CopyData(_drawCommandBuffer); + _drawCommandBufferDirty = false; + } + + if (_useGpuCulling) + { + // Ignore passed in gfxCmds for now since GPU frustum culling + // may still require multiple command buffer submissions. + _ExecuteFrustumCull(updateBufferData, + renderPassState, resourceRegistry); + } } -void -HdSt_PipelineDrawBatch::EncodeDraw( - HdStRenderPassStateSharedPtr const & renderPassState, - HdStResourceRegistrySharedPtr const & resourceRegistry) +void HdSt_PipelineDrawBatch::EncodeDraw( + HdStRenderPassStateSharedPtr const &renderPassState, + HdStResourceRegistrySharedPtr const &resourceRegistry) { - if (_HasNothingToDraw()) return; - - Hgi *hgi = resourceRegistry->GetHgi(); - HgiCapabilities const *capabilities = hgi->GetCapabilities(); - - // For ICBs on Apple Silicon, we do not support rendering to non-MSAA - // surfaces, such as OIT as Volumetrics. Disable in these cases. - bool const drawICB = - _allowIndirectCommandEncoding && - capabilities->IsSet(HgiDeviceCapabilitiesBitsIndirectCommandBuffers) && - renderPassState->GetMultiSampleEnabled(); - - _indirectCommands.reset(); - if (drawICB) { - _PrepareIndirectCommandBuffer(renderPassState, resourceRegistry); - } + if (_HasNothingToDraw()) + return; + + Hgi *hgi = resourceRegistry->GetHgi(); + HgiCapabilities const *capabilities = hgi->GetCapabilities(); + + // For ICBs on Apple Silicon, we do not support rendering to non-MSAA + // surfaces, such as OIT as Volumetrics. Disable in these cases. + bool const drawICB = + _allowIndirectCommandEncoding && + capabilities->IsSet(HgiDeviceCapabilitiesBitsIndirectCommandBuffers) && + renderPassState->GetMultiSampleEnabled(); + + _indirectCommands.reset(); + if (drawICB) + { + _PrepareIndirectCommandBuffer(renderPassState, resourceRegistry); + } } //////////////////////////////////////////////////////////// // GPU Resource Binding //////////////////////////////////////////////////////////// -namespace { - -// Resources to Bind/Unbind for a drawItem -struct _BindingState : public _DrawItemState +namespace { - _BindingState( - HdStDrawItem const * drawItem, - HdStDispatchBufferSharedPtr const & dispatchBuffer, - HdSt_ResourceBinder const & binder, - HdStGLSLProgramSharedPtr const & glslProgram, - HdStShaderCodeSharedPtrVector const & shaders, - HdSt_GeometricShaderSharedPtr const & geometricShader) - : _DrawItemState(drawItem) - , dispatchBuffer(dispatchBuffer) - , binder(binder) - , glslProgram(glslProgram) - , shaders(shaders) - , geometricShader(geometricShader) - { } + // Resources to Bind/Unbind for a drawItem + struct _BindingState : public _DrawItemState + { + _BindingState( + HdStDrawItem const *drawItem, + HdStDispatchBufferSharedPtr const &dispatchBuffer, + HdSt_ResourceBinder const &binder, + HdStGLSLProgramSharedPtr const &glslProgram, + HdStShaderCodeSharedPtrVector const &shaders, + HdSt_GeometricShaderSharedPtr const &geometricShader) + : _DrawItemState(drawItem), dispatchBuffer(dispatchBuffer), binder(binder), glslProgram(glslProgram), shaders(shaders), geometricShader(geometricShader) + { + } // Core resources needed for view transformation & frustum culling. void GetBindingsForViewTransformation( - HgiResourceBindingsDesc * bindingsDesc) const; + HgiResourceBindingsDesc *bindingsDesc) const; // Core resources plus additional resources needed for drawing. void GetBindingsForDrawing( - HgiResourceBindingsDesc * bindingsDesc, - HdStBufferResourceSharedPtr const & tessFactorsBuffer, - bool bindTessFactors) const; + HgiResourceBindingsDesc *bindingsDesc, + HdStBufferResourceSharedPtr const &tessFactorsBuffer, + bool bindTessFactors) const; HdStDispatchBufferSharedPtr dispatchBuffer; - HdSt_ResourceBinder const & binder; + HdSt_ResourceBinder const &binder; HdStGLSLProgramSharedPtr glslProgram; HdStShaderCodeSharedPtrVector shaders; HdSt_GeometricShaderSharedPtr geometricShader; -}; + }; -void -_BindingState::GetBindingsForViewTransformation( - HgiResourceBindingsDesc * bindingsDesc) const -{ + void + _BindingState::GetBindingsForViewTransformation( + HgiResourceBindingsDesc *bindingsDesc) const + { bindingsDesc->debugName = "PipelineDrawBatch.ViewTransformation"; // Bind the constant buffer for the prim transformation and bounds. @@ -1061,21 +1100,23 @@ _BindingState::GetBindingsForViewTransformation( bindingsDesc, constantBar, _tokens->constantPrimvars); // Bind the instance buffers to support instance transformations. - if (instanceIndexBar) { - for (size_t level = 0; level < instancePrimvarBars.size(); ++level) { - binder.GetInstanceBufferArrayBindingDesc( - bindingsDesc, instancePrimvarBars[level], level); - } - binder.GetBufferArrayBindingDesc(bindingsDesc, instanceIndexBar); + if (instanceIndexBar) + { + for (size_t level = 0; level < instancePrimvarBars.size(); ++level) + { + binder.GetInstanceBufferArrayBindingDesc( + bindingsDesc, instancePrimvarBars[level], level); + } + binder.GetBufferArrayBindingDesc(bindingsDesc, instanceIndexBar); } -} - -void -_BindingState::GetBindingsForDrawing( - HgiResourceBindingsDesc * bindingsDesc, - HdStBufferResourceSharedPtr const & tessFactorsBuffer, - bool bindTessFactors) const -{ + } + + void + _BindingState::GetBindingsForDrawing( + HgiResourceBindingsDesc *bindingsDesc, + HdStBufferResourceSharedPtr const &tessFactorsBuffer, + bool bindTessFactors) const + { GetBindingsForViewTransformation(bindingsDesc); bindingsDesc->debugName = "PipelineDrawBatch.Drawing"; @@ -1088,74 +1129,83 @@ _BindingState::GetBindingsForDrawing( binder.GetBufferArrayBindingDesc(bindingsDesc, fvarBar); binder.GetBufferArrayBindingDesc(bindingsDesc, varyingBar); - if (tessFactorsBuffer) { + if (tessFactorsBuffer) + { + binder.GetBufferBindingDesc(bindingsDesc, + HdTokens->tessFactors, + tessFactorsBuffer, + tessFactorsBuffer->GetOffset()); + if (bindTessFactors) + { binder.GetBufferBindingDesc(bindingsDesc, HdTokens->tessFactors, tessFactorsBuffer, tessFactorsBuffer->GetOffset()); - if (bindTessFactors) { - binder.GetBufferBindingDesc(bindingsDesc, - HdTokens->tessFactors, - tessFactorsBuffer, - tessFactorsBuffer->GetOffset()); - HgiBufferBindDesc &tessFactorBuffDesc = bindingsDesc->buffers.back(); - tessFactorBuffDesc.resourceType = HgiBindResourceTypeTessFactors; - } + HgiBufferBindDesc &tessFactorBuffDesc = bindingsDesc->buffers.back(); + tessFactorBuffDesc.resourceType = HgiBindResourceTypeTessFactors; + } } - for (HdStShaderCodeSharedPtr const & shader : shaders) { - HdStBufferArrayRangeSharedPtr shaderBar = - std::static_pointer_cast( - shader->GetShaderData()); - - binder.GetInterleavedBufferArrayBindingDesc( - bindingsDesc, shaderBar, HdTokens->materialParams); - - HdStBindingRequestVector bindingRequests; - shader->AddBindings(&bindingRequests); - for (auto const & req : bindingRequests) { - binder.GetBindingRequestBindingDesc(bindingsDesc, req); - } - HdSt_TextureBinder::GetBindingDescs( - binder, bindingsDesc, shader->GetNamedTextureHandles()); + for (HdStShaderCodeSharedPtr const &shader : shaders) + { + HdStBufferArrayRangeSharedPtr shaderBar = + std::static_pointer_cast( + shader->GetShaderData()); + + binder.GetInterleavedBufferArrayBindingDesc( + bindingsDesc, shaderBar, HdTokens->materialParams); + + HdStBindingRequestVector bindingRequests; + shader->AddBindings(&bindingRequests); + for (auto const &req : bindingRequests) + { + binder.GetBindingRequestBindingDesc(bindingsDesc, req); + } + HdSt_TextureBinder::GetBindingDescs( + binder, bindingsDesc, shader->GetNamedTextureHandles()); } -} + } -HgiVertexBufferDescVector -_GetVertexBuffersForViewTransformation(_BindingState const & state) -{ + HgiVertexBufferDescVector + _GetVertexBuffersForViewTransformation(_BindingState const &state) + { // Bind the dispatchBuffer drawing coordinate resource views HdStBufferArrayRangeSharedPtr const dispatchBar = - state.dispatchBuffer->GetBufferArrayRange(); + state.dispatchBuffer->GetBufferArrayRange(); size_t const dispatchBufferStride = - state.dispatchBuffer->GetCommandNumUints()*sizeof(uint32_t); + state.dispatchBuffer->GetCommandNumUints() * sizeof(uint32_t); HgiVertexAttributeDescVector attrDescVector; - for (auto const & namedResource : dispatchBar->GetResources()) { - HdStBinding const binding = - state.binder.GetBinding(namedResource.first); - HdStBufferResourceSharedPtr const & resource = namedResource.second; - HdTupleType const tupleType = resource->GetTupleType(); - - if (binding.GetType() == HdStBinding::DRAW_INDEX_INSTANCE) { - HgiVertexAttributeDesc attrDesc; - attrDesc.format = - HdStHgiConversions::GetHgiVertexFormat(tupleType.type); - attrDesc.offset = resource->GetOffset(), - attrDesc.shaderBindLocation = binding.GetLocation(); - attrDescVector.push_back(attrDesc); - } else if (binding.GetType() == - HdStBinding::DRAW_INDEX_INSTANCE_ARRAY) { - for (size_t i = 0; i < tupleType.count; ++i) { - HgiVertexAttributeDesc attrDesc; - attrDesc.format = - HdStHgiConversions::GetHgiVertexFormat(tupleType.type); - attrDesc.offset = resource->GetOffset() + i*sizeof(uint32_t); - attrDesc.shaderBindLocation = binding.GetLocation() + i; - attrDescVector.push_back(attrDesc); - } + for (auto const &namedResource : dispatchBar->GetResources()) + { + HdStBinding const binding = + state.binder.GetBinding(namedResource.first); + HdStBufferResourceSharedPtr const &resource = namedResource.second; + HdTupleType const tupleType = resource->GetTupleType(); + + if (binding.GetType() == HdStBinding::DRAW_INDEX_INSTANCE) + { + HgiVertexAttributeDesc attrDesc; + attrDesc.format = + HdStHgiConversions::GetHgiVertexFormat(tupleType.type); + attrDesc.offset = resource->GetOffset(), + attrDesc.shaderBindLocation = binding.GetLocation(); + attrDescVector.push_back(attrDesc); + } + else if (binding.GetType() == + HdStBinding::DRAW_INDEX_INSTANCE_ARRAY) + { + for (size_t i = 0; i < tupleType.count; ++i) + { + HgiVertexAttributeDesc attrDesc; + attrDesc.format = + HdStHgiConversions::GetHgiVertexFormat(tupleType.type); + attrDesc.offset = resource->GetOffset() + i * sizeof(uint32_t); + attrDesc.shaderBindLocation = binding.GetLocation() + i; + attrDescVector.push_back(attrDesc); } + } } // All drawing coordinate resources are sourced from the same buffer. @@ -1166,86 +1216,93 @@ _GetVertexBuffersForViewTransformation(_BindingState const & state) bufferDesc.vertexStride = dispatchBufferStride; return HgiVertexBufferDescVector{bufferDesc}; -} + } -HgiVertexBufferDescVector -_GetVertexBuffersForDrawing(_BindingState const & state) -{ + HgiVertexBufferDescVector + _GetVertexBuffersForDrawing(_BindingState const &state) + { // Bind the vertexBar resources HgiVertexBufferDescVector vertexBufferDescVector = _GetVertexBuffersForViewTransformation(state); - for (auto const & namedResource : state.vertexBar->GetResources()) { - HdStBinding const binding = - state.binder.GetBinding(namedResource.first); - HdStBufferResourceSharedPtr const & resource = namedResource.second; - HdTupleType const tupleType = resource->GetTupleType(); - - if (binding.GetType() == HdStBinding::VERTEX_ATTR) { - HgiVertexAttributeDesc attrDesc; - attrDesc.format = - HdStHgiConversions::GetHgiVertexFormat(tupleType.type); - attrDesc.offset = resource->GetOffset(), - attrDesc.shaderBindLocation = binding.GetLocation(); - - // Each vertexBar resource is sourced from a distinct buffer. - HgiVertexBufferDesc bufferDesc; - bufferDesc.bindingIndex = vertexBufferDescVector.size(); - bufferDesc.vertexAttributes = {attrDesc}; - if (state.geometricShader->GetUseMetalTessellation()) { - bufferDesc.vertexStepFunction = - HgiVertexBufferStepFunctionPerPatchControlPoint; - } else { - bufferDesc.vertexStepFunction = - HgiVertexBufferStepFunctionPerVertex; - } - bufferDesc.vertexStride = HdDataSizeOfTupleType(tupleType); - vertexBufferDescVector.push_back(bufferDesc); + for (auto const &namedResource : state.vertexBar->GetResources()) + { + HdStBinding const binding = + state.binder.GetBinding(namedResource.first); + HdStBufferResourceSharedPtr const &resource = namedResource.second; + HdTupleType const tupleType = resource->GetTupleType(); + + if (binding.GetType() == HdStBinding::VERTEX_ATTR) + { + HgiVertexAttributeDesc attrDesc; + attrDesc.format = + HdStHgiConversions::GetHgiVertexFormat(tupleType.type); + attrDesc.offset = resource->GetOffset(), + attrDesc.shaderBindLocation = binding.GetLocation(); + + // Each vertexBar resource is sourced from a distinct buffer. + HgiVertexBufferDesc bufferDesc; + bufferDesc.bindingIndex = vertexBufferDescVector.size(); + bufferDesc.vertexAttributes = {attrDesc}; + if (state.geometricShader->GetUseMetalTessellation()) + { + bufferDesc.vertexStepFunction = + HgiVertexBufferStepFunctionPerPatchControlPoint; } + else + { + bufferDesc.vertexStepFunction = + HgiVertexBufferStepFunctionPerVertex; + } + bufferDesc.vertexStride = HdDataSizeOfTupleType(tupleType); + vertexBufferDescVector.push_back(bufferDesc); + } } return vertexBufferDescVector; -} + } -uint32_t -_GetVertexBufferBindingsForViewTransformation( - HgiVertexBufferBindingVector *bindings, - _BindingState const & state) -{ + uint32_t + _GetVertexBufferBindingsForViewTransformation( + HgiVertexBufferBindingVector *bindings, + _BindingState const &state) + { // Bind the dispatchBuffer drawing coordinate resource views HdStBufferResourceSharedPtr resource = - state.dispatchBuffer->GetEntireResource(); - + state.dispatchBuffer->GetEntireResource(); + bindings->emplace_back(resource->GetHandle(), - (uint32_t)resource->GetOffset(), - 0); + (uint32_t)resource->GetOffset(), + 0); return static_cast(bindings->size()); -} + } -uint32_t -_GetVertexBufferBindingsForDrawing( - HgiVertexBufferBindingVector *bindings, - _BindingState const & state) -{ + uint32_t + _GetVertexBufferBindingsForDrawing( + HgiVertexBufferBindingVector *bindings, + _BindingState const &state) + { uint32_t nextBinding = // continue binding subsequent locations _GetVertexBufferBindingsForViewTransformation(bindings, state); - for (auto const & namedResource : state.vertexBar->GetResources()) { - HdStBinding const binding = - state.binder.GetBinding(namedResource.first); - HdStBufferResourceSharedPtr const & resource = namedResource.second; - - if (binding.GetType() == HdStBinding::VERTEX_ATTR) { - bindings->emplace_back(resource->GetHandle(), - static_cast(resource->GetOffset()), - nextBinding); - nextBinding++; - } + for (auto const &namedResource : state.vertexBar->GetResources()) + { + HdStBinding const binding = + state.binder.GetBinding(namedResource.first); + HdStBufferResourceSharedPtr const &resource = namedResource.second; + + if (binding.GetType() == HdStBinding::VERTEX_ATTR) + { + bindings->emplace_back(resource->GetHandle(), + static_cast(resource->GetOffset()), + nextBinding); + nextBinding++; + } } return nextBinding; -} + } } // annonymous namespace @@ -1253,751 +1310,780 @@ _GetVertexBufferBindingsForDrawing( // GPU Drawing //////////////////////////////////////////////////////////// -static -HgiGraphicsPipelineSharedPtr +static HgiGraphicsPipelineSharedPtr _GetDrawPipeline( - HdStRenderPassStateSharedPtr const & renderPassState, - HdStResourceRegistrySharedPtr const & resourceRegistry, - _BindingState const & state) + HdStRenderPassStateSharedPtr const &renderPassState, + HdStResourceRegistrySharedPtr const &resourceRegistry, + _BindingState const &state) { - // Drawing pipeline is compatible as long as the shader and - // pipeline state are the same. - HgiShaderProgramHandle const & programHandle = - state.glslProgram->GetProgram(); + // Drawing pipeline is compatible as long as the shader and + // pipeline state are the same. + HgiShaderProgramHandle const &programHandle = + state.glslProgram->GetProgram(); - static const uint64_t salt = ArchHash64(__FUNCTION__, sizeof(__FUNCTION__)); - uint64_t hash = salt; - hash = TfHash::Combine(hash, programHandle.Get()); - hash = TfHash::Combine(hash, renderPassState->GetGraphicsPipelineHash()); + static const uint64_t salt = ArchHash64(__FUNCTION__, sizeof(__FUNCTION__)); + uint64_t hash = salt; + hash = TfHash::Combine(hash, programHandle.Get()); + hash = TfHash::Combine(hash, renderPassState->GetGraphicsPipelineHash()); - HdInstance pipelineInstance = - resourceRegistry->RegisterGraphicsPipeline(hash); + HdInstance pipelineInstance = + resourceRegistry->RegisterGraphicsPipeline(hash); - if (pipelineInstance.IsFirstInstance()) { - HgiGraphicsPipelineDesc pipeDesc; + if (pipelineInstance.IsFirstInstance()) + { + HgiGraphicsPipelineDesc pipeDesc; - renderPassState->InitGraphicsPipelineDesc(&pipeDesc, - state.geometricShader); + renderPassState->InitGraphicsPipelineDesc(&pipeDesc, + state.geometricShader); - pipeDesc.shaderProgram = state.glslProgram->GetProgram(); - pipeDesc.vertexBuffers = _GetVertexBuffersForDrawing(state); + pipeDesc.shaderProgram = state.glslProgram->GetProgram(); + pipeDesc.vertexBuffers = _GetVertexBuffersForDrawing(state); - Hgi* hgi = resourceRegistry->GetHgi(); - HgiGraphicsPipelineHandle pso = hgi->CreateGraphicsPipeline(pipeDesc); + Hgi *hgi = resourceRegistry->GetHgi(); + HgiGraphicsPipelineHandle pso = hgi->CreateGraphicsPipeline(pipeDesc); - pipelineInstance.SetValue( - std::make_shared(pso)); - } + pipelineInstance.SetValue( + std::make_shared(pso)); + } - return pipelineInstance.GetValue(); + return pipelineInstance.GetValue(); } -static -HgiGraphicsPipelineSharedPtr +static HgiGraphicsPipelineSharedPtr _GetPTCSPipeline( - HdStRenderPassStateSharedPtr const & renderPassState, - HdStResourceRegistrySharedPtr const & resourceRegistry, - _BindingState const & state) -{ - // PTCS pipeline is compatible as long as the shader and - // pipeline state are the same. - HgiShaderProgramHandle const & programHandle = - state.glslProgram->GetProgram(); - - static const uint64_t salt = ArchHash64(__FUNCTION__, sizeof(__FUNCTION__)); - uint64_t hash = salt; - hash = TfHash::Combine(hash, programHandle.Get()); - hash = TfHash::Combine(hash, renderPassState->GetGraphicsPipelineHash()); - - HdInstance pipelineInstance = - resourceRegistry->RegisterGraphicsPipeline(hash); - - if (pipelineInstance.IsFirstInstance()) { - HgiGraphicsPipelineDesc pipeDesc; - - renderPassState->InitGraphicsPipelineDesc(&pipeDesc, - state.geometricShader); - - pipeDesc.rasterizationState.rasterizerEnabled = false; - pipeDesc.multiSampleState.sampleCount = HgiSampleCount1; - pipeDesc.multiSampleState.alphaToCoverageEnable = false; - pipeDesc.depthState.depthWriteEnabled = false; - pipeDesc.depthState.depthTestEnabled = false; - pipeDesc.depthState.stencilTestEnabled = false; - pipeDesc.primitiveType = HgiPrimitiveTypePatchList; - pipeDesc.multiSampleState.multiSampleEnable = false; - - pipeDesc.shaderProgram = state.glslProgram->GetProgram(); - pipeDesc.vertexBuffers = _GetVertexBuffersForDrawing(state); - pipeDesc.tessellationState.tessFactorMode = - HgiTessellationState::TessControl; - - Hgi* hgi = resourceRegistry->GetHgi(); - HgiGraphicsPipelineHandle pso = hgi->CreateGraphicsPipeline(pipeDesc); - - pipelineInstance.SetValue( - std::make_shared(pso)); - } - - return pipelineInstance.GetValue(); -} - -void -HdSt_PipelineDrawBatch::ExecuteDraw( - HgiGraphicsCmds * gfxCmds, - HdStRenderPassStateSharedPtr const & renderPassState, - HdStResourceRegistrySharedPtr const & resourceRegistry) + HdStRenderPassStateSharedPtr const &renderPassState, + HdStResourceRegistrySharedPtr const &resourceRegistry, + _BindingState const &state) { - TRACE_FUNCTION(); - - if (!TF_VERIFY(!_drawItemInstances.empty())) return; - - if (!TF_VERIFY(_dispatchBuffer)) return; - - if (_HasNothingToDraw()) return; + // PTCS pipeline is compatible as long as the shader and + // pipeline state are the same. + HgiShaderProgramHandle const &programHandle = + state.glslProgram->GetProgram(); + + static const uint64_t salt = ArchHash64(__FUNCTION__, sizeof(__FUNCTION__)); + uint64_t hash = salt; + hash = TfHash::Combine(hash, programHandle.Get()); + hash = TfHash::Combine(hash, renderPassState->GetGraphicsPipelineHash()); + + HdInstance pipelineInstance = + resourceRegistry->RegisterGraphicsPipeline(hash); + + if (pipelineInstance.IsFirstInstance()) + { + HgiGraphicsPipelineDesc pipeDesc; + + renderPassState->InitGraphicsPipelineDesc(&pipeDesc, + state.geometricShader); + + pipeDesc.rasterizationState.rasterizerEnabled = false; + pipeDesc.multiSampleState.sampleCount = HgiSampleCount1; + pipeDesc.multiSampleState.alphaToCoverageEnable = false; + pipeDesc.depthState.depthWriteEnabled = false; + pipeDesc.depthState.depthTestEnabled = false; + pipeDesc.depthState.stencilTestEnabled = false; + pipeDesc.primitiveType = HgiPrimitiveTypePatchList; + pipeDesc.multiSampleState.multiSampleEnable = false; + + pipeDesc.shaderProgram = state.glslProgram->GetProgram(); + pipeDesc.vertexBuffers = _GetVertexBuffersForDrawing(state); + pipeDesc.tessellationState.tessFactorMode = + HgiTessellationState::TessControl; Hgi *hgi = resourceRegistry->GetHgi(); - HgiCapabilities const *capabilities = hgi->GetCapabilities(); + HgiGraphicsPipelineHandle pso = hgi->CreateGraphicsPipeline(pipeDesc); - if (_tessFactorsBuffer) { - // Metal tessellation tessFactors are computed by PTCS. - _ExecutePTCS(gfxCmds, renderPassState, resourceRegistry); - - // Finish computing tessFactors before drawing. - gfxCmds->InsertMemoryBarrier(HgiMemoryBarrierAll); - } + pipelineInstance.SetValue( + std::make_shared(pso)); + } - // - // If an indirect command buffer was created in the Prepare phase then - // execute it here. Otherwise render with the normal graphicsCmd path. - // - if (_indirectCommands) { - HgiIndirectCommandEncoder *encoder = hgi->GetIndirectCommandEncoder(); - encoder->ExecuteDraw(gfxCmds, _indirectCommands.get()); + return pipelineInstance.GetValue(); +} - hgi->DestroyResourceBindings(&(_indirectCommands->resourceBindings)); - _indirectCommands.reset(); - } - else { - _DrawingProgram & program = _GetDrawingProgram(renderPassState, - resourceRegistry); - if (!TF_VERIFY(program.IsValid())) return; - - _BindingState state( - _drawItemInstances.front()->GetDrawItem(), - _dispatchBuffer, - program.GetBinder(), - program.GetGLSLProgram(), - program.GetComposedShaders(), - program.GetGeometricShader()); - - HgiGraphicsPipelineSharedPtr pso = - _GetDrawPipeline( - renderPassState, - resourceRegistry, - state); - - HgiGraphicsPipelineHandle psoHandle = *pso.get(); - gfxCmds->BindPipeline(psoHandle); - - HgiResourceBindingsDesc bindingsDesc; - state.GetBindingsForDrawing(&bindingsDesc, - _tessFactorsBuffer, /*bindTessFactors=*/true); - - HgiResourceBindingsHandle resourceBindings = - hgi->CreateResourceBindings(bindingsDesc); - gfxCmds->BindResources(resourceBindings); - - HgiVertexBufferBindingVector bindings; - _GetVertexBufferBindingsForDrawing(&bindings, state); - gfxCmds->BindVertexBuffers(bindings); - - // Drawing can be either direct or indirect. For either case, - // the drawing batch and drawing program are prepared to resolve - // drawing coordinate state indirectly, i.e. from buffer data. - bool const drawIndirect = - capabilities->IsSet(HgiDeviceCapabilitiesBitsMultiDrawIndirect); - - if (drawIndirect) { - _ExecuteDrawIndirect(gfxCmds, state.indexBar); - } else { - _ExecuteDrawImmediate(gfxCmds, state.indexBar); - } +void HdSt_PipelineDrawBatch::ExecuteDraw( + HgiGraphicsCmds *gfxCmds, + HdStRenderPassStateSharedPtr const &renderPassState, + HdStResourceRegistrySharedPtr const &resourceRegistry) +{ + TRACE_FUNCTION(); - hgi->DestroyResourceBindings(&resourceBindings); - } + if (!TF_VERIFY(!_drawItemInstances.empty())) + return; - HD_PERF_COUNTER_INCR(HdPerfTokens->drawCalls); - HD_PERF_COUNTER_ADD(HdTokens->itemsDrawn, _numVisibleItems); -} + if (!TF_VERIFY(_dispatchBuffer)) + return; -void -HdSt_PipelineDrawBatch::_ExecuteDrawIndirect( - HgiGraphicsCmds * gfxCmds, - HdStBufferArrayRangeSharedPtr const & indexBar) -{ - TRACE_FUNCTION(); - - HdStBufferResourceSharedPtr paramBuffer = _dispatchBuffer-> - GetBufferArrayRange()->GetResource(HdTokens->drawDispatch); - if (!TF_VERIFY(paramBuffer)) return; - - if (!_useDrawIndexed) { - gfxCmds->DrawIndirect( - paramBuffer->GetHandle(), - paramBuffer->GetOffset(), - _dispatchBuffer->GetCount(), - paramBuffer->GetStride()); - } else { - HdStBufferResourceSharedPtr indexBuffer = - indexBar->GetResource(HdTokens->indices); - if (!TF_VERIFY(indexBuffer)) return; - - gfxCmds->DrawIndexedIndirect( - indexBuffer->GetHandle(), - paramBuffer->GetHandle(), - paramBuffer->GetOffset(), - _dispatchBuffer->GetCount(), - paramBuffer->GetStride(), - _drawCommandBuffer, - _patchBaseVertexByteOffset); - } -} + if (_HasNothingToDraw()) + return; -void -HdSt_PipelineDrawBatch::_ExecuteDrawImmediate( - HgiGraphicsCmds * gfxCmds, - HdStBufferArrayRangeSharedPtr const & indexBar) -{ - TRACE_FUNCTION(); - - uint32_t const drawCount = _dispatchBuffer->GetCount(); - uint32_t const strideUInt32 = _dispatchBuffer->GetCommandNumUints(); - - if (!_useDrawIndexed) { - for (uint32_t i = 0; i < drawCount; ++i) { - _DrawNonIndexedCommand const * cmd = - reinterpret_cast<_DrawNonIndexedCommand*>( - &_drawCommandBuffer[i * strideUInt32]); - - if (cmd->common.count && cmd->common.instanceCount) { - gfxCmds->Draw( - cmd->common.count, - cmd->common.baseVertex, - cmd->common.instanceCount, - cmd->common.baseInstance); - } - } - } else { - HdStBufferResourceSharedPtr indexBuffer = - indexBar->GetResource(HdTokens->indices); - if (!TF_VERIFY(indexBuffer)) return; - - bool const useMetalTessellation = - _drawItemInstances[0]->GetDrawItem()-> - GetGeometricShader()->GetUseMetalTessellation(); - - for (uint32_t i = 0; i < drawCount; ++i) { - _DrawIndexedCommand const * cmd = - reinterpret_cast<_DrawIndexedCommand*>( - &_drawCommandBuffer[i * strideUInt32]); - - uint32_t const indexBufferByteOffset = - static_cast(cmd->common.baseIndex * sizeof(uint32_t)); - - if (cmd->common.count && cmd->common.instanceCount) { - if (useMetalTessellation) { - gfxCmds->DrawIndexed( - indexBuffer->GetHandle(), - cmd->metalPatch.patchCount, - indexBufferByteOffset, - cmd->metalPatch.baseVertex, - cmd->metalPatch.instanceCount, - cmd->metalPatch.baseInstance); - } else { - gfxCmds->DrawIndexed( - indexBuffer->GetHandle(), - cmd->common.count, - indexBufferByteOffset, - cmd->common.baseVertex, - cmd->common.instanceCount, - cmd->common.baseInstance); - } - } - } - } -} + Hgi *hgi = resourceRegistry->GetHgi(); + HgiCapabilities const *capabilities = hgi->GetCapabilities(); -//////////////////////////////////////////////////////////// -// GPU Frustum Culling -//////////////////////////////////////////////////////////// + if (_tessFactorsBuffer) + { + // Metal tessellation tessFactors are computed by PTCS. + _ExecutePTCS(gfxCmds, renderPassState, resourceRegistry); -static -HgiComputePipelineSharedPtr -_GetCullPipeline( - HdStResourceRegistrySharedPtr const & resourceRegistry, - _BindingState const & state, - size_t byteSizeUniforms) -{ - // Culling pipeline is compatible as long as the shader is the same. - HgiShaderProgramHandle const & programHandle = - state.glslProgram->GetProgram(); - uint64_t const hash = reinterpret_cast(programHandle.Get()); - - HdInstance pipelineInstance = - resourceRegistry->RegisterComputePipeline(hash); - - if (pipelineInstance.IsFirstInstance()) { - // Create a points primitive, vertex shader only pipeline that uses - // a uniform block data for the 'cullParams' in the shader. - HgiComputePipelineDesc pipeDesc; - pipeDesc.debugName = "FrustumCulling"; - pipeDesc.shaderProgram = programHandle; - pipeDesc.shaderConstantsDesc.byteSize = byteSizeUniforms; - - Hgi* hgi = resourceRegistry->GetHgi(); - HgiComputePipelineSharedPtr pipe = - std::make_shared( - hgi->CreateComputePipeline(pipeDesc)); - - pipelineInstance.SetValue(pipe); - } + // Finish computing tessFactors before drawing. + gfxCmds->InsertMemoryBarrier(HgiMemoryBarrierAll); + } - return pipelineInstance.GetValue(); -} + // + // If an indirect command buffer was created in the Prepare phase then + // execute it here. Otherwise render with the normal graphicsCmd path. + // + if (_indirectCommands) + { + HgiIndirectCommandEncoder *encoder = hgi->GetIndirectCommandEncoder(); + encoder->ExecuteDraw(gfxCmds, _indirectCommands.get()); -void -HdSt_PipelineDrawBatch::_PrepareIndirectCommandBuffer( - HdStRenderPassStateSharedPtr const & renderPassState, - HdStResourceRegistrySharedPtr const & resourceRegistry) -{ - Hgi *hgi = resourceRegistry->GetHgi(); - _DrawingProgram & program = _GetDrawingProgram(renderPassState, - resourceRegistry); - if (!TF_VERIFY(program.IsValid())) return; + hgi->DestroyResourceBindings(&(_indirectCommands->resourceBindings)); + _indirectCommands.reset(); + } + else + { + _DrawingProgram &program = _GetDrawingProgram(renderPassState, + resourceRegistry); + if (!TF_VERIFY(program.IsValid())) + return; _BindingState state( - _drawItemInstances.front()->GetDrawItem(), - _dispatchBuffer, - program.GetBinder(), - program.GetGLSLProgram(), - program.GetComposedShaders(), - program.GetGeometricShader()); + _drawItemInstances.front()->GetDrawItem(), + _dispatchBuffer, + program.GetBinder(), + program.GetGLSLProgram(), + program.GetComposedShaders(), + program.GetGeometricShader()); HgiGraphicsPipelineSharedPtr pso = _GetDrawPipeline( renderPassState, resourceRegistry, state); - + HgiGraphicsPipelineHandle psoHandle = *pso.get(); + gfxCmds->BindPipeline(psoHandle); HgiResourceBindingsDesc bindingsDesc; state.GetBindingsForDrawing(&bindingsDesc, - _tessFactorsBuffer, /*bindTessFactors=*/true); + _tessFactorsBuffer, /*bindTessFactors=*/true); HgiResourceBindingsHandle resourceBindings = - hgi->CreateResourceBindings(bindingsDesc); - - HgiVertexBufferBindingVector vertexBindings; - _GetVertexBufferBindingsForDrawing(&vertexBindings, state); - - HdStBufferResourceSharedPtr paramBuffer = _dispatchBuffer-> - GetBufferArrayRange()->GetResource(HdTokens->drawDispatch); - - HgiIndirectCommandEncoder *encoder = hgi->GetIndirectCommandEncoder(); - HgiComputeCmds *computeCmds = - resourceRegistry->GetGlobalComputeCmds(HgiComputeDispatchConcurrent); - - if (!_useDrawIndexed) { - _indirectCommands = encoder->EncodeDraw( - computeCmds, - psoHandle, - resourceBindings, - vertexBindings, - paramBuffer->GetHandle(), - paramBuffer->GetOffset(), - _dispatchBuffer->GetCount(), - paramBuffer->GetStride()); - } else { - HdStBufferResourceSharedPtr indexBuffer = - state.indexBar->GetResource(HdTokens->indices); - - _indirectCommands = encoder->EncodeDrawIndexed( - computeCmds, - psoHandle, - resourceBindings, - vertexBindings, - indexBuffer->GetHandle(), - paramBuffer->GetHandle(), - paramBuffer->GetOffset(), - _dispatchBuffer->GetCount(), - paramBuffer->GetStride(), - _patchBaseVertexByteOffset); - } -} - -void -HdSt_PipelineDrawBatch::_ExecuteFrustumCull( - bool const updateBufferData, - HdStRenderPassStateSharedPtr const & renderPassState, - HdStResourceRegistrySharedPtr const & resourceRegistry) -{ - TRACE_FUNCTION(); - - // Disable GPU culling when instancing enabled and - // not using instance culling. - if (_useInstancing && !_useInstanceCulling) return; + hgi->CreateResourceBindings(bindingsDesc); + gfxCmds->BindResources(resourceBindings); - // Bypass freezeCulling if the command buffer is dirty. - bool const freezeCulling = TfDebug::IsEnabled(HD_FREEZE_CULL_FRUSTUM); - if (freezeCulling && !updateBufferData) return; - - if (updateBufferData) { - _dispatchBufferCullInput->CopyData(_drawCommandBuffer); - } - - _CreateCullingProgram(resourceRegistry); - if (!TF_VERIFY(_cullingProgram.IsValid())) return; - - struct Uniforms { - GfMatrix4f cullMatrix; - GfVec2f drawRangeNDC; - uint32_t drawCommandNumUints; - }; - - // We perform frustum culling in a compute shader, stomping the - // instanceCount of each drawing command in the dispatch buffer to 0 for - // primitives that are culled, skipping over other elements. - - _BindingState state( - _drawItemInstances.front()->GetDrawItem(), - _dispatchBufferCullInput, - _cullingProgram.GetBinder(), - _cullingProgram.GetGLSLProgram(), - _cullingProgram.GetComposedShaders(), - _cullingProgram.GetGeometricShader()); - - Hgi * hgi = resourceRegistry->GetHgi(); - - HgiComputePipelineSharedPtr const & pso = - _GetCullPipeline(resourceRegistry, - state, - sizeof(Uniforms)); - HgiComputePipelineHandle psoHandle = *pso.get(); + HgiVertexBufferBindingVector bindings; + _GetVertexBufferBindingsForDrawing(&bindings, state); + gfxCmds->BindVertexBuffers(bindings); - HgiComputeCmds* computeCmds = - resourceRegistry->GetGlobalComputeCmds(HgiComputeDispatchConcurrent); - computeCmds->PushDebugGroup("FrustumCulling Cmds"); + // Drawing can be either direct or indirect. For either case, + // the drawing batch and drawing program are prepared to resolve + // drawing coordinate state indirectly, i.e. from buffer data. + bool const drawIndirect = + capabilities->IsSet(HgiDeviceCapabilitiesBitsMultiDrawIndirect); - HgiResourceBindingsDesc bindingsDesc; - state.GetBindingsForViewTransformation(&bindingsDesc); - - if (IsEnabledGPUCountVisibleInstances()) { - _BeginGPUCountVisibleInstances(resourceRegistry); - state.binder.GetBufferBindingDesc( - &bindingsDesc, - _tokens->drawIndirectResult, - _resultBuffer, - _resultBuffer->GetOffset()); - + if (drawIndirect) + { + _ExecuteDrawIndirect(gfxCmds, state.indexBar); } - - // bind destination buffer - // (using entire buffer bind to start from offset=0) - state.binder.GetBufferBindingDesc( - &bindingsDesc, - _tokens->dispatchBuffer, - _dispatchBuffer->GetEntireResource(), - _dispatchBuffer->GetEntireResource()->GetOffset()); - - // bind the read-only copy of the destination buffer for input. - state.binder.GetBufferBindingDesc( - &bindingsDesc, - _tokens->drawCullInput, - _dispatchBufferCullInput->GetEntireResource(), - _dispatchBufferCullInput->GetEntireResource()->GetOffset()); - - // HdSt_ResourceBinder::GetBufferBindingDesc() sets state usage - // to all graphics pipeline stages. Instead we have to set all the - // buffer stage usage to Compute. - for (HgiBufferBindDesc & bufDesc : bindingsDesc.buffers) { - bufDesc.stageUsage = HgiShaderStageCompute; - bufDesc.writable = true; + else + { + _ExecuteDrawImmediate(gfxCmds, state.indexBar); } - HgiResourceBindingsHandle resourceBindings = - hgi->CreateResourceBindings(bindingsDesc); + hgi->DestroyResourceBindings(&resourceBindings); + } - computeCmds->BindResources(resourceBindings); - computeCmds->BindPipeline(psoHandle); + HD_PERF_COUNTER_INCR(HdPerfTokens->drawCalls); + HD_PERF_COUNTER_ADD(HdTokens->itemsDrawn, _numVisibleItems); +} - GfMatrix4f const &cullMatrix = GfMatrix4f(renderPassState->GetCullMatrix()); - GfVec2f const &drawRangeNdc = renderPassState->GetDrawingRangeNDC(); +void HdSt_PipelineDrawBatch::_ExecuteDrawIndirect( + HgiGraphicsCmds *gfxCmds, + HdStBufferArrayRangeSharedPtr const &indexBar) +{ + TRACE_FUNCTION(); + + HdStBufferResourceSharedPtr paramBuffer = _dispatchBuffer->GetBufferArrayRange()->GetResource(HdTokens->drawDispatch); + if (!TF_VERIFY(paramBuffer)) + return; + + if (!_useDrawIndexed) + { + gfxCmds->DrawIndirect( + paramBuffer->GetHandle(), + paramBuffer->GetOffset(), + _dispatchBuffer->GetCount(), + paramBuffer->GetStride()); + } + else + { + HdStBufferResourceSharedPtr indexBuffer = + indexBar->GetResource(HdTokens->indices); + if (!TF_VERIFY(indexBuffer)) + return; + + gfxCmds->DrawIndexedIndirect( + indexBuffer->GetHandle(), + paramBuffer->GetHandle(), + paramBuffer->GetOffset(), + _dispatchBuffer->GetCount(), + paramBuffer->GetStride(), + _drawCommandBuffer, + _patchBaseVertexByteOffset); + } +} - HdStBufferResourceSharedPtr paramBuffer = _dispatchBuffer-> - GetBufferArrayRange()->GetResource(HdTokens->drawDispatch); +void HdSt_PipelineDrawBatch::_ExecuteDrawImmediate( + HgiGraphicsCmds *gfxCmds, + HdStBufferArrayRangeSharedPtr const &indexBar) +{ + TRACE_FUNCTION(); - // set instanced cull parameters - Uniforms cullParams; - cullParams.cullMatrix = cullMatrix; - cullParams.drawRangeNDC = drawRangeNdc; - cullParams.drawCommandNumUints = _dispatchBuffer->GetCommandNumUints(); + uint32_t const drawCount = _dispatchBuffer->GetCount(); + uint32_t const strideUInt32 = _dispatchBuffer->GetCommandNumUints(); - computeCmds->SetConstantValues( - psoHandle, 0, - sizeof(Uniforms), &cullParams); + if (!_useDrawIndexed) + { + for (uint32_t i = 0; i < drawCount; ++i) + { + _DrawNonIndexedCommand const *cmd = + reinterpret_cast<_DrawNonIndexedCommand *>( + &_drawCommandBuffer[i * strideUInt32]); + + if (cmd->common.count && cmd->common.instanceCount) + { + gfxCmds->Draw( + cmd->common.count, + cmd->common.baseVertex, + cmd->common.instanceCount, + cmd->common.baseInstance); + } + } + } + else + { + HdStBufferResourceSharedPtr indexBuffer = + indexBar->GetResource(HdTokens->indices); + if (!TF_VERIFY(indexBuffer)) + return; - int const inputCount = _dispatchBufferCullInput->GetCount(); - computeCmds->Dispatch(inputCount, 1); - computeCmds->PopDebugGroup(); + bool const useMetalTessellation = + _drawItemInstances[0]->GetDrawItem()->GetGeometricShader()->GetUseMetalTessellation(); - if (IsEnabledGPUCountVisibleInstances()) { - _EndGPUCountVisibleInstances(resourceRegistry, &_numVisibleItems); + for (uint32_t i = 0; i < drawCount; ++i) + { + _DrawIndexedCommand const *cmd = + reinterpret_cast<_DrawIndexedCommand *>( + &_drawCommandBuffer[i * strideUInt32]); + + uint32_t const indexBufferByteOffset = + static_cast(cmd->common.baseIndex * sizeof(uint32_t)); + + if (cmd->common.count && cmd->common.instanceCount) + { + if (useMetalTessellation) + { + gfxCmds->DrawIndexed( + indexBuffer->GetHandle(), + cmd->metalPatch.patchCount, + indexBufferByteOffset, + cmd->metalPatch.baseVertex, + cmd->metalPatch.instanceCount, + cmd->metalPatch.baseInstance); + } + else + { + gfxCmds->DrawIndexed( + indexBuffer->GetHandle(), + cmd->common.count, + indexBufferByteOffset, + cmd->common.baseVertex, + cmd->common.instanceCount, + cmd->common.baseInstance); + } + } } - - hgi->DestroyResourceBindings(&resourceBindings); + } } +//////////////////////////////////////////////////////////// +// GPU Frustum Culling +//////////////////////////////////////////////////////////// -void -HdSt_PipelineDrawBatch::_ExecutePTCS( - HgiGraphicsCmds *ptcsGfxCmds, - HdStRenderPassStateSharedPtr const & renderPassState, - HdStResourceRegistrySharedPtr const & resourceRegistry) +static HgiComputePipelineSharedPtr +_GetCullPipeline( + HdStResourceRegistrySharedPtr const &resourceRegistry, + _BindingState const &state, + size_t byteSizeUniforms) { - TRACE_FUNCTION(); - - if (!TF_VERIFY(!_drawItemInstances.empty())) return; - - if (!TF_VERIFY(_dispatchBuffer)) return; + // Culling pipeline is compatible as long as the shader is the same. + HgiShaderProgramHandle const &programHandle = + state.glslProgram->GetProgram(); + uint64_t const hash = reinterpret_cast(programHandle.Get()); + + HdInstance pipelineInstance = + resourceRegistry->RegisterComputePipeline(hash); + + if (pipelineInstance.IsFirstInstance()) + { + // Create a points primitive, vertex shader only pipeline that uses + // a uniform block data for the 'cullParams' in the shader. + HgiComputePipelineDesc pipeDesc; + pipeDesc.debugName = "FrustumCulling"; + pipeDesc.shaderProgram = programHandle; + pipeDesc.shaderConstantsDesc.byteSize = byteSizeUniforms; - if (_HasNothingToDraw()) return; - - HgiCapabilities const *capabilities = - resourceRegistry->GetHgi()->GetCapabilities(); - - // Drawing can be either direct or indirect. For either case, - // the drawing batch and drawing program are prepared to resolve - // drawing coordinate state indirectly, i.e. from buffer data. - bool const drawIndirect = - capabilities->IsSet(HgiDeviceCapabilitiesBitsMultiDrawIndirect); - _DrawingProgram & program = _GetDrawingProgram(renderPassState, - resourceRegistry); - if (!TF_VERIFY(program.IsValid())) return; - - _BindingState state( - _drawItemInstances.front()->GetDrawItem(), - _dispatchBuffer, - program.GetBinder(), - program.GetGLSLProgram(), - program.GetComposedShaders(), - program.GetGeometricShader()); - - Hgi * hgi = resourceRegistry->GetHgi(); - - HgiGraphicsPipelineSharedPtr const & psoTess = - _GetPTCSPipeline(renderPassState, - resourceRegistry, - state); - - HgiGraphicsPipelineHandle psoTessHandle = *psoTess.get(); - ptcsGfxCmds->BindPipeline(psoTessHandle); - - HgiResourceBindingsDesc bindingsDesc; - state.GetBindingsForDrawing(&bindingsDesc, - _tessFactorsBuffer, /*bindTessFactors=*/false); + Hgi *hgi = resourceRegistry->GetHgi(); + HgiComputePipelineSharedPtr pipe = + std::make_shared( + hgi->CreateComputePipeline(pipeDesc)); - HgiResourceBindingsHandle resourceBindings = - hgi->CreateResourceBindings(bindingsDesc); - ptcsGfxCmds->BindResources(resourceBindings); + pipelineInstance.SetValue(pipe); + } - HgiVertexBufferBindingVector bindings; - _GetVertexBufferBindingsForDrawing(&bindings, state); - ptcsGfxCmds->BindVertexBuffers(bindings); + return pipelineInstance.GetValue(); +} - if (drawIndirect) { - _ExecuteDrawIndirect(ptcsGfxCmds, state.indexBar); - } else { - _ExecuteDrawImmediate(ptcsGfxCmds, state.indexBar); - } +void HdSt_PipelineDrawBatch::_PrepareIndirectCommandBuffer( + HdStRenderPassStateSharedPtr const &renderPassState, + HdStResourceRegistrySharedPtr const &resourceRegistry) +{ + Hgi *hgi = resourceRegistry->GetHgi(); + _DrawingProgram &program = _GetDrawingProgram(renderPassState, + resourceRegistry); + if (!TF_VERIFY(program.IsValid())) + return; + + _BindingState state( + _drawItemInstances.front()->GetDrawItem(), + _dispatchBuffer, + program.GetBinder(), + program.GetGLSLProgram(), + program.GetComposedShaders(), + program.GetGeometricShader()); + + HgiGraphicsPipelineSharedPtr pso = + _GetDrawPipeline( + renderPassState, + resourceRegistry, + state); + + HgiGraphicsPipelineHandle psoHandle = *pso.get(); + + HgiResourceBindingsDesc bindingsDesc; + state.GetBindingsForDrawing(&bindingsDesc, + _tessFactorsBuffer, /*bindTessFactors=*/true); + + HgiResourceBindingsHandle resourceBindings = + hgi->CreateResourceBindings(bindingsDesc); + + HgiVertexBufferBindingVector vertexBindings; + _GetVertexBufferBindingsForDrawing(&vertexBindings, state); + + HdStBufferResourceSharedPtr paramBuffer = _dispatchBuffer->GetBufferArrayRange()->GetResource(HdTokens->drawDispatch); + + HgiIndirectCommandEncoder *encoder = hgi->GetIndirectCommandEncoder(); + HgiComputeCmds *computeCmds = + resourceRegistry->GetGlobalComputeCmds(HgiComputeDispatchConcurrent); + + if (!_useDrawIndexed) + { + _indirectCommands = encoder->EncodeDraw( + computeCmds, + psoHandle, + resourceBindings, + vertexBindings, + paramBuffer->GetHandle(), + paramBuffer->GetOffset(), + _dispatchBuffer->GetCount(), + paramBuffer->GetStride()); + } + else + { + HdStBufferResourceSharedPtr indexBuffer = + state.indexBar->GetResource(HdTokens->indices); + + _indirectCommands = encoder->EncodeDrawIndexed( + computeCmds, + psoHandle, + resourceBindings, + vertexBindings, + indexBuffer->GetHandle(), + paramBuffer->GetHandle(), + paramBuffer->GetOffset(), + _dispatchBuffer->GetCount(), + paramBuffer->GetStride(), + _patchBaseVertexByteOffset); + } +} - hgi->DestroyResourceBindings(&resourceBindings); +void HdSt_PipelineDrawBatch::_ExecuteFrustumCull( + bool const updateBufferData, + HdStRenderPassStateSharedPtr const &renderPassState, + HdStResourceRegistrySharedPtr const &resourceRegistry) +{ + TRACE_FUNCTION(); + + // Disable GPU culling when instancing enabled and + // not using instance culling. + if (_useInstancing && !_useInstanceCulling) + return; + + // Bypass freezeCulling if the command buffer is dirty. + bool const freezeCulling = TfDebug::IsEnabled(HD_FREEZE_CULL_FRUSTUM); + if (freezeCulling && !updateBufferData) + return; + + if (updateBufferData) + { + _dispatchBufferCullInput->CopyData(_drawCommandBuffer); + } + + _CreateCullingProgram(resourceRegistry); + if (!TF_VERIFY(_cullingProgram.IsValid())) + return; + + struct Uniforms + { + GfMatrix4f cullMatrix; + GfVec2f drawRangeNDC; + uint32_t drawCommandNumUints; + }; + + // We perform frustum culling in a compute shader, stomping the + // instanceCount of each drawing command in the dispatch buffer to 0 for + // primitives that are culled, skipping over other elements. + + _BindingState state( + _drawItemInstances.front()->GetDrawItem(), + _dispatchBufferCullInput, + _cullingProgram.GetBinder(), + _cullingProgram.GetGLSLProgram(), + _cullingProgram.GetComposedShaders(), + _cullingProgram.GetGeometricShader()); + + Hgi *hgi = resourceRegistry->GetHgi(); + + HgiComputePipelineSharedPtr const &pso = + _GetCullPipeline(resourceRegistry, + state, + sizeof(Uniforms)); + HgiComputePipelineHandle psoHandle = *pso.get(); + + HgiComputeCmds *computeCmds = + resourceRegistry->GetGlobalComputeCmds(HgiComputeDispatchConcurrent); + computeCmds->PushDebugGroup("FrustumCulling Cmds"); + + HgiResourceBindingsDesc bindingsDesc; + state.GetBindingsForViewTransformation(&bindingsDesc); + + if (IsEnabledGPUCountVisibleInstances()) + { + _BeginGPUCountVisibleInstances(resourceRegistry); + state.binder.GetBufferBindingDesc( + &bindingsDesc, + _tokens->drawIndirectResult, + _resultBuffer, + _resultBuffer->GetOffset()); + } + + // bind destination buffer + // (using entire buffer bind to start from offset=0) + state.binder.GetBufferBindingDesc( + &bindingsDesc, + _tokens->dispatchBuffer, + _dispatchBuffer->GetEntireResource(), + _dispatchBuffer->GetEntireResource()->GetOffset()); + + // bind the read-only copy of the destination buffer for input. + state.binder.GetBufferBindingDesc( + &bindingsDesc, + _tokens->drawCullInput, + _dispatchBufferCullInput->GetEntireResource(), + _dispatchBufferCullInput->GetEntireResource()->GetOffset()); + + // HdSt_ResourceBinder::GetBufferBindingDesc() sets state usage + // to all graphics pipeline stages. Instead we have to set all the + // buffer stage usage to Compute. + for (HgiBufferBindDesc &bufDesc : bindingsDesc.buffers) + { + bufDesc.stageUsage = HgiShaderStageCompute; + bufDesc.writable = true; + } + + HgiResourceBindingsHandle resourceBindings = + hgi->CreateResourceBindings(bindingsDesc); + + computeCmds->BindResources(resourceBindings); + computeCmds->BindPipeline(psoHandle); + + GfMatrix4f const &cullMatrix = GfMatrix4f(renderPassState->GetCullMatrix()); + GfVec2f const &drawRangeNdc = renderPassState->GetDrawingRangeNDC(); + + HdStBufferResourceSharedPtr paramBuffer = _dispatchBuffer->GetBufferArrayRange()->GetResource(HdTokens->drawDispatch); + + // set instanced cull parameters + Uniforms cullParams; + cullParams.cullMatrix = cullMatrix; + cullParams.drawRangeNDC = drawRangeNdc; + cullParams.drawCommandNumUints = _dispatchBuffer->GetCommandNumUints(); + + computeCmds->SetConstantValues( + psoHandle, 0, + sizeof(Uniforms), &cullParams); + + int const inputCount = _dispatchBufferCullInput->GetCount(); + computeCmds->Dispatch(inputCount, 1); + computeCmds->PopDebugGroup(); + + if (IsEnabledGPUCountVisibleInstances()) + { + _EndGPUCountVisibleInstances(resourceRegistry, &_numVisibleItems); + } + + hgi->DestroyResourceBindings(&resourceBindings); } -void -HdSt_PipelineDrawBatch::DrawItemInstanceChanged( - HdStDrawItemInstance const * instance) +void HdSt_PipelineDrawBatch::_ExecutePTCS( + HgiGraphicsCmds *ptcsGfxCmds, + HdStRenderPassStateSharedPtr const &renderPassState, + HdStResourceRegistrySharedPtr const &resourceRegistry) { - // We need to check the visibility and update if needed - if (!_dispatchBuffer) return; - - size_t const batchIndex = instance->GetBatchIndex(); - int const commandNumUints = _dispatchBuffer->GetCommandNumUints(); - int const numLevels = instance->GetDrawItem()->GetInstancePrimvarNumLevels(); - int const instanceIndexWidth = numLevels + 1; - - // When non-instance culling is being used, cullcommand points the same - // location as drawcommands. Then we update the same place twice, it - // might be better than branching. - std::vector::iterator instanceCountIt = - _drawCommandBuffer.begin() - + batchIndex * commandNumUints - + _instanceCountOffset; - std::vector::iterator cullInstanceCountIt = - _drawCommandBuffer.begin() - + batchIndex * commandNumUints - + _cullInstanceCountOffset; - - HdBufferArrayRangeSharedPtr const &instanceIndexBar_ = - instance->GetDrawItem()->GetInstanceIndexRange(); - HdStBufferArrayRangeSharedPtr instanceIndexBar = - std::static_pointer_cast(instanceIndexBar_); - - uint32_t const newInstanceCount = - _GetInstanceCount(instance, instanceIndexBar, instanceIndexWidth); - - TF_DEBUG(HDST_DRAW).Msg("\nInstance Count changed: %d -> %d\n", - *instanceCountIt, - newInstanceCount); - - // Update instance count and overall count of visible items. - if (static_cast(newInstanceCount) != (*instanceCountIt)) { - _numVisibleItems += (newInstanceCount - (*instanceCountIt)); - *instanceCountIt = newInstanceCount; - *cullInstanceCountIt = newInstanceCount; - _drawCommandBufferDirty = true; - } + TRACE_FUNCTION(); + + if (!TF_VERIFY(!_drawItemInstances.empty())) + return; + + if (!TF_VERIFY(_dispatchBuffer)) + return; + + if (_HasNothingToDraw()) + return; + + HgiCapabilities const *capabilities = + resourceRegistry->GetHgi()->GetCapabilities(); + + // Drawing can be either direct or indirect. For either case, + // the drawing batch and drawing program are prepared to resolve + // drawing coordinate state indirectly, i.e. from buffer data. + bool const drawIndirect = + capabilities->IsSet(HgiDeviceCapabilitiesBitsMultiDrawIndirect); + _DrawingProgram &program = _GetDrawingProgram(renderPassState, + resourceRegistry); + if (!TF_VERIFY(program.IsValid())) + return; + + _BindingState state( + _drawItemInstances.front()->GetDrawItem(), + _dispatchBuffer, + program.GetBinder(), + program.GetGLSLProgram(), + program.GetComposedShaders(), + program.GetGeometricShader()); + + Hgi *hgi = resourceRegistry->GetHgi(); + + HgiGraphicsPipelineSharedPtr const &psoTess = + _GetPTCSPipeline(renderPassState, + resourceRegistry, + state); + + HgiGraphicsPipelineHandle psoTessHandle = *psoTess.get(); + ptcsGfxCmds->BindPipeline(psoTessHandle); + + HgiResourceBindingsDesc bindingsDesc; + state.GetBindingsForDrawing(&bindingsDesc, + _tessFactorsBuffer, /*bindTessFactors=*/false); + + HgiResourceBindingsHandle resourceBindings = + hgi->CreateResourceBindings(bindingsDesc); + ptcsGfxCmds->BindResources(resourceBindings); + + HgiVertexBufferBindingVector bindings; + _GetVertexBufferBindingsForDrawing(&bindings, state); + ptcsGfxCmds->BindVertexBuffers(bindings); + + if (drawIndirect) + { + _ExecuteDrawIndirect(ptcsGfxCmds, state.indexBar); + } + else + { + _ExecuteDrawImmediate(ptcsGfxCmds, state.indexBar); + } + + hgi->DestroyResourceBindings(&resourceBindings); } -void -HdSt_PipelineDrawBatch::_BeginGPUCountVisibleInstances( - HdStResourceRegistrySharedPtr const & resourceRegistry) +void HdSt_PipelineDrawBatch::DrawItemInstanceChanged( + HdStDrawItemInstance const *instance) { - if (!_resultBuffer) { - HdTupleType tupleType; - tupleType.type = HdTypeInt32; - tupleType.count = 1; - - _resultBuffer = - resourceRegistry->RegisterBufferResource( - _tokens->drawIndirectResult, tupleType); - } + // We need to check the visibility and update if needed + if (!_dispatchBuffer) + return; + + size_t const batchIndex = instance->GetBatchIndex(); + int const commandNumUints = _dispatchBuffer->GetCommandNumUints(); + int const numLevels = instance->GetDrawItem()->GetInstancePrimvarNumLevels(); + int const instanceIndexWidth = numLevels + 1; + + // When non-instance culling is being used, cullcommand points the same + // location as drawcommands. Then we update the same place twice, it + // might be better than branching. + std::vector::iterator instanceCountIt = + _drawCommandBuffer.begin() + batchIndex * commandNumUints + _instanceCountOffset; + std::vector::iterator cullInstanceCountIt = + _drawCommandBuffer.begin() + batchIndex * commandNumUints + _cullInstanceCountOffset; + + HdBufferArrayRangeSharedPtr const &instanceIndexBar_ = + instance->GetDrawItem()->GetInstanceIndexRange(); + HdStBufferArrayRangeSharedPtr instanceIndexBar = + std::static_pointer_cast(instanceIndexBar_); + + uint32_t const newInstanceCount = + _GetInstanceCount(instance, instanceIndexBar, instanceIndexWidth); + + TF_DEBUG(HDST_DRAW).Msg("\nInstance Count changed: %d -> %d\n", + *instanceCountIt, + newInstanceCount); + + // Update instance count and overall count of visible items. + if (static_cast(newInstanceCount) != (*instanceCountIt)) + { + _numVisibleItems += (newInstanceCount - (*instanceCountIt)); + *instanceCountIt = newInstanceCount; + *cullInstanceCountIt = newInstanceCount; + _drawCommandBufferDirty = true; + } +} - // Reset visible item count - static const int32_t count = 0; - HgiBlitCmds* blitCmds = resourceRegistry->GetGlobalBlitCmds(); - HgiBufferCpuToGpuOp op; - op.cpuSourceBuffer = &count; - op.sourceByteOffset = 0; - op.gpuDestinationBuffer = _resultBuffer->GetHandle(); - op.destinationByteOffset = 0; - op.byteSize = sizeof(count); - blitCmds->CopyBufferCpuToGpu(op); - - // For now we need to submit here, because there gfx commands after - // _BeginGPUCountVisibleInstances that rely on this having executed on GPU. - resourceRegistry->SubmitBlitWork(); +void HdSt_PipelineDrawBatch::_BeginGPUCountVisibleInstances( + HdStResourceRegistrySharedPtr const &resourceRegistry) +{ + if (!_resultBuffer) + { + HdTupleType tupleType; + tupleType.type = HdTypeInt32; + tupleType.count = 1; + + _resultBuffer = + resourceRegistry->RegisterBufferResource( + _tokens->drawIndirectResult, tupleType); + } + + // Reset visible item count + static const int32_t count = 0; + HgiBlitCmds *blitCmds = resourceRegistry->GetGlobalBlitCmds(); + HgiBufferCpuToGpuOp op; + op.cpuSourceBuffer = &count; + op.sourceByteOffset = 0; + op.gpuDestinationBuffer = _resultBuffer->GetHandle(); + op.destinationByteOffset = 0; + op.byteSize = sizeof(count); + blitCmds->CopyBufferCpuToGpu(op); + + // For now we need to submit here, because there gfx commands after + // _BeginGPUCountVisibleInstances that rely on this having executed on GPU. + resourceRegistry->SubmitBlitWork(); } -void -HdSt_PipelineDrawBatch::_EndGPUCountVisibleInstances( - HdStResourceRegistrySharedPtr const & resourceRegistry, - size_t * result) +void HdSt_PipelineDrawBatch::_EndGPUCountVisibleInstances( + HdStResourceRegistrySharedPtr const &resourceRegistry, + size_t *result) { - // Submit and wait for all the work recorded up to this point. - // The GPU work must complete before we can read-back the GPU buffer. - // GPU frustum culling is (currently) a vertex shader without a fragment - // shader, so we submit the blit work, but do not have any compute work. - resourceRegistry->SubmitBlitWork(HgiSubmitWaitTypeWaitUntilCompleted); - - int32_t count = 0; - - // Submit GPU buffer read back - HgiBufferGpuToCpuOp copyOp; - copyOp.byteSize = sizeof(count); - copyOp.cpuDestinationBuffer = &count; - copyOp.destinationByteOffset = 0; - copyOp.gpuSourceBuffer = _resultBuffer->GetHandle(); - copyOp.sourceByteOffset = 0; - - HgiBlitCmds* blitCmds = resourceRegistry->GetGlobalBlitCmds(); - blitCmds->CopyBufferGpuToCpu(copyOp); - resourceRegistry->SubmitBlitWork(HgiSubmitWaitTypeWaitUntilCompleted); - - *result = count; + // Submit and wait for all the work recorded up to this point. + // The GPU work must complete before we can read-back the GPU buffer. + // GPU frustum culling is (currently) a vertex shader without a fragment + // shader, so we submit the blit work, but do not have any compute work. + resourceRegistry->SubmitBlitWork(HgiSubmitWaitTypeWaitUntilCompleted); + + int32_t count = 0; + + // Submit GPU buffer read back + HgiBufferGpuToCpuOp copyOp; + copyOp.byteSize = sizeof(count); + copyOp.cpuDestinationBuffer = &count; + copyOp.destinationByteOffset = 0; + copyOp.gpuSourceBuffer = _resultBuffer->GetHandle(); + copyOp.sourceByteOffset = 0; + + HgiBlitCmds *blitCmds = resourceRegistry->GetGlobalBlitCmds(); + blitCmds->CopyBufferGpuToCpu(copyOp); + resourceRegistry->SubmitBlitWork(HgiSubmitWaitTypeWaitUntilCompleted); + + *result = count; } -void -HdSt_PipelineDrawBatch::_CreateCullingProgram( - HdStResourceRegistrySharedPtr const & resourceRegistry) +void HdSt_PipelineDrawBatch::_CreateCullingProgram( + HdStResourceRegistrySharedPtr const &resourceRegistry) { - if (!_cullingProgram.GetGLSLProgram() || _dirtyCullingProgram) { - // Create a culling compute shader key - HdSt_CullingComputeShaderKey shaderKey(_useInstanceCulling, - _useTinyPrimCulling, - IsEnabledGPUCountVisibleInstances()); - - // access the drawing coord from the drawCullInput buffer - _CullingProgram::DrawingCoordBufferBinding drawingCoordBufferBinding{ - _tokens->drawCullInput, - uint32_t(_drawCoordOffset), - uint32_t(_dispatchBuffer->GetCommandNumUints()), - }; - - // sharing the culling geometric shader for the same configuration. - HdSt_GeometricShaderSharedPtr cullShader = - HdSt_GeometricShader::Create(shaderKey, resourceRegistry); - _cullingProgram.SetDrawingCoordBufferBinding(drawingCoordBufferBinding); - _cullingProgram.SetGeometricShader(cullShader); - - _cullingProgram.CompileShader(_drawItemInstances.front()->GetDrawItem(), - resourceRegistry); - - _dirtyCullingProgram = false; - } + if (!_cullingProgram.GetGLSLProgram() || _dirtyCullingProgram) + { + // Create a culling compute shader key + HdSt_CullingComputeShaderKey shaderKey(_useInstanceCulling, + _useTinyPrimCulling, + IsEnabledGPUCountVisibleInstances()); + + // access the drawing coord from the drawCullInput buffer + _CullingProgram::DrawingCoordBufferBinding drawingCoordBufferBinding{ + _tokens->drawCullInput, + uint32_t(_drawCoordOffset), + uint32_t(_dispatchBuffer->GetCommandNumUints()), + }; + + // sharing the culling geometric shader for the same configuration. + HdSt_GeometricShaderSharedPtr cullShader = + HdSt_GeometricShader::Create(shaderKey, resourceRegistry); + _cullingProgram.SetDrawingCoordBufferBinding(drawingCoordBufferBinding); + _cullingProgram.SetGeometricShader(cullShader); + + _cullingProgram.CompileShader(_drawItemInstances.front()->GetDrawItem(), + resourceRegistry); + + _dirtyCullingProgram = false; + } } -void -HdSt_PipelineDrawBatch::_CullingProgram::Initialize( +void HdSt_PipelineDrawBatch::_CullingProgram::Initialize( bool useDrawIndexed, bool useInstanceCulling, size_t bufferArrayHash) { - if (useDrawIndexed != _useDrawIndexed || - useInstanceCulling != _useInstanceCulling || - bufferArrayHash != _bufferArrayHash) { - // reset shader - Reset(); - } - - _useDrawIndexed = useDrawIndexed; - _useInstanceCulling = useInstanceCulling; - _bufferArrayHash = bufferArrayHash; + if (useDrawIndexed != _useDrawIndexed || + useInstanceCulling != _useInstanceCulling || + bufferArrayHash != _bufferArrayHash) + { + // reset shader + Reset(); + } + + _useDrawIndexed = useDrawIndexed; + _useInstanceCulling = useInstanceCulling; + _bufferArrayHash = bufferArrayHash; } /* virtual */ -void -HdSt_PipelineDrawBatch::_CullingProgram::_GetCustomBindings( - HdStBindingRequestVector * customBindings, - bool * enableInstanceDraw) const +void HdSt_PipelineDrawBatch::_CullingProgram::_GetCustomBindings( + HdStBindingRequestVector *customBindings, + bool *enableInstanceDraw) const { - if (!TF_VERIFY(enableInstanceDraw) || - !TF_VERIFY(customBindings)) return; - - customBindings->push_back(HdStBindingRequest(HdStBinding::SSBO, - _tokens->drawIndirectResult)); - customBindings->push_back(HdStBindingRequest(HdStBinding::SSBO, - _tokens->dispatchBuffer)); - customBindings->push_back(HdStBindingRequest(HdStBinding::UBO, - _tokens->ulocCullParams)); - customBindings->push_back(HdStBindingRequest(HdStBinding::SSBO, - _tokens->drawCullInput)); - - // set instanceDraw true if instanceCulling is enabled. - // this value will be used to determine if glVertexAttribDivisor needs to - // be enabled or not. - *enableInstanceDraw = _useInstanceCulling; + if (!TF_VERIFY(enableInstanceDraw) || + !TF_VERIFY(customBindings)) + return; + + customBindings->push_back(HdStBindingRequest(HdStBinding::SSBO, + _tokens->drawIndirectResult)); + customBindings->push_back(HdStBindingRequest(HdStBinding::SSBO, + _tokens->dispatchBuffer)); + customBindings->push_back(HdStBindingRequest(HdStBinding::UBO, + _tokens->ulocCullParams)); + customBindings->push_back(HdStBindingRequest(HdStBinding::SSBO, + _tokens->drawCullInput)); + + // set instanceDraw true if instanceCulling is enabled. + // this value will be used to determine if glVertexAttribDivisor needs to + // be enabled or not. + *enableInstanceDraw = _useInstanceCulling; } PXR_NAMESPACE_CLOSE_SCOPE diff --git a/Sources/OpenUSD/imaging/hdSt/primUtils.cpp b/Sources/OpenUSD/imaging/hdSt/primUtils.cpp index 78736c150b..c1ea421ed6 100644 --- a/Sources/OpenUSD/imaging/hdSt/primUtils.cpp +++ b/Sources/OpenUSD/imaging/hdSt/primUtils.cpp @@ -56,7 +56,7 @@ #include "pxr/base/tf/envSetting.h" #include "pxr/base/tf/staticData.h" -#include "pxr/base/arch/hash.h" +#include "Arch/hash.h" #include @@ -69,836 +69,876 @@ TF_MAKE_STATIC_DATA( HdSt_MaterialNetworkShaderSharedPtr, _fallbackWidgetShader) { - *_fallbackWidgetShader = std::make_shared( - std::make_shared(HdStPackageWidgetShader())); + *_fallbackWidgetShader = std::make_shared( + std::make_shared(HdStPackageWidgetShader())); } // ----------------------------------------------------------------------------- // Draw invalidation utilities // ----------------------------------------------------------------------------- -void -HdStMarkDrawBatchesDirty(HdRenderParam *renderParam) +void HdStMarkDrawBatchesDirty(HdRenderParam *renderParam) { - if (TF_VERIFY(renderParam)) { - HdStRenderParam *stRenderParam = - static_cast(renderParam); - stRenderParam->MarkDrawBatchesDirty(); - } + if (TF_VERIFY(renderParam)) + { + HdStRenderParam *stRenderParam = + static_cast(renderParam); + stRenderParam->MarkDrawBatchesDirty(); + } } -void -HdStMarkMaterialTagsDirty(HdRenderParam *renderParam) +void HdStMarkMaterialTagsDirty(HdRenderParam *renderParam) { - if (TF_VERIFY(renderParam)) { - HdStRenderParam *stRenderParam = - static_cast(renderParam); - stRenderParam->MarkMaterialTagsDirty(); - } + if (TF_VERIFY(renderParam)) + { + HdStRenderParam *stRenderParam = + static_cast(renderParam); + stRenderParam->MarkMaterialTagsDirty(); + } } -void -HdStMarkGeomSubsetDrawItemsDirty(HdRenderParam *renderParam) +void HdStMarkGeomSubsetDrawItemsDirty(HdRenderParam *renderParam) { - if (TF_VERIFY(renderParam)) { - HdStRenderParam *stRenderParam = - static_cast(renderParam); - stRenderParam->MarkGeomSubsetDrawItemsDirty(); - } + if (TF_VERIFY(renderParam)) + { + HdStRenderParam *stRenderParam = + static_cast(renderParam); + stRenderParam->MarkGeomSubsetDrawItemsDirty(); + } } -void -HdStMarkGarbageCollectionNeeded(HdRenderParam *renderParam) +void HdStMarkGarbageCollectionNeeded(HdRenderParam *renderParam) { - if (TF_VERIFY(renderParam)) { - HdStRenderParam *stRenderParam = - static_cast(renderParam); - stRenderParam->SetGarbageCollectionNeeded(); - } + if (TF_VERIFY(renderParam)) + { + HdStRenderParam *stRenderParam = + static_cast(renderParam); + stRenderParam->SetGarbageCollectionNeeded(); + } } // ----------------------------------------------------------------------------- // Primvar descriptor filtering utilities // ----------------------------------------------------------------------------- static bool -_IsEnabledPrimvarFiltering(HdStDrawItem const * drawItem) +_IsEnabledPrimvarFiltering(HdStDrawItem const *drawItem) { - HdSt_MaterialNetworkShaderSharedPtr materialNetworkShader = - drawItem->GetMaterialNetworkShader(); - return materialNetworkShader && - materialNetworkShader->IsEnabledPrimvarFiltering(); + HdSt_MaterialNetworkShaderSharedPtr materialNetworkShader = + drawItem->GetMaterialNetworkShader(); + return materialNetworkShader && + materialNetworkShader->IsEnabledPrimvarFiltering(); } static TfTokenVector const & -_GetFilterNamesForMaterial(HdStDrawItem const * drawItem) +_GetFilterNamesForMaterial(HdStDrawItem const *drawItem) { - HdSt_MaterialNetworkShaderSharedPtr materialNetworkShader = - drawItem->GetMaterialNetworkShader(); - if (materialNetworkShader) { - return materialNetworkShader->GetPrimvarNames(); - } - - static const TfTokenVector fallback = TfTokenVector(); - return fallback; + HdSt_MaterialNetworkShaderSharedPtr materialNetworkShader = + drawItem->GetMaterialNetworkShader(); + if (materialNetworkShader) + { + return materialNetworkShader->GetPrimvarNames(); + } + + static const TfTokenVector fallback = TfTokenVector(); + return fallback; } static TfTokenVector -_GetFilterNames(HdRprim const * prim, - HdStDrawItem const * drawItem, - HdStInstancer const * instancer = nullptr) +_GetFilterNames(HdRprim const *prim, + HdStDrawItem const *drawItem, + HdStInstancer const *instancer = nullptr) { - TfTokenVector filterNames = prim->GetBuiltinPrimvarNames(); - - const TfTokenVector &matPvNames = _GetFilterNamesForMaterial(drawItem); - filterNames.insert(filterNames.end(), matPvNames.begin(), - matPvNames.end()); - - if (instancer) { - TfTokenVector const & names = instancer->GetBuiltinPrimvarNames(); - filterNames.insert(filterNames.end(), names.begin(), names.end()); - } - return filterNames; + TfTokenVector filterNames = prim->GetBuiltinPrimvarNames(); + + const TfTokenVector &matPvNames = _GetFilterNamesForMaterial(drawItem); + filterNames.insert(filterNames.end(), matPvNames.begin(), + matPvNames.end()); + + if (instancer) + { + TfTokenVector const &names = instancer->GetBuiltinPrimvarNames(); + filterNames.insert(filterNames.end(), names.begin(), names.end()); + } + return filterNames; } static HdPrimvarDescriptorVector _FilterPrimvarDescriptors(HdPrimvarDescriptorVector primvars, - TfTokenVector const & filterNames) + TfTokenVector const &filterNames) { - primvars.erase( - std::remove_if(primvars.begin(), primvars.end(), - [&filterNames](HdPrimvarDescriptor const &desc) { - return std::find(filterNames.begin(), filterNames.end(), - desc.name) == filterNames.end(); - }), - primvars.end()); - - return primvars; + primvars.erase( + std::remove_if(primvars.begin(), primvars.end(), + [&filterNames](HdPrimvarDescriptor const &desc) + { + return std::find(filterNames.begin(), filterNames.end(), + desc.name) == filterNames.end(); + }), + primvars.end()); + + return primvars; } HdPrimvarDescriptorVector HdStGetPrimvarDescriptors( - HdRprim const * prim, - HdStDrawItem const * drawItem, - HdSceneDelegate * delegate, + HdRprim const *prim, + HdStDrawItem const *drawItem, + HdSceneDelegate *delegate, HdInterpolation interpolation, HdReprSharedPtr const &repr, HdMeshGeomStyle descGeomStyle, int geomSubsetDescIndex, size_t numGeomSubsets) { - HD_TRACE_FUNCTION(); - - HdPrimvarDescriptorVector primvars = - prim->GetPrimvarDescriptors(delegate, interpolation); - - TfTokenVector filterNames; - if (_IsEnabledPrimvarFiltering(drawItem)) { - filterNames = _GetFilterNames(prim, drawItem); - } - - if (numGeomSubsets != 0 && - repr && - descGeomStyle != HdMeshGeomStyleInvalid && - descGeomStyle != HdMeshGeomStylePoints) { - for (size_t i = 0; i < numGeomSubsets; ++i) { - HdStDrawItem const * subsetDrawItem = - static_cast(repr->GetDrawItemForGeomSubset( - geomSubsetDescIndex, numGeomSubsets, i)); - if (!TF_VERIFY(subsetDrawItem)) { - continue; - } - if (_IsEnabledPrimvarFiltering(subsetDrawItem)) { - const TfTokenVector matPvNames = _GetFilterNamesForMaterial( - subsetDrawItem); - filterNames.insert(filterNames.end(), matPvNames.begin(), - matPvNames.end()); - } - } - std::sort(filterNames.begin(), filterNames.end()); - filterNames.erase(std::unique(filterNames.begin(), filterNames.end()), - filterNames.end()); + HD_TRACE_FUNCTION(); + + HdPrimvarDescriptorVector primvars = + prim->GetPrimvarDescriptors(delegate, interpolation); + + TfTokenVector filterNames; + if (_IsEnabledPrimvarFiltering(drawItem)) + { + filterNames = _GetFilterNames(prim, drawItem); + } + + if (numGeomSubsets != 0 && + repr && + descGeomStyle != HdMeshGeomStyleInvalid && + descGeomStyle != HdMeshGeomStylePoints) + { + for (size_t i = 0; i < numGeomSubsets; ++i) + { + HdStDrawItem const *subsetDrawItem = + static_cast(repr->GetDrawItemForGeomSubset( + geomSubsetDescIndex, numGeomSubsets, i)); + if (!TF_VERIFY(subsetDrawItem)) + { + continue; + } + if (_IsEnabledPrimvarFiltering(subsetDrawItem)) + { + const TfTokenVector matPvNames = _GetFilterNamesForMaterial( + subsetDrawItem); + filterNames.insert(filterNames.end(), matPvNames.begin(), + matPvNames.end()); + } } + std::sort(filterNames.begin(), filterNames.end()); + filterNames.erase(std::unique(filterNames.begin(), filterNames.end()), + filterNames.end()); + } - if (filterNames.empty()) { - return primvars; - } - return _FilterPrimvarDescriptors(primvars, filterNames); + if (filterNames.empty()) + { + return primvars; + } + return _FilterPrimvarDescriptors(primvars, filterNames); } HdPrimvarDescriptorVector HdStGetInstancerPrimvarDescriptors( - HdStInstancer const * instancer, - HdSceneDelegate * delegate) + HdStInstancer const *instancer, + HdSceneDelegate *delegate) { - HdPrimvarDescriptorVector primvars = - delegate->GetPrimvarDescriptors(instancer->GetId(), - HdInterpolationInstance); + HdPrimvarDescriptorVector primvars = + delegate->GetPrimvarDescriptors(instancer->GetId(), + HdInterpolationInstance); - // XXX: Can we do filtering? - return primvars; + // XXX: Can we do filtering? + return primvars; } // ----------------------------------------------------------------------------- // Tracking render tag changes // ----------------------------------------------------------------------------- -void -HdStUpdateRenderTag(HdSceneDelegate *delegate, - HdRenderParam *renderParam, - HdRprim *rprim) +void HdStUpdateRenderTag(HdSceneDelegate *delegate, + HdRenderParam *renderParam, + HdRprim *rprim) { - HdStRenderParam * const stRenderParam = - static_cast(renderParam); - - const TfToken prevRenderTag = rprim->GetRenderTag(); - rprim->HdRprim::UpdateRenderTag(delegate, renderParam); - const TfToken &renderTag = rprim->GetRenderTag(); - if (renderTag == prevRenderTag) { - return; - } - stRenderParam->DecreaseRenderTagCount(prevRenderTag); - stRenderParam->IncreaseRenderTagCount(renderTag); + HdStRenderParam *const stRenderParam = + static_cast(renderParam); + + const TfToken prevRenderTag = rprim->GetRenderTag(); + rprim->HdRprim::UpdateRenderTag(delegate, renderParam); + const TfToken &renderTag = rprim->GetRenderTag(); + if (renderTag == prevRenderTag) + { + return; + } + stRenderParam->DecreaseRenderTagCount(prevRenderTag); + stRenderParam->IncreaseRenderTagCount(renderTag); } // ----------------------------------------------------------------------------- // Material processing utilities // ----------------------------------------------------------------------------- -void -HdStSetMaterialId(HdSceneDelegate *delegate, - HdRenderParam *renderParam, - HdRprim *rprim) +void HdStSetMaterialId(HdSceneDelegate *delegate, + HdRenderParam *renderParam, + HdRprim *rprim) { - SdfPath const& newMaterialId = delegate->GetMaterialId(rprim->GetId()); - if (rprim->GetMaterialId() != newMaterialId) { - rprim->SetMaterialId(newMaterialId); - - // The batches need to be validated and rebuilt since a changed shader - // may change aggregation. - HdStMarkDrawBatchesDirty(renderParam); - } + SdfPath const &newMaterialId = delegate->GetMaterialId(rprim->GetId()); + if (rprim->GetMaterialId() != newMaterialId) + { + rprim->SetMaterialId(newMaterialId); + + // The batches need to be validated and rebuilt since a changed shader + // may change aggregation. + HdStMarkDrawBatchesDirty(renderParam); + } } -void -HdStSetMaterialTag(HdRenderParam * const renderParam, - HdDrawItem *drawItem, - const TfToken &materialTag) +void HdStSetMaterialTag(HdRenderParam *const renderParam, + HdDrawItem *drawItem, + const TfToken &materialTag) { - HdStRenderParam * const stRenderParam = - static_cast(renderParam); + HdStRenderParam *const stRenderParam = + static_cast(renderParam); - { - // prevMaterialTag scoped to express that it is a reference - // to a field modified by SetMaterialTag later. - const TfToken &prevMaterialTag = drawItem->GetMaterialTag(); + { + // prevMaterialTag scoped to express that it is a reference + // to a field modified by SetMaterialTag later. + const TfToken &prevMaterialTag = drawItem->GetMaterialTag(); - if (materialTag == prevMaterialTag) { - return; - } - - stRenderParam->DecreaseMaterialTagCount(prevMaterialTag); - } + if (materialTag == prevMaterialTag) { - stRenderParam->IncreaseMaterialTagCount(materialTag); - drawItem->SetMaterialTag(materialTag); + return; } - // Trigger invalidation of the draw items cache of the render pass(es). - HdStMarkMaterialTagsDirty(renderParam); + stRenderParam->DecreaseMaterialTagCount(prevMaterialTag); + } + { + stRenderParam->IncreaseMaterialTagCount(materialTag); + drawItem->SetMaterialTag(materialTag); + } + + // Trigger invalidation of the draw items cache of the render pass(es). + HdStMarkMaterialTagsDirty(renderParam); } // Opinion precedence: // Show occluded selection > Material opinion > displayOpacity primvar // -static -TfToken -_ComputeMaterialTag(HdSceneDelegate * const delegate, - SdfPath const & materialId, +static TfToken +_ComputeMaterialTag(HdSceneDelegate *const delegate, + SdfPath const &materialId, const bool hasDisplayOpacityPrimvar, const bool occludedSelectionShowsThrough) { - if (occludedSelectionShowsThrough) { - return HdStMaterialTagTokens->translucentToSelection; - } - - const HdStMaterial *material = - static_cast( - delegate->GetRenderIndex().GetSprim( - HdPrimTypeTokens->material, materialId)); - if (material) { - return material->GetMaterialTag(); - } - - if (hasDisplayOpacityPrimvar) { - return HdStMaterialTagTokens->masked; - } - - return HdMaterialTagTokens->defaultMaterialTag; + if (occludedSelectionShowsThrough) + { + return HdStMaterialTagTokens->translucentToSelection; + } + + const HdStMaterial *material = + static_cast( + delegate->GetRenderIndex().GetSprim( + HdPrimTypeTokens->material, materialId)); + if (material) + { + return material->GetMaterialTag(); + } + + if (hasDisplayOpacityPrimvar) + { + return HdStMaterialTagTokens->masked; + } + + return HdMaterialTagTokens->defaultMaterialTag; } -void -HdStSetMaterialTag(HdSceneDelegate * const delegate, - HdRenderParam * const renderParam, - HdDrawItem *drawItem, - SdfPath const & materialId, - const bool hasDisplayOpacityPrimvar, - const bool occludedSelectionShowsThrough) +void HdStSetMaterialTag(HdSceneDelegate *const delegate, + HdRenderParam *const renderParam, + HdDrawItem *drawItem, + SdfPath const &materialId, + const bool hasDisplayOpacityPrimvar, + const bool occludedSelectionShowsThrough) { - HdStSetMaterialTag( - renderParam, drawItem, - _ComputeMaterialTag( - delegate, materialId, hasDisplayOpacityPrimvar, - occludedSelectionShowsThrough)); + HdStSetMaterialTag( + renderParam, drawItem, + _ComputeMaterialTag( + delegate, materialId, hasDisplayOpacityPrimvar, + occludedSelectionShowsThrough)); } HdSt_MaterialNetworkShaderSharedPtr HdStGetMaterialNetworkShader( - HdRprim const * prim, - HdSceneDelegate * delegate) + HdRprim const *prim, + HdSceneDelegate *delegate) { - return HdStGetMaterialNetworkShader(prim, delegate, prim->GetMaterialId()); + return HdStGetMaterialNetworkShader(prim, delegate, prim->GetMaterialId()); } HdSt_MaterialNetworkShaderSharedPtr HdStGetMaterialNetworkShader( - HdRprim const * prim, - HdSceneDelegate * delegate, - SdfPath const & materialId) + HdRprim const *prim, + HdSceneDelegate *delegate, + SdfPath const &materialId) { - // Resolve the prim's material or use the fallback material. - HdRenderIndex &renderIndex = delegate->GetRenderIndex(); - HdStMaterial const * material = static_cast( - renderIndex.GetSprim(HdPrimTypeTokens->material, materialId)); - if (material == nullptr) { - if (prim->GetRenderTag(delegate) == HdRenderTagTokens->widget) { - TF_DEBUG(HD_RPRIM_UPDATED).Msg("Using built-in widget material for " - "%s\n", prim->GetId().GetText()); - - return *_fallbackWidgetShader; - } else { - TF_DEBUG(HD_RPRIM_UPDATED).Msg("Using fallback material for %s\n", - prim->GetId().GetText()); - - material = static_cast( - renderIndex.GetFallbackSprim(HdPrimTypeTokens->material)); - } + // Resolve the prim's material or use the fallback material. + HdRenderIndex &renderIndex = delegate->GetRenderIndex(); + HdStMaterial const *material = static_cast( + renderIndex.GetSprim(HdPrimTypeTokens->material, materialId)); + if (material == nullptr) + { + if (prim->GetRenderTag(delegate) == HdRenderTagTokens->widget) + { + TF_DEBUG(HD_RPRIM_UPDATED).Msg("Using built-in widget material for " + "%s\n", + prim->GetId().GetText()); + + return *_fallbackWidgetShader; } + else + { + TF_DEBUG(HD_RPRIM_UPDATED).Msg("Using fallback material for %s\n", prim->GetId().GetText()); - return material->GetMaterialNetworkShader(); + material = static_cast( + renderIndex.GetFallbackSprim(HdPrimTypeTokens->material)); + } + } + + return material->GetMaterialNetworkShader(); } // ----------------------------------------------------------------------------- // Primvar processing and BAR allocation utilities // ----------------------------------------------------------------------------- -bool -HdStIsValidBAR(HdBufferArrayRangeSharedPtr const& range) +bool HdStIsValidBAR(HdBufferArrayRangeSharedPtr const &range) { - return (range && range->IsValid()); + return (range && range->IsValid()); } -bool -HdStCanSkipBARAllocationOrUpdate( - HdBufferSourceSharedPtrVector const& sources, - HdStComputationComputeQueuePairVector const& computations, - HdBufferArrayRangeSharedPtr const& curRange, +bool HdStCanSkipBARAllocationOrUpdate( + HdBufferSourceSharedPtrVector const &sources, + HdStComputationComputeQueuePairVector const &computations, + HdBufferArrayRangeSharedPtr const &curRange, HdDirtyBits dirtyBits) { - TF_UNUSED(dirtyBits); - // XXX: DirtyPrimvar is serving a double role of indicating primvar value - // dirtyness as well as descriptor dirtyness. - // We should move to a separate dirty bit for the latter. - bool mayHaveDirtyPrimvarDesc = (dirtyBits & HdChangeTracker::DirtyPrimvar); - - // If we have no buffer/computation sources, we can skip processing in the - // following cases: - // - we haven't allocated a BAR previously - // - we have an existing BAR and its primvar descriptors haven't changed - bool noDataSourcesToUpdate = sources.empty() && computations.empty(); - return noDataSourcesToUpdate && - (!HdStIsValidBAR(curRange) || !mayHaveDirtyPrimvarDesc); + TF_UNUSED(dirtyBits); + // XXX: DirtyPrimvar is serving a double role of indicating primvar value + // dirtyness as well as descriptor dirtyness. + // We should move to a separate dirty bit for the latter. + bool mayHaveDirtyPrimvarDesc = (dirtyBits & HdChangeTracker::DirtyPrimvar); + + // If we have no buffer/computation sources, we can skip processing in the + // following cases: + // - we haven't allocated a BAR previously + // - we have an existing BAR and its primvar descriptors haven't changed + bool noDataSourcesToUpdate = sources.empty() && computations.empty(); + return noDataSourcesToUpdate && + (!HdStIsValidBAR(curRange) || !mayHaveDirtyPrimvarDesc); } -bool -HdStCanSkipBARAllocationOrUpdate( - HdBufferSourceSharedPtrVector const& sources, - HdBufferArrayRangeSharedPtr const& curRange, +bool HdStCanSkipBARAllocationOrUpdate( + HdBufferSourceSharedPtrVector const &sources, + HdBufferArrayRangeSharedPtr const &curRange, HdDirtyBits dirtyBits) { - return HdStCanSkipBARAllocationOrUpdate( - sources, HdStComputationComputeQueuePairVector(), curRange, dirtyBits); + return HdStCanSkipBARAllocationOrUpdate( + sources, HdStComputationComputeQueuePairVector(), curRange, dirtyBits); } HdBufferSpecVector _GetRemovedPrimvarBufferSpecs( - HdBufferSpecVector const& curBarSpecs, - HdPrimvarDescriptorVector const& newPrimvarDescs, - HdExtComputationPrimvarDescriptorVector const& newCompPrimvarDescs, - TfTokenVector const& internallyGeneratedPrimvarNames, - SdfPath const& rprimId) + HdBufferSpecVector const &curBarSpecs, + HdPrimvarDescriptorVector const &newPrimvarDescs, + HdExtComputationPrimvarDescriptorVector const &newCompPrimvarDescs, + TfTokenVector const &internallyGeneratedPrimvarNames, + SdfPath const &rprimId) { - HdBufferSpecVector removedPrimvarSpecs; - // Get the new list of primvar sources for the BAR. We need to use both - // the primvar descriptor list (that we get via the scene delegate), as - // well as any internally generated primvars that are always added (such as - // primId). This may contain primvars that fail validation, but we're only - // interested in finding out existing primvars that aren't in the list. - TfTokenVector newPrimvarNames; - newPrimvarNames.reserve(newPrimvarDescs.size()); - for (auto const& desc : newPrimvarDescs) { - newPrimvarNames.emplace_back(desc.name); - } - for (auto const& desc : newCompPrimvarDescs) { - newPrimvarNames.emplace_back(desc.name); + HdBufferSpecVector removedPrimvarSpecs; + // Get the new list of primvar sources for the BAR. We need to use both + // the primvar descriptor list (that we get via the scene delegate), as + // well as any internally generated primvars that are always added (such as + // primId). This may contain primvars that fail validation, but we're only + // interested in finding out existing primvars that aren't in the list. + TfTokenVector newPrimvarNames; + newPrimvarNames.reserve(newPrimvarDescs.size()); + for (auto const &desc : newPrimvarDescs) + { + newPrimvarNames.emplace_back(desc.name); + } + for (auto const &desc : newCompPrimvarDescs) + { + newPrimvarNames.emplace_back(desc.name); + } + + // Check if the existing BAR has buffers that are neither in the new source + // list nor are internally generated. + for (auto const &spec : curBarSpecs) + { + + bool isInNewList = + std::find(newPrimvarNames.begin(), newPrimvarNames.end(), spec.name) != newPrimvarNames.end(); + + if (isInNewList) + { + continue; // avoid the search below } - // Check if the existing BAR has buffers that are neither in the new source - // list nor are internally generated. - for (auto const& spec : curBarSpecs) { - - bool isInNewList = - std::find(newPrimvarNames.begin(), newPrimvarNames.end(), spec.name) - != newPrimvarNames.end(); - - if (isInNewList) { - continue; // avoid the search below - } + bool isInGeneratedList = + std::find(internallyGeneratedPrimvarNames.begin(), + internallyGeneratedPrimvarNames.end(), spec.name) != internallyGeneratedPrimvarNames.end(); - bool isInGeneratedList = - std::find(internallyGeneratedPrimvarNames.begin(), - internallyGeneratedPrimvarNames.end(), spec.name) - != internallyGeneratedPrimvarNames.end(); - - if (!isInGeneratedList) { - TF_DEBUG(HD_RPRIM_UPDATED).Msg( - "%s: Found primvar %s that has been removed\n", - rprimId.GetText(), spec.name.GetText()); - removedPrimvarSpecs.emplace_back(spec); - } + if (!isInGeneratedList) + { + TF_DEBUG(HD_RPRIM_UPDATED).Msg("%s: Found primvar %s that has been removed\n", rprimId.GetText(), spec.name.GetText()); + removedPrimvarSpecs.emplace_back(spec); } + } - return removedPrimvarSpecs; + return removedPrimvarSpecs; } HdBufferSpecVector HdStGetRemovedPrimvarBufferSpecs( - HdBufferArrayRangeSharedPtr const& curRange, - HdPrimvarDescriptorVector const& newPrimvarDescs, - HdExtComputationPrimvarDescriptorVector const& newCompPrimvarDescs, - TfTokenVector const& internallyGeneratedPrimvarNames, - SdfPath const& rprimId) + HdBufferArrayRangeSharedPtr const &curRange, + HdPrimvarDescriptorVector const &newPrimvarDescs, + HdExtComputationPrimvarDescriptorVector const &newCompPrimvarDescs, + TfTokenVector const &internallyGeneratedPrimvarNames, + SdfPath const &rprimId) { - if (!HdStIsValidBAR(curRange)) { - return HdBufferSpecVector(); - } + if (!HdStIsValidBAR(curRange)) + { + return HdBufferSpecVector(); + } - HdBufferSpecVector curBarSpecs; - curRange->GetBufferSpecs(&curBarSpecs); + HdBufferSpecVector curBarSpecs; + curRange->GetBufferSpecs(&curBarSpecs); - return _GetRemovedPrimvarBufferSpecs(curBarSpecs, newPrimvarDescs, - newCompPrimvarDescs, internallyGeneratedPrimvarNames, rprimId); + return _GetRemovedPrimvarBufferSpecs(curBarSpecs, newPrimvarDescs, + newCompPrimvarDescs, internallyGeneratedPrimvarNames, rprimId); } HdBufferSpecVector HdStGetRemovedPrimvarBufferSpecs( - HdBufferArrayRangeSharedPtr const& curRange, - HdPrimvarDescriptorVector const& newPrimvarDescs, - TfTokenVector const& internallyGeneratedPrimvarNames, - SdfPath const& rprimId) + HdBufferArrayRangeSharedPtr const &curRange, + HdPrimvarDescriptorVector const &newPrimvarDescs, + TfTokenVector const &internallyGeneratedPrimvarNames, + SdfPath const &rprimId) { - return HdStGetRemovedPrimvarBufferSpecs(curRange, newPrimvarDescs, - HdExtComputationPrimvarDescriptorVector(), - internallyGeneratedPrimvarNames, rprimId); + return HdStGetRemovedPrimvarBufferSpecs(curRange, newPrimvarDescs, + HdExtComputationPrimvarDescriptorVector(), + internallyGeneratedPrimvarNames, rprimId); } // XXX: Not currently exported; does anyone else need it? HdBufferSpecVector HdStGetRemovedOrReplacedPrimvarBufferSpecs( - HdBufferArrayRangeSharedPtr const& curRange, - HdPrimvarDescriptorVector const& newPrimvarDescs, - HdExtComputationPrimvarDescriptorVector const& newCompPrimvarDescs, - TfTokenVector const& internallyGeneratedPrimvarNames, - HdBufferSpecVector const& updatedSpecs, - SdfPath const& rprimId) + HdBufferArrayRangeSharedPtr const &curRange, + HdPrimvarDescriptorVector const &newPrimvarDescs, + HdExtComputationPrimvarDescriptorVector const &newCompPrimvarDescs, + TfTokenVector const &internallyGeneratedPrimvarNames, + HdBufferSpecVector const &updatedSpecs, + SdfPath const &rprimId) { - if (!HdStIsValidBAR(curRange)) { - return HdBufferSpecVector(); - } - - HdBufferSpecVector curBarSpecs; - curRange->GetBufferSpecs(&curBarSpecs); - - HdBufferSpecVector removedOrReplacedSpecs = _GetRemovedPrimvarBufferSpecs( - curBarSpecs, newPrimvarDescs, newCompPrimvarDescs, - internallyGeneratedPrimvarNames, rprimId); - - // Sometimes the buffer spec for a given named primvar has changed, e.g., - // when an array-valued primvar has changed size. Such specs are not - // in removedSpecs at this point, so we need to add them to ensure that - // the old spec gets removed. Otherwise we will get shader compilation - // errors after the new spec has been added because the primvar variable - // will be defined twice. - - for (const auto& curSpec : curBarSpecs) { - const auto newSpec = std::find_if(updatedSpecs.begin(), - updatedSpecs.end(), - [&](const auto& spec) { return spec.name == curSpec.name; }); - // If we find a new spec that matches by name, we check if it is - // different from the old spec. If it is, it needs to be removed. - // The call to UpdateShaderStorageBufferArrayRange below will add - // the new spec regardless, but will only remove the old one if it - // is in removedSpecs. This fixes the case where resized array-valued - // constant primvars were being declared multiple times causing - // shader compilation failures. - if (newSpec != updatedSpecs.end() && - curSpec != *newSpec) { - TF_DEBUG(HD_RPRIM_UPDATED).Msg( - "%s: Found primvar %s that has been replaced\n", - rprimId.GetText(), curSpec.name.GetText()); - removedOrReplacedSpecs.push_back(curSpec); - } + if (!HdStIsValidBAR(curRange)) + { + return HdBufferSpecVector(); + } + + HdBufferSpecVector curBarSpecs; + curRange->GetBufferSpecs(&curBarSpecs); + + HdBufferSpecVector removedOrReplacedSpecs = _GetRemovedPrimvarBufferSpecs( + curBarSpecs, newPrimvarDescs, newCompPrimvarDescs, + internallyGeneratedPrimvarNames, rprimId); + + // Sometimes the buffer spec for a given named primvar has changed, e.g., + // when an array-valued primvar has changed size. Such specs are not + // in removedSpecs at this point, so we need to add them to ensure that + // the old spec gets removed. Otherwise we will get shader compilation + // errors after the new spec has been added because the primvar variable + // will be defined twice. + + for (const auto &curSpec : curBarSpecs) + { + const auto newSpec = std::find_if(updatedSpecs.begin(), + updatedSpecs.end(), + [&](const auto &spec) + { return spec.name == curSpec.name; }); + // If we find a new spec that matches by name, we check if it is + // different from the old spec. If it is, it needs to be removed. + // The call to UpdateShaderStorageBufferArrayRange below will add + // the new spec regardless, but will only remove the old one if it + // is in removedSpecs. This fixes the case where resized array-valued + // constant primvars were being declared multiple times causing + // shader compilation failures. + if (newSpec != updatedSpecs.end() && + curSpec != *newSpec) + { + TF_DEBUG(HD_RPRIM_UPDATED).Msg("%s: Found primvar %s that has been replaced\n", rprimId.GetText(), curSpec.name.GetText()); + removedOrReplacedSpecs.push_back(curSpec); } - return removedOrReplacedSpecs; + } + return removedOrReplacedSpecs; } // XXX: Not currently exported; does anyone else need it? HdBufferSpecVector HdStGetRemovedOrReplacedPrimvarBufferSpecs( - HdBufferArrayRangeSharedPtr const& curRange, - HdPrimvarDescriptorVector const& newPrimvarDescs, - TfTokenVector const& internallyGeneratedPrimvarNames, - HdBufferSpecVector const& updatedSpecs, - SdfPath const& rprimId) + HdBufferArrayRangeSharedPtr const &curRange, + HdPrimvarDescriptorVector const &newPrimvarDescs, + TfTokenVector const &internallyGeneratedPrimvarNames, + HdBufferSpecVector const &updatedSpecs, + SdfPath const &rprimId) { - return HdStGetRemovedOrReplacedPrimvarBufferSpecs( - curRange, newPrimvarDescs, - HdExtComputationPrimvarDescriptorVector(), - internallyGeneratedPrimvarNames, updatedSpecs, rprimId); + return HdStGetRemovedOrReplacedPrimvarBufferSpecs( + curRange, newPrimvarDescs, + HdExtComputationPrimvarDescriptorVector(), + internallyGeneratedPrimvarNames, updatedSpecs, rprimId); } -void -HdStUpdateDrawItemBAR( - HdBufferArrayRangeSharedPtr const& newRange, +void HdStUpdateDrawItemBAR( + HdBufferArrayRangeSharedPtr const &newRange, int drawCoordIndex, HdRprimSharedData *sharedData, HdRenderParam *renderParam, HdChangeTracker *changeTracker) { - if (!sharedData) { - TF_CODING_ERROR("Null shared data ptr received\n"); - return; + if (!sharedData) + { + TF_CODING_ERROR("Null shared data ptr received\n"); + return; + } + + HdBufferArrayRangeSharedPtr const &curRange = + sharedData->barContainer.Get(drawCoordIndex); + SdfPath const &id = sharedData->rprimID; + + if (curRange == newRange) + { + // Nothing to do. The draw item's BAR hasn't been changed. + TF_DEBUG(HD_RPRIM_UPDATED).Msg("%s: BAR at draw coord %d is still (%p)\n", id.GetText(), drawCoordIndex, curRange.get()); + + return; + } + + bool const curRangeValid = HdStIsValidBAR(curRange); + bool const newRangeValid = HdStIsValidBAR(newRange); + + if (curRangeValid) + { + HdStMarkGarbageCollectionNeeded(renderParam); + + TF_DEBUG(HD_RPRIM_UPDATED).Msg("%s: Marking garbage collection needed to possibly reclaim BAR %p" + " at draw coord index %d\n", + id.GetText(), (void *)curRange.get(), drawCoordIndex); + } + + // Flag deep batch invalidation for the following scenarios: + // 1. Invalid <-> Valid transitions. + // 2. When the new range is associated with a buffer array that + // fails the aggregation test (used during batching). + // 3. When the dispatch buffer needs to be updated for MDI batches. + // Note: This is needed only for indirect draw batches to update the + // dispatch buffer, but we prefer to not hardcode a check for + // the same. + bool const rebuildDispatchBuffer = curRangeValid && newRangeValid && + curRange->GetElementOffset() != newRange->GetElementOffset(); + + if (curRangeValid != newRangeValid || + !newRange->IsAggregatedWith(curRange) || + rebuildDispatchBuffer) + { + + HdStMarkDrawBatchesDirty(renderParam); + + if (TfDebug::IsEnabled(HD_RPRIM_UPDATED)) + { + if (curRangeValid != newRangeValid) + { + TfDebug::Helper().Msg( + "%s: Marking all batches dirty due to an invalid <-> valid" + " transition (new BAR %p, existing BAR %p)\n", + id.GetText(), newRange.get(), curRange.get()); + } + else if (!newRange->IsAggregatedWith(curRange)) + { + TfDebug::Helper().Msg( + "%s: Marking all batches dirty since the new BAR (%p) " + "doesn't aggregate with the existing BAR (%p)\n", + id.GetText(), newRange.get(), curRange.get()); + } + else + { + TfDebug::Helper().Msg( + "%s: Marking all batches dirty since the new BAR (%p) " + "doesn't aggregate with the existing BAR (%p)\n", + id.GetText(), newRange.get(), curRange.get()); + } } + } - HdBufferArrayRangeSharedPtr const& curRange = - sharedData->barContainer.Get(drawCoordIndex); - SdfPath const& id = sharedData->rprimID; + if (TfDebug::IsEnabled(HD_RPRIM_UPDATED)) + { + TfDebug::Helper().Msg( + "%s: Updating BAR at draw coord index %d from %p to %p\n", + id.GetText(), drawCoordIndex, curRange.get(), newRange.get()); - if (curRange == newRange) { - // Nothing to do. The draw item's BAR hasn't been changed. - TF_DEBUG(HD_RPRIM_UPDATED).Msg( - "%s: BAR at draw coord %d is still (%p)\n", - id.GetText(), drawCoordIndex, curRange.get()); - - return; + if (newRangeValid) + { + TfDebug::Helper().Msg( + "Buffer array version for the new range is %lu\n", + newRange->GetVersion()); } - bool const curRangeValid = HdStIsValidBAR(curRange); - bool const newRangeValid = HdStIsValidBAR(newRange); - - if (curRangeValid) { - HdStMarkGarbageCollectionNeeded(renderParam); - - TF_DEBUG(HD_RPRIM_UPDATED).Msg( - "%s: Marking garbage collection needed to possibly reclaim BAR %p" - " at draw coord index %d\n", - id.GetText(), (void*)curRange.get(), drawCoordIndex); - + HdBufferSpecVector oldSpecs; + if (curRangeValid) + { + curRange->GetBufferSpecs(&oldSpecs); } - - // Flag deep batch invalidation for the following scenarios: - // 1. Invalid <-> Valid transitions. - // 2. When the new range is associated with a buffer array that - // fails the aggregation test (used during batching). - // 3. When the dispatch buffer needs to be updated for MDI batches. - // Note: This is needed only for indirect draw batches to update the - // dispatch buffer, but we prefer to not hardcode a check for - // the same. - bool const rebuildDispatchBuffer = curRangeValid && newRangeValid && - curRange->GetElementOffset() != newRange->GetElementOffset(); - - if (curRangeValid != newRangeValid || - !newRange->IsAggregatedWith(curRange) || - rebuildDispatchBuffer) { - - HdStMarkDrawBatchesDirty(renderParam); - - if (TfDebug::IsEnabled(HD_RPRIM_UPDATED)) { - if (curRangeValid != newRangeValid) { - TfDebug::Helper().Msg( - "%s: Marking all batches dirty due to an invalid <-> valid" - " transition (new BAR %p, existing BAR %p)\n", - id.GetText(), newRange.get(), curRange.get()); - - } else if (!newRange->IsAggregatedWith(curRange)) { - TfDebug::Helper().Msg( - "%s: Marking all batches dirty since the new BAR (%p) " - "doesn't aggregate with the existing BAR (%p)\n", - id.GetText(), newRange.get(), curRange.get()); - - } else { - TfDebug::Helper().Msg( - "%s: Marking all batches dirty since the new BAR (%p) " - "doesn't aggregate with the existing BAR (%p)\n", - id.GetText(), newRange.get(), curRange.get()); - } - } + HdBufferSpecVector newSpecs; + if (newRangeValid) + { + newRange->GetBufferSpecs(&newSpecs); } + if (oldSpecs != newSpecs) + { + TfDebug::Helper().Msg("Old buffer specs:\n"); + HdBufferSpec::Dump(oldSpecs); - if (TfDebug::IsEnabled(HD_RPRIM_UPDATED)) { - TfDebug::Helper().Msg( - "%s: Updating BAR at draw coord index %d from %p to %p\n", - id.GetText(), drawCoordIndex, curRange.get(), newRange.get()); - - if (newRangeValid) { - TfDebug::Helper().Msg( - "Buffer array version for the new range is %lu\n", - newRange->GetVersion()); - } - - HdBufferSpecVector oldSpecs; - if (curRangeValid) { - curRange->GetBufferSpecs(&oldSpecs); - } - HdBufferSpecVector newSpecs; - if (newRangeValid) { - newRange->GetBufferSpecs(&newSpecs); - } - if (oldSpecs != newSpecs) { - TfDebug::Helper().Msg("Old buffer specs:\n"); - HdBufferSpec::Dump(oldSpecs); - - TfDebug::Helper().Msg("New buffer specs:\n"); - HdBufferSpec::Dump(newSpecs); - } + TfDebug::Helper().Msg("New buffer specs:\n"); + HdBufferSpec::Dump(newSpecs); } + } - // Note: This should happen at the end since curRange is a reference to - // the BAR at the drawCoordIndex. - sharedData->barContainer.Set(drawCoordIndex, newRange); + // Note: This should happen at the end since curRange is a reference to + // the BAR at the drawCoordIndex. + sharedData->barContainer.Set(drawCoordIndex, newRange); } bool HdStIsPrimvarExistentAndValid( HdRprim *prim, HdSceneDelegate *delegate, - HdPrimvarDescriptorVector const& primvars, - TfToken const& primvarName) + HdPrimvarDescriptorVector const &primvars, + TfToken const &primvarName) { - SdfPath const& id = prim->GetId(); - - for (const HdPrimvarDescriptor& pv: primvars) { - // Note: the value check here should match - // HdStIsInstancePrimvarExistentAndValid. - if (pv.name == primvarName) { - VtValue value = delegate->Get(id, pv.name); - - if (value.IsHolding() || - value.IsHolding()) { - return false; - } - - if (value.IsArrayValued() && value.GetArraySize() == 0) { - // Catch empty arrays - return false; - } - - return (!value.IsEmpty()); - } + SdfPath const &id = prim->GetId(); + + for (const HdPrimvarDescriptor &pv : primvars) + { + // Note: the value check here should match + // HdStIsInstancePrimvarExistentAndValid. + if (pv.name == primvarName) + { + VtValue value = delegate->Get(id, pv.name); + + if (value.IsHolding() || + value.IsHolding()) + { + return false; + } + + if (value.IsArrayValued() && value.GetArraySize() == 0) + { + // Catch empty arrays + return false; + } + + return (!value.IsEmpty()); } + } - return false; + return false; } // ----------------------------------------------------------------------------- // Constant primvar processing utilities // ----------------------------------------------------------------------------- -bool -HdStShouldPopulateConstantPrimvars( +bool HdStShouldPopulateConstantPrimvars( HdDirtyBits const *dirtyBits, - SdfPath const& id) + SdfPath const &id) { - return HdChangeTracker::IsAnyPrimvarDirty(*dirtyBits, id) || - HdChangeTracker::IsTransformDirty(*dirtyBits, id) || - HdChangeTracker::IsExtentDirty(*dirtyBits, id) || - HdChangeTracker::IsPrimIdDirty(*dirtyBits, id); + return HdChangeTracker::IsAnyPrimvarDirty(*dirtyBits, id) || + HdChangeTracker::IsTransformDirty(*dirtyBits, id) || + HdChangeTracker::IsExtentDirty(*dirtyBits, id) || + HdChangeTracker::IsPrimIdDirty(*dirtyBits, id); } -void -HdStPopulateConstantPrimvars( +void HdStPopulateConstantPrimvars( HdRprim *prim, HdRprimSharedData *sharedData, HdSceneDelegate *delegate, HdRenderParam *renderParam, HdStDrawItem *drawItem, HdDirtyBits *dirtyBits, - HdPrimvarDescriptorVector const& constantPrimvars, + HdPrimvarDescriptorVector const &constantPrimvars, bool *hasMirroredTransform) { - HD_TRACE_FUNCTION(); - HF_MALLOC_TAG_FUNCTION(); - - SdfPath const& id = prim->GetId(); - SdfPath const& instancerId = prim->GetInstancerId(); - - HdRenderIndex &renderIndex = delegate->GetRenderIndex(); - HdStResourceRegistrySharedPtr const& hdStResourceRegistry = - std::static_pointer_cast( - renderIndex.GetResourceRegistry()); - - // Update uniforms - HdBufferSourceSharedPtrVector sources; - if (HdChangeTracker::IsTransformDirty(*dirtyBits, id)) { - const GfMatrix4d transform = delegate->GetTransform(id); - sharedData->bounds.SetMatrix(transform); // for CPU frustum culling - - HgiCapabilities const * capabilities = - hdStResourceRegistry->GetHgi()->GetCapabilities(); - bool const doublesSupported = capabilities->IsSet( - HgiDeviceCapabilitiesBitsShaderDoublePrecision); - - sources.push_back( - std::make_shared( - HdTokens->transform, transform, doublesSupported)); - - sources.push_back( - std::make_shared( - HdTokens->transformInverse, transform.GetInverse(), - doublesSupported)); - - bool leftHanded = transform.IsLeftHanded(); - - // If this is a prototype (has instancer), - // also push the instancer transform separately. - if (!instancerId.IsEmpty()) { - // Gather all instancer transforms in the instancing hierarchy - const VtMatrix4dArray rootTransforms = - prim->GetInstancerTransforms(delegate); - VtMatrix4dArray rootInverseTransforms(rootTransforms.size()); - for (size_t i = 0; i < rootTransforms.size(); ++i) { - rootInverseTransforms[i] = rootTransforms[i].GetInverse(); - // Flip the handedness if necessary - leftHanded ^= rootTransforms[i].IsLeftHanded(); - } - - sources.push_back( - std::make_shared( - HdInstancerTokens->instancerTransform, - rootTransforms, - rootTransforms.size(), - doublesSupported)); - sources.push_back( - std::make_shared( - HdInstancerTokens->instancerTransformInverse, - rootInverseTransforms, - rootInverseTransforms.size(), - doublesSupported)); - - // XXX: It might be worth to consider to have isFlipped - // for non-instanced prims as well. It can improve - // the drawing performance on older-GPUs by reducing - // fragment shader cost, although it needs more GPU memory. - - // Set as int (GLSL needs 32-bit align for bool) - sources.push_back( - std::make_shared( - HdTokens->isFlipped, - VtValue(int(leftHanded)))); - } - - if (hasMirroredTransform) { - *hasMirroredTransform = leftHanded; - } - } - if (HdChangeTracker::IsExtentDirty(*dirtyBits, id)) { - // Note: If the scene description doesn't provide the extents, we use - // the default constructed GfRange3d which is [FLT_MAX, -FLT_MAX], - // which disables frustum culling for the prim. - sharedData->bounds.SetRange(prim->GetExtent(delegate)); - - GfVec3d const & localMin = drawItem->GetBounds().GetBox().GetMin(); - HdBufferSourceSharedPtr sourceMin = std::make_shared( - HdTokens->bboxLocalMin, - VtValue(GfVec4f( - localMin[0], - localMin[1], - localMin[2], - 1.0f))); - sources.push_back(sourceMin); - - GfVec3d const & localMax = drawItem->GetBounds().GetBox().GetMax(); - HdBufferSourceSharedPtr sourceMax = std::make_shared( - HdTokens->bboxLocalMax, - VtValue(GfVec4f( - localMax[0], - localMax[1], - localMax[2], - 1.0f))); - sources.push_back(sourceMax); + HD_TRACE_FUNCTION(); + HF_MALLOC_TAG_FUNCTION(); + + SdfPath const &id = prim->GetId(); + SdfPath const &instancerId = prim->GetInstancerId(); + + HdRenderIndex &renderIndex = delegate->GetRenderIndex(); + HdStResourceRegistrySharedPtr const &hdStResourceRegistry = + std::static_pointer_cast( + renderIndex.GetResourceRegistry()); + + // Update uniforms + HdBufferSourceSharedPtrVector sources; + if (HdChangeTracker::IsTransformDirty(*dirtyBits, id)) + { + const GfMatrix4d transform = delegate->GetTransform(id); + sharedData->bounds.SetMatrix(transform); // for CPU frustum culling + + HgiCapabilities const *capabilities = + hdStResourceRegistry->GetHgi()->GetCapabilities(); + bool const doublesSupported = capabilities->IsSet( + HgiDeviceCapabilitiesBitsShaderDoublePrecision); + + sources.push_back( + std::make_shared( + HdTokens->transform, transform, doublesSupported)); + + sources.push_back( + std::make_shared( + HdTokens->transformInverse, transform.GetInverse(), + doublesSupported)); + + bool leftHanded = transform.IsLeftHanded(); + + // If this is a prototype (has instancer), + // also push the instancer transform separately. + if (!instancerId.IsEmpty()) + { + // Gather all instancer transforms in the instancing hierarchy + const VtMatrix4dArray rootTransforms = + prim->GetInstancerTransforms(delegate); + VtMatrix4dArray rootInverseTransforms(rootTransforms.size()); + for (size_t i = 0; i < rootTransforms.size(); ++i) + { + rootInverseTransforms[i] = rootTransforms[i].GetInverse(); + // Flip the handedness if necessary + leftHanded ^= rootTransforms[i].IsLeftHanded(); + } + + sources.push_back( + std::make_shared( + HdInstancerTokens->instancerTransform, + rootTransforms, + rootTransforms.size(), + doublesSupported)); + sources.push_back( + std::make_shared( + HdInstancerTokens->instancerTransformInverse, + rootInverseTransforms, + rootInverseTransforms.size(), + doublesSupported)); + + // XXX: It might be worth to consider to have isFlipped + // for non-instanced prims as well. It can improve + // the drawing performance on older-GPUs by reducing + // fragment shader cost, although it needs more GPU memory. + + // Set as int (GLSL needs 32-bit align for bool) + sources.push_back( + std::make_shared( + HdTokens->isFlipped, + VtValue(int(leftHanded)))); } - if (HdChangeTracker::IsPrimIdDirty(*dirtyBits, id)) { - int32_t primId = prim->GetPrimId(); - HdBufferSourceSharedPtr source = std::make_shared( - HdTokens->primID, - VtValue(primId)); - sources.push_back(source); + if (hasMirroredTransform) + { + *hasMirroredTransform = leftHanded; } + } + if (HdChangeTracker::IsExtentDirty(*dirtyBits, id)) + { + // Note: If the scene description doesn't provide the extents, we use + // the default constructed GfRange3d which is [FLT_MAX, -FLT_MAX], + // which disables frustum culling for the prim. + sharedData->bounds.SetRange(prim->GetExtent(delegate)); + + GfVec3d const &localMin = drawItem->GetBounds().GetBox().GetMin(); + HdBufferSourceSharedPtr sourceMin = std::make_shared( + HdTokens->bboxLocalMin, + VtValue(GfVec4f( + localMin[0], + localMin[1], + localMin[2], + 1.0f))); + sources.push_back(sourceMin); + + GfVec3d const &localMax = drawItem->GetBounds().GetBox().GetMax(); + HdBufferSourceSharedPtr sourceMax = std::make_shared( + HdTokens->bboxLocalMax, + VtValue(GfVec4f( + localMax[0], + localMax[1], + localMax[2], + 1.0f))); + sources.push_back(sourceMax); + } + + if (HdChangeTracker::IsPrimIdDirty(*dirtyBits, id)) + { + int32_t primId = prim->GetPrimId(); + HdBufferSourceSharedPtr source = std::make_shared( + HdTokens->primID, + VtValue(primId)); + sources.push_back(source); + } + + if (HdChangeTracker::IsAnyPrimvarDirty(*dirtyBits, id)) + { + sources.reserve(sources.size() + constantPrimvars.size()); + for (const HdPrimvarDescriptor &pv : constantPrimvars) + { + if (HdChangeTracker::IsPrimvarDirty(*dirtyBits, id, pv.name)) + { + VtValue value = delegate->Get(id, pv.name); - if (HdChangeTracker::IsAnyPrimvarDirty(*dirtyBits, id)) { - sources.reserve(sources.size()+constantPrimvars.size()); - for (const HdPrimvarDescriptor& pv: constantPrimvars) { - if (HdChangeTracker::IsPrimvarDirty(*dirtyBits, id, pv.name)) { - VtValue value = delegate->Get(id, pv.name); - - // XXX Storm doesn't support string primvars yet - if (value.IsHolding() || - value.IsHolding()) { - continue; - } - - if (value.IsArrayValued() && value.GetArraySize() == 0) { - // A value holding an empty array does not count as an - // empty value. Catch that case here. - // - // Do nothing in this case. - } else if (!value.IsEmpty()) { - // Given that this is a constant primvar, if it is - // holding VtArray then use that as a single array - // value rather than as one value per element. - HdBufferSourceSharedPtr source = - std::make_shared(pv.name, value, - value.IsArrayValued() ? value.GetArraySize() : 1); - - TF_VERIFY(source->GetTupleType().type != HdTypeInvalid); - TF_VERIFY(source->GetTupleType().count > 0); - sources.push_back(source); - } - } + // XXX Storm doesn't support string primvars yet + if (value.IsHolding() || + value.IsHolding()) + { + continue; + } + + if (value.IsArrayValued() && value.GetArraySize() == 0) + { + // A value holding an empty array does not count as an + // empty value. Catch that case here. + // + // Do nothing in this case. } + else if (!value.IsEmpty()) + { + // Given that this is a constant primvar, if it is + // holding VtArray then use that as a single array + // value rather than as one value per element. + HdBufferSourceSharedPtr source = + std::make_shared(pv.name, value, + value.IsArrayValued() ? value.GetArraySize() : 1); + + TF_VERIFY(source->GetTupleType().type != HdTypeInvalid); + TF_VERIFY(source->GetTupleType().count > 0); + sources.push_back(source); + } + } } + } - HdBufferArrayRangeSharedPtr const& bar = - drawItem->GetConstantPrimvarRange(); + HdBufferArrayRangeSharedPtr const &bar = + drawItem->GetConstantPrimvarRange(); - if (HdStCanSkipBARAllocationOrUpdate(sources, bar, *dirtyBits)) { - return; - } + if (HdStCanSkipBARAllocationOrUpdate(sources, bar, *dirtyBits)) + { + return; + } - HdBufferSpecVector bufferSpecs; - HdBufferSpec::GetBufferSpecs(sources, &bufferSpecs); + HdBufferSpecVector bufferSpecs; + HdBufferSpec::GetBufferSpecs(sources, &bufferSpecs); - // XXX: This should be based off the DirtyPrimvarDesc bit. - bool hasDirtyPrimvarDesc = (*dirtyBits & HdChangeTracker::DirtyPrimvar); - HdBufferSpecVector removedSpecs; - if (hasDirtyPrimvarDesc) { - static TfTokenVector internallyGeneratedPrimvars = + // XXX: This should be based off the DirtyPrimvarDesc bit. + bool hasDirtyPrimvarDesc = (*dirtyBits & HdChangeTracker::DirtyPrimvar); + HdBufferSpecVector removedSpecs; + if (hasDirtyPrimvarDesc) + { + static TfTokenVector internallyGeneratedPrimvars = { HdTokens->transform, HdTokens->transformInverse, @@ -907,38 +947,37 @@ HdStPopulateConstantPrimvars( HdTokens->isFlipped, HdTokens->bboxLocalMin, HdTokens->bboxLocalMax, - HdTokens->primID - }; - removedSpecs = HdStGetRemovedOrReplacedPrimvarBufferSpecs(bar, - constantPrimvars, internallyGeneratedPrimvars, bufferSpecs, id); - } - - HdBufferArrayRangeSharedPtr range = - hdStResourceRegistry->UpdateShaderStorageBufferArrayRange( - HdTokens->primvar, bar, bufferSpecs, removedSpecs, - HdBufferArrayUsageHint()); - - HdStUpdateDrawItemBAR( - range, - drawItem->GetDrawingCoord()->GetConstantPrimvarIndex(), - sharedData, - renderParam, - &(renderIndex.GetChangeTracker())); - - TF_VERIFY(drawItem->GetConstantPrimvarRange()->IsValid()); - - if (!sources.empty()) { - hdStResourceRegistry->AddSources( - drawItem->GetConstantPrimvarRange(), std::move(sources)); - } + HdTokens->primID}; + removedSpecs = HdStGetRemovedOrReplacedPrimvarBufferSpecs(bar, + constantPrimvars, internallyGeneratedPrimvars, bufferSpecs, id); + } + + HdBufferArrayRangeSharedPtr range = + hdStResourceRegistry->UpdateShaderStorageBufferArrayRange( + HdTokens->primvar, bar, bufferSpecs, removedSpecs, + HdBufferArrayUsageHint()); + + HdStUpdateDrawItemBAR( + range, + drawItem->GetDrawingCoord()->GetConstantPrimvarIndex(), + sharedData, + renderParam, + &(renderIndex.GetChangeTracker())); + + TF_VERIFY(drawItem->GetConstantPrimvarRange()->IsValid()); + + if (!sources.empty()) + { + hdStResourceRegistry->AddSources( + drawItem->GetConstantPrimvarRange(), std::move(sources)); + } } // ----------------------------------------------------------------------------- // Instancer processing utilities // ----------------------------------------------------------------------------- -void -HdStUpdateInstancerData( +void HdStUpdateInstancerData( HdRenderIndex &renderIndex, HdRenderParam *renderParam, HdRprim *prim, @@ -946,197 +985,213 @@ HdStUpdateInstancerData( HdRprimSharedData *sharedData, HdDirtyBits rprimDirtyBits) { - // If there's nothing to do, bail. - if (!(rprimDirtyBits & HdChangeTracker::DirtyInstancer)) { - return; - } - - // XXX: This belongs in HdRenderIndex!!! - HdInstancer::_SyncInstancerAndParents(renderIndex, prim->GetInstancerId()); - - HdDrawingCoord *drawingCoord = drawItem->GetDrawingCoord(); - HdChangeTracker &changeTracker = renderIndex.GetChangeTracker(); - - // If the instance topology changes, we want to force an instance index - // rebuild even if the index dirty bit isn't set... - bool forceIndexRebuild = false; - - if (rprimDirtyBits & HdChangeTracker::DirtyInstancer) { - // If the instancer topology has changed, we might need to change - // how many levels we allocate in the drawing coord. - int instancerLevels = HdInstancer::GetInstancerNumLevels( - renderIndex, *prim); + // If there's nothing to do, bail. + if (!(rprimDirtyBits & HdChangeTracker::DirtyInstancer)) + { + return; + } + + // XXX: This belongs in HdRenderIndex!!! + HdInstancer::_SyncInstancerAndParents(renderIndex, prim->GetInstancerId()); + + HdDrawingCoord *drawingCoord = drawItem->GetDrawingCoord(); + HdChangeTracker &changeTracker = renderIndex.GetChangeTracker(); + + // If the instance topology changes, we want to force an instance index + // rebuild even if the index dirty bit isn't set... + bool forceIndexRebuild = false; + + if (rprimDirtyBits & HdChangeTracker::DirtyInstancer) + { + // If the instancer topology has changed, we might need to change + // how many levels we allocate in the drawing coord. + int instancerLevels = HdInstancer::GetInstancerNumLevels( + renderIndex, *prim); + + if (instancerLevels != sharedData->instancerLevels) + { + sharedData->barContainer.Resize( + drawingCoord->GetInstancePrimvarIndex(0) + instancerLevels); + sharedData->instancerLevels = instancerLevels; - if (instancerLevels != sharedData->instancerLevels) { - sharedData->barContainer.Resize( - drawingCoord->GetInstancePrimvarIndex(0) + instancerLevels); - sharedData->instancerLevels = instancerLevels; + HdStMarkGarbageCollectionNeeded(renderParam); + HdStMarkDrawBatchesDirty(renderParam); + forceIndexRebuild = true; + } + } + + /* INSTANCE PRIMVARS */ + // Populate all instance primvars by backtracing hierarachy. + int level = 0; + SdfPath parentId = prim->GetInstancerId(); + while (!parentId.IsEmpty()) + { + HdInstancer *const instancer = renderIndex.GetInstancer(parentId); + if (!TF_VERIFY(instancer)) + { + return; + } + const int drawCoordIndex = drawingCoord->GetInstancePrimvarIndex(level); + HdBufferArrayRangeSharedPtr const instancerRange = + static_cast(instancer)->GetInstancePrimvarRange(); - HdStMarkGarbageCollectionNeeded(renderParam); - HdStMarkDrawBatchesDirty(renderParam); - forceIndexRebuild = true; - } + // If we need to update the BAR, that indicates an instancing topology + // change and we want to force an index rebuild. + if (instancerRange != sharedData->barContainer.Get(drawCoordIndex)) + { + forceIndexRebuild = true; } - /* INSTANCE PRIMVARS */ - // Populate all instance primvars by backtracing hierarachy. - int level = 0; - SdfPath parentId = prim->GetInstancerId(); - while (!parentId.IsEmpty()) { - HdInstancer * const instancer = renderIndex.GetInstancer(parentId); - if(!TF_VERIFY(instancer)) { - return; - } - const int drawCoordIndex = drawingCoord->GetInstancePrimvarIndex(level); - HdBufferArrayRangeSharedPtr const instancerRange = - static_cast(instancer)->GetInstancePrimvarRange(); - - // If we need to update the BAR, that indicates an instancing topology - // change and we want to force an index rebuild. - if (instancerRange != sharedData->barContainer.Get(drawCoordIndex)) { - forceIndexRebuild = true; - } + // update instance primvar slot in the drawing coordinate. + HdStUpdateDrawItemBAR( + static_cast(instancer)->GetInstancePrimvarRange(), + drawCoordIndex, + sharedData, + renderParam, + &changeTracker); + + parentId = instancer->GetParentId(); + ++level; + } + + /* INSTANCE INDICES */ + // Note, GetInstanceIndices will check index sizes against primvar sizes. + // The instance indices are a cartesian product of each level, so they need + // to be recomputed per-rprim. + if (HdChangeTracker::IsInstanceIndexDirty(rprimDirtyBits, prim->GetId()) || + forceIndexRebuild) + { + parentId = prim->GetInstancerId(); + if (!parentId.IsEmpty()) + { + HdInstancer *const instancer = renderIndex.GetInstancer(parentId); + if (!TF_VERIFY(instancer)) + { + return; + } + + // update instance indices + // + // We add a zero as the first value in instanceIndices. This is + // added as a way of avoiding correctness issues in the instance + // frustum cull vertex shader. This issue happens when an instanced + // prim has geom subsets resulting in multiple draw items. See + // ViewFrustumCull.VertexInstancing in frustumCull.glslfx for + // details. + VtIntArray const originalInstanceIndices = + static_cast(instancer)->GetInstanceIndices(prim->GetId()); + VtIntArray instanceIndices = + VtIntArray(originalInstanceIndices.size() + 1); + instanceIndices[0] = 0; + std::copy(originalInstanceIndices.cbegin(), + originalInstanceIndices.cend(), + instanceIndices.begin() + 1); + + HdStResourceRegistry *const resourceRegistry = + static_cast( + renderIndex.GetResourceRegistry().get()); + + // Create the bar if needed. + if (!drawItem->GetInstanceIndexRange()) + { + + // Note: we add the instance indices twice, so that frustum + // culling can compute culledInstanceIndices as instanceIndices + // masked by visibility. + HdBufferSpecVector bufferSpecs; + bufferSpecs.emplace_back( + HdInstancerTokens->instanceIndices, + HdTupleType{HdTypeInt32, 1}); + bufferSpecs.emplace_back( + HdInstancerTokens->culledInstanceIndices, + HdTupleType{HdTypeInt32, 1}); + + HdBufferArrayRangeSharedPtr const range = + resourceRegistry->AllocateNonUniformBufferArrayRange( + HdTokens->topology, + bufferSpecs, + HdBufferArrayUsageHint()); - // update instance primvar slot in the drawing coordinate. HdStUpdateDrawItemBAR( - static_cast(instancer)->GetInstancePrimvarRange(), - drawCoordIndex, + range, + drawingCoord->GetInstanceIndexIndex(), sharedData, renderParam, &changeTracker); - parentId = instancer->GetParentId(); - ++level; - } - - /* INSTANCE INDICES */ - // Note, GetInstanceIndices will check index sizes against primvar sizes. - // The instance indices are a cartesian product of each level, so they need - // to be recomputed per-rprim. - if (HdChangeTracker::IsInstanceIndexDirty(rprimDirtyBits, prim->GetId()) || - forceIndexRebuild) { - parentId = prim->GetInstancerId(); - if (!parentId.IsEmpty()) { - HdInstancer * const instancer = renderIndex.GetInstancer(parentId); - if (!TF_VERIFY(instancer)) { - return; - } - - // update instance indices - // - // We add a zero as the first value in instanceIndices. This is - // added as a way of avoiding correctness issues in the instance - // frustum cull vertex shader. This issue happens when an instanced - // prim has geom subsets resulting in multiple draw items. See - // ViewFrustumCull.VertexInstancing in frustumCull.glslfx for - // details. - VtIntArray const originalInstanceIndices = - static_cast(instancer)-> - GetInstanceIndices(prim->GetId()); - VtIntArray instanceIndices = - VtIntArray(originalInstanceIndices.size() + 1); - instanceIndices[0] = 0; - std::copy(originalInstanceIndices.cbegin(), - originalInstanceIndices.cend(), - instanceIndices.begin() + 1); - - HdStResourceRegistry* const resourceRegistry = - static_cast( - renderIndex.GetResourceRegistry().get()); - - // Create the bar if needed. - if (!drawItem->GetInstanceIndexRange()) { - - // Note: we add the instance indices twice, so that frustum - // culling can compute culledInstanceIndices as instanceIndices - // masked by visibility. - HdBufferSpecVector bufferSpecs; - bufferSpecs.emplace_back( - HdInstancerTokens->instanceIndices, - HdTupleType {HdTypeInt32, 1}); - bufferSpecs.emplace_back( - HdInstancerTokens->culledInstanceIndices, - HdTupleType {HdTypeInt32, 1}); - - HdBufferArrayRangeSharedPtr const range = - resourceRegistry->AllocateNonUniformBufferArrayRange( - HdTokens->topology, - bufferSpecs, - HdBufferArrayUsageHint()); - - HdStUpdateDrawItemBAR( - range, - drawingCoord->GetInstanceIndexIndex(), - sharedData, - renderParam, - &changeTracker); - - TF_VERIFY(drawItem->GetInstanceIndexRange()->IsValid()); - } - - // If the instance index range is too big to upload, it's very - // dangerous since the shader could index into bad memory. If we're - // not failing on asserts, we need to zero out the index array so no - // instances draw. - if (!TF_VERIFY(instanceIndices.size() <= - drawItem->GetInstanceIndexRange()->GetMaxNumElements())) { - instanceIndices = VtIntArray(); - } - - HdBufferSourceSharedPtrVector sources; - sources.push_back( - std::make_shared( - HdInstancerTokens->instanceIndices, - VtValue(instanceIndices))); - sources.push_back( - std::make_shared( - HdInstancerTokens->culledInstanceIndices, - VtValue(instanceIndices))); - - resourceRegistry->AddSources( - drawItem->GetInstanceIndexRange(), std::move(sources)); - } + TF_VERIFY(drawItem->GetInstanceIndexRange()->IsValid()); + } + + // If the instance index range is too big to upload, it's very + // dangerous since the shader could index into bad memory. If we're + // not failing on asserts, we need to zero out the index array so no + // instances draw. + if (!TF_VERIFY(instanceIndices.size() <= + drawItem->GetInstanceIndexRange()->GetMaxNumElements())) + { + instanceIndices = VtIntArray(); + } + + HdBufferSourceSharedPtrVector sources; + sources.push_back( + std::make_shared( + HdInstancerTokens->instanceIndices, + VtValue(instanceIndices))); + sources.push_back( + std::make_shared( + HdInstancerTokens->culledInstanceIndices, + VtValue(instanceIndices))); + + resourceRegistry->AddSources( + drawItem->GetInstanceIndexRange(), std::move(sources)); } + } } bool HdStIsInstancePrimvarExistentAndValid( HdRenderIndex &renderIndex, HdRprim *rprim, - TfToken const& primvarName) + TfToken const &primvarName) { - SdfPath parentId = rprim->GetInstancerId(); - while (!parentId.IsEmpty()) { - HdInstancer * const instancer = renderIndex.GetInstancer(parentId); - if (!TF_VERIFY(instancer)) { - return false; - } + SdfPath parentId = rprim->GetInstancerId(); + while (!parentId.IsEmpty()) + { + HdInstancer *const instancer = renderIndex.GetInstancer(parentId); + if (!TF_VERIFY(instancer)) + { + return false; + } - HdPrimvarDescriptorVector const primvars = - instancer->GetDelegate()->GetPrimvarDescriptors(instancer->GetId(), - HdInterpolationInstance); - - for (const HdPrimvarDescriptor& pv : primvars) { - // We're looking for a primvar with the given name at any level - // (since instance primvars aggregate). Note: the value check here - // must match HdStIsPrimvarExistentAndValid. - if (pv.name == primvarName) { - const VtValue value = - instancer->GetDelegate()->Get(instancer->GetId(), pv.name); - if (value.IsHolding() || - value.IsHolding()) { - return false; - } - if (value.IsArrayValued() && value.GetArraySize() == 0) { - return false; - } - return (!value.IsEmpty()); - } - } + HdPrimvarDescriptorVector const primvars = + instancer->GetDelegate()->GetPrimvarDescriptors(instancer->GetId(), + HdInterpolationInstance); - parentId = instancer->GetParentId(); + for (const HdPrimvarDescriptor &pv : primvars) + { + // We're looking for a primvar with the given name at any level + // (since instance primvars aggregate). Note: the value check here + // must match HdStIsPrimvarExistentAndValid. + if (pv.name == primvarName) + { + const VtValue value = + instancer->GetDelegate()->Get(instancer->GetId(), pv.name); + if (value.IsHolding() || + value.IsHolding()) + { + return false; + } + if (value.IsArrayValued() && value.GetArraySize() == 0) + { + return false; + } + return (!value.IsEmpty()); + } } - return false; + parentId = instancer->GetParentId(); + } + + return false; } // ----------------------------------------------------------------------------- @@ -1148,29 +1203,32 @@ bool HdStIsInstancePrimvarExistentAndValid( // visibility of each indexed entity. static HdBufferSourceSharedPtr _GetBitmaskEncodedVisibilityBuffer(VtIntArray invisibleIndices, - int numTotalIndices, - TfToken const& bufferName, - SdfPath const& rprimId) + int numTotalIndices, + TfToken const &bufferName, + SdfPath const &rprimId) { - size_t numBitsPerUInt = std::numeric_limits::digits; // i.e, 32 - size_t numUIntsNeeded = ceil(numTotalIndices/(float) numBitsPerUInt); - // Initialize all bits to 1 (visible) - VtArray visibility(numUIntsNeeded, - std::numeric_limits::max()); - - for (VtIntArray::const_iterator i = invisibleIndices.begin(), - end = invisibleIndices.end(); i != end; ++i) { - if (*i >= numTotalIndices || *i < 0) { - // This invisible index is out of range. Ignore it silently. - continue; - } - const size_t arrayIndex = *i/numBitsPerUInt; - const size_t bitIndex = *i % numBitsPerUInt; - visibility[arrayIndex] &= ~(1 << bitIndex); // set bit to 0 + size_t numBitsPerUInt = std::numeric_limits::digits; // i.e, 32 + size_t numUIntsNeeded = ceil(numTotalIndices / (float)numBitsPerUInt); + // Initialize all bits to 1 (visible) + VtArray visibility(numUIntsNeeded, + std::numeric_limits::max()); + + for (VtIntArray::const_iterator i = invisibleIndices.begin(), + end = invisibleIndices.end(); + i != end; ++i) + { + if (*i >= numTotalIndices || *i < 0) + { + // This invisible index is out of range. Ignore it silently. + continue; } + const size_t arrayIndex = *i / numBitsPerUInt; + const size_t bitIndex = *i % numBitsPerUInt; + visibility[arrayIndex] &= ~(1 << bitIndex); // set bit to 0 + } - return std::make_shared( - bufferName, VtValue(visibility), numUIntsNeeded); + return std::make_shared( + bufferName, VtValue(visibility), numUIntsNeeded); } void HdStProcessTopologyVisibility( @@ -1183,75 +1241,80 @@ void HdStProcessTopologyVisibility( HdRenderParam *renderParam, HdChangeTracker *changeTracker, HdStResourceRegistrySharedPtr const &resourceRegistry, - SdfPath const& rprimId) + SdfPath const &rprimId) { - HD_TRACE_FUNCTION(); - HF_MALLOC_TAG_FUNCTION(); - HdBufferArrayRangeSharedPtr tvBAR = drawItem->GetTopologyVisibilityRange(); - HdBufferSourceSharedPtrVector sources; - - // For the general case wherein there is no topological invisibility, we - // don't create a BAR. - // If any topological invisibility is authored (points/elements), create the - // BAR with both sources. Once the BAR is created, we don't attempt to - // delete it when there's no topological invisibility authored; we simply - // reset the bits to make all elements/points visible. - if (tvBAR || (!invisibleElements.empty() || !invisiblePoints.empty())) { - sources.push_back(_GetBitmaskEncodedVisibilityBuffer( - invisibleElements, - numTotalElements, - HdTokens->elementsVisibility, - rprimId)); - sources.push_back(_GetBitmaskEncodedVisibilityBuffer( - invisiblePoints, - numTotalPoints, - HdTokens->pointsVisibility, - rprimId)); - } - - // Exit early if the BAR doesn't need to be allocated. - if (!tvBAR && sources.empty()) return; - - HdBufferSpecVector bufferSpecs; - HdBufferSpec::GetBufferSpecs(sources, &bufferSpecs); - bool barNeedsReallocation = false; - if (tvBAR) { - HdBufferSpecVector oldBufferSpecs; - tvBAR->GetBufferSpecs(&oldBufferSpecs); - if (oldBufferSpecs != bufferSpecs) { - barNeedsReallocation = true; - } + HD_TRACE_FUNCTION(); + HF_MALLOC_TAG_FUNCTION(); + HdBufferArrayRangeSharedPtr tvBAR = drawItem->GetTopologyVisibilityRange(); + HdBufferSourceSharedPtrVector sources; + + // For the general case wherein there is no topological invisibility, we + // don't create a BAR. + // If any topological invisibility is authored (points/elements), create the + // BAR with both sources. Once the BAR is created, we don't attempt to + // delete it when there's no topological invisibility authored; we simply + // reset the bits to make all elements/points visible. + if (tvBAR || (!invisibleElements.empty() || !invisiblePoints.empty())) + { + sources.push_back(_GetBitmaskEncodedVisibilityBuffer( + invisibleElements, + numTotalElements, + HdTokens->elementsVisibility, + rprimId)); + sources.push_back(_GetBitmaskEncodedVisibilityBuffer( + invisiblePoints, + numTotalPoints, + HdTokens->pointsVisibility, + rprimId)); + } + + // Exit early if the BAR doesn't need to be allocated. + if (!tvBAR && sources.empty()) + return; + + HdBufferSpecVector bufferSpecs; + HdBufferSpec::GetBufferSpecs(sources, &bufferSpecs); + bool barNeedsReallocation = false; + if (tvBAR) + { + HdBufferSpecVector oldBufferSpecs; + tvBAR->GetBufferSpecs(&oldBufferSpecs); + if (oldBufferSpecs != bufferSpecs) + { + barNeedsReallocation = true; } + } - // XXX: Transition this code to use the Update* method instead. - if (!tvBAR || barNeedsReallocation) { - HdBufferArrayRangeSharedPtr range = - resourceRegistry->AllocateShaderStorageBufferArrayRange( - HdTokens->topologyVisibility, - bufferSpecs, - HdBufferArrayUsageHint()); - sharedData->barContainer.Set( - drawItem->GetDrawingCoord()->GetTopologyVisibilityIndex(), range); + // XXX: Transition this code to use the Update* method instead. + if (!tvBAR || barNeedsReallocation) + { + HdBufferArrayRangeSharedPtr range = + resourceRegistry->AllocateShaderStorageBufferArrayRange( + HdTokens->topologyVisibility, + bufferSpecs, + HdBufferArrayUsageHint()); + sharedData->barContainer.Set( + drawItem->GetDrawingCoord()->GetTopologyVisibilityIndex(), range); - HdStMarkDrawBatchesDirty(renderParam); + HdStMarkDrawBatchesDirty(renderParam); - if (barNeedsReallocation) { - HdStMarkGarbageCollectionNeeded(renderParam); - } + if (barNeedsReallocation) + { + HdStMarkGarbageCollectionNeeded(renderParam); } + } - TF_VERIFY(drawItem->GetTopologyVisibilityRange()->IsValid()); + TF_VERIFY(drawItem->GetTopologyVisibilityRange()->IsValid()); - resourceRegistry->AddSources( - drawItem->GetTopologyVisibilityRange(), std::move(sources)); + resourceRegistry->AddSources( + drawItem->GetTopologyVisibilityRange(), std::move(sources)); } -bool -HdStIsEnabledSharedVertexPrimvar() +bool HdStIsEnabledSharedVertexPrimvar() { - static bool enabled = - (TfGetEnvSetting(HDST_ENABLE_SHARED_VERTEX_PRIMVAR) == 1); - return enabled; + static bool enabled = + (TfGetEnvSetting(HDST_ENABLE_SHARED_VERTEX_PRIMVAR) == 1); + return enabled; } uint64_t @@ -1260,50 +1323,56 @@ HdStComputeSharedPrimvarId( HdBufferSourceSharedPtrVector const &sources, HdStComputationComputeQueuePairVector const &computations) { - size_t primvarId = baseId; - for (HdBufferSourceSharedPtr const &bufferSource : sources) { - size_t sourceId = bufferSource->ComputeHash(); - primvarId = ArchHash64((const char*)&sourceId, - sizeof(sourceId), primvarId); - - if (bufferSource->HasPreChainedBuffer()) { - HdBufferSourceSharedPtr src = bufferSource->GetPreChainedBuffer(); - - while (src) { - size_t chainedSourceId = bufferSource->ComputeHash(); - primvarId = ArchHash64((const char*)&chainedSourceId, - sizeof(chainedSourceId), primvarId); - - src = src->GetPreChainedBuffer(); - } - } + size_t primvarId = baseId; + for (HdBufferSourceSharedPtr const &bufferSource : sources) + { + size_t sourceId = bufferSource->ComputeHash(); + primvarId = ArchHash64((const char *)&sourceId, + sizeof(sourceId), primvarId); + + if (bufferSource->HasPreChainedBuffer()) + { + HdBufferSourceSharedPtr src = bufferSource->GetPreChainedBuffer(); + + while (src) + { + size_t chainedSourceId = bufferSource->ComputeHash(); + primvarId = ArchHash64((const char *)&chainedSourceId, + sizeof(chainedSourceId), primvarId); + + src = src->GetPreChainedBuffer(); + } } + } - for (const auto& computation : computations) { - if (std::shared_ptr refinedComputation = + for (const auto &computation : computations) + { + if (std::shared_ptr refinedComputation = std::dynamic_pointer_cast( - computation.first)) { - primvarId = TfHash::Combine(primvarId, - refinedComputation->GetInterpolation()); - } + computation.first)) + { + primvarId = TfHash::Combine(primvarId, + refinedComputation->GetInterpolation()); } - HdBufferSpecVector bufferSpecs; - HdStGetBufferSpecsFromCompuations(computations, &bufferSpecs); + } + HdBufferSpecVector bufferSpecs; + HdStGetBufferSpecsFromCompuations(computations, &bufferSpecs); - return TfHash::Combine(primvarId, bufferSpecs); + return TfHash::Combine(primvarId, bufferSpecs); } -void -HdStGetBufferSpecsFromCompuations( - HdStComputationComputeQueuePairVector const& computations, - HdBufferSpecVector *bufferSpecs) +void HdStGetBufferSpecsFromCompuations( + HdStComputationComputeQueuePairVector const &computations, + HdBufferSpecVector *bufferSpecs) { - for (auto const &compQueuePair : computations) { - HdStComputationSharedPtr const& comp = compQueuePair.first; - if (comp->IsValid()) { - comp->GetBufferSpecs(bufferSpecs); - } + for (auto const &compQueuePair : computations) + { + HdStComputationSharedPtr const &comp = compQueuePair.first; + if (comp->IsValid()) + { + comp->GetBufferSpecs(bufferSpecs); } + } } PXR_NAMESPACE_CLOSE_SCOPE diff --git a/Sources/OpenUSD/imaging/hdSt/ptexMipmapTextureLoader.cpp b/Sources/OpenUSD/imaging/hdSt/ptexMipmapTextureLoader.cpp index 1d976e464c..bf6efdc4d0 100644 --- a/Sources/OpenUSD/imaging/hdSt/ptexMipmapTextureLoader.cpp +++ b/Sources/OpenUSD/imaging/hdSt/ptexMipmapTextureLoader.cpp @@ -23,7 +23,7 @@ // #include "pxr/imaging/hdSt/ptexMipmapTextureLoader.h" -#include "pxr/base/arch/fileSystem.h" +#include "Arch/fileSystem.h" #include "pxr/base/tf/diagnostic.h" #include @@ -35,316 +35,336 @@ PXR_NAMESPACE_OPEN_SCOPE - // sample neighbor pixels and populate around blocks -void -HdStPtexMipmapTextureLoader::Block::guttering( +void HdStPtexMipmapTextureLoader::Block::guttering( HdStPtexMipmapTextureLoader *loader, PtexTexture *ptex, int level, int wid, int hei, unsigned char *pptr, int bpp, int stride) { - int lineBufferSize = std::max(wid, hei) * bpp; - unsigned char * lineBuffer = new unsigned char[lineBufferSize]; - - int numEdges = ptex->meshType() == Ptex::mt_triangle ? 3 : 4; - - for (int edge = 0; edge < numEdges; edge++) { - int len = (edge == 0 || edge == 2) ? wid : hei; - loader->sampleNeighbor(lineBuffer, this->index, edge, len, bpp); - - unsigned char *s = lineBuffer, *d; - for (int j = 0; j < len; ++j) { - d = pptr; - switch (edge) { - case Ptex::e_bottom: - d += bpp * (j + 1); - break; - case Ptex::e_right: - d += stride * (j + 1) + bpp * (wid+1); - break; - case Ptex::e_top: - d += stride * (hei+1) + bpp*(len-j); - break; - case Ptex::e_left: - d += stride * (len-j); - break; - } - for (int k = 0; k < bpp; k++) - *d++ = *s++; - } - } - delete[] lineBuffer; + int lineBufferSize = std::max(wid, hei) * bpp; + unsigned char *lineBuffer = new unsigned char[lineBufferSize]; - // fix corner pixels - int numchannels = ptex->numChannels(); - float *accumPixel = new float[numchannels]; - int uv[4][2] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}}; + int numEdges = ptex->meshType() == Ptex::mt_triangle ? 3 : 4; + for (int edge = 0; edge < numEdges; edge++) + { + int len = (edge == 0 || edge == 2) ? wid : hei; + loader->sampleNeighbor(lineBuffer, this->index, edge, len, bpp); - for (int edge = 0; edge < numEdges; edge++) { - int du = uv[edge][0]; - int dv = uv[edge][1]; - - /* There are 3 cases when filling a corner pixel on gutter. - - case 1: Regular 4 valence - We already have correct 'B' and 'C' pixels by edge - resampling above. - so here only one more pixel 'D' is needed, - and it will be placed on the gutter corner. - +-----+-----+ - | | |<-current - | B|A | - +-----*-----+ - | D|C | - | | | - +-----+-----+ - - case 2: T-vertex case (note that this doesn't mean 3 valence) - If the current face comes from non-quad root face, there - could be a T-vertex on its corner. Just like case 1, - need to fill border corner with pixel 'D'. - +-----+-----+ - | | |<-current - | B|A | - | *-----+ - | D|C | - | | | - +-----+-----+ - - case 3: Other than 4 valence case - (everything else, including boundary) - Since guttering pixels are placed on the border of each - ptex faces, it's not possible to store more than 4 pixels - at a coner for a reasonable interpolation. - In this case, we need to average all corner pixels and - overwrite with an averaged value, so that every face - vertex picks the same value. - +---+---+ - | | |<-current - | B|A | - +---*---| - | D/E\C | - | / \ | - |/ \| - +-------+ - */ - - // seamless mipmap only works with square faces. - if (loader->getCornerPixel(accumPixel, numchannels, - this->index, edge, (int8_t)(this->ulog2-level))) { - // case1, case 2 - if (edge == 1 || edge == 2) du += wid; - if (edge == 2 || edge == 3) dv += hei; - unsigned char *d = pptr + dv*stride + du*bpp; - Ptex::ConvertFromFloat(d, accumPixel, - ptex->dataType(), numchannels); - } else { - // case 3, set accumPixel to the corner 4 pixels - if (edge == 1 || edge == 2) du += wid - 1; - if (edge == 2 || edge == 3) dv += hei - 1; - for (int x = 0; x < 2; ++x) { - for (int y = 0; y < 2; ++y) { - unsigned char *d = pptr + (dv+x)*stride + (du+y)*bpp; - Ptex::ConvertFromFloat(d, accumPixel, - ptex->dataType(), numchannels); - } - } + unsigned char *s = lineBuffer, *d; + for (int j = 0; j < len; ++j) + { + d = pptr; + switch (edge) + { + case Ptex::e_bottom: + d += bpp * (j + 1); + break; + case Ptex::e_right: + d += stride * (j + 1) + bpp * (wid + 1); + break; + case Ptex::e_top: + d += stride * (hei + 1) + bpp * (len - j); + break; + case Ptex::e_left: + d += stride * (len - j); + break; + } + for (int k = 0; k < bpp; k++) + *d++ = *s++; + } + } + delete[] lineBuffer; + + // fix corner pixels + int numchannels = ptex->numChannels(); + float *accumPixel = new float[numchannels]; + int uv[4][2] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}}; + + for (int edge = 0; edge < numEdges; edge++) + { + int du = uv[edge][0]; + int dv = uv[edge][1]; + + /* There are 3 cases when filling a corner pixel on gutter. + + case 1: Regular 4 valence + We already have correct 'B' and 'C' pixels by edge + resampling above. + so here only one more pixel 'D' is needed, + and it will be placed on the gutter corner. + +-----+-----+ + | | |<-current + | B|A | + +-----*-----+ + | D|C | + | | | + +-----+-----+ + + case 2: T-vertex case (note that this doesn't mean 3 valence) + If the current face comes from non-quad root face, there + could be a T-vertex on its corner. Just like case 1, + need to fill border corner with pixel 'D'. + +-----+-----+ + | | |<-current + | B|A | + | *-----+ + | D|C | + | | | + +-----+-----+ + + case 3: Other than 4 valence case + (everything else, including boundary) + Since guttering pixels are placed on the border of each + ptex faces, it's not possible to store more than 4 pixels + at a coner for a reasonable interpolation. + In this case, we need to average all corner pixels and + overwrite with an averaged value, so that every face + vertex picks the same value. + +---+---+ + | | |<-current + | B|A | + +---*---| + | D/E\C | + | / \ | + |/ \| + +-------+ + */ + + // seamless mipmap only works with square faces. + if (loader->getCornerPixel(accumPixel, numchannels, + this->index, edge, (int8_t)(this->ulog2 - level))) + { + // case1, case 2 + if (edge == 1 || edge == 2) + du += wid; + if (edge == 2 || edge == 3) + dv += hei; + unsigned char *d = pptr + dv * stride + du * bpp; + Ptex::ConvertFromFloat(d, accumPixel, + ptex->dataType(), numchannels); + } + else + { + // case 3, set accumPixel to the corner 4 pixels + if (edge == 1 || edge == 2) + du += wid - 1; + if (edge == 2 || edge == 3) + dv += hei - 1; + for (int x = 0; x < 2; ++x) + { + for (int y = 0; y < 2; ++y) + { + unsigned char *d = pptr + (dv + x) * stride + (du + y) * bpp; + Ptex::ConvertFromFloat(d, accumPixel, + ptex->dataType(), numchannels); } + } } - delete[] accumPixel; + } + delete[] accumPixel; } -void -HdStPtexMipmapTextureLoader::Block::Generate( +void HdStPtexMipmapTextureLoader::Block::Generate( HdStPtexMipmapTextureLoader *loader, PtexTexture *ptex, unsigned char *destination, int bpp, int wid, int maxLevels) { - const Ptex::FaceInfo &faceInfo = ptex->getFaceInfo(index); - int stride = bpp * wid; + const Ptex::FaceInfo &faceInfo = ptex->getFaceInfo(index); + int stride = bpp * wid; - int ulog2_ = this->ulog2; - int vlog2_ = this->vlog2; + int ulog2_ = this->ulog2; + int vlog2_ = this->vlog2; - int level = 0; - int uofs = u, vofs = v; + int level = 0; + int uofs = u, vofs = v; - // The minimum size of non-subface is 4x4, so that it matches with adjacent - // 2x2 subfaces. - int limit = faceInfo.isSubface() ? 1 : 2; + // The minimum size of non-subface is 4x4, so that it matches with adjacent + // 2x2 subfaces. + int limit = faceInfo.isSubface() ? 1 : 2; - // but if the base size is already less than limit, we'd like to pick it - // instead of nothing. - limit = std::min(std::min(limit, ulog2_), vlog2_); + // but if the base size is already less than limit, we'd like to pick it + // instead of nothing. + limit = std::min(std::min(limit, ulog2_), vlog2_); - while (ulog2_ >= limit && vlog2_ >= limit - && (maxLevels == -1 || level <= maxLevels)) { - if (level % 2 == 1) - uofs += (1<<(ulog2_+1))+2; - if ((level > 0) && (level % 2 == 0)) - vofs += (1<<(vlog2_+1)) + 2; + while (ulog2_ >= limit && vlog2_ >= limit && (maxLevels == -1 || level <= maxLevels)) + { + if (level % 2 == 1) + uofs += (1 << (ulog2_ + 1)) + 2; + if ((level > 0) && (level % 2 == 0)) + vofs += (1 << (vlog2_ + 1)) + 2; - unsigned char *dst = destination + vofs * stride + uofs * bpp; - unsigned char *dstData = destination - + (vofs + 1) * stride - + (uofs + 1) * bpp; - ptex->getData(index, dstData, stride, Ptex::Res(ulog2_, vlog2_)); + unsigned char *dst = destination + vofs * stride + uofs * bpp; + unsigned char *dstData = destination + (vofs + 1) * stride + (uofs + 1) * bpp; + ptex->getData(index, dstData, stride, Ptex::Res(ulog2_, vlog2_)); - guttering(loader, ptex, level, 1<width <= width) && (block->height <= height); - } - }; + uint16_t u, v, width, height; - typedef std::list BlockList; - - Page(uint16_t width, uint16_t height) { - _slots.push_back(Slot(0, 0, width, height)); - } - - bool IsFull() const { - return _slots.empty(); + // returns true if a block can fit in this slot + bool Fits(const Block *block) + { + return (block->width <= width) && (block->height <= height); } - - // true when the block "b" is successfully added to this page : - // - // |--------------------------| |------------|-------------| - // | | |............| | - // | | |............| | - // | | |.... B .....| Right Slot | - // | | |............| | - // | | |............| | - // | | |------------|-------------| - // | Original Slot | ==> | | - // | | | | - // | | | Bottom Slot | - // | | | | - // | | | | - // |--------------------------| |--------------------------| - // - bool AddBlock(Block *block, const SlotLimit &limit) { - for (SlotList::iterator it = _slots.begin(); it != _slots.end(); ++it) { - if (it->Fits(block)) { - _blocks.push_back(block); - - block->u = it->u; - block->v = it->v; - - // add new slot to the right - if (it->width > block->width) { - // first check if the remainder block would even - // be possible to fill before adding it. - uint16_t w = it->width - block->width; - uint16_t h = block->height; - if (uint32_t(w * h) >= limit.numTexels && - w >= limit.width && - h >= limit.height) { - _slots.push_front(Slot(it->u + block->width, - it->v, - w, h)); - } - } - // add new slot to the bottom - if (it->height > block->height) { - // first check if the remainder block would even - // be possible to fill before adding it. - uint16_t w = it->width; - uint16_t h = (it->height - block->height); - if (uint32_t(w * h) >= limit.numTexels && - w >= limit.width && - h >= limit.height) { - _slots.push_back(Slot(it->u, - it->v + block->height, - w, h)); - } - } - _slots.erase(it); - return true; - } + }; + + typedef std::list BlockList; + + Page(uint16_t width, uint16_t height) + { + _slots.push_back(Slot(0, 0, width, height)); + } + + bool IsFull() const + { + return _slots.empty(); + } + + // true when the block "b" is successfully added to this page : + // + // |--------------------------| |------------|-------------| + // | | |............| | + // | | |............| | + // | | |.... B .....| Right Slot | + // | | |............| | + // | | |............| | + // | | |------------|-------------| + // | Original Slot | ==> | | + // | | | | + // | | | Bottom Slot | + // | | | | + // | | | | + // |--------------------------| |--------------------------| + // + bool AddBlock(Block *block, const SlotLimit &limit) + { + for (SlotList::iterator it = _slots.begin(); it != _slots.end(); ++it) + { + if (it->Fits(block)) + { + _blocks.push_back(block); + + block->u = it->u; + block->v = it->v; + + // add new slot to the right + if (it->width > block->width) + { + // first check if the remainder block would even + // be possible to fill before adding it. + uint16_t w = it->width - block->width; + uint16_t h = block->height; + if (uint32_t(w * h) >= limit.numTexels && + w >= limit.width && + h >= limit.height) + { + _slots.push_front(Slot(it->u + block->width, + it->v, + w, h)); + } } - return false; - } - - void Generate(HdStPtexMipmapTextureLoader *loader, PtexTexture *ptex, - unsigned char *destination, - int bpp, int width, int maxLevels) { - for (BlockList::iterator it = _blocks.begin(); - it != _blocks.end(); ++it) { - (*it)->Generate(loader, ptex, destination, bpp, width, maxLevels); + // add new slot to the bottom + if (it->height > block->height) + { + // first check if the remainder block would even + // be possible to fill before adding it. + uint16_t w = it->width; + uint16_t h = (it->height - block->height); + if (uint32_t(w * h) >= limit.numTexels && + w >= limit.width && + h >= limit.height) + { + _slots.push_back(Slot(it->u, + it->v + block->height, + w, h)); + } } + _slots.erase(it); + return true; + } } - - const BlockList &GetBlocks() const { - return _blocks; + return false; + } + + void Generate(HdStPtexMipmapTextureLoader *loader, PtexTexture *ptex, + unsigned char *destination, + int bpp, int width, int maxLevels) + { + for (BlockList::iterator it = _blocks.begin(); + it != _blocks.end(); ++it) + { + (*it)->Generate(loader, ptex, destination, bpp, width, maxLevels); } + } - void Dump() const { - for (BlockList::const_iterator it = _blocks.begin(); - it != _blocks.end(); ++it) { - printf(" (%d, %d) %d x %d\n", - (*it)->u, (*it)->v, (*it)->width, (*it)->height); - } + const BlockList &GetBlocks() const + { + return _blocks; + } + + void Dump() const + { + for (BlockList::const_iterator it = _blocks.begin(); + it != _blocks.end(); ++it) + { + printf(" (%d, %d) %d x %d\n", + (*it)->u, (*it)->v, (*it)->width, (*it)->height); } + } private: - BlockList _blocks; + BlockList _blocks; - typedef std::list SlotList; - SlotList _slots; + typedef std::list SlotList; + SlotList _slots; }; // --------------------------------------------------------------------------- @@ -353,123 +373,147 @@ struct HdStPtexMipmapTextureLoader::Page class HdStPtexMipmapTextureLoader::CornerIterator { public: - CornerIterator(PtexTexture *ptex, int face, int edge, int8_t reslog2) : - _ptex(ptex), - _startFace(face), _startEdge(edge), - _currentFace(face), _currentEdge(edge), _reslog2(reslog2), - _clockWise(true), _mid(false), _done(false), _isBoundary(true) { - - _numChannels = _ptex->numChannels(); - _currentInfo = _ptex->getFaceInfo(_currentFace); - if (_currentInfo.isSubface()) ++_reslog2; - } + CornerIterator(PtexTexture *ptex, int face, int edge, int8_t reslog2) : _ptex(ptex), + _startFace(face), _startEdge(edge), + _currentFace(face), _currentEdge(edge), _reslog2(reslog2), + _clockWise(true), _mid(false), _done(false), _isBoundary(true) + { + + _numChannels = _ptex->numChannels(); + _currentInfo = _ptex->getFaceInfo(_currentFace); + if (_currentInfo.isSubface()) + ++_reslog2; + } + + int GetCurrentFace() const + { + return _currentFace; + } + + void GetPixel(float *resultPixel) + { + int8_t r = (int8_t)(_currentInfo.isSubface() ? _reslog2 - 1 : _reslog2); + + // limit to the maximum ptex resolution + r = std::min(std::min(r, _currentInfo.res.ulog2), + _currentInfo.res.vlog2); + Ptex::Res res(r, r); + int uv[4][2] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}}; + int u = uv[_currentEdge][0] * (res.u() - 1); + int v = uv[_currentEdge][1] * (res.v() - 1); - int GetCurrentFace() const { - return _currentFace; - } + _ptex->getPixel(_currentFace, u, v, resultPixel, 0, _numChannels, res); + } - void GetPixel(float *resultPixel) { - int8_t r = (int8_t)(_currentInfo.isSubface() ? _reslog2 - 1 : _reslog2); + bool IsDone() const + { + return _done; + } - // limit to the maximum ptex resolution - r = std::min(std::min(r, _currentInfo.res.ulog2), - _currentInfo.res.vlog2); - Ptex::Res res(r, r); - int uv[4][2] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}}; - int u = uv[_currentEdge][0] * (res.u()-1); - int v = uv[_currentEdge][1] * (res.v()-1); + bool IsSubface() const + { + return _currentInfo.isSubface(); + } - _ptex->getPixel(_currentFace, u, v, resultPixel, 0, _numChannels, res); - } + bool IsBoundary() const + { + return _isBoundary; + } - bool IsDone() const { - return _done; - } + void Next() + { + if (_done) + return; - bool IsSubface() const { - return _currentInfo.isSubface(); - } + // next face + Ptex::FaceInfo info = _ptex->getFaceInfo(_currentFace); - bool IsBoundary() const { - return _isBoundary; + if (_clockWise) + { + _currentFace = info.adjface(_currentEdge); + if (_mid) + { + _currentFace = _ptex->getFaceInfo(_currentFace).adjface(2); + _currentEdge = 1; + _mid = false; + } + else if (info.isSubface() && + (!_ptex->getFaceInfo(_currentFace).isSubface()) && + _currentEdge == 3) + { + _mid = true; + _currentEdge = info.adjedge(_currentEdge); + } + else + { + _mid = false; + _currentEdge = info.adjedge(_currentEdge); + _currentEdge = (_currentEdge + 1) % 4; + } + } + else + { + _currentFace = info.adjface((_currentEdge + 3) % 4); + _currentEdge = info.adjedge((_currentEdge + 3) % 4); } - void Next() { - if (_done) return; - - // next face - Ptex::FaceInfo info = _ptex->getFaceInfo(_currentFace); - - if (_clockWise) { - _currentFace = info.adjface(_currentEdge); - if (_mid) { - _currentFace = _ptex->getFaceInfo(_currentFace).adjface(2); - _currentEdge = 1; - _mid = false; - } else if (info.isSubface() && - (!_ptex->getFaceInfo(_currentFace).isSubface()) && - _currentEdge == 3) { - _mid = true; - _currentEdge = info.adjedge(_currentEdge); - } else { - _mid = false; - _currentEdge = info.adjedge(_currentEdge); - _currentEdge = (_currentEdge+1)%4; - } - } else { - _currentFace = info.adjface((_currentEdge+3)%4); - _currentEdge = info.adjedge((_currentEdge+3)%4); - } - - if (_currentFace == -1) { - // border case. - if (_clockWise) { - // reset position and restart counter clock wise - Ptex::FaceInfo sinfo = _ptex->getFaceInfo(_startFace); - _currentFace = sinfo.adjface((_startEdge+3)%4); - _currentEdge = sinfo.adjedge((_startEdge+3)%4); - _clockWise = false; - } else { - // end - _done = true; - return; - } - } - Ptex::FaceInfo nextFaceInfo = _ptex->getFaceInfo(_currentFace); - if ((!_clockWise) && - (!info.isSubface()) && (nextFaceInfo.isSubface())) { - // needs tricky traverse for boundary subface... - if (_currentEdge == 3) { - _currentFace = nextFaceInfo.adjface(2); - _currentEdge = 0; - } - } - - if (_currentFace == -1) { - _done = true; - return; - } + if (_currentFace == -1) + { + // border case. + if (_clockWise) + { + // reset position and restart counter clock wise + Ptex::FaceInfo sinfo = _ptex->getFaceInfo(_startFace); + _currentFace = sinfo.adjface((_startEdge + 3) % 4); + _currentEdge = sinfo.adjedge((_startEdge + 3) % 4); + _clockWise = false; + } + else + { + // end + _done = true; + return; + } + } + Ptex::FaceInfo nextFaceInfo = _ptex->getFaceInfo(_currentFace); + if ((!_clockWise) && + (!info.isSubface()) && (nextFaceInfo.isSubface())) + { + // needs tricky traverse for boundary subface... + if (_currentEdge == 3) + { + _currentFace = nextFaceInfo.adjface(2); + _currentEdge = 0; + } + } - if (_currentFace == _startFace) { - _done = true; - _isBoundary = false; - return; - } + if (_currentFace == -1) + { + _done = true; + return; + } - _currentInfo = _ptex->getFaceInfo(_currentFace); + if (_currentFace == _startFace) + { + _done = true; + _isBoundary = false; + return; } + _currentInfo = _ptex->getFaceInfo(_currentFace); + } + private: - PtexTexture *_ptex; - int _numChannels; - int _startFace, _startEdge; - int _currentFace, _currentEdge; - int8_t _reslog2; - bool _clockWise; - bool _mid; - bool _done; - bool _isBoundary; - Ptex::FaceInfo _currentInfo; + PtexTexture *_ptex; + int _numChannels; + int _startFace, _startEdge; + int _currentFace, _currentEdge; + int8_t _reslog2; + bool _clockWise; + bool _mid; + bool _done; + bool _isBoundary; + Ptex::FaceInfo _currentInfo; }; // --------------------------------------------------------------------------- @@ -478,569 +522,661 @@ HdStPtexMipmapTextureLoader::HdStPtexMipmapTextureLoader(PtexTexture *ptex, int maxNumPages, int maxLevels, size_t targetMemory, - bool seamlessMipmap) : - _ptex(ptex), _maxLevels(maxLevels), _bpp(0), - _pageWidth(0), _pageHeight(0), _texelBuffer(NULL), _layoutBuffer(NULL), - _memoryUsage(0) + bool seamlessMipmap) : _ptex(ptex), _maxLevels(maxLevels), _bpp(0), + _pageWidth(0), _pageHeight(0), _texelBuffer(NULL), _layoutBuffer(NULL), + _memoryUsage(0) { - // byte per pixel - _bpp = ptex->numChannels() * Ptex::DataSize(ptex->dataType()); - - int numFaces = ptex->numFaces(); - _blocks.resize(numFaces); - - for (int i = 0; i < numFaces; ++i) { - const Ptex::FaceInfo &faceInfo = ptex->getFaceInfo(i); - _blocks[i].index = i; - if (seamlessMipmap) { - // need to squarize ptex face - unsigned char s = std::min(faceInfo.res.ulog2, faceInfo.res.vlog2); - _blocks[i].SetSize(s, s, _maxLevels != 0); - } else { - _blocks[i].SetSize(faceInfo.res.ulog2, - faceInfo.res.vlog2, - _maxLevels != 0); - } + // byte per pixel + _bpp = ptex->numChannels() * Ptex::DataSize(ptex->dataType()); + + int numFaces = ptex->numFaces(); + _blocks.resize(numFaces); + + for (int i = 0; i < numFaces; ++i) + { + const Ptex::FaceInfo &faceInfo = ptex->getFaceInfo(i); + _blocks[i].index = i; + if (seamlessMipmap) + { + // need to squarize ptex face + unsigned char s = std::min(faceInfo.res.ulog2, faceInfo.res.vlog2); + _blocks[i].SetSize(s, s, _maxLevels != 0); + } + else + { + _blocks[i].SetSize(faceInfo.res.ulog2, + faceInfo.res.vlog2, + _maxLevels != 0); } + } - optimizePacking(maxNumPages, targetMemory); - generateBuffers(); + optimizePacking(maxNumPages, targetMemory); + generateBuffers(); } HdStPtexMipmapTextureLoader::~HdStPtexMipmapTextureLoader() { - for (size_t i = 0; i < _pages.size(); ++i) { - delete _pages[i]; - } - delete[] _texelBuffer; - delete[] _layoutBuffer; + for (size_t i = 0; i < _pages.size(); ++i) + { + delete _pages[i]; + } + delete[] _texelBuffer; + delete[] _layoutBuffer; } // resample border texels for guttering // -int -HdStPtexMipmapTextureLoader::resampleBorder(int face, int edgeId, - unsigned char *result, - int dstLength, int bpp, - float srcStart, float srcEnd) +int HdStPtexMipmapTextureLoader::resampleBorder(int face, int edgeId, + unsigned char *result, + int dstLength, int bpp, + float srcStart, float srcEnd) { - TF_VERIFY(static_cast(face) < _blocks.size()); - Ptex::Res res(_blocks[face].ulog2, _blocks[face].vlog2); - - int edgeLength = (edgeId == 0 || edgeId == 2) ? res.u() : res.v(); - int srcOffset = (int)(srcStart*edgeLength); - int srcLength = (int)((srcEnd-srcStart)*edgeLength); - - if (dstLength >= srcLength) { - PtexFaceData * data = _ptex->getData(face, res); - if (!data) { - // XXX:validation - // We should add a validation step to ensure we don't have missing - // face data and that the format is right (quad vs tri). - TF_WARN("Ptex missing texture face for face %d at res (%d x %d)", - face, res.u(), res.v()); - return srcLength; - } - // copy or up sampling (nearest) - unsigned char *border = new unsigned char[bpp*srcLength]; - - // order of the result will be flipped to match adjacent pixel order - for (int i = 0; i < srcLength; ++i) { - int u = 0, v = 0; - if (edgeId == Ptex::e_bottom) { - u = edgeLength-1-(i+srcOffset); - v = 0; - } else if (edgeId == Ptex::e_right) { - u = res.u()-1; - v = edgeLength-1-(i+srcOffset); - } else if (edgeId == Ptex::e_top) { - u = i+srcOffset; - v = res.v()-1; - } else if (edgeId == Ptex::e_left) { - u = 0; - v = i+srcOffset; - } - data->getPixel(u, v, &border[i*bpp]); - } + TF_VERIFY(static_cast(face) < _blocks.size()); + Ptex::Res res(_blocks[face].ulog2, _blocks[face].vlog2); - // nearest resample to fit dstLength - for (int i = 0; i < dstLength; ++i) { - for (int j = 0; j < bpp; j++) { - result[i*bpp+j] = border[(i*srcLength/dstLength)*bpp+j]; - } - } - delete[] border; - data->release(); - } else { - // down sampling - while (srcLength > dstLength && res.ulog2 && res.vlog2) { - --res.ulog2; - --res.vlog2; - srcLength /= 2; - } + int edgeLength = (edgeId == 0 || edgeId == 2) ? res.u() : res.v(); + int srcOffset = (int)(srcStart * edgeLength); + int srcLength = (int)((srcEnd - srcStart) * edgeLength); - PtexFaceData * data = _ptex->getData(face, res); - if (!data) { - // XXX:validation - // We should add a validation step to ensure we don't have missing - // face data and that the format is right (quad vs tri). - TF_WARN("Ptex missing texture face for face %d at res (%d x %d)", - face, res.u(), res.v()); - return srcLength; - } + if (dstLength >= srcLength) + { + PtexFaceData *data = _ptex->getData(face, res); + if (!data) + { + // XXX:validation + // We should add a validation step to ensure we don't have missing + // face data and that the format is right (quad vs tri). + TF_WARN("Ptex missing texture face for face %d at res (%d x %d)", + face, res.u(), res.v()); + return srcLength; + } + // copy or up sampling (nearest) + unsigned char *border = new unsigned char[bpp * srcLength]; - unsigned char *border = new unsigned char[bpp*srcLength]; - edgeLength = (edgeId == 0 || edgeId == 2) ? res.u() : res.v(); - srcOffset = (int)(srcStart*edgeLength); - - for (int i = 0; i < dstLength; ++i) { - int u = 0, v = 0; - if (edgeId == Ptex::e_bottom) { - u = edgeLength-1-(i+srcOffset); - v = 0; - } else if (edgeId == Ptex::e_right) { - u = res.u() - 1; - v = edgeLength-1-(i+srcOffset); - } else if (edgeId == Ptex::e_top) { - u = i+srcOffset; - v = res.v() - 1; - } else if (edgeId == Ptex::e_left) { - u = 0; - v = i+srcOffset; - } - data->getPixel(u, v, &border[i*bpp]); + // order of the result will be flipped to match adjacent pixel order + for (int i = 0; i < srcLength; ++i) + { + int u = 0, v = 0; + if (edgeId == Ptex::e_bottom) + { + u = edgeLength - 1 - (i + srcOffset); + v = 0; + } + else if (edgeId == Ptex::e_right) + { + u = res.u() - 1; + v = edgeLength - 1 - (i + srcOffset); + } + else if (edgeId == Ptex::e_top) + { + u = i + srcOffset; + v = res.v() - 1; + } + else if (edgeId == Ptex::e_left) + { + u = 0; + v = i + srcOffset; + } + data->getPixel(u, v, &border[i * bpp]); + } - for (int j = 0; j < bpp; ++j) { - result[i*bpp+j] = border[i*bpp+j]; - } - } + // nearest resample to fit dstLength + for (int i = 0; i < dstLength; ++i) + { + for (int j = 0; j < bpp; j++) + { + result[i * bpp + j] = border[(i * srcLength / dstLength) * bpp + j]; + } + } + delete[] border; + data->release(); + } + else + { + // down sampling + while (srcLength > dstLength && res.ulog2 && res.vlog2) + { + --res.ulog2; + --res.vlog2; + srcLength /= 2; + } - delete[] border; - data->release(); + PtexFaceData *data = _ptex->getData(face, res); + if (!data) + { + // XXX:validation + // We should add a validation step to ensure we don't have missing + // face data and that the format is right (quad vs tri). + TF_WARN("Ptex missing texture face for face %d at res (%d x %d)", + face, res.u(), res.v()); + return srcLength; + } + + unsigned char *border = new unsigned char[bpp * srcLength]; + edgeLength = (edgeId == 0 || edgeId == 2) ? res.u() : res.v(); + srcOffset = (int)(srcStart * edgeLength); + + for (int i = 0; i < dstLength; ++i) + { + int u = 0, v = 0; + if (edgeId == Ptex::e_bottom) + { + u = edgeLength - 1 - (i + srcOffset); + v = 0; + } + else if (edgeId == Ptex::e_right) + { + u = res.u() - 1; + v = edgeLength - 1 - (i + srcOffset); + } + else if (edgeId == Ptex::e_top) + { + u = i + srcOffset; + v = res.v() - 1; + } + else if (edgeId == Ptex::e_left) + { + u = 0; + v = i + srcOffset; + } + data->getPixel(u, v, &border[i * bpp]); + + for (int j = 0; j < bpp; ++j) + { + result[i * bpp + j] = border[i * bpp + j]; + } } - return srcLength; + delete[] border; + data->release(); + } + + return srcLength; } // flip order of pixel buffer static void flipBuffer(unsigned char *buffer, int length, int bpp) { - for (int i = 0; i < length/2; ++i) { - for (int j = 0; j < bpp; j++) { - std::swap(buffer[i*bpp+j], buffer[(length-1-i)*bpp+j]); - } + for (int i = 0; i < length / 2; ++i) + { + for (int j = 0; j < bpp; j++) + { + std::swap(buffer[i * bpp + j], buffer[(length - 1 - i) * bpp + j]); } + } } // sample neighbor face's edge -void -HdStPtexMipmapTextureLoader::sampleNeighbor(unsigned char *border, int face, - int edge, int length, int bpp) +void HdStPtexMipmapTextureLoader::sampleNeighbor(unsigned char *border, int face, + int edge, int length, int bpp) { - const Ptex::FaceInfo &fi = _ptex->getFaceInfo(face); - - // copy adjacent borders - int adjface = fi.adjface(edge); - if (adjface != -1) { - int ae = fi.adjedge(edge); - if (!fi.isSubface() && _ptex->getFaceInfo(adjface).isSubface()) { - /* nonsubface -> subface (1:0.5) see http://ptex.us/adjdata.html for more detail - +------------------+ - | face | - +--------edge------+ - | adj face | | - +----------+-------+ - */ - if (_ptex->meshType() == Ptex::mt_quad) { - resampleBorder(adjface, ae, border, length/2, bpp); - const Ptex::FaceInfo &sfi1 = _ptex->getFaceInfo(adjface); - adjface = sfi1.adjface((ae+3)%4); - ae = (sfi1.adjedge((ae+3)%4)+3)%4; - resampleBorder(adjface, ae, border+(length/2*bpp), - length/2, bpp); - } else { - TF_WARN("Assuming quad mesh format"); - } - - } else if (fi.isSubface() && !_ptex->getFaceInfo(adjface).isSubface()) { - /* subface -> nonsubface (0.5:1). two possible configuration - case 1 case 2 - +----------+----------+ +----------+----------+--------+ - | face | B | | | face | B | - +---edge---+----------+ +----------+--edge----+--------+ - |0.0 0.5 1.0| |0.0 0.5 1.0| - | adj face | | adj face | - +---------------------+ +---------------------+ - */ - if (_ptex->meshType() == Ptex::mt_quad) { - int Bf = fi.adjface((edge+1)%4); - int Be = fi.adjedge((edge+1)%4); - int f = _ptex->getFaceInfo(Bf).adjface((Be+1)%4); - int e = _ptex->getFaceInfo(Bf).adjedge((Be+1)%4); - if (f == adjface && e == ae) { // case 1 - resampleBorder(adjface, ae, border, - length, bpp, 0.0, 0.5); - } else { // case 2 - resampleBorder(adjface, ae, border, - length, bpp, 0.5, 1.0); - } - } else { - TF_WARN("Assuming quad mesh format"); - } - - } else { - /* ordinary case (1:1 match) - +------------------+ - | face | - +--------edge------+ - | adj face | - +----------+-------+ - */ - resampleBorder(adjface, ae, border, length, bpp); + const Ptex::FaceInfo &fi = _ptex->getFaceInfo(face); + + // copy adjacent borders + int adjface = fi.adjface(edge); + if (adjface != -1) + { + int ae = fi.adjedge(edge); + if (!fi.isSubface() && _ptex->getFaceInfo(adjface).isSubface()) + { + /* nonsubface -> subface (1:0.5) see http://ptex.us/adjdata.html for more detail + +------------------+ + | face | + +--------edge------+ + | adj face | | + +----------+-------+ + */ + if (_ptex->meshType() == Ptex::mt_quad) + { + resampleBorder(adjface, ae, border, length / 2, bpp); + const Ptex::FaceInfo &sfi1 = _ptex->getFaceInfo(adjface); + adjface = sfi1.adjface((ae + 3) % 4); + ae = (sfi1.adjedge((ae + 3) % 4) + 3) % 4; + resampleBorder(adjface, ae, border + (length / 2 * bpp), + length / 2, bpp); + } + else + { + TF_WARN("Assuming quad mesh format"); + } + } + else if (fi.isSubface() && !_ptex->getFaceInfo(adjface).isSubface()) + { + /* subface -> nonsubface (0.5:1). two possible configuration + case 1 case 2 + +----------+----------+ +----------+----------+--------+ + | face | B | | | face | B | + +---edge---+----------+ +----------+--edge----+--------+ + |0.0 0.5 1.0| |0.0 0.5 1.0| + | adj face | | adj face | + +---------------------+ +---------------------+ + */ + if (_ptex->meshType() == Ptex::mt_quad) + { + int Bf = fi.adjface((edge + 1) % 4); + int Be = fi.adjedge((edge + 1) % 4); + int f = _ptex->getFaceInfo(Bf).adjface((Be + 1) % 4); + int e = _ptex->getFaceInfo(Bf).adjedge((Be + 1) % 4); + if (f == adjface && e == ae) + { // case 1 + resampleBorder(adjface, ae, border, + length, bpp, 0.0, 0.5); + } + else + { // case 2 + resampleBorder(adjface, ae, border, + length, bpp, 0.5, 1.0); } - } else { - /* border edge. duplicate itself - +-----------------+ - | face | - +-------edge------+ - */ - resampleBorder(face, edge, border, length, bpp); - flipBuffer(border, length, bpp); + } + else + { + TF_WARN("Assuming quad mesh format"); + } } + else + { + /* ordinary case (1:1 match) + +------------------+ + | face | + +--------edge------+ + | adj face | + +----------+-------+ + */ + resampleBorder(adjface, ae, border, length, bpp); + } + } + else + { + /* border edge. duplicate itself + +-----------------+ + | face | + +-------edge------+ + */ + resampleBorder(face, edge, border, length, bpp); + flipBuffer(border, length, bpp); + } } // get corner pixel by traversing all adjacent faces around vertex // -bool -HdStPtexMipmapTextureLoader::getCornerPixel(float *resultPixel, int numchannels, - int face, int edge, - int8_t reslog2) +bool HdStPtexMipmapTextureLoader::getCornerPixel(float *resultPixel, int numchannels, + int face, int edge, + int8_t reslog2) { - const Ptex::FaceInfo &fi = _ptex->getFaceInfo(face); + const Ptex::FaceInfo &fi = _ptex->getFaceInfo(face); + /* + see http://ptex.us/adjdata.html Figure 2 for the reason of conditions edge==1 and 3 + */ + + if (fi.isSubface() && edge == 3) + { /* - see http://ptex.us/adjdata.html Figure 2 for the reason of conditions edge==1 and 3 + in T-vertex case, this function sets 'D' pixel value to *resultPixel and returns false + gutter line + | + +------+-------+ + | | | + | D|C |<-- gutter line + | *-------+ + | B|A [2] | + | |[3] [1]| + | | [0] | + +------+-------+ */ - - if (fi.isSubface() && edge == 3) { - /* - in T-vertex case, this function sets 'D' pixel value to *resultPixel and returns false - gutter line - | - +------+-------+ - | | | - | D|C |<-- gutter line - | *-------+ - | B|A [2] | - | |[3] [1]| - | | [0] | - +------+-------+ - */ - int adjface = fi.adjface(edge); - if (adjface != -1 && !_ptex->getFaceInfo(adjface).isSubface()) { - int adjedge = fi.adjedge(edge); - - Ptex::Res res(std::min((int)_blocks[adjface].ulog2, reslog2+1), - std::min((int)_blocks[adjface].vlog2, reslog2+1)); - - int uv[2] = {0, 0}; - if (adjedge == 0) { - uv[0] = res.u()/2; - uv[1] = 0; - } else if (adjedge == 1) { - uv[0] = res.u()-1; - uv[1] = res.v()/2; - } else if (adjedge == 2) { - uv[0] = res.u()/2-1; - uv[1] = res.v()-1; - } else { - uv[0] = 0; - uv[1] = res.v()/2-1; - } - - _ptex->getPixel(adjface, uv[0], uv[1], - resultPixel, 0, numchannels, res); - return true; - } - } - if (fi.isSubface() && edge == 1) { - /* gutter line - | - +------+-------+ - | | [3] | - | |[0] [2]| - | B|A [1] | - | *-------+ - | D|C |<-- gutter line - | | | - +------+-------+ - - note: here we're focusing on vertex A which corresponds to the edge 1, - but the edge 0 is an adjacent edge to get D pixel. - */ - int adjface = fi.adjface(0); - if (adjface != -1 && !_ptex->getFaceInfo(adjface).isSubface()) { - int adjedge = fi.adjedge(0); - Ptex::Res res(std::min((int)_blocks[adjface].ulog2, reslog2+1), - std::min((int)_blocks[adjface].vlog2, reslog2+1)); - - int uv[2] = {0, 0}; - if (adjedge == 0) { - uv[0] = res.u()/2-1; - uv[1] = 0; - } else if (adjedge == 1) { - uv[0] = res.u()-1; - uv[1] = res.v()/2-1; - } else if (adjedge == 2) { - uv[0] = res.u()/2; - uv[1] = res.v()-1; - } else { - uv[0] = 0; - uv[1] = res.v()/2; - } - - _ptex->getPixel(adjface, uv[0], uv[1], - resultPixel, 0, numchannels, res); - return true; - } - } - - float *pixel = (float*)alloca(sizeof(float)*numchannels); - float *accumPixel = (float*)alloca(sizeof(float)*numchannels); - // clear accum pixel - memset(accumPixel, 0, sizeof(float)*numchannels); - - // iterate faces around the vertex - int numFaces = 0; - CornerIterator it(_ptex, face, edge, reslog2); - for (; !it.IsDone(); it.Next(), ++numFaces) { - it.GetPixel(pixel); - - // accumulate pixel value - for (int j = 0; j < numchannels; ++j) { - accumPixel[j] += pixel[j]; - if (numFaces == 2) { - // also save the diagonal pixel for regular corner case - resultPixel[j] = pixel[j]; - } - } + int adjface = fi.adjface(edge); + if (adjface != -1 && !_ptex->getFaceInfo(adjface).isSubface()) + { + int adjedge = fi.adjedge(edge); + + Ptex::Res res(std::min((int)_blocks[adjface].ulog2, reslog2 + 1), + std::min((int)_blocks[adjface].vlog2, reslog2 + 1)); + + int uv[2] = {0, 0}; + if (adjedge == 0) + { + uv[0] = res.u() / 2; + uv[1] = 0; + } + else if (adjedge == 1) + { + uv[0] = res.u() - 1; + uv[1] = res.v() / 2; + } + else if (adjedge == 2) + { + uv[0] = res.u() / 2 - 1; + uv[1] = res.v() - 1; + } + else + { + uv[0] = 0; + uv[1] = res.v() / 2 - 1; + } + + _ptex->getPixel(adjface, uv[0], uv[1], + resultPixel, 0, numchannels, res); + return true; } - // if regular corner, returns diagonal pixel without averaging - if (numFaces == 4 && (!it.IsBoundary())) { - return true; + } + if (fi.isSubface() && edge == 1) + { + /* gutter line + | + +------+-------+ + | | [3] | + | |[0] [2]| + | B|A [1] | + | *-------+ + | D|C |<-- gutter line + | | | + +------+-------+ + + note: here we're focusing on vertex A which corresponds to the edge 1, + but the edge 0 is an adjacent edge to get D pixel. + */ + int adjface = fi.adjface(0); + if (adjface != -1 && !_ptex->getFaceInfo(adjface).isSubface()) + { + int adjedge = fi.adjedge(0); + Ptex::Res res(std::min((int)_blocks[adjface].ulog2, reslog2 + 1), + std::min((int)_blocks[adjface].vlog2, reslog2 + 1)); + + int uv[2] = {0, 0}; + if (adjedge == 0) + { + uv[0] = res.u() / 2 - 1; + uv[1] = 0; + } + else if (adjedge == 1) + { + uv[0] = res.u() - 1; + uv[1] = res.v() / 2 - 1; + } + else if (adjedge == 2) + { + uv[0] = res.u() / 2; + uv[1] = res.v() - 1; + } + else + { + uv[0] = 0; + uv[1] = res.v() / 2; + } + + _ptex->getPixel(adjface, uv[0], uv[1], + resultPixel, 0, numchannels, res); + return true; } - - // non-4 valence. let's average and return false; - for (int j = 0; j < numchannels; ++j) { - resultPixel[j] = accumPixel[j]/numFaces; + } + + float *pixel = (float *)alloca(sizeof(float) * numchannels); + float *accumPixel = (float *)alloca(sizeof(float) * numchannels); + // clear accum pixel + memset(accumPixel, 0, sizeof(float) * numchannels); + + // iterate faces around the vertex + int numFaces = 0; + CornerIterator it(_ptex, face, edge, reslog2); + for (; !it.IsDone(); it.Next(), ++numFaces) + { + it.GetPixel(pixel); + + // accumulate pixel value + for (int j = 0; j < numchannels; ++j) + { + accumPixel[j] += pixel[j]; + if (numFaces == 2) + { + // also save the diagonal pixel for regular corner case + resultPixel[j] = pixel[j]; + } } - return false; + } + // if regular corner, returns diagonal pixel without averaging + if (numFaces == 4 && (!it.IsBoundary())) + { + return true; + } + + // non-4 valence. let's average and return false; + for (int j = 0; j < numchannels; ++j) + { + resultPixel[j] = accumPixel[j] / numFaces; + } + return false; } -int -HdStPtexMipmapTextureLoader::getLevelDiff(int face, int edge) +int HdStPtexMipmapTextureLoader::getLevelDiff(int face, int edge) { - // returns the highest mipmap level difference around the vertex - // at face/edge - Ptex::FaceInfo faceInfo = _ptex->getFaceInfo(face); - - // note: seamless interpolation only works for square tex faces. - int8_t baseRes = _blocks[face].ulog2; - if (faceInfo.isSubface()) ++baseRes; - - int maxDiff = 0; - CornerIterator it(_ptex, face, edge, baseRes); - for (; !it.IsDone(); it.Next()) { - int res = _blocks[it.GetCurrentFace()].ulog2; - if (it.IsSubface()) ++res; - maxDiff = std::max(maxDiff, baseRes - res); - } - return maxDiff; + // returns the highest mipmap level difference around the vertex + // at face/edge + Ptex::FaceInfo faceInfo = _ptex->getFaceInfo(face); + + // note: seamless interpolation only works for square tex faces. + int8_t baseRes = _blocks[face].ulog2; + if (faceInfo.isSubface()) + ++baseRes; + + int maxDiff = 0; + CornerIterator it(_ptex, face, edge, baseRes); + for (; !it.IsDone(); it.Next()) + { + int res = _blocks[it.GetCurrentFace()].ulog2; + if (it.IsSubface()) + ++res; + maxDiff = std::max(maxDiff, baseRes - res); + } + return maxDiff; } -void -HdStPtexMipmapTextureLoader::optimizePacking(int maxNumPages, - size_t targetMemory) +void HdStPtexMipmapTextureLoader::optimizePacking(int maxNumPages, + size_t targetMemory) { - size_t numTexels = 0; - - // prepare a list of pointers - typedef std::vector BlockArray; - typedef std::list BlockPtrList; - BlockPtrList blocks; - for (BlockArray::iterator it = _blocks.begin(); it != _blocks.end(); ++it) { - blocks.push_back(&(*it)); - numTexels += it->GetNumTexels(); + size_t numTexels = 0; + + // prepare a list of pointers + typedef std::vector BlockArray; + typedef std::list BlockPtrList; + BlockPtrList blocks; + for (BlockArray::iterator it = _blocks.begin(); it != _blocks.end(); ++it) + { + blocks.push_back(&(*it)); + numTexels += it->GetNumTexels(); + } + + // try to fit into the target memory size if specified + if (targetMemory != 0 && _bpp * numTexels > targetMemory) + { + size_t numTargetTexels = targetMemory / _bpp; + + // This is the list of blocks that can possibly be reduced in size to + // save memory. + BlockPtrList candidateBlocks; + for (Block *block : blocks) + { + if (block->ulog2 < 2 || block->vlog2 < 2) + { + // these blocks can't be reduced in size, skip. + } + else + { + candidateBlocks.push_back(block); + } } - // try to fit into the target memory size if specified - if (targetMemory != 0 && _bpp * numTexels > targetMemory) { - size_t numTargetTexels = targetMemory / _bpp; - - // This is the list of blocks that can possibly be reduced in size to - // save memory. - BlockPtrList candidateBlocks; - for (Block *block : blocks) { - if (block->ulog2 < 2 || block->vlog2 < 2) { - // these blocks can't be reduced in size, skip. - } else { - candidateBlocks.push_back(block); - } - } - - // sort blocks by area order - candidateBlocks.sort(Block::sortByArea); - - while (numTexels > numTargetTexels && candidateBlocks.size() > 0) { - // round robin the candidate blocks and move them to the closed - // list if they can't be reduced further. - Block *block = candidateBlocks.front(); - candidateBlocks.pop_front(); - - if (block->ulog2 < 2 || block->vlog2 < 2) { - // This block can't be reduced in size, move to closed list. - // In this case since we are using borrowed pointers from the - // 'blocks' master list we can just make sure it is removed - // from the candidate list. - continue; - } else { - // move it to the back of the list so we reduce other candidates - // before coming back to this one. - candidateBlocks.push_back(block); - } + // sort blocks by area order + candidateBlocks.sort(Block::sortByArea); - // pick a smaller mipmap - numTexels -= block->GetNumTexels(); - block->SetSize((unsigned char)(block->ulog2-1), - (unsigned char)(block->vlog2-1), _maxLevels != 0); - numTexels += block->GetNumTexels(); - } + while (numTexels > numTargetTexels && candidateBlocks.size() > 0) + { + // round robin the candidate blocks and move them to the closed + // list if they can't be reduced further. + Block *block = candidateBlocks.front(); + candidateBlocks.pop_front(); + + if (block->ulog2 < 2 || block->vlog2 < 2) + { + // This block can't be reduced in size, move to closed list. + // In this case since we are using borrowed pointers from the + // 'blocks' master list we can just make sure it is removed + // from the candidate list. + continue; + } + else + { + // move it to the back of the list so we reduce other candidates + // before coming back to this one. + candidateBlocks.push_back(block); + } + + // pick a smaller mipmap + numTexels -= block->GetNumTexels(); + block->SetSize((unsigned char)(block->ulog2 - 1), + (unsigned char)(block->vlog2 - 1), _maxLevels != 0); + numTexels += block->GetNumTexels(); } - - // sort blocks by height-width order, possibly after reducing sizes - // to fit in target memory. - blocks.sort(Block::sort); - - size_t smallestBlockTexels = blocks.size() > 0 ? - blocks.front()->GetNumTexels() : 0; - uint16_t smallestBlockWidth = blocks.size() > 0 ? - blocks.front()->width : 0; - uint16_t smallestBlockHeight = blocks.size() > 0 ? - blocks.front()->width : 0; - for (BlockPtrList::iterator it = blocks.begin(); it != blocks.end(); ++it) { - smallestBlockTexels = std::min(smallestBlockTexels, - (size_t)(*it)->GetNumTexels()); - smallestBlockWidth = std::min(smallestBlockWidth, (*it)->width); - smallestBlockHeight = std::min(smallestBlockHeight, (*it)->height); + } + + // sort blocks by height-width order, possibly after reducing sizes + // to fit in target memory. + blocks.sort(Block::sort); + + size_t smallestBlockTexels = blocks.size() > 0 ? blocks.front()->GetNumTexels() : 0; + uint16_t smallestBlockWidth = blocks.size() > 0 ? blocks.front()->width : 0; + uint16_t smallestBlockHeight = blocks.size() > 0 ? blocks.front()->width : 0; + for (BlockPtrList::iterator it = blocks.begin(); it != blocks.end(); ++it) + { + smallestBlockTexels = std::min(smallestBlockTexels, + (size_t)(*it)->GetNumTexels()); + smallestBlockWidth = std::min(smallestBlockWidth, (*it)->width); + smallestBlockHeight = std::min(smallestBlockHeight, (*it)->height); + } + + // compute page size --------------------------------------------- + { + // page size is set to the largest edge of the largest block : + // this is the smallest possible page size, which should minimize + // the texels wasted on the "last page" when the smallest blocks are + // being packed. + int w = 0, h = 0; + for (BlockPtrList::iterator it = blocks.begin(); + it != blocks.end(); ++it) + { + w = std::max(w, (int)(*it)->width); + h = std::max(h, (int)(*it)->height); } - // compute page size --------------------------------------------- + // grow the pagesize to make sure the optimization will not exceed + // the maximum number of pages allowed + int minPageSize = 512; + int maxPageSize = 4096; // XXX:should be configurable. + + // use minPageSize if too small + if (w < minPageSize) { - // page size is set to the largest edge of the largest block : - // this is the smallest possible page size, which should minimize - // the texels wasted on the "last page" when the smallest blocks are - // being packed. - int w = 0, h = 0; - for (BlockPtrList::iterator it = blocks.begin(); - it != blocks.end(); ++it) { - w = std::max(w, (int)(*it)->width); - h = std::max(h, (int)(*it)->height); - } + w = minPageSize; + } - // grow the pagesize to make sure the optimization will not exceed - // the maximum number of pages allowed - int minPageSize = 512; - int maxPageSize = 4096; // XXX:should be configurable. + if (h < minPageSize) + { + h = minPageSize; + } - // use minPageSize if too small - if (w < minPageSize) { - w = minPageSize; - } - - if (h < minPageSize) { - h = minPageSize; - } + // rough estimate of num pages + int estimatedNumPages = (int)numTexels / w / h; - // rough estimate of num pages - int estimatedNumPages = (int)numTexels/w/h; + // if expecting too many pages, increase page size + int pageLimit = std::max(1, maxNumPages / 2); + if (estimatedNumPages > pageLimit) + { + w = std::min(w * (estimatedNumPages / pageLimit), maxPageSize); + estimatedNumPages = (int)numTexels / w / h; + } + if (estimatedNumPages > pageLimit) + { + h = std::min(h * (estimatedNumPages / pageLimit), maxPageSize); + } - // if expecting too many pages, increase page size - int pageLimit = std::max(1, maxNumPages/2); - if (estimatedNumPages > pageLimit) { - w = std::min(w*(estimatedNumPages/pageLimit), maxPageSize); - estimatedNumPages = (int)numTexels/w/h; - } - if (estimatedNumPages > pageLimit) { - h = std::min(h*(estimatedNumPages/pageLimit), maxPageSize); - } + _pageWidth = w; + _pageHeight = h; + } - _pageWidth = w; - _pageHeight = h; - } + // pack blocks into slots ---------------------------------------- + Page::SlotLimit limit(smallestBlockTexels, + smallestBlockWidth, + smallestBlockHeight); - // pack blocks into slots ---------------------------------------- - Page::SlotLimit limit(smallestBlockTexels, - smallestBlockWidth, - smallestBlockHeight); + // Use a list of working pages while we pack. Move them off the working + // set when they are filled. + std::list openPages; - // Use a list of working pages while we pack. Move them off the working - // set when they are filled. - std::list openPages; + for (BlockPtrList::iterator it = blocks.begin(); + it != blocks.end(); ++it) + { + Block *block = *it; - for (BlockPtrList::iterator it = blocks.begin(); - it != blocks.end(); ++it) { - Block *block = *it; - - // traverse existing pages for a suitable slot --------------- - bool added = false; - for (std::list::iterator pageIt = openPages.begin(); - pageIt != openPages.end(); ++pageIt) { - Page *page = *pageIt; - if ((added = page->AddBlock(block, limit)) == true) { - // check if full, then move page to closed list. - openPages.erase(pageIt); - if (page->IsFull()) { - _pages.push_back(page); - } else { - // not full yet but likely much more full than the next page - // in line so move it to the back - openPages.push_back(page); - } - break; - } + // traverse existing pages for a suitable slot --------------- + bool added = false; + for (std::list::iterator pageIt = openPages.begin(); + pageIt != openPages.end(); ++pageIt) + { + Page *page = *pageIt; + if ((added = page->AddBlock(block, limit)) == true) + { + // check if full, then move page to closed list. + openPages.erase(pageIt); + if (page->IsFull()) + { + _pages.push_back(page); } - // if no page was found : start new page - if (!added) { - Page *page = new Page(_pageWidth, _pageHeight); - added = page->AddBlock(block, limit); - // check if full, then move page to closed list. - if (page->IsFull()) { - _pages.push_back(page); - } else { - openPages.push_back(page); - } - // XXX -- Should not use assert(). - assert(added); + else + { + // not full yet but likely much more full than the next page + // in line so move it to the back + openPages.push_back(page); } + break; + } } - - // move the remaining open pages to the closed list as we have no more - // blocks to pack. - _pages.insert(_pages.end(), openPages.begin(), openPages.end()); - - // set corner pixel mipmap factors - for (BlockArray::iterator it = _blocks.begin(); it != _blocks.end(); ++it) { - int face = it->index; - uint16_t adjSizeDiffs = 0; - for (int edge = 0; edge < 4; ++edge) { - int levelDiff = getLevelDiff(face, edge); - adjSizeDiffs <<= 4; - adjSizeDiffs |= (uint16_t)levelDiff; - } - it->adjSizeDiffs = adjSizeDiffs; - // printf("Block %d, %08x\n", it->index, adjSizeDiffs); + // if no page was found : start new page + if (!added) + { + Page *page = new Page(_pageWidth, _pageHeight); + added = page->AddBlock(block, limit); + // check if full, then move page to closed list. + if (page->IsFull()) + { + _pages.push_back(page); + } + else + { + openPages.push_back(page); + } + // XXX -- Should not use assert(). + assert(added); } + } + + // move the remaining open pages to the closed list as we have no more + // blocks to pack. + _pages.insert(_pages.end(), openPages.begin(), openPages.end()); + + // set corner pixel mipmap factors + for (BlockArray::iterator it = _blocks.begin(); it != _blocks.end(); ++it) + { + int face = it->index; + uint16_t adjSizeDiffs = 0; + for (int edge = 0; edge < 4; ++edge) + { + int levelDiff = getLevelDiff(face, edge); + adjSizeDiffs <<= 4; + adjSizeDiffs |= (uint16_t)levelDiff; + } + it->adjSizeDiffs = adjSizeDiffs; + // printf("Block %d, %08x\n", it->index, adjSizeDiffs); + } #if 0 for (size_t i = 0; i < _pages.size(); ++i) { @@ -1050,53 +1186,54 @@ HdStPtexMipmapTextureLoader::optimizePacking(int maxNumPages, #endif } -void -HdStPtexMipmapTextureLoader::generateBuffers() +void HdStPtexMipmapTextureLoader::generateBuffers() { - // ptex layout struct - // struct Layout { - // uint16_t page; - // uint16_t nMipmap; - // uint16_t u; - // uint16_t v; - // uint16_t adjSizeDiffs; //(4:4:4:4) - // uint8_t width log2; - // uint8_t height log2; - // }; - - int numFaces = (int)_blocks.size(); - int numPages = (int)_pages.size(); - - // populate the texels - int pageStride = _bpp * _pageWidth * _pageHeight; - - _texelBuffer = new unsigned char[pageStride * numPages]; - _memoryUsage = pageStride * numPages; - memset(_texelBuffer, 0, pageStride * numPages); - - for (int i = 0; i < numPages; ++i) { - _pages[i]->Generate(this, _ptex, _texelBuffer + pageStride * i, - _bpp, _pageWidth, _maxLevels); - } - - // populate the layout texture buffer - _layoutBuffer = new unsigned char[numFaces * sizeof(uint16_t) * 6]; - _memoryUsage += numFaces * sizeof(uint16_t) * 6; - for (int i = 0; i < numPages; ++i) { - Page *page = _pages[i]; - for (Page::BlockList::const_iterator it = page->GetBlocks().begin(); - it != page->GetBlocks().end(); ++it) { - int ptexIndex = (*it)->index; - uint16_t *p = (uint16_t*)(_layoutBuffer - + sizeof(uint16_t)*6*ptexIndex); - *p++ = (uint16_t)i; // page - *p++ = (uint16_t)((*it)->nMipmaps-1); - *p++ = (uint16_t)((*it)->u+1); - *p++ = (uint16_t)((*it)->v+1); - *p++ = (*it)->adjSizeDiffs; - *p++ = (uint16_t)(((*it)->ulog2 << 8) | (*it)->vlog2); - } + // ptex layout struct + // struct Layout { + // uint16_t page; + // uint16_t nMipmap; + // uint16_t u; + // uint16_t v; + // uint16_t adjSizeDiffs; //(4:4:4:4) + // uint8_t width log2; + // uint8_t height log2; + // }; + + int numFaces = (int)_blocks.size(); + int numPages = (int)_pages.size(); + + // populate the texels + int pageStride = _bpp * _pageWidth * _pageHeight; + + _texelBuffer = new unsigned char[pageStride * numPages]; + _memoryUsage = pageStride * numPages; + memset(_texelBuffer, 0, pageStride * numPages); + + for (int i = 0; i < numPages; ++i) + { + _pages[i]->Generate(this, _ptex, _texelBuffer + pageStride * i, + _bpp, _pageWidth, _maxLevels); + } + + // populate the layout texture buffer + _layoutBuffer = new unsigned char[numFaces * sizeof(uint16_t) * 6]; + _memoryUsage += numFaces * sizeof(uint16_t) * 6; + for (int i = 0; i < numPages; ++i) + { + Page *page = _pages[i]; + for (Page::BlockList::const_iterator it = page->GetBlocks().begin(); + it != page->GetBlocks().end(); ++it) + { + int ptexIndex = (*it)->index; + uint16_t *p = (uint16_t *)(_layoutBuffer + sizeof(uint16_t) * 6 * ptexIndex); + *p++ = (uint16_t)i; // page + *p++ = (uint16_t)((*it)->nMipmaps - 1); + *p++ = (uint16_t)((*it)->u + 1); + *p++ = (uint16_t)((*it)->v + 1); + *p++ = (*it)->adjSizeDiffs; + *p++ = (uint16_t)(((*it)->ulog2 << 8) | (*it)->vlog2); } + } #if 0 // debug @@ -1119,4 +1256,3 @@ HdStPtexMipmapTextureLoader::generateBuffers() } PXR_NAMESPACE_CLOSE_SCOPE - diff --git a/Sources/OpenUSD/imaging/hdSt/subdivision.cpp b/Sources/OpenUSD/imaging/hdSt/subdivision.cpp index c600b4fe75..1c4bbd7a6e 100644 --- a/Sources/OpenUSD/imaging/hdSt/subdivision.cpp +++ b/Sources/OpenUSD/imaging/hdSt/subdivision.cpp @@ -44,8 +44,8 @@ #include "pxr/imaging/hgi/shaderProgram.h" #include "pxr/imaging/hgi/tokens.h" -#include "pxr/imaging/pxOsd/refinerFactory.h" -#include "pxr/imaging/pxOsd/tokens.h" +#include "PxOsd/refinerFactory.h" +#include "PxOsd/tokens.h" #include "pxr/base/gf/vec2i.h" #include "pxr/base/gf/vec3i.h" @@ -61,20 +61,11 @@ PXR_NAMESPACE_OPEN_SCOPE - // --------------------------------------------------------------------------- TF_DEFINE_PRIVATE_TOKENS( _tokens, - (evalStencils) - (stencilData) - (sizes) - (offsets) - (indices) - (weights) - (baseFaceToRefinedFacesMap) - (refinedFaceCounts) -); + (evalStencils)(stencilData)(sizes)(offsets)(indices)(weights)(baseFaceToRefinedFacesMap)(refinedFaceCounts)); // The stencil table data is managed using two buffer array ranges // the first containing the sizes and offsets which are perPoint for @@ -83,10 +74,10 @@ TF_DEFINE_PRIVATE_TOKENS( class HdSt_GpuStencilTable { public: - size_t numCoarsePoints; - size_t numRefinedPoints; - HdBufferArrayRangeSharedPtr perPointRange; - HdBufferArrayRangeSharedPtr perIndexRange; + size_t numCoarsePoints; + size_t numRefinedPoints; + HdBufferArrayRangeSharedPtr perPointRange; + HdBufferArrayRangeSharedPtr perIndexRange; }; // --------------------------------------------------------------------------- @@ -108,34 +99,34 @@ class HdSt_GpuStencilTable /// class HdSt_OsdIndexComputation final : public HdComputedBufferSource { - struct BaseFaceInfo - { - int baseFaceParam; - GfVec2i baseFaceEdgeIndices; - }; + struct BaseFaceInfo + { + int baseFaceParam; + GfVec2i baseFaceEdgeIndices; + }; public: - HdSt_OsdIndexComputation(HdSt_MeshTopology *topology, - HdBufferSourceSharedPtr const &osdTopology); - bool Resolve() override; - bool HasChainedBuffer() const override; - void GetBufferSpecs(HdBufferSpecVector *specs) const override; - HdBufferSourceSharedPtrVector GetChainedBuffers() const override; + HdSt_OsdIndexComputation(HdSt_MeshTopology *topology, + HdBufferSourceSharedPtr const &osdTopology); + bool Resolve() override; + bool HasChainedBuffer() const override; + void GetBufferSpecs(HdBufferSpecVector *specs) const override; + HdBufferSourceSharedPtrVector GetChainedBuffers() const override; private: - bool _CheckValid() const override; - - void _PopulateUniformPrimitiveBuffer( - HdSt_Subdivision::PatchTable const *patchTable); - void _PopulatePatchPrimitiveBuffer( - HdSt_Subdivision::PatchTable const *patchTable); - void _CreateBaseFaceMapping( - std::vector *result); - - HdSt_MeshTopology *_topology; - HdBufferSourceSharedPtr _osdTopology; - HdBufferSourceSharedPtr _primitiveBuffer; - HdBufferSourceSharedPtr _edgeIndicesBuffer; + bool _CheckValid() const override; + + void _PopulateUniformPrimitiveBuffer( + HdSt_Subdivision::PatchTable const *patchTable); + void _PopulatePatchPrimitiveBuffer( + HdSt_Subdivision::PatchTable const *patchTable); + void _CreateBaseFaceMapping( + std::vector *result); + + HdSt_MeshTopology *_topology; + HdBufferSourceSharedPtr _osdTopology; + HdBufferSourceSharedPtr _primitiveBuffer; + HdBufferSourceSharedPtr _edgeIndicesBuffer; }; // --------------------------------------------------------------------------- @@ -144,27 +135,27 @@ class HdSt_OsdFvarIndexComputation final : public HdComputedBufferSource { public: - HdSt_OsdFvarIndexComputation(HdSt_MeshTopology *topology, - HdBufferSourceSharedPtr const &osdTopology, - int channel); - bool HasChainedBuffer() const override; - bool Resolve() override; - void GetBufferSpecs(HdBufferSpecVector *specs) const override; - HdBufferSourceSharedPtrVector GetChainedBuffers() const override; + HdSt_OsdFvarIndexComputation(HdSt_MeshTopology *topology, + HdBufferSourceSharedPtr const &osdTopology, + int channel); + bool HasChainedBuffer() const override; + bool Resolve() override; + void GetBufferSpecs(HdBufferSpecVector *specs) const override; + HdBufferSourceSharedPtrVector GetChainedBuffers() const override; protected: - bool _CheckValid() const override; + bool _CheckValid() const override; private: - void _PopulateFvarPatchParamBuffer( - HdSt_Subdivision::PatchTable const *patchTable); - - HdSt_MeshTopology *_topology; - HdBufferSourceSharedPtr _osdTopology; - HdBufferSourceSharedPtr _fvarPatchParamBuffer; - int _channel; - TfToken _indicesName; - TfToken _patchParamName; + void _PopulateFvarPatchParamBuffer( + HdSt_Subdivision::PatchTable const *patchTable); + + HdSt_MeshTopology *_topology; + HdBufferSourceSharedPtr _osdTopology; + HdBufferSourceSharedPtr _fvarPatchParamBuffer; + int _channel; + TfToken _indicesName; + TfToken _patchParamName; }; // --------------------------------------------------------------------------- @@ -172,42 +163,41 @@ class HdSt_OsdFvarIndexComputation final : public HdComputedBufferSource class HdSt_OsdTopologyComputation final : public HdComputedBufferSource { public: - HdSt_OsdTopologyComputation(HdSt_MeshTopology *topology, - SdfPath const &id); + HdSt_OsdTopologyComputation(HdSt_MeshTopology *topology, + SdfPath const &id); - bool Resolve() override; - void GetBufferSpecs(HdBufferSpecVector *specs) const override; + bool Resolve() override; + void GetBufferSpecs(HdBufferSpecVector *specs) const override; protected: - bool _CheckValid() const override; + bool _CheckValid() const override; private: - HdSt_MeshTopology *_topology; - SdfPath const _id; + HdSt_MeshTopology *_topology; + SdfPath const _id; }; // --------------------------------------------------------------------------- /// \class HdSt_OsdBaseFaceToRefinedFacesMapComputation -class HdSt_OsdBaseFaceToRefinedFacesMapComputation final : - public HdComputedBufferSource +class HdSt_OsdBaseFaceToRefinedFacesMapComputation final : public HdComputedBufferSource { public: - HdSt_OsdBaseFaceToRefinedFacesMapComputation( - HdSt_Subdivision const *subdivision, - HdBufferSourceSharedPtr const &osdTopology); + HdSt_OsdBaseFaceToRefinedFacesMapComputation( + HdSt_Subdivision const *subdivision, + HdBufferSourceSharedPtr const &osdTopology); - bool HasChainedBuffer() const override; - bool Resolve() override; - void GetBufferSpecs(HdBufferSpecVector *specs) const override; - HdBufferSourceSharedPtrVector GetChainedBuffers() const override; + bool HasChainedBuffer() const override; + bool Resolve() override; + void GetBufferSpecs(HdBufferSpecVector *specs) const override; + HdBufferSourceSharedPtrVector GetChainedBuffers() const override; protected: - bool _CheckValid() const override; + bool _CheckValid() const override; private: - HdSt_Subdivision const *_subdivision; - HdBufferSourceSharedPtr _osdTopology; - HdBufferSourceSharedPtr _refinedFaceCounts; + HdSt_Subdivision const *_subdivision; + HdBufferSourceSharedPtr _osdTopology; + HdBufferSourceSharedPtr _refinedFaceCounts; }; // --------------------------------------------------------------------------- @@ -219,46 +209,51 @@ class HdSt_OsdBaseFaceToRefinedFacesMapComputation final : class HdSt_OsdStencilTableBufferSource final : public HdBufferSource { public: - HdSt_OsdStencilTableBufferSource( - HdSt_Subdivision const *subdivision, - HdBufferSourceSharedPtr const &osdTopology, - TfToken const &name, - HdSt_GpuStencilTableSharedPtr const &gpuStencilTable, - HdSt_MeshTopology::Interpolation interpolation, - int fvarChannel = 0); - - bool Resolve() override; - void GetBufferSpecs(HdBufferSpecVector *specs) const override; - - TfToken const & GetName() const override { - return _name; - } - size_t ComputeHash() const override { - return 0; - } - void const * GetData() const override { - return _resultData; - } - HdTupleType GetTupleType() const override { - return _resultTupleType; - } - size_t GetNumElements() const override { - return _resultNumElements; - } + HdSt_OsdStencilTableBufferSource( + HdSt_Subdivision const *subdivision, + HdBufferSourceSharedPtr const &osdTopology, + TfToken const &name, + HdSt_GpuStencilTableSharedPtr const &gpuStencilTable, + HdSt_MeshTopology::Interpolation interpolation, + int fvarChannel = 0); + + bool Resolve() override; + void GetBufferSpecs(HdBufferSpecVector *specs) const override; + + TfToken const &GetName() const override + { + return _name; + } + size_t ComputeHash() const override + { + return 0; + } + void const *GetData() const override + { + return _resultData; + } + HdTupleType GetTupleType() const override + { + return _resultTupleType; + } + size_t GetNumElements() const override + { + return _resultNumElements; + } protected: - bool _CheckValid() const override; + bool _CheckValid() const override; private: - HdSt_Subdivision const * _subdivision; - HdBufferSourceSharedPtr const _osdTopology; - TfToken _name; - HdSt_GpuStencilTableSharedPtr _gpuStencilTable; - HdSt_MeshTopology::Interpolation const _interpolation; - int const _fvarChannel; - void const * _resultData; - size_t _resultNumElements; - HdTupleType _resultTupleType; + HdSt_Subdivision const *_subdivision; + HdBufferSourceSharedPtr const _osdTopology; + TfToken _name; + HdSt_GpuStencilTableSharedPtr _gpuStencilTable; + HdSt_MeshTopology::Interpolation const _interpolation; + int const _fvarChannel; + void const *_resultData; + size_t _resultNumElements; + HdTupleType _resultTupleType; }; HdSt_OsdStencilTableBufferSource::HdSt_OsdStencilTableBufferSource( @@ -268,65 +263,63 @@ HdSt_OsdStencilTableBufferSource::HdSt_OsdStencilTableBufferSource( HdSt_GpuStencilTableSharedPtr const &gpuStencilTable, HdSt_MeshTopology::Interpolation interpolation, int fvarChannel) - : _subdivision(subdivision) - , _osdTopology(osdTopology) - , _name(name) - , _gpuStencilTable(gpuStencilTable) - , _interpolation(interpolation) - , _fvarChannel(fvarChannel) - , _resultData(nullptr) - , _resultNumElements(0) - , _resultTupleType(HdTupleType{HdTypeInt32, 0}) -{ -} - -bool -HdSt_OsdStencilTableBufferSource::Resolve() -{ - if (_osdTopology && !_osdTopology->IsResolved()) return false; - - if (!_TryLock()) return false; - - HdSt_Subdivision::StencilTable const * stencilTable = - _subdivision->GetStencilTable(_interpolation, _fvarChannel); - - _gpuStencilTable->numCoarsePoints = stencilTable->GetNumControlVertices(); - _gpuStencilTable->numRefinedPoints = stencilTable->GetNumStencils(); - - if (_name == _tokens->sizes) { - _resultData = stencilTable->GetSizes().data(); - _resultNumElements = stencilTable->GetSizes().size(); - _resultTupleType = HdTupleType{HdTypeInt32, 1}; - } else if (_name == _tokens->offsets) { - _resultData = stencilTable->GetOffsets().data(); - _resultNumElements = stencilTable->GetOffsets().size(); - _resultTupleType = HdTupleType{HdTypeInt32, 1}; - } else if (_name == _tokens->indices) { - _resultData = stencilTable->GetControlIndices().data(); - _resultNumElements = stencilTable->GetControlIndices().size(); - _resultTupleType = HdTupleType{HdTypeInt32, 1}; - } else if (_name == _tokens->weights) { - // Note: weights table may have excess entries, so here we - // copy only the entries corresponding to control indices. - _resultData = stencilTable->GetWeights().data(); - _resultNumElements = stencilTable->GetControlIndices().size(); - _resultTupleType = HdTupleType{HdTypeFloat, 1}; - } + : _subdivision(subdivision), _osdTopology(osdTopology), _name(name), _gpuStencilTable(gpuStencilTable), _interpolation(interpolation), _fvarChannel(fvarChannel), _resultData(nullptr), _resultNumElements(0), _resultTupleType(HdTupleType{HdTypeInt32, 0}) +{ +} - _SetResolved(); - return true; +bool HdSt_OsdStencilTableBufferSource::Resolve() +{ + if (_osdTopology && !_osdTopology->IsResolved()) + return false; + + if (!_TryLock()) + return false; + + HdSt_Subdivision::StencilTable const *stencilTable = + _subdivision->GetStencilTable(_interpolation, _fvarChannel); + + _gpuStencilTable->numCoarsePoints = stencilTable->GetNumControlVertices(); + _gpuStencilTable->numRefinedPoints = stencilTable->GetNumStencils(); + + if (_name == _tokens->sizes) + { + _resultData = stencilTable->GetSizes().data(); + _resultNumElements = stencilTable->GetSizes().size(); + _resultTupleType = HdTupleType{HdTypeInt32, 1}; + } + else if (_name == _tokens->offsets) + { + _resultData = stencilTable->GetOffsets().data(); + _resultNumElements = stencilTable->GetOffsets().size(); + _resultTupleType = HdTupleType{HdTypeInt32, 1}; + } + else if (_name == _tokens->indices) + { + _resultData = stencilTable->GetControlIndices().data(); + _resultNumElements = stencilTable->GetControlIndices().size(); + _resultTupleType = HdTupleType{HdTypeInt32, 1}; + } + else if (_name == _tokens->weights) + { + // Note: weights table may have excess entries, so here we + // copy only the entries corresponding to control indices. + _resultData = stencilTable->GetWeights().data(); + _resultNumElements = stencilTable->GetControlIndices().size(); + _resultTupleType = HdTupleType{HdTypeFloat, 1}; + } + + _SetResolved(); + return true; } -void -HdSt_OsdStencilTableBufferSource::GetBufferSpecs(HdBufferSpecVector *) const +void HdSt_OsdStencilTableBufferSource::GetBufferSpecs(HdBufferSpecVector *) const { - // nothing + // nothing } -bool -HdSt_OsdStencilTableBufferSource::_CheckValid() const +bool HdSt_OsdStencilTableBufferSource::_CheckValid() const { - return true; + return true; } HdSt_Subdivision::StencilTable const * @@ -334,208 +327,221 @@ HdSt_Subdivision::GetStencilTable( HdSt_MeshTopology::Interpolation interpolation, int fvarChannel) const { - if (interpolation == HdSt_MeshTopology::INTERPOLATE_FACEVARYING) { - if (!TF_VERIFY(fvarChannel >= 0)) { - return nullptr; - } + if (interpolation == HdSt_MeshTopology::INTERPOLATE_FACEVARYING) + { + if (!TF_VERIFY(fvarChannel >= 0)) + { + return nullptr; + } - if (!TF_VERIFY(fvarChannel < (int)_faceVaryingStencils.size())) { - return nullptr; - } + if (!TF_VERIFY(fvarChannel < (int)_faceVaryingStencils.size())) + { + return nullptr; } + } - return (interpolation == HdSt_MeshTopology::INTERPOLATE_VERTEX) ? - _vertexStencils.get() : - (interpolation == HdSt_MeshTopology::INTERPOLATE_VARYING) ? - _varyingStencils.get() : - _faceVaryingStencils[fvarChannel].get(); + return (interpolation == HdSt_MeshTopology::INTERPOLATE_VERTEX) ? _vertexStencils.get() : (interpolation == HdSt_MeshTopology::INTERPOLATE_VARYING) ? _varyingStencils.get() + : _faceVaryingStencils[fvarChannel].get(); } HdSt_GpuStencilTableSharedPtr HdSt_Subdivision::_GetGpuStencilTable( - HdSt_MeshTopology * topology, - HdBufferSourceSharedPtr const & osdTopology, - HdStResourceRegistry * registry, + HdSt_MeshTopology *topology, + HdBufferSourceSharedPtr const &osdTopology, + HdStResourceRegistry *registry, HdSt_MeshTopology::Interpolation interpolation, int fvarChannel) { - std::unique_lock lock(_gpuStencilMutex); + std::unique_lock lock(_gpuStencilMutex); - if (interpolation == HdSt_MeshTopology::INTERPOLATE_VERTEX) { - if (!_gpuVertexStencils) { - _gpuVertexStencils = _CreateGpuStencilTable( - osdTopology, registry, interpolation); - } - return _gpuVertexStencils; - } else if (interpolation == HdSt_MeshTopology::INTERPOLATE_VARYING) { - if (!_gpuVaryingStencils) { - _gpuVaryingStencils = _CreateGpuStencilTable( - osdTopology, registry, interpolation); - } - return _gpuVaryingStencils; - } else { - if (_gpuFaceVaryingStencils.empty()) { - _gpuFaceVaryingStencils.resize( - topology->GetFvarTopologies().size()); - } - if (!_gpuFaceVaryingStencils[fvarChannel]) { - _gpuFaceVaryingStencils[fvarChannel] = _CreateGpuStencilTable( - osdTopology, registry, interpolation, fvarChannel); - } - return _gpuFaceVaryingStencils[fvarChannel]; + if (interpolation == HdSt_MeshTopology::INTERPOLATE_VERTEX) + { + if (!_gpuVertexStencils) + { + _gpuVertexStencils = _CreateGpuStencilTable( + osdTopology, registry, interpolation); + } + return _gpuVertexStencils; + } + else if (interpolation == HdSt_MeshTopology::INTERPOLATE_VARYING) + { + if (!_gpuVaryingStencils) + { + _gpuVaryingStencils = _CreateGpuStencilTable( + osdTopology, registry, interpolation); + } + return _gpuVaryingStencils; + } + else + { + if (_gpuFaceVaryingStencils.empty()) + { + _gpuFaceVaryingStencils.resize( + topology->GetFvarTopologies().size()); + } + if (!_gpuFaceVaryingStencils[fvarChannel]) + { + _gpuFaceVaryingStencils[fvarChannel] = _CreateGpuStencilTable( + osdTopology, registry, interpolation, fvarChannel); } + return _gpuFaceVaryingStencils[fvarChannel]; + } } HdSt_GpuStencilTableSharedPtr HdSt_Subdivision::_CreateGpuStencilTable( - HdBufferSourceSharedPtr const & osdTopology, - HdStResourceRegistry * registry, + HdBufferSourceSharedPtr const &osdTopology, + HdStResourceRegistry *registry, HdSt_MeshTopology::Interpolation interpolation, int fvarChannel) const { - // Allocate buffer array range for perPoint data - HdBufferSpecVector perPointSpecs = { - { _tokens->sizes, HdTupleType{HdTypeInt32, 1} }, - { _tokens->offsets, HdTupleType{HdTypeInt32, 1} }, - }; - HdBufferArrayRangeSharedPtr perPointRange = - registry->AllocateSingleBufferArrayRange( - _tokens->stencilData, perPointSpecs, HdBufferArrayUsageHint()); - - // Allocate buffer array range for perIndex data - HdBufferSpecVector perIndexSpecs = { - { _tokens->indices, HdTupleType{HdTypeInt32, 1} }, - { _tokens->weights, HdTupleType{HdTypeFloat, 1} }, - }; - HdBufferArrayRangeSharedPtr perIndexRange = - registry->AllocateSingleBufferArrayRange( - _tokens->stencilData, perIndexSpecs, HdBufferArrayUsageHint()); - - HdSt_GpuStencilTableSharedPtr gpuStencilTable = - std::make_shared( - HdSt_GpuStencilTable{0, 0, perPointRange, perIndexRange}); - - // Register buffer sources for computed perPoint stencil table data - HdBufferSourceSharedPtrVector perPointSources{ - std::make_shared( - this, osdTopology, _tokens->sizes, - gpuStencilTable, interpolation, fvarChannel), - std::make_shared( - this, osdTopology, _tokens->offsets, - gpuStencilTable, interpolation, fvarChannel) - }; - registry->AddSources(perPointRange, std::move(perPointSources)); - - // Register buffer sources for computed perIndex stencil table data - HdBufferSourceSharedPtrVector perIndexSources{ - std::make_shared( - this, osdTopology, _tokens->indices, - gpuStencilTable, interpolation, fvarChannel), - std::make_shared( - this, osdTopology, _tokens->weights, - gpuStencilTable, interpolation, fvarChannel) - }; - registry->AddSources(perIndexRange, std::move(perIndexSources)); - - return gpuStencilTable; -} - -bool -HdSt_Subdivision::RefinesToTriangles(TfToken const &scheme) -{ - if (scheme == PxOsdOpenSubdivTokens->loop) { - return true; - } - return false; + // Allocate buffer array range for perPoint data + HdBufferSpecVector perPointSpecs = { + {_tokens->sizes, HdTupleType{HdTypeInt32, 1}}, + {_tokens->offsets, HdTupleType{HdTypeInt32, 1}}, + }; + HdBufferArrayRangeSharedPtr perPointRange = + registry->AllocateSingleBufferArrayRange( + _tokens->stencilData, perPointSpecs, HdBufferArrayUsageHint()); + + // Allocate buffer array range for perIndex data + HdBufferSpecVector perIndexSpecs = { + {_tokens->indices, HdTupleType{HdTypeInt32, 1}}, + {_tokens->weights, HdTupleType{HdTypeFloat, 1}}, + }; + HdBufferArrayRangeSharedPtr perIndexRange = + registry->AllocateSingleBufferArrayRange( + _tokens->stencilData, perIndexSpecs, HdBufferArrayUsageHint()); + + HdSt_GpuStencilTableSharedPtr gpuStencilTable = + std::make_shared( + HdSt_GpuStencilTable{0, 0, perPointRange, perIndexRange}); + + // Register buffer sources for computed perPoint stencil table data + HdBufferSourceSharedPtrVector perPointSources{ + std::make_shared( + this, osdTopology, _tokens->sizes, + gpuStencilTable, interpolation, fvarChannel), + std::make_shared( + this, osdTopology, _tokens->offsets, + gpuStencilTable, interpolation, fvarChannel)}; + registry->AddSources(perPointRange, std::move(perPointSources)); + + // Register buffer sources for computed perIndex stencil table data + HdBufferSourceSharedPtrVector perIndexSources{ + std::make_shared( + this, osdTopology, _tokens->indices, + gpuStencilTable, interpolation, fvarChannel), + std::make_shared( + this, osdTopology, _tokens->weights, + gpuStencilTable, interpolation, fvarChannel)}; + registry->AddSources(perIndexRange, std::move(perIndexSources)); + + return gpuStencilTable; +} + +bool HdSt_Subdivision::RefinesToTriangles(TfToken const &scheme) +{ + if (scheme == PxOsdOpenSubdivTokens->loop) + { + return true; + } + return false; } -bool -HdSt_Subdivision::RefinesToBSplinePatches(TfToken const &scheme) +bool HdSt_Subdivision::RefinesToBSplinePatches(TfToken const &scheme) { - return scheme == PxOsdOpenSubdivTokens->catmullClark; + return scheme == PxOsdOpenSubdivTokens->catmullClark; } -bool -HdSt_Subdivision::RefinesToBoxSplineTrianglePatches(TfToken const &scheme) +bool HdSt_Subdivision::RefinesToBoxSplineTrianglePatches(TfToken const &scheme) { #if OPENSUBDIV_VERSION_NUMBER >= 30400 - // v3.4.0 added support for limit surface patches for loop meshes - if (scheme == PxOsdOpenSubdivTokens->loop) { - return true; - } + // v3.4.0 added support for limit surface patches for loop meshes + if (scheme == PxOsdOpenSubdivTokens->loop) + { + return true; + } #endif - return false; + return false; } // --------------------------------------------------------------------------- /*virtual*/ -void -HdSt_OsdIndexComputation::GetBufferSpecs(HdBufferSpecVector *specs) const -{ - if (_topology->RefinesToBSplinePatches()) { - // bi-cubic bspline patches - specs->emplace_back(HdTokens->indices, - HdTupleType {HdTypeInt32, 16}); - // 3+1 (includes sharpness) - specs->emplace_back(HdTokens->primitiveParam, - HdTupleType {HdTypeInt32Vec4, 1}); - specs->emplace_back(HdTokens->edgeIndices, - HdTupleType {HdTypeInt32Vec2, 1}); - } else if (_topology->RefinesToBoxSplineTrianglePatches()) { - // quartic box spline triangle patches - specs->emplace_back(HdTokens->indices, - HdTupleType {HdTypeInt32, 12}); - // 3+1 (includes sharpness) - specs->emplace_back(HdTokens->primitiveParam, - HdTupleType {HdTypeInt32Vec4, 1}); - // int will suffice, but this unifies it for all the cases - specs->emplace_back(HdTokens->edgeIndices, - HdTupleType {HdTypeInt32Vec2, 1}); - } else if (HdSt_Subdivision::RefinesToTriangles(_topology->GetScheme())) { - // triangles (loop) - specs->emplace_back(HdTokens->indices, - HdTupleType {HdTypeInt32Vec3, 1}); - specs->emplace_back(HdTokens->primitiveParam, - HdTupleType {HdTypeInt32Vec3, 1}); - // int will suffice, but this unifies it for all the cases - specs->emplace_back(HdTokens->edgeIndices, - HdTupleType {HdTypeInt32Vec2, 1}); - } else { - // quads (catmark, bilinear) - if (_topology->TriangulateQuads()) { - specs->emplace_back(HdTokens->indices, - HdTupleType {HdTypeInt32, 6}); - } else { - specs->emplace_back(HdTokens->indices, - HdTupleType {HdTypeInt32, 4}); - } - specs->emplace_back(HdTokens->primitiveParam, - HdTupleType {HdTypeInt32Vec3, 1}); - specs->emplace_back(HdTokens->edgeIndices, - HdTupleType {HdTypeInt32Vec2, 1}); +void HdSt_OsdIndexComputation::GetBufferSpecs(HdBufferSpecVector *specs) const +{ + if (_topology->RefinesToBSplinePatches()) + { + // bi-cubic bspline patches + specs->emplace_back(HdTokens->indices, + HdTupleType{HdTypeInt32, 16}); + // 3+1 (includes sharpness) + specs->emplace_back(HdTokens->primitiveParam, + HdTupleType{HdTypeInt32Vec4, 1}); + specs->emplace_back(HdTokens->edgeIndices, + HdTupleType{HdTypeInt32Vec2, 1}); + } + else if (_topology->RefinesToBoxSplineTrianglePatches()) + { + // quartic box spline triangle patches + specs->emplace_back(HdTokens->indices, + HdTupleType{HdTypeInt32, 12}); + // 3+1 (includes sharpness) + specs->emplace_back(HdTokens->primitiveParam, + HdTupleType{HdTypeInt32Vec4, 1}); + // int will suffice, but this unifies it for all the cases + specs->emplace_back(HdTokens->edgeIndices, + HdTupleType{HdTypeInt32Vec2, 1}); + } + else if (HdSt_Subdivision::RefinesToTriangles(_topology->GetScheme())) + { + // triangles (loop) + specs->emplace_back(HdTokens->indices, + HdTupleType{HdTypeInt32Vec3, 1}); + specs->emplace_back(HdTokens->primitiveParam, + HdTupleType{HdTypeInt32Vec3, 1}); + // int will suffice, but this unifies it for all the cases + specs->emplace_back(HdTokens->edgeIndices, + HdTupleType{HdTypeInt32Vec2, 1}); + } + else + { + // quads (catmark, bilinear) + if (_topology->TriangulateQuads()) + { + specs->emplace_back(HdTokens->indices, + HdTupleType{HdTypeInt32, 6}); + } + else + { + specs->emplace_back(HdTokens->indices, + HdTupleType{HdTypeInt32, 4}); } + specs->emplace_back(HdTokens->primitiveParam, + HdTupleType{HdTypeInt32Vec3, 1}); + specs->emplace_back(HdTokens->edgeIndices, + HdTupleType{HdTypeInt32Vec2, 1}); + } } /*virtual*/ -bool -HdSt_OsdIndexComputation::HasChainedBuffer() const +bool HdSt_OsdIndexComputation::HasChainedBuffer() const { - return true; + return true; } /*virtual*/ HdBufferSourceSharedPtrVector HdSt_OsdIndexComputation::GetChainedBuffers() const { - return { _primitiveBuffer, _edgeIndicesBuffer }; + return {_primitiveBuffer, _edgeIndicesBuffer}; } /*virtual*/ -bool -HdSt_OsdIndexComputation::_CheckValid() const +bool HdSt_OsdIndexComputation::_CheckValid() const { - return true; + return true; } // --------------------------------------------------------------------------- @@ -548,11 +554,7 @@ HdSt_OsdRefineComputationCPU::HdSt_OsdRefineComputationCPU( HdBufferSourceSharedPtr const &osdTopology, HdSt_MeshTopology::Interpolation interpolation, int fvarChannel) - : _topology(topology) - , _source(source) - , _osdTopology(osdTopology) - , _interpolation(interpolation) - , _fvarChannel(fvarChannel) + : _topology(topology), _source(source), _osdTopology(osdTopology), _interpolation(interpolation), _fvarChannel(fvarChannel) { } @@ -561,106 +563,106 @@ HdSt_OsdRefineComputationCPU::~HdSt_OsdRefineComputationCPU() = default; TfToken const & HdSt_OsdRefineComputationCPU::GetName() const { - return _source->GetName(); + return _source->GetName(); } template void TfHashAppend(HashState &h, HdSt_OsdRefineComputationCPU const &bs) { - h.Append(bs.GetInterpolation()); + h.Append(bs.GetInterpolation()); } size_t HdSt_OsdRefineComputationCPU::ComputeHash() const { - return TfHash()(*this); + return TfHash()(*this); } void const * HdSt_OsdRefineComputationCPU::GetData() const { - return _primvarBuffer.data(); + return _primvarBuffer.data(); } HdTupleType HdSt_OsdRefineComputationCPU::GetTupleType() const { - return _source->GetTupleType(); + return _source->GetTupleType(); } size_t HdSt_OsdRefineComputationCPU::GetNumElements() const { - // Stride is measured here in components, not bytes. - size_t const elementStride = - HdGetComponentCount(_source->GetTupleType().type); - return _primvarBuffer.size() / elementStride; + // Stride is measured here in components, not bytes. + size_t const elementStride = + HdGetComponentCount(_source->GetTupleType().type); + return _primvarBuffer.size() / elementStride; } HdSt_MeshTopology::Interpolation HdSt_OsdRefineComputationCPU::GetInterpolation() const { - return _interpolation; + return _interpolation; } -bool -HdSt_OsdRefineComputationCPU::Resolve() +bool HdSt_OsdRefineComputationCPU::Resolve() { - if (_source && !_source->IsResolved()) return false; - if (_osdTopology && !_osdTopology->IsResolved()) return false; + if (_source && !_source->IsResolved()) + return false; + if (_osdTopology && !_osdTopology->IsResolved()) + return false; - if (!_TryLock()) return false; + if (!_TryLock()) + return false; - HD_TRACE_FUNCTION(); - HF_MALLOC_TAG_FUNCTION(); + HD_TRACE_FUNCTION(); + HF_MALLOC_TAG_FUNCTION(); - HdSt_Subdivision *subdivision = _topology->GetSubdivision(); - if (!TF_VERIFY(subdivision)) { - _SetResolved(); - return true; - } + HdSt_Subdivision *subdivision = _topology->GetSubdivision(); + if (!TF_VERIFY(subdivision)) + { + _SetResolved(); + return true; + } - // prepare cpu vertex buffer including refined vertices - subdivision->RefineCPU(_source, - &_primvarBuffer, - _interpolation, - _fvarChannel); + // prepare cpu vertex buffer including refined vertices + subdivision->RefineCPU(_source, + &_primvarBuffer, + _interpolation, + _fvarChannel); - HD_PERF_COUNTER_INCR(HdPerfTokens->subdivisionRefineCPU); + HD_PERF_COUNTER_INCR(HdPerfTokens->subdivisionRefineCPU); - _SetResolved(); - return true; + _SetResolved(); + return true; } -bool -HdSt_OsdRefineComputationCPU::_CheckValid() const +bool HdSt_OsdRefineComputationCPU::_CheckValid() const { - bool valid = _source->IsValid(); + bool valid = _source->IsValid(); - // _osdTopology is optional - valid &= _osdTopology ? _osdTopology->IsValid() : true; + // _osdTopology is optional + valid &= _osdTopology ? _osdTopology->IsValid() : true; - return valid; + return valid; } -void -HdSt_OsdRefineComputationCPU::GetBufferSpecs(HdBufferSpecVector *specs) const +void HdSt_OsdRefineComputationCPU::GetBufferSpecs(HdBufferSpecVector *specs) const { - // produces same buffer specs as source - _source->GetBufferSpecs(specs); + // produces same buffer specs as source + _source->GetBufferSpecs(specs); } -bool -HdSt_OsdRefineComputationCPU::HasPreChainedBuffer() const +bool HdSt_OsdRefineComputationCPU::HasPreChainedBuffer() const { - return true; + return true; } HdBufferSourceSharedPtr HdSt_OsdRefineComputationCPU::GetPreChainedBuffer() const { - return _source; + return _source; } // --------------------------------------------------------------------------- @@ -671,287 +673,291 @@ HdSt_OsdRefineComputationGPU::HdSt_OsdRefineComputationGPU( HdSt_MeshTopology *topology, TfToken const &primvarName, HdType type, - HdSt_GpuStencilTableSharedPtr const & gpuStencilTable, + HdSt_GpuStencilTableSharedPtr const &gpuStencilTable, HdSt_MeshTopology::Interpolation interpolation) - : _topology(topology) - , _primvarName(primvarName) - , _gpuStencilTable(gpuStencilTable) - , _interpolation(interpolation) + : _topology(topology), _primvarName(primvarName), _gpuStencilTable(gpuStencilTable), _interpolation(interpolation) { } HdSt_OsdRefineComputationGPU::~HdSt_OsdRefineComputationGPU() = default; -void -HdSt_OsdRefineComputationGPU::GetBufferSpecs(HdBufferSpecVector *specs) const +void HdSt_OsdRefineComputationGPU::GetBufferSpecs(HdBufferSpecVector *specs) const { - // nothing - // - // GPU subdivision requires the source data on GPU in prior to - // execution, so no need to populate bufferspec on registration. + // nothing + // + // GPU subdivision requires the source data on GPU in prior to + // execution, so no need to populate bufferspec on registration. } -void -HdSt_OsdRefineComputationGPU::Execute(HdBufferArrayRangeSharedPtr const &range, - HdResourceRegistry *resourceRegistry) +void HdSt_OsdRefineComputationGPU::Execute(HdBufferArrayRangeSharedPtr const &range, + HdResourceRegistry *resourceRegistry) { - HD_TRACE_FUNCTION(); - HF_MALLOC_TAG_FUNCTION(); + HD_TRACE_FUNCTION(); + HF_MALLOC_TAG_FUNCTION(); - HdSt_Subdivision * subdivision = _topology->GetSubdivision(); - if (!TF_VERIFY(subdivision)) return; + HdSt_Subdivision *subdivision = _topology->GetSubdivision(); + if (!TF_VERIFY(subdivision)) + return; - HdStResourceRegistry * hdStResourceRegistry = - static_cast(resourceRegistry); + HdStResourceRegistry *hdStResourceRegistry = + static_cast(resourceRegistry); - subdivision->RefineGPU(range, - _primvarName, - _gpuStencilTable, - hdStResourceRegistry); + subdivision->RefineGPU(range, + _primvarName, + _gpuStencilTable, + hdStResourceRegistry); - HD_PERF_COUNTER_INCR(HdPerfTokens->subdivisionRefineGPU); + HD_PERF_COUNTER_INCR(HdPerfTokens->subdivisionRefineGPU); } -int -HdSt_OsdRefineComputationGPU::GetNumOutputElements() const +int HdSt_OsdRefineComputationGPU::GetNumOutputElements() const { - // returns the total number of vertices, including coarse and refined ones - HdSt_Subdivision const * subdivision = _topology->GetSubdivision(); - if (!TF_VERIFY(subdivision)) return 0; - if (_interpolation == HdSt_MeshTopology::INTERPOLATE_VERTEX) { - return subdivision->GetNumVertices(); - } else if (_interpolation == HdSt_MeshTopology::INTERPOLATE_VARYING) { - return subdivision->GetNumVarying(); - } else { - return subdivision->GetMaxNumFaceVarying(); - } + // returns the total number of vertices, including coarse and refined ones + HdSt_Subdivision const *subdivision = _topology->GetSubdivision(); + if (!TF_VERIFY(subdivision)) + return 0; + if (_interpolation == HdSt_MeshTopology::INTERPOLATE_VERTEX) + { + return subdivision->GetNumVertices(); + } + else if (_interpolation == HdSt_MeshTopology::INTERPOLATE_VARYING) + { + return subdivision->GetNumVarying(); + } + else + { + return subdivision->GetMaxNumFaceVarying(); + } } HdSt_MeshTopology::Interpolation HdSt_OsdRefineComputationGPU::GetInterpolation() const { - return _interpolation; + return _interpolation; } // --------------------------------------------------------------------------- HdSt_Subdivision::HdSt_Subdivision(bool adaptive, int refineLevel) - : _adaptive(adaptive) - , _refineLevel(refineLevel) - , _maxNumFaceVarying(0) + : _adaptive(adaptive), _refineLevel(refineLevel), _maxNumFaceVarying(0) { } HdSt_Subdivision::~HdSt_Subdivision() = default; -void -HdSt_Subdivision::SetRefinementTables( - std::unique_ptr && vertexStencils, - std::unique_ptr && varyingStencils, - std::vector> && faceVaryingStencils, - std::unique_ptr && patchTable) +void HdSt_Subdivision::SetRefinementTables( + std::unique_ptr &&vertexStencils, + std::unique_ptr &&varyingStencils, + std::vector> &&faceVaryingStencils, + std::unique_ptr &&patchTable) { - _vertexStencils = std::move(vertexStencils); - _varyingStencils = std::move(varyingStencils); + _vertexStencils = std::move(vertexStencils); + _varyingStencils = std::move(varyingStencils); - _faceVaryingStencils.resize(faceVaryingStencils.size()); - for (size_t i = 0; i < _faceVaryingStencils.size(); ++i) { - _faceVaryingStencils[i] = std::move(faceVaryingStencils[i]); - } + _faceVaryingStencils.resize(faceVaryingStencils.size()); + for (size_t i = 0; i < _faceVaryingStencils.size(); ++i) + { + _faceVaryingStencils[i] = std::move(faceVaryingStencils[i]); + } - _patchTable = std::move(patchTable); + _patchTable = std::move(patchTable); - _maxNumFaceVarying = 0; - for (size_t i = 0; i < _faceVaryingStencils.size(); ++i) { - _maxNumFaceVarying = std::max(_maxNumFaceVarying, GetNumFaceVarying(i)); - } + _maxNumFaceVarying = 0; + for (size_t i = 0; i < _faceVaryingStencils.size(); ++i) + { + _maxNumFaceVarying = std::max(_maxNumFaceVarying, GetNumFaceVarying(i)); + } } -int -HdSt_Subdivision::GetNumVertices() const +int HdSt_Subdivision::GetNumVertices() const { - // returns the total number of vertices, including coarse and refined ones. - if (!TF_VERIFY(_vertexStencils)) return 0; + // returns the total number of vertices, including coarse and refined ones. + if (!TF_VERIFY(_vertexStencils)) + return 0; - return _vertexStencils->GetNumStencils() + - _vertexStencils->GetNumControlVertices(); + return _vertexStencils->GetNumStencils() + + _vertexStencils->GetNumControlVertices(); } -int -HdSt_Subdivision::GetNumVarying() const +int HdSt_Subdivision::GetNumVarying() const { - // returns the total number of vertices, including coarse and refined ones. - if (!TF_VERIFY(_varyingStencils)) return 0; + // returns the total number of vertices, including coarse and refined ones. + if (!TF_VERIFY(_varyingStencils)) + return 0; - return _varyingStencils->GetNumStencils() + - _varyingStencils->GetNumControlVertices(); + return _varyingStencils->GetNumStencils() + + _varyingStencils->GetNumControlVertices(); } -int -HdSt_Subdivision::GetNumFaceVarying(int channel) const +int HdSt_Subdivision::GetNumFaceVarying(int channel) const { - // returns the total number of vertices, including coarse and refined ones. - if (!TF_VERIFY(_faceVaryingStencils[channel])) return 0; + // returns the total number of vertices, including coarse and refined ones. + if (!TF_VERIFY(_faceVaryingStencils[channel])) + return 0; - return _faceVaryingStencils[channel]->GetNumStencils() + - _faceVaryingStencils[channel]->GetNumControlVertices(); + return _faceVaryingStencils[channel]->GetNumStencils() + + _faceVaryingStencils[channel]->GetNumControlVertices(); } -int -HdSt_Subdivision::GetMaxNumFaceVarying() const +int HdSt_Subdivision::GetMaxNumFaceVarying() const { - // returns the largest total number of face-varying values (coarse and - // refined) for all the face-varying channels - return _maxNumFaceVarying; + // returns the largest total number of face-varying values (coarse and + // refined) for all the face-varying channels + return _maxNumFaceVarying; } VtIntArray HdSt_Subdivision::GetRefinedFvarIndices(int channel) const { - VtIntArray fvarIndices; - if (_patchTable && _patchTable->GetNumFVarChannels() > channel) { - OpenSubdiv::Far::ConstIndexArray indices = - _patchTable->GetFVarValues(channel); - for (int i = 0; i < indices.size(); ++i) { - fvarIndices.push_back(indices[i]); - } + VtIntArray fvarIndices; + if (_patchTable && _patchTable->GetNumFVarChannels() > channel) + { + OpenSubdiv::Far::ConstIndexArray indices = + _patchTable->GetFVarValues(channel); + for (int i = 0; i < indices.size(); ++i) + { + fvarIndices.push_back(indices[i]); } - return fvarIndices; -} - -namespace { - -void -_EvalStencilsCPU( - std::vector * primvarBuffer, - int const elementStride, - int const numCoarsePoints, - int const numRefinedPoints, - std::vector const & sizes, - std::vector const & offsets, - std::vector const & indices, - std::vector const & weights); - -void -_EvalStencilsGPU( - HdBufferArrayRangeSharedPtr const & range_, - TfToken const & primvarName, - int const numCoarsePoints, - int const numRefinedPoints, - HdBufferArrayRangeSharedPtr const & perPointRange_, - HdBufferArrayRangeSharedPtr const & perIndexRange_, - HdResourceRegistry * resourceRegistry); + } + return fvarIndices; +} + +namespace +{ + + void + _EvalStencilsCPU( + std::vector *primvarBuffer, + int const elementStride, + int const numCoarsePoints, + int const numRefinedPoints, + std::vector const &sizes, + std::vector const &offsets, + std::vector const &indices, + std::vector const &weights); + + void + _EvalStencilsGPU( + HdBufferArrayRangeSharedPtr const &range_, + TfToken const &primvarName, + int const numCoarsePoints, + int const numRefinedPoints, + HdBufferArrayRangeSharedPtr const &perPointRange_, + HdBufferArrayRangeSharedPtr const &perIndexRange_, + HdResourceRegistry *resourceRegistry); }; -void -HdSt_Subdivision::RefineCPU(HdBufferSourceSharedPtr const & source, - std::vector * primvarBuffer, - HdSt_MeshTopology::Interpolation interpolation, - int fvarChannel) -{ - HD_TRACE_FUNCTION(); - HF_MALLOC_TAG_FUNCTION(); - - HdSt_Subdivision::StencilTable const * stencilTable = - GetStencilTable(interpolation, fvarChannel); - - if (!TF_VERIFY(stencilTable)) return; - - // if there is no stencil (e.g. torus with adaptive refinement), - // just return here - if (stencilTable->GetNumStencils() == 0) return; - - // Stride is measured here in components, not bytes. - size_t const elementStride = - HdGetComponentCount(source->GetTupleType().type); - - size_t const numTotalElements = - stencilTable->GetNumControlVertices() + stencilTable->GetNumStencils(); - primvarBuffer->resize(numTotalElements * elementStride); - - // if the mesh has more vertices than that in use in topology, - // we need to trim the buffer so that they won't overrun the coarse - // vertex buffer which we allocated using the stencil table. - // see HdSt_Subdivision::GetNumVertices() - size_t numSrcElements = source->GetNumElements(); - if (numSrcElements > (size_t)stencilTable->GetNumControlVertices()) { - numSrcElements = stencilTable->GetNumControlVertices(); - } - - float const * srcData = static_cast(source->GetData()); - std::copy(srcData, srcData + (numSrcElements * elementStride), - primvarBuffer->begin()); - - _EvalStencilsCPU( - primvarBuffer, - elementStride, - stencilTable->GetNumControlVertices(), - stencilTable->GetNumStencils(), - stencilTable->GetSizes(), - stencilTable->GetOffsets(), - stencilTable->GetControlIndices(), - stencilTable->GetWeights() - ); -} - -void -HdSt_Subdivision::RefineGPU( - HdBufferArrayRangeSharedPtr const & primvarRange, - TfToken const & primvarName, - HdSt_GpuStencilTableSharedPtr const & gpuStencilTable, - HdStResourceRegistry * resourceRegistry) +void HdSt_Subdivision::RefineCPU(HdBufferSourceSharedPtr const &source, + std::vector *primvarBuffer, + HdSt_MeshTopology::Interpolation interpolation, + int fvarChannel) +{ + HD_TRACE_FUNCTION(); + HF_MALLOC_TAG_FUNCTION(); + + HdSt_Subdivision::StencilTable const *stencilTable = + GetStencilTable(interpolation, fvarChannel); + + if (!TF_VERIFY(stencilTable)) + return; + + // if there is no stencil (e.g. torus with adaptive refinement), + // just return here + if (stencilTable->GetNumStencils() == 0) + return; + + // Stride is measured here in components, not bytes. + size_t const elementStride = + HdGetComponentCount(source->GetTupleType().type); + + size_t const numTotalElements = + stencilTable->GetNumControlVertices() + stencilTable->GetNumStencils(); + primvarBuffer->resize(numTotalElements * elementStride); + + // if the mesh has more vertices than that in use in topology, + // we need to trim the buffer so that they won't overrun the coarse + // vertex buffer which we allocated using the stencil table. + // see HdSt_Subdivision::GetNumVertices() + size_t numSrcElements = source->GetNumElements(); + if (numSrcElements > (size_t)stencilTable->GetNumControlVertices()) + { + numSrcElements = stencilTable->GetNumControlVertices(); + } + + float const *srcData = static_cast(source->GetData()); + std::copy(srcData, srcData + (numSrcElements * elementStride), + primvarBuffer->begin()); + + _EvalStencilsCPU( + primvarBuffer, + elementStride, + stencilTable->GetNumControlVertices(), + stencilTable->GetNumStencils(), + stencilTable->GetSizes(), + stencilTable->GetOffsets(), + stencilTable->GetControlIndices(), + stencilTable->GetWeights()); +} + +void HdSt_Subdivision::RefineGPU( + HdBufferArrayRangeSharedPtr const &primvarRange, + TfToken const &primvarName, + HdSt_GpuStencilTableSharedPtr const &gpuStencilTable, + HdStResourceRegistry *resourceRegistry) { - HD_TRACE_FUNCTION(); - HF_MALLOC_TAG_FUNCTION(); + HD_TRACE_FUNCTION(); + HF_MALLOC_TAG_FUNCTION(); - if (!TF_VERIFY(gpuStencilTable)) return; + if (!TF_VERIFY(gpuStencilTable)) + return; - // if there is no stencil (e.g. torus with adaptive refinement), - // just return here - if (gpuStencilTable->numRefinedPoints == 0) return; + // if there is no stencil (e.g. torus with adaptive refinement), + // just return here + if (gpuStencilTable->numRefinedPoints == 0) + return; - _EvalStencilsGPU( - primvarRange, - primvarName, - gpuStencilTable->numCoarsePoints, - gpuStencilTable->numRefinedPoints, - gpuStencilTable->perPointRange, - gpuStencilTable->perIndexRange, - resourceRegistry); + _EvalStencilsGPU( + primvarRange, + primvarName, + gpuStencilTable->numCoarsePoints, + gpuStencilTable->numRefinedPoints, + gpuStencilTable->perPointRange, + gpuStencilTable->perIndexRange, + resourceRegistry); } HdBufferSourceSharedPtr HdSt_Subdivision::CreateTopologyComputation(HdSt_MeshTopology *topology, SdfPath const &id) { - return std::make_shared(topology, id); + return std::make_shared(topology, id); } HdBufferSourceSharedPtr HdSt_Subdivision::CreateIndexComputation(HdSt_MeshTopology *topology, - HdBufferSourceSharedPtr const &osdTopology) + HdBufferSourceSharedPtr const &osdTopology) { - return std::make_shared(topology, osdTopology); + return std::make_shared(topology, osdTopology); } HdBufferSourceSharedPtr HdSt_Subdivision::CreateFvarIndexComputation(HdSt_MeshTopology *topology, - HdBufferSourceSharedPtr const &osdTopology, int channel) + HdBufferSourceSharedPtr const &osdTopology, int channel) { - return std::make_shared( - topology, osdTopology, channel); + return std::make_shared( + topology, osdTopology, channel); } HdBufferSourceSharedPtr HdSt_Subdivision::CreateRefineComputationCPU(HdSt_MeshTopology *topology, - HdBufferSourceSharedPtr const &source, - HdBufferSourceSharedPtr const &osdTopology, - HdSt_MeshTopology::Interpolation interpolation, - int fvarChannel) + HdBufferSourceSharedPtr const &source, + HdBufferSourceSharedPtr const &osdTopology, + HdSt_MeshTopology::Interpolation interpolation, + int fvarChannel) { - return std::make_shared( - topology, source, osdTopology, interpolation, fvarChannel); + return std::make_shared( + topology, source, osdTopology, interpolation, fvarChannel); } HdStComputationSharedPtr @@ -964,198 +970,213 @@ HdSt_Subdivision::CreateRefineComputationGPU( HdSt_MeshTopology::Interpolation interpolation, int fvarChannel) { - HdSt_GpuStencilTableSharedPtr gpuStencilTable = - _GetGpuStencilTable(topology, osdTopology, - resourceRegistry, interpolation, fvarChannel); + HdSt_GpuStencilTableSharedPtr gpuStencilTable = + _GetGpuStencilTable(topology, osdTopology, + resourceRegistry, interpolation, fvarChannel); - return std::make_shared( - topology, name, dataType, gpuStencilTable, interpolation); + return std::make_shared( + topology, name, dataType, gpuStencilTable, interpolation); } HdBufferSourceSharedPtr HdSt_Subdivision::CreateBaseFaceToRefinedFacesMapComputation( HdBufferSourceSharedPtr const &osdTopology) { - return std::make_shared( - this, osdTopology); + return std::make_shared( + this, osdTopology); } // --------------------------------------------------------------------------- HdSt_OsdTopologyComputation::HdSt_OsdTopologyComputation( HdSt_MeshTopology *topology, SdfPath const &id) - : _topology(topology) - , _id(id) + : _topology(topology), _id(id) { } -void -HdSt_OsdTopologyComputation::GetBufferSpecs(HdBufferSpecVector *specs) const +void HdSt_OsdTopologyComputation::GetBufferSpecs(HdBufferSpecVector *specs) const { - // nothing + // nothing } -bool -HdSt_OsdTopologyComputation::Resolve() +bool HdSt_OsdTopologyComputation::Resolve() { - using namespace OpenSubdiv; + using namespace OpenSubdiv; - if (!_TryLock()) return false; - - HD_TRACE_FUNCTION(); - HF_MALLOC_TAG_FUNCTION(); + if (!_TryLock()) + return false; - // do far analysis and set stencils and patch table into HdSt_Subdivision. + HD_TRACE_FUNCTION(); + HF_MALLOC_TAG_FUNCTION(); - if (!TF_VERIFY(_topology)) { - _SetResolved(); - return true; - } + // do far analysis and set stencils and patch table into HdSt_Subdivision. - HdSt_Subdivision * subdivision = _topology->GetSubdivision(); - if (!TF_VERIFY(subdivision)) { - _SetResolved(); - return true; - } + if (!TF_VERIFY(_topology)) + { + _SetResolved(); + return true; + } - // create topology refiner - PxOsdTopologyRefinerSharedPtr refiner; - - // for empty topology, we don't need to refine anything. - // but still need to return the typed buffer for codegen - int numFvarChannels = 0; - if (_topology->GetFaceVertexCounts().size() == 0) { - // leave refiner empty - } else { - refiner = PxOsdRefinerFactory::Create(_topology->GetPxOsdMeshTopology(), - _topology->GetFvarTopologies(), - TfToken(_id.GetText())); - numFvarChannels = refiner->GetNumFVarChannels(); + HdSt_Subdivision *subdivision = _topology->GetSubdivision(); + if (!TF_VERIFY(subdivision)) + { + _SetResolved(); + return true; + } + + // create topology refiner + PxOsdTopologyRefinerSharedPtr refiner; + + // for empty topology, we don't need to refine anything. + // but still need to return the typed buffer for codegen + int numFvarChannels = 0; + if (_topology->GetFaceVertexCounts().size() == 0) + { + // leave refiner empty + } + else + { + refiner = PxOsdRefinerFactory::Create(_topology->GetPxOsdMeshTopology(), + _topology->GetFvarTopologies(), + TfToken(_id.GetText())); + numFvarChannels = refiner->GetNumFVarChannels(); + } + + std::unique_ptr vertexStencils; + std::unique_ptr varyingStencils; + std::vector> + faceVaryingStencils(numFvarChannels); + std::unique_ptr patchTable; + + // refine topology and create stencil tables and patch table + if (refiner) + { + bool const adaptive = subdivision->IsAdaptive(); + int const level = subdivision->GetRefineLevel(); + + Far::PatchTableFactory::Options patchOptions(level); + if (numFvarChannels > 0) + { + patchOptions.generateFVarTables = true; + patchOptions.includeFVarBaseLevelIndices = true; + patchOptions.generateFVarLegacyLinearPatches = !adaptive; } - - std::unique_ptr vertexStencils; - std::unique_ptr varyingStencils; - std::vector> - faceVaryingStencils(numFvarChannels); - std::unique_ptr patchTable; - - // refine topology and create stencil tables and patch table - if (refiner) { - bool const adaptive = subdivision->IsAdaptive(); - int const level = subdivision->GetRefineLevel(); - - Far::PatchTableFactory::Options patchOptions(level); - if (numFvarChannels > 0) { - patchOptions.generateFVarTables = true; - patchOptions.includeFVarBaseLevelIndices = true; - patchOptions.generateFVarLegacyLinearPatches = !adaptive; - } - if (adaptive) { - patchOptions.endCapType = - Far::PatchTableFactory::Options::ENDCAP_BSPLINE_BASIS; + if (adaptive) + { + patchOptions.endCapType = + Far::PatchTableFactory::Options::ENDCAP_BSPLINE_BASIS; #if OPENSUBDIV_VERSION_NUMBER >= 30400 - // Improve fidelity when refining to limit surface patches - // These options supported since v3.1.0 and v3.2.0 respectively. - patchOptions.useInfSharpPatch = true; - patchOptions.generateLegacySharpCornerPatches = false; + // Improve fidelity when refining to limit surface patches + // These options supported since v3.1.0 and v3.2.0 respectively. + patchOptions.useInfSharpPatch = true; + patchOptions.generateLegacySharpCornerPatches = false; #endif - } + } - // split trace scopes. - { - HD_TRACE_SCOPE("refine"); - if (adaptive) { - Far::TopologyRefiner::AdaptiveOptions adaptiveOptions(level); + // split trace scopes. + { + HD_TRACE_SCOPE("refine"); + if (adaptive) + { + Far::TopologyRefiner::AdaptiveOptions adaptiveOptions(level); #if OPENSUBDIV_VERSION_NUMBER >= 30400 - adaptiveOptions = patchOptions.GetRefineAdaptiveOptions(); + adaptiveOptions = patchOptions.GetRefineAdaptiveOptions(); #endif - refiner->RefineAdaptive(adaptiveOptions); - } else { - refiner->RefineUniform(level); - } - } - { - HD_TRACE_SCOPE("stencil factory"); - Far::StencilTableFactory::Options options; - options.generateOffsets = true; - options.generateIntermediateLevels = adaptive; - options.interpolationMode = - Far::StencilTableFactory::INTERPOLATE_VERTEX; - vertexStencils.reset( - Far::StencilTableFactory::Create(*refiner, options)); - - options.interpolationMode = - Far::StencilTableFactory::INTERPOLATE_VARYING; - varyingStencils.reset( - Far::StencilTableFactory::Create(*refiner, options)); - - options.interpolationMode = - Far::StencilTableFactory::INTERPOLATE_FACE_VARYING; - for (int i = 0; i < numFvarChannels; ++i) { - options.fvarChannel = i; - faceVaryingStencils[i].reset( - Far::StencilTableFactory::Create(*refiner, options)); - } - } - { - HD_TRACE_SCOPE("patch factory"); - patchTable.reset( - Far::PatchTableFactory::Create(*refiner, patchOptions)); - } + refiner->RefineAdaptive(adaptiveOptions); + } + else + { + refiner->RefineUniform(level); + } } + { + HD_TRACE_SCOPE("stencil factory"); + Far::StencilTableFactory::Options options; + options.generateOffsets = true; + options.generateIntermediateLevels = adaptive; + options.interpolationMode = + Far::StencilTableFactory::INTERPOLATE_VERTEX; + vertexStencils.reset( + Far::StencilTableFactory::Create(*refiner, options)); + + options.interpolationMode = + Far::StencilTableFactory::INTERPOLATE_VARYING; + varyingStencils.reset( + Far::StencilTableFactory::Create(*refiner, options)); + + options.interpolationMode = + Far::StencilTableFactory::INTERPOLATE_FACE_VARYING; + for (int i = 0; i < numFvarChannels; ++i) + { + options.fvarChannel = i; + faceVaryingStencils[i].reset( + Far::StencilTableFactory::Create(*refiner, options)); + } + } + { + HD_TRACE_SCOPE("patch factory"); + patchTable.reset( + Far::PatchTableFactory::Create(*refiner, patchOptions)); + } + } - // merge local point stencils - if (patchTable && patchTable->GetLocalPointStencilTable()) { - // append stencils - if (Far::StencilTable const *vertexStencilsWithLocalPoints = + // merge local point stencils + if (patchTable && patchTable->GetLocalPointStencilTable()) + { + // append stencils + if (Far::StencilTable const *vertexStencilsWithLocalPoints = Far::StencilTableFactory::AppendLocalPointStencilTable( *refiner, vertexStencils.get(), - patchTable->GetLocalPointStencilTable())) { - vertexStencils.reset(vertexStencilsWithLocalPoints); - } + patchTable->GetLocalPointStencilTable())) + { + vertexStencils.reset(vertexStencilsWithLocalPoints); } - if (patchTable && patchTable->GetLocalPointVaryingStencilTable()) { - // append stencils - if (Far::StencilTable const *varyingStencilsWithLocalPoints = + } + if (patchTable && patchTable->GetLocalPointVaryingStencilTable()) + { + // append stencils + if (Far::StencilTable const *varyingStencilsWithLocalPoints = Far::StencilTableFactory::AppendLocalPointStencilTableVarying( *refiner, varyingStencils.get(), - patchTable->GetLocalPointVaryingStencilTable())) { - varyingStencils.reset(varyingStencilsWithLocalPoints); - } + patchTable->GetLocalPointVaryingStencilTable())) + { + varyingStencils.reset(varyingStencilsWithLocalPoints); } - for (int i = 0; i < numFvarChannels; ++i) { - if (patchTable && patchTable->GetLocalPointFaceVaryingStencilTable(i)) { - // append stencils - if (Far::StencilTable const *faceVaryingStencilsWithLocalPoints = - Far::StencilTableFactory - ::AppendLocalPointStencilTableFaceVarying( - *refiner, - faceVaryingStencils[i].get(), - patchTable->GetLocalPointFaceVaryingStencilTable(i), - i)) { - faceVaryingStencils[i].reset( - faceVaryingStencilsWithLocalPoints); - } - } + } + for (int i = 0; i < numFvarChannels; ++i) + { + if (patchTable && patchTable->GetLocalPointFaceVaryingStencilTable(i)) + { + // append stencils + if (Far::StencilTable const *faceVaryingStencilsWithLocalPoints = + Far::StencilTableFactory ::AppendLocalPointStencilTableFaceVarying( + *refiner, + faceVaryingStencils[i].get(), + patchTable->GetLocalPointFaceVaryingStencilTable(i), + i)) + { + faceVaryingStencils[i].reset( + faceVaryingStencilsWithLocalPoints); + } } + } - // set tables to topology - // HdSt_Subdivision takes an ownership of stencilTables and patchTable. - subdivision->SetRefinementTables(std::move(vertexStencils), - std::move(varyingStencils), - std::move(faceVaryingStencils), - std::move(patchTable)); + // set tables to topology + // HdSt_Subdivision takes an ownership of stencilTables and patchTable. + subdivision->SetRefinementTables(std::move(vertexStencils), + std::move(varyingStencils), + std::move(faceVaryingStencils), + std::move(patchTable)); - _SetResolved(); - return true; + _SetResolved(); + return true; } -bool -HdSt_OsdTopologyComputation::_CheckValid() const +bool HdSt_OsdTopologyComputation::_CheckValid() const { - return true; + return true; } // --------------------------------------------------------------------------- @@ -1163,415 +1184,456 @@ HdSt_OsdTopologyComputation::_CheckValid() const HdSt_OsdIndexComputation::HdSt_OsdIndexComputation( HdSt_MeshTopology *topology, HdBufferSourceSharedPtr const &osdTopology) - : _topology(topology) - , _osdTopology(osdTopology) + : _topology(topology), _osdTopology(osdTopology) { } -bool -HdSt_OsdIndexComputation::Resolve() +bool HdSt_OsdIndexComputation::Resolve() { - using namespace OpenSubdiv; + using namespace OpenSubdiv; - if (_osdTopology && !_osdTopology->IsResolved()) return false; + if (_osdTopology && !_osdTopology->IsResolved()) + return false; - if (!_TryLock()) return false; + if (!_TryLock()) + return false; - HdSt_Subdivision * subdivision = _topology->GetSubdivision(); - if (!TF_VERIFY(subdivision)) { - _SetResolved(); - return true; - } + HdSt_Subdivision *subdivision = _topology->GetSubdivision(); + if (!TF_VERIFY(subdivision)) + { + _SetResolved(); + return true; + } - HdSt_Subdivision::PatchTable const * patchTable = - subdivision->GetPatchTable(); + HdSt_Subdivision::PatchTable const *patchTable = + subdivision->GetPatchTable(); - Far::Index const *firstIndex = NULL; - size_t ptableSize = 0; - if (patchTable) { - ptableSize = patchTable->GetPatchControlVerticesTable().size(); - if (ptableSize > 0) { - firstIndex = &patchTable->GetPatchControlVerticesTable()[0]; - } + Far::Index const *firstIndex = NULL; + size_t ptableSize = 0; + if (patchTable) + { + ptableSize = patchTable->GetPatchControlVerticesTable().size(); + if (ptableSize > 0) + { + firstIndex = &patchTable->GetPatchControlVerticesTable()[0]; + } + } + + TfToken const &scheme = _topology->GetScheme(); + + if (_topology->RefinesToBSplinePatches() || + _topology->RefinesToBoxSplineTrianglePatches()) + { + + // Bundle groups of 12 or 16 patch control vertices. + int const arraySize = patchTable + ? patchTable->GetPatchArrayDescriptor(0).GetNumControlVertices() + : 0; + + VtArray indices(ptableSize); + memcpy(indices.data(), firstIndex, ptableSize * sizeof(int)); + + HdBufferSourceSharedPtr patchIndices = + std::make_shared( + HdTokens->indices, VtValue(indices), arraySize); + + _SetResult(patchIndices); + + _PopulatePatchPrimitiveBuffer(patchTable); + } + else if (HdSt_Subdivision::RefinesToTriangles(scheme)) + { + // populate refined triangle indices. + VtArray indices(ptableSize / 3); + memcpy(reinterpret_cast(indices.data()), + firstIndex, ptableSize * sizeof(int)); + + HdBufferSourceSharedPtr triIndices = + std::make_shared( + HdTokens->indices, VtValue(indices)); + _SetResult(triIndices); + + _PopulateUniformPrimitiveBuffer(patchTable); + } + else + { + // populate refined quad indices. + size_t const numQuads = ptableSize / 4; + + int const numIndicesPerQuad = + _topology->TriangulateQuads() + ? HdMeshTriQuadBuilder::NumIndicesPerTriQuad + : HdMeshTriQuadBuilder::NumIndicesPerQuad; + VtIntArray indices(numQuads * numIndicesPerQuad); + + if (numIndicesPerQuad == 4) + { + memcpy(indices.data(), firstIndex, ptableSize * sizeof(int)); + } + else + { + HdMeshTriQuadBuilder outputIndices(indices.data(), true); + for (size_t i = 0; i < numQuads; ++i) + { + GfVec4i quadIndices(&firstIndex[i * 4]); + outputIndices.EmitQuadFace(quadIndices); + } } - TfToken const & scheme = _topology->GetScheme(); - - if (_topology->RefinesToBSplinePatches() || - _topology->RefinesToBoxSplineTrianglePatches()) { - - // Bundle groups of 12 or 16 patch control vertices. - int const arraySize = patchTable - ? patchTable->GetPatchArrayDescriptor(0).GetNumControlVertices() - : 0; - - VtArray indices(ptableSize); - memcpy(indices.data(), firstIndex, ptableSize * sizeof(int)); - - HdBufferSourceSharedPtr patchIndices = - std::make_shared( - HdTokens->indices, VtValue(indices), arraySize); - - _SetResult(patchIndices); - - _PopulatePatchPrimitiveBuffer(patchTable); - } else if (HdSt_Subdivision::RefinesToTriangles(scheme)) { - // populate refined triangle indices. - VtArray indices(ptableSize/3); - memcpy(reinterpret_cast(indices.data()), - firstIndex, ptableSize * sizeof(int)); - - HdBufferSourceSharedPtr triIndices = - std::make_shared( - HdTokens->indices, VtValue(indices)); - _SetResult(triIndices); - - _PopulateUniformPrimitiveBuffer(patchTable); - } else { - // populate refined quad indices. - size_t const numQuads = ptableSize / 4; - - int const numIndicesPerQuad = - _topology->TriangulateQuads() - ? HdMeshTriQuadBuilder::NumIndicesPerTriQuad - : HdMeshTriQuadBuilder::NumIndicesPerQuad; - VtIntArray indices(numQuads * numIndicesPerQuad); - - if (numIndicesPerQuad == 4) { - memcpy(indices.data(), firstIndex, ptableSize * sizeof(int)); - } else { - HdMeshTriQuadBuilder outputIndices(indices.data(), true); - for (size_t i=0; i( - HdTokens->indices, VtValue(indices), numIndicesPerQuad); - _SetResult(quadIndices); + // refined quads index buffer + HdBufferSourceSharedPtr quadIndices = + std::make_shared( + HdTokens->indices, VtValue(indices), numIndicesPerQuad); + _SetResult(quadIndices); - _PopulateUniformPrimitiveBuffer(patchTable); - } + _PopulateUniformPrimitiveBuffer(patchTable); + } - _SetResolved(); - return true; + _SetResolved(); + return true; } -void -HdSt_OsdIndexComputation::_CreateBaseFaceMapping( +void HdSt_OsdIndexComputation::_CreateBaseFaceMapping( std::vector *result) { - HD_TRACE_FUNCTION(); - HF_MALLOC_TAG_FUNCTION(); + HD_TRACE_FUNCTION(); + HF_MALLOC_TAG_FUNCTION(); - if (!TF_VERIFY(result)) return; + if (!TF_VERIFY(result)) + return; - int const * numVertsPtr = _topology->GetFaceVertexCounts().cdata(); - int const numFaces = _topology->GetFaceVertexCounts().size(); - int const numVertIndices = _topology->GetFaceVertexIndices().size(); + int const *numVertsPtr = _topology->GetFaceVertexCounts().cdata(); + int const numFaces = _topology->GetFaceVertexCounts().size(); + int const numVertIndices = _topology->GetFaceVertexIndices().size(); - result->clear(); - result->reserve(numFaces); + result->clear(); + result->reserve(numFaces); - int regFaceSize = 4; - if (HdSt_Subdivision::RefinesToTriangles( _topology->GetScheme() )) { - regFaceSize = 3; - } + int regFaceSize = 4; + if (HdSt_Subdivision::RefinesToTriangles(_topology->GetScheme())) + { + regFaceSize = 3; + } + + for (int i = 0, v = 0, ev = 0; i < numFaces; ++i) + { + int const nv = numVertsPtr[i]; + + if (v + nv > numVertIndices) + break; - for (int i = 0, v = 0, ev = 0; i numVertIndices) break; - - if (nv == regFaceSize) { - BaseFaceInfo info; - info.baseFaceParam = - HdMeshUtil::EncodeCoarseFaceParam(i, /*edgeFlag=*/0); - info.baseFaceEdgeIndices = GfVec2i(ev, 0); - result->push_back(info); - } else if (nv < 3) { - int const numBaseFaces = (regFaceSize == 4) ? nv : nv - 2; - for (int f = 0; f < numBaseFaces; ++f) { - BaseFaceInfo info; - info.baseFaceParam = - HdMeshUtil::EncodeCoarseFaceParam(i, /*edgeFlag=*/0); - info.baseFaceEdgeIndices = GfVec2i(-1, -1); - result->push_back(info); - } - } else { - for (int j = 0; j < nv; ++j) { - int edgeFlag = 0; - if (j == 0) { - edgeFlag = 1; - } else if (j == nv - 1) { - edgeFlag = 2; - } else { - edgeFlag = 3; - } - - BaseFaceInfo info; - info.baseFaceParam = - HdMeshUtil::EncodeCoarseFaceParam(i, edgeFlag); - info.baseFaceEdgeIndices = GfVec2i(ev+j, ev+(j+nv-1)%nv); - result->push_back(info); - } + if (nv == regFaceSize) + { + BaseFaceInfo info; + info.baseFaceParam = + HdMeshUtil::EncodeCoarseFaceParam(i, /*edgeFlag=*/0); + info.baseFaceEdgeIndices = GfVec2i(ev, 0); + result->push_back(info); + } + else if (nv < 3) + { + int const numBaseFaces = (regFaceSize == 4) ? nv : nv - 2; + for (int f = 0; f < numBaseFaces; ++f) + { + BaseFaceInfo info; + info.baseFaceParam = + HdMeshUtil::EncodeCoarseFaceParam(i, /*edgeFlag=*/0); + info.baseFaceEdgeIndices = GfVec2i(-1, -1); + result->push_back(info); + } + } + else + { + for (int j = 0; j < nv; ++j) + { + int edgeFlag = 0; + if (j == 0) + { + edgeFlag = 1; + } + else if (j == nv - 1) + { + edgeFlag = 2; + } + else + { + edgeFlag = 3; } - v += nv; - ev += nv; + BaseFaceInfo info; + info.baseFaceParam = + HdMeshUtil::EncodeCoarseFaceParam(i, edgeFlag); + info.baseFaceEdgeIndices = GfVec2i(ev + j, ev + (j + nv - 1) % nv); + result->push_back(info); + } } - result->shrink_to_fit(); + v += nv; + ev += nv; + } + + result->shrink_to_fit(); } -void -HdSt_OsdIndexComputation::_PopulateUniformPrimitiveBuffer( - HdSt_Subdivision::PatchTable const * patchTable) +void HdSt_OsdIndexComputation::_PopulateUniformPrimitiveBuffer( + HdSt_Subdivision::PatchTable const *patchTable) { - HD_TRACE_FUNCTION(); - HF_MALLOC_TAG_FUNCTION(); + HD_TRACE_FUNCTION(); + HF_MALLOC_TAG_FUNCTION(); - std::vector patchFaceToBaseFaceMapping; - _CreateBaseFaceMapping(&patchFaceToBaseFaceMapping); + std::vector patchFaceToBaseFaceMapping; + _CreateBaseFaceMapping(&patchFaceToBaseFaceMapping); - size_t numPatches = patchTable - ? patchTable->GetPatchParamTable().size() - : 0; - VtVec3iArray primitiveParam(numPatches); - VtVec2iArray edgeIndices(numPatches); + size_t numPatches = patchTable + ? patchTable->GetPatchParamTable().size() + : 0; + VtVec3iArray primitiveParam(numPatches); + VtVec2iArray edgeIndices(numPatches); - for (size_t i = 0; i < numPatches; ++i) { - OpenSubdiv::Far::PatchParam const &patchParam = - patchTable->GetPatchParamTable()[i]; + for (size_t i = 0; i < numPatches; ++i) + { + OpenSubdiv::Far::PatchParam const &patchParam = + patchTable->GetPatchParamTable()[i]; - int patchFaceIndex = patchParam.GetFaceId(); - BaseFaceInfo const & info = patchFaceToBaseFaceMapping[patchFaceIndex]; + int patchFaceIndex = patchParam.GetFaceId(); + BaseFaceInfo const &info = patchFaceToBaseFaceMapping[patchFaceIndex]; - unsigned int field0 = patchParam.field0; - unsigned int field1 = patchParam.field1; - primitiveParam[i][0] = info.baseFaceParam; - primitiveParam[i][1] = *((int*)&field0); - primitiveParam[i][2] = *((int*)&field1); + unsigned int field0 = patchParam.field0; + unsigned int field1 = patchParam.field1; + primitiveParam[i][0] = info.baseFaceParam; + primitiveParam[i][1] = *((int *)&field0); + primitiveParam[i][2] = *((int *)&field1); - edgeIndices[i] = info.baseFaceEdgeIndices; - } - - _primitiveBuffer.reset(new HdVtBufferSource( - HdTokens->primitiveParam, - VtValue(primitiveParam))); + edgeIndices[i] = info.baseFaceEdgeIndices; + } - _edgeIndicesBuffer.reset(new HdVtBufferSource( - HdTokens->edgeIndices, - VtValue(edgeIndices))); + _primitiveBuffer.reset(new HdVtBufferSource( + HdTokens->primitiveParam, + VtValue(primitiveParam))); + _edgeIndicesBuffer.reset(new HdVtBufferSource( + HdTokens->edgeIndices, + VtValue(edgeIndices))); } -void -HdSt_OsdIndexComputation::_PopulatePatchPrimitiveBuffer( - HdSt_Subdivision::PatchTable const * patchTable) +void HdSt_OsdIndexComputation::_PopulatePatchPrimitiveBuffer( + HdSt_Subdivision::PatchTable const *patchTable) { - HD_TRACE_FUNCTION(); - HF_MALLOC_TAG_FUNCTION(); + HD_TRACE_FUNCTION(); + HF_MALLOC_TAG_FUNCTION(); - std::vector patchFaceToBaseFaceMapping; - _CreateBaseFaceMapping(&patchFaceToBaseFaceMapping); + std::vector patchFaceToBaseFaceMapping; + _CreateBaseFaceMapping(&patchFaceToBaseFaceMapping); - size_t numPatches = patchTable - ? patchTable->GetPatchParamTable().size() - : 0; - VtVec4iArray primitiveParam(numPatches); - VtVec2iArray edgeIndices(numPatches); + size_t numPatches = patchTable + ? patchTable->GetPatchParamTable().size() + : 0; + VtVec4iArray primitiveParam(numPatches); + VtVec2iArray edgeIndices(numPatches); - for (size_t i = 0; i < numPatches; ++i) { - OpenSubdiv::Far::PatchParam const &patchParam = - patchTable->GetPatchParamTable()[i]; + for (size_t i = 0; i < numPatches; ++i) + { + OpenSubdiv::Far::PatchParam const &patchParam = + patchTable->GetPatchParamTable()[i]; - float sharpness = 0.0; - if (i < patchTable->GetSharpnessIndexTable().size()) { - OpenSubdiv::Far::Index sharpnessIndex = - patchTable->GetSharpnessIndexTable()[i]; - if (sharpnessIndex >= 0) - sharpness = patchTable->GetSharpnessValues()[sharpnessIndex]; - } + float sharpness = 0.0; + if (i < patchTable->GetSharpnessIndexTable().size()) + { + OpenSubdiv::Far::Index sharpnessIndex = + patchTable->GetSharpnessIndexTable()[i]; + if (sharpnessIndex >= 0) + sharpness = patchTable->GetSharpnessValues()[sharpnessIndex]; + } - int patchFaceIndex = patchParam.GetFaceId(); - BaseFaceInfo const & info = patchFaceToBaseFaceMapping[patchFaceIndex]; + int patchFaceIndex = patchParam.GetFaceId(); + BaseFaceInfo const &info = patchFaceToBaseFaceMapping[patchFaceIndex]; - unsigned int field0 = patchParam.field0; - unsigned int field1 = patchParam.field1; - primitiveParam[i][0] = info.baseFaceParam; - primitiveParam[i][1] = *((int*)&field0); - primitiveParam[i][2] = *((int*)&field1); + unsigned int field0 = patchParam.field0; + unsigned int field1 = patchParam.field1; + primitiveParam[i][0] = info.baseFaceParam; + primitiveParam[i][1] = *((int *)&field0); + primitiveParam[i][2] = *((int *)&field1); - int sharpnessAsInt = static_cast(sharpness); - primitiveParam[i][3] = sharpnessAsInt; + int sharpnessAsInt = static_cast(sharpness); + primitiveParam[i][3] = sharpnessAsInt; - edgeIndices[i] = info.baseFaceEdgeIndices; - } - _primitiveBuffer.reset(new HdVtBufferSource( - HdTokens->primitiveParam, - VtValue(primitiveParam))); + edgeIndices[i] = info.baseFaceEdgeIndices; + } + _primitiveBuffer.reset(new HdVtBufferSource( + HdTokens->primitiveParam, + VtValue(primitiveParam))); - _edgeIndicesBuffer.reset(new HdVtBufferSource( - HdTokens->edgeIndices, - VtValue(edgeIndices))); + _edgeIndicesBuffer.reset(new HdVtBufferSource( + HdTokens->edgeIndices, + VtValue(edgeIndices))); } // --------------------------------------------------------------------------- -HdSt_OsdFvarIndexComputation::HdSt_OsdFvarIndexComputation ( +HdSt_OsdFvarIndexComputation::HdSt_OsdFvarIndexComputation( HdSt_MeshTopology *topology, HdBufferSourceSharedPtr const &osdTopology, int channel) - : _topology(topology) - , _osdTopology(osdTopology) - , _channel(channel) + : _topology(topology), _osdTopology(osdTopology), _channel(channel) { - _indicesName = TfToken( - HdStTokens->fvarIndices.GetString() + std::to_string(_channel)); - _patchParamName = TfToken( - HdStTokens->fvarPatchParam.GetString() + std::to_string(_channel)); + _indicesName = TfToken( + HdStTokens->fvarIndices.GetString() + std::to_string(_channel)); + _patchParamName = TfToken( + HdStTokens->fvarPatchParam.GetString() + std::to_string(_channel)); } -bool -HdSt_OsdFvarIndexComputation::Resolve() +bool HdSt_OsdFvarIndexComputation::Resolve() { - using namespace OpenSubdiv; - - if (_osdTopology && !_osdTopology->IsResolved()) return false; + using namespace OpenSubdiv; - if (!_TryLock()) return false; - - HdSt_Subdivision * subdivision = _topology->GetSubdivision(); - if (!TF_VERIFY(subdivision)) { - _SetResolved(); - return true; - } + if (_osdTopology && !_osdTopology->IsResolved()) + return false; - VtIntArray fvarIndices = subdivision->GetRefinedFvarIndices(_channel); - if (!TF_VERIFY(!fvarIndices.empty())) { - _SetResolved(); - return true; - } + if (!_TryLock()) + return false; - Far::Index const * firstIndex = fvarIndices.cdata(); - Far::PatchTable const * patchTable = subdivision->GetPatchTable(); - size_t numPatches = patchTable ? patchTable->GetNumPatchesTotal() : 0; - - TfToken const & scheme = _topology->GetScheme(); - - if (_topology->RefinesToBSplinePatches() || - _topology->RefinesToBoxSplineTrianglePatches()) { - - // Bundle groups of 12 or 16 patch control vertices - int const arraySize = patchTable ? - patchTable->GetFVarPatchDescriptor(_channel).GetNumControlVertices() - : 0; - - VtIntArray indices(arraySize * numPatches); - memcpy(indices.data(), firstIndex, - arraySize * numPatches * sizeof(int)); - - HdBufferSourceSharedPtr patchIndices = - std::make_shared( - _indicesName, VtValue(indices), arraySize); - - _SetResult(patchIndices); - _PopulateFvarPatchParamBuffer(patchTable); - } else if (HdSt_Subdivision::RefinesToTriangles(scheme)) { - // populate refined triangle indices. - VtArray indices(numPatches); - memcpy(reinterpret_cast(indices.data()), - firstIndex, 3 * numPatches * sizeof(int)); - - HdBufferSourceSharedPtr triIndices = - std::make_shared(_indicesName, VtValue(indices)); - _SetResult(triIndices); - } else { - // populate refined quad indices. - VtArray indices(numPatches); - memcpy(reinterpret_cast(indices.data()), - firstIndex, 4 * numPatches * sizeof(int)); - - HdBufferSourceSharedPtr quadIndices = - std::make_shared(_indicesName, VtValue(indices)); - _SetResult(quadIndices); - } + HdSt_Subdivision *subdivision = _topology->GetSubdivision(); + if (!TF_VERIFY(subdivision)) + { + _SetResolved(); + return true; + } + VtIntArray fvarIndices = subdivision->GetRefinedFvarIndices(_channel); + if (!TF_VERIFY(!fvarIndices.empty())) + { _SetResolved(); return true; + } + + Far::Index const *firstIndex = fvarIndices.cdata(); + Far::PatchTable const *patchTable = subdivision->GetPatchTable(); + size_t numPatches = patchTable ? patchTable->GetNumPatchesTotal() : 0; + + TfToken const &scheme = _topology->GetScheme(); + + if (_topology->RefinesToBSplinePatches() || + _topology->RefinesToBoxSplineTrianglePatches()) + { + + // Bundle groups of 12 or 16 patch control vertices + int const arraySize = patchTable ? patchTable->GetFVarPatchDescriptor(_channel).GetNumControlVertices() + : 0; + + VtIntArray indices(arraySize * numPatches); + memcpy(indices.data(), firstIndex, + arraySize * numPatches * sizeof(int)); + + HdBufferSourceSharedPtr patchIndices = + std::make_shared( + _indicesName, VtValue(indices), arraySize); + + _SetResult(patchIndices); + _PopulateFvarPatchParamBuffer(patchTable); + } + else if (HdSt_Subdivision::RefinesToTriangles(scheme)) + { + // populate refined triangle indices. + VtArray indices(numPatches); + memcpy(reinterpret_cast(indices.data()), + firstIndex, 3 * numPatches * sizeof(int)); + + HdBufferSourceSharedPtr triIndices = + std::make_shared(_indicesName, VtValue(indices)); + _SetResult(triIndices); + } + else + { + // populate refined quad indices. + VtArray indices(numPatches); + memcpy(reinterpret_cast(indices.data()), + firstIndex, 4 * numPatches * sizeof(int)); + + HdBufferSourceSharedPtr quadIndices = + std::make_shared(_indicesName, VtValue(indices)); + _SetResult(quadIndices); + } + + _SetResolved(); + return true; +} + +void HdSt_OsdFvarIndexComputation::_PopulateFvarPatchParamBuffer( + HdSt_Subdivision::PatchTable const *patchTable) +{ + HD_TRACE_FUNCTION(); + HF_MALLOC_TAG_FUNCTION(); + + VtVec2iArray fvarPatchParam(0); + + if (patchTable) + { + OpenSubdiv::Far::ConstPatchParamArray patchParamArray = + patchTable->GetFVarPatchParams(_channel); + size_t numPatches = patchParamArray.size(); + fvarPatchParam.resize(numPatches); + + for (size_t i = 0; i < numPatches; ++i) + { + OpenSubdiv::Far::PatchParam const &patchParam = patchParamArray[i]; + fvarPatchParam[i][0] = patchParam.field0; + fvarPatchParam[i][1] = patchParam.field1; + } + } + + _fvarPatchParamBuffer.reset(new HdVtBufferSource( + _patchParamName, VtValue(fvarPatchParam))); } -void -HdSt_OsdFvarIndexComputation::_PopulateFvarPatchParamBuffer( - HdSt_Subdivision::PatchTable const * patchTable) +void HdSt_OsdFvarIndexComputation::GetBufferSpecs(HdBufferSpecVector *specs) const { - HD_TRACE_FUNCTION(); - HF_MALLOC_TAG_FUNCTION(); - - VtVec2iArray fvarPatchParam(0); - - if (patchTable) { - OpenSubdiv::Far::ConstPatchParamArray patchParamArray = - patchTable->GetFVarPatchParams(_channel); - size_t numPatches = patchParamArray.size(); - fvarPatchParam.resize(numPatches); - - for (size_t i = 0; i < numPatches; ++i) { - OpenSubdiv::Far::PatchParam const &patchParam = patchParamArray[i]; - fvarPatchParam[i][0] = patchParam.field0; - fvarPatchParam[i][1] = patchParam.field1; - } - } - - _fvarPatchParamBuffer.reset(new HdVtBufferSource( - _patchParamName, VtValue(fvarPatchParam))); -} - -void -HdSt_OsdFvarIndexComputation::GetBufferSpecs(HdBufferSpecVector *specs) const -{ - if (_topology->RefinesToBSplinePatches()) { - // bi-cubic bspline patches - specs->emplace_back(_indicesName, HdTupleType {HdTypeInt32, 16}); - specs->emplace_back(_patchParamName, HdTupleType {HdTypeInt32Vec2, 1}); - } else if (_topology->RefinesToBoxSplineTrianglePatches()) { - // quartic box spline triangle patches - specs->emplace_back(_indicesName, HdTupleType {HdTypeInt32, 12}); - specs->emplace_back(_patchParamName, HdTupleType {HdTypeInt32Vec2, 1}); - } else if (HdSt_Subdivision::RefinesToTriangles(_topology->GetScheme())) { - // triangles (loop) - specs->emplace_back(_indicesName, HdTupleType {HdTypeInt32Vec3, 1}); - } else { - // quads (catmark, bilinear) - specs->emplace_back(_indicesName, HdTupleType {HdTypeInt32Vec4, 1}); - } + if (_topology->RefinesToBSplinePatches()) + { + // bi-cubic bspline patches + specs->emplace_back(_indicesName, HdTupleType{HdTypeInt32, 16}); + specs->emplace_back(_patchParamName, HdTupleType{HdTypeInt32Vec2, 1}); + } + else if (_topology->RefinesToBoxSplineTrianglePatches()) + { + // quartic box spline triangle patches + specs->emplace_back(_indicesName, HdTupleType{HdTypeInt32, 12}); + specs->emplace_back(_patchParamName, HdTupleType{HdTypeInt32Vec2, 1}); + } + else if (HdSt_Subdivision::RefinesToTriangles(_topology->GetScheme())) + { + // triangles (loop) + specs->emplace_back(_indicesName, HdTupleType{HdTypeInt32Vec3, 1}); + } + else + { + // quads (catmark, bilinear) + specs->emplace_back(_indicesName, HdTupleType{HdTypeInt32Vec4, 1}); + } } -bool -HdSt_OsdFvarIndexComputation::HasChainedBuffer() const +bool HdSt_OsdFvarIndexComputation::HasChainedBuffer() const { - return (_topology->RefinesToBSplinePatches() || - _topology->RefinesToBoxSplineTrianglePatches()); + return (_topology->RefinesToBSplinePatches() || + _topology->RefinesToBoxSplineTrianglePatches()); } HdBufferSourceSharedPtrVector HdSt_OsdFvarIndexComputation::GetChainedBuffers() const { - if (_topology->RefinesToBSplinePatches() || - _topology->RefinesToBoxSplineTrianglePatches()) { - return { _fvarPatchParamBuffer }; - } else { - return {}; - } + if (_topology->RefinesToBSplinePatches() || + _topology->RefinesToBoxSplineTrianglePatches()) + { + return {_fvarPatchParamBuffer}; + } + else + { + return {}; + } } -bool -HdSt_OsdFvarIndexComputation::_CheckValid() const { - return true; +bool HdSt_OsdFvarIndexComputation::_CheckValid() const +{ + return true; } // --------------------------------------------------------------------------- @@ -1579,242 +1641,256 @@ HdSt_OsdFvarIndexComputation::_CheckValid() const { HdSt_OsdBaseFaceToRefinedFacesMapComputation:: HdSt_OsdBaseFaceToRefinedFacesMapComputation( HdSt_Subdivision const *subdivision, - HdBufferSourceSharedPtr const &osdTopology) : - _subdivision(subdivision), _osdTopology(osdTopology) -{} + HdBufferSourceSharedPtr const &osdTopology) : _subdivision(subdivision), _osdTopology(osdTopology) +{ +} void HdSt_OsdBaseFaceToRefinedFacesMapComputation::GetBufferSpecs( HdBufferSpecVector *specs) const { - specs->emplace_back(_tokens->baseFaceToRefinedFacesMap, - HdTupleType {HdTypeInt32, 1}); - specs->emplace_back(_tokens->refinedFaceCounts, - HdTupleType {HdTypeInt32, 1}); + specs->emplace_back(_tokens->baseFaceToRefinedFacesMap, + HdTupleType{HdTypeInt32, 1}); + specs->emplace_back(_tokens->refinedFaceCounts, + HdTupleType{HdTypeInt32, 1}); } -bool -HdSt_OsdBaseFaceToRefinedFacesMapComputation::Resolve() +bool HdSt_OsdBaseFaceToRefinedFacesMapComputation::Resolve() { - if (_osdTopology && !_osdTopology->IsResolved()) return false; + if (_osdTopology && !_osdTopology->IsResolved()) + return false; - if (!_TryLock()) return false; + if (!_TryLock()) + return false; - if (!TF_VERIFY(_subdivision)) { - _SetResolved(); - return true; - } - - HdSt_Subdivision::PatchTable const *patchTable = - _subdivision->GetPatchTable(); - const size_t numPatches = patchTable ? - patchTable->GetPatchParamTable().size() : 0; - const size_t numBaseFaces = patchTable ? - patchTable->GetNumPtexFaces() : 0; - - std::vector> baseFaceToRefinedFacesMap(numBaseFaces); - - for (size_t i = 0; i < numPatches; ++i) { - OpenSubdiv::Far::PatchParam const &patchParam = - patchTable->GetPatchParamTable()[i]; - baseFaceToRefinedFacesMap[patchParam.GetFaceId()].push_back(i); - } + if (!TF_VERIFY(_subdivision)) + { + _SetResolved(); + return true; + } - VtIntArray baseFaceToRefinedFacesArr; - VtIntArray refinedFaceCounts(numBaseFaces); - size_t currRefinedFaceCount = 0; + HdSt_Subdivision::PatchTable const *patchTable = + _subdivision->GetPatchTable(); + const size_t numPatches = patchTable ? patchTable->GetPatchParamTable().size() : 0; + const size_t numBaseFaces = patchTable ? patchTable->GetNumPtexFaces() : 0; - for (size_t i = 0; i < numBaseFaces; ++i) { - std::vector refinedFaces = baseFaceToRefinedFacesMap[i]; - currRefinedFaceCount += refinedFaces.size(); - - for (size_t j = 0; j < refinedFaces.size(); ++j) { - baseFaceToRefinedFacesArr.push_back(refinedFaces[j]); - } - refinedFaceCounts[i] = currRefinedFaceCount; + std::vector> baseFaceToRefinedFacesMap(numBaseFaces); + + for (size_t i = 0; i < numPatches; ++i) + { + OpenSubdiv::Far::PatchParam const &patchParam = + patchTable->GetPatchParamTable()[i]; + baseFaceToRefinedFacesMap[patchParam.GetFaceId()].push_back(i); + } + + VtIntArray baseFaceToRefinedFacesArr; + VtIntArray refinedFaceCounts(numBaseFaces); + size_t currRefinedFaceCount = 0; + + for (size_t i = 0; i < numBaseFaces; ++i) + { + std::vector refinedFaces = baseFaceToRefinedFacesMap[i]; + currRefinedFaceCount += refinedFaces.size(); + + for (size_t j = 0; j < refinedFaces.size(); ++j) + { + baseFaceToRefinedFacesArr.push_back(refinedFaces[j]); } + refinedFaceCounts[i] = currRefinedFaceCount; + } - HdBufferSourceSharedPtr source = std::make_shared( - _tokens->baseFaceToRefinedFacesMap, VtValue(baseFaceToRefinedFacesArr)); - _SetResult(source); + HdBufferSourceSharedPtr source = std::make_shared( + _tokens->baseFaceToRefinedFacesMap, VtValue(baseFaceToRefinedFacesArr)); + _SetResult(source); - _refinedFaceCounts = std::make_shared( - _tokens->refinedFaceCounts, VtValue(refinedFaceCounts)); + _refinedFaceCounts = std::make_shared( + _tokens->refinedFaceCounts, VtValue(refinedFaceCounts)); - _SetResolved(); - return true; + _SetResolved(); + return true; } -bool -HdSt_OsdBaseFaceToRefinedFacesMapComputation::HasChainedBuffer() const +bool HdSt_OsdBaseFaceToRefinedFacesMapComputation::HasChainedBuffer() const { - return true; + return true; } HdBufferSourceSharedPtrVector HdSt_OsdBaseFaceToRefinedFacesMapComputation::GetChainedBuffers() const { - return { _refinedFaceCounts }; + return {_refinedFaceCounts}; } -bool -HdSt_OsdBaseFaceToRefinedFacesMapComputation::_CheckValid() const +bool HdSt_OsdBaseFaceToRefinedFacesMapComputation::_CheckValid() const { - return true; + return true; } // --------------------------------------------------------------------------- -namespace { - -void -_EvalStencilsCPU( - std::vector * primvarBuffer, - int const elementStride, - int const numCoarsePoints, - int const numRefinedPoints, - std::vector const & sizes, - std::vector const & offsets, - std::vector const & indices, - std::vector const & weights) +namespace { + + void + _EvalStencilsCPU( + std::vector *primvarBuffer, + int const elementStride, + int const numCoarsePoints, + int const numRefinedPoints, + std::vector const &sizes, + std::vector const &offsets, + std::vector const &indices, + std::vector const &weights) + { int const numElements = elementStride; std::vector dst(numElements); - for (int pointIndex = 0; pointIndex < numRefinedPoints; ++pointIndex) { - for (int element = 0; element < numElements; ++element) { - dst[element] = 0; - } - - int const stencilSize = sizes[pointIndex]; - int const stencilOffset = offsets[pointIndex]; - - for (int stencil = 0; stencil < stencilSize; ++stencil) { - int const index = indices[stencil + stencilOffset]; - float const weight = weights[stencil + stencilOffset]; - int const srcIndex = index * elementStride; - for (int element = 0; element < numElements; ++element) { - dst[element] += weight * (*primvarBuffer)[srcIndex + element]; - } + for (int pointIndex = 0; pointIndex < numRefinedPoints; ++pointIndex) + { + for (int element = 0; element < numElements; ++element) + { + dst[element] = 0; + } + + int const stencilSize = sizes[pointIndex]; + int const stencilOffset = offsets[pointIndex]; + + for (int stencil = 0; stencil < stencilSize; ++stencil) + { + int const index = indices[stencil + stencilOffset]; + float const weight = weights[stencil + stencilOffset]; + int const srcIndex = index * elementStride; + for (int element = 0; element < numElements; ++element) + { + dst[element] += weight * (*primvarBuffer)[srcIndex + element]; } + } - int const dstIndex = (pointIndex + numCoarsePoints) * elementStride; - for (int element = 0; element < numElements; ++element) { - (*primvarBuffer)[dstIndex + element] = dst[element]; - } + int const dstIndex = (pointIndex + numCoarsePoints) * elementStride; + for (int element = 0; element < numElements; ++element) + { + (*primvarBuffer)[dstIndex + element] = dst[element]; + } } -} + } -enum { + enum + { BufferBinding_Uniforms, BufferBinding_Sizes, BufferBinding_Offsets, BufferBinding_Indices, BufferBinding_Weights, BufferBinding_Primvar, -}; - -HgiResourceBindingsSharedPtr -_CreateResourceBindings( - Hgi* hgi, - HgiBufferHandle const & sizes, - HgiBufferHandle const & offsets, - HgiBufferHandle const & indices, - HgiBufferHandle const & weights, - HgiBufferHandle const & primvar) -{ + }; + + HgiResourceBindingsSharedPtr + _CreateResourceBindings( + Hgi *hgi, + HgiBufferHandle const &sizes, + HgiBufferHandle const &offsets, + HgiBufferHandle const &indices, + HgiBufferHandle const &weights, + HgiBufferHandle const &primvar) + { // Begin the resource set HgiResourceBindingsDesc resourceDesc; resourceDesc.debugName = "EvalStencils"; - if (sizes) { - HgiBufferBindDesc bufBind0; - bufBind0.bindingIndex = BufferBinding_Sizes; - bufBind0.resourceType = HgiBindResourceTypeStorageBuffer; - bufBind0.stageUsage = HgiShaderStageCompute; - bufBind0.writable = false; - bufBind0.offsets.push_back(0); - bufBind0.buffers.push_back(sizes); - resourceDesc.buffers.push_back(std::move(bufBind0)); + if (sizes) + { + HgiBufferBindDesc bufBind0; + bufBind0.bindingIndex = BufferBinding_Sizes; + bufBind0.resourceType = HgiBindResourceTypeStorageBuffer; + bufBind0.stageUsage = HgiShaderStageCompute; + bufBind0.writable = false; + bufBind0.offsets.push_back(0); + bufBind0.buffers.push_back(sizes); + resourceDesc.buffers.push_back(std::move(bufBind0)); } - if (offsets) { - HgiBufferBindDesc bufBind1; - bufBind1.bindingIndex = BufferBinding_Offsets; - bufBind1.resourceType = HgiBindResourceTypeStorageBuffer; - bufBind1.stageUsage = HgiShaderStageCompute; - bufBind1.writable = false; - bufBind1.offsets.push_back(0); - bufBind1.buffers.push_back(offsets); - resourceDesc.buffers.push_back(std::move(bufBind1)); + if (offsets) + { + HgiBufferBindDesc bufBind1; + bufBind1.bindingIndex = BufferBinding_Offsets; + bufBind1.resourceType = HgiBindResourceTypeStorageBuffer; + bufBind1.stageUsage = HgiShaderStageCompute; + bufBind1.writable = false; + bufBind1.offsets.push_back(0); + bufBind1.buffers.push_back(offsets); + resourceDesc.buffers.push_back(std::move(bufBind1)); } - if (indices) { - HgiBufferBindDesc bufBind2; - bufBind2.bindingIndex = BufferBinding_Indices; - bufBind2.resourceType = HgiBindResourceTypeStorageBuffer; - bufBind2.stageUsage = HgiShaderStageCompute; - bufBind2.writable = false; - bufBind2.offsets.push_back(0); - bufBind2.buffers.push_back(indices); - resourceDesc.buffers.push_back(std::move(bufBind2)); + if (indices) + { + HgiBufferBindDesc bufBind2; + bufBind2.bindingIndex = BufferBinding_Indices; + bufBind2.resourceType = HgiBindResourceTypeStorageBuffer; + bufBind2.stageUsage = HgiShaderStageCompute; + bufBind2.writable = false; + bufBind2.offsets.push_back(0); + bufBind2.buffers.push_back(indices); + resourceDesc.buffers.push_back(std::move(bufBind2)); } - if (weights) { - HgiBufferBindDesc bufBind3; - bufBind3.bindingIndex = BufferBinding_Weights; - bufBind3.resourceType = HgiBindResourceTypeStorageBuffer; - bufBind3.stageUsage = HgiShaderStageCompute; - bufBind3.writable = false; - bufBind3.offsets.push_back(0); - bufBind3.buffers.push_back(weights); - resourceDesc.buffers.push_back(std::move(bufBind3)); + if (weights) + { + HgiBufferBindDesc bufBind3; + bufBind3.bindingIndex = BufferBinding_Weights; + bufBind3.resourceType = HgiBindResourceTypeStorageBuffer; + bufBind3.stageUsage = HgiShaderStageCompute; + bufBind3.writable = false; + bufBind3.offsets.push_back(0); + bufBind3.buffers.push_back(weights); + resourceDesc.buffers.push_back(std::move(bufBind3)); } - if (primvar) { - HgiBufferBindDesc bufBind4; - bufBind4.bindingIndex = BufferBinding_Primvar; - bufBind4.resourceType = HgiBindResourceTypeStorageBuffer; - bufBind4.stageUsage = HgiShaderStageCompute; - bufBind4.writable = true; - bufBind4.offsets.push_back(0); - bufBind4.buffers.push_back(primvar); - resourceDesc.buffers.push_back(std::move(bufBind4)); + if (primvar) + { + HgiBufferBindDesc bufBind4; + bufBind4.bindingIndex = BufferBinding_Primvar; + bufBind4.resourceType = HgiBindResourceTypeStorageBuffer; + bufBind4.stageUsage = HgiShaderStageCompute; + bufBind4.writable = true; + bufBind4.offsets.push_back(0); + bufBind4.buffers.push_back(primvar); + resourceDesc.buffers.push_back(std::move(bufBind4)); } return std::make_shared( hgi->CreateResourceBindings(resourceDesc)); -} - -HgiComputePipelineSharedPtr -_CreatePipeline( - Hgi * hgi, - uint32_t constantValuesSize, - HgiShaderProgramHandle const & program) -{ + } + + HgiComputePipelineSharedPtr + _CreatePipeline( + Hgi *hgi, + uint32_t constantValuesSize, + HgiShaderProgramHandle const &program) + { HgiComputePipelineDesc desc; desc.debugName = "EvalStencils"; desc.shaderProgram = program; desc.shaderConstantsDesc.byteSize = constantValuesSize; return std::make_shared( hgi->CreateComputePipeline(desc)); -} - -void -_EvalStencilsGPU( - HdBufferArrayRangeSharedPtr const & primvarRange_, - TfToken const & primvarName, - int const numCoarsePoints, - int const numRefinedPoints, - HdBufferArrayRangeSharedPtr const & perPointRange_, - HdBufferArrayRangeSharedPtr const & perIndexRange_, - HdResourceRegistry * resourceRegistry) -{ + } + + void + _EvalStencilsGPU( + HdBufferArrayRangeSharedPtr const &primvarRange_, + TfToken const &primvarName, + int const numCoarsePoints, + int const numRefinedPoints, + HdBufferArrayRangeSharedPtr const &perPointRange_, + HdBufferArrayRangeSharedPtr const &perIndexRange_, + HdResourceRegistry *resourceRegistry) + { // select shader by datatype TfToken shaderToken = _tokens->evalStencils; - if (!TF_VERIFY(!shaderToken.IsEmpty())) return; + if (!TF_VERIFY(!shaderToken.IsEmpty())) + return; HdStBufferArrayRangeSharedPtr primvarRange = - std::static_pointer_cast (primvarRange_); + std::static_pointer_cast(primvarRange_); HdStBufferResourceSharedPtr primvar = primvarRange->GetResource(primvarName); @@ -1822,78 +1898,82 @@ _EvalStencilsGPU( size_t const elementStride = HdGetComponentCount(primvar->GetTupleType().type); - struct Uniform { - int pointIndexStart; - int pointIndexEnd; - int srcBase; - int srcStride; - int dstBase; - int dstStride; - int sizesBase; - int offsetsBase; - int indicesBase; - int weightsBase; + struct Uniform + { + int pointIndexStart; + int pointIndexEnd; + int srcBase; + int srcStride; + int dstBase; + int dstStride; + int sizesBase; + int offsetsBase; + int indicesBase; + int weightsBase; } uniform; - HdStResourceRegistry* hdStResourceRegistry = - static_cast(resourceRegistry); + HdStResourceRegistry *hdStResourceRegistry = + static_cast(resourceRegistry); std::string const defines = TfStringPrintf("#define EVAL_STENCILS_NUM_ELEMENTS %zd\n", elementStride); - HdStGLSLProgramSharedPtr computeProgram - = HdStGLSLProgram::GetComputeProgram(shaderToken, - defines, - hdStResourceRegistry, - [&](HgiShaderFunctionDesc &computeDesc) { - computeDesc.debugName = shaderToken.GetString(); - computeDesc.shaderStage = HgiShaderStageCompute; - computeDesc.computeDescriptor.localSize = GfVec3i(64, 1, 1); - - HgiShaderFunctionAddBuffer(&computeDesc, - "sizes", HdStTokens->_int, - BufferBinding_Sizes, HgiBindingTypePointer); - HgiShaderFunctionAddBuffer(&computeDesc, - "offsets", HdStTokens->_int, - BufferBinding_Offsets, HgiBindingTypePointer); - HgiShaderFunctionAddBuffer(&computeDesc, - "indices", HdStTokens->_int, - BufferBinding_Indices, HgiBindingTypePointer); - HgiShaderFunctionAddBuffer(&computeDesc, - "weights", HdStTokens->_float, - BufferBinding_Weights, HgiBindingTypePointer); - HgiShaderFunctionAddWritableBuffer(&computeDesc, - "primvar", HdStTokens->_float, - BufferBinding_Primvar); - - static const std::string params[] = { - "pointIndexStart", - "pointIndexEnd", - "srcBase", - "srcStride", - "dstBase", - "dstStride", - "sizesBase", - "offsetsBase", - "indicesBase", - "weightsBase", - }; - static_assert((sizeof(Uniform) / sizeof(int)) == - (sizeof(params) / sizeof(params[0])), ""); - for (std::string const & param : params) { - HgiShaderFunctionAddConstantParam( - &computeDesc, param, HdStTokens->_int); - } - HgiShaderFunctionAddStageInput( - &computeDesc, "hd_GlobalInvocationID", "uvec3", - HgiShaderKeywordTokens->hdGlobalInvocationID); - }); - - if (!computeProgram) return; + HdStGLSLProgramSharedPtr computeProgram = HdStGLSLProgram::GetComputeProgram(shaderToken, + defines, + hdStResourceRegistry, + [&](HgiShaderFunctionDesc &computeDesc) + { + computeDesc.debugName = shaderToken.GetString(); + computeDesc.shaderStage = HgiShaderStageCompute; + computeDesc.computeDescriptor.localSize = GfVec3i(64, 1, 1); + + HgiShaderFunctionAddBuffer(&computeDesc, + "sizes", HdStTokens->_int, + BufferBinding_Sizes, HgiBindingTypePointer); + HgiShaderFunctionAddBuffer(&computeDesc, + "offsets", HdStTokens->_int, + BufferBinding_Offsets, HgiBindingTypePointer); + HgiShaderFunctionAddBuffer(&computeDesc, + "indices", HdStTokens->_int, + BufferBinding_Indices, HgiBindingTypePointer); + HgiShaderFunctionAddBuffer(&computeDesc, + "weights", HdStTokens->_float, + BufferBinding_Weights, HgiBindingTypePointer); + HgiShaderFunctionAddWritableBuffer(&computeDesc, + "primvar", HdStTokens->_float, + BufferBinding_Primvar); + + static const std::string params[] = { + "pointIndexStart", + "pointIndexEnd", + "srcBase", + "srcStride", + "dstBase", + "dstStride", + "sizesBase", + "offsetsBase", + "indicesBase", + "weightsBase", + }; + static_assert((sizeof(Uniform) / sizeof(int)) == + (sizeof(params) / sizeof(params[0])), + ""); + for (std::string const ¶m : params) + { + HgiShaderFunctionAddConstantParam( + &computeDesc, param, HdStTokens->_int); + } + HgiShaderFunctionAddStageInput( + &computeDesc, "hd_GlobalInvocationID", "uvec3", + HgiShaderKeywordTokens->hdGlobalInvocationID); + }); + + if (!computeProgram) + return; HdStBufferArrayRangeSharedPtr perPointRange = - std::static_pointer_cast (perPointRange_); + std::static_pointer_cast(perPointRange_); HdStBufferArrayRangeSharedPtr perIndexRange = - std::static_pointer_cast (perIndexRange_); + std::static_pointer_cast(perIndexRange_); // prepare uniform buffer for GPU computation uniform.pointIndexStart = 0; @@ -1913,61 +1993,63 @@ _EvalStencilsGPU( // buffer resources for GPU computation HdStBufferResourceSharedPtr sizes = perPointRange->GetResource( - _tokens->sizes); + _tokens->sizes); HdStBufferResourceSharedPtr offsets = perPointRange->GetResource( - _tokens->offsets); + _tokens->offsets); HdStBufferResourceSharedPtr indices = perIndexRange->GetResource( - _tokens->indices); + _tokens->indices); HdStBufferResourceSharedPtr weights = perIndexRange->GetResource( - _tokens->weights); + _tokens->weights); - Hgi* hgi = hdStResourceRegistry->GetHgi(); + Hgi *hgi = hdStResourceRegistry->GetHgi(); // Generate hash for resource bindings and pipeline. // XXX Needs fingerprint hash to avoid collisions - uint64_t const rbHash = (uint64_t) TfHash::Combine( + uint64_t const rbHash = (uint64_t)TfHash::Combine( sizes->GetHandle().Get(), offsets->GetHandle().Get(), indices->GetHandle().Get(), weights->GetHandle().Get(), primvar->GetHandle().Get()); - uint64_t const pHash = (uint64_t) TfHash::Combine( + uint64_t const pHash = (uint64_t)TfHash::Combine( computeProgram->GetProgram().Get(), sizeof(uniform)); // Get or add resource bindings in registry. HdInstance resourceBindingsInstance = hdStResourceRegistry->RegisterResourceBindings(rbHash); - if (resourceBindingsInstance.IsFirstInstance()) { - HgiResourceBindingsSharedPtr rb = - _CreateResourceBindings(hgi, - sizes->GetHandle(), - offsets->GetHandle(), - indices->GetHandle(), - weights->GetHandle(), - primvar->GetHandle()); - resourceBindingsInstance.SetValue(rb); + if (resourceBindingsInstance.IsFirstInstance()) + { + HgiResourceBindingsSharedPtr rb = + _CreateResourceBindings(hgi, + sizes->GetHandle(), + offsets->GetHandle(), + indices->GetHandle(), + weights->GetHandle(), + primvar->GetHandle()); + resourceBindingsInstance.SetValue(rb); } - HgiResourceBindingsSharedPtr const & resourceBindingsPtr = + HgiResourceBindingsSharedPtr const &resourceBindingsPtr = resourceBindingsInstance.GetValue(); HgiResourceBindingsHandle resourceBindings = *resourceBindingsPtr.get(); // Get or add pipeline in registry. HdInstance computePipelineInstance = hdStResourceRegistry->RegisterComputePipeline(pHash); - if (computePipelineInstance.IsFirstInstance()) { - HgiComputePipelineSharedPtr pipe = _CreatePipeline( - hgi, sizeof(uniform), computeProgram->GetProgram()); - computePipelineInstance.SetValue(pipe); + if (computePipelineInstance.IsFirstInstance()) + { + HgiComputePipelineSharedPtr pipe = _CreatePipeline( + hgi, sizeof(uniform), computeProgram->GetProgram()); + computePipelineInstance.SetValue(pipe); } - HgiComputePipelineSharedPtr const & pipelinePtr = + HgiComputePipelineSharedPtr const &pipelinePtr = computePipelineInstance.GetValue(); HgiComputePipelineHandle pipeline = *pipelinePtr.get(); - HgiComputeCmds* computeCmds = hdStResourceRegistry->GetGlobalComputeCmds(); + HgiComputeCmds *computeCmds = hdStResourceRegistry->GetGlobalComputeCmds(); computeCmds->PushDebugGroup("EvalStencils Cmds"); computeCmds->BindResources(resourceBindings); computeCmds->BindPipeline(pipeline); @@ -1981,9 +2063,8 @@ _EvalStencilsGPU( // submit the work computeCmds->PopDebugGroup(); -} + } } // Anonymous namespace - PXR_NAMESPACE_CLOSE_SCOPE diff --git a/Sources/OpenUSD/imaging/hdSt/vboMemoryManager.cpp b/Sources/OpenUSD/imaging/hdSt/vboMemoryManager.cpp index f40fe3cd2a..c060857de5 100644 --- a/Sources/OpenUSD/imaging/hdSt/vboMemoryManager.cpp +++ b/Sources/OpenUSD/imaging/hdSt/vboMemoryManager.cpp @@ -38,7 +38,7 @@ #include "pxr/imaging/hgi/blitCmdsOps.h" #include "pxr/imaging/hgi/buffer.h" -#include "pxr/base/arch/hash.h" +#include "Arch/hash.h" #include "pxr/base/tf/diagnostic.h" #include "pxr/base/tf/envSetting.h" #include "pxr/base/tf/iterator.h" @@ -50,8 +50,7 @@ PXR_NAMESPACE_OPEN_SCOPE - -TF_DEFINE_ENV_SETTING(HD_MAX_VBO_SIZE, (1*1024*1024*1024), +TF_DEFINE_ENV_SETTING(HD_MAX_VBO_SIZE, (1 * 1024 * 1024 * 1024), "Maximum aggregated VBO size"); // --------------------------------------------------------------------------- @@ -63,91 +62,92 @@ HdStVBOMemoryManager::CreateBufferArray( HdBufferSpecVector const &bufferSpecs, HdBufferArrayUsageHint usageHint) { - return std::make_shared( - _resourceRegistry, role, bufferSpecs, usageHint); + return std::make_shared( + _resourceRegistry, role, bufferSpecs, usageHint); } - HdBufferArrayRangeSharedPtr HdStVBOMemoryManager::CreateBufferArrayRange() { - return std::make_shared<_StripedBufferArrayRange>(_resourceRegistry); + return std::make_shared<_StripedBufferArrayRange>(_resourceRegistry); } - HdStAggregationStrategy::AggregationId HdStVBOMemoryManager::ComputeAggregationId( HdBufferSpecVector const &bufferSpecs, HdBufferArrayUsageHint usageHint) const { - static size_t salt = ArchHash(__FUNCTION__, sizeof(__FUNCTION__)); - size_t result = salt; - for (HdBufferSpec const &spec : bufferSpecs) { - boost::hash_combine(result, spec.Hash()); - } + static size_t salt = ArchHash(__FUNCTION__, sizeof(__FUNCTION__)); + size_t result = salt; + for (HdBufferSpec const &spec : bufferSpecs) + { + boost::hash_combine(result, spec.Hash()); + } - boost::hash_combine(result, usageHint.value); + boost::hash_combine(result, usageHint.value); - // promote to size_t - return (AggregationId)result; + // promote to size_t + return (AggregationId)result; } - /// Returns the buffer specs from a given buffer array -HdBufferSpecVector +HdBufferSpecVector HdStVBOMemoryManager::GetBufferSpecs( HdBufferArraySharedPtr const &bufferArray) const { - _StripedBufferArraySharedPtr bufferArray_ = - std::static_pointer_cast<_StripedBufferArray> (bufferArray); - return bufferArray_->GetBufferSpecs(); + _StripedBufferArraySharedPtr bufferArray_ = + std::static_pointer_cast<_StripedBufferArray>(bufferArray); + return bufferArray_->GetBufferSpecs(); } - /// Returns the size of the GPU memory used by the passed buffer array -size_t +size_t HdStVBOMemoryManager::GetResourceAllocation( - HdBufferArraySharedPtr const &bufferArray, - VtDictionary &result) const -{ - std::set idSet; - size_t gpuMemoryUsed = 0; - - _StripedBufferArraySharedPtr bufferArray_ = - std::static_pointer_cast<_StripedBufferArray> (bufferArray); - - TF_FOR_ALL(resIt, bufferArray_->GetResources()) { - HdStBufferResourceSharedPtr const & resource = resIt->second; - HgiBufferHandle buffer = resource->GetHandle(); - - // XXX avoid double counting of resources shared within a buffer - uint64_t id = buffer ? buffer->GetRawResource() : 0; - if (idSet.count(id) == 0) { - idSet.insert(id); - - std::string const & role = resource->GetRole().GetString(); - size_t size = size_t(resource->GetSize()); - - if (result.count(role)) { - size_t currentSize = result[role].Get(); - result[role] = VtValue(currentSize + size); - } else { - result[role] = VtValue(size); - } - - gpuMemoryUsed += size; - } + HdBufferArraySharedPtr const &bufferArray, + VtDictionary &result) const +{ + std::set idSet; + size_t gpuMemoryUsed = 0; + + _StripedBufferArraySharedPtr bufferArray_ = + std::static_pointer_cast<_StripedBufferArray>(bufferArray); + + TF_FOR_ALL(resIt, bufferArray_->GetResources()) + { + HdStBufferResourceSharedPtr const &resource = resIt->second; + HgiBufferHandle buffer = resource->GetHandle(); + + // XXX avoid double counting of resources shared within a buffer + uint64_t id = buffer ? buffer->GetRawResource() : 0; + if (idSet.count(id) == 0) + { + idSet.insert(id); + + std::string const &role = resource->GetRole().GetString(); + size_t size = size_t(resource->GetSize()); + + if (result.count(role)) + { + size_t currentSize = result[role].Get(); + result[role] = VtValue(currentSize + size); + } + else + { + result[role] = VtValue(size); + } + + gpuMemoryUsed += size; } + } - return gpuMemoryUsed; + return gpuMemoryUsed; } - // --------------------------------------------------------------------------- // _StripedBufferArray // --------------------------------------------------------------------------- HdStVBOMemoryManager::_StripedBufferArray::_StripedBufferArray( - HdStResourceRegistry* resourceRegistry, + HdStResourceRegistry *resourceRegistry, TfToken const &role, HdBufferSpecVector const &bufferSpecs, HdBufferArrayUsageHint usageHint) @@ -157,361 +157,389 @@ HdStVBOMemoryManager::_StripedBufferArray::_StripedBufferArray( _totalCapacity(0), _maxBytesPerElement(0) { - HD_TRACE_FUNCTION(); - HF_MALLOC_TAG_FUNCTION(); - - /* - non-interleaved non-uniform buffer array (for example) - .------------------------------------------------------. - vec3 | pos.x (prim0) || pos.x (prim1) || ... | - | y || y || | - | z || z || | - '------------------------------------------------------' - .------------------------------------------------------. - vec4 | color.r (prim0) || color.r (prim1) || ... | - | g || g || | - | b || b || | - | a || a || | - '------------------------------------------------------' - ^--range0.numElements--^^--range1.numElements--^ - | - ^-^ ^--range1.offset - stride - */ - - // populate BufferResources - TF_FOR_ALL(it, bufferSpecs) { - int stride = HdDataSizeOfTupleType(it->tupleType); - _AddResource(it->name, it->tupleType, /*offset*/0, stride); - } - - // VBO Memory Manage supports an effectivly limitless set of ranges - _SetMaxNumRanges(std::numeric_limits::max()); - - // compute max bytes / elements - TF_FOR_ALL (it, GetResources()) { - _maxBytesPerElement = std::max( - _maxBytesPerElement, - HdDataSizeOfTupleType(it->second->GetTupleType())); - } - - // GetMaxNumElements() will crash with a divide by 0 - // error if _maxBytesPerElement is 0. - // - // This can happen if bufferSpecs was empty and thus - // no resources were added. If means something went - // wrong earlier and we are just trying to survive. - if (!TF_VERIFY(_maxBytesPerElement != 0)) - { - _maxBytesPerElement = 1; - } + HD_TRACE_FUNCTION(); + HF_MALLOC_TAG_FUNCTION(); + + /* + non-interleaved non-uniform buffer array (for example) + .------------------------------------------------------. + vec3 | pos.x (prim0) || pos.x (prim1) || ... | + | y || y || | + | z || z || | + '------------------------------------------------------' + .------------------------------------------------------. + vec4 | color.r (prim0) || color.r (prim1) || ... | + | g || g || | + | b || b || | + | a || a || | + '------------------------------------------------------' + ^--range0.numElements--^^--range1.numElements--^ + | + ^-^ ^--range1.offset + stride + */ + + // populate BufferResources + TF_FOR_ALL(it, bufferSpecs) + { + int stride = HdDataSizeOfTupleType(it->tupleType); + _AddResource(it->name, it->tupleType, /*offset*/ 0, stride); + } + + // VBO Memory Manage supports an effectivly limitless set of ranges + _SetMaxNumRanges(std::numeric_limits::max()); + + // compute max bytes / elements + TF_FOR_ALL(it, GetResources()) + { + _maxBytesPerElement = std::max( + _maxBytesPerElement, + HdDataSizeOfTupleType(it->second->GetTupleType())); + } + + // GetMaxNumElements() will crash with a divide by 0 + // error if _maxBytesPerElement is 0. + // + // This can happen if bufferSpecs was empty and thus + // no resources were added. If means something went + // wrong earlier and we are just trying to survive. + if (!TF_VERIFY(_maxBytesPerElement != 0)) + { + _maxBytesPerElement = 1; + } } HdStBufferResourceSharedPtr -HdStVBOMemoryManager::_StripedBufferArray::_AddResource(TfToken const& name, - HdTupleType tupleType, - int offset, - int stride) -{ - HD_TRACE_FUNCTION(); - if (TfDebug::IsEnabled(HD_SAFE_MODE)) { - // duplication check - HdStBufferResourceSharedPtr bufferRes = GetResource(name); - if (!TF_VERIFY(!bufferRes)) { - return bufferRes; - } +HdStVBOMemoryManager::_StripedBufferArray::_AddResource(TfToken const &name, + HdTupleType tupleType, + int offset, + int stride) +{ + HD_TRACE_FUNCTION(); + if (TfDebug::IsEnabled(HD_SAFE_MODE)) + { + // duplication check + HdStBufferResourceSharedPtr bufferRes = GetResource(name); + if (!TF_VERIFY(!bufferRes)) + { + return bufferRes; } + } - HdStBufferResourceSharedPtr bufferRes = - std::make_shared( - GetRole(), tupleType, offset, stride); - _resourceList.emplace_back(name, bufferRes); - return bufferRes; + HdStBufferResourceSharedPtr bufferRes = + std::make_shared( + GetRole(), tupleType, offset, stride); + _resourceList.emplace_back(name, bufferRes); + return bufferRes; } HdStVBOMemoryManager::_StripedBufferArray::~_StripedBufferArray() { - HD_TRACE_FUNCTION(); - HF_MALLOC_TAG_FUNCTION(); + HD_TRACE_FUNCTION(); + HF_MALLOC_TAG_FUNCTION(); - // invalidate buffer array ranges in range list - // (these ranges may still be held by drawItems) - size_t rangeCount = GetRangeCount(); - for (size_t rangeIdx = 0; rangeIdx < rangeCount; ++rangeIdx) { - _StripedBufferArrayRangeSharedPtr range = _GetRangeSharedPtr(rangeIdx); + // invalidate buffer array ranges in range list + // (these ranges may still be held by drawItems) + size_t rangeCount = GetRangeCount(); + for (size_t rangeIdx = 0; rangeIdx < rangeCount; ++rangeIdx) + { + _StripedBufferArrayRangeSharedPtr range = _GetRangeSharedPtr(rangeIdx); - if (range) { - range->Invalidate(); - } + if (range) + { + range->Invalidate(); } + } } - -bool -HdStVBOMemoryManager::_StripedBufferArray::GarbageCollect() +bool HdStVBOMemoryManager::_StripedBufferArray::GarbageCollect() { - HD_TRACE_FUNCTION(); - HF_MALLOC_TAG_FUNCTION(); + HD_TRACE_FUNCTION(); + HF_MALLOC_TAG_FUNCTION(); - if (_needsCompaction) { - RemoveUnusedRanges(); + if (_needsCompaction) + { + RemoveUnusedRanges(); - std::vector ranges; - size_t rangeCount = GetRangeCount(); - ranges.reserve(rangeCount); - for (size_t i = 0; i < rangeCount; ++i) { - HdBufferArrayRangeSharedPtr range = GetRange(i).lock(); - if (range) - ranges.push_back(range); - } - Reallocate(ranges, shared_from_this()); + std::vector ranges; + size_t rangeCount = GetRangeCount(); + ranges.reserve(rangeCount); + for (size_t i = 0; i < rangeCount; ++i) + { + HdBufferArrayRangeSharedPtr range = GetRange(i).lock(); + if (range) + ranges.push_back(range); } + Reallocate(ranges, shared_from_this()); + } - if (GetRangeCount() == 0) { - _DeallocateResources(); - return true; - } - return false; + if (GetRangeCount() == 0) + { + _DeallocateResources(); + return true; + } + return false; } -void -HdStVBOMemoryManager::_StripedBufferArray::Reallocate( +void HdStVBOMemoryManager::_StripedBufferArray::Reallocate( std::vector const &ranges, HdBufferArraySharedPtr const &curRangeOwner) { - HD_TRACE_FUNCTION(); - HF_MALLOC_TAG_FUNCTION(); + HD_TRACE_FUNCTION(); + HF_MALLOC_TAG_FUNCTION(); - HD_PERF_COUNTER_INCR(HdPerfTokens->vboRelocated); + HD_PERF_COUNTER_INCR(HdPerfTokens->vboRelocated); - _StripedBufferArraySharedPtr curRangeOwner_ = - std::static_pointer_cast<_StripedBufferArray> (curRangeOwner); + _StripedBufferArraySharedPtr curRangeOwner_ = + std::static_pointer_cast<_StripedBufferArray>(curRangeOwner); - if (!TF_VERIFY(GetResources().size() == - curRangeOwner_->GetResources().size())) { - TF_CODING_ERROR("Resource mismatch when reallocating buffer array"); - return; + if (!TF_VERIFY(GetResources().size() == + curRangeOwner_->GetResources().size())) + { + TF_CODING_ERROR("Resource mismatch when reallocating buffer array"); + return; + } + + if (TfDebug::IsEnabled(HD_SAFE_MODE)) + { + HdStBufferResourceNamedList::size_type bresIdx = 0; + TF_FOR_ALL(bresIt, GetResources()) + { + TF_VERIFY(curRangeOwner_->GetResources()[bresIdx++].second == + curRangeOwner_->GetResource(bresIt->first)); } + } - if (TfDebug::IsEnabled(HD_SAFE_MODE)) { - HdStBufferResourceNamedList::size_type bresIdx = 0; - TF_FOR_ALL(bresIt, GetResources()) { - TF_VERIFY(curRangeOwner_->GetResources()[bresIdx++].second == - curRangeOwner_->GetResource(bresIt->first)); - } + // count up total elements and update new offsets + size_t totalNumElements = 0; + std::vector newOffsets; + newOffsets.reserve(ranges.size()); + + TF_FOR_ALL(it, ranges) + { + HdBufferArrayRangeSharedPtr const &range = *it; + if (!range) + { + TF_CODING_ERROR("Expired range found in the reallocation list"); + continue; } - // count up total elements and update new offsets - size_t totalNumElements = 0; - std::vector newOffsets; - newOffsets.reserve(ranges.size()); + // save new offset + newOffsets.push_back(totalNumElements); - TF_FOR_ALL (it, ranges) { - HdBufferArrayRangeSharedPtr const &range = *it; - if (!range) { - TF_CODING_ERROR("Expired range found in the reallocation list"); - continue; - } + // XXX: always tightly pack for now. + totalNumElements += range->GetNumElements(); + } - // save new offset - newOffsets.push_back(totalNumElements); + // update range list (should be done before early exit) + _SetRangeList(ranges); - // XXX: always tightly pack for now. - totalNumElements += range->GetNumElements(); + _totalCapacity = totalNumElements; + + Hgi *hgi = _resourceRegistry->GetHgi(); + HgiBlitCmds *blitCmds = _resourceRegistry->GetGlobalBlitCmds(); + blitCmds->PushDebugGroup(__ARCH_PRETTY_FUNCTION__); + + // resize each BufferResource + HdStBufferResourceNamedList const &resources = GetResources(); + for (size_t bresIdx = 0; bresIdx < resources.size(); ++bresIdx) + { + HdStBufferResourceSharedPtr const &bres = resources[bresIdx].second; + HdStBufferResourceSharedPtr const &curRes = + curRangeOwner_->GetResources()[bresIdx].second; + + int bytesPerElement = HdDataSizeOfTupleType(bres->GetTupleType()); + TF_VERIFY(bytesPerElement > 0); + size_t bufferSize = bytesPerElement * _totalCapacity; + + // allocate new one + // curBuf and oldBuf will be different when we are adopting ranges + // from another buffer array. + HgiBufferHandle &oldBuf = bres->GetHandle(); + HgiBufferHandle &curBuf = curRes->GetHandle(); + HgiBufferHandle newBuf; + + // Skip buffers of zero size + if (bufferSize > 0) + { + HgiBufferDesc bufDesc; + bufDesc.usage = HgiBufferUsageUniform | HgiBufferUsageVertex; + bufDesc.byteSize = bufferSize; + bufDesc.vertexStride = bytesPerElement; + bufDesc.debugName = resources[bresIdx].first.GetText(); + newBuf = hgi->CreateBuffer(bufDesc); } - // update range list (should be done before early exit) - _SetRangeList(ranges); - - _totalCapacity = totalNumElements; - - Hgi* hgi = _resourceRegistry->GetHgi(); - HgiBlitCmds* blitCmds = _resourceRegistry->GetGlobalBlitCmds(); - blitCmds->PushDebugGroup(__ARCH_PRETTY_FUNCTION__); - - // resize each BufferResource - HdStBufferResourceNamedList const& resources = GetResources(); - for (size_t bresIdx=0; bresIdxGetResources()[bresIdx].second; - - int bytesPerElement = HdDataSizeOfTupleType(bres->GetTupleType()); - TF_VERIFY(bytesPerElement > 0); - size_t bufferSize = bytesPerElement * _totalCapacity; - - // allocate new one - // curBuf and oldBuf will be different when we are adopting ranges - // from another buffer array. - HgiBufferHandle& oldBuf = bres->GetHandle(); - HgiBufferHandle& curBuf = curRes->GetHandle(); - HgiBufferHandle newBuf; - - // Skip buffers of zero size - if (bufferSize > 0) { - HgiBufferDesc bufDesc; - bufDesc.usage = HgiBufferUsageUniform | HgiBufferUsageVertex; - bufDesc.byteSize = bufferSize; - bufDesc.vertexStride = bytesPerElement; - bufDesc.debugName = resources[bresIdx].first.GetText(); - newBuf = hgi->CreateBuffer(bufDesc); - } + // if old and new buffer exist, copy unchanged data + if (curBuf && newBuf) + { + std::vector::iterator newOffsetIt = newOffsets.begin(); - // if old and new buffer exist, copy unchanged data - if (curBuf && newBuf) { - std::vector::iterator newOffsetIt = newOffsets.begin(); - - // pre-pass to combine consecutive buffer range relocation - HdStBufferRelocator relocator(curBuf, newBuf); - TF_FOR_ALL (it, ranges) { - _StripedBufferArrayRangeSharedPtr range = - std::static_pointer_cast<_StripedBufferArrayRange>(*it); - if (!range) { - TF_CODING_ERROR("_StripedBufferArrayRange " - "expired unexpectedly."); - continue; - } - - // copy the range. There are three cases: - // - // 1. src length (capacity) == dst length (numElements) - // Copy the entire range - // - // 2. src length < dst length - // Enlarging the range. This typically happens when - // applying quadrangulation/subdivision to populate - // additional data at the end of source data. - // - // 3. src length > dst length - // Shrinking the range. When the garbage collection - // truncates ranges. - // - int oldSize = range->GetCapacity(); - int newSize = range->GetNumElements(); - ptrdiff_t copySize = - std::min(oldSize, newSize) * bytesPerElement; - int oldOffset = range->GetElementOffset(); - if (copySize > 0) { - ptrdiff_t readOffset = oldOffset * bytesPerElement; - ptrdiff_t writeOffset = *newOffsetIt * bytesPerElement; - - relocator.AddRange(readOffset, writeOffset, copySize); - } - ++newOffsetIt; - } - - // buffer copy - relocator.Commit(blitCmds); + // pre-pass to combine consecutive buffer range relocation + HdStBufferRelocator relocator(curBuf, newBuf); + TF_FOR_ALL(it, ranges) + { + _StripedBufferArrayRangeSharedPtr range = + std::static_pointer_cast<_StripedBufferArrayRange>(*it); + if (!range) + { + TF_CODING_ERROR("_StripedBufferArrayRange " + "expired unexpectedly."); + continue; } - if (oldBuf) { - // delete old buffer - hgi->DestroyBuffer(&oldBuf); + + // copy the range. There are three cases: + // + // 1. src length (capacity) == dst length (numElements) + // Copy the entire range + // + // 2. src length < dst length + // Enlarging the range. This typically happens when + // applying quadrangulation/subdivision to populate + // additional data at the end of source data. + // + // 3. src length > dst length + // Shrinking the range. When the garbage collection + // truncates ranges. + // + int oldSize = range->GetCapacity(); + int newSize = range->GetNumElements(); + ptrdiff_t copySize = + std::min(oldSize, newSize) * bytesPerElement; + int oldOffset = range->GetElementOffset(); + if (copySize > 0) + { + ptrdiff_t readOffset = oldOffset * bytesPerElement; + ptrdiff_t writeOffset = *newOffsetIt * bytesPerElement; + + relocator.AddRange(readOffset, writeOffset, copySize); } + ++newOffsetIt; + } - // update allocation of buffer resource - bres->SetAllocation(newBuf, bufferSize); + // buffer copy + relocator.Commit(blitCmds); + } + if (oldBuf) + { + // delete old buffer + hgi->DestroyBuffer(&oldBuf); } - // update ranges - for (size_t idx = 0; idx < ranges.size(); ++idx) { - _StripedBufferArrayRangeSharedPtr range = - std::static_pointer_cast<_StripedBufferArrayRange>(ranges[idx]); - if (!range) { - TF_CODING_ERROR("_StripedBufferArrayRange expired unexpectedly."); - continue; - } - range->SetElementOffset(newOffsets[idx]); - range->SetCapacity(range->GetNumElements()); + // update allocation of buffer resource + bres->SetAllocation(newBuf, bufferSize); + } + + // update ranges + for (size_t idx = 0; idx < ranges.size(); ++idx) + { + _StripedBufferArrayRangeSharedPtr range = + std::static_pointer_cast<_StripedBufferArrayRange>(ranges[idx]); + if (!range) + { + TF_CODING_ERROR("_StripedBufferArrayRange expired unexpectedly."); + continue; } + range->SetElementOffset(newOffsets[idx]); + range->SetCapacity(range->GetNumElements()); + } - blitCmds->PopDebugGroup(); + blitCmds->PopDebugGroup(); - _needsReallocation = false; - _needsCompaction = false; + _needsReallocation = false; + _needsCompaction = false; - // increment version to rebuild dispatch buffers. - IncrementVersion(); + // increment version to rebuild dispatch buffers. + IncrementVersion(); } -void -HdStVBOMemoryManager::_StripedBufferArray::_DeallocateResources() +void HdStVBOMemoryManager::_StripedBufferArray::_DeallocateResources() { - Hgi* hgi = _resourceRegistry->GetHgi(); - TF_FOR_ALL (it, GetResources()) { - hgi->DestroyBuffer(&it->second->GetHandle()); - } + Hgi *hgi = _resourceRegistry->GetHgi(); + TF_FOR_ALL(it, GetResources()) + { + hgi->DestroyBuffer(&it->second->GetHandle()); + } } /*virtual*/ size_t HdStVBOMemoryManager::_StripedBufferArray::GetMaxNumElements() const { - static size_t vboMaxSize = TfGetEnvSetting(HD_MAX_VBO_SIZE); - return vboMaxSize / _maxBytesPerElement; + static size_t vboMaxSize = TfGetEnvSetting(HD_MAX_VBO_SIZE); + return vboMaxSize / _maxBytesPerElement; } -void -HdStVBOMemoryManager::_StripedBufferArray::DebugDump(std::ostream &out) const +void HdStVBOMemoryManager::_StripedBufferArray::DebugDump(std::ostream &out) const { - out << " HdStVBOMemoryManager\n"; - out << " total capacity = " << _totalCapacity << "\n"; - out << " Range entries " << GetRangeCount() << ":\n"; + out << " HdStVBOMemoryManager\n"; + out << " total capacity = " << _totalCapacity << "\n"; + out << " Range entries " << GetRangeCount() << ":\n"; - size_t rangeCount = GetRangeCount(); - for (size_t rangeIdx = 0; rangeIdx < rangeCount; ++rangeIdx) { - _StripedBufferArrayRangeSharedPtr range = _GetRangeSharedPtr(rangeIdx); - if (range) { - out << " " << rangeIdx << *range; - } + size_t rangeCount = GetRangeCount(); + for (size_t rangeIdx = 0; rangeIdx < rangeCount; ++rangeIdx) + { + _StripedBufferArrayRangeSharedPtr range = _GetRangeSharedPtr(rangeIdx); + if (range) + { + out << " " << rangeIdx << *range; } + } } HdStBufferResourceSharedPtr HdStVBOMemoryManager::_StripedBufferArray::GetResource() const { - HD_TRACE_FUNCTION(); + HD_TRACE_FUNCTION(); - if (_resourceList.empty()) return HdStBufferResourceSharedPtr(); + if (_resourceList.empty()) + return HdStBufferResourceSharedPtr(); - if (TfDebug::IsEnabled(HD_SAFE_MODE)) { - // make sure this buffer array has only one resource. - HgiBufferHandle const& buffer = - _resourceList.begin()->second->GetHandle(); - TF_FOR_ALL (it, _resourceList) { - if (it->second->GetHandle() != buffer) { - TF_CODING_ERROR("GetResource(void) called on" - "HdBufferArray having multiple GPU resources"); - } - } + if (TfDebug::IsEnabled(HD_SAFE_MODE)) + { + // make sure this buffer array has only one resource. + HgiBufferHandle const &buffer = + _resourceList.begin()->second->GetHandle(); + TF_FOR_ALL(it, _resourceList) + { + if (it->second->GetHandle() != buffer) + { + TF_CODING_ERROR("GetResource(void) called on" + "HdBufferArray having multiple GPU resources"); + } } + } - // returns the first item - return _resourceList.begin()->second; + // returns the first item + return _resourceList.begin()->second; } HdStBufferResourceSharedPtr -HdStVBOMemoryManager::_StripedBufferArray::GetResource(TfToken const& name) +HdStVBOMemoryManager::_StripedBufferArray::GetResource(TfToken const &name) { - HD_TRACE_FUNCTION(); + HD_TRACE_FUNCTION(); - // linear search. - // The number of buffer resources should be small (<10 or so). - for (HdStBufferResourceNamedList::iterator it = _resourceList.begin(); - it != _resourceList.end(); ++it) { - if (it->first == name) return it->second; - } - return HdStBufferResourceSharedPtr(); + // linear search. + // The number of buffer resources should be small (<10 or so). + for (HdStBufferResourceNamedList::iterator it = _resourceList.begin(); + it != _resourceList.end(); ++it) + { + if (it->first == name) + return it->second; + } + return HdStBufferResourceSharedPtr(); } HdBufferSpecVector HdStVBOMemoryManager::_StripedBufferArray::GetBufferSpecs() const { - HdBufferSpecVector result; - result.reserve(_resourceList.size()); - TF_FOR_ALL (it, _resourceList) { - result.emplace_back(it->first, it->second->GetTupleType()); - } - return result; + HdBufferSpecVector result; + result.reserve(_resourceList.size()); + TF_FOR_ALL(it, _resourceList) + { + result.emplace_back(it->first, it->second->GetTupleType()); + } + return result; } // --------------------------------------------------------------------------- @@ -519,79 +547,75 @@ HdStVBOMemoryManager::_StripedBufferArray::GetBufferSpecs() const // --------------------------------------------------------------------------- HdStVBOMemoryManager::_StripedBufferArrayRange::~_StripedBufferArrayRange() { - // Notify that hosting buffer array needs to be garbage collected. - // - // Don't do any substantial work here. - // - if (_stripedBufferArray) { - _stripedBufferArray->SetNeedsCompaction(); + // Notify that hosting buffer array needs to be garbage collected. + // + // Don't do any substantial work here. + // + if (_stripedBufferArray) + { + _stripedBufferArray->SetNeedsCompaction(); - // notify source bufferArray to bump the version so that - // drawbatches to be rebuilt. - // Also note that the buffer migration takes place only in - // this StripedBufferArray, not in other InterleavedVBO/SimpleVBO. - _stripedBufferArray->IncrementVersion(); - } + // notify source bufferArray to bump the version so that + // drawbatches to be rebuilt. + // Also note that the buffer migration takes place only in + // this StripedBufferArray, not in other InterleavedVBO/SimpleVBO. + _stripedBufferArray->IncrementVersion(); + } } - -bool -HdStVBOMemoryManager::_StripedBufferArrayRange::IsAssigned() const +bool HdStVBOMemoryManager::_StripedBufferArrayRange::IsAssigned() const { - return (_stripedBufferArray != nullptr); + return (_stripedBufferArray != nullptr); } -bool -HdStVBOMemoryManager::_StripedBufferArrayRange::IsImmutable() const +bool HdStVBOMemoryManager::_StripedBufferArrayRange::IsImmutable() const { - return (_stripedBufferArray != nullptr) - && _stripedBufferArray->IsImmutable(); + return (_stripedBufferArray != nullptr) && _stripedBufferArray->IsImmutable(); } -bool -HdStVBOMemoryManager::_StripedBufferArrayRange::RequiresStaging() const +bool HdStVBOMemoryManager::_StripedBufferArrayRange::RequiresStaging() const { - return true; + return true; } -bool -HdStVBOMemoryManager::_StripedBufferArrayRange::Resize(int numElements) -{ - HD_TRACE_FUNCTION(); - HF_MALLOC_TAG_FUNCTION(); - - if (!TF_VERIFY(_stripedBufferArray)) return false; - - bool needsReallocation = false; - - // XXX: varying topology points fix (bug 114080) - // - // MDI draw uses a dispatch buffer, and it includes numElements to be - // drawn. When a topology is varying, numElements will change so the - // dispatch buffer has to be rebuilt. Currently we depend on entire - // buffer reallocation for index-drawing prims (e.g. meshes and curves) - // with varying topology. We always allocate new BARs for them, - // which is inefficient, and will be addressed later (bug 103767) - // - // However varying points have another problem: When it reduces its - // number of points, it doesn't cause the reallocation in the below code - // (disabled by #if 0) since points don't have an index buffer. - // - // These two problems have to be solved together by introducing more - // robust mechanism which updates dispatch buffer partially to - // reflect numElements correctly without having reallocation. - // It needs more works, until then, we invoke reallocation whenever - // numElements changes in an aggregated buffer, for the correctness - // problem of points drawing (this is bug 114080). - // - // The varying mesh batch may suffer a performance regression - // from this treatment, but it should be relatively small. Because the - // topology buffer has already been reallocated on every changes as - // described above and the primvar buffer is also reallocated in - // GarbageCollect() before drawing (see HdEngine::Draw()). - // - // We need to revisit to clean this up soon. - // +bool HdStVBOMemoryManager::_StripedBufferArrayRange::Resize(int numElements) +{ + HD_TRACE_FUNCTION(); + HF_MALLOC_TAG_FUNCTION(); + + if (!TF_VERIFY(_stripedBufferArray)) + return false; + + bool needsReallocation = false; + + // XXX: varying topology points fix (bug 114080) + // + // MDI draw uses a dispatch buffer, and it includes numElements to be + // drawn. When a topology is varying, numElements will change so the + // dispatch buffer has to be rebuilt. Currently we depend on entire + // buffer reallocation for index-drawing prims (e.g. meshes and curves) + // with varying topology. We always allocate new BARs for them, + // which is inefficient, and will be addressed later (bug 103767) + // + // However varying points have another problem: When it reduces its + // number of points, it doesn't cause the reallocation in the below code + // (disabled by #if 0) since points don't have an index buffer. + // + // These two problems have to be solved together by introducing more + // robust mechanism which updates dispatch buffer partially to + // reflect numElements correctly without having reallocation. + // It needs more works, until then, we invoke reallocation whenever + // numElements changes in an aggregated buffer, for the correctness + // problem of points drawing (this is bug 114080). + // + // The varying mesh batch may suffer a performance regression + // from this treatment, but it should be relatively small. Because the + // topology buffer has already been reallocated on every changes as + // described above and the primvar buffer is also reallocated in + // GarbageCollect() before drawing (see HdEngine::Draw()). + // + // We need to revisit to clean this up soon. + // #if 0 if (_capacity < numElements) { // mark entire buffer array to be relocated @@ -602,203 +626,211 @@ HdStVBOMemoryManager::_StripedBufferArrayRange::Resize(int numElements) _stripedBufferArray->SetNeedsCompaction(); } #else - if (_capacity != numElements) { - const size_t numMaxElements = GetMaxNumElements(); + if (_capacity != numElements) + { + const size_t numMaxElements = GetMaxNumElements(); - if (static_cast(numElements) > numMaxElements) { - TF_WARN("Attempting to resize the BAR with 0x%x elements when the " - "max number of elements in the buffer array is 0x%lx. " - "Clamping BAR size to the latter.", - numElements, numMaxElements); + if (static_cast(numElements) > numMaxElements) + { + TF_WARN("Attempting to resize the BAR with 0x%x elements when the " + "max number of elements in the buffer array is 0x%lx. " + "Clamping BAR size to the latter.", + numElements, numMaxElements); - numElements = numMaxElements; - } - _stripedBufferArray->SetNeedsReallocation(); - needsReallocation = true; + numElements = numMaxElements; } + _stripedBufferArray->SetNeedsReallocation(); + needsReallocation = true; + } #endif - _numElements = numElements; - return needsReallocation; + _numElements = numElements; + return needsReallocation; } -void -HdStVBOMemoryManager::_StripedBufferArrayRange::CopyData( +void HdStVBOMemoryManager::_StripedBufferArrayRange::CopyData( HdBufferSourceSharedPtr const &bufferSource) { - HD_TRACE_FUNCTION(); - HF_MALLOC_TAG_FUNCTION(); - - if (!TF_VERIFY(_stripedBufferArray)) return; - - HdStBufferResourceSharedPtr VBO = - _stripedBufferArray->GetResource(bufferSource->GetName()); - - if (!TF_VERIFY((VBO && VBO->GetHandle()), - "VBO doesn't exist for %s", - bufferSource->GetName().GetText())) { - return; - } - - // datatype of bufferSource has to match with bufferResource - if (!TF_VERIFY(bufferSource->GetTupleType() == VBO->GetTupleType(), - "'%s': (%s (%i) x %zu) != (%s (%i) x %zu)\n", - bufferSource->GetName().GetText(), - TfEnum::GetName(bufferSource->GetTupleType().type).c_str(), - bufferSource->GetTupleType().type, - bufferSource->GetTupleType().count, - TfEnum::GetName(VBO->GetTupleType().type).c_str(), - VBO->GetTupleType().type, - VBO->GetTupleType().count)) { - return; - } - - int bytesPerElement = HdDataSizeOfTupleType(VBO->GetTupleType()); - - // overrun check. for graceful handling of erroneous assets, - // issue warning here and continue to copy for the valid range. - size_t dstSize = _numElements * bytesPerElement; - size_t srcSize = - bufferSource->GetNumElements() * - HdDataSizeOfTupleType(bufferSource->GetTupleType()); - if (srcSize > dstSize) { - TF_WARN("%s: size %ld is larger than the range (%ld)", - bufferSource->GetName().GetText(), srcSize, dstSize); - srcSize = dstSize; - } - size_t vboOffset = bytesPerElement * _elementOffset; - - HD_PERF_COUNTER_INCR(HdStPerfTokens->copyBufferCpuToGpu); - - HgiBufferCpuToGpuOp blitOp; - blitOp.cpuSourceBuffer = bufferSource->GetData(); - blitOp.gpuDestinationBuffer = VBO->GetHandle(); - - blitOp.sourceByteOffset = 0; - blitOp.byteSize = srcSize; - blitOp.destinationByteOffset = vboOffset; - - HdStStagingBuffer *stagingBuffer = - GetResourceRegistry()->GetStagingBuffer(); - stagingBuffer->StageCopy(blitOp); -} - -int -HdStVBOMemoryManager::_StripedBufferArrayRange::GetByteOffset( - TfToken const& resourceName) const -{ - if (!TF_VERIFY(_stripedBufferArray)) return 0; - HdStBufferResourceSharedPtr VBO = - _stripedBufferArray->GetResource(resourceName); - - if (!VBO || (!VBO->GetHandle() && _numElements > 0)) { - TF_CODING_ERROR("VBO doesn't exist for %s", resourceName.GetText()); - return 0; - } - - return (int) _GetByteOffset(VBO); + HD_TRACE_FUNCTION(); + HF_MALLOC_TAG_FUNCTION(); + + if (!TF_VERIFY(_stripedBufferArray)) + return; + + HdStBufferResourceSharedPtr VBO = + _stripedBufferArray->GetResource(bufferSource->GetName()); + + if (!TF_VERIFY((VBO && VBO->GetHandle()), + "VBO doesn't exist for %s", + bufferSource->GetName().GetText())) + { + return; + } + + // datatype of bufferSource has to match with bufferResource + if (!TF_VERIFY(bufferSource->GetTupleType() == VBO->GetTupleType(), + "'%s': (%s (%i) x %zu) != (%s (%i) x %zu)\n", + bufferSource->GetName().GetText(), + TfEnum::GetName(bufferSource->GetTupleType().type).c_str(), + bufferSource->GetTupleType().type, + bufferSource->GetTupleType().count, + TfEnum::GetName(VBO->GetTupleType().type).c_str(), + VBO->GetTupleType().type, + VBO->GetTupleType().count)) + { + return; + } + + int bytesPerElement = HdDataSizeOfTupleType(VBO->GetTupleType()); + + // overrun check. for graceful handling of erroneous assets, + // issue warning here and continue to copy for the valid range. + size_t dstSize = _numElements * bytesPerElement; + size_t srcSize = + bufferSource->GetNumElements() * + HdDataSizeOfTupleType(bufferSource->GetTupleType()); + if (srcSize > dstSize) + { + TF_WARN("%s: size %ld is larger than the range (%ld)", + bufferSource->GetName().GetText(), srcSize, dstSize); + srcSize = dstSize; + } + size_t vboOffset = bytesPerElement * _elementOffset; + + HD_PERF_COUNTER_INCR(HdStPerfTokens->copyBufferCpuToGpu); + + HgiBufferCpuToGpuOp blitOp; + blitOp.cpuSourceBuffer = bufferSource->GetData(); + blitOp.gpuDestinationBuffer = VBO->GetHandle(); + + blitOp.sourceByteOffset = 0; + blitOp.byteSize = srcSize; + blitOp.destinationByteOffset = vboOffset; + + HdStStagingBuffer *stagingBuffer = + GetResourceRegistry()->GetStagingBuffer(); + stagingBuffer->StageCopy(blitOp); +} + +int HdStVBOMemoryManager::_StripedBufferArrayRange::GetByteOffset( + TfToken const &resourceName) const +{ + if (!TF_VERIFY(_stripedBufferArray)) + return 0; + HdStBufferResourceSharedPtr VBO = + _stripedBufferArray->GetResource(resourceName); + + if (!VBO || (!VBO->GetHandle() && _numElements > 0)) + { + TF_CODING_ERROR("VBO doesn't exist for %s", resourceName.GetText()); + return 0; + } + + return (int)_GetByteOffset(VBO); } VtValue HdStVBOMemoryManager::_StripedBufferArrayRange::ReadData( TfToken const &name) const { - HD_TRACE_FUNCTION(); - HF_MALLOC_TAG_FUNCTION(); + HD_TRACE_FUNCTION(); + HF_MALLOC_TAG_FUNCTION(); - VtValue result; - if (!TF_VERIFY(_stripedBufferArray)) return result; + VtValue result; + if (!TF_VERIFY(_stripedBufferArray)) + return result; - HdStBufferResourceSharedPtr VBO = _stripedBufferArray->GetResource(name); + HdStBufferResourceSharedPtr VBO = _stripedBufferArray->GetResource(name); - if (!VBO || (!VBO->GetHandle() && _numElements > 0)) { - TF_CODING_ERROR("VBO doesn't exist for %s", name.GetText()); - return result; - } + if (!VBO || (!VBO->GetHandle() && _numElements > 0)) + { + TF_CODING_ERROR("VBO doesn't exist for %s", name.GetText()); + return result; + } - size_t vboOffset = _GetByteOffset(VBO); + size_t vboOffset = _GetByteOffset(VBO); - result = HdStReadBuffer(VBO->GetHandle(), - VBO->GetTupleType(), - vboOffset, - /*stride=*/0, // not interleaved. - _numElements, - /*elementStride=*/0, - GetResourceRegistry()); + result = HdStReadBuffer(VBO->GetHandle(), + VBO->GetTupleType(), + vboOffset, + /*stride=*/0, // not interleaved. + _numElements, + /*elementStride=*/0, + GetResourceRegistry()); - return result; + return result; } size_t HdStVBOMemoryManager::_StripedBufferArrayRange::GetMaxNumElements() const { - return _stripedBufferArray->GetMaxNumElements(); + return _stripedBufferArray->GetMaxNumElements(); } HdBufferArrayUsageHint HdStVBOMemoryManager::_StripedBufferArrayRange::GetUsageHint() const { - if (!TF_VERIFY(_stripedBufferArray)) { - return HdBufferArrayUsageHint(); - } + if (!TF_VERIFY(_stripedBufferArray)) + { + return HdBufferArrayUsageHint(); + } - return _stripedBufferArray->GetUsageHint(); + return _stripedBufferArray->GetUsageHint(); } - HdStBufferResourceSharedPtr HdStVBOMemoryManager::_StripedBufferArrayRange::GetResource() const { - if (!TF_VERIFY(_stripedBufferArray)) return HdStBufferResourceSharedPtr(); + if (!TF_VERIFY(_stripedBufferArray)) + return HdStBufferResourceSharedPtr(); - return _stripedBufferArray->GetResource(); + return _stripedBufferArray->GetResource(); } HdStBufferResourceSharedPtr -HdStVBOMemoryManager::_StripedBufferArrayRange::GetResource(TfToken const& name) +HdStVBOMemoryManager::_StripedBufferArrayRange::GetResource(TfToken const &name) { - if (!TF_VERIFY(_stripedBufferArray)) return HdStBufferResourceSharedPtr(); + if (!TF_VERIFY(_stripedBufferArray)) + return HdStBufferResourceSharedPtr(); - return _stripedBufferArray->GetResource(name); + return _stripedBufferArray->GetResource(name); } -HdStBufferResourceNamedList const& +HdStBufferResourceNamedList const & HdStVBOMemoryManager::_StripedBufferArrayRange::GetResources() const { - if (!TF_VERIFY(_stripedBufferArray)) { - static HdStBufferResourceNamedList empty; - return empty; - } - return _stripedBufferArray->GetResources(); + if (!TF_VERIFY(_stripedBufferArray)) + { + static HdStBufferResourceNamedList empty; + return empty; + } + return _stripedBufferArray->GetResources(); } -void -HdStVBOMemoryManager::_StripedBufferArrayRange::SetBufferArray(HdBufferArray *bufferArray) +void HdStVBOMemoryManager::_StripedBufferArrayRange::SetBufferArray(HdBufferArray *bufferArray) { - _stripedBufferArray = static_cast<_StripedBufferArray *>(bufferArray); + _stripedBufferArray = static_cast<_StripedBufferArray *>(bufferArray); } -void -HdStVBOMemoryManager::_StripedBufferArrayRange::DebugDump(std::ostream &out) const +void HdStVBOMemoryManager::_StripedBufferArrayRange::DebugDump(std::ostream &out) const { - out << "[StripedBAR] offset = " << _elementOffset - << ", numElements = " << _numElements - << ", capacity = " << _capacity - << "\n"; + out << "[StripedBAR] offset = " << _elementOffset + << ", numElements = " << _numElements + << ", capacity = " << _capacity + << "\n"; } const void * HdStVBOMemoryManager::_StripedBufferArrayRange::_GetAggregation() const { - return _stripedBufferArray; + return _stripedBufferArray; } size_t HdStVBOMemoryManager::_StripedBufferArrayRange::_GetByteOffset( - HdStBufferResourceSharedPtr const& resource) const + HdStBufferResourceSharedPtr const &resource) const { - return HdDataSizeOfTupleType(resource->GetTupleType()) * _elementOffset; + return HdDataSizeOfTupleType(resource->GetTupleType()) * _elementOffset; } PXR_NAMESPACE_CLOSE_SCOPE - diff --git a/Sources/OpenUSD/imaging/hdsi/implicitSurfaceSceneIndex.cpp b/Sources/OpenUSD/imaging/hdsi/implicitSurfaceSceneIndex.cpp index 01d6367ee4..1b14b0ca86 100644 --- a/Sources/OpenUSD/imaging/hdsi/implicitSurfaceSceneIndex.cpp +++ b/Sources/OpenUSD/imaging/hdsi/implicitSurfaceSceneIndex.cpp @@ -23,13 +23,13 @@ #include "pxr/imaging/hdsi/implicitSurfaceSceneIndex.h" -#include "pxr/imaging/geomUtil/capsuleMeshGenerator.h" -#include "pxr/imaging/geomUtil/coneMeshGenerator.h" -#include "pxr/imaging/geomUtil/cuboidMeshGenerator.h" -#include "pxr/imaging/geomUtil/cylinderMeshGenerator.h" -#include "pxr/imaging/geomUtil/sphereMeshGenerator.h" +#include "GeomUtil/capsuleMeshGenerator.h" +#include "GeomUtil/coneMeshGenerator.h" +#include "GeomUtil/cuboidMeshGenerator.h" +#include "GeomUtil/cylinderMeshGenerator.h" +#include "GeomUtil/sphereMeshGenerator.h" -#include "pxr/imaging/pxOsd/meshTopology.h" +#include "PxOsd/meshTopology.h" #include "pxr/imaging/hd/capsuleSchema.h" #include "pxr/imaging/hd/coneSchema.h" @@ -47,7 +47,7 @@ #include "pxr/imaging/hd/sphereSchema.h" #include "pxr/imaging/hd/tokens.h" #include "pxr/imaging/hd/xformSchema.h" -#include "pxr/imaging/pxOsd/tokens.h" +#include "PxOsd/tokens.h" #include "pxr/base/tf/iterator.h" #include "pxr/base/trace/trace.h" @@ -55,37 +55,38 @@ PXR_NAMESPACE_OPEN_SCOPE TF_DEFINE_PUBLIC_TOKENS(HdsiImplicitSurfaceSceneIndexTokens, - HDSI_IMPLICIT_SURFACE_SCENE_INDEX_TOKENS); + HDSI_IMPLICIT_SURFACE_SCENE_INDEX_TOKENS); TF_DEFINE_PRIVATE_TOKENS( _tokens, - ((xAxis, "X")) - ((yAxis, "Y")) - ((zAxis, "Z")) + ((xAxis, "X"))((yAxis, "Y"))((zAxis, "Z")) - (implicitToMesh) - (implicitToXform) -); + (implicitToMesh)(implicitToXform)); namespace { -GfMatrix4d -_GetBasis(TfToken const &axis) -{ + GfMatrix4d + _GetBasis(TfToken const &axis) + { GfVec4d u, v, spine; - if (axis == _tokens->xAxis) { - u = GfVec4d::YAxis(); - v = GfVec4d::ZAxis(); - spine = GfVec4d::XAxis(); - } else if (axis == _tokens->yAxis) { - u = GfVec4d::ZAxis(); - v = GfVec4d::XAxis(); - spine = GfVec4d::YAxis(); - } else { // (axis == _tokens->zAxis) - u = GfVec4d::XAxis(); - v = GfVec4d::YAxis(); - spine = GfVec4d::ZAxis(); + if (axis == _tokens->xAxis) + { + u = GfVec4d::YAxis(); + v = GfVec4d::ZAxis(); + spine = GfVec4d::XAxis(); + } + else if (axis == _tokens->yAxis) + { + u = GfVec4d::ZAxis(); + v = GfVec4d::XAxis(); + spine = GfVec4d::YAxis(); + } + else + { // (axis == _tokens->zAxis) + u = GfVec4d::XAxis(); + v = GfVec4d::YAxis(); + spine = GfVec4d::ZAxis(); } GfMatrix4d basis; @@ -95,14 +96,14 @@ _GetBasis(TfToken const &axis) basis.SetRow(3, GfVec4d::WAxis()); return basis; -} + } -using Time = HdSampledDataSource::Time; + using Time = HdSampledDataSource::Time; -template -HdContainerDataSourceHandle -_ComputePointsDependenciesDataSource(const SdfPath &primPath) -{ + template + HdContainerDataSourceHandle + _ComputePointsDependenciesDataSource(const SdfPath &primPath) + { HdPathDataSourceHandle const dependedOnPrimPathDataSource = HdRetainedTypedSampledDataSource::New( primPath); @@ -114,20 +115,19 @@ _ComputePointsDependenciesDataSource(const SdfPath &primPath) HdPrimvarsSchema::GetPointsLocator().Append( HdPrimvarSchemaTokens->primvarValue)); - return - HdRetainedContainerDataSource::New( - _tokens->implicitToMesh, - HdDependencySchema::Builder() - .SetDependedOnPrimPath(dependedOnPrimPathDataSource) - .SetDependedOnDataSourceLocator(dependedOnLocatorDataSource) - .SetAffectedDataSourceLocator(affectedLocatorDataSource) - .Build()); -} - -template -HdContainerDataSourceHandle -_ComputeMatrixDependenciesDataSource(const SdfPath &primPath) -{ + return HdRetainedContainerDataSource::New( + _tokens->implicitToMesh, + HdDependencySchema::Builder() + .SetDependedOnPrimPath(dependedOnPrimPathDataSource) + .SetDependedOnDataSourceLocator(dependedOnLocatorDataSource) + .SetAffectedDataSourceLocator(affectedLocatorDataSource) + .Build()); + } + + template + HdContainerDataSourceHandle + _ComputeMatrixDependenciesDataSource(const SdfPath &primPath) + { HdPathDataSourceHandle const dependedOnPrimPathDataSource = HdRetainedTypedSampledDataSource::New( primPath); @@ -139,62 +139,62 @@ _ComputeMatrixDependenciesDataSource(const SdfPath &primPath) HdXformSchema::GetDefaultLocator() .Append(HdXformSchemaTokens->matrix)); - return - HdRetainedContainerDataSource::New( - _tokens->implicitToXform, - HdDependencySchema::Builder() - .SetDependedOnPrimPath(dependedOnPrimPathDataSource) - .SetDependedOnDataSourceLocator(dependedOnLocatorDataSource) - .SetAffectedDataSourceLocator(affectedLocatorDataSource) - .Build()); -} - -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// + return HdRetainedContainerDataSource::New( + _tokens->implicitToXform, + HdDependencySchema::Builder() + .SetDependedOnPrimPath(dependedOnPrimPathDataSource) + .SetDependedOnDataSourceLocator(dependedOnLocatorDataSource) + .SetAffectedDataSourceLocator(affectedLocatorDataSource) + .Build()); + } -// Cube + /////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////// -namespace _CubeToMesh -{ + // Cube -HdContainerDataSourceHandle -_ComputeMeshDataSource() -{ - static const PxOsdMeshTopology topology = - GeomUtilCuboidMeshGenerator::GenerateTopology(); - - return - HdMeshSchema::Builder() - .SetTopology( - HdMeshTopologySchema::Builder() - .SetFaceVertexCounts( - HdRetainedTypedSampledDataSource::New( - topology.GetFaceVertexCounts())) - .SetFaceVertexIndices( - HdRetainedTypedSampledDataSource::New( - topology.GetFaceVertexIndices())) - .SetOrientation( - HdRetainedTypedSampledDataSource::New( - HdMeshTopologySchemaTokens->rightHanded)) - .Build()) - .SetSubdivisionScheme( - HdRetainedTypedSampledDataSource::New( - topology.GetScheme())) - .SetDoubleSided( - HdRetainedTypedSampledDataSource::New(false)) - .Build(); -} + namespace _CubeToMesh + { -class _PointsDataSource : public HdVec3fArrayDataSource -{ -public: - HD_DECLARE_DATASOURCE(_PointsDataSource); + HdContainerDataSourceHandle + _ComputeMeshDataSource() + { + static const PxOsdMeshTopology topology = + GeomUtilCuboidMeshGenerator::GenerateTopology(); + + return HdMeshSchema::Builder() + .SetTopology( + HdMeshTopologySchema::Builder() + .SetFaceVertexCounts( + HdRetainedTypedSampledDataSource::New( + topology.GetFaceVertexCounts())) + .SetFaceVertexIndices( + HdRetainedTypedSampledDataSource::New( + topology.GetFaceVertexIndices())) + .SetOrientation( + HdRetainedTypedSampledDataSource::New( + HdMeshTopologySchemaTokens->rightHanded)) + .Build()) + .SetSubdivisionScheme( + HdRetainedTypedSampledDataSource::New( + topology.GetScheme())) + .SetDoubleSided( + HdRetainedTypedSampledDataSource::New(false)) + .Build(); + } + + class _PointsDataSource : public HdVec3fArrayDataSource + { + public: + HD_DECLARE_DATASOURCE(_PointsDataSource); - VtValue GetValue(const Time shutterOffset) override { + VtValue GetValue(const Time shutterOffset) override + { return VtValue(GetTypedValue(shutterOffset)); - } + } - VtVec3fArray GetTypedValue(const Time shutterOffset) override { + VtVec3fArray GetTypedValue(const Time shutterOffset) override + { const size_t numPoints = GeomUtilCuboidMeshGenerator::ComputeNumPoints(); VtVec3fArray points(numPoints); @@ -203,151 +203,153 @@ class _PointsDataSource : public HdVec3fArrayDataSource GeomUtilCuboidMeshGenerator::GeneratePoints( points.begin(), - size, size, size - ); - - return points; - } + size, size, size); - bool GetContributingSampleTimesForInterval( - const Time startTime, - const Time endTime, - std::vector