in renderdoc/driver/vulkan/vk_shaderdebug.cpp [579:1348]
bool CalculateSampleGather(rdcspv::ThreadState &lane, rdcspv::Op opcode,
DebugAPIWrapper::TextureType texType, ShaderBindIndex imageBind,
ShaderBindIndex samplerBind, const ShaderVariable &uv,
const ShaderVariable &ddxCalc, const ShaderVariable &ddyCalc,
const ShaderVariable &compare, rdcspv::GatherChannel gatherChannel,
const rdcspv::ImageOperandsAndParamDatas &operands,
ShaderVariable &output) override
{
ShaderConstParameters constParams = {};
ShaderUniformParameters uniformParams = {};
const bool buffer = (texType & DebugAPIWrapper::Buffer_Texture) != 0;
const bool uintTex = (texType & DebugAPIWrapper::UInt_Texture) != 0;
const bool sintTex = (texType & DebugAPIWrapper::SInt_Texture) != 0;
// fetch the right type of descriptor depending on if we're buffer or not
bool valid = true;
rdcstr access = StringFormat::Fmt("performing %s operation", ToStr(opcode).c_str());
const Descriptor &imageDescriptor = buffer ? GetDescriptor(access, ShaderBindIndex(), valid)
: GetDescriptor(access, imageBind, valid);
const Descriptor &bufferViewDescriptor = buffer
? GetDescriptor(access, imageBind, valid)
: GetDescriptor(access, ShaderBindIndex(), valid);
// fetch the sampler (if there's no sampler, this will silently return dummy data without
// marking invalid
const SamplerDescriptor &samplerDescriptor = GetSamplerDescriptor(access, samplerBind, valid);
// if any descriptor lookup failed, return now
if(!valid)
return false;
VkMarkerRegion markerRegion("CalculateSampleGather");
VkBufferView bufferView =
m_pDriver->GetResourceManager()->GetLiveHandle<VkBufferView>(bufferViewDescriptor.view);
VkSampler sampler =
m_pDriver->GetResourceManager()->GetLiveHandle<VkSampler>(samplerDescriptor.object);
VkImageView view =
m_pDriver->GetResourceManager()->GetLiveHandle<VkImageView>(imageDescriptor.view);
VkImageLayout layout = convert((DescriptorSlotImageLayout)imageDescriptor.byteOffset);
// promote view to Array view
const VulkanCreationInfo::ImageView &viewProps = m_Creation.m_ImageView[GetResID(view)];
const VulkanCreationInfo::Image &imageProps = m_Creation.m_Image[viewProps.image];
const bool depthTex = IsDepthOrStencilFormat(viewProps.format);
VkDevice dev = m_pDriver->GetDev();
// how many co-ordinates should there be
int coords = 0, gradCoords = 0;
if(buffer)
{
constParams.dim = ShaderDebugBind::Buffer;
coords = gradCoords = 1;
}
else
{
switch(viewProps.viewType)
{
case VK_IMAGE_VIEW_TYPE_1D:
coords = 1;
gradCoords = 1;
constParams.dim = ShaderDebugBind::Tex1D;
break;
case VK_IMAGE_VIEW_TYPE_2D:
coords = 2;
gradCoords = 2;
constParams.dim = ShaderDebugBind::Tex2D;
break;
case VK_IMAGE_VIEW_TYPE_3D:
coords = 3;
gradCoords = 3;
constParams.dim = ShaderDebugBind::Tex3D;
break;
case VK_IMAGE_VIEW_TYPE_CUBE:
coords = 3;
gradCoords = 3;
constParams.dim = ShaderDebugBind::TexCube;
break;
case VK_IMAGE_VIEW_TYPE_1D_ARRAY:
coords = 2;
gradCoords = 1;
constParams.dim = ShaderDebugBind::Tex1D;
break;
case VK_IMAGE_VIEW_TYPE_2D_ARRAY:
coords = 3;
gradCoords = 2;
constParams.dim = ShaderDebugBind::Tex2D;
break;
case VK_IMAGE_VIEW_TYPE_CUBE_ARRAY:
coords = 4;
gradCoords = 3;
constParams.dim = ShaderDebugBind::TexCube;
break;
case VK_IMAGE_VIEW_TYPE_MAX_ENUM:
RDCERR("Invalid image view type %s", ToStr(viewProps.viewType).c_str());
return false;
}
if(imageProps.samples > 1)
constParams.dim = ShaderDebugBind::Tex2DMS;
}
// handle query opcodes now
switch(opcode)
{
case rdcspv::Op::ImageQueryLevels:
{
output.value.u32v[0] = viewProps.range.levelCount;
if(viewProps.range.levelCount == VK_REMAINING_MIP_LEVELS)
output.value.u32v[0] = imageProps.mipLevels - viewProps.range.baseMipLevel;
return true;
}
case rdcspv::Op::ImageQuerySamples:
{
output.value.u32v[0] = (uint32_t)imageProps.samples;
return true;
}
case rdcspv::Op::ImageQuerySize:
case rdcspv::Op::ImageQuerySizeLod:
{
uint32_t mip = viewProps.range.baseMipLevel;
if(opcode == rdcspv::Op::ImageQuerySizeLod)
mip += uintComp(lane.GetSrc(operands.lod), 0);
RDCEraseEl(output.value);
int i = 0;
setUintComp(output, i++, RDCMAX(1U, imageProps.extent.width >> mip));
if(coords >= 2)
setUintComp(output, i++, RDCMAX(1U, imageProps.extent.height >> mip));
if(viewProps.viewType == VK_IMAGE_VIEW_TYPE_3D)
setUintComp(output, i++, RDCMAX(1U, imageProps.extent.depth >> mip));
if(viewProps.viewType == VK_IMAGE_VIEW_TYPE_1D_ARRAY ||
viewProps.viewType == VK_IMAGE_VIEW_TYPE_2D_ARRAY)
setUintComp(output, i++, imageProps.arrayLayers);
else if(viewProps.viewType == VK_IMAGE_VIEW_TYPE_CUBE ||
viewProps.viewType == VK_IMAGE_VIEW_TYPE_CUBE_ARRAY)
setUintComp(output, i++, imageProps.arrayLayers / 6);
if(buffer)
{
const VulkanCreationInfo::BufferView &bufViewProps =
m_Creation.m_BufferView[GetResID(bufferView)];
VkDeviceSize size = bufViewProps.size;
if(size == VK_WHOLE_SIZE)
{
const VulkanCreationInfo::Buffer &bufProps = m_Creation.m_Buffer[bufViewProps.buffer];
size = bufProps.size - bufViewProps.offset;
}
setUintComp(output, 0, uint32_t(size / GetByteSize(1, 1, 1, bufViewProps.format, 0)));
}
return true;
}
default: break;
}
// create our own view (if we haven't already for this view) so we can promote to array
VkImageView sampleView = m_SampleViews[GetResID(view)];
if(sampleView == VK_NULL_HANDLE && view != VK_NULL_HANDLE)
{
VkImageViewCreateInfo viewInfo = {VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO};
viewInfo.image = m_pDriver->GetResourceManager()->GetCurrentHandle<VkImage>(viewProps.image);
viewInfo.format = viewProps.format;
viewInfo.viewType = viewProps.viewType;
if(viewInfo.viewType == VK_IMAGE_VIEW_TYPE_1D)
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_1D_ARRAY;
else if(viewInfo.viewType == VK_IMAGE_VIEW_TYPE_2D)
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
else if(viewInfo.viewType == VK_IMAGE_VIEW_TYPE_CUBE &&
m_pDriver->GetDeviceEnabledFeatures().imageCubeArray)
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_CUBE_ARRAY;
viewInfo.components = viewProps.componentMapping;
viewInfo.subresourceRange = viewProps.range;
// if KHR_maintenance2 is available, ensure we have sampled usage available
VkImageViewUsageCreateInfo usageCreateInfo = {VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO};
if(m_pDriver->GetExtensions(NULL).ext_KHR_maintenance2)
{
usageCreateInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
viewInfo.pNext = &usageCreateInfo;
}
VkResult vkr = m_pDriver->vkCreateImageView(dev, &viewInfo, NULL, &sampleView);
m_pDriver->CheckVkResult(vkr);
m_SampleViews[GetResID(view)] = sampleView;
}
if(operands.flags & rdcspv::ImageOperands::Bias)
{
const ShaderVariable &biasVar = lane.GetSrc(operands.bias);
// silently cast parameters to 32-bit floats
float bias = floatComp(biasVar, 0);
if(bias != 0.0f)
{
// bias can only be used with implicit lod operations, but we want to do everything with
// explicit lod operations. So we instead push the bias into a new sampler, which is
// entirely equivalent.
// first check to see if we have one already, since the bias is probably going to be
// coherent.
SamplerBiasKey key = {GetResID(sampler), bias};
auto insertIt = m_BiasSamplers.insert(std::make_pair(key, VkSampler()));
if(insertIt.second)
{
const VulkanCreationInfo::Sampler &samplerProps = m_Creation.m_Sampler[key.first];
VkSamplerCreateInfo sampInfo = {VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO};
sampInfo.magFilter = samplerProps.magFilter;
sampInfo.minFilter = samplerProps.minFilter;
sampInfo.mipmapMode = samplerProps.mipmapMode;
sampInfo.addressModeU = samplerProps.address[0];
sampInfo.addressModeV = samplerProps.address[1];
sampInfo.addressModeW = samplerProps.address[2];
sampInfo.mipLodBias = samplerProps.mipLodBias;
sampInfo.anisotropyEnable = samplerProps.maxAnisotropy >= 1.0f;
sampInfo.maxAnisotropy = samplerProps.maxAnisotropy;
sampInfo.compareEnable = samplerProps.compareEnable;
sampInfo.compareOp = samplerProps.compareOp;
sampInfo.minLod = samplerProps.minLod;
sampInfo.maxLod = samplerProps.maxLod;
sampInfo.borderColor = samplerProps.borderColor;
sampInfo.unnormalizedCoordinates = samplerProps.unnormalizedCoordinates;
VkSamplerReductionModeCreateInfo reductionInfo = {
VK_STRUCTURE_TYPE_SAMPLER_REDUCTION_MODE_CREATE_INFO};
if(samplerProps.reductionMode != VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE)
{
reductionInfo.reductionMode = samplerProps.reductionMode;
reductionInfo.pNext = sampInfo.pNext;
sampInfo.pNext = &reductionInfo;
}
VkSamplerYcbcrConversionInfo ycbcrInfo = {VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO};
if(samplerProps.ycbcr != ResourceId())
{
ycbcrInfo.conversion =
m_pDriver->GetResourceManager()->GetCurrentHandle<VkSamplerYcbcrConversion>(
viewProps.image);
ycbcrInfo.pNext = sampInfo.pNext;
sampInfo.pNext = &ycbcrInfo;
}
VkSamplerCustomBorderColorCreateInfoEXT borderInfo = {
VK_STRUCTURE_TYPE_SAMPLER_CUSTOM_BORDER_COLOR_CREATE_INFO_EXT};
if(samplerProps.customBorder)
{
borderInfo.customBorderColor = samplerProps.customBorderColor;
borderInfo.format = samplerProps.customBorderFormat;
borderInfo.pNext = sampInfo.pNext;
sampInfo.pNext = &borderInfo;
}
// now add the shader's bias on
sampInfo.mipLodBias += bias;
VkResult vkr = m_pDriver->vkCreateSampler(dev, &sampInfo, NULL, &sampler);
m_pDriver->CheckVkResult(vkr);
insertIt.first->second = sampler;
}
else
{
sampler = insertIt.first->second;
}
}
}
constParams.operation = (uint32_t)opcode;
// proj opcodes have an extra q parameter, but we do the divide ourselves and 'demote' these to
// non-proj variants
bool proj = false;
switch(opcode)
{
case rdcspv::Op::ImageSampleProjExplicitLod:
{
constParams.operation = (uint32_t)rdcspv::Op::ImageSampleExplicitLod;
proj = true;
break;
}
case rdcspv::Op::ImageSampleProjImplicitLod:
{
constParams.operation = (uint32_t)rdcspv::Op::ImageSampleImplicitLod;
proj = true;
break;
}
case rdcspv::Op::ImageSampleProjDrefExplicitLod:
{
constParams.operation = (uint32_t)rdcspv::Op::ImageSampleDrefExplicitLod;
proj = true;
break;
}
case rdcspv::Op::ImageSampleProjDrefImplicitLod:
{
constParams.operation = (uint32_t)rdcspv::Op::ImageSampleDrefImplicitLod;
proj = true;
break;
}
default: break;
}
bool useCompare = false;
switch(opcode)
{
case rdcspv::Op::ImageDrefGather:
case rdcspv::Op::ImageSampleDrefExplicitLod:
case rdcspv::Op::ImageSampleDrefImplicitLod:
case rdcspv::Op::ImageSampleProjDrefExplicitLod:
case rdcspv::Op::ImageSampleProjDrefImplicitLod:
{
useCompare = true;
if(m_pDriver->GetDriverInfo().QualcommDrefNon2DCompileCrash() &&
constParams.dim != ShaderDebugBind::Tex2D)
{
m_pDriver->AddDebugMessage(
MessageCategory::Execution, MessageSeverity::High, MessageSource::RuntimeWarning,
"Dref sample against non-2D texture, this cannot be debugged due to a driver bug");
}
break;
}
default: break;
}
bool gatherOp = false;
switch(opcode)
{
case rdcspv::Op::ImageFetch:
{
// co-ordinates after the used ones are read as 0s. This allows us to then read an implicit
// 0 for array layer when we promote accesses to arrays.
uniformParams.texel_uvw.x = uintComp(uv, 0);
if(coords >= 2)
uniformParams.texel_uvw.y = uintComp(uv, 1);
if(coords >= 3)
uniformParams.texel_uvw.z = uintComp(uv, 2);
if(!buffer && operands.flags & rdcspv::ImageOperands::Lod)
uniformParams.texel_lod = uintComp(lane.GetSrc(operands.lod), 0);
else
uniformParams.texel_lod = 0;
if(operands.flags & rdcspv::ImageOperands::Sample)
uniformParams.sampleIdx = uintComp(lane.GetSrc(operands.sample), 0);
break;
}
case rdcspv::Op::ImageGather:
case rdcspv::Op::ImageDrefGather:
{
gatherOp = true;
// silently cast parameters to 32-bit floats
for(int i = 0; i < coords; i++)
uniformParams.uvwa[i] = floatComp(uv, i);
if(useCompare)
uniformParams.compare = floatComp(compare, 0);
constParams.gatherChannel = gatherChannel;
if(operands.flags & rdcspv::ImageOperands::ConstOffsets)
{
ShaderVariable constOffsets = lane.GetSrc(operands.constOffsets);
constParams.useGradOrGatherOffsets = VK_TRUE;
// should be an array of ivec2
RDCASSERT(constOffsets.members.size() == 4);
// sign extend variables lower than 32-bits
for(int i = 0; i < 4; i++)
{
if(constOffsets.members[i].type == VarType::SByte)
{
constOffsets.members[i].value.s32v[0] = constOffsets.members[i].value.s8v[0];
constOffsets.members[i].value.s32v[1] = constOffsets.members[i].value.s8v[1];
}
else if(constOffsets.members[i].type == VarType::SShort)
{
constOffsets.members[i].value.s32v[0] = constOffsets.members[i].value.s16v[0];
constOffsets.members[i].value.s32v[1] = constOffsets.members[i].value.s16v[1];
}
}
constParams.gatherOffsets.u0 = constOffsets.members[0].value.s32v[0];
constParams.gatherOffsets.v0 = constOffsets.members[0].value.s32v[1];
constParams.gatherOffsets.u1 = constOffsets.members[1].value.s32v[0];
constParams.gatherOffsets.v1 = constOffsets.members[1].value.s32v[1];
constParams.gatherOffsets.u2 = constOffsets.members[2].value.s32v[0];
constParams.gatherOffsets.v2 = constOffsets.members[2].value.s32v[1];
constParams.gatherOffsets.u3 = constOffsets.members[3].value.s32v[0];
constParams.gatherOffsets.v3 = constOffsets.members[3].value.s32v[1];
}
break;
}
case rdcspv::Op::ImageQueryLod:
case rdcspv::Op::ImageSampleExplicitLod:
case rdcspv::Op::ImageSampleImplicitLod:
case rdcspv::Op::ImageSampleProjExplicitLod:
case rdcspv::Op::ImageSampleProjImplicitLod:
case rdcspv::Op::ImageSampleDrefExplicitLod:
case rdcspv::Op::ImageSampleDrefImplicitLod:
case rdcspv::Op::ImageSampleProjDrefExplicitLod:
case rdcspv::Op::ImageSampleProjDrefImplicitLod:
{
// silently cast parameters to 32-bit floats
for(int i = 0; i < coords; i++)
uniformParams.uvwa[i] = floatComp(uv, i);
if(proj)
{
// coords shouldn't be 4 because that's only valid for cube arrays which can't be
// projected
RDCASSERT(coords < 4);
// do the divide ourselves rather than severely complicating the sample shader (as proj
// variants need non-arrayed textures)
float q = floatComp(uv, coords);
uniformParams.uvwa[0] /= q;
uniformParams.uvwa[1] /= q;
uniformParams.uvwa[2] /= q;
}
if(operands.flags & rdcspv::ImageOperands::MinLod)
{
const ShaderVariable &minLodVar = lane.GetSrc(operands.minLod);
// silently cast parameters to 32-bit floats
uniformParams.minlod = floatComp(minLodVar, 0);
}
if(useCompare)
{
// silently cast parameters to 32-bit floats
uniformParams.compare = floatComp(compare, 0);
}
if(operands.flags & rdcspv::ImageOperands::Lod)
{
const ShaderVariable &lodVar = lane.GetSrc(operands.lod);
// silently cast parameters to 32-bit floats
uniformParams.lod = floatComp(lodVar, 0);
constParams.useGradOrGatherOffsets = VK_FALSE;
}
else if(operands.flags & rdcspv::ImageOperands::Grad)
{
ShaderVariable ddx = lane.GetSrc(operands.grad.first);
ShaderVariable ddy = lane.GetSrc(operands.grad.second);
constParams.useGradOrGatherOffsets = VK_TRUE;
// silently cast parameters to 32-bit floats
RDCASSERTEQUAL(ddx.type, ddy.type);
for(int i = 0; i < gradCoords; i++)
{
uniformParams.ddx[i] = floatComp(ddx, i);
uniformParams.ddy[i] = floatComp(ddy, i);
}
}
if(opcode == rdcspv::Op::ImageSampleImplicitLod ||
opcode == rdcspv::Op::ImageSampleProjImplicitLod || opcode == rdcspv::Op::ImageQueryLod)
{
// use grad to sub in for the implicit lod
constParams.useGradOrGatherOffsets = VK_TRUE;
// silently cast parameters to 32-bit floats
RDCASSERTEQUAL(ddxCalc.type, ddyCalc.type);
for(int i = 0; i < gradCoords; i++)
{
uniformParams.ddx[i] = floatComp(ddxCalc, i);
uniformParams.ddy[i] = floatComp(ddyCalc, i);
}
}
break;
}
default:
{
RDCERR("Unsupported opcode %s", ToStr(opcode).c_str());
return false;
}
}
if(operands.flags & rdcspv::ImageOperands::ConstOffset)
{
ShaderVariable constOffset = lane.GetSrc(operands.constOffset);
// sign extend variables lower than 32-bits
for(uint8_t c = 0; c < constOffset.columns; c++)
{
if(constOffset.type == VarType::SByte)
constOffset.value.s32v[c] = constOffset.value.s8v[c];
else if(constOffset.type == VarType::SShort)
constOffset.value.s32v[c] = constOffset.value.s16v[c];
}
// pass offsets as uniform where possible - when the feature (widely available) on gather
// operations. On non-gather operations we are forced to use const offsets and must specialise
// the pipeline.
if(m_pDriver->GetDeviceEnabledFeatures().shaderImageGatherExtended && gatherOp)
{
uniformParams.offset.x = constOffset.value.s32v[0];
if(gradCoords >= 2)
uniformParams.offset.y = constOffset.value.s32v[1];
if(gradCoords >= 3)
uniformParams.offset.z = constOffset.value.s32v[2];
}
else
{
constParams.constOffsets.x = constOffset.value.s32v[0];
if(gradCoords >= 2)
constParams.constOffsets.y = constOffset.value.s32v[1];
if(gradCoords >= 3)
constParams.constOffsets.z = constOffset.value.s32v[2];
}
}
else if(operands.flags & rdcspv::ImageOperands::Offset)
{
ShaderVariable offset = lane.GetSrc(operands.offset);
// sign extend variables lower than 32-bits
for(uint8_t c = 0; c < offset.columns; c++)
{
if(offset.type == VarType::SByte)
offset.value.s32v[c] = offset.value.s8v[c];
else if(offset.type == VarType::SShort)
offset.value.s32v[c] = offset.value.s16v[c];
}
// if the app's shader used a dynamic offset, we can too!
uniformParams.offset.x = offset.value.s32v[0];
if(gradCoords >= 2)
uniformParams.offset.y = offset.value.s32v[1];
if(gradCoords >= 3)
uniformParams.offset.z = offset.value.s32v[2];
}
if(!m_pDriver->GetDeviceEnabledFeatures().shaderImageGatherExtended &&
(uniformParams.offset.x != 0 || uniformParams.offset.y != 0 || uniformParams.offset.z != 0))
{
m_pDriver->AddDebugMessage(
MessageCategory::Execution, MessageSeverity::High, MessageSource::RuntimeWarning,
StringFormat::Fmt("Use of constant offsets %d/%d/%d is not supported without "
"shaderImageGatherExtended device feature",
uniformParams.offset.x, uniformParams.offset.y, uniformParams.offset.z));
}
VkPipeline pipe = MakePipe(constParams, 32, depthTex, uintTex, sintTex);
if(pipe == VK_NULL_HANDLE)
{
m_pDriver->AddDebugMessage(MessageCategory::Execution, MessageSeverity::High,
MessageSource::RuntimeWarning,
"Failed to compile graphics pipeline for sampling operation");
return false;
}
VkDescriptorImageInfo samplerWriteInfo = {Unwrap(sampler), VK_NULL_HANDLE,
VK_IMAGE_LAYOUT_UNDEFINED};
VkDescriptorImageInfo imageWriteInfo = {VK_NULL_HANDLE, Unwrap(sampleView), layout};
VkDescriptorBufferInfo uniformWriteInfo = {};
m_DebugData.ConstantsBuffer.FillDescriptor(uniformWriteInfo);
VkWriteDescriptorSet writeSets[] = {
{
VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
NULL,
Unwrap(m_DebugData.DescSet),
(uint32_t)ShaderDebugBind::Constants,
0,
1,
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
NULL,
&uniformWriteInfo,
NULL,
},
{
VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
NULL,
Unwrap(m_DebugData.DescSet),
(uint32_t)constParams.dim,
0,
1,
VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
&imageWriteInfo,
NULL,
NULL,
},
{
VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
NULL,
Unwrap(m_DebugData.DescSet),
(uint32_t)ShaderDebugBind::Sampler,
0,
1,
VK_DESCRIPTOR_TYPE_SAMPLER,
&samplerWriteInfo,
NULL,
NULL,
},
};
if(buffer)
{
writeSets[1].pTexelBufferView = UnwrapPtr(bufferView);
writeSets[1].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
}
// reset descriptor sets to dummy state
if(depthTex)
{
uint32_t resetIndex = 3;
rdcarray<VkWriteDescriptorSet> writes;
for(size_t i = 0; i < ARRAY_COUNT(m_DebugData.DummyWrites[resetIndex]); i++)
{
// not all textures may be supported for depth, so only update those that are valid
if(m_DebugData.DummyWrites[resetIndex][i].descriptorCount != 0)
writes.push_back(m_DebugData.DummyWrites[resetIndex][i]);
}
ObjDisp(dev)->UpdateDescriptorSets(Unwrap(dev), (uint32_t)writes.count(), writes.data(), 0,
NULL);
}
else
{
uint32_t resetIndex = 0;
if(uintTex)
resetIndex = 1;
else if(sintTex)
resetIndex = 2;
ObjDisp(dev)->UpdateDescriptorSets(Unwrap(dev),
ARRAY_COUNT(m_DebugData.DummyWrites[resetIndex]),
m_DebugData.DummyWrites[resetIndex], 0, NULL);
}
// overwrite with our data
ObjDisp(dev)->UpdateDescriptorSets(Unwrap(dev), sampler != VK_NULL_HANDLE ? 3 : 2, writeSets, 0,
NULL);
void *constants = m_DebugData.ConstantsBuffer.Map(NULL, 0);
if(!constants)
return false;
memcpy(constants, &uniformParams, sizeof(uniformParams));
m_DebugData.ConstantsBuffer.Unmap();
{
VkCommandBuffer cmd = m_pDriver->GetNextCmd();
if(cmd == VK_NULL_HANDLE)
return false;
VkCommandBufferBeginInfo beginInfo = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, NULL,
VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT};
VkResult vkr = ObjDisp(cmd)->BeginCommandBuffer(Unwrap(cmd), &beginInfo);
m_pDriver->CheckVkResult(vkr);
VkClearValue clear = {};
VkRenderPassBeginInfo rpbegin = {
VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
NULL,
Unwrap(m_DebugData.RenderPass),
Unwrap(m_DebugData.Framebuffer),
{{0, 0}, {1, 1}},
1,
&clear,
};
ObjDisp(cmd)->CmdBeginRenderPass(Unwrap(cmd), &rpbegin, VK_SUBPASS_CONTENTS_INLINE);
ObjDisp(cmd)->CmdBindPipeline(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, Unwrap(pipe));
ObjDisp(cmd)->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS,
Unwrap(m_DebugData.PipeLayout), 0, 1,
UnwrapPtr(m_DebugData.DescSet), 0, NULL);
// push uvw/ddx/ddy for the vertex shader
ObjDisp(cmd)->CmdPushConstants(Unwrap(cmd), Unwrap(m_DebugData.PipeLayout), VK_SHADER_STAGE_ALL,
sizeof(Vec4f) * 0, sizeof(Vec4f), &uniformParams.uvwa);
ObjDisp(cmd)->CmdPushConstants(Unwrap(cmd), Unwrap(m_DebugData.PipeLayout), VK_SHADER_STAGE_ALL,
sizeof(Vec4f) * 1, sizeof(Vec3f), &uniformParams.ddx);
ObjDisp(cmd)->CmdPushConstants(Unwrap(cmd), Unwrap(m_DebugData.PipeLayout), VK_SHADER_STAGE_ALL,
sizeof(Vec4f) * 2, sizeof(Vec3f), &uniformParams.ddy);
ObjDisp(cmd)->CmdDraw(Unwrap(cmd), 3, 1, 0, 0);
ObjDisp(cmd)->CmdEndRenderPass(Unwrap(cmd));
VkBufferImageCopy region = {
0, sizeof(Vec4f), 1, {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}, {0, 0, 0}, {1, 1, 1},
};
ObjDisp(cmd)->CmdCopyImageToBuffer(Unwrap(cmd), Unwrap(m_DebugData.Image),
VK_IMAGE_LAYOUT_GENERAL,
Unwrap(m_DebugData.ReadbackBuffer.buf), 1, ®ion);
VkBufferMemoryBarrier bufBarrier = {
VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
NULL,
VK_ACCESS_TRANSFER_WRITE_BIT,
VK_ACCESS_HOST_READ_BIT,
VK_QUEUE_FAMILY_IGNORED,
VK_QUEUE_FAMILY_IGNORED,
Unwrap(m_DebugData.ReadbackBuffer.buf),
0,
VK_WHOLE_SIZE,
};
// wait for copy to finish before reading back to host
DoPipelineBarrier(cmd, 1, &bufBarrier);
vkr = ObjDisp(cmd)->EndCommandBuffer(Unwrap(cmd));
m_pDriver->CheckVkResult(vkr);
m_pDriver->SubmitCmds();
m_pDriver->FlushQ();
}
float *retf = (float *)m_DebugData.ReadbackBuffer.Map(NULL, 0);
if(!retf)
return false;
uint32_t *retu = (uint32_t *)retf;
int32_t *reti = (int32_t *)retf;
// convert full precision results, we did all sampling at 32-bit precision
for(uint8_t c = 0; c < 4; c++)
{
if(VarTypeCompType(output.type) == CompType::Float)
setFloatComp(output, c, retf[c]);
else if(VarTypeCompType(output.type) == CompType::SInt)
setIntComp(output, c, reti[c]);
else
setUintComp(output, c, retu[c]);
}
m_DebugData.ReadbackBuffer.Unmap();
return true;
}