Merge pull request #936 from NickBMarine/metalFvarExample

Added fvar support for metal as well as a ui for fvar.
This commit is contained in:
David G Yu 2017-06-09 17:57:26 -07:00 committed by GitHub
commit fde91b4a42
6 changed files with 376 additions and 109 deletions

View File

@ -213,6 +213,18 @@ enum {
}
};
auto callbackBoundary = [=](int boundaryType) {
switch((FVarBoundary)boundaryType) {
case kFVarLinearNone:
case kFVarLinearCornersOnly:
case kFVarLinearCornersPlus1:
case kFVarLinearCornersPlus2:
case kFVarLinearBoundaries:
case kFVarLinearAll:
self.osdRenderer.fVarBoundary = (FVarBoundary)boundaryType;
}
};
auto callbackDisplayStyle = [=](int displayStyle) {
switch((DisplayStyle)displayStyle) {
case kDisplayStyleWire:
@ -231,6 +243,7 @@ enum {
case kShadingMaterial:
case kShadingPatchType:
case kShadingPatchCoord:
case kShadingFaceVarying:
self.osdRenderer.shadingMode = (ShadingMode)shadingMode;
break;
default:
@ -282,8 +295,8 @@ enum {
hud.AddCheckBox("Fractional spacing (T)", _osdRenderer.useFractionalTessellation,
10, y, callbackCheckbox, kHUD_CB_FRACTIONAL_SPACING, 't');
y += 20;
hud.AddCheckBox("Frustum Patch Culling (B)", _osdRenderer.usePatchClipCulling,
10, y, callbackCheckbox, kHUD_CB_PATCH_CULL, 'b');
hud.AddCheckBox("Frustum Patch Culling (F)", _osdRenderer.usePatchClipCulling,
10, y, callbackCheckbox, kHUD_CB_PATCH_CULL, 'f');
y += 20;
hud.AddCheckBox("Backface Culling (L)", _osdRenderer.usePatchBackfaceCulling,
10, y, callbackCheckbox, kHUD_CB_BACK_CULL, 'l');
@ -321,10 +334,34 @@ enum {
hud.AddPullDownButton(shading_pulldown, "Normal",
kShadingNormal,
_osdRenderer.shadingMode == kShadingNormal);
hud.AddPullDownButton(shading_pulldown, "Face Varying",
kShadingFaceVarying,
_osdRenderer.shadingMode == kShadingFaceVarying);
int compute_pulldown = hud.AddPullDown("Compute (K)", 475, 10, 300, callbackKernel, 'k');
int compute_pulldown = hud.AddPullDown("Compute (K)", 475, 10, 175, callbackKernel, 'k');
hud.AddPullDownButton(compute_pulldown, "CPU", kCPU, _osdRenderer.kernelType == kCPU);
hud.AddPullDownButton(compute_pulldown, "Metal", kMetal, _osdRenderer.kernelType == kMetal);
int boundary_pulldown = hud.AddPullDown("Boundary (B)", 650, 10, 300, callbackBoundary, 'b');
hud.AddPullDownButton(boundary_pulldown, "None (edge only)",
kFVarLinearNone,
_osdRenderer.fVarBoundary == kFVarLinearNone);
hud.AddPullDownButton(boundary_pulldown, "Corners Only",
kFVarLinearCornersOnly,
_osdRenderer.fVarBoundary == kFVarLinearCornersOnly);
hud.AddPullDownButton(boundary_pulldown, "Corners 1 (edge corner)",
kFVarLinearCornersPlus1,
_osdRenderer.fVarBoundary == kFVarLinearCornersPlus1);
hud.AddPullDownButton(boundary_pulldown, "Corners 2 (edge corner prop)",
kFVarLinearCornersPlus2,
_osdRenderer.fVarBoundary == kFVarLinearCornersPlus2);
hud.AddPullDownButton(boundary_pulldown, "Boundaries (always sharp)",
kFVarLinearBoundaries,
_osdRenderer.fVarBoundary == kFVarLinearBoundaries);
hud.AddPullDownButton(boundary_pulldown, "All (bilinear)",
kFVarLinearAll,
_osdRenderer.fVarBoundary == kFVarLinearAll);
{
hud.AddCheckBox("Adaptive (`)", _osdRenderer.useAdaptive,
10, 190, callbackCheckbox, kHUD_CB_ADAPTIVE, '`');

View File

@ -34,6 +34,15 @@ typedef enum {
kEndCapGregoryBasis,
} EndCap;
typedef enum {
kFVarLinearNone = 0,
kFVarLinearCornersOnly,
kFVarLinearCornersPlus1,
kFVarLinearCornersPlus2,
kFVarLinearBoundaries,
kFVarLinearAll
} FVarBoundary;
typedef enum {
kCPU = 0,
kMetal,
@ -49,7 +58,8 @@ typedef enum {
kShadingMaterial = 0,
kShadingPatchType,
kShadingNormal,
kShadingPatchCoord
kShadingPatchCoord,
kShadingFaceVarying,
} ShadingMode;
@ -105,6 +115,7 @@ typedef struct {
@property (nonatomic) DisplayStyle displayStyle;
@property (nonatomic) ShadingMode shadingMode;
@property (nonatomic) EndCap endCapMode;
@property (nonatomic) FVarBoundary fVarBoundary;
@property (nonatomic) KernelType kernelType;
@end

View File

@ -31,7 +31,7 @@ using namespace metal;
#define SHADING_TYPE_PATCH 1
#define SHADING_TYPE_NORMAL 2
#define SHADING_TYPE_PATCH_COORD 3
#define SHADING_TYPE_FACE_VARYING 4
struct PerFrameConstants {
float4x4 ModelViewMatrix;
@ -46,7 +46,7 @@ struct OutputVertex {
float3 position;
float3 normal;
#if SHADING_TYPE == SHADING_TYPE_PATCH || SHADING_TYPE == SHADING_TYPE_PATCH_COORD
#if SHADING_TYPE == SHADING_TYPE_PATCH || SHADING_TYPE == SHADING_TYPE_PATCH_COORD || SHADING_TYPE_FACE_VARYING
float3 patchColor;
#endif
};
@ -65,6 +65,7 @@ struct SolidColorVertex {
private:
uint _color [[flat, user(color)]];
};
struct PackedInputVertex {
packed_float3 position;
};
@ -190,7 +191,6 @@ getAdaptivePatchColor(int3 patchParam
#if OSD_PATCH_REGULAR
struct ControlPoint
{
float3 P [[attribute(0)]];
#if OSD_PATCH_ENABLE_SINGLE_CREASE
float3 P1 [[attribute(1)]];
@ -213,7 +213,6 @@ struct PatchInput
#elif OSD_PATCH_GREGORY || OSD_PATCH_GREGORY_BOUNDARY
struct ControlPoint
{
float3 P [[attribute(0)]];
float3 Ep [[attribute(1)]];
float3 Em [[attribute(2)]];
@ -399,6 +398,9 @@ vertex OutputVertex vertex_main(
#else
const OsdVertexBufferSet patchInput,
#endif
const device float* osdFaceVaryingData [[buffer(OSD_FVAR_DATA_BUFFER_INDEX)]],
const device int* osdFaceVaryingIndices [[buffer(OSD_FVAR_INDICES_BUFFER_INDEX)]],
const device packed_int3* osdFaceVaryingPatchParams [[buffer(OSD_FVAR_PATCHPARAM_BUFFER_INDEX)]],
float2 position_in_patch [[position_in_patch]],
uint patch_id [[patch_id]]
)
@ -430,6 +432,52 @@ vertex OutputVertex vertex_main(
#elif SHADING_TYPE == SHADING_TYPE_NORMAL
#elif SHADING_TYPE == SHADING_TYPE_PATCH_COORD
out.patchColor = patchVertex.patchCoord.xyz;
#elif SHADING_TYPE == SHADING_TYPE_FACE_VARYING
int patchIndex = OsdGetPatchIndex(patch_id);
float2 uv = position_in_patch;
#if OSD_FACEVARYING_PATCH_REGULAR
float wP[16], wDs[16], wDt[16], wDss[16], wDst[16], wDtt[16];
int patchCVs = 16;
int patchStride = patchCVs;
int3 fvarPatchParam = osdFaceVaryingPatchParams[patchIndex];
int boundaryMask = OsdGetPatchBoundaryMask(fvarPatchParam);
OsdGetBSplinePatchWeights(uv.x, uv.y, 1.0f, boundaryMask, wP, wDs, wDt, wDss, wDst, wDtt);
#elif OSD_FACEVARYING_PATCH_GREGORY_BASIS
float wP[20], wDs[20], wDt[20], wDss[20], wDst[20], wDtt[20];
int patchCVs = 20;
int patchStride = patchCVs;
int3 fvarPatchParam = osdFaceVaryingPatchParams[patchIndex];
if (OsdGetPatchIsRegular(fvarPatchParam)) {
float wP16[16], wDs16[16], wDt16[16], wDss16[16], wDst16[16], wDtt16[16];
patchCVs = 16;
int boundaryMask = OsdGetPatchBoundaryMask(fvarPatchParam);
OsdGetBSplinePatchWeights(uv.x, uv.y, 1.0f, boundaryMask, wP16, wDs16, wDt16, wDss16, wDst16, wDtt16);
for (int i=0; i<patchCVs; ++i) {
wP[i] = wP16[i];
}
} else {
OsdGetGregoryPatchWeights(uv.x, uv.y, 1.0f, wP, wDs, wDt, wDss, wDst, wDtt);
}
#elif OSD_FACEVARYING_PATCH_GREGORY || OSD_PATCH_GREGORY_BOUNDARY
TODO
#else
float wP[4], wDs[4], wDt[4], wDss[4], wDst[4], wDtt[4];
int patchCVs = 4;
int patchStride = patchCVs;
OsdGetBilinearPatchWeights(uv.x, uv.y, 1.0f, wP, wDs, wDt, wDss, wDst, wDtt);
#endif
int primOffset = patchIndex * patchStride;
float2 fvarUV = float2(0.);
for (int i = 0; i < patchCVs; ++i) {
int index = osdFaceVaryingIndices[primOffset + i] * 2 /* OSD_FVAR_WIDTH */ + 0 /* fvarOffset */;
float2 cv = float2(osdFaceVaryingData[index + 0], osdFaceVaryingData[index + 1]);
fvarUV += wP[i] * cv;
}
out.patchColor.rg = fvarUV;
#endif
return out;
@ -488,6 +536,7 @@ vertex SolidColorVertex vertex_lines(
const auto in = osdPerPatchVertexBezier[patch_id * VERTEX_CONTROL_POINTS_PER_PATCH + BSplineControlLineIndices[idx]];
SolidColorVertex out;
out.positionOut = frameConsts.ModelViewProjectionMatrix * float4(in.P, 1.0);
out.positionOut.z -= 0.001;
@ -590,6 +639,8 @@ vertex OutputVertex vertex_main(
device unsigned* indicesBuffer [[buffer(INDICES_BUFFER_INDEX)]],
device PackedInputVertex* vertexBuffer [[buffer(VERTEX_BUFFER_INDEX)]],
const constant PerFrameConstants& frameConsts [[buffer(FRAME_CONST_BUFFER_INDEX)]],
const device float2* osdFaceVaryingData[[buffer(OSD_FVAR_DATA_BUFFER_INDEX)]],
const device int* osdFaceVaryingIndices[[buffer(OSD_FVAR_INDICES_BUFFER_INDEX)]],
uint vertex_id [[vertex_id]]
)
{
@ -604,11 +655,13 @@ vertex OutputVertex vertex_main(
float3 p1 = vertexBuffer[indicesBuffer[quadId * 4 + 1]].position;
float3 p2 = vertexBuffer[indicesBuffer[quadId * 4 + 2]].position;
float3 position = vertexBuffer[indicesBuffer[quadId * 4 + triangleIdx[vertex_id % 6]]].position;
float2 uv = osdFaceVaryingData[osdFaceVaryingIndices[quadId * 4 + triangleIdx[vertex_id % 6]]].xy;
#else
float3 p0 = vertexBuffer[indicesBuffer[primID * 3 + 0]].position;
float3 p1 = vertexBuffer[indicesBuffer[primID * 3 + 1]].position;
float3 p2 = vertexBuffer[indicesBuffer[primID * 3 + 2]].position;
float3 position = vertexBuffer[indicesBuffer[vertex_id]].position;
float2 uv = osdFacevaryingData[osdFaceVaryingIndices[vertex_id]].xy;
#endif
float3 normal = normalize(cross(p2 - p1, p0 - p1));
@ -621,6 +674,8 @@ vertex OutputVertex vertex_main(
#if SHADING_TYPE == SHADING_TYPE_PATCH || SHADING_TYPE == SHADING_TYPE_PATCH_COORD
out.patchColor = out.normal;
#elif SHADING_TYPE == SHADING_TYPE_FACE_VARYING
out.patchColor.rg = uv;
#endif
return out;
@ -669,17 +724,17 @@ fragment float4 fragment_main(OutputVertex in [[stage_in]],
const float3 diffuseColor = float3(0.4f, 0.4f, 0.8f);
#elif SHADING_TYPE == SHADING_TYPE_PATCH
const float3 diffuseColor = in.patchColor;
#else
#endif
#if SHADING_TYPE == SHADING_TYPE_NORMAL
color.xyz = normalize(in.normal) * 0.5 + 0.5;
#elif SHADING_TYPE == SHADING_TYPE_PATCH_COORD
color.xy = in.patchColor.xy;
color.z = 0;
#elif SHADING_TYPE == SHADING_TYPE_PATCH_COORD || SHADING_TYPE == SHADING_TYPE_FACE_VARYING
color.xyz = lighting(1.0, lightData, in.position, normalize(in.normal));
int checker = int(floor(20*in.patchColor.r)+floor(20*in.patchColor.g))&1;
color.xyz *= float3(in.patchColor.rg*checker, 1-checker);
color.xyz = pow(color.xyz, 1/2.2);
#else
color.xyz = lighting(diffuseColor, lightData, in.position, normalize(in.normal));
#endif
// color.xyz = pow(color.xyz, 2.2);
color.w = 1;
return max(color,shade);
}

View File

@ -67,9 +67,17 @@
#define OSD_DRAWINDIRECT_BUFFER_INDEX 14
#define OSD_KERNELLIMIT_BUFFER_INDEX 15
#define OSD_FVAR_DATA_BUFFER_INDEX 16
#define OSD_FVAR_INDICES_BUFFER_INDEX 17
#define OSD_FVAR_PATCHPARAM_BUFFER_INDEX 18
#define FRAME_CONST_BUFFER_INDEX 11
#define INDICES_BUFFER_INDEX 2
#define USE_FACE_VARYING 1
#define FVAR_SINGLE_BUFFER 1
using namespace OpenSubdiv::OPENSUBDIV_VERSION;
template <> Far::StencilTable const * Osd::convertToCompatibleStencilTable<OpenSubdiv::Far::StencilTable, OpenSubdiv::Far::StencilTable, OpenSubdiv::Osd::MTLContext>(
@ -145,12 +153,18 @@ using PerFrameBuffer = MTLRingBuffer<DataType, FRAME_LAG>;
id<MTLDepthStencilState> _readWriteDepthStencilState;
id<MTLDepthStencilState> _readOnlyDepthStencilState;
id<MTLBuffer> _faceVaryingDataBuffer;
id<MTLBuffer> _faceVaryingIndicesBuffer;
id<MTLBuffer> _faceVaryingPatchParamBuffer;
Camera _cameraData;
Osd::MTLContext _context;
int _numVertexElements;
int _numVaryingElements;
int _numFaceVaryingElements;
int _numVertices;
int _frameCount;
int _animationFrames;
@ -199,7 +213,6 @@ using PerFrameBuffer = MTLRingBuffer<DataType, FRAME_LAG>;
_context.device = [delegate deviceFor:self];
_context.commandQueue = [delegate commandQueueFor:self];
_osdShaderSource = @(shaderSource);
_needsRebuild = true;
@ -223,6 +236,8 @@ using PerFrameBuffer = MTLRingBuffer<DataType, FRAME_LAG>;
auto p = _vertexData.data();
auto n = _animatedVertices.data();
int numElements = _numVertexElements + _numVaryingElements;
float r = sin(_animationFrames*0.01f) * _animateVertices;
for (int i = 0; i < _numVertices; ++i) {
float move = 0.05f*cosf(p[0]*20+_animationFrames*0.01f);
@ -232,8 +247,12 @@ using PerFrameBuffer = MTLRingBuffer<DataType, FRAME_LAG>;
n[1] = -p[0]*st + p[1]*ct;
n[2] = p[2];
p += _numVertexElements;
n += _numVertexElements;
for (int j = 0; j < _numVaryingElements; ++j) {
n[3 + j] = p[3 + j];
}
p += numElements;
n += numElements;
}
_mesh->UpdateVertexBuffer(_animatedVertices.data(), 0, _numVertices);
@ -283,10 +302,18 @@ using PerFrameBuffer = MTLRingBuffer<DataType, FRAME_LAG>;
auto pav = _mesh->GetPatchTable()->GetPatchArrays();
auto pib = _mesh->GetPatchTable()->GetPatchIndexBuffer();
auto pfvarav = _mesh->GetPatchTable()->GetFVarPatchArrays();
[renderCommandEncoder setVertexBuffer:buffer offset:0 atIndex:VERTEX_BUFFER_INDEX];
[renderCommandEncoder setVertexBuffer:pib offset:0 atIndex:INDICES_BUFFER_INDEX];
[renderCommandEncoder setVertexBuffer:_frameConstantsBuffer offset:0 atIndex:FRAME_CONST_BUFFER_INDEX];
#if FVAR_SINGLE_BUFFER
int faceVaryingDataBufferOffset = _doAdaptive ? 0 : _shape->uvs.size() * sizeof(float);
[renderCommandEncoder setVertexBuffer:_faceVaryingDataBuffer offset:faceVaryingDataBufferOffset atIndex:OSD_FVAR_DATA_BUFFER_INDEX];
#else
[renderCommandEncoder setVertexBuffer:_faceVaryingDataBuffer offset:0 atIndex:OSD_FVAR_DATA_BUFFER_INDEX];
#endif
[renderCommandEncoder setVertexBuffer:_faceVaryingIndicesBuffer offset:0 atIndex:OSD_FVAR_INDICES_BUFFER_INDEX];
if(_doAdaptive)
{
@ -294,6 +321,7 @@ using PerFrameBuffer = MTLRingBuffer<DataType, FRAME_LAG>;
[renderCommandEncoder setVertexBuffer:_perPatchDataBuffer offset:0 atIndex:OSD_PERPATCHVERTEXBEZIER_BUFFER_INDEX];
[renderCommandEncoder setVertexBuffer:_mesh->GetPatchTable()->GetPatchParamBuffer() offset:0 atIndex:OSD_PATCHPARAM_BUFFER_INDEX];
[renderCommandEncoder setVertexBuffer:_perPatchDataBuffer offset:0 atIndex:OSD_PERPATCHVERTEXGREGORY_BUFFER_INDEX];
[renderCommandEncoder setVertexBuffer:_faceVaryingPatchParamBuffer offset:0 atIndex:OSD_FVAR_PATCHPARAM_BUFFER_INDEX];
}
if(_endCapMode == kEndCapLegacyGregory)
@ -323,6 +351,12 @@ using PerFrameBuffer = MTLRingBuffer<DataType, FRAME_LAG>;
if(_doAdaptive)
{
[renderCommandEncoder setVertexBufferOffset:patch.primitiveIdBase * sizeof(int) * 3 atIndex:OSD_PATCHPARAM_BUFFER_INDEX];
auto& fvarPatch = pfvarav[i];
assert(sizeof(Osd::PatchParam) == sizeof(int) * 3);
[renderCommandEncoder setVertexBufferOffset:fvarPatch.primitiveIdBase * sizeof(int) * 3 atIndex:OSD_FVAR_PATCHPARAM_BUFFER_INDEX];
[renderCommandEncoder setVertexBufferOffset:fvarPatch.indexBase * sizeof(unsigned) atIndex:OSD_FVAR_INDICES_BUFFER_INDEX];
}
[renderCommandEncoder setVertexBufferOffset:patch.indexBase * sizeof(unsigned) atIndex:INDICES_BUFFER_INDEX];
@ -569,6 +603,7 @@ using PerFrameBuffer = MTLRingBuffer<DataType, FRAME_LAG>;
break;
case Far::PatchDescriptor::GREGORY_BASIS:
kernelExecutionLimit = patch.GetNumPatches() * 4;
[computeCommandEncoder setBufferOffset:_perPatchDataOffsets[3] atIndex:OSD_PERPATCHVERTEXGREGORY_BUFFER_INDEX];
[computeCommandEncoder setBufferOffset:_tessFactorOffsets[3] atIndex:QUAD_TESSFACTORS_INDEX];
break;
default: assert("Unsupported patch type" && 0); break;
@ -593,7 +628,6 @@ using PerFrameBuffer = MTLRingBuffer<DataType, FRAME_LAG>;
using namespace Sdc;
using namespace Osd;
using namespace Far;
auto shapeDesc = &g_defaultShapes[[_loadedModels indexOfObject:_currentModel]];
_shape.reset(Shape::parseObj(shapeDesc->data.c_str(), shapeDesc->scheme));
const auto scheme = shapeDesc->scheme;
@ -602,9 +636,10 @@ using PerFrameBuffer = MTLRingBuffer<DataType, FRAME_LAG>;
Sdc::SchemeType sdctype = GetSdcType(*_shape);
Sdc::Options sdcoptions = GetSdcOptions(*_shape);
sdcoptions.SetFVarLinearInterpolation((OpenSubdiv::Sdc::Options::FVarLinearInterpolation)_fVarBoundary);
std::unique_ptr<OpenSubdiv::Far::TopologyRefiner> refiner;
refiner.reset(
Far::TopologyRefinerFactory<Shape>::Create(*_shape, Far::TopologyRefinerFactory<Shape>::Options(sdctype, sdcoptions)));
refiner.reset(Far::TopologyRefinerFactory<Shape>::Create(*_shape, Far::TopologyRefinerFactory<Shape>::Options(sdctype, sdcoptions)));
// save coarse topology (used for coarse mesh drawing)
Far::TopologyLevel const & refBaseLevel = refiner->GetLevel(0);
@ -626,22 +661,33 @@ using PerFrameBuffer = MTLRingBuffer<DataType, FRAME_LAG>;
int level = _refinementLevel;
_numVertexElements = 3;
int numVaryingElements = 0;
#if USE_FACE_VARYING
_numFaceVaryingElements = _shape->HasUV() ? 2 : 0;
#else
_numFaceVaryingElements = 0;
#endif
_numVaryingElements = 0;
bits.set(OpenSubdiv::Osd::MeshInterleaveVarying, _numVaryingElements > 0);
bits.set(OpenSubdiv::Osd::MeshFVarData, _numFaceVaryingElements > 0);
bits.set(OpenSubdiv::Osd::MeshFVarAdaptive, _doAdaptive);
int numElements = _numVertexElements + _numVaryingElements;
if(_kernelType == kCPU)
{
_mesh.reset(new CPUMeshType(
refiner.release(),
_mesh.reset(new CPUMeshType(refiner.get(),
_numVertexElements,
numVaryingElements,
_numVaryingElements,
level, bits, nullptr, &_context));
}
else
{
_mesh.reset(new mtlMeshType(
refiner.release(),
_mesh.reset(new mtlMeshType(refiner.get(),
_numVertexElements,
numVaryingElements,
_numVaryingElements,
level, bits, nullptr, &_context));
}
@ -650,7 +696,7 @@ using PerFrameBuffer = MTLRingBuffer<DataType, FRAME_LAG>;
[_delegate setupRenderPipelineState:desc for:self];
const auto vertexDescriptor = desc.vertexDescriptor;
vertexDescriptor.layouts[0].stride = sizeof(float) * _numVertexElements;
vertexDescriptor.layouts[0].stride = sizeof(float) * numElements;
vertexDescriptor.layouts[0].stepFunction = MTLVertexStepFunctionPerVertex;
vertexDescriptor.layouts[0].stepRate = 1;
vertexDescriptor.attributes[0].format = MTLVertexFormatFloat3;
@ -669,51 +715,111 @@ using PerFrameBuffer = MTLRingBuffer<DataType, FRAME_LAG>;
&_context));
}
_vertexData.resize(refBaseLevel.GetNumVertices() * _numVertexElements);
_vertexData.resize(refBaseLevel.GetNumVertices() * numElements);
_meshCenter = simd::float3{0,0,0};
if(_shape->normals.size())
{
for(int i = 0; i < refBaseLevel.GetNumVertices(); i++)
{
_vertexData[i * _numVertexElements + 0] = _shape->verts[i * 3 + 0];
_vertexData[i * _numVertexElements + 1] = _shape->verts[i * 3 + 1];
_vertexData[i * _numVertexElements + 2] = _shape->verts[i * 3 + 2];
_vertexData[i * numElements + 0] = _shape->verts[i * 3 + 0];
_vertexData[i * numElements + 1] = _shape->verts[i * 3 + 1];
_vertexData[i * numElements + 2] = _shape->verts[i * 3 + 2];
}
}
else
{
for(int vertexIdx = 0; vertexIdx < refBaseLevel.GetNumVertices(); vertexIdx++)
{
_vertexData[vertexIdx * _numVertexElements + 0] = _shape->verts[vertexIdx * 3 + 0];
_vertexData[vertexIdx * _numVertexElements + 1] = _shape->verts[vertexIdx * 3 + 1];
_vertexData[vertexIdx * _numVertexElements + 2] = _shape->verts[vertexIdx * 3 + 2];
}
for(auto faceIdx = 0; faceIdx < refBaseLevel.GetNumFaces(); faceIdx++)
{
auto faceIndices = refBaseLevel.GetFaceVertices(faceIdx);
simd::float3 v[4];
for(int faceVert = 0; faceVert < faceIndices.size(); faceVert++)
{
memcpy(v + faceVert, _shape->verts.data() + faceIndices[faceVert] * 3, sizeof(float) * 3);
}
}
}
for(auto vertexIdx = 0; vertexIdx < refBaseLevel.GetNumVertices(); vertexIdx++)
{
_meshCenter[0] += _vertexData[vertexIdx * _numVertexElements + 0];
_meshCenter[1] += _vertexData[vertexIdx * _numVertexElements + 1];
_meshCenter[2] += _vertexData[vertexIdx * _numVertexElements + 2];
_meshCenter[0] += _vertexData[vertexIdx * numElements + 0];
_meshCenter[1] += _vertexData[vertexIdx * numElements + 1];
_meshCenter[2] += _vertexData[vertexIdx * numElements + 2];
}
_meshCenter /= (_shape->verts.size() / 3);
_mesh->UpdateVertexBuffer(_vertexData.data(), 0, refBaseLevel.GetNumVertices());
_mesh->Refine();
_mesh->Synchronize();
if(_numFaceVaryingElements > 0)
{
Far::StencilTableFactory::Options stencilTableFactoryOptions;
stencilTableFactoryOptions.interpolationMode = Far::StencilTableFactory::INTERPOLATE_FACE_VARYING;
stencilTableFactoryOptions.generateOffsets = true;
stencilTableFactoryOptions.generateControlVerts = false;
stencilTableFactoryOptions.generateIntermediateLevels = _doAdaptive;
stencilTableFactoryOptions.factorizeIntermediateLevels = true;
stencilTableFactoryOptions.maxLevel = level;
stencilTableFactoryOptions.fvarChannel = 0;
Far::PatchTable const *farPatchTable = _mesh->GetFarPatchTable();
Far::StencilTable const *stencilTable = Far::StencilTableFactory::Create(*refiner, stencilTableFactoryOptions);
Far::StencilTable const *stencilTableWithLocalPoints = Far::StencilTableFactory::AppendLocalPointStencilTableFaceVarying(*refiner,
stencilTable,
farPatchTable->GetLocalPointFaceVaryingStencilTable(),
0);
if(stencilTableWithLocalPoints) {
delete stencilTable;
stencilTable = stencilTableWithLocalPoints;
}
Osd::MTLStencilTable mtlStencilTable = Osd::MTLStencilTable(stencilTable, &_context);
uint32_t fvarWidth = _numFaceVaryingElements;
uint32_t coarseFVarValuesCount = _shape->uvs.size() / fvarWidth;
uint32_t finalFVarValuesCount = stencilTable->GetNumStencils();
#if FVAR_SINGLE_BUFFER
Osd::CPUMTLVertexBuffer *fvarDataBuffer = Osd::CPUMTLVertexBuffer::Create(fvarWidth, coarseFVarValuesCount + finalFVarValuesCount, &_context);
fvarDataBuffer->UpdateData(_shape->uvs.data(), 0, coarseFVarValuesCount, &_context);
_faceVaryingDataBuffer = fvarDataBuffer->BindMTLBuffer(&_context);
_faceVaryingDataBuffer.label = @"OSD FVar data";
Osd::BufferDescriptor srcDesc(0, fvarWidth, fvarWidth);
Osd::BufferDescriptor dstDesc(coarseFVarValuesCount * fvarWidth, fvarWidth, fvarWidth);
Osd::MTLComputeEvaluator::EvalStencils(fvarDataBuffer, srcDesc,
fvarDataBuffer, dstDesc,
&mtlStencilTable,
nullptr,
&_context);
#else
Osd::CPUMTLVertexBuffer *coarseFVarDataBuffer = Osd::CPUMTLVertexBuffer::Create(fvarWidth, coarseFVarValuesCount, &_context);
coarseFVarDataBuffer->UpdateData(_shape->uvs.data(), 0, coarseFVarValuesCount, &_context);
id<MTLBuffer> mtlCoarseFVarDataBuffer = coarseFVarDataBuffer->BindMTLBuffer(&_context);
mtlCoarseFVarDataBuffer.label = @"OSD FVar coarse data";
Osd::CPUMTLVertexBuffer *refinedFVarDataBuffer = Osd::CPUMTLVertexBuffer::Create(fvarWidth, finalFVarValuesCount, &_context);
_faceVaryingDataBuffer = refinedFVarDataBuffer->BindMTLBuffer(&_context);
_faceVaryingDataBuffer.label = @"OSD FVar data";
Osd::BufferDescriptor coarseBufferDescriptor(0, fvarWidth, fvarWidth);
Osd::BufferDescriptor refinedBufferDescriptor(0, fvarWidth, fvarWidth);
Osd::MTLComputeEvaluator::EvalStencils(coarseFVarDataBuffer, coarseBufferDescriptor,
refinedFVarDataBuffer, refinedBufferDescriptor,
&mtlStencilTable,
nullptr,
&_context);
#endif
Osd::MTLPatchTable const *patchTable = _mesh->GetPatchTable();
_faceVaryingIndicesBuffer = patchTable->GetFVarPatchIndexBuffer(0);
_faceVaryingIndicesBuffer.label = @"OSD FVar indices";
_faceVaryingPatchParamBuffer = patchTable->GetFVarPatchParamBuffer(0);
_faceVaryingPatchParamBuffer.label = @"OSD FVar patch params";
#if FVAR_SINGLE_BUFFER
delete fvarDataBuffer;
#else
delete refinedFVarDataBuffer;
delete coarseFVarDataBuffer;
#endif
delete stencilTable;
}
refiner.release();
}
-(void)_updateState {
@ -771,11 +877,13 @@ using PerFrameBuffer = MTLRingBuffer<DataType, FRAME_LAG>;
}
_tessFactorOffsets[0] = totalPatches * sizeof(MTLQuadTessellationFactorsHalf);
_perPatchDataOffsets[0] = totalPatchDataSize;
float elementFloats = 3;
if(_useSingleCrease)
elementFloats += 6;
totalPatchDataSize += elementFloats * sizeof(float) * patch.GetNumPatches() * patch.desc.GetNumControlVertices();
totalPatchDataSize += elementFloats * sizeof(float) * patch.GetNumPatches() * patch.desc.GetNumControlVertices(); // OsdPerPatchVertexBezier
}
break;
case Far::PatchDescriptor::GREGORY:
@ -785,8 +893,10 @@ using PerFrameBuffer = MTLRingBuffer<DataType, FRAME_LAG>;
}
_tessFactorOffsets[1] = totalPatches * sizeof(MTLQuadTessellationFactorsHalf);
_perPatchDataOffsets[1] = totalPatchDataSize;
totalPatchDataSize += sizeof(float) * 4 * 8 * patch.GetNumPatches() * patch.desc.GetNumControlVertices();
totalPatchDataSize += sizeof(float) * 3 * 5 * patch.GetNumPatches() * patch.desc.GetNumControlVertices();
break;
case Far::PatchDescriptor::GREGORY_BOUNDARY:
if(_usePatchIndexBuffer)
{
@ -794,7 +904,8 @@ using PerFrameBuffer = MTLRingBuffer<DataType, FRAME_LAG>;
}
_tessFactorOffsets[2] = totalPatches * sizeof(MTLQuadTessellationFactorsHalf);
_perPatchDataOffsets[2] = totalPatchDataSize;
totalPatchDataSize += sizeof(float) * 4 * 8 * patch.GetNumPatches() * patch.desc.GetNumControlVertices();
totalPatchDataSize += sizeof(float) * 3 * 5 * patch.GetNumPatches() * patch.desc.GetNumControlVertices();
break;
case Far::PatchDescriptor::GREGORY_BASIS:
if(_usePatchIndexBuffer)
@ -803,7 +914,8 @@ using PerFrameBuffer = MTLRingBuffer<DataType, FRAME_LAG>;
}
_tessFactorOffsets[3] = totalPatches * sizeof(MTLQuadTessellationFactorsHalf);
_perPatchDataOffsets[3] = totalPatchDataSize;
//Improved basis doesn't have per-patch-per-vertex data.
totalPatchDataSize += sizeof(float) * 3 * patch.GetNumPatches() * patch.desc.GetNumControlVertices(); // OsdPerPatchVertexGregory
break;
}
@ -826,13 +938,15 @@ using PerFrameBuffer = MTLRingBuffer<DataType, FRAME_LAG>;
}
Osd::MTLPatchShaderSource shaderSource;
auto& patchArrays = _mesh->GetPatchTable()->GetPatchArrays();
for(auto& patch : patchArrays)
auto patchArrays = _mesh->GetPatchTable()->GetPatchArrays();
auto pFVarArray = _mesh->GetPatchTable()->GetFVarPatchArrays();
for(int i = 0; i < patchArrays.size(); ++i)
{
auto type = patch.GetDescriptor().GetType();
auto type = patchArrays[i].GetDescriptor().GetType();
auto fvarType = pFVarArray[i].GetDescriptor().GetType();
auto& threadsPerThreadgroup = _threadgroupSizes[type];
threadsPerThreadgroup = 32; //Initial guess of 32
int usefulControlPoints = patch.GetDescriptor().GetNumControlVertices();
int usefulControlPoints = patchArrays[i].GetDescriptor().GetNumControlVertices();
auto compileOptions = [[MTLCompileOptions alloc] init];
auto preprocessor = [[NSMutableDictionary alloc] init];
@ -873,6 +987,8 @@ using PerFrameBuffer = MTLRingBuffer<DataType, FRAME_LAG>;
#endif
//Need to define the input vertex struct so that it's available everywhere.
{
shaderBuilder << R"(
#include <metal_stdlib>
using namespace metal;
@ -881,12 +997,17 @@ using PerFrameBuffer = MTLRingBuffer<DataType, FRAME_LAG>;
metal::packed_float3 position;
};
)";
}
shaderBuilder << shaderSource.GetHullShaderSource(type);
shaderBuilder << shaderSource.GetHullShaderSource(type, fvarType);
if(_numFaceVaryingElements > 0)
shaderBuilder << shaderSource.GetPatchBasisShaderSource();
shaderBuilder << _osdShaderSource.UTF8String;
const auto str = shaderBuilder.str();
int numElements = _numVertexElements + _numVaryingElements;
DEFINE(VERTEX_BUFFER_INDEX,VERTEX_BUFFER_INDEX);
DEFINE(PATCH_INDICES_BUFFER_INDEX,PATCH_INDICES_BUFFER_INDEX);
DEFINE(CONTROL_INDICES_BUFFER_INDEX,CONTROL_INDICES_BUFFER_INDEX);
@ -916,14 +1037,17 @@ using PerFrameBuffer = MTLRingBuffer<DataType, FRAME_LAG>;
DEFINE(USE_PTVS_SHARPNESS, 1);
DEFINE(THREADS_PER_THREADGROUP, threadsPerThreadgroup);
DEFINE(CONTROL_POINTS_PER_THREAD, std::max<int>(1, usefulControlPoints / threadsPerThreadgroup));
DEFINE(VERTEX_CONTROL_POINTS_PER_PATCH, patch.desc.GetNumControlVertices());
DEFINE(VERTEX_CONTROL_POINTS_PER_PATCH, patchArrays[i].desc.GetNumControlVertices());
DEFINE(OSD_MAX_VALENCE, _mesh->GetMaxValence());
DEFINE(OSD_NUM_ELEMENTS, _numVertexElements);
DEFINE(OSD_NUM_ELEMENTS, numElements);
DEFINE(OSD_ENABLE_BACKPATCH_CULL, _usePatchBackfaceCulling);
DEFINE(SHADING_TYPE, _shadingMode);
DEFINE(OSD_USE_PATCH_INDEX_BUFFER, _usePatchIndexBuffer);
DEFINE(OSD_ENABLE_SCREENSPACE_TESSELLATION, _useScreenspaceTessellation && _useFractionalTessellation);
DEFINE(OSD_ENABLE_PATCH_CULL, _usePatchClipCulling && _doAdaptive);
DEFINE(OSD_FVAR_DATA_BUFFER_INDEX, OSD_FVAR_DATA_BUFFER_INDEX);
DEFINE(OSD_FVAR_INDICES_BUFFER_INDEX, OSD_FVAR_INDICES_BUFFER_INDEX);
DEFINE(OSD_FVAR_PATCHPARAM_BUFFER_INDEX, OSD_FVAR_PATCHPARAM_BUFFER_INDEX);
compileOptions.preprocessorMacros = preprocessor;
@ -974,7 +1098,7 @@ using PerFrameBuffer = MTLRingBuffer<DataType, FRAME_LAG>;
vertexDesc.layouts[OSD_PATCHPARAM_BUFFER_INDEX].stepRate = 1;
vertexDesc.layouts[OSD_PATCHPARAM_BUFFER_INDEX].stride = sizeof(int) * 3;
// PatchInput :: int3 patchParam [[attribute(10)]];
vertexDesc.attributes[10].bufferIndex = OSD_PATCHPARAM_BUFFER_INDEX;
vertexDesc.attributes[10].format = MTLVertexFormatInt3;
vertexDesc.attributes[10].offset = 0;
@ -987,33 +1111,45 @@ using PerFrameBuffer = MTLRingBuffer<DataType, FRAME_LAG>;
vertexDesc.layouts[OSD_PERPATCHVERTEXBEZIER_BUFFER_INDEX].stepRate = 1;
vertexDesc.layouts[OSD_PERPATCHVERTEXBEZIER_BUFFER_INDEX].stride = sizeof(float) * 3;
// ControlPoint :: float3 P [[attribute(0)]];
// OsdPerPatchVertexBezier :: packed_float3 P
vertexDesc.attributes[0].bufferIndex = OSD_PERPATCHVERTEXBEZIER_BUFFER_INDEX;
vertexDesc.attributes[0].format = MTLVertexFormatFloat3;
vertexDesc.attributes[0].offset = 0;
if(_useSingleCrease)
{
vertexDesc.layouts[OSD_PERPATCHVERTEXBEZIER_BUFFER_INDEX].stride += sizeof(float) * 6;
vertexDesc.layouts[OSD_PERPATCHVERTEXBEZIER_BUFFER_INDEX].stride += sizeof(float) * 3 * 2;
// ControlPoint :: float3 P1 [[attribute(1)]];
// OsdPerPatchVertexBezier :: packed_float3 P1
vertexDesc.attributes[1].bufferIndex = OSD_PERPATCHVERTEXBEZIER_BUFFER_INDEX;
vertexDesc.attributes[1].format = MTLVertexFormatFloat3;
vertexDesc.attributes[1].offset = sizeof(float) * 3;
// ControlPoint :: float3 P2 [[attribute(2)]];
// OsdPerPatchVertexBezier :: packed_float3 P2
vertexDesc.attributes[2].bufferIndex = OSD_PERPATCHVERTEXBEZIER_BUFFER_INDEX;
vertexDesc.attributes[2].format = MTLVertexFormatFloat3;
vertexDesc.attributes[2].offset = sizeof(float) * 6;
// USE_PTVS_SHARPNESS is true and so OsdPerPatchVertexBezier :: float2 vSegments is not used
}
if(_useScreenspaceTessellation)
{
vertexDesc.layouts[OSD_PERPATCHTESSFACTORS_BUFFER_INDEX].stepFunction = MTLVertexStepFunctionPerPatch;
vertexDesc.layouts[OSD_PERPATCHTESSFACTORS_BUFFER_INDEX].stepRate = 1;
vertexDesc.layouts[OSD_PERPATCHTESSFACTORS_BUFFER_INDEX].stride = sizeof(float) * 8;
vertexDesc.layouts[OSD_PERPATCHTESSFACTORS_BUFFER_INDEX].stride = sizeof(float) * 4 * 2;
// PatchInput :: float4 tessOuterLo [[attribute(5)]];
// OsdPerPatchTessFactors :: float4 tessOuterLo;
vertexDesc.attributes[5].bufferIndex = OSD_PERPATCHTESSFACTORS_BUFFER_INDEX;
vertexDesc.attributes[5].format = MTLVertexFormatFloat4;
vertexDesc.attributes[5].offset = 0;
// PatchInput :: float4 tessOuterHi [[attribute(6)]];
// OsdPerPatchTessFactors :: float4 tessOuterHi;
vertexDesc.attributes[6].bufferIndex = OSD_PERPATCHTESSFACTORS_BUFFER_INDEX;
vertexDesc.attributes[6].format = MTLVertexFormatFloat4;
vertexDesc.attributes[6].offset = sizeof(float) * 4;
@ -1026,6 +1162,11 @@ using PerFrameBuffer = MTLRingBuffer<DataType, FRAME_LAG>;
vertexDesc.layouts[OSD_PERPATCHVERTEXGREGORY_BUFFER_INDEX].stepRate = 1;
vertexDesc.layouts[OSD_PERPATCHVERTEXGREGORY_BUFFER_INDEX].stride = sizeof(float) * 3 * 5;
// ControlPoint :: float3 P [[attribute(0)]];
// ControlPoint :: float3 Ep [[attribute(1)]];
// ControlPoint :: float3 Em [[attribute(2)]];
// ControlPoint :: float3 Fp [[attribute(3)]];
// ControlPoint :: float3 Fm [[attribute(4)]];
for(int i = 0; i < 5; i++)
{
vertexDesc.attributes[i].bufferIndex = OSD_PERPATCHVERTEXGREGORY_BUFFER_INDEX;
@ -1038,9 +1179,11 @@ using PerFrameBuffer = MTLRingBuffer<DataType, FRAME_LAG>;
vertexDesc.layouts[VERTEX_BUFFER_INDEX].stepRate = 1;
vertexDesc.layouts[VERTEX_BUFFER_INDEX].stride = sizeof(float) * 3;
// ControlPoint :: float3 position [[attribute(0)]];
vertexDesc.attributes[0].bufferIndex = VERTEX_BUFFER_INDEX;
vertexDesc.attributes[0].format = MTLVertexFormatFloat3;
vertexDesc.attributes[0].offset = 0;
break;
case Far::PatchDescriptor::QUADS:
//Quads cannot use stage in, due to the need for re-indexing.
@ -1212,6 +1355,12 @@ using PerFrameBuffer = MTLRingBuffer<DataType, FRAME_LAG>;
_kernelType = kernelType;
}
-(void)setFVarBoundary:(FVarBoundary)fVarBoundary {
_needsRebuild |= (fVarBoundary != _fVarBoundary);
_fVarBoundary = fVarBoundary;
}
-(void)setCurrentModel:(NSString *)currentModel {
_needsRebuild |= ![currentModel isEqualToString:_currentModel];
_currentModel = currentModel;

View File

@ -39,11 +39,14 @@ namespace OpenSubdiv {
static std::string GetPatchBasisShaderSource();
static std::string GetVertexShaderSource(Far::PatchDescriptor::Type type);
static std::string GetVertexShaderSource(Far::PatchDescriptor::Type type,
Far::PatchDescriptor::Type fvarType);
static std::string GetHullShaderSource(Far::PatchDescriptor::Type type);
static std::string GetHullShaderSource(Far::PatchDescriptor::Type type,
Far::PatchDescriptor::Type fvarType);
static std::string GetDomainShaderSource(Far::PatchDescriptor::Type type);
static std::string GetDomainShaderSource(Far::PatchDescriptor::Type type,
Far::PatchDescriptor::Type fvarType);
};
} // end namespace Osd

View File

@ -50,19 +50,28 @@ namespace OpenSubdiv {
#include "mtlPatchGregoryBasis.gen.h"
);
static std::string GetPatchTypeDefine(Far::PatchDescriptor::Type type) {
static std::string GetPatchTypeDefine(Far::PatchDescriptor::Type type,
Far::PatchDescriptor::Type fvarType) {
std::stringstream ss;
switch(type) {
case Far::PatchDescriptor::LINES: return "#define OSD_PATCH_LINES 1\n";
case Far::PatchDescriptor::TRIANGLES: return "#define OSD_PATCH_TRIANGLES 1\n";
case Far::PatchDescriptor::QUADS: return "#define OSD_PATCH_QUADS 1\n";
case Far::PatchDescriptor::REGULAR: return "#define OSD_PATCH_BSPLINE 1\n#define OSD_PATCH_REGULAR 1\n";
case Far::PatchDescriptor::GREGORY: return "#define OSD_PATCH_GREGORY 1\n";
case Far::PatchDescriptor::GREGORY_BOUNDARY: return "#define OSD_PATCH_GREGORY_BOUNDRY 1\n";
case Far::PatchDescriptor::GREGORY_BASIS: return "#define OSD_PATCH_GREGORY_BASIS 1\n";
case Far::PatchDescriptor::LINES: ss << "#define OSD_PATCH_LINES 1\n"; break;
case Far::PatchDescriptor::TRIANGLES: ss << "#define OSD_PATCH_TRIANGLES 1\n"; break;
case Far::PatchDescriptor::QUADS: ss << "#define OSD_PATCH_QUADS 1\n"; break;
case Far::PatchDescriptor::REGULAR: ss << "#define OSD_PATCH_BSPLINE 1\n#define OSD_PATCH_REGULAR 1\n"; break;
case Far::PatchDescriptor::GREGORY: ss << "#define OSD_PATCH_GREGORY 1\n"; break;
case Far::PatchDescriptor::GREGORY_BOUNDARY: ss << "#define OSD_PATCH_GREGORY_BOUNDRY 1\n"; break;
case Far::PatchDescriptor::GREGORY_BASIS: ss << "#define OSD_PATCH_GREGORY_BASIS 1\n"; break;
default:
assert("Unknown Far::PatchDescriptor::Type" && 0);
return "";
}
switch(fvarType) {
case Far::PatchDescriptor::REGULAR: ss << "#define OSD_FACEVARYING_PATCH_REGULAR 1\n"; break;
case Far::PatchDescriptor::GREGORY_BASIS: ss << "#define OSD_FACEVARYING_PATCH_GREGORY_BASIS 1\n"; break;
default:
return ss.str();
}
return ss.str();
}
static std::string GetPatchTypeSource(Far::PatchDescriptor::Type type) {
@ -102,9 +111,10 @@ namespace OpenSubdiv {
/*static*/
std::string
MTLPatchShaderSource::GetVertexShaderSource(Far::PatchDescriptor::Type type) {
MTLPatchShaderSource::GetVertexShaderSource(Far::PatchDescriptor::Type type,
Far::PatchDescriptor::Type fvarType) {
std::stringstream ss;
ss << GetPatchTypeDefine(type);
ss << GetPatchTypeDefine(type, fvarType);
ss << GetCommonShaderSource();
ss << GetPatchTypeSource(type);
return ss.str();
@ -112,9 +122,10 @@ namespace OpenSubdiv {
/*static*/
std::string
MTLPatchShaderSource::GetHullShaderSource(Far::PatchDescriptor::Type type) {
MTLPatchShaderSource::GetHullShaderSource(Far::PatchDescriptor::Type type,
Far::PatchDescriptor::Type fvarType) {
std::stringstream ss;
ss << GetPatchTypeDefine(type);
ss << GetPatchTypeDefine(type, fvarType);
ss << GetCommonShaderSource();
ss << GetPatchTypeSource(type);
return ss.str();
@ -122,9 +133,10 @@ namespace OpenSubdiv {
/*static*/
std::string
MTLPatchShaderSource::GetDomainShaderSource(Far::PatchDescriptor::Type type) {
MTLPatchShaderSource::GetDomainShaderSource(Far::PatchDescriptor::Type type,
Far::PatchDescriptor::Type fvarType) {
std::stringstream ss;
ss << GetPatchTypeDefine(type);
ss << GetPatchTypeDefine(type, fvarType);
ss << GetCommonShaderSource();
ss << GetPatchTypeSource(type);
return ss.str();