diff --git a/renderdoc/driver/gl/gl_replay.cpp b/renderdoc/driver/gl/gl_replay.cpp index b34ac77b4..03fbd1f1b 100644 --- a/renderdoc/driver/gl/gl_replay.cpp +++ b/renderdoc/driver/gl/gl_replay.cpp @@ -2428,8 +2428,8 @@ byte *GLReplay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, texType = eGL_TEXTURE_2D_ARRAY; texname = tempTex; depth = 1; - depth = samples; - arraysize = samples; + depth = arraysize * samples; + arraysize = arraysize * samples; samples = 1; } diff --git a/renderdoc/driver/vulkan/vk_common.cpp b/renderdoc/driver/vulkan/vk_common.cpp index 4b6334316..eff45abcb 100644 --- a/renderdoc/driver/vulkan/vk_common.cpp +++ b/renderdoc/driver/vulkan/vk_common.cpp @@ -2552,6 +2552,7 @@ string ToStrHelper::Get(const VkResult &el) TOSTR_CASE_STRINGIZE(VK_ERROR_OUT_OF_DATE_KHR) TOSTR_CASE_STRINGIZE(VK_ERROR_INCOMPATIBLE_DISPLAY_KHR) TOSTR_CASE_STRINGIZE(VK_ERROR_VALIDATION_FAILED_EXT) + TOSTR_CASE_STRINGIZE(VK_ERROR_INVALID_SHADER_NV) default: break; } diff --git a/renderdoc/driver/vulkan/vk_debug.cpp b/renderdoc/driver/vulkan/vk_debug.cpp index 209a791fa..0ae72c493 100644 --- a/renderdoc/driver/vulkan/vk_debug.cpp +++ b/renderdoc/driver/vulkan/vk_debug.cpp @@ -271,6 +271,12 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver, VkDevice dev) m_PickPixelFB = VK_NULL_HANDLE; m_PickPixelRP = VK_NULL_HANDLE; + m_ArrayMSDescSetLayout = VK_NULL_HANDLE; + m_ArrayMSPipeLayout = VK_NULL_HANDLE; + m_ArrayMSDescSet = VK_NULL_HANDLE; + m_Array2MSPipe = VK_NULL_HANDLE; + m_MS2ArrayPipe = VK_NULL_HANDLE; + m_TextDescSetLayout = VK_NULL_HANDLE; m_TextPipeLayout = VK_NULL_HANDLE; m_TextDescSet = VK_NULL_HANDLE; @@ -650,7 +656,7 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver, VkDevice dev) }; // declare a few more misc things that are needed on both paths - VkDescriptorBufferInfo bufInfo[6]; + VkDescriptorBufferInfo bufInfo[7]; RDCEraseEl(bufInfo); vector sources; @@ -1070,6 +1076,32 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver, VkDevice dev) RDCASSERTEQUAL(vkr, VK_SUCCESS); } + { + VkDescriptorSetLayoutBinding layoutBinding[] = { + { + 0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_ALL, NULL, + }, + { + 1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_ALL, NULL, + }, + { + 2, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_ALL, NULL, + }, + }; + + VkDescriptorSetLayoutCreateInfo descsetLayoutInfo = { + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, + NULL, + 0, + ARRAY_COUNT(layoutBinding), + &layoutBinding[0], + }; + + vkr = m_pDriver->vkCreateDescriptorSetLayout(dev, &descsetLayoutInfo, NULL, + &m_ArrayMSDescSetLayout); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + } + { VkDescriptorSetLayoutBinding layoutBinding[] = { { @@ -1229,6 +1261,11 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver, VkDevice dev) vkr = m_pDriver->vkCreatePipelineLayout(dev, &pipeLayoutInfo, NULL, &m_CheckerboardPipeLayout); RDCASSERTEQUAL(vkr, VK_SUCCESS); + pipeLayoutInfo.pSetLayouts = &m_ArrayMSDescSetLayout; + + vkr = m_pDriver->vkCreatePipelineLayout(dev, &pipeLayoutInfo, NULL, &m_ArrayMSPipeLayout); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + pipeLayoutInfo.pSetLayouts = &m_QuadDescSetLayout; vkr = m_pDriver->vkCreatePipelineLayout(dev, &pipeLayoutInfo, NULL, &m_QuadResolvePipeLayout); @@ -1258,6 +1295,10 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver, VkDevice dev) vkr = m_pDriver->vkAllocateDescriptorSets(dev, &descSetAllocInfo, &m_CheckerboardDescSet); RDCASSERTEQUAL(vkr, VK_SUCCESS); + descSetAllocInfo.pSetLayouts = &m_ArrayMSDescSetLayout; + vkr = m_pDriver->vkAllocateDescriptorSets(dev, &descSetAllocInfo, &m_ArrayMSDescSet); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + descSetAllocInfo.pSetLayouts = &m_TexDisplayDescSetLayout; for(size_t i = 0; i < ARRAY_COUNT(m_TexDisplayDescSet); i++) { @@ -1315,6 +1356,8 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver, VkDevice dev) RDCCOMPILE_ASSERT(sizeof(TexDisplayUBOData) <= 128, "tex display size"); + m_ArrayMSUBO.Create(driver, dev, 16, 1, 0); + string shaderSources[] = { GetEmbeddedResource(glsl_blit_vert), GetEmbeddedResource(glsl_checkerboard_frag), GetEmbeddedResource(glsl_texdisplay_frag), GetEmbeddedResource(glsl_mesh_vert), @@ -1322,13 +1365,13 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver, VkDevice dev) GetEmbeddedResource(glsl_minmaxtile_comp), GetEmbeddedResource(glsl_minmaxresult_comp), GetEmbeddedResource(glsl_histogram_comp), GetEmbeddedResource(glsl_outline_frag), GetEmbeddedResource(glsl_quadresolve_frag), GetEmbeddedResource(glsl_quadwrite_frag), - GetEmbeddedResource(glsl_mesh_comp), + GetEmbeddedResource(glsl_mesh_comp), GetEmbeddedResource(glsl_ms2array_comp), }; SPIRVShaderStage shaderStages[] = { eSPIRVVertex, eSPIRVFragment, eSPIRVFragment, eSPIRVVertex, eSPIRVGeometry, eSPIRVFragment, eSPIRVCompute, eSPIRVCompute, eSPIRVCompute, eSPIRVFragment, - eSPIRVFragment, eSPIRVFragment, eSPIRVCompute, + eSPIRVFragment, eSPIRVFragment, eSPIRVCompute, eSPIRVCompute, }; enum shaderIdx @@ -1346,6 +1389,7 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver, VkDevice dev) QUADRESOLVEFS, QUADWRITEFS, MESHCS, + MS2ARRAYCS, NUM_SHADERS, }; @@ -1642,8 +1686,6 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver, VkDevice dev) } } - m_CacheShaders = false; - { compPipeInfo.stage.module = module[MESHCS]; compPipeInfo.layout = m_MeshPickLayout; @@ -1653,6 +1695,17 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver, VkDevice dev) RDCASSERTEQUAL(vkr, VK_SUCCESS); } + { + compPipeInfo.stage.module = module[MS2ARRAYCS]; + compPipeInfo.layout = m_ArrayMSPipeLayout; + + vkr = m_pDriver->vkCreateComputePipelines(dev, VK_NULL_HANDLE, 1, &compPipeInfo, NULL, + &m_MS2ArrayPipe); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + } + + m_CacheShaders = false; + m_pDriver->vkDestroyRenderPass(dev, RGBA16RP, NULL); m_pDriver->vkDestroyRenderPass(dev, RGBA32RP, NULL); m_pDriver->vkDestroyRenderPass(dev, RGBA8RP, NULL); @@ -2062,6 +2115,7 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver, VkDevice dev) m_OverdrawRampUBO.FillDescriptor(bufInfo[3]); m_MeshPickUBO.FillDescriptor(bufInfo[4]); m_MeshPickResult.FillDescriptor(bufInfo[5]); + m_ArrayMSUBO.FillDescriptor(bufInfo[6]); VkWriteDescriptorSet analysisSetWrites[] = { {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, NULL, Unwrap(m_CheckerboardDescSet), 0, 0, 1, @@ -2076,6 +2130,8 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver, VkDevice dev) VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, NULL, &bufInfo[4], NULL}, {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, NULL, Unwrap(m_MeshPickDescSet), 3, 0, 1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, NULL, &bufInfo[5], NULL}, + {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, NULL, Unwrap(m_ArrayMSDescSet), 2, 0, 1, + VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, NULL, &bufInfo[6], NULL}, }; ObjDisp(dev)->UpdateDescriptorSets(Unwrap(dev), ARRAY_COUNT(analysisSetWrites), analysisSetWrites, @@ -2161,6 +2217,12 @@ VulkanDebugManager::~VulkanDebugManager() m_pDriver->vkDestroyImage(dev, m_PickPixelImage, NULL); m_pDriver->vkFreeMemory(dev, m_PickPixelImageMem, NULL); + m_pDriver->vkDestroyDescriptorSetLayout(dev, m_ArrayMSDescSetLayout, NULL); + m_pDriver->vkDestroyPipelineLayout(dev, m_ArrayMSPipeLayout, NULL); + m_pDriver->vkDestroyPipeline(dev, m_Array2MSPipe, NULL); + m_pDriver->vkDestroyPipeline(dev, m_MS2ArrayPipe, NULL); + m_ArrayMSUBO.Destroy(); + m_pDriver->vkDestroyDescriptorSetLayout(dev, m_TextDescSetLayout, NULL); m_pDriver->vkDestroyPipelineLayout(dev, m_TextPipeLayout, NULL); m_pDriver->vkDestroyPipeline(dev, m_TextPipeline[0], NULL); @@ -2762,6 +2824,127 @@ void VulkanDebugManager::CreateCustomShaderPipeline(ResourceId shader) RDCASSERTEQUAL(vkr, VK_SUCCESS); } +void VulkanDebugManager::CopyTex2DMSToArray(VkImage destArray, VkImage srcMS, VkExtent3D extent, + uint32_t layers, uint32_t samples, VkFormat fmt) +{ + if(!m_pDriver->GetDeviceFeatures().shaderStorageImageMultisample || + !m_pDriver->GetDeviceFeatures().shaderStorageImageWriteWithoutFormat) + return; + + if(m_MS2ArrayPipe == VK_NULL_HANDLE) + return; + + VkDevice dev = m_Device; + + VkResult vkr = VK_SUCCESS; + + VkImageView srcView, destView; + + VkImageViewCreateInfo viewInfo = { + VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, + NULL, + 0, + srcMS, + VK_IMAGE_VIEW_TYPE_2D, + VK_FORMAT_UNDEFINED, + {VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, + VK_COMPONENT_SWIZZLE_IDENTITY}, + { + VK_IMAGE_ASPECT_COLOR_BIT, 0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS, + }, + }; + + uint32_t bs = GetByteSize(1, 1, 1, fmt, 0); + + if(bs == 1) + viewInfo.format = VK_FORMAT_R8_UINT; + else if(bs == 2) + viewInfo.format = VK_FORMAT_R16_UINT; + else if(bs == 4) + viewInfo.format = VK_FORMAT_R32_UINT; + else if(bs == 8) + viewInfo.format = VK_FORMAT_R32G32_UINT; + else if(bs == 16) + viewInfo.format = VK_FORMAT_R32G32B32A32_UINT; + + if(viewInfo.format == VK_FORMAT_UNDEFINED) + { + RDCERR("Can't copy 2D to Array with format %s", ToStr::Get(fmt).c_str()); + return; + } + + if(IsStencilOnlyFormat(fmt)) + viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT; + else if(IsDepthOrStencilFormat(fmt)) + viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + + vkr = ObjDisp(dev)->CreateImageView(Unwrap(dev), &viewInfo, NULL, &srcView); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + + viewInfo.image = destArray; + viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY; + + vkr = ObjDisp(dev)->CreateImageView(Unwrap(dev), &viewInfo, NULL, &destView); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + + VkDescriptorImageInfo srcdesc = {0}; + srcdesc.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + srcdesc.imageView = srcView; + srcdesc.sampler = Unwrap(m_PointSampler); // not used + + VkDescriptorImageInfo destdesc = {0}; + destdesc.imageLayout = VK_IMAGE_LAYOUT_GENERAL; + destdesc.imageView = destView; + destdesc.sampler = Unwrap(m_PointSampler); // not used + + VkWriteDescriptorSet writeSet[] = { + {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, NULL, Unwrap(m_ArrayMSDescSet), 0, 0, 1, + VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &srcdesc, NULL, NULL}, + {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, NULL, Unwrap(m_ArrayMSDescSet), 1, 0, 1, + VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &destdesc, NULL, NULL}, + }; + + ObjDisp(dev)->UpdateDescriptorSets(Unwrap(dev), ARRAY_COUNT(writeSet), writeSet, 0, NULL); + + uint32_t *data = (uint32_t *)m_ArrayMSUBO.Map(NULL); + *data = samples; + m_ArrayMSUBO.Unmap(); + + VkCommandBuffer cmd = m_pDriver->GetNextCmd(); + + VkCommandBufferBeginInfo beginInfo = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, NULL, + VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT}; + + ObjDisp(cmd)->BeginCommandBuffer(Unwrap(cmd), &beginInfo); + + ObjDisp(cmd)->CmdBindPipeline(Unwrap(cmd), VK_PIPELINE_BIND_POINT_COMPUTE, Unwrap(m_MS2ArrayPipe)); + ObjDisp(cmd)->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_COMPUTE, + Unwrap(m_ArrayMSPipeLayout), 0, 1, + UnwrapPtr(m_ArrayMSDescSet), 0, NULL); + + ObjDisp(cmd)->CmdDispatch(Unwrap(cmd), extent.width, extent.height, layers * samples); + + ObjDisp(cmd)->EndCommandBuffer(Unwrap(cmd)); + + // submit cmds and wait for idle so we can readback + m_pDriver->SubmitCmds(); + m_pDriver->FlushQ(); + + ObjDisp(dev)->DestroyImageView(Unwrap(dev), srcView, NULL); + ObjDisp(dev)->DestroyImageView(Unwrap(dev), destView, NULL); +} + +void VulkanDebugManager::CopyArrayToTex2DMS(VkImage destMS, VkImage srcArray, VkExtent3D extent, + uint32_t layers, uint32_t samples, VkFormat fmt) +{ + if(!m_pDriver->GetDeviceFeatures().shaderStorageImageMultisample || + !m_pDriver->GetDeviceFeatures().shaderStorageImageWriteWithoutFormat) + return; + + if(m_Array2MSPipe == VK_NULL_HANDLE) + return; +} + FloatVector VulkanDebugManager::InterpretVertex(byte *data, uint32_t vert, const MeshDisplay &cfg, byte *end, bool &valid) { diff --git a/renderdoc/driver/vulkan/vk_debug.h b/renderdoc/driver/vulkan/vk_debug.h index 24ad09da0..5d02ac6e9 100644 --- a/renderdoc/driver/vulkan/vk_debug.h +++ b/renderdoc/driver/vulkan/vk_debug.h @@ -126,6 +126,11 @@ public: uint32_t PickVertex(uint32_t eventID, const MeshDisplay &cfg, uint32_t x, uint32_t y, uint32_t w, uint32_t h); + void CopyTex2DMSToArray(VkImage destArray, VkImage srcMS, VkExtent3D extent, uint32_t layers, + uint32_t samples, VkFormat fmt); + void CopyArrayToTex2DMS(VkImage destMS, VkImage srcArray, VkExtent3D extent, uint32_t layers, + uint32_t samples, VkFormat fmt); + void CreateCustomShaderTex(uint32_t width, uint32_t height, uint32_t mip); void CreateCustomShaderPipeline(ResourceId shader); @@ -229,6 +234,13 @@ public: VkFramebuffer m_PickPixelFB; VkRenderPass m_PickPixelRP; + VkDescriptorSetLayout m_ArrayMSDescSetLayout; + VkPipelineLayout m_ArrayMSPipeLayout; + VkDescriptorSet m_ArrayMSDescSet; + VkPipeline m_Array2MSPipe; + VkPipeline m_MS2ArrayPipe; + GPUBuffer m_ArrayMSUBO; + VkDescriptorSetLayout m_TextDescSetLayout; VkPipelineLayout m_TextPipeLayout; VkDescriptorSet m_TextDescSet; diff --git a/renderdoc/driver/vulkan/vk_replay.cpp b/renderdoc/driver/vulkan/vk_replay.cpp index 315774d0c..05bea464b 100644 --- a/renderdoc/driver/vulkan/vk_replay.cpp +++ b/renderdoc/driver/vulkan/vk_replay.cpp @@ -4928,7 +4928,109 @@ byte *VulkanReplay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t m else if(wasms) { // copy/expand multisampled live texture to array readback texture - RDCUNIMPLEMENTED("Saving multisampled textures directly as arrays"); + + // multiply array layers by sample count + uint32_t numSamples = (uint32_t)imInfo.samples; + imCreateInfo.arrayLayers *= numSamples; + imCreateInfo.mipLevels = 1; + imCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; + imCreateInfo.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT; + imCreateInfo.usage |= VK_IMAGE_USAGE_STORAGE_BIT; + + // create resolve texture + vt->CreateImage(Unwrap(dev), &imCreateInfo, NULL, &tmpImage); + + VkMemoryRequirements mrq = {0}; + vt->GetImageMemoryRequirements(Unwrap(dev), tmpImage, &mrq); + + VkMemoryAllocateInfo allocInfo = { + VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, NULL, mrq.size, + m_pDriver->GetGPULocalMemoryIndex(mrq.memoryTypeBits), + }; + + vkr = vt->AllocateMemory(Unwrap(dev), &allocInfo, NULL, &tmpMemory); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + + vkr = vt->BindImageMemory(Unwrap(dev), tmpImage, tmpMemory, 0); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + + VkImageMemoryBarrier srcimBarrier = { + VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + NULL, + 0, + 0, + VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_QUEUE_FAMILY_IGNORED, + VK_QUEUE_FAMILY_IGNORED, + srcImage, + {srcAspectMask, 0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS}}; + + VkImageMemoryBarrier dstimBarrier = { + VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + NULL, + 0, + 0, + VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_GENERAL, + 0, + 0, // MULTIDEVICE - need to actually pick the right queue family here maybe? + tmpImage, + {srcAspectMask, 0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS}}; + + // ensure all previous writes have completed + srcimBarrier.srcAccessMask = VK_ACCESS_ALL_WRITE_BITS; + // before we go copying to array + srcimBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + + for(size_t si = 0; si < layouts.subresourceStates.size(); si++) + { + srcimBarrier.subresourceRange = layouts.subresourceStates[si].subresourceRange; + srcimBarrier.oldLayout = layouts.subresourceStates[si].newLayout; + DoPipelineBarrier(cmd, 1, &srcimBarrier); + } + + srcimBarrier.oldLayout = srcimBarrier.newLayout; + + srcimBarrier.srcAccessMask = 0; + srcimBarrier.dstAccessMask = 0; + + // move tmp image into transfer destination layout + DoPipelineBarrier(cmd, 1, &dstimBarrier); + + vkr = vt->EndCommandBuffer(Unwrap(cmd)); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + + // expand multisamples out to array + GetDebugManager()->CopyTex2DMSToArray(tmpImage, srcImage, imCreateInfo.extent, + imCreateInfo.arrayLayers, numSamples, imCreateInfo.format); + + // fetch a new command buffer for copy & readback + cmd = m_pDriver->GetNextCmd(); + + vkr = vt->BeginCommandBuffer(Unwrap(cmd), &beginInfo); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + + srcimBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; + + // image layout back to normal + for(size_t si = 0; si < layouts.subresourceStates.size(); si++) + { + srcimBarrier.subresourceRange = layouts.subresourceStates[si].subresourceRange; + srcimBarrier.newLayout = layouts.subresourceStates[si].newLayout; + srcimBarrier.dstAccessMask = MakeAccessMask(srcimBarrier.newLayout); + DoPipelineBarrier(cmd, 1, &srcimBarrier); + } + + // wait for copy to finish before copy to buffer + dstimBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; + dstimBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + dstimBarrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL; + dstimBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + + DoPipelineBarrier(cmd, 1, &dstimBarrier); + + srcImage = tmpImage; } VkImageMemoryBarrier srcimBarrier = { diff --git a/renderdoc/driver/vulkan/vk_resources.cpp b/renderdoc/driver/vulkan/vk_resources.cpp index 5015df3ab..f22997509 100644 --- a/renderdoc/driver/vulkan/vk_resources.cpp +++ b/renderdoc/driver/vulkan/vk_resources.cpp @@ -208,6 +208,19 @@ bool IsDepthOrStencilFormat(VkFormat f) return false; } +bool IsDepthAndStencilFormat(VkFormat f) +{ + switch(f) + { + case VK_FORMAT_D16_UNORM_S8_UINT: + case VK_FORMAT_X8_D24_UNORM_PACK32: + case VK_FORMAT_D32_SFLOAT_S8_UINT: return true; + default: break; + } + + return false; +} + bool IsStencilFormat(VkFormat f) { switch(f) @@ -222,19 +235,6 @@ bool IsStencilFormat(VkFormat f) return false; } -VkFormat GetDepthOnlyFormat(VkFormat f) -{ - switch(f) - { - case VK_FORMAT_D16_UNORM_S8_UINT: return VK_FORMAT_D16_UNORM; - case VK_FORMAT_D24_UNORM_S8_UINT: return VK_FORMAT_X8_D24_UNORM_PACK32; - case VK_FORMAT_D32_SFLOAT_S8_UINT: return VK_FORMAT_D32_SFLOAT; - default: break; - } - - return f; -} - bool IsDepthOnlyFormat(VkFormat f) { switch(f) @@ -360,6 +360,118 @@ bool IsSIntFormat(VkFormat f) return false; } +VkFormat GetDepthOnlyFormat(VkFormat f) +{ + switch(f) + { + case VK_FORMAT_D16_UNORM_S8_UINT: return VK_FORMAT_D16_UNORM; + case VK_FORMAT_D24_UNORM_S8_UINT: return VK_FORMAT_X8_D24_UNORM_PACK32; + case VK_FORMAT_D32_SFLOAT_S8_UINT: return VK_FORMAT_D32_SFLOAT; + default: break; + } + + return f; +} + +VkFormat GetUIntTypedFormat(VkFormat f) +{ + switch(f) + { + case VK_FORMAT_R8_UNORM: + case VK_FORMAT_R8_SNORM: + case VK_FORMAT_R8_USCALED: + case VK_FORMAT_R8_SSCALED: + case VK_FORMAT_R8_SINT: + case VK_FORMAT_R8_SRGB: return VK_FORMAT_R8_UINT; + case VK_FORMAT_R8G8_UNORM: + case VK_FORMAT_R8G8_SNORM: + case VK_FORMAT_R8G8_USCALED: + case VK_FORMAT_R8G8_SSCALED: + case VK_FORMAT_R8G8_SINT: + case VK_FORMAT_R8G8_SRGB: return VK_FORMAT_R8G8_UINT; + case VK_FORMAT_R8G8B8_UNORM: + case VK_FORMAT_R8G8B8_SNORM: + case VK_FORMAT_R8G8B8_USCALED: + case VK_FORMAT_R8G8B8_SSCALED: + case VK_FORMAT_R8G8B8_SINT: + case VK_FORMAT_R8G8B8_SRGB: return VK_FORMAT_R8G8B8_UINT; + case VK_FORMAT_R8G8B8A8_UNORM: + case VK_FORMAT_R8G8B8A8_SNORM: + case VK_FORMAT_R8G8B8A8_USCALED: + case VK_FORMAT_R8G8B8A8_SSCALED: + case VK_FORMAT_R8G8B8A8_SINT: + case VK_FORMAT_R8G8B8A8_SRGB: return VK_FORMAT_R8G8B8A8_UINT; + case VK_FORMAT_B8G8R8_UNORM: + case VK_FORMAT_B8G8R8_SNORM: + case VK_FORMAT_B8G8R8_USCALED: + case VK_FORMAT_B8G8R8_SSCALED: + case VK_FORMAT_B8G8R8_SINT: + case VK_FORMAT_B8G8R8_SRGB: return VK_FORMAT_B8G8R8_UINT; + case VK_FORMAT_B8G8R8A8_UNORM: + case VK_FORMAT_B8G8R8A8_SNORM: + case VK_FORMAT_B8G8R8A8_USCALED: + case VK_FORMAT_B8G8R8A8_SSCALED: + case VK_FORMAT_B8G8R8A8_SINT: + case VK_FORMAT_B8G8R8A8_SRGB: return VK_FORMAT_B8G8R8A8_UINT; + case VK_FORMAT_A8B8G8R8_UNORM_PACK32: + case VK_FORMAT_A8B8G8R8_SNORM_PACK32: + case VK_FORMAT_A8B8G8R8_USCALED_PACK32: + case VK_FORMAT_A8B8G8R8_SSCALED_PACK32: + case VK_FORMAT_A8B8G8R8_SINT_PACK32: + case VK_FORMAT_A8B8G8R8_SRGB_PACK32: return VK_FORMAT_A8B8G8R8_UINT_PACK32; + case VK_FORMAT_A2R10G10B10_UNORM_PACK32: + case VK_FORMAT_A2R10G10B10_SNORM_PACK32: + case VK_FORMAT_A2R10G10B10_USCALED_PACK32: + case VK_FORMAT_A2R10G10B10_SSCALED_PACK32: + case VK_FORMAT_A2R10G10B10_SINT_PACK32: return VK_FORMAT_A2R10G10B10_UINT_PACK32; + case VK_FORMAT_A2B10G10R10_UNORM_PACK32: + case VK_FORMAT_A2B10G10R10_SNORM_PACK32: + case VK_FORMAT_A2B10G10R10_USCALED_PACK32: + case VK_FORMAT_A2B10G10R10_SSCALED_PACK32: + case VK_FORMAT_A2B10G10R10_SINT_PACK32: return VK_FORMAT_A2B10G10R10_UINT_PACK32; + case VK_FORMAT_R16_UNORM: + case VK_FORMAT_R16_SNORM: + case VK_FORMAT_R16_USCALED: + case VK_FORMAT_R16_SSCALED: + case VK_FORMAT_R16_SINT: return VK_FORMAT_R16_UINT; + case VK_FORMAT_R16G16_UNORM: + case VK_FORMAT_R16G16_SNORM: + case VK_FORMAT_R16G16_USCALED: + case VK_FORMAT_R16G16_SSCALED: + case VK_FORMAT_R16G16_SINT: return VK_FORMAT_R16G16_UINT; + case VK_FORMAT_R16G16B16_UNORM: + case VK_FORMAT_R16G16B16_SNORM: + case VK_FORMAT_R16G16B16_USCALED: + case VK_FORMAT_R16G16B16_SSCALED: + case VK_FORMAT_R16G16B16_SINT: return VK_FORMAT_R16G16B16_UINT; + case VK_FORMAT_R16G16B16A16_UNORM: + case VK_FORMAT_R16G16B16A16_SNORM: + case VK_FORMAT_R16G16B16A16_USCALED: + case VK_FORMAT_R16G16B16A16_SSCALED: + case VK_FORMAT_R16G16B16A16_SINT: return VK_FORMAT_R16G16B16A16_UINT; + case VK_FORMAT_R32_SINT: + case VK_FORMAT_R32_SFLOAT: return VK_FORMAT_R32_UINT; + case VK_FORMAT_R32G32_SINT: + case VK_FORMAT_R32G32_SFLOAT: return VK_FORMAT_R32G32_UINT; + case VK_FORMAT_R32G32B32_SINT: + case VK_FORMAT_R32G32B32_SFLOAT: return VK_FORMAT_R32G32B32_UINT; + case VK_FORMAT_R32G32B32A32_SINT: + case VK_FORMAT_R32G32B32A32_SFLOAT: return VK_FORMAT_R32G32B32A32_UINT; + case VK_FORMAT_R64_SINT: + case VK_FORMAT_R64_SFLOAT: return VK_FORMAT_R64_UINT; + case VK_FORMAT_R64G64_SINT: + case VK_FORMAT_R64G64_SFLOAT: return VK_FORMAT_R64G64_UINT; + case VK_FORMAT_R64G64B64_SINT: + case VK_FORMAT_R64G64B64_SFLOAT: return VK_FORMAT_R64G64B64_UINT; + case VK_FORMAT_R64G64B64A64_SINT: + case VK_FORMAT_R64G64B64A64_SFLOAT: return VK_FORMAT_R64G64B64A64_UINT; + case VK_FORMAT_S8_UINT: return VK_FORMAT_S8_UINT; + default: break; + } + + return f; +} + uint32_t GetByteSize(uint32_t Width, uint32_t Height, uint32_t Depth, VkFormat Format, uint32_t mip) { uint32_t w = RDCMAX(Width >> mip, 1U); diff --git a/renderdoc/driver/vulkan/vk_resources.h b/renderdoc/driver/vulkan/vk_resources.h index 5a0187190..18d522b35 100644 --- a/renderdoc/driver/vulkan/vk_resources.h +++ b/renderdoc/driver/vulkan/vk_resources.h @@ -1066,6 +1066,7 @@ struct ImageLayouts bool IsBlockFormat(VkFormat f); bool IsDepthOrStencilFormat(VkFormat f); +bool IsDepthAndStencilFormat(VkFormat f); bool IsDepthOnlyFormat(VkFormat f); bool IsStencilFormat(VkFormat f); bool IsStencilOnlyFormat(VkFormat f); @@ -1074,5 +1075,6 @@ bool IsUIntFormat(VkFormat f); bool IsSIntFormat(VkFormat f); VkFormat GetDepthOnlyFormat(VkFormat f); +VkFormat GetUIntTypedFormat(VkFormat f); uint32_t GetByteSize(uint32_t Width, uint32_t Height, uint32_t Depth, VkFormat Format, uint32_t mip); diff --git a/renderdoc/driver/vulkan/wrappers/vk_device_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_device_funcs.cpp index b52b52abc..2fb16754b 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_device_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_device_funcs.cpp @@ -933,6 +933,13 @@ bool WrappedVulkan::Serialise_vkCreateDevice(Serialiser *localSerialiser, else RDCWARN("vertexPipelineStoresAndAtomics = false, output mesh data will not be available"); + if(availFeatures.shaderStorageImageWriteWithoutFormat) + enabledFeatures.shaderStorageImageWriteWithoutFormat = true; + else + RDCWARN( + "shaderStorageImageWriteWithoutFormat = false, save/load from 2DMS textures will not be " + "possible"); + uint32_t numExts = 0; VkResult vkr = diff --git a/renderdoc/driver/vulkan/wrappers/vk_resource_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_resource_funcs.cpp index 2c50339a3..6833e7161 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_resource_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_resource_funcs.cpp @@ -988,6 +988,10 @@ bool WrappedVulkan::Serialise_vkCreateImage(Serialiser *localSerialiser, VkDevic info.usage |= VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; + // ensure we can cast multisampled images, for copying to arrays + if((int)info.samples > 1) + info.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT; + VkResult ret = ObjDisp(device)->CreateImage(Unwrap(device), &info, NULL, &img); info.usage = origusage;