From bdca520459e417ec15b802dacdee8715f6b1c04f Mon Sep 17 00:00:00 2001 From: Nicholas Blasingame Date: Mon, 5 Jun 2017 15:06:47 -0700 Subject: [PATCH] Added fvar support for metla as well as a ui for fvar. --- examples/mtlViewer/OSX/ViewController.mm | 47 +++- examples/mtlViewer/mtlViewer.h | 13 +- examples/mtlViewer/mtlViewer.metal | 77 +++++- examples/mtlViewer/mtlViewer.mm | 299 +++++++++++++++++------ opensubdiv/osd/mtlPatchShaderSource.h | 9 +- opensubdiv/osd/mtlPatchShaderSource.mm | 40 +-- 6 files changed, 376 insertions(+), 109 deletions(-) diff --git a/examples/mtlViewer/OSX/ViewController.mm b/examples/mtlViewer/OSX/ViewController.mm index 890488d0..4ec786c5 100644 --- a/examples/mtlViewer/OSX/ViewController.mm +++ b/examples/mtlViewer/OSX/ViewController.mm @@ -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: @@ -224,13 +236,14 @@ enum { assert("Unknown displayStyle" && 0); } }; - + auto callbackShadingMode = [=](int shadingMode) { switch((ShadingMode)shadingMode) { case kShadingNormal: 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); - - int compute_pulldown = hud.AddPullDown("Compute (K)", 475, 10, 300, callbackKernel, 'k'); + hud.AddPullDownButton(shading_pulldown, "Face Varying", + kShadingFaceVarying, + _osdRenderer.shadingMode == kShadingFaceVarying); + + 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, '`'); diff --git a/examples/mtlViewer/mtlViewer.h b/examples/mtlViewer/mtlViewer.h index 8ed6c196..5069f1c5 100644 --- a/examples/mtlViewer/mtlViewer.h +++ b/examples/mtlViewer/mtlViewer.h @@ -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 diff --git a/examples/mtlViewer/mtlViewer.metal b/examples/mtlViewer/mtlViewer.metal index 85d1eaf9..76a6f5d5 100644 --- a/examples/mtlViewer/mtlViewer.metal +++ b/examples/mtlViewer/mtlViewer.metal @@ -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 Far::StencilTable const * Osd::convertToCompatibleStencilTable( @@ -145,12 +153,18 @@ using PerFrameBuffer = MTLRingBuffer; id _readWriteDepthStencilState; id _readOnlyDepthStencilState; + id _faceVaryingDataBuffer; + id _faceVaryingIndicesBuffer; + id _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; _context.device = [delegate deviceFor:self]; _context.commandQueue = [delegate commandQueueFor:self]; - _osdShaderSource = @(shaderSource); _needsRebuild = true; @@ -216,13 +229,15 @@ using PerFrameBuffer = MTLRingBuffer; if(_needsRebuild) { [self _rebuildState]; } - + if(!_freeze) { if(_animateVertices) { _animatedVertices.resize(_vertexData.size()); 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; 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; 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: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; [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; 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]; @@ -367,7 +401,7 @@ using PerFrameBuffer = MTLRingBuffer; if(_displayStyle == kDisplayStyleWireOnShaded) { - simd::float4 shade = {1, 1,1,1}; + simd::float4 shade = {1,1,1,1}; [renderCommandEncoder setFragmentBytes:&shade length:sizeof(shade) atIndex:2]; [renderCommandEncoder setTriangleFillMode:MTLTriangleFillModeLines]; [renderCommandEncoder setDepthBias:-5 slopeScale:-1.0 clamp:-100.0]; @@ -440,7 +474,7 @@ using PerFrameBuffer = MTLRingBuffer; [renderCommandEncoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:patch.GetNumPatches() * 6]; if(_displayStyle == kDisplayStyleWireOnShaded) { - simd::float4 shade = {1, 1,1,1}; + simd::float4 shade = {1,1,1,1}; [renderCommandEncoder setFragmentBytes:&shade length:sizeof(shade) atIndex:2]; [renderCommandEncoder setTriangleFillMode:MTLTriangleFillModeLines]; [renderCommandEncoder setDepthBias:-5 slopeScale:-1.0 clamp:-100.0]; @@ -453,7 +487,7 @@ using PerFrameBuffer = MTLRingBuffer; [renderCommandEncoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:patch.GetNumPatches() * d.GetNumControlVertices()]; if(_displayStyle == kDisplayStyleWireOnShaded) { - simd::float4 shade = {1, 1,1,1}; + simd::float4 shade = {1,1,1,1}; [renderCommandEncoder setFragmentBytes:&shade length:sizeof(shade) atIndex:2]; [renderCommandEncoder setTriangleFillMode:MTLTriangleFillModeLines]; [renderCommandEncoder setDepthBias:-5 slopeScale:-1.0 clamp:-100.0]; @@ -569,6 +603,7 @@ using PerFrameBuffer = MTLRingBuffer; 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; 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; @@ -601,10 +635,11 @@ using PerFrameBuffer = MTLRingBuffer; // create Far mesh (topology) Sdc::SchemeType sdctype = GetSdcType(*_shape); Sdc::Options sdcoptions = GetSdcOptions(*_shape); - + + sdcoptions.SetFVarLinearInterpolation((OpenSubdiv::Sdc::Options::FVarLinearInterpolation)_fVarBoundary); + std::unique_ptr refiner; - refiner.reset( - Far::TopologyRefinerFactory::Create(*_shape, Far::TopologyRefinerFactory::Options(sdctype, sdcoptions))); + refiner.reset(Far::TopologyRefinerFactory::Create(*_shape, Far::TopologyRefinerFactory::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; 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; [_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; &_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++) { - 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 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; } _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; } _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; } _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; } _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; } 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,20 +987,27 @@ using PerFrameBuffer = MTLRingBuffer; #endif //Need to define the input vertex struct so that it's available everywhere. - shaderBuilder << R"( - #include - using namespace metal; + + { + shaderBuilder << R"( + #include + using namespace metal; + + struct OsdInputVertexType { + metal::packed_float3 position; + }; + )"; + } - struct OsdInputVertexType { - 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,15 +1037,18 @@ using PerFrameBuffer = MTLRingBuffer; DEFINE(USE_PTVS_SHARPNESS, 1); DEFINE(THREADS_PER_THREADGROUP, threadsPerThreadgroup); DEFINE(CONTROL_POINTS_PER_THREAD, std::max(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; NSError* err = nil; @@ -974,7 +1098,7 @@ using PerFrameBuffer = MTLRingBuffer; 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; 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; 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; 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; _kernelType = kernelType; } + +-(void)setFVarBoundary:(FVarBoundary)fVarBoundary { + _needsRebuild |= (fVarBoundary != _fVarBoundary); + _fVarBoundary = fVarBoundary; +} + -(void)setCurrentModel:(NSString *)currentModel { _needsRebuild |= ![currentModel isEqualToString:_currentModel]; _currentModel = currentModel; diff --git a/opensubdiv/osd/mtlPatchShaderSource.h b/opensubdiv/osd/mtlPatchShaderSource.h index cdcea597..d4e0bf4c 100644 --- a/opensubdiv/osd/mtlPatchShaderSource.h +++ b/opensubdiv/osd/mtlPatchShaderSource.h @@ -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 diff --git a/opensubdiv/osd/mtlPatchShaderSource.mm b/opensubdiv/osd/mtlPatchShaderSource.mm index 4cf9763a..a537b442 100644 --- a/opensubdiv/osd/mtlPatchShaderSource.mm +++ b/opensubdiv/osd/mtlPatchShaderSource.mm @@ -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();