Ensure re-used handles in descriptor sets don't cause problems

* Previously if a handle was reused, and then a stale descriptor referencing the
  old handle was removed it would remove the *new* object from the list of
  referenced resources. This could cause a resource to be not included in a
  capture if nothing else added a new reference.
This commit is contained in:
baldurk
2019-12-12 15:14:28 +00:00
parent 6581251ec0
commit 0773f13949
15 changed files with 307 additions and 185 deletions
+45 -40
View File
@@ -921,23 +921,40 @@ bool IsValid(const VkWriteDescriptorSet &write, uint32_t arrayElement)
return false;
}
void DescriptorSetBindingElement::RemoveBindRefs(VkResourceRecord *record)
void DescriptorSetSlotBufferInfo::SetFrom(const VkDescriptorBufferInfo &bufInfo)
{
buffer = GetResID(bufInfo.buffer);
offset = bufInfo.offset;
range = bufInfo.range;
}
void DescriptorSetSlotImageInfo::SetFrom(const VkDescriptorImageInfo &imInfo, bool setSampler,
bool setImageView)
{
if(setSampler)
sampler = GetResID(imInfo.sampler);
if(setImageView)
imageView = GetResID(imInfo.imageView);
imageLayout = imInfo.imageLayout;
}
void DescriptorSetSlot::RemoveBindRefs(VulkanResourceManager *rm, VkResourceRecord *record)
{
SCOPED_LOCK(record->descInfo->refLock);
if(texelBufferView != VK_NULL_HANDLE)
if(texelBufferView != ResourceId())
{
record->RemoveBindFrameRef(GetResID(texelBufferView));
record->RemoveBindFrameRef(texelBufferView);
VkResourceRecord *viewRecord = GetRecord(texelBufferView);
VkResourceRecord *viewRecord = rm->GetResourceRecord(texelBufferView);
if(viewRecord && viewRecord->baseResource != ResourceId())
record->RemoveBindFrameRef(viewRecord->baseResource);
}
if(imageInfo.imageView != VK_NULL_HANDLE)
if(imageInfo.imageView != ResourceId())
{
record->RemoveBindFrameRef(GetResID(imageInfo.imageView));
record->RemoveBindFrameRef(imageInfo.imageView);
VkResourceRecord *viewRecord = GetRecord(imageInfo.imageView);
VkResourceRecord *viewRecord = rm->GetResourceRecord(imageInfo.imageView);
if(viewRecord)
{
record->RemoveBindFrameRef(viewRecord->baseResource);
@@ -945,34 +962,35 @@ void DescriptorSetBindingElement::RemoveBindRefs(VkResourceRecord *record)
record->RemoveBindFrameRef(viewRecord->baseResourceMem);
}
}
if(imageInfo.sampler != VK_NULL_HANDLE)
if(imageInfo.sampler != ResourceId())
{
record->RemoveBindFrameRef(GetResID(imageInfo.sampler));
record->RemoveBindFrameRef(imageInfo.sampler);
}
if(bufferInfo.buffer != VK_NULL_HANDLE)
if(bufferInfo.buffer != ResourceId())
{
record->RemoveBindFrameRef(GetResID(bufferInfo.buffer));
record->RemoveBindFrameRef(bufferInfo.buffer);
VkResourceRecord *bufRecord = GetRecord(bufferInfo.buffer);
VkResourceRecord *bufRecord = rm->GetResourceRecord(bufferInfo.buffer);
if(bufRecord && bufRecord->baseResource != ResourceId())
record->RemoveBindFrameRef(bufRecord->baseResource);
}
// NULL everything out now so that we don't accidentally reference an object
// that was removed already
texelBufferView = VK_NULL_HANDLE;
bufferInfo.buffer = VK_NULL_HANDLE;
imageInfo.imageView = VK_NULL_HANDLE;
imageInfo.sampler = VK_NULL_HANDLE;
texelBufferView = ResourceId();
bufferInfo.buffer = ResourceId();
imageInfo.imageView = ResourceId();
imageInfo.sampler = ResourceId();
}
void DescriptorSetBindingElement::AddBindRefs(VkResourceRecord *record, FrameRefType ref)
void DescriptorSetSlot::AddBindRefs(VulkanResourceManager *rm, VkResourceRecord *record,
FrameRefType ref)
{
SCOPED_LOCK(record->descInfo->refLock);
if(texelBufferView != VK_NULL_HANDLE)
if(texelBufferView != ResourceId())
{
VkResourceRecord *bufView = GetRecord(texelBufferView);
VkResourceRecord *bufView = rm->GetResourceRecord(texelBufferView);
record->AddBindFrameRef(bufView->GetResourceID(), eFrameRef_Read,
bufView->resInfo && bufView->resInfo->IsSparse());
if(bufView->baseResource != ResourceId())
@@ -980,34 +998,21 @@ void DescriptorSetBindingElement::AddBindRefs(VkResourceRecord *record, FrameRef
if(bufView->baseResourceMem != ResourceId())
record->AddMemFrameRef(bufView->baseResourceMem, bufView->memOffset, bufView->memSize, ref);
}
if(imageInfo.imageView != VK_NULL_HANDLE)
if(imageInfo.imageView != ResourceId())
{
VkResourceRecord *view = GetRecord(imageInfo.imageView);
VkResourceRecord *view = rm->GetResourceRecord(imageInfo.imageView);
record->AddImgFrameRef(view, ref);
}
if(imageInfo.sampler != VK_NULL_HANDLE)
if(imageInfo.sampler != ResourceId())
{
record->AddBindFrameRef(GetResID(imageInfo.sampler), eFrameRef_Read);
record->AddBindFrameRef(imageInfo.sampler, eFrameRef_Read);
}
if(bufferInfo.buffer != VK_NULL_HANDLE)
if(bufferInfo.buffer != ResourceId())
{
VkResourceRecord *buf = GetRecord(bufferInfo.buffer);
record->AddBindFrameRef(GetResID(bufferInfo.buffer), eFrameRef_Read,
VkResourceRecord *buf = rm->GetResourceRecord(bufferInfo.buffer);
record->AddBindFrameRef(bufferInfo.buffer, eFrameRef_Read,
buf->resInfo && buf->resInfo->IsSparse());
if(buf->baseResource != ResourceId())
record->AddMemFrameRef(buf->baseResource, buf->memOffset, buf->memSize, ref);
}
}
void DescriptorSetSlot::CreateFrom(const DescriptorSetBindingElement &slot)
{
bufferInfo.buffer = GetResID(slot.bufferInfo.buffer);
bufferInfo.offset = slot.bufferInfo.offset;
bufferInfo.range = slot.bufferInfo.range;
imageInfo.sampler = GetResID(slot.imageInfo.sampler);
imageInfo.imageView = GetResID(slot.imageInfo.imageView);
imageInfo.imageLayout = slot.imageInfo.imageLayout;
texelBufferView = GetResID(slot.texelBufferView);
}
}
+10 -17
View File
@@ -392,27 +392,17 @@ struct MemoryAllocation
#define IsReplayingAndReading() (ser.IsReading() && IsReplayMode(m_State))
struct VkResourceRecord;
class VulkanResourceManager;
FrameRefType GetRefType(VkDescriptorType descType);
// the possible contents of a descriptor set slot,
// taken from the VkWriteDescriptorSet
struct DescriptorSetBindingElement
{
VkDescriptorBufferInfo bufferInfo;
VkDescriptorImageInfo imageInfo;
VkBufferView texelBufferView;
void RemoveBindRefs(VkResourceRecord *record);
void AddBindRefs(VkResourceRecord *record, FrameRefType ref);
};
// serialisable snapshot of descriptor set slots. Needed because if we snapshot
// DescriptorSetBindingElement
// the VkBuffer or VkImageView handles may have been deleted and recreated by the time we fetch
// their ResourceId
// tracking for descriptor set slots. Needed because if we use something without IDs for tracking
// binding elements the handles may be deleted and recreated, and stale bindings could interfere
// with new bindings
struct DescriptorSetSlotBufferInfo
{
void SetFrom(const VkDescriptorBufferInfo &bufInfo);
ResourceId buffer;
VkDeviceSize offset;
VkDeviceSize range;
@@ -420,6 +410,8 @@ struct DescriptorSetSlotBufferInfo
struct DescriptorSetSlotImageInfo
{
void SetFrom(const VkDescriptorImageInfo &imInfo, bool setSampler, bool setImageView);
ResourceId sampler;
ResourceId imageView;
VkImageLayout imageLayout;
@@ -427,7 +419,8 @@ struct DescriptorSetSlotImageInfo
struct DescriptorSetSlot
{
void CreateFrom(const DescriptorSetBindingElement &slot);
void RemoveBindRefs(VulkanResourceManager *rm, VkResourceRecord *record);
void AddBindRefs(VulkanResourceManager *rm, VkResourceRecord *record, FrameRefType ref);
// VkDescriptorBufferInfo
DescriptorSetSlotBufferInfo bufferInfo;
+7 -7
View File
@@ -3794,7 +3794,7 @@ void WrappedVulkan::AddUsage(VulkanDrawcallTreeNode &drawNode,
for(uint32_t a = 0; a < layout.bindings[bind].descriptorCount; a++)
{
DescriptorSetBindingElement &slot = descset.currentBindings[bind][a];
DescriptorSetSlot &slot = descset.currentBindings[bind][a];
ResourceId id;
@@ -3803,20 +3803,20 @@ void WrappedVulkan::AddUsage(VulkanDrawcallTreeNode &drawNode,
case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
if(slot.imageInfo.imageView != VK_NULL_HANDLE)
id = c.m_ImageView[GetResID(slot.imageInfo.imageView)].image;
if(slot.imageInfo.imageView != ResourceId())
id = c.m_ImageView[slot.imageInfo.imageView].image;
break;
case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
if(slot.texelBufferView != VK_NULL_HANDLE)
id = c.m_BufferView[GetResID(slot.texelBufferView)].buffer;
if(slot.texelBufferView != ResourceId())
id = c.m_BufferView[slot.texelBufferView].buffer;
break;
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
if(slot.bufferInfo.buffer != VK_NULL_HANDLE)
id = GetResID(slot.bufferInfo.buffer);
if(slot.bufferInfo.buffer != ResourceId())
id = slot.bufferInfo.buffer;
break;
default: RDCERR("Unexpected type %d", layout.bindings[bind].descriptorType); break;
}
+1 -1
View File
@@ -697,7 +697,7 @@ private:
DescriptorSetInfo &operator=(const DescriptorSetInfo &) = default;
~DescriptorSetInfo() { clear(); }
ResourceId layout;
std::vector<DescriptorSetBindingElement *> currentBindings;
std::vector<DescriptorSetSlot *> currentBindings;
bool push;
void clear()
+7 -8
View File
@@ -127,18 +127,18 @@ void DescSetLayout::Init(VulkanResourceManager *resourceMan, VulkanCreationInfo
}
}
void DescSetLayout::CreateBindingsArray(std::vector<DescriptorSetBindingElement *> &descBindings) const
void DescSetLayout::CreateBindingsArray(std::vector<DescriptorSetSlot *> &descBindings) const
{
descBindings.resize(bindings.size());
for(size_t i = 0; i < bindings.size(); i++)
{
descBindings[i] = new DescriptorSetBindingElement[bindings[i].descriptorCount];
memset(descBindings[i], 0, sizeof(DescriptorSetBindingElement) * bindings[i].descriptorCount);
descBindings[i] = new DescriptorSetSlot[bindings[i].descriptorCount];
memset(descBindings[i], 0, sizeof(DescriptorSetSlot) * bindings[i].descriptorCount);
}
}
void DescSetLayout::UpdateBindingsArray(const DescSetLayout &prevLayout,
std::vector<DescriptorSetBindingElement *> &descBindings) const
std::vector<DescriptorSetSlot *> &descBindings) const
{
// if we have fewer bindings now, delete the orphaned bindings arrays
for(size_t i = bindings.size(); i < prevLayout.bindings.size(); i++)
@@ -151,14 +151,13 @@ void DescSetLayout::UpdateBindingsArray(const DescSetLayout &prevLayout,
for(size_t i = 0; i < bindings.size(); i++)
{
// allocate new slot array
DescriptorSetBindingElement *newSlots =
new DescriptorSetBindingElement[bindings[i].descriptorCount];
memset(newSlots, 0, sizeof(DescriptorSetBindingElement) * bindings[i].descriptorCount);
DescriptorSetSlot *newSlots = new DescriptorSetSlot[bindings[i].descriptorCount];
memset(newSlots, 0, sizeof(DescriptorSetSlot) * bindings[i].descriptorCount);
// copy over any previous bindings that overlapped
if(i < prevLayout.bindings.size())
memcpy(newSlots, descBindings[i],
sizeof(DescriptorSetBindingElement) *
sizeof(DescriptorSetSlot) *
RDCMIN(prevLayout.bindings[i].descriptorCount, bindings[i].descriptorCount));
// delete old array, and assign the new one
+2 -2
View File
@@ -60,9 +60,9 @@ struct DescSetLayout
void Init(VulkanResourceManager *resourceMan, VulkanCreationInfo &info,
const VkDescriptorSetLayoutCreateInfo *pCreateInfo);
void CreateBindingsArray(std::vector<DescriptorSetBindingElement *> &descBindings) const;
void CreateBindingsArray(std::vector<DescriptorSetSlot *> &descBindings) const;
void UpdateBindingsArray(const DescSetLayout &prevLayout,
std::vector<DescriptorSetBindingElement *> &descBindings) const;
std::vector<DescriptorSetSlot *> &descBindings) const;
struct Binding
{
+9 -7
View File
@@ -63,7 +63,7 @@ bool WrappedVulkan::Prepare_InitialState(WrappedVkRes *res)
{
for(uint32_t b = 0; b < layout.bindings[i].descriptorCount; b++)
{
initialContents.descriptorSlots[e++].CreateFrom(record->descInfo->descBindings[i][b]);
initialContents.descriptorSlots[e++] = record->descInfo->descBindings[i][b];
}
}
}
@@ -651,7 +651,7 @@ uint64_t WrappedVulkan::GetSize_InitialState(ResourceId id, const VkInitialConte
for(size_t i = 0; i < layout.bindings.size(); i++)
NumBindings += layout.bindings[i].descriptorCount;
return 32 + NumBindings * sizeof(DescriptorSetBindingElement);
return 32 + NumBindings * sizeof(DescriptorSetSlot);
}
else if(initial.type == eResBuffer)
{
@@ -1487,13 +1487,13 @@ void WrappedVulkan::Apply_InitialState(WrappedVkRes *live, const VkInitialConten
// need to blat over the current descriptor set contents, so these are available
// when we want to fetch pipeline state
std::vector<DescriptorSetBindingElement *> &bindings = m_DescriptorSetState[id].currentBindings;
std::vector<DescriptorSetSlot *> &bindings = m_DescriptorSetState[id].currentBindings;
for(uint32_t i = 0; i < initial.numDescriptors; i++)
{
RDCASSERT(writes[i].dstBinding < bindings.size());
DescriptorSetBindingElement *bind = bindings[writes[i].dstBinding];
DescriptorSetSlot *bind = bindings[writes[i].dstBinding];
for(uint32_t d = 0; d < writes[i].descriptorCount; d++)
{
@@ -1502,18 +1502,20 @@ void WrappedVulkan::Apply_InitialState(WrappedVkRes *live, const VkInitialConten
if(writes[i].descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER ||
writes[i].descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER)
{
bind[idx].texelBufferView = writes[i].pTexelBufferView[d];
bind[idx].texelBufferView = GetResID(writes[i].pTexelBufferView[d]);
}
else if(writes[i].descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER ||
writes[i].descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC ||
writes[i].descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER ||
writes[i].descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC)
{
bind[idx].bufferInfo = writes[i].pBufferInfo[d];
bind[idx].bufferInfo.SetFrom(writes[i].pBufferInfo[d]);
}
else
{
bind[idx].imageInfo = writes[i].pImageInfo[d];
// we don't ever pass invalid parameters so we can unconditionally set both. Invalid
// elements are set to VK_NULL_HANDLE which is safe
bind[idx].imageInfo.SetFrom(writes[i].pImageInfo[d], true, true);
}
}
}
+18 -4
View File
@@ -1382,7 +1382,7 @@ void VulkanReplay::PatchReservedDescriptors(const VulkanStatePipeline &pipe,
if(bind.descriptorCount == 0 || bind.stageFlags == 0)
continue;
DescriptorSetBindingElement *slot = setInfo.currentBindings[b];
DescriptorSetSlot *slot = setInfo.currentBindings[b];
write.dstBinding = uint32_t(b + newBindingsCount);
write.dstArrayElement = 0;
@@ -1399,7 +1399,14 @@ void VulkanReplay::PatchReservedDescriptors(const VulkanStatePipeline &pipe,
{
VkDescriptorImageInfo *out = new VkDescriptorImageInfo[write.descriptorCount];
for(uint32_t w = 0; w < write.descriptorCount; w++)
out[w] = slot[w].imageInfo;
{
const DescriptorSetSlotImageInfo &src = slot[w].imageInfo;
out[w].imageLayout = src.imageLayout;
out[w].sampler = GetResourceManager()->GetCurrentHandle<VkSampler>(src.sampler);
out[w].imageView = GetResourceManager()->GetCurrentHandle<VkImageView>(src.imageView);
}
write.pImageInfo = out;
allocImgWrites.push_back(out);
break;
@@ -1409,7 +1416,8 @@ void VulkanReplay::PatchReservedDescriptors(const VulkanStatePipeline &pipe,
{
VkBufferView *out = new VkBufferView[write.descriptorCount];
for(uint32_t w = 0; w < write.descriptorCount; w++)
out[w] = slot[w].texelBufferView;
out[w] =
GetResourceManager()->GetCurrentHandle<VkBufferView>(slot[w].texelBufferView);
write.pTexelBufferView = out;
allocBufViewWrites.push_back(out);
break;
@@ -1421,7 +1429,13 @@ void VulkanReplay::PatchReservedDescriptors(const VulkanStatePipeline &pipe,
{
VkDescriptorBufferInfo *out = new VkDescriptorBufferInfo[write.descriptorCount];
for(uint32_t w = 0; w < write.descriptorCount; w++)
out[w] = slot[w].bufferInfo;
{
const DescriptorSetSlotBufferInfo &src = slot[w].bufferInfo;
out[w].offset = src.offset;
out[w].range = src.range;
out[w].buffer = GetResourceManager()->GetCurrentHandle<VkBuffer>(src.buffer);
}
write.pBufferInfo = out;
allocBufWrites.push_back(out);
break;
+9 -13
View File
@@ -1598,7 +1598,7 @@ void VulkanReplay::SavePipelineState(uint32_t eventId)
dst.bindings.resize(m_pDriver->m_DescriptorSetState[src].currentBindings.size());
for(size_t b = 0; b < m_pDriver->m_DescriptorSetState[src].currentBindings.size(); b++)
{
DescriptorSetBindingElement *info = m_pDriver->m_DescriptorSetState[src].currentBindings[b];
DescriptorSetSlot *info = m_pDriver->m_DescriptorSetState[src].currentBindings[b];
const DescSetLayout::Binding &layoutBind = c.m_DescSetLayout[layoutId].bindings[b];
curBind.bind = (uint32_t)b;
@@ -1699,9 +1699,9 @@ void VulkanReplay::SavePipelineState(uint32_t eventId)
dst.bindings[b].binds[a].samplerResourceId = layoutBind.immutableSampler[a];
dst.bindings[b].binds[a].immutableSampler = true;
}
else if(info[a].imageInfo.sampler != VK_NULL_HANDLE)
else if(info[a].imageInfo.sampler != ResourceId())
{
dst.bindings[b].binds[a].samplerResourceId = GetResID(info[a].imageInfo.sampler);
dst.bindings[b].binds[a].samplerResourceId = info[a].imageInfo.sampler;
}
if(dst.bindings[b].binds[a].samplerResourceId != ResourceId())
@@ -1749,12 +1749,10 @@ void VulkanReplay::SavePipelineState(uint32_t eventId)
layoutBind.descriptorType == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT ||
layoutBind.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE)
{
VkImageView view = info[a].imageInfo.imageView;
ResourceId viewid = info[a].imageInfo.imageView;
if(view != VK_NULL_HANDLE)
if(viewid != ResourceId())
{
ResourceId viewid = GetResID(view);
dst.bindings[b].binds[a].viewResourceId = rm->GetOriginalID(viewid);
dst.bindings[b].binds[a].resourceResourceId =
rm->GetOriginalID(c.m_ImageView[viewid].image);
@@ -1784,12 +1782,10 @@ void VulkanReplay::SavePipelineState(uint32_t eventId)
if(layoutBind.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER ||
layoutBind.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER)
{
VkBufferView view = info[a].texelBufferView;
ResourceId viewid = info[a].texelBufferView;
if(view != VK_NULL_HANDLE)
if(viewid != ResourceId())
{
ResourceId viewid = GetResID(view);
dst.bindings[b].binds[a].viewResourceId = rm->GetOriginalID(viewid);
dst.bindings[b].binds[a].resourceResourceId =
rm->GetOriginalID(c.m_BufferView[viewid].buffer);
@@ -1828,9 +1824,9 @@ void VulkanReplay::SavePipelineState(uint32_t eventId)
{
dst.bindings[b].binds[a].viewResourceId = ResourceId();
if(info[a].bufferInfo.buffer != VK_NULL_HANDLE)
if(info[a].bufferInfo.buffer != ResourceId())
dst.bindings[b].binds[a].resourceResourceId =
rm->GetOriginalID(GetResID(info[a].bufferInfo.buffer));
rm->GetOriginalID(info[a].bufferInfo.buffer);
dst.bindings[b].binds[a].byteOffset = info[a].bufferInfo.offset;
if(dynamicOffset)
+1 -1
View File
@@ -1013,7 +1013,7 @@ struct DescriptorSetData
// descriptor set bindings for this descriptor set. Filled out on
// create from the layout.
std::vector<DescriptorSetBindingElement *> descBindings;
std::vector<DescriptorSetSlot *> descBindings;
// lock protecting bindFrameRefs and bindMemRefs
Threading::CriticalSection refLock;
+14 -7
View File
@@ -444,7 +444,7 @@ void VulkanRenderState::BindDescriptorSet(const DescSetLayout &descLayout, VkCom
push.descriptorType = bind.descriptorType;
push.descriptorCount = bind.descriptorCount;
DescriptorSetBindingElement *slots = setInfo.currentBindings[b];
DescriptorSetSlot *slots = setInfo.currentBindings[b];
if(push.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER ||
push.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER)
@@ -452,7 +452,8 @@ void VulkanRenderState::BindDescriptorSet(const DescSetLayout &descLayout, VkCom
VkBufferView *dst = new VkBufferView[push.descriptorCount];
for(uint32_t a = 0; a < push.descriptorCount; a++)
dst[a] = Unwrap(slots[a].texelBufferView);
dst[a] =
Unwrap(GetResourceManager()->GetCurrentHandle<VkBufferView>(slots[a].texelBufferView));
push.pTexelBufferView = dst;
allocBufViewWrites.push_back(dst);
@@ -467,9 +468,12 @@ void VulkanRenderState::BindDescriptorSet(const DescSetLayout &descLayout, VkCom
for(uint32_t a = 0; a < push.descriptorCount; a++)
{
dst[a] = slots[a].imageInfo;
dst[a].sampler = Unwrap(dst[a].sampler);
dst[a].imageView = Unwrap(dst[a].imageView);
const DescriptorSetSlotImageInfo &src = slots[a].imageInfo;
dst[a].imageLayout = src.imageLayout;
dst[a].sampler = Unwrap(GetResourceManager()->GetCurrentHandle<VkSampler>(src.sampler));
dst[a].imageView =
Unwrap(GetResourceManager()->GetCurrentHandle<VkImageView>(src.imageView));
}
push.pImageInfo = dst;
@@ -481,8 +485,11 @@ void VulkanRenderState::BindDescriptorSet(const DescSetLayout &descLayout, VkCom
for(uint32_t a = 0; a < push.descriptorCount; a++)
{
dst[a] = slots[a].bufferInfo;
dst[a].buffer = Unwrap(dst[a].buffer);
const DescriptorSetSlotBufferInfo &src = slots[a].bufferInfo;
dst[a].offset = src.offset;
dst[a].range = src.range;
dst[a].buffer = Unwrap(GetResourceManager()->GetCurrentHandle<VkBuffer>(src.buffer));
}
push.pBufferInfo = dst;
@@ -3728,7 +3728,7 @@ void WrappedVulkan::ApplyPushDescriptorWrites(VkPipelineBindPoint pipelineBindPo
const DescSetLayout &desclayout = m_CreationInfo.m_DescSetLayout[descSetLayouts[set]];
std::vector<DescriptorSetBindingElement *> &bindings = m_DescriptorSetState[setId].currentBindings;
std::vector<DescriptorSetSlot *> &bindings = m_DescriptorSetState[setId].currentBindings;
ResourceId prevLayout = m_DescriptorSetState[setId].layout;
if(prevLayout == ResourceId())
@@ -3749,7 +3749,7 @@ void WrappedVulkan::ApplyPushDescriptorWrites(VkPipelineBindPoint pipelineBindPo
RDCASSERT(writeDesc.dstBinding < bindings.size());
DescriptorSetBindingElement **bind = &bindings[writeDesc.dstBinding];
DescriptorSetSlot **bind = &bindings[writeDesc.dstBinding];
const DescSetLayout::Binding *layoutBinding = &desclayout.bindings[writeDesc.dstBinding];
uint32_t curIdx = writeDesc.dstArrayElement;
@@ -3767,7 +3767,7 @@ void WrappedVulkan::ApplyPushDescriptorWrites(VkPipelineBindPoint pipelineBindPo
curIdx = 0;
}
(*bind)[curIdx].texelBufferView = writeDesc.pTexelBufferView[d];
(*bind)[curIdx].texelBufferView = GetResID(writeDesc.pTexelBufferView[d]);
}
}
else if(writeDesc.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER ||
@@ -3787,7 +3787,18 @@ void WrappedVulkan::ApplyPushDescriptorWrites(VkPipelineBindPoint pipelineBindPo
curIdx = 0;
}
(*bind)[curIdx].imageInfo = writeDesc.pImageInfo[d];
bool sampler = true;
bool imageView = true;
// ignore descriptors not part of the write, as they might not even point to a valid
// object so trying to get their ID could crash
if(layoutBinding->immutableSampler ||
writeDesc.descriptorType != VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
sampler = false;
if(writeDesc.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER)
imageView = false;
(*bind)[curIdx].imageInfo.SetFrom(writeDesc.pImageInfo[d], sampler, imageView);
}
}
else
@@ -3803,7 +3814,7 @@ void WrappedVulkan::ApplyPushDescriptorWrites(VkPipelineBindPoint pipelineBindPo
curIdx = 0;
}
(*bind)[curIdx].bufferInfo = writeDesc.pBufferInfo[d];
(*bind)[curIdx].bufferInfo.SetFrom(writeDesc.pBufferInfo[d]);
}
}
}
@@ -651,13 +651,13 @@ void WrappedVulkan::ReplayDescriptorSetWrite(VkDevice device, const VkWriteDescr
ObjDisp(device)->UpdateDescriptorSets(Unwrap(device), 1, &unwrapped, 0, NULL);
// update our local tracking
std::vector<DescriptorSetBindingElement *> &bindings =
std::vector<DescriptorSetSlot *> &bindings =
m_DescriptorSetState[GetResID(writeDesc.dstSet)].currentBindings;
{
RDCASSERT(writeDesc.dstBinding < bindings.size());
DescriptorSetBindingElement **bind = &bindings[writeDesc.dstBinding];
DescriptorSetSlot **bind = &bindings[writeDesc.dstBinding];
layoutBinding = &layout.bindings[writeDesc.dstBinding];
curIdx = writeDesc.dstArrayElement;
@@ -675,7 +675,7 @@ void WrappedVulkan::ReplayDescriptorSetWrite(VkDevice device, const VkWriteDescr
curIdx = 0;
}
(*bind)[curIdx].texelBufferView = writeDesc.pTexelBufferView[d];
(*bind)[curIdx].texelBufferView = GetResID(writeDesc.pTexelBufferView[d]);
}
}
else if(writeDesc.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER ||
@@ -695,7 +695,18 @@ void WrappedVulkan::ReplayDescriptorSetWrite(VkDevice device, const VkWriteDescr
curIdx = 0;
}
(*bind)[curIdx].imageInfo = writeDesc.pImageInfo[d];
bool sampler = true;
bool imageView = true;
// ignore descriptors not part of the write, as they might not even point to a valid
// object so trying to get their ID could crash
if(layoutBinding->immutableSampler ||
writeDesc.descriptorType != VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
sampler = false;
if(writeDesc.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER)
imageView = false;
(*bind)[curIdx].imageInfo.SetFrom(writeDesc.pImageInfo[d], sampler, imageView);
}
}
else
@@ -711,7 +722,7 @@ void WrappedVulkan::ReplayDescriptorSetWrite(VkDevice device, const VkWriteDescr
curIdx = 0;
}
(*bind)[curIdx].bufferInfo = writeDesc.pBufferInfo[d];
(*bind)[curIdx].bufferInfo.SetFrom(writeDesc.pBufferInfo[d]);
}
}
}
@@ -731,10 +742,8 @@ void WrappedVulkan::ReplayDescriptorSetCopy(VkDevice device, const VkCopyDescrip
ResourceId srcSetId = GetResID(copyDesc.srcSet);
// update our local tracking
std::vector<DescriptorSetBindingElement *> &dstbindings =
m_DescriptorSetState[dstSetId].currentBindings;
std::vector<DescriptorSetBindingElement *> &srcbindings =
m_DescriptorSetState[srcSetId].currentBindings;
std::vector<DescriptorSetSlot *> &dstbindings = m_DescriptorSetState[dstSetId].currentBindings;
std::vector<DescriptorSetSlot *> &srcbindings = m_DescriptorSetState[srcSetId].currentBindings;
{
RDCASSERT(copyDesc.dstBinding < dstbindings.size());
@@ -748,8 +757,8 @@ void WrappedVulkan::ReplayDescriptorSetCopy(VkDevice device, const VkCopyDescrip
const DescSetLayout::Binding *layoutSrcBinding = &srclayout.bindings[copyDesc.srcBinding];
const DescSetLayout::Binding *layoutDstBinding = &dstlayout.bindings[copyDesc.dstBinding];
DescriptorSetBindingElement **dstbind = &dstbindings[copyDesc.dstBinding];
DescriptorSetBindingElement **srcbind = &srcbindings[copyDesc.srcBinding];
DescriptorSetSlot **dstbind = &dstbindings[copyDesc.dstBinding];
DescriptorSetSlot **srcbind = &srcbindings[copyDesc.srcBinding];
uint32_t curDstIdx = copyDesc.dstArrayElement;
uint32_t curSrcIdx = copyDesc.srcArrayElement;
@@ -1013,7 +1022,7 @@ void WrappedVulkan::vkUpdateDescriptorSets(VkDevice device, uint32_t writeCount,
RDCASSERT(descWrite.dstBinding < record->descInfo->descBindings.size());
DescriptorSetBindingElement **binding = &record->descInfo->descBindings[descWrite.dstBinding];
DescriptorSetSlot **binding = &record->descInfo->descBindings[descWrite.dstBinding];
const DescSetLayout::Binding *layoutBinding = &layout.bindings[descWrite.dstBinding];
@@ -1057,14 +1066,14 @@ void WrappedVulkan::vkUpdateDescriptorSets(VkDevice device, uint32_t writeCount,
curIdx = 0;
}
DescriptorSetBindingElement &bind = (*binding)[curIdx];
DescriptorSetSlot &bind = (*binding)[curIdx];
bind.RemoveBindRefs(record);
bind.RemoveBindRefs(GetResourceManager(), record);
if(descWrite.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER ||
descWrite.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER)
{
bind.texelBufferView = descWrite.pTexelBufferView[d];
bind.texelBufferView = GetResID(descWrite.pTexelBufferView[d]);
}
else if(descWrite.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER ||
descWrite.descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER ||
@@ -1072,24 +1081,25 @@ void WrappedVulkan::vkUpdateDescriptorSets(VkDevice device, uint32_t writeCount,
descWrite.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE ||
descWrite.descriptorType == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT)
{
bind.imageInfo = descWrite.pImageInfo[d];
bool sampler = true;
bool imageView = true;
// ignore descriptors not part of the write, by NULL'ing out those members
// as they might not even point to a valid object
// ignore descriptors not part of the write, as they might not even point to a valid
// object so trying to get their ID could crash
if(layoutBinding->immutableSampler ||
descWrite.descriptorType != VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
sampler = false;
if(descWrite.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER)
bind.imageInfo.imageView = VK_NULL_HANDLE;
else if(descWrite.descriptorType != VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
bind.imageInfo.sampler = VK_NULL_HANDLE;
imageView = false;
if(layoutBinding->immutableSampler)
bind.imageInfo.sampler = VK_NULL_HANDLE;
bind.imageInfo.SetFrom(descWrite.pImageInfo[d], sampler, imageView);
}
else
{
bind.bufferInfo = descWrite.pBufferInfo[d];
bind.bufferInfo.SetFrom(descWrite.pBufferInfo[d]);
}
bind.AddBindRefs(record, ref);
bind.AddBindRefs(GetResourceManager(), record, ref);
}
}
@@ -1110,9 +1120,9 @@ void WrappedVulkan::vkUpdateDescriptorSets(VkDevice device, uint32_t writeCount,
RDCASSERT(pDescriptorCopies[i].dstBinding < dstrecord->descInfo->descBindings.size());
RDCASSERT(pDescriptorCopies[i].srcBinding < srcrecord->descInfo->descBindings.size());
DescriptorSetBindingElement **dstbinding =
DescriptorSetSlot **dstbinding =
&dstrecord->descInfo->descBindings[pDescriptorCopies[i].dstBinding];
DescriptorSetBindingElement **srcbinding =
DescriptorSetSlot **srcbinding =
&srcrecord->descInfo->descBindings[pDescriptorCopies[i].srcBinding];
const DescSetLayout::Binding *dstlayoutBinding =
@@ -1144,11 +1154,11 @@ void WrappedVulkan::vkUpdateDescriptorSets(VkDevice device, uint32_t writeCount,
curSrcIdx = 0;
}
DescriptorSetBindingElement &bind = (*dstbinding)[curDstIdx];
DescriptorSetSlot &bind = (*dstbinding)[curDstIdx];
bind.RemoveBindRefs(dstrecord);
bind.RemoveBindRefs(GetResourceManager(), dstrecord);
bind = (*srcbinding)[curSrcIdx];
bind.AddBindRefs(dstrecord, ref);
bind.AddBindRefs(GetResourceManager(), dstrecord, ref);
}
}
}
@@ -1396,7 +1406,7 @@ void WrappedVulkan::vkUpdateDescriptorSetWithTemplate(
RDCASSERT(entry.dstBinding < record->descInfo->descBindings.size());
DescriptorSetBindingElement **binding = &record->descInfo->descBindings[entry.dstBinding];
DescriptorSetSlot **binding = &record->descInfo->descBindings[entry.dstBinding];
const DescSetLayout::Binding *layoutBinding = &layout.bindings[entry.dstBinding];
@@ -1427,14 +1437,14 @@ void WrappedVulkan::vkUpdateDescriptorSetWithTemplate(
const byte *src = (const byte *)pData + entry.offset + entry.stride * d;
DescriptorSetBindingElement &bind = (*binding)[curIdx];
DescriptorSetSlot &bind = (*binding)[curIdx];
bind.RemoveBindRefs(record);
bind.RemoveBindRefs(GetResourceManager(), record);
if(entry.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER ||
entry.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER)
{
bind.texelBufferView = *(VkBufferView *)src;
bind.texelBufferView = GetResID(*(const VkBufferView *)src);
}
else if(entry.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER ||
entry.descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER ||
@@ -1442,21 +1452,27 @@ void WrappedVulkan::vkUpdateDescriptorSetWithTemplate(
entry.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE ||
entry.descriptorType == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT)
{
bind.imageInfo = *(VkDescriptorImageInfo *)src;
const VkDescriptorImageInfo &srcInfo = *(const VkDescriptorImageInfo *)src;
// ignore descriptors not part of the write, by NULL'ing out those members
// as they might not even point to a valid object
bool sampler = true;
bool imageView = true;
// ignore descriptors not part of the write, as they might not even point to a valid
// object so trying to get their ID could crash
if(layoutBinding->immutableSampler ||
entry.descriptorType != VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
sampler = false;
if(entry.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER)
bind.imageInfo.imageView = VK_NULL_HANDLE;
else if(entry.descriptorType != VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
bind.imageInfo.sampler = VK_NULL_HANDLE;
imageView = false;
bind.imageInfo.SetFrom(srcInfo, sampler, imageView);
}
else
{
bind.bufferInfo = *(VkDescriptorBufferInfo *)src;
bind.bufferInfo.SetFrom(*(const VkDescriptorBufferInfo *)src);
}
bind.AddBindRefs(record, ref);
bind.AddBindRefs(GetResourceManager(), record, ref);
}
}
}
+103 -1
View File
@@ -72,6 +72,21 @@ void main()
Color = vertIn.col;
}
)EOSHADER";
const std::string pixel2 = R"EOSHADER(
#version 450 core
#extension GL_EXT_samplerless_texture_functions : enable
layout(location = 0, index = 0) out vec4 Color;
layout(binding = 0) uniform texture2D tex;
void main()
{
Color = vec4(0, 1, 0, 1) * texelFetch(tex, ivec2(0), 0);
}
)EOSHADER";
int main()
@@ -138,6 +153,15 @@ void main()
VkPipelineLayout immutlayout =
createPipelineLayout(vkh::PipelineLayoutCreateInfo({immutsetlayout}));
VkDescriptorSetLayout setlayout2 = createDescriptorSetLayout(vkh::DescriptorSetLayoutCreateInfo({
{0, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT},
{1, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT},
}));
VkDescriptorSet descset2 = allocateDescriptorSet(setlayout2);
VkPipelineLayout layout2 = createPipelineLayout(vkh::PipelineLayoutCreateInfo({setlayout2}));
vkh::GraphicsPipelineCreateInfo pipeCreateInfo;
pipeCreateInfo.layout = layout;
@@ -160,6 +184,15 @@ void main()
VkPipeline immutpipe = createGraphicsPipeline(pipeCreateInfo);
pipeCreateInfo.stages = {
CompileShaderModule(common + vertex, ShaderLang::glsl, ShaderStage::vert, "main"),
CompileShaderModule(pixel2, ShaderLang::glsl, ShaderStage::frag, "main"),
};
pipeCreateInfo.layout = layout2;
VkPipeline pipe2 = createGraphicsPipeline(pipeCreateInfo);
{
// invalid handle - should not be used because the flag for derived pipelines is not used
pipeCreateInfo.basePipelineHandle = (VkPipeline)0x1234;
@@ -236,7 +269,8 @@ void main()
AllocatedImage img(this,
vkh::ImageCreateInfo(4, 4, 0, VK_FORMAT_R32G32B32A32_SFLOAT,
VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT),
VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT |
VK_IMAGE_USAGE_TRANSFER_DST_BIT),
VmaAllocationCreateInfo({0, VMA_MEMORY_USAGE_GPU_ONLY}));
VkImage validImage = img.image;
@@ -252,6 +286,15 @@ void main()
vkh::ImageMemoryBarrier(0, 0, VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_GENERAL, img.image),
});
vkCmdClearColorImage(cmd, img.image, VK_IMAGE_LAYOUT_GENERAL,
vkh::ClearColorValue(1.0f, 1.0f, 1.0f, 1.0f), 1,
vkh::ImageSubresourceRange());
vkh::cmdPipelineBarrier(
cmd, {
vkh::ImageMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT,
VK_IMAGE_LAYOUT_GENERAL,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, img.image),
});
vkEndCommandBuffer(cmd);
Submit(99, 99, {cmd});
}
@@ -462,6 +505,53 @@ void main()
vkCreateDescriptorUpdateTemplateKHR(device, &createInfo, NULL, &pushtempl);
}
// check that stale views in descriptors don't cause problems if the handle is re-used
VkImageView view1, view2;
CHECK_VKR(vkCreateImageView(device, vkh::ImageViewCreateInfo(img.image, VK_IMAGE_VIEW_TYPE_2D,
VK_FORMAT_R32G32B32A32_SFLOAT),
NULL, &view1));
CHECK_VKR(vkCreateImageView(device, vkh::ImageViewCreateInfo(img.image, VK_IMAGE_VIEW_TYPE_2D,
VK_FORMAT_R32G32B32A32_SFLOAT),
NULL, &view2));
vkh::updateDescriptorSets(
device, {
// bind view1 to binding 0, we will override this
vkh::WriteDescriptorSet(descset2, 0, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
{vkh::DescriptorImageInfo(view1)}),
// we bind view2 to binding 1. This will become stale
vkh::WriteDescriptorSet(descset2, 1, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
{vkh::DescriptorImageInfo(view2)}),
});
vkDestroyImageView(device, view2, NULL);
// create view3. Under RD, this is expected to get the same handle as view2 (but a new ID)
VkImageView view3;
CHECK_VKR(vkCreateImageView(device, vkh::ImageViewCreateInfo(img.image, VK_IMAGE_VIEW_TYPE_2D,
VK_FORMAT_R32G32B32A32_SFLOAT),
NULL, &view3));
if(rdoc)
{
TEST_ASSERT(view2 == view3,
"Expected view3 to be a re-used handle. Test isn't going to be valid");
}
vkh::updateDescriptorSets(
device,
{
// bind view3 to 0. This means the same handle is now in both binding but only binding 0
// is valid, binding 1 refers to the 'old' version of this handle.
vkh::WriteDescriptorSet(descset2, 0, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
{vkh::DescriptorImageInfo(view3)}),
// this unbinds the stale view2. Nothing should happen, but if we're comparing by handle
// this may remove a reference to view3 since it will have the same handle
vkh::WriteDescriptorSet(descset2, 1, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
{vkh::DescriptorImageInfo(view1)}),
});
while(Running())
{
VkCommandBuffer cmd = GetCommandBuffer();
@@ -498,6 +588,11 @@ void main()
vkCmdDraw(cmd, 3, 1, 0, 0);
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe2);
vkh::cmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, layout2, 0, {descset2}, {});
vkCmdDraw(cmd, 3, 1, 0, 0);
vkCmdEndRenderPass(cmd);
FinishUsingBackbuffer(cmd, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_GENERAL);
@@ -509,6 +604,13 @@ void main()
Present();
}
vkDeviceWaitIdle(device);
vkDestroySampler(device, validSampler, NULL);
vkDestroyImageView(device, view1, NULL);
vkDestroyImageView(device, view3, NULL);
if(KHR_descriptor_update_template && KHR_push_descriptor)
vkDestroyDescriptorUpdateTemplateKHR(device, pushtempl, NULL);
+7 -30
View File
@@ -6,37 +6,14 @@ class VK_Parameter_Zoo(rdtest.TestCase):
demos_test_name = 'VK_Parameter_Zoo'
def check_capture(self):
draw = self.find_draw("Draw")
draw = self.get_last_draw()
self.check(draw is not None)
draw = draw.previous
self.controller.SetFrameEvent(draw.eventId, False)
postvs_data = self.get_postvs(rd.MeshDataStage.VSOut, 0, draw.numIndices)
pipe: rd.PipeState = self.controller.GetPipelineState()
postvs_ref = {
0: {
'vtx': 0,
'idx': 0,
'gl_PerVertex.gl_Position': [-0.5, 0.5, 0.0, 1.0],
'vertOut.pos': [-0.5, 0.5, 0.0, 1.0],
'vertOut.col': [1.0, 0.0, 0.0, 1.0],
'vertOut.uv': [0.0, 0.0, 0.0, 1.0],
},
1: {
'vtx': 1,
'idx': 1,
'gl_PerVertex.gl_Position': [0.0, -0.5, 0.0, 1.0],
'vertOut.pos': [0.0, -0.5, 0.0, 1.0],
'vertOut.col': [0.0, 1.0, 0.0, 1.0],
'vertOut.uv': [0.0, 1.0, 0.0, 1.0],
},
2: {
'vtx': 2,
'idx': 2,
'gl_PerVertex.gl_Position': [0.5, 0.5, 0.0, 1.0],
'vertOut.pos': [0.5, 0.5, 0.0, 1.0],
'vertOut.col': [0.0, 0.0, 1.0, 1.0],
'vertOut.uv': [1.0, 0.0, 0.0, 1.0],
},
}
self.check_mesh_data(postvs_ref, postvs_data)
self.check_pixel_value(pipe.GetOutputTargets()[0].resourceId, 0.5, 0.5, [0.0, 1.0, 0.0, 1.0])