Merge pull request #1320 from davidgyu/dev_osd_patch_drawing_compatibilty

Improved osd patch drawing compatibility
This commit is contained in:
David G Yu 2023-09-13 18:18:41 -07:00 committed by GitHub
commit 3597371f84
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 572 additions and 498 deletions

View File

@ -22,101 +22,11 @@
// language governing permissions and limitations under the Apache License. // language governing permissions and limitations under the Apache License.
// //
// // The following callback functions are used when evaluating tessellation
// typical shader composition ordering (see glDrawRegistry:_CompileShader) // rates and when using legacy patch drawing.
//
//
// - 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
mat4 OsdModelViewMatrix(); mat4 OsdModelViewMatrix();
mat4 OsdProjectionMatrix(); mat4 OsdProjectionMatrix();
mat4 OsdModelViewProjectionMatrix();
float OsdTessLevel(); float OsdTessLevel();
int OsdGregoryQuadOffsetBase();
int OsdPrimitiveIdBase();
int OsdBaseVertex();
#ifndef OSD_DISPLACEMENT_CALLBACK
#define OSD_DISPLACEMENT_CALLBACK
#endif
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Patch Parameters // Patch Parameters
@ -130,22 +40,6 @@ int OsdBaseVertex();
// bitfield -- refinement-level, non-quad, boundary, transition, uv-offset // bitfield -- refinement-level, non-quad, boundary, transition, uv-offset
// sharpness -- crease sharpness for single-crease patches // 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) int OsdGetPatchFaceId(ivec3 patchParam)
{ {
@ -239,38 +133,6 @@ vec4 OsdInterpolatePatchCoordTriangle(vec2 localUV, ivec3 patchParam)
return result; 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 void
@ -582,7 +444,7 @@ OsdFlipMatrix(mat4 m)
} }
// Regular BSpline to Bezier // 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, 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, 4.f/6.f, 2.f/6.f, 0.f,
0.f, 2.f/6.f, 4.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) // 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, 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, 4.f/6.f, 2.f/6.f, 0.f,
0.f, 2.f/6.f, 4.f/6.f, 0.f, 0.f, 2.f/6.f, 4.f/6.f, 0.f,

View File

@ -22,6 +22,128 @@
// language governing permissions and limitations under the Apache License. // 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 // Legacy Gregory
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------

View File

@ -67,10 +67,18 @@ static const char *gregoryTriangleShaderSource =
/*static*/ /*static*/
std::string std::string
GLSLPatchShaderSource::GetCommonShaderSource() { GLSLPatchShaderSource::GetPatchDrawingShaderSource() {
std::stringstream ss; std::stringstream ss;
ss << std::string(commonShaderSource); ss << std::string(commonShaderSource);
ss << std::string(commonTessShaderSource); ss << std::string(commonTessShaderSource);
return ss.str();
}
/*static*/
std::string
GLSLPatchShaderSource::GetCommonShaderSource() {
std::stringstream ss;
ss << GetPatchDrawingShaderSource();
ss << std::string(patchLegacyShaderSource); ss << std::string(patchLegacyShaderSource);
return ss.str(); return ss.str();
} }

View File

