/*virtual*/ void HdSt_Osd3Subdivision::RefineCPU(HdBufferSourceSharedPtr const &source, bool varying, void *vertexBuffer) { OpenSubdiv::Far::StencilTable const *stencilTable = varying ? _varyingStencils : _vertexStencils; if (!TF_VERIFY(stencilTable)) return; OpenSubdiv::Osd::CpuVertexBuffer *osdVertexBuffer = static_cast<OpenSubdiv::Osd::CpuVertexBuffer*>(vertexBuffer); int numElements = source->GetNumElements(); int stride = source->GetNumComponents(); // NOTE: in osd, GetNumElements() returns how many fields in a vertex // (i.e. 3 for XYZ, and 4 for RGBA) // in hydra, GetNumElements() returns how many vertices // (or faces, etc) in a buffer. We basically follow the hydra // convention in this file. TF_VERIFY(stride == osdVertexBuffer->GetNumElements()); // if the mesh has more vertices than that in use in topology (faceIndices), // we need to trim the buffer so that they won't overrun the coarse // vertex buffer which we allocated using the stencil table. // see HdSt_Osd3Subdivision::GetNumVertices() if (numElements > stencilTable->GetNumControlVertices()) { numElements = stencilTable->GetNumControlVertices(); } // filling coarse vertices osdVertexBuffer->UpdateData((const float*)source->GetData(), /*offset=*/0, numElements); // if there is no stencil (e.g. torus with adaptive refinement), // just return here if (stencilTable->GetNumStencils() == 0) return; // apply opensubdiv with CPU evaluator. OpenSubdiv::Osd::BufferDescriptor srcDesc(0, stride, stride); OpenSubdiv::Osd::BufferDescriptor dstDesc(numElements*stride, stride, stride); OpenSubdiv::Osd::CpuEvaluator::EvalStencils( osdVertexBuffer, srcDesc, osdVertexBuffer, dstDesc, stencilTable); }
HdBufferSourceSharedPtr _TriangulateFaceVarying(HdBufferSourceSharedPtr const &source, VtIntArray const &faceVertexCounts, VtIntArray const &holeFaces, bool flip, SdfPath const &id) { T const *srcPtr = reinterpret_cast<T const *>(source->GetData()); int numElements = source->GetNumElements(); // CPU face-varying triangulation bool invalidTopology = false; int numFVarValues = 0; int holeIndex = 0; int numHoleFaces = holeFaces.size(); for (int i = 0; i < faceVertexCounts.size(); ++i) { int nv = faceVertexCounts[i] - 2; if (nv < 1) { // skip degenerated face invalidTopology = true; } else if (holeIndex < numHoleFaces and holeFaces[holeIndex] == i) { // skip hole face ++holeIndex; } else { numFVarValues += 3 * nv; } } if (invalidTopology) { TF_WARN("degenerated face found [%s]", id.GetText()); invalidTopology = false; } VtArray<T> results(numFVarValues); // reset holeIndex holeIndex = 0; int dstIndex = 0; for (int i = 0, v = 0; i < faceVertexCounts.size(); ++i) { int nVerts = faceVertexCounts[i]; if (nVerts < 3) { // Skip degenerate faces. } else if (holeIndex < numHoleFaces and holeFaces[holeIndex] == i) { // Skip hole faces. ++holeIndex; } else { // triangulate. // apply same triangulation as index does for (int j=0; j < nVerts-2; ++j) { if (not _FanTriangulate(&results[dstIndex], srcPtr, v, j, numElements, flip)) { invalidTopology = true; } dstIndex += 3; } } v += nVerts; } if (invalidTopology) { TF_WARN("numVerts and verts are incosistent [%s]", id.GetText()); } return HdBufferSourceSharedPtr(new HdVtBufferSource( source->GetName(), VtValue(results))); }
void HdStExtComputation::Sync(HdSceneDelegate *sceneDelegate, HdRenderParam *renderParam, HdDirtyBits *dirtyBits) { HD_TRACE_FUNCTION(); HF_MALLOC_TAG_FUNCTION(); TF_DEBUG(HD_EXT_COMPUTATION_UPDATED).Msg( "HdStExtComputation::Sync %s\n", GetId().GetText()); HdExtComputation::_Sync(sceneDelegate, renderParam, dirtyBits); // We only commit GPU resources when directly executing a GPU computation // or when aggregating inputs for a downstream computation. if (GetGpuKernelSource().empty() && !IsInputAggregation()) { return; } HdRenderIndex &renderIndex = sceneDelegate->GetRenderIndex(); HdStResourceRegistrySharedPtr const & resourceRegistry = boost::dynamic_pointer_cast<HdStResourceRegistry>( renderIndex.GetResourceRegistry()); HdBufferSourceVector inputs; for (TfToken const & inputName: GetSceneInputNames()) { VtValue inputValue = sceneDelegate->GetExtComputationInput( GetId(), inputName); size_t arraySize = inputValue.IsArrayValued() ? inputValue.GetArraySize() : 1; HdBufferSourceSharedPtr inputSource = HdBufferSourceSharedPtr( new HdVtBufferSource(inputName, inputValue, arraySize)); if (inputSource->IsValid()) { inputs.push_back(inputSource); } else { TF_WARN("Unsupported type %s for source %s in extComputation %s.", inputValue.GetType().GetTypeName().c_str(), inputName.GetText(), GetId().GetText()); } } _inputRange.reset(); if (!inputs.empty()) { if (_IsEnabledSharedExtComputationData() && IsInputAggregation()) { uint64_t inputId = _ComputeSharedComputationInputId(0, inputs); HdInstance<uint64_t, HdBufferArrayRangeSharedPtr> barInstance; std::unique_lock<std::mutex> regLog = resourceRegistry->RegisterExtComputationDataRange(inputId, &barInstance); if (barInstance.IsFirstInstance()) { // Allocate the first buffer range for this input key _inputRange = _AllocateComputationDataRange(inputs, resourceRegistry); barInstance.SetValue(_inputRange); TF_DEBUG(HD_SHARED_EXT_COMPUTATION_DATA).Msg( "Allocated shared ExtComputation buffer range: %s: %p\n", GetId().GetText(), (void *)_inputRange.get()); } else { // Share the existing buffer range for this input key _inputRange = barInstance.GetValue(); TF_DEBUG(HD_SHARED_EXT_COMPUTATION_DATA).Msg( "Reused shared ExtComputation buffer range: %s: %p\n", GetId().GetText(), (void *)_inputRange.get()); } } else { // We're not sharing, so go ahead and allocate new buffer range. _inputRange = _AllocateComputationDataRange(inputs, resourceRegistry); } // Make sure that we also release any stale input range data renderIndex.GetChangeTracker().SetGarbageCollectionNeeded(); } }