Reorganized legacy patch drawing shader source

Relocated from PatchCommon to PatchLegacy several aspects of the
shader source which can cause problems with typical use cases.
Specifically, things like resource bindings, input assembler and
interstage declarations are best left to client code.

These are not removed, just relocated and remain available for
backward compatibility. Updated the GLSL, HLSL, and MSL source.
This commit is contained in:
David G Yu 2023-09-07 16:44:43 -07:00 committed by David G Yu
parent 18f3b91c28
commit c2ed7d5cf0
7 changed files with 471 additions and 482 deletions

View File

@ -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,

View File

@ -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
// ----------------------------------------------------------------------------

View File

@ -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<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)
{
@ -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,

View File

@ -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<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
// ----------------------------------------------------------------------------

View File

@ -24,173 +24,15 @@
// language governing permissions and limitations under the Apache License.
//
//----------------------------------------------------------
// Patches.Common
//----------------------------------------------------------
#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 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);
}

View File

@ -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)
{

View File

@ -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
// ----------------------------------------------------------------------------