void HdPoints::_PopulateVertexPrimVars(HdDrawItem *drawItem, HdChangeTracker::DirtyBits *dirtyBits) { HD_TRACE_FUNCTION(); HD_MALLOC_TAG_FUNCTION(); SdfPath const& id = GetId(); HdSceneDelegate* delegate = GetDelegate(); HdResourceRegistry *resourceRegistry = &HdResourceRegistry::GetInstance(); // The "points" attribute is expected to be in this list. TfTokenVector primVarNames = delegate->GetPrimVarVertexNames(id); TfTokenVector const& vars = delegate->GetPrimVarVaryingNames(id); primVarNames.insert(primVarNames.end(), vars.begin(), vars.end()); HdBufferSourceVector sources; sources.reserve(primVarNames.size()); int pointsIndexInSourceArray = -1; TF_FOR_ALL(nameIt, primVarNames) { if (not HdChangeTracker::IsPrimVarDirty(*dirtyBits, id, *nameIt)) continue; // TODO: We don't need to pull primvar metadata every time a value // changes, but we need support from the delegate. //assert name not in range.bufferArray.GetResources() VtValue value = delegate->Get(id, *nameIt); if (!value.IsEmpty()) { // Store where the points will be stored in the source array // we need this later to figure out if the number of points is changing // and we need to force a garbage collection to resize the buffer if (*nameIt == HdTokens->points) { pointsIndexInSourceArray = sources.size(); } // XXX: do we need special treatment for width as basicCurves? HdBufferSourceSharedPtr source(new HdVtBufferSource(*nameIt, value)); sources.push_back(source); } } // return before allocation if it's empty. if (sources.empty()) return; if (not drawItem->GetVertexPrimVarRange() or not drawItem->GetVertexPrimVarRange()->IsValid()) { // initialize buffer array HdBufferSpecVector bufferSpecs; TF_FOR_ALL(it, sources) { (*it)->AddBufferSpecs(&bufferSpecs); }
void HdRprim::_PopulateConstantPrimVars(HdSceneDelegate* delegate, HdDrawItem *drawItem, HdDirtyBits *dirtyBits) { HD_TRACE_FUNCTION(); HF_MALLOC_TAG_FUNCTION(); SdfPath const& id = GetId(); HdRenderIndex &renderIndex = delegate->GetRenderIndex(); HdResourceRegistry *resourceRegistry = &HdResourceRegistry::GetInstance(); // XXX: this should be in a different method // XXX: This should be in HdSt getting the HdSt Shader const HdShader *shader = static_cast<const HdShader *>( renderIndex.GetSprim(HdPrimTypeTokens->shader, _surfaceShaderID)); if (shader == nullptr) { shader = static_cast<const HdShader *>( renderIndex.GetFallbackSprim(HdPrimTypeTokens->shader)); } _sharedData.surfaceShader = shader->GetShaderCode(); // update uniforms HdBufferSourceVector sources; if (HdChangeTracker::IsTransformDirty(*dirtyBits, id)) { GfMatrix4d transform = delegate->GetTransform(id); _sharedData.bounds.SetMatrix(transform); // for CPU frustum culling HdBufferSourceSharedPtr source(new HdVtBufferSource( HdTokens->transform, transform)); sources.push_back(source); source.reset(new HdVtBufferSource(HdTokens->transformInverse, transform.GetInverse())); sources.push_back(source); // if this is a prototype (has instancer), // also push the instancer transform separately. if (!_instancerID.IsEmpty()) { // gather all instancer transforms in the instancing hierarchy VtMatrix4dArray rootTransforms = _GetInstancerTransforms(delegate); VtMatrix4dArray rootInverseTransforms(rootTransforms.size()); bool leftHanded = transform.IsLeftHanded(); for (size_t i = 0; i < rootTransforms.size(); ++i) { rootInverseTransforms[i] = rootTransforms[i].GetInverse(); // flip the handedness if necessary leftHanded ^= rootTransforms[i].IsLeftHanded(); } source.reset(new HdVtBufferSource( HdTokens->instancerTransform, rootTransforms, /*staticArray=*/true)); sources.push_back(source); source.reset(new HdVtBufferSource( HdTokens->instancerTransformInverse, rootInverseTransforms, /*staticArray=*/true)); sources.push_back(source); // XXX: It might be worth to consider to have isFlipped // for non-instanced prims as well. It can improve // the drawing performance on older-GPUs by reducing // fragment shader cost, although it needs more GPU memory. // set as int (GLSL needs 32-bit align for bool) source.reset(new HdVtBufferSource( HdTokens->isFlipped, VtValue(int(leftHanded)))); sources.push_back(source); } } if (HdChangeTracker::IsExtentDirty(*dirtyBits, id)) { _sharedData.bounds.SetRange(GetExtent(delegate)); GfVec3d const & localMin = drawItem->GetBounds().GetBox().GetMin(); HdBufferSourceSharedPtr sourceMin(new HdVtBufferSource( HdTokens->bboxLocalMin, VtValue(GfVec4f( localMin[0], localMin[1], localMin[2], 0)))); sources.push_back(sourceMin); GfVec3d const & localMax = drawItem->GetBounds().GetBox().GetMax(); HdBufferSourceSharedPtr sourceMax(new HdVtBufferSource( HdTokens->bboxLocalMax, VtValue(GfVec4f( localMax[0], localMax[1], localMax[2], 0)))); sources.push_back(sourceMax); } if (HdChangeTracker::IsPrimIdDirty(*dirtyBits, id)) { GfVec4f primIdColor; int32_t primId = GetPrimId(); HdBufferSourceSharedPtr source(new HdVtBufferSource( HdTokens->primID, VtValue(primId))); sources.push_back(source); } if (HdChangeTracker::IsAnyPrimVarDirty(*dirtyBits, id)) { TfTokenVector primVarNames = delegate->GetPrimVarConstantNames(id); sources.reserve(sources.size()+primVarNames.size()); TF_FOR_ALL(nameIt, primVarNames) { if (HdChangeTracker::IsPrimVarDirty(*dirtyBits, id, *nameIt)) { VtValue value = delegate->Get(id, *nameIt); // XXX Hydra doesn't support string primvar yet if (value.IsHolding<std::string>()) continue; if (!value.IsEmpty()) { HdBufferSourceSharedPtr source( new HdVtBufferSource(*nameIt, value)); // if it's an unacceptable type, skip it (e.g. std::string) if (source->GetNumComponents() > 0) { sources.push_back(source); } } } } }
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(); } }
void HdSurfaceShader::Sync() { HD_TRACE_FUNCTION(); HD_MALLOC_TAG_FUNCTION(); // _delegate might be null in certain conditions including when // Hydra is using a fallback surface shader if (not _delegate) { return; } SdfPath const& id = GetID(); HdSceneDelegate* delegate = GetDelegate(); HdResourceRegistry *resourceRegistry = &HdResourceRegistry::GetInstance(); HdChangeTracker& changeTracker = delegate->GetRenderIndex().GetChangeTracker(); HdChangeTracker::DirtyBits bits = changeTracker.GetShaderDirtyBits(id); if(bits & HdChangeTracker::DirtySurfaceShader) { _fragmentSource = delegate->GetSurfaceShaderSource(id); _geometrySource = delegate->GetDisplacementShaderSource(id); // XXX Forcing collections to be dirty to reload everything // Something more efficient can be done here changeTracker.MarkAllCollectionsDirty(); } if(bits & HdChangeTracker::DirtyParams) { HdBufferSourceVector sources; TextureDescriptorVector textures; _params = delegate->GetSurfaceShaderParams(id); TF_FOR_ALL(paramIt, _params) { if (paramIt->IsPrimvar()) { // skip -- maybe not necessary, but more memory efficient continue; } else if (paramIt->IsFallback()) { HdBufferSourceSharedPtr source(new HdVtBufferSource( paramIt->GetName(), delegate->GetSurfaceShaderParamValue(id, paramIt->GetName()))); sources.push_back(source); } else if (paramIt->IsTexture()) { bool bindless = HdRenderContextCaps::GetInstance() .bindlessTextureEnabled; // register bindless handle HdTextureResource::ID texID = delegate->GetTextureResourceID(paramIt->GetConnection()); HdTextureResourceSharedPtr texResource; { HdInstance<HdTextureResource::ID, HdTextureResourceSharedPtr> texInstance; std::unique_lock<std::mutex> regLock = resourceRegistry->RegisterTextureResource(texID, &texInstance); if (not TF_VERIFY(not texInstance.IsFirstInstance(), "%s", paramIt->GetConnection().GetText())) { continue; } texResource = texInstance.GetValue(); if (not TF_VERIFY(texResource)) { continue; } } TextureDescriptor tex; tex.name = paramIt->GetName(); if (texResource->IsPtex()) { tex.type = TextureDescriptor::TEXTURE_PTEX_TEXEL; tex.handle = bindless ? texResource->GetTexelsTextureHandle() : texResource->GetTexelsTextureId(); textures.push_back(tex); if (bindless) { HdBufferSourceSharedPtr source(new Hd_BindlessSamplerBufferSource( tex.name, GL_SAMPLER_2D_ARRAY, tex.handle)); sources.push_back(source); } // layout tex.name = TfToken(std::string(paramIt->GetName().GetText()) + "_layout"); tex.type = TextureDescriptor::TEXTURE_PTEX_LAYOUT; tex.handle = bindless ? texResource->GetLayoutTextureHandle() : texResource->GetLayoutTextureId(); textures.push_back(tex); if (bindless) { HdBufferSourceSharedPtr source(new Hd_BindlessSamplerBufferSource( tex.name, GL_INT_SAMPLER_BUFFER, tex.handle)); sources.push_back(source); } } else { tex.type = TextureDescriptor::TEXTURE_2D; tex.handle = bindless ? texResource->GetTexelsTextureHandle() : texResource->GetTexelsTextureId(); tex.sampler = texResource->GetTexelsSamplerId(); textures.push_back(tex); if (bindless) { HdBufferSourceSharedPtr source(new Hd_BindlessSamplerBufferSource( tex.name, GL_SAMPLER_2D, tex.handle)); sources.push_back(source); } } } } _textureDescriptors = textures; // return before allocation if it's empty. if (sources.empty()) return; // Allocate a new uniform buffer if not exists. if (not _paramArray) { // establish a buffer range HdBufferSpecVector bufferSpecs; TF_FOR_ALL(srcIt, sources) { (*srcIt)->AddBufferSpecs(&bufferSpecs); }