diff --git a/opensubdiv/osd/glslPatchCommon.glsl b/opensubdiv/osd/glslPatchCommon.glsl index 1bb113e71..11bfaf62a 100644 --- a/opensubdiv/osd/glslPatchCommon.glsl +++ b/opensubdiv/osd/glslPatchCommon.glsl @@ -22,101 +22,11 @@ // language governing permissions and limitations under the Apache License. // -// -// typical shader composition ordering (see glDrawRegistry:_CompileShader) -// -// -// - glsl version string (#version 430) -// -// - common defines (#define OSD_ENABLE_PATCH_CULL, ...) -// - source defines (#define VERTEX_SHADER, ...) -// -// - osd headers (glslPatchCommon: varying structs, -// glslPtexCommon: ptex functions) -// - client header (Osd*Matrix(), displacement callback, ...) -// -// - osd shader source (glslPatchBSpline, glslPatchGregory, ...) -// or -// client shader source (vertex/geometry/fragment shader) -// - -//---------------------------------------------------------- -// Patches.Common -//---------------------------------------------------------- - -// XXXdyu all handling of varying data can be managed by client code -#ifndef OSD_USER_VARYING_DECLARE -#define OSD_USER_VARYING_DECLARE -// type var; -#endif - -#ifndef OSD_USER_VARYING_ATTRIBUTE_DECLARE -#define OSD_USER_VARYING_ATTRIBUTE_DECLARE -// layout(location = loc) in type var; -#endif - -#ifndef OSD_USER_VARYING_PER_VERTEX -#define OSD_USER_VARYING_PER_VERTEX() -// output.var = var; -#endif - -#ifndef OSD_USER_VARYING_PER_CONTROL_POINT -#define OSD_USER_VARYING_PER_CONTROL_POINT(ID_OUT, ID_IN) -// output[ID_OUT].var = input[ID_IN].var -#endif - -#ifndef OSD_USER_VARYING_PER_EVAL_POINT -#define OSD_USER_VARYING_PER_EVAL_POINT(UV, a, b, c, d) -// output.var = -// mix(mix(input[a].var, input[b].var, UV.x), -// mix(input[c].var, input[d].var, UV.x), UV.y) -#endif - -#ifndef OSD_USER_VARYING_PER_EVAL_POINT_TRIANGLE -#define OSD_USER_VARYING_PER_EVAL_POINT_TRIANGLE(UV, a, b, c) -// output.var = -// input[a].var * (1.0f-UV.x-UV.y) + -// input[b].var * UV.x + -// input[c].var * UV.y; -#endif - -#if __VERSION__ < 420 - #define centroid -#endif - -struct ControlVertex { - vec4 position; -#ifdef OSD_ENABLE_PATCH_CULL - ivec3 clipFlag; -#endif -}; - -// XXXdyu all downstream data can be handled by client code -struct OutputVertex { - vec4 position; - vec3 normal; - vec3 tangent; - vec3 bitangent; - vec4 patchCoord; // u, v, faceLevel, faceId - vec2 tessCoord; // tesscoord.st -#if defined OSD_COMPUTE_NORMAL_DERIVATIVES - vec3 Nu; - vec3 Nv; -#endif -}; - -// osd shaders need following functions defined +// The following callback functions are used when evaluating tessellation +// rates and when using legacy patch drawing. mat4 OsdModelViewMatrix(); mat4 OsdProjectionMatrix(); -mat4 OsdModelViewProjectionMatrix(); float OsdTessLevel(); -int OsdGregoryQuadOffsetBase(); -int OsdPrimitiveIdBase(); -int OsdBaseVertex(); - -#ifndef OSD_DISPLACEMENT_CALLBACK -#define OSD_DISPLACEMENT_CALLBACK -#endif // ---------------------------------------------------------------------------- // Patch Parameters @@ -130,22 +40,6 @@ int OsdBaseVertex(); // bitfield -- refinement-level, non-quad, boundary, transition, uv-offset // sharpness -- crease sharpness for single-crease patches // -// These are stored in OsdPatchParamBuffer indexed by the value returned -// from OsdGetPatchIndex() which is a function of the current PrimitiveID -// along with an optional client provided offset. -// - -uniform isamplerBuffer OsdPatchParamBuffer; - -int OsdGetPatchIndex(int primitiveId) -{ - return (primitiveId + OsdPrimitiveIdBase()); -} - -ivec3 OsdGetPatchParam(int patchIndex) -{ - return texelFetch(OsdPatchParamBuffer, patchIndex).xyz; -} int OsdGetPatchFaceId(ivec3 patchParam) { @@ -239,38 +133,6 @@ vec4 OsdInterpolatePatchCoordTriangle(vec2 localUV, ivec3 patchParam) return result; } -// ---------------------------------------------------------------------------- -// patch culling -// ---------------------------------------------------------------------------- - -#ifdef OSD_ENABLE_PATCH_CULL - -#define OSD_PATCH_CULL_COMPUTE_CLIPFLAGS(P) \ - vec4 clipPos = OsdModelViewProjectionMatrix() * P; \ - bvec3 clip0 = lessThan(clipPos.xyz, vec3(clipPos.w)); \ - bvec3 clip1 = greaterThan(clipPos.xyz, -vec3(clipPos.w)); \ - outpt.v.clipFlag = ivec3(clip0) + 2*ivec3(clip1); \ - -#define OSD_PATCH_CULL(N) \ - ivec3 clipFlag = ivec3(0); \ - for(int i = 0; i < N; ++i) { \ - clipFlag |= inpt[i].v.clipFlag; \ - } \ - if (clipFlag != ivec3(3) ) { \ - gl_TessLevelInner[0] = 0; \ - gl_TessLevelInner[1] = 0; \ - gl_TessLevelOuter[0] = 0; \ - gl_TessLevelOuter[1] = 0; \ - gl_TessLevelOuter[2] = 0; \ - gl_TessLevelOuter[3] = 0; \ - return; \ - } - -#else -#define OSD_PATCH_CULL_COMPUTE_CLIPFLAGS(P) -#define OSD_PATCH_CULL(N) -#endif - // ---------------------------------------------------------------------------- void @@ -582,7 +444,7 @@ OsdFlipMatrix(mat4 m) } // Regular BSpline to Bezier -uniform mat4 Q = mat4( +const mat4 Q = mat4( 1.f/6.f, 4.f/6.f, 1.f/6.f, 0.f, 0.f, 4.f/6.f, 2.f/6.f, 0.f, 0.f, 2.f/6.f, 4.f/6.f, 0.f, @@ -590,7 +452,7 @@ uniform mat4 Q = mat4( ); // Infinitely Sharp (boundary) -uniform mat4 Mi = mat4( +const mat4 Mi = mat4( 1.f/6.f, 4.f/6.f, 1.f/6.f, 0.f, 0.f, 4.f/6.f, 2.f/6.f, 0.f, 0.f, 2.f/6.f, 4.f/6.f, 0.f, diff --git a/opensubdiv/osd/glslPatchLegacy.glsl b/opensubdiv/osd/glslPatchLegacy.glsl index e1e7002d1..ff988178e 100644 --- a/opensubdiv/osd/glslPatchLegacy.glsl +++ b/opensubdiv/osd/glslPatchLegacy.glsl @@ -22,6 +22,128 @@ // language governing permissions and limitations under the Apache License. // +//---------------------------------------------------------- +// Patches.Common +//---------------------------------------------------------- + +// XXXdyu all handling of varying data can be managed by client code +#ifndef OSD_USER_VARYING_DECLARE +#define OSD_USER_VARYING_DECLARE +// type var; +#endif + +#ifndef OSD_USER_VARYING_ATTRIBUTE_DECLARE +#define OSD_USER_VARYING_ATTRIBUTE_DECLARE +// layout(location = loc) in type var; +#endif + +#ifndef OSD_USER_VARYING_PER_VERTEX +#define OSD_USER_VARYING_PER_VERTEX() +// output.var = var; +#endif + +#ifndef OSD_USER_VARYING_PER_CONTROL_POINT +#define OSD_USER_VARYING_PER_CONTROL_POINT(ID_OUT, ID_IN) +// output[ID_OUT].var = input[ID_IN].var +#endif + +#ifndef OSD_USER_VARYING_PER_EVAL_POINT +#define OSD_USER_VARYING_PER_EVAL_POINT(UV, a, b, c, d) +// output.var = +// mix(mix(input[a].var, input[b].var, UV.x), +// mix(input[c].var, input[d].var, UV.x), UV.y) +#endif + +#ifndef OSD_USER_VARYING_PER_EVAL_POINT_TRIANGLE +#define OSD_USER_VARYING_PER_EVAL_POINT_TRIANGLE(UV, a, b, c) +// output.var = +// input[a].var * (1.0f-UV.x-UV.y) + +// input[b].var * UV.x + +// input[c].var * UV.y; +#endif + +#if __VERSION__ < 420 + #define centroid +#endif + +struct ControlVertex { + vec4 position; +#ifdef OSD_ENABLE_PATCH_CULL + ivec3 clipFlag; +#endif +}; + +// XXXdyu all downstream data can be handled by client code +struct OutputVertex { + vec4 position; + vec3 normal; + vec3 tangent; + vec3 bitangent; + vec4 patchCoord; // u, v, faceLevel, faceId + vec2 tessCoord; // tesscoord.st +#if defined OSD_COMPUTE_NORMAL_DERIVATIVES + vec3 Nu; + vec3 Nv; +#endif +}; + +mat4 OsdModelViewProjectionMatrix(); +int OsdGregoryQuadOffsetBase(); +int OsdPrimitiveIdBase(); +int OsdBaseVertex(); + +#ifndef OSD_DISPLACEMENT_CALLBACK +#define OSD_DISPLACEMENT_CALLBACK +#endif + +// These are stored in OsdPatchParamBuffer indexed by the value returned +// from OsdGetPatchIndex() which is a function of the current PrimitiveID +// along with an optional client provided offset. + +uniform isamplerBuffer OsdPatchParamBuffer; + +int OsdGetPatchIndex(int primitiveId) +{ + return (primitiveId + OsdPrimitiveIdBase()); +} + +ivec3 OsdGetPatchParam(int patchIndex) +{ + return texelFetch(OsdPatchParamBuffer, patchIndex).xyz; +} + +// ---------------------------------------------------------------------------- +// patch culling +// ---------------------------------------------------------------------------- + +#ifdef OSD_ENABLE_PATCH_CULL + +#define OSD_PATCH_CULL_COMPUTE_CLIPFLAGS(P) \ + vec4 clipPos = OsdModelViewProjectionMatrix() * P; \ + bvec3 clip0 = lessThan(clipPos.xyz, vec3(clipPos.w)); \ + bvec3 clip1 = greaterThan(clipPos.xyz, -vec3(clipPos.w)); \ + outpt.v.clipFlag = ivec3(clip0) + 2*ivec3(clip1); \ + +#define OSD_PATCH_CULL(N) \ + ivec3 clipFlag = ivec3(0); \ + for(int i = 0; i < N; ++i) { \ + clipFlag |= inpt[i].v.clipFlag; \ + } \ + if (clipFlag != ivec3(3) ) { \ + gl_TessLevelInner[0] = 0; \ + gl_TessLevelInner[1] = 0; \ + gl_TessLevelOuter[0] = 0; \ + gl_TessLevelOuter[1] = 0; \ + gl_TessLevelOuter[2] = 0; \ + gl_TessLevelOuter[3] = 0; \ + return; \ + } + +#else +#define OSD_PATCH_CULL_COMPUTE_CLIPFLAGS(P) +#define OSD_PATCH_CULL(N) +#endif + // ---------------------------------------------------------------------------- // Legacy Gregory // ---------------------------------------------------------------------------- diff --git a/opensubdiv/osd/glslPatchShaderSource.cpp b/opensubdiv/osd/glslPatchShaderSource.cpp index 81a78041f..f6f9f51bf 100644 --- a/opensubdiv/osd/glslPatchShaderSource.cpp +++ b/opensubdiv/osd/glslPatchShaderSource.cpp @@ -67,10 +67,18 @@ static const char *gregoryTriangleShaderSource = /*static*/ std::string -GLSLPatchShaderSource::GetCommonShaderSource() { +GLSLPatchShaderSource::GetPatchDrawingShaderSource() { std::stringstream ss; ss << std::string(commonShaderSource); ss << std::string(commonTessShaderSource); + return ss.str(); +} + +/*static*/ +std::string +GLSLPatchShaderSource::GetCommonShaderSource() { + std::stringstream ss; + ss << GetPatchDrawingShaderSource(); ss << std::string(patchLegacyShaderSource); return ss.str(); } diff --git a/opensubdiv/osd/glslPatchShaderSource.h b/opensubdiv/osd/glslPatchShaderSource.h index 579a41ff3..487fa4119 100644 --- a/opensubdiv/osd/glslPatchShaderSource.h +++ b/opensubdiv/osd/glslPatchShaderSource.h @@ -26,20 +26,39 @@ #define OPENSUBDIV3_OSD_GLSL_PATCH_SHADER_SOURCE_H #include "../version.h" -#include + #include "../far/patchDescriptor.h" +#include + namespace OpenSubdiv { namespace OPENSUBDIV_VERSION { namespace Osd { +/// \brief Provides shader source which can be used by client code. class GLSLPatchShaderSource { public: - static std::string GetCommonShaderSource(); - + /// \brief Returns shader source which can be used to evaluate + /// position and first and second derivatives on piecewise parametric + /// patches resulting from subdivision refinement. static std::string GetPatchBasisShaderSource(); + /// \brief Returns shader source which can be used while drawing + /// piecewise parametric patches resulting from subdivision refinement, + /// e.g. while using GPU HW tessellation. + static std::string GetPatchDrawingShaderSource(); + + /// \name Alternative methods + /// \{ + /// These methods return shader source which can be used + /// while drawing. Unlike the methods above, the source returned + /// by these methods includes support for legacy patch types along + /// with dependencies on specific resource bindings and interstage + /// shader variable declarations. + + static std::string GetCommonShaderSource(); + static std::string GetVertexShaderSource( Far::PatchDescriptor::Type type); @@ -48,6 +67,8 @@ class GLSLPatchShaderSource { static std::string GetTessEvalShaderSource( Far::PatchDescriptor::Type type); + + /// \} }; } // end namespace Osd diff --git a/opensubdiv/osd/hlslPatchCommon.hlsl b/opensubdiv/osd/hlslPatchCommon.hlsl index a824477bb..d580e81a4 100644 --- a/opensubdiv/osd/hlslPatchCommon.hlsl +++ b/opensubdiv/osd/hlslPatchCommon.hlsl @@ -22,52 +22,11 @@ // language governing permissions and limitations under the Apache License. // -//---------------------------------------------------------- -// Patches.Common -//---------------------------------------------------------- - -struct InputVertex { - float4 position : POSITION; - float3 normal : NORMAL; -}; - -struct HullVertex { - float4 position : POSITION; -#ifdef OSD_ENABLE_PATCH_CULL - int3 clipFlag : CLIPFLAG; -#endif -}; - -// XXXdyu all downstream data can be handled by client code -struct OutputVertex { - float4 positionOut : SV_Position; - float4 position : POSITION1; - float3 normal : NORMAL; - float3 tangent : TANGENT; - float3 bitangent : TANGENT1; - float4 patchCoord : PATCHCOORD; // u, v, faceLevel, faceId - noperspective float4 edgeDistance : EDGEDISTANCE; -#if defined(OSD_COMPUTE_NORMAL_DERIVATIVES) - float3 Nu : TANGENT2; - float3 Nv : TANGENT3; -#endif -#if defined OSD_PATCH_ENABLE_SINGLE_CREASE - float2 vSegments : VSEGMENTS; -#endif -}; - -// osd shaders need following functions defined +// The following callback functions are used when evaluating tessellation +// rates and when using legacy patch drawing. float4x4 OsdModelViewMatrix(); float4x4 OsdProjectionMatrix(); -float4x4 OsdModelViewProjectionMatrix(); float OsdTessLevel(); -int OsdGregoryQuadOffsetBase(); -int OsdPrimitiveIdBase(); -int OsdBaseVertex(); - -#ifndef OSD_DISPLACEMENT_CALLBACK -#define OSD_DISPLACEMENT_CALLBACK -#endif // ---------------------------------------------------------------------------- // Patch Parameters @@ -81,31 +40,6 @@ int OsdBaseVertex(); // bitfield -- refinement-level, non-quad, boundary, transition, uv-offset // sharpness -- crease sharpness for single-crease patches // -// These are stored in OsdPatchParamBuffer indexed by the value returned -// from OsdGetPatchIndex() which is a function of the current PrimitiveID -// along with an optional client provided offset. -// - -#if defined OSD_PATCH_ENABLE_SINGLE_CREASE - Buffer OsdPatchParamBuffer : register( t0 ); -#else - Buffer OsdPatchParamBuffer : register( t0 ); -#endif - -int OsdGetPatchIndex(int primitiveId) -{ - return (primitiveId + OsdPrimitiveIdBase()); -} - -int3 OsdGetPatchParam(int patchIndex) -{ -#if defined OSD_PATCH_ENABLE_SINGLE_CREASE - return OsdPatchParamBuffer[patchIndex].xyz; -#else - uint2 p = OsdPatchParamBuffer[patchIndex].xy; - return int3(p.x, p.y, 0); -#endif -} int OsdGetPatchFaceId(int3 patchParam) { @@ -199,60 +133,6 @@ float4 OsdInterpolatePatchCoordTriangle(float2 localUV, int3 patchParam) return result; } -// ---------------------------------------------------------------------------- -// patch culling -// ---------------------------------------------------------------------------- - -#ifdef OSD_ENABLE_PATCH_CULL - -#define OSD_PATCH_CULL_COMPUTE_CLIPFLAGS(P) \ - float4 clipPos = mul(OsdModelViewProjectionMatrix(), P); \ - int3 clip0 = int3(clipPos.x < clipPos.w, \ - clipPos.y < clipPos.w, \ - clipPos.z < clipPos.w); \ - int3 clip1 = int3(clipPos.x > -clipPos.w, \ - clipPos.y > -clipPos.w, \ - clipPos.z > -clipPos.w); \ - output.clipFlag = int3(clip0) + 2*int3(clip1); \ - -#define OSD_PATCH_CULL(N) \ - int3 clipFlag = int3(0,0,0); \ - for(int i = 0; i < N; ++i) { \ - clipFlag |= patch[i].clipFlag; \ - } \ - if (any(clipFlag != int3(3,3,3))) { \ - output.tessLevelInner[0] = 0; \ - output.tessLevelInner[1] = 0; \ - output.tessLevelOuter[0] = 0; \ - output.tessLevelOuter[1] = 0; \ - output.tessLevelOuter[2] = 0; \ - output.tessLevelOuter[3] = 0; \ - output.tessOuterLo = float4(0,0,0,0); \ - output.tessOuterHi = float4(0,0,0,0); \ - return output; \ - } - -#define OSD_PATCH_CULL_TRIANGLE(N) \ - int3 clipFlag = int3(0,0,0); \ - for(int i = 0; i < N; ++i) { \ - clipFlag |= patch[i].clipFlag; \ - } \ - if (any(clipFlag != int3(3,3,3))) { \ - output.tessLevelInner[0] = 0; \ - output.tessLevelOuter[0] = 0; \ - output.tessLevelOuter[1] = 0; \ - output.tessLevelOuter[2] = 0; \ - output.tessOuterLo = float4(0,0,0,0); \ - output.tessOuterHi = float4(0,0,0,0); \ - return output; \ - } - -#else -#define OSD_PATCH_CULL_COMPUTE_CLIPFLAGS(P) -#define OSD_PATCH_CULL(N) -#define OSD_PATCH_CULL_TRIANGLE(N) -#endif - // ---------------------------------------------------------------------------- void @@ -564,7 +444,7 @@ OsdFlipMatrix(float4x4 m) } // Regular BSpline to Bezier -static float4x4 Q = { +static const float4x4 Q = { 1.f/6.f, 4.f/6.f, 1.f/6.f, 0.f, 0.f, 4.f/6.f, 2.f/6.f, 0.f, 0.f, 2.f/6.f, 4.f/6.f, 0.f, @@ -572,7 +452,7 @@ static float4x4 Q = { }; // Infinitely Sharp (boundary) -static float4x4 Mi = { +static const float4x4 Mi = { 1.f/6.f, 4.f/6.f, 1.f/6.f, 0.f, 0.f, 4.f/6.f, 2.f/6.f, 0.f, 0.f, 2.f/6.f, 4.f/6.f, 0.f, diff --git a/opensubdiv/osd/hlslPatchLegacy.hlsl b/opensubdiv/osd/hlslPatchLegacy.hlsl index 606291ea1..5ec5813ce 100644 --- a/opensubdiv/osd/hlslPatchLegacy.hlsl +++ b/opensubdiv/osd/hlslPatchLegacy.hlsl @@ -22,6 +22,128 @@ // language governing permissions and limitations under the Apache License. // +//---------------------------------------------------------- +// Patches.Common +//---------------------------------------------------------- + +struct InputVertex { + float4 position : POSITION; + float3 normal : NORMAL; +}; + +struct HullVertex { + float4 position : POSITION; +#ifdef OSD_ENABLE_PATCH_CULL + int3 clipFlag : CLIPFLAG; +#endif +}; + +// XXXdyu all downstream data can be handled by client code +struct OutputVertex { + float4 positionOut : SV_Position; + float4 position : POSITION1; + float3 normal : NORMAL; + float3 tangent : TANGENT; + float3 bitangent : TANGENT1; + float4 patchCoord : PATCHCOORD; // u, v, faceLevel, faceId + noperspective float4 edgeDistance : EDGEDISTANCE; +#if defined(OSD_COMPUTE_NORMAL_DERIVATIVES) + float3 Nu : TANGENT2; + float3 Nv : TANGENT3; +#endif +#if defined OSD_PATCH_ENABLE_SINGLE_CREASE + float2 vSegments : VSEGMENTS; +#endif +}; + +float4x4 OsdModelViewProjectionMatrix(); +int OsdGregoryQuadOffsetBase(); +int OsdPrimitiveIdBase(); +int OsdBaseVertex(); + +#ifndef OSD_DISPLACEMENT_CALLBACK +#define OSD_DISPLACEMENT_CALLBACK +#endif + +// These are stored in OsdPatchParamBuffer indexed by the value returned +// from OsdGetPatchIndex() which is a function of the current PrimitiveID +// along with an optional client provided offset. + +#if defined OSD_PATCH_ENABLE_SINGLE_CREASE + Buffer OsdPatchParamBuffer : register( t0 ); +#else + Buffer OsdPatchParamBuffer : register( t0 ); +#endif + +int OsdGetPatchIndex(int primitiveId) +{ + return (primitiveId + OsdPrimitiveIdBase()); +} + +int3 OsdGetPatchParam(int patchIndex) +{ +#if defined OSD_PATCH_ENABLE_SINGLE_CREASE + return OsdPatchParamBuffer[patchIndex].xyz; +#else + uint2 p = OsdPatchParamBuffer[patchIndex].xy; + return int3(p.x, p.y, 0); +#endif +} + +// ---------------------------------------------------------------------------- +// patch culling +// ---------------------------------------------------------------------------- + +#ifdef OSD_ENABLE_PATCH_CULL + +#define OSD_PATCH_CULL_COMPUTE_CLIPFLAGS(P) \ + float4 clipPos = mul(OsdModelViewProjectionMatrix(), P); \ + int3 clip0 = int3(clipPos.x < clipPos.w, \ + clipPos.y < clipPos.w, \ + clipPos.z < clipPos.w); \ + int3 clip1 = int3(clipPos.x > -clipPos.w, \ + clipPos.y > -clipPos.w, \ + clipPos.z > -clipPos.w); \ + output.clipFlag = int3(clip0) + 2*int3(clip1); \ + +#define OSD_PATCH_CULL(N) \ + int3 clipFlag = int3(0,0,0); \ + for(int i = 0; i < N; ++i) { \ + clipFlag |= patch[i].clipFlag; \ + } \ + if (any(clipFlag != int3(3,3,3))) { \ + output.tessLevelInner[0] = 0; \ + output.tessLevelInner[1] = 0; \ + output.tessLevelOuter[0] = 0; \ + output.tessLevelOuter[1] = 0; \ + output.tessLevelOuter[2] = 0; \ + output.tessLevelOuter[3] = 0; \ + output.tessOuterLo = float4(0,0,0,0); \ + output.tessOuterHi = float4(0,0,0,0); \ + return output; \ + } + +#define OSD_PATCH_CULL_TRIANGLE(N) \ + int3 clipFlag = int3(0,0,0); \ + for(int i = 0; i < N; ++i) { \ + clipFlag |= patch[i].clipFlag; \ + } \ + if (any(clipFlag != int3(3,3,3))) { \ + output.tessLevelInner[0] = 0; \ + output.tessLevelOuter[0] = 0; \ + output.tessLevelOuter[1] = 0; \ + output.tessLevelOuter[2] = 0; \ + output.tessOuterLo = float4(0,0,0,0); \ + output.tessOuterHi = float4(0,0,0,0); \ + return output; \ + } + +#else +#define OSD_PATCH_CULL_COMPUTE_CLIPFLAGS(P) +#define OSD_PATCH_CULL(N) +#define OSD_PATCH_CULL_TRIANGLE(N) +#endif + // ---------------------------------------------------------------------------- // Legacy Gregory // ---------------------------------------------------------------------------- diff --git a/opensubdiv/osd/hlslPatchShaderSource.cpp b/opensubdiv/osd/hlslPatchShaderSource.cpp index 6a3bba496..977835b18 100644 --- a/opensubdiv/osd/hlslPatchShaderSource.cpp +++ b/opensubdiv/osd/hlslPatchShaderSource.cpp @@ -69,10 +69,18 @@ static const char *gregoryTriangleShaderSource = /*static*/ std::string -HLSLPatchShaderSource::GetCommonShaderSource() { +HLSLPatchShaderSource::GetPatchDrawingShaderSource() { std::stringstream ss; ss << std::string(commonShaderSource); ss << std::string(commonTessShaderSource); + return ss.str(); +} + +/*static*/ +std::string +HLSLPatchShaderSource::GetCommonShaderSource() { + std::stringstream ss; + ss << GetPatchDrawingShaderSource(); ss << std::string(patchLegacyShaderSource); return ss.str(); } diff --git a/opensubdiv/osd/hlslPatchShaderSource.h b/opensubdiv/osd/hlslPatchShaderSource.h index 028637a9e..96f55d938 100644 --- a/opensubdiv/osd/hlslPatchShaderSource.h +++ b/opensubdiv/osd/hlslPatchShaderSource.h @@ -26,25 +26,46 @@ #define OPENSUBDIV3_OSD_HLSL_PATCH_SHADER_SOURCE_H #include "../version.h" -#include + #include "../far/patchDescriptor.h" +#include + namespace OpenSubdiv { namespace OPENSUBDIV_VERSION { namespace Osd { +/// \brief Provides shader source which can be used by client code. class HLSLPatchShaderSource { public: - static std::string GetCommonShaderSource(); - + /// \brief Returns shader source which can be used to evaluate + /// position and first and second derivatives on piecewise parametric + /// patches resulting from subdivision refinement. static std::string GetPatchBasisShaderSource(); + /// \brief Returns shader source which can be used while drawing + /// piecewise parametric patches resulting from subdivision refinement, + /// e.g. while using GPU HW tessellation. + static std::string GetPatchDrawingShaderSource(); + + /// \name Alternative methods + /// \{ + /// These methods return shader source which can be used + /// while drawing. Unlike the methods above, the source returned + /// by these methods includes support for legacy patch types along + /// with dependencies on specific resource bindings and interstage + /// shader variable declarations. + + static std::string GetCommonShaderSource(); + static std::string GetVertexShaderSource(Far::PatchDescriptor::Type type); static std::string GetHullShaderSource(Far::PatchDescriptor::Type type); static std::string GetDomainShaderSource(Far::PatchDescriptor::Type type); + + /// @} }; } // end namespace Osd diff --git a/opensubdiv/osd/mtlPatchCommon.metal b/opensubdiv/osd/mtlPatchCommon.metal index 60c1a18d4..8d0ea18c5 100644 --- a/opensubdiv/osd/mtlPatchCommon.metal +++ b/opensubdiv/osd/mtlPatchCommon.metal @@ -24,173 +24,15 @@ // language governing permissions and limitations under the Apache License. // -//---------------------------------------------------------- -// Patches.Common -//---------------------------------------------------------- - #include -#define offsetof_(X, Y) &(((device X*)nullptr)->Y) - -#define OSD_IS_ADAPTIVE (OSD_PATCH_REGULAR || OSD_PATCH_BOX_SPLINE_TRIANGLE || OSD_PATCH_GREGORY_BASIS || OSD_PATCH_GREGORY_TRIANGLE || OSD_PATCH_GREGORY || OSD_PATCH_GREGORY_BOUNDARY) - -#ifndef OSD_MAX_TESS_LEVEL -#define OSD_MAX_TESS_LEVEL 64 -#endif - -#ifndef OSD_NUM_ELEMENTS -#define OSD_NUM_ELEMENTS 3 -#endif - using namespace metal; -using OsdPatchParamBufferType = packed_int3; - -struct OsdPerVertexGregory { - float3 P; - short3 clipFlag; - int valence; - float3 e0; - float3 e1; -#if OSD_PATCH_GREGORY_BOUNDARY - int zerothNeighbor; - float3 org; -#endif - float3 r[OSD_MAX_VALENCE]; -}; - -struct OsdPerPatchVertexGregory { - packed_float3 P; - packed_float3 Ep; - packed_float3 Em; - packed_float3 Fp; - packed_float3 Fm; -}; - -//---------------------------------------------------------- -// HLSL->Metal Compatibility -//---------------------------------------------------------- - -float4 mul(float4x4 a, float4 b) -{ - return a * b; -} - -float3 mul(float4x4 a, float3 b) -{ - float3x3 m(a[0].xyz, a[1].xyz, a[2].xyz); - return m * b; - -} - -//---------------------------------------------------------- -// Patches.Common -//---------------------------------------------------------- - -struct HullVertex { - float4 position; -#if OSD_ENABLE_PATCH_CULL - short3 clipFlag; -#endif - - float3 GetPosition() threadgroup - { - return position.xyz; - } - - void SetPosition(float3 v) threadgroup - { - position.xyz = v; - } -}; - -// XXXdyu all downstream data can be handled by client code -struct OsdPatchVertex { - float3 position; - float3 normal; - float3 tangent; - float3 bitangent; - float4 patchCoord; //u, v, faceLevel, faceId - float2 tessCoord; // tesscoord.st -#if OSD_COMPUTE_NORMAL_DERIVATIVES - float3 Nu; - float3 Nv; -#endif -#if OSD_PATCH_ENABLE_SINGLE_CREASE - float2 vSegments; -#endif -}; - -struct OsdPerPatchTessFactors { - float4 tessOuterLo; - float4 tessOuterHi; -}; - -struct OsdPerPatchVertexBezier { - packed_float3 P; -#if OSD_PATCH_ENABLE_SINGLE_CREASE - packed_float3 P1; - packed_float3 P2; -#if !USE_PTVS_SHARPNESS - float2 vSegments; -#endif -#endif -}; - -struct OsdPerPatchVertexGregoryBasis { - packed_float3 P; -}; - -#if OSD_PATCH_REGULAR || OSD_PATCH_BOX_SPLINE_TRIANGLE -using PatchVertexType = HullVertex; -using PerPatchVertexType = OsdPerPatchVertexBezier; -#elif OSD_PATCH_GREGORY || OSD_PATCH_GREGORY_BOUNDARY -using PatchVertexType = OsdPerVertexGregory; -using PerPatchVertexType = OsdPerPatchVertexGregory; -#elif OSD_PATCH_GREGORY_BASIS || OSD_PATCH_GREGORY_TRIANGLE -using PatchVertexType = HullVertex; -using PerPatchVertexType = OsdPerPatchVertexGregoryBasis; -#else -using PatchVertexType = OsdInputVertexType; -using PerPatchVertexType = OsdInputVertexType; -#endif - -//Shared buffers used by OSD that are common to all kernels -struct OsdPatchParamBufferSet -{ - const device OsdInputVertexType* vertexBuffer [[buffer(VERTEX_BUFFER_INDEX)]]; - const device unsigned* indexBuffer [[buffer(CONTROL_INDICES_BUFFER_INDEX)]]; - - const device OsdPatchParamBufferType* patchParamBuffer [[buffer(OSD_PATCHPARAM_BUFFER_INDEX)]]; - - device PerPatchVertexType* perPatchVertexBuffer [[buffer(OSD_PERPATCHVERTEX_BUFFER_INDEX)]]; - -#if !USE_PTVS_FACTORS - device OsdPerPatchTessFactors* patchTessBuffer [[buffer(OSD_PERPATCHTESSFACTORS_BUFFER_INDEX)]]; -#endif - -#if OSD_PATCH_GREGORY || OSD_PATCH_GREGORY_BOUNDARY - const device int* quadOffsetBuffer [[buffer(OSD_QUADOFFSET_BUFFER_INDEX)]]; - const device int* valenceBuffer [[buffer(OSD_VALENCE_BUFFER_INDEX)]]; -#endif - - const constant unsigned& kernelExecutionLimit [[buffer(OSD_KERNELLIMIT_BUFFER_INDEX)]]; -}; - -//Shared buffers used by OSD that are common to all PTVS implementations -struct OsdVertexBufferSet -{ - const device OsdInputVertexType* vertexBuffer [[buffer(VERTEX_BUFFER_INDEX)]]; - const device unsigned* indexBuffer [[buffer(CONTROL_INDICES_BUFFER_INDEX)]]; - - const device OsdPatchParamBufferType* patchParamBuffer [[buffer(OSD_PATCHPARAM_BUFFER_INDEX)]]; - - device PerPatchVertexType* perPatchVertexBuffer [[buffer(OSD_PERPATCHVERTEX_BUFFER_INDEX)]]; - -#if !USE_PTVS_FACTORS - device OsdPerPatchTessFactors* patchTessBuffer [[buffer(OSD_PERPATCHTESSFACTORS_BUFFER_INDEX)]]; -#endif -}; +// The following callback functions are used when evaluating tessellation +// rates and when using legacy patch drawing. +float4x4 OsdModelViewMatrix(); +float4x4 OsdProjectionMatrix(); +float OsdTessLevel(); // ---------------------------------------------------------------------------- // Patch Parameters @@ -204,25 +46,6 @@ struct OsdVertexBufferSet // bitfield -- refinement-level, non-quad, boundary, transition, uv-offset // sharpness -- crease sharpness for single-crease patches // -// These are stored in OsdPatchParamBuffer indexed by the value returned -// from OsdGetPatchIndex() which is a function of the current PrimitiveID -// along with an optional client provided offset. -// - -int3 OsdGetPatchParam(int patchIndex, const device OsdPatchParamBufferType* osdPatchParamBuffer) -{ -#if OSD_PATCH_ENABLE_SINGLE_CREASE - return int3(osdPatchParamBuffer[patchIndex]); -#else - auto p = osdPatchParamBuffer[patchIndex]; - return int3(p[0], p[1], 0); -#endif -} - -int OsdGetPatchIndex(int primitiveId) -{ - return primitiveId; -} int OsdGetPatchFaceId(int3 patchParam) { @@ -316,40 +139,6 @@ float4 OsdInterpolatePatchCoordTriangle(float2 localUV, int3 patchParam) return result; } -// ---------------------------------------------------------------------------- -// patch culling -// ---------------------------------------------------------------------------- - -bool OsdCullPerPatchVertex( - threadgroup PatchVertexType* patch, - float4x4 ModelViewMatrix - ) -{ -#if OSD_ENABLE_BACKPATCH_CULL && OSD_PATCH_REGULAR - auto v0 = float3(ModelViewMatrix * patch[5].position); - auto v3 = float3(ModelViewMatrix * patch[6].position); - auto v12 = float3(ModelViewMatrix * patch[9].position); - - auto n = normalize(cross(v3 - v0, v12 - v0)); - v0 = normalize(v0 + v3 + v12); - - if(dot(v0, n) > 0.6f) - { - return false; - } -#endif -#if OSD_ENABLE_PATCH_CULL - short3 clipFlag = short3(0,0,0); - for(int i = 0; i < CONTROL_POINTS_PER_PATCH; ++i) { - clipFlag |= patch[i].clipFlag; - } - if (any(clipFlag != short3(3,3,3))) { - return false; - } -#endif - return true; -} - // ---------------------------------------------------------------------------- void @@ -421,6 +210,17 @@ OsdUnivar4x4(float u, thread float* B, thread float* D, thread float* C) // ---------------------------------------------------------------------------- +struct OsdPerPatchVertexBezier { + packed_float3 P; +#if OSD_PATCH_ENABLE_SINGLE_CREASE + packed_float3 P1; + packed_float3 P2; +#if !USE_PTVS_SHARPNESS + float2 vSegments; +#endif +#endif +}; + float3 OsdEvalBezier(float3 cp[16], float2 uv) { @@ -1088,6 +888,10 @@ OsdEvalPatchBezier(int3 patchParam, float2 UV, // Gregory Basis // ---------------------------------------------------------------------------- +struct OsdPerPatchVertexGregoryBasis { + packed_float3 P; +}; + void OsdComputePerPatchVertexGregoryBasis(int3 patchParam, int ID, float3 cv, device OsdPerPatchVertexGregoryBasis& result) @@ -1444,3 +1248,4 @@ OsdEvalPatchGregoryTriangle(int3 patchParam, float2 UV, float3 cv[18], OsdEvalPatchBezierTriangle(patchParam, UV, bezcv, P, dPu, dPv, N, dNu, dNv); } + diff --git a/opensubdiv/osd/mtlPatchCommonTess.metal b/opensubdiv/osd/mtlPatchCommonTess.metal index f75f74262..7818ff097 100644 --- a/opensubdiv/osd/mtlPatchCommonTess.metal +++ b/opensubdiv/osd/mtlPatchCommonTess.metal @@ -81,6 +81,10 @@ // (0,0) (1,0) // +#ifndef OSD_MAX_TESS_LEVEL +#define OSD_MAX_TESS_LEVEL 64 +#endif + float OsdComputePostProjectionSphereExtent( const float4x4 OsdProjectionMatrix, float3 center, float diameter) { diff --git a/opensubdiv/osd/mtlPatchLegacy.metal b/opensubdiv/osd/mtlPatchLegacy.metal index a171e3ce4..987e6a756 100644 --- a/opensubdiv/osd/mtlPatchLegacy.metal +++ b/opensubdiv/osd/mtlPatchLegacy.metal @@ -24,6 +24,200 @@ // language governing permissions and limitations under the Apache License. // +//---------------------------------------------------------- +// Patches.Common +//---------------------------------------------------------- + +#define offsetof_(X, Y) &(((device X*)nullptr)->Y) + +#define OSD_IS_ADAPTIVE (OSD_PATCH_REGULAR || OSD_PATCH_BOX_SPLINE_TRIANGLE || OSD_PATCH_GREGORY_BASIS || OSD_PATCH_GREGORY_TRIANGLE || OSD_PATCH_GREGORY || OSD_PATCH_GREGORY_BOUNDARY) + +#ifndef OSD_NUM_ELEMENTS +#define OSD_NUM_ELEMENTS 3 +#endif + +struct OsdPerVertexGregory { + float3 P; + short3 clipFlag; + int valence; + float3 e0; + float3 e1; +#if OSD_PATCH_GREGORY_BOUNDARY + int zerothNeighbor; + float3 org; +#endif + float3 r[OSD_MAX_VALENCE]; +}; + +struct OsdPerPatchVertexGregory { + packed_float3 P; + packed_float3 Ep; + packed_float3 Em; + packed_float3 Fp; + packed_float3 Fm; +}; + +//---------------------------------------------------------- +// HLSL->Metal Compatibility +//---------------------------------------------------------- + +float4 mul(float4x4 a, float4 b) +{ + return a * b; +} + +float3 mul(float4x4 a, float3 b) +{ + float3x3 m(a[0].xyz, a[1].xyz, a[2].xyz); + return m * b; + +} + +struct HullVertex { + float4 position; +#if OSD_ENABLE_PATCH_CULL + short3 clipFlag; +#endif + + float3 GetPosition() threadgroup + { + return position.xyz; + } + + void SetPosition(float3 v) threadgroup + { + position.xyz = v; + } +}; + +// XXXdyu all downstream data can be handled by client code +struct OsdPatchVertex { + float3 position; + float3 normal; + float3 tangent; + float3 bitangent; + float4 patchCoord; //u, v, faceLevel, faceId + float2 tessCoord; // tesscoord.st +#if OSD_COMPUTE_NORMAL_DERIVATIVES + float3 Nu; + float3 Nv; +#endif +#if OSD_PATCH_ENABLE_SINGLE_CREASE + float2 vSegments; +#endif +}; + +struct OsdPerPatchTessFactors { + float4 tessOuterLo; + float4 tessOuterHi; +}; + +using OsdPatchParamBufferType = packed_int3; + +#if OSD_PATCH_REGULAR || OSD_PATCH_BOX_SPLINE_TRIANGLE +using PatchVertexType = HullVertex; +using PerPatchVertexType = OsdPerPatchVertexBezier; +#elif OSD_PATCH_GREGORY || OSD_PATCH_GREGORY_BOUNDARY +using PatchVertexType = OsdPerVertexGregory; +using PerPatchVertexType = OsdPerPatchVertexGregory; +#elif OSD_PATCH_GREGORY_BASIS || OSD_PATCH_GREGORY_TRIANGLE +using PatchVertexType = HullVertex; +using PerPatchVertexType = OsdPerPatchVertexGregoryBasis; +#else +using PatchVertexType = OsdInputVertexType; +using PerPatchVertexType = OsdInputVertexType; +#endif + +//Shared buffers used by OSD that are common to all kernels +struct OsdPatchParamBufferSet +{ + const device OsdInputVertexType* vertexBuffer [[buffer(VERTEX_BUFFER_INDEX)]]; + const device unsigned* indexBuffer [[buffer(CONTROL_INDICES_BUFFER_INDEX)]]; + + const device OsdPatchParamBufferType* patchParamBuffer [[buffer(OSD_PATCHPARAM_BUFFER_INDEX)]]; + + device PerPatchVertexType* perPatchVertexBuffer [[buffer(OSD_PERPATCHVERTEX_BUFFER_INDEX)]]; + +#if !USE_PTVS_FACTORS + device OsdPerPatchTessFactors* patchTessBuffer [[buffer(OSD_PERPATCHTESSFACTORS_BUFFER_INDEX)]]; +#endif + +#if OSD_PATCH_GREGORY || OSD_PATCH_GREGORY_BOUNDARY + const device int* quadOffsetBuffer [[buffer(OSD_QUADOFFSET_BUFFER_INDEX)]]; + const device int* valenceBuffer [[buffer(OSD_VALENCE_BUFFER_INDEX)]]; +#endif + + const constant unsigned& kernelExecutionLimit [[buffer(OSD_KERNELLIMIT_BUFFER_INDEX)]]; +}; + +//Shared buffers used by OSD that are common to all PTVS implementations +struct OsdVertexBufferSet +{ + const device OsdInputVertexType* vertexBuffer [[buffer(VERTEX_BUFFER_INDEX)]]; + const device unsigned* indexBuffer [[buffer(CONTROL_INDICES_BUFFER_INDEX)]]; + + const device OsdPatchParamBufferType* patchParamBuffer [[buffer(OSD_PATCHPARAM_BUFFER_INDEX)]]; + + device PerPatchVertexType* perPatchVertexBuffer [[buffer(OSD_PERPATCHVERTEX_BUFFER_INDEX)]]; + +#if !USE_PTVS_FACTORS + device OsdPerPatchTessFactors* patchTessBuffer [[buffer(OSD_PERPATCHTESSFACTORS_BUFFER_INDEX)]]; +#endif +}; + +// These are stored in OsdPatchParamBuffer indexed by the value returned +// from OsdGetPatchIndex() which is a function of the current PrimitiveID +// along with an optional client provided offset. + +int3 OsdGetPatchParam(int patchIndex, const device OsdPatchParamBufferType* osdPatchParamBuffer) +{ +#if OSD_PATCH_ENABLE_SINGLE_CREASE + return int3(osdPatchParamBuffer[patchIndex]); +#else + auto p = osdPatchParamBuffer[patchIndex]; + return int3(p[0], p[1], 0); +#endif +} + +int OsdGetPatchIndex(int primitiveId) +{ + return primitiveId; +} + +// ---------------------------------------------------------------------------- +// patch culling +// ---------------------------------------------------------------------------- + +bool OsdCullPerPatchVertex( + threadgroup PatchVertexType* patch, + float4x4 ModelViewMatrix + ) +{ +#if OSD_ENABLE_BACKPATCH_CULL && OSD_PATCH_REGULAR + auto v0 = float3(ModelViewMatrix * patch[5].position); + auto v3 = float3(ModelViewMatrix * patch[6].position); + auto v12 = float3(ModelViewMatrix * patch[9].position); + + auto n = normalize(cross(v3 - v0, v12 - v0)); + v0 = normalize(v0 + v3 + v12); + + if(dot(v0, n) > 0.6f) + { + return false; + } +#endif +#if OSD_ENABLE_PATCH_CULL + short3 clipFlag = short3(0,0,0); + for(int i = 0; i < CONTROL_POINTS_PER_PATCH; ++i) { + clipFlag |= patch[i].clipFlag; + } + if (any(clipFlag != short3(3,3,3))) { + return false; + } +#endif + return true; +} + // ---------------------------------------------------------------------------- // Legacy Gregory // ---------------------------------------------------------------------------- diff --git a/opensubdiv/osd/mtlPatchShaderSource.h b/opensubdiv/osd/mtlPatchShaderSource.h index 54bbf6cda..616b7725b 100644 --- a/opensubdiv/osd/mtlPatchShaderSource.h +++ b/opensubdiv/osd/mtlPatchShaderSource.h @@ -26,7 +26,9 @@ #define OPENSUBDIV3_OSD_MTL_PATCH_SHADER_SOURCE_H #import "../version.h" + #import "../far/patchDescriptor.h" + #import namespace OpenSubdiv { @@ -34,12 +36,29 @@ namespace OPENSUBDIV_VERSION { namespace Osd { +/// \brief Provides shader source which can be used by client code. class MTLPatchShaderSource { - public: - static std::string GetCommonShaderSource(); - +public: + /// \brief Returns shader source which can be used to evaluate + /// position and first and second derivatives on piecewise parametric + /// patches resulting from subdivision refinement. static std::string GetPatchBasisShaderSource(); + /// \brief Returns shader source which can be used while drawing + /// piecewise parametric patches resulting from subdivision refinement, + /// e.g. while using GPU HW tessellation. + static std::string GetPatchDrawingShaderSource(); + + /// \name Alternative methods + /// \{ + /// These methods return shader source which can be used + /// while drawing. Unlike the methods above, the source returned + /// by these methods includes support for legacy patch types along + /// with dependencies on specific resource bindings and interstage + /// shader variable declarations. + + static std::string GetCommonShaderSource(); + static std::string GetVertexShaderSource(Far::PatchDescriptor::Type type); static std::string GetHullShaderSource(Far::PatchDescriptor::Type type); @@ -59,6 +78,9 @@ class MTLPatchShaderSource { static std::string GetDomainShaderSource( Far::PatchDescriptor::Type type, Far::PatchDescriptor::Type fvarType); + + /// @} + }; } // end namespace Osd diff --git a/opensubdiv/osd/mtlPatchShaderSource.mm b/opensubdiv/osd/mtlPatchShaderSource.mm index 754909f01..d73b3aaec 100644 --- a/opensubdiv/osd/mtlPatchShaderSource.mm +++ b/opensubdiv/osd/mtlPatchShaderSource.mm @@ -147,20 +147,25 @@ /*static*/ std::string -MTLPatchShaderSource::GetCommonShaderSource() { +MTLPatchShaderSource::GetPatchDrawingShaderSource() { #if TARGET_OS_IOS || TARGET_OS_TV return std::string("#define OSD_METAL_IOS 1\n") .append(commonShaderSource) - .append(commonTessShaderSource) - .append(patchLegacyShaderSource); + .append(commonTessShaderSource); #elif TARGET_OS_OSX return std::string("#define OSD_METAL_OSX 1\n") .append(commonShaderSource) - .append(commonTessShaderSource) - .append(patchLegacyShaderSource); + .append(commonTessShaderSource); #endif } +/*static*/ +std::string +MTLPatchShaderSource::GetCommonShaderSource() { + return GetPatchDrawingShaderSource() + .append(patchLegacyShaderSource); +} + /*static*/ std::string MTLPatchShaderSource::GetPatchBasisShaderSource() {