@ -26,20 +26,39 @@
#define OPENSUBDIV3_OSD_GLSL_PATCH_SHADER_SOURCE_H #define OPENSUBDIV3_OSD_GLSL_PATCH_SHADER_SOURCE_H
#include "../version.h" #include "../version.h"
#include <string>
#include "../far/patchDescriptor.h" #include "../far/patchDescriptor.h"
#include <string>
namespace OpenSubdiv { namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION { namespace OPENSUBDIV_VERSION {
namespace Osd { namespace Osd {
/// \brief Provides shader source which can be used by client code.
class GLSLPatchShaderSource { class GLSLPatchShaderSource {
public: 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(); 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( static std::string GetVertexShaderSource(
Far::PatchDescriptor::Type type); Far::PatchDescriptor::Type type);
@ -48,6 +67,8 @@ public:
static std::string GetTessEvalShaderSource( static std::string GetTessEvalShaderSource(
Far::PatchDescriptor::Type type); Far::PatchDescriptor::Type type);
/// \}
}; };
} // end namespace Osd } // end namespace Osd

View File

@ -22,52 +22,11 @@
// language governing permissions and limitations under the Apache License. // language governing permissions and limitations under the Apache License.
// //
//---------------------------------------------------------- // The following callback functions are used when evaluating tessellation
// Patches.Common // rates and when using legacy patch drawing.
//----------------------------------------------------------
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
float4x4 OsdModelViewMatrix(); float4x4 OsdModelViewMatrix();
float4x4 OsdProjectionMatrix(); float4x4 OsdProjectionMatrix();
float4x4 OsdModelViewProjectionMatrix();
float OsdTessLevel(); float OsdTessLevel();
int OsdGregoryQuadOffsetBase();
int OsdPrimitiveIdBase();
int OsdBaseVertex();
#ifndef OSD_DISPLACEMENT_CALLBACK
#define OSD_DISPLACEMENT_CALLBACK
#endif
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Patch Parameters // Patch Parameters
@ -81,31 +40,6 @@ int OsdBaseVertex();
// bitfield -- refinement-level, non-quad, boundary, transition, uv-offset // bitfield -- refinement-level, non-quad, boundary, transition, uv-offset
// sharpness -- crease sharpness for single-crease patches // 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<uint3> OsdPatchParamBuffer : register( t0 );
#else
Buffer<uint2> 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) int OsdGetPatchFaceId(int3 patchParam)
{ {
@ -199,60 +133,6 @@ float4 OsdInterpolatePatchCoordTriangle(float2 localUV, int3 patchParam)
return result; 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 void
@ -564,7 +444,7 @@ OsdFlipMatrix(float4x4 m)
} }
// Regular BSpline to Bezier // 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, 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, 4.f/6.f, 2.f/6.f, 0.f,
0.f, 2.f/6.f, 4.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) // Infinitely Sharp (boundary)
static float4x4 Mi = { static const float4x4 Mi = {
1.f/6.f, 4.f/6.f, 1.f/6.f, 0.f, 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, 4.f/6.f, 2.f/6.f, 0.f,
0.f, 2.f/6.f, 4.f/6.f, 0.f, 0.f, 2.f/6.f, 4.f/6.f, 0.f,

View File

@ -22,6 +22,128 @@
// language governing permissions and limitations under the Apache License. // 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<uint3> OsdPatchParamBuffer : register( t0 );
#else
Buffer<uint2> 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 // Legacy Gregory
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------

View File

@ -69,10 +69,18 @@ static const char *gregoryTriangleShaderSource =
/*static*/ /*static*/
std::string std::string
HLSLPatchShaderSource::GetCommonShaderSource() { HLSLPatchShaderSource::GetPatchDrawingShaderSource() {
std::stringstream ss; std::stringstream ss;
ss << std::string(commonShaderSource); ss << std::string(commonShaderSource);
ss << std::string(commonTessShaderSource); ss << std::string(commonTessShaderSource);
return ss.str();
}
/*static*/
std::string
HLSLPatchShaderSource::GetCommonShaderSource() {
std::stringstream ss;
ss << GetPatchDrawingShaderSource();
ss << std::string(patchLegacyShaderSource); ss << std::string(patchLegacyShaderSource);
return ss.str(); return ss.str();
} }

View File

@ -26,25 +26,46 @@
#define OPENSUBDIV3_OSD_HLSL_PATCH_SHADER_SOURCE_H #define OPENSUBDIV3_OSD_HLSL_PATCH_SHADER_SOURCE_H
#include "../version.h" #include "../version.h"
#include <string>
#include "../far/patchDescriptor.h" #include "../far/patchDescriptor.h"
#include <string>
namespace OpenSubdiv { namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION { namespace OPENSUBDIV_VERSION {
namespace Osd { namespace Osd {
/// \brief Provides shader source which can be used by client code.
class HLSLPatchShaderSource { class HLSLPatchShaderSource {
public: 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(); 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 GetVertexShaderSource(Far::PatchDescriptor::Type type);
static std::string GetHullShaderSource(Far::PatchDescriptor::Type type); static std::string GetHullShaderSource(Far::PatchDescriptor::Type type);
static std::string GetDomainShaderSource(Far::PatchDescriptor::Type type); static std::string GetDomainShaderSource(Far::PatchDescriptor::Type type);
/// @}
}; };
} // end namespace Osd } // end namespace Osd

View File

@ -24,173 +24,15 @@
// language governing permissions and limitations under the Apache License. // language governing permissions and limitations under the Apache License.
// //
//----------------------------------------------------------
// Patches.Common
//----------------------------------------------------------
#include <metal_stdlib> #include <metal_stdlib>
#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 namespace metal;
using OsdPatchParamBufferType = packed_int3; // The following callback functions are used when evaluating tessellation
// rates and when using legacy patch drawing.
struct OsdPerVertexGregory { float4x4 OsdModelViewMatrix();
float3 P; float4x4 OsdProjectionMatrix();
short3 clipFlag; float OsdTessLevel();
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
};
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Patch Parameters // Patch Parameters
@ -204,25 +46,6 @@ struct OsdVertexBufferSet
// bitfield -- refinement-level, non-quad, boundary, transition, uv-offset // bitfield -- refinement-level, non-quad, boundary, transition, uv-offset
// sharpness -- crease sharpness for single-crease patches // 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) int OsdGetPatchFaceId(int3 patchParam)
{ {
@ -316,40 +139,6 @@ float4 OsdInterpolatePatchCoordTriangle(float2 localUV, int3 patchParam)
return result; 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 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 float3
OsdEvalBezier(float3 cp[16], float2 uv) OsdEvalBezier(float3 cp[16], float2 uv)
{ {
@ -1088,6 +888,10 @@ OsdEvalPatchBezier(int3 patchParam, float2 UV,
// Gregory Basis // Gregory Basis
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
struct OsdPerPatchVertexGregoryBasis {
packed_float3 P;
};
void void
OsdComputePerPatchVertexGregoryBasis(int3 patchParam, int ID, float3 cv, OsdComputePerPatchVertexGregoryBasis(int3 patchParam, int ID, float3 cv,
device OsdPerPatchVertexGregoryBasis& result) 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); OsdEvalPatchBezierTriangle(patchParam, UV, bezcv, P, dPu, dPv, N, dNu, dNv);
} }

View File

@ -81,6 +81,10 @@
// (0,0) (1,0) // (0,0) (1,0)
// //
#ifndef OSD_MAX_TESS_LEVEL
#define OSD_MAX_TESS_LEVEL 64
#endif
float OsdComputePostProjectionSphereExtent( float OsdComputePostProjectionSphereExtent(
const float4x4 OsdProjectionMatrix, float3 center, float diameter) const float4x4 OsdProjectionMatrix, float3 center, float diameter)
{ {

View File

@ -24,6 +24,200 @@
// language governing permissions and limitations under the Apache License. // 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 // Legacy Gregory
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------

View File

@ -26,7 +26,9 @@
#define OPENSUBDIV3_OSD_MTL_PATCH_SHADER_SOURCE_H #define OPENSUBDIV3_OSD_MTL_PATCH_SHADER_SOURCE_H
#import "../version.h" #import "../version.h"
#import "../far/patchDescriptor.h" #import "../far/patchDescriptor.h"
#import <string> #import <string>
namespace OpenSubdiv { namespace OpenSubdiv {
@ -34,12 +36,29 @@ namespace OPENSUBDIV_VERSION {
namespace Osd { namespace Osd {
/// \brief Provides shader source which can be used by client code.
class MTLPatchShaderSource { class MTLPatchShaderSource {
public: 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(); 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 GetVertexShaderSource(Far::PatchDescriptor::Type type);
static std::string GetHullShaderSource(Far::PatchDescriptor::Type type); static std::string GetHullShaderSource(Far::PatchDescriptor::Type type);
@ -59,6 +78,9 @@ class MTLPatchShaderSource {
static std::string GetDomainShaderSource( static std::string GetDomainShaderSource(
Far::PatchDescriptor::Type type, Far::PatchDescriptor::Type type,
Far::PatchDescriptor::Type fvarType); Far::PatchDescriptor::Type fvarType);
/// @}
}; };
} // end namespace Osd } // end namespace Osd

View File

@ -147,20 +147,25 @@ GetPatchTypeSource(Far::PatchDescriptor::Type type) {
/*static*/ /*static*/
std::string std::string
MTLPatchShaderSource::GetCommonShaderSource() { MTLPatchShaderSource::GetPatchDrawingShaderSource() {
#if TARGET_OS_IOS || TARGET_OS_TV #if TARGET_OS_IOS || TARGET_OS_TV
return std::string("#define OSD_METAL_IOS 1\n") return std::string("#define OSD_METAL_IOS 1\n")
.append(commonShaderSource) .append(commonShaderSource)
.append(commonTessShaderSource) .append(commonTessShaderSource);
.append(patchLegacyShaderSource);
#elif TARGET_OS_OSX #elif TARGET_OS_OSX
return std::string("#define OSD_METAL_OSX 1\n") return std::string("#define OSD_METAL_OSX 1\n")
.append(commonShaderSource) .append(commonShaderSource)
.append(commonTessShaderSource) .append(commonTessShaderSource);
.append(patchLegacyShaderSource);
#endif #endif
} }
/*static*/
std::string
MTLPatchShaderSource::GetCommonShaderSource() {
return GetPatchDrawingShaderSource()
.append(patchLegacyShaderSource);
}
/*static*/ /*static*/
std::string std::string
MTLPatchShaderSource::GetPatchBasisShaderSource() { MTLPatchShaderSource::GetPatchBasisShaderSource() {