From 22d58cf7393ccefd0264114a088ff5ab038ff1df Mon Sep 17 00:00:00 2001 From: baldurk Date: Thu, 9 Jun 2016 10:48:44 -0700 Subject: [PATCH] Implement custom display shaders for vulkan --- docs/how/how_custom_visualisation.rst | 58 ++++- renderdoc/driver/vulkan/vk_debug.cpp | 342 +++++++++++++++++++++++++- renderdoc/driver/vulkan/vk_debug.h | 14 ++ renderdoc/driver/vulkan/vk_replay.cpp | 180 ++++++++++++-- renderdocui/Windows/ShaderViewer.cs | 41 ++- 5 files changed, 604 insertions(+), 31 deletions(-) diff --git a/docs/how/how_custom_visualisation.rst b/docs/how/how_custom_visualisation.rst index c036b7b8d..698d1326f 100644 --- a/docs/how/how_custom_visualisation.rst +++ b/docs/how/how_custom_visualisation.rst @@ -44,6 +44,24 @@ This input is defined as two parameters to the shader entry point. The first def You must bind these parameters like this in this order to ensure the linkage with the vertex shader matches. +Constant Parameters +``````````````````` + +There are several constant parameters available, each detailed below with the values they contain. Where possible these are bound by name as globals for convenience, but in Vulkan all variables must be contained within a single uniform buffer. The parameters correspond with the GLSL documentation but are contained within a uniform buffer at binding 0, with a structure given as so: + + +.. highlight:: c++ +.. code:: c++ + + layout(binding = 0, std140) uniform RENDERDOC_Uniforms + { + uvec4 TexDim; + uint SelectedMip; + uint TextureType; + } RENDERDOC; + +In this way you can access the properties as ``RENDERDOC.TexDim`` insetad of ``RENDERDOC_TexDim``. + Texture dimensions `````````````````` @@ -84,7 +102,7 @@ This variable will be set to a given integer value, depending on the type of the .. note:: - The value varies depending on whether this is an HLSL shader or GLSL, as they have different resource types. + The value varies depending on the API this shader will be used for, as each has different resource bindings. D3D11 / HLSL ^^^^^^^^^^^^ @@ -113,6 +131,14 @@ OpenGL / GLSL #. Buffer texture #. 2D texture (Multisampled) +Vulkan / GLSL +^^^^^^^^^^^^^ + +#. 1D texture +#. 2D texture +#. 3D texture +#. 2D texture (Multisampled) + Samplers (D3D11 only) ````````````````````` @@ -195,6 +221,36 @@ OpenGL / GLSL layout (binding = 9) uniform samplerBuffer texBuffer; layout (binding = 10) uniform sampler2DMS tex2DMS; +Vulkan / GLSL +^^^^^^^^^^^^^ + +.. highlight:: c++ +.. code:: c++ + + // Floating point samplers + + // binding = 5 + RENDERDOC_TextureType + layout(binding = 6) uniform sampler1DArray tex1DArray; + layout(binding = 7) uniform sampler2DArray tex2DArray; + layout(binding = 8) uniform sampler3D tex3D; + layout(binding = 9) uniform sampler2DMS tex2DMS; + + // Unsigned int samplers + + // binding = 10 + RENDERDOC_TextureType + layout(binding = 11) uniform usampler1DArray texUInt1DArray; + layout(binding = 12) uniform usampler2DArray texUInt2DArray; + layout(binding = 13) uniform usampler3D texUInt3D; + layout(binding = 14) uniform usampler2DMS texUInt2DMS; + + // Int samplers + + // binding = 15 + RENDERDOC_TextureType + layout(binding = 16) uniform isampler1DArray texSInt1DArray; + layout(binding = 17) uniform isampler2DArray texSInt2DArray; + layout(binding = 18) uniform isampler3D texSInt3D; + layout(binding = 19) uniform isampler2DMS texSInt2DMS; + These resources are bound sparsely with the appropriate type for the current texture. With a couple of exceptions there will only be one texture bound at any one time. diff --git a/renderdoc/driver/vulkan/vk_debug.cpp b/renderdoc/driver/vulkan/vk_debug.cpp index e13391313..a4a23f16f 100644 --- a/renderdoc/driver/vulkan/vk_debug.cpp +++ b/renderdoc/driver/vulkan/vk_debug.cpp @@ -253,6 +253,15 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver, VkDevice dev) RDCEraseEl(m_TexDisplayDummyInfos); m_TexDisplayDummyMemory = VK_NULL_HANDLE; + m_CustomTexWidth = m_CustomTexHeight = 0; + m_CustomTexImg = VK_NULL_HANDLE; + m_CustomTexImgView = VK_NULL_HANDLE; + m_CustomTexMemSize = 0; + m_CustomTexMem = VK_NULL_HANDLE; + m_CustomTexFB = VK_NULL_HANDLE; + m_CustomTexRP = VK_NULL_HANDLE; + m_CustomTexPipeline = VK_NULL_HANDLE; + m_PickPixelImageMem = VK_NULL_HANDLE; m_PickPixelImage = VK_NULL_HANDLE; m_PickPixelImageView = VK_NULL_HANDLE; @@ -1653,8 +1662,7 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver, VkDevice dev) for(size_t i = 0; i < ARRAY_COUNT(module); i++) { - // hold onto the mesh shaders/modules as we create these - // pipelines later + // hold onto the shaders/modules we use later if(i == MESHVS) { m_MeshModules[0] = module[i]; @@ -1667,6 +1675,10 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver, VkDevice dev) { m_MeshModules[2] = module[i]; } + else if(i == BLITVS) + { + m_BlitVSModule = module[i]; + } else if(i == HISTOGRAMCS || i == MINMAXTILECS || i == MINMAXRESULTCS) { // not compiled normally @@ -2133,6 +2145,13 @@ VulkanDebugManager::~VulkanDebugManager() m_pDriver->vkFreeMemory(dev, m_TexDisplayDummyMemory, NULL); + m_pDriver->vkDestroyRenderPass(dev, m_CustomTexRP, NULL); + m_pDriver->vkDestroyFramebuffer(dev, m_CustomTexFB, NULL); + m_pDriver->vkDestroyImage(dev, m_CustomTexImg, NULL); + m_pDriver->vkDestroyImageView(dev, m_CustomTexImgView, NULL); + m_pDriver->vkFreeMemory(dev, m_CustomTexMem, NULL); + m_pDriver->vkDestroyPipeline(dev, m_CustomTexPipeline, NULL); + m_CheckerboardUBO.Destroy(); m_TexDisplayUBO.Destroy(); @@ -2300,6 +2319,325 @@ void VulkanDebugManager::RenderTextInternal(const TextPrintState &textstate, flo ObjDisp(textstate.cmd)->CmdDraw(Unwrap(textstate.cmd), 4, (uint32_t)strlen(text), 0, 0); } +void VulkanDebugManager::CreateCustomShaderTex(uint32_t width, uint32_t height) +{ + VkDevice dev = m_Device; + + if(m_CustomTexImg != VK_NULL_HANDLE) + { + if(width == m_CustomTexWidth && height == m_CustomTexHeight) + return; + + m_pDriver->vkDestroyRenderPass(dev, m_CustomTexRP, NULL); + m_pDriver->vkDestroyFramebuffer(dev, m_CustomTexFB, NULL); + m_pDriver->vkDestroyImageView(dev, m_CustomTexImgView, NULL); + m_pDriver->vkDestroyImage(dev, m_CustomTexImg, NULL); + } + + m_CustomTexWidth = width; + m_CustomTexHeight = height; + + VkResult vkr = VK_SUCCESS; + + VkImageCreateInfo imInfo = { + VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, + NULL, + 0, + VK_IMAGE_TYPE_2D, + VK_FORMAT_R16G16B16A16_SFLOAT, + {width, height, 1}, + 1, + 1, + VK_SAMPLE_COUNT_1_BIT, + VK_IMAGE_TILING_OPTIMAL, + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | + VK_IMAGE_USAGE_TRANSFER_SRC_BIT, + VK_SHARING_MODE_EXCLUSIVE, + 0, + NULL, + VK_IMAGE_LAYOUT_UNDEFINED, + }; + + vkr = m_pDriver->vkCreateImage(m_Device, &imInfo, NULL, &m_CustomTexImg); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + + VkMemoryRequirements mrq; + m_pDriver->vkGetImageMemoryRequirements(m_Device, m_CustomTexImg, &mrq); + + // if no memory is allocated, or it's not enough, + // then allocate + if(m_CustomTexMem == VK_NULL_HANDLE || mrq.size > m_CustomTexMemSize) + { + if(m_CustomTexMem != VK_NULL_HANDLE) + m_pDriver->vkFreeMemory(m_Device, m_CustomTexMem, NULL); + + VkMemoryAllocateInfo allocInfo = { + VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, NULL, mrq.size, + m_pDriver->GetGPULocalMemoryIndex(mrq.memoryTypeBits), + }; + + vkr = m_pDriver->vkAllocateMemory(m_Device, &allocInfo, NULL, &m_CustomTexMem); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + + m_CustomTexMemSize = mrq.size; + } + + vkr = m_pDriver->vkBindImageMemory(m_Device, m_CustomTexImg, m_CustomTexMem, 0); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + + VkImageViewCreateInfo viewInfo = { + VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, + NULL, + 0, + m_CustomTexImg, + VK_IMAGE_VIEW_TYPE_2D, + imInfo.format, + {VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, + VK_COMPONENT_SWIZZLE_IDENTITY}, + { + VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1, + }, + }; + + vkr = m_pDriver->vkCreateImageView(m_Device, &viewInfo, NULL, &m_CustomTexImgView); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + + // need to update image layout into valid state + + VkImageMemoryBarrier barrier = { + VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + NULL, + 0, + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + 0, + 0, // MULTIDEVICE - need to actually pick the right queue family here maybe? + Unwrap(m_CustomTexImg), + {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}}; + + m_pDriver->m_ImageLayouts[GetResID(m_CustomTexImg)].subresourceStates[0].newLayout = + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + VkCommandBuffer cmd = m_pDriver->GetNextCmd(); + + VkCommandBufferBeginInfo beginInfo = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, NULL, + VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT}; + + ObjDisp(dev)->BeginCommandBuffer(Unwrap(cmd), &beginInfo); + + DoPipelineBarrier(cmd, 1, &barrier); + + vkr = ObjDisp(dev)->EndCommandBuffer(Unwrap(cmd)); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + +#if defined(SINGLE_FLUSH_VALIDATE) + m_pDriver->SubmitCmds(); +#endif + + VkAttachmentDescription colDesc = {0, + imInfo.format, + imInfo.samples, + VK_ATTACHMENT_LOAD_OP_LOAD, + VK_ATTACHMENT_STORE_OP_STORE, + VK_ATTACHMENT_LOAD_OP_DONT_CARE, + VK_ATTACHMENT_STORE_OP_DONT_CARE, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; + + VkAttachmentReference colRef = {0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; + + VkSubpassDescription sub = { + 0, VK_PIPELINE_BIND_POINT_GRAPHICS, + 0, NULL, // inputs + 1, &colRef, // color + NULL, // resolve + NULL, // depth-stencil + 0, NULL, // preserve + }; + + VkRenderPassCreateInfo rpinfo = { + VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, + NULL, + 0, + 1, + &colDesc, + 1, + &sub, + 0, + NULL, // dependencies + }; + + vkr = m_pDriver->vkCreateRenderPass(m_Device, &rpinfo, NULL, &m_CustomTexRP); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + + // Create framebuffer rendering just to overlay image, no depth + VkFramebufferCreateInfo fbinfo = { + VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, + NULL, + 0, + m_CustomTexRP, + 1, + &m_CustomTexImgView, + width, + height, + 1, + }; + + vkr = m_pDriver->vkCreateFramebuffer(m_Device, &fbinfo, NULL, &m_CustomTexFB); + RDCASSERTEQUAL(vkr, VK_SUCCESS); +} + +void VulkanDebugManager::CreateCustomShaderPipeline(ResourceId shader) +{ + VkDevice dev = m_Device; + + if(shader == ResourceId()) + return; + + if(m_CustomTexPipeline != VK_NULL_HANDLE) + { + if(m_CustomTexShader == shader) + return; + + m_pDriver->vkDestroyPipeline(dev, m_CustomTexPipeline, NULL); + } + + m_CustomTexShader = shader; + + // declare the pipeline creation info and all of its sub-structures + // these are modified as appropriate for each pipeline we create + VkPipelineShaderStageCreateInfo stages[2] = { + {VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, NULL, 0, VK_SHADER_STAGE_VERTEX_BIT, + m_BlitVSModule, "main", NULL}, + {VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, NULL, 0, VK_SHADER_STAGE_FRAGMENT_BIT, + GetResourceManager()->GetCurrentHandle(shader), "main", NULL}, + }; + + VkPipelineVertexInputStateCreateInfo vi = { + VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, + NULL, + 0, + 0, + NULL, // vertex bindings + 0, + NULL, // vertex attributes + }; + + VkPipelineInputAssemblyStateCreateInfo ia = { + VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, + NULL, + 0, + VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, + false, + }; + + VkRect2D scissor = {{0, 0}, {4096, 4096}}; + + VkPipelineViewportStateCreateInfo vp = { + VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, NULL, 0, 1, NULL, 1, &scissor}; + + VkPipelineRasterizationStateCreateInfo rs = { + VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, + NULL, + 0, + true, + false, + VK_POLYGON_MODE_FILL, + VK_CULL_MODE_NONE, + VK_FRONT_FACE_CLOCKWISE, + false, + 0.0f, + 0.0f, + 0.0f, + 1.0f, + }; + + VkPipelineMultisampleStateCreateInfo msaa = { + VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, + NULL, + 0, + VK_SAMPLE_COUNT_1_BIT, + false, + 0.0f, + NULL, + false, + false, + }; + + VkPipelineDepthStencilStateCreateInfo ds = { + VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, + NULL, + 0, + false, + false, + VK_COMPARE_OP_ALWAYS, + false, + false, + {VK_STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP, VK_COMPARE_OP_ALWAYS, 0, 0, 0}, + {VK_STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP, VK_COMPARE_OP_ALWAYS, 0, 0, 0}, + 0.0f, + 1.0f, + }; + + VkPipelineColorBlendAttachmentState attState = { + false, + VK_BLEND_FACTOR_ONE, + VK_BLEND_FACTOR_ZERO, + VK_BLEND_OP_ADD, + VK_BLEND_FACTOR_ONE, + VK_BLEND_FACTOR_ZERO, + VK_BLEND_OP_ADD, + 0xf, + }; + + VkPipelineColorBlendStateCreateInfo cb = { + VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, + NULL, + 0, + false, + VK_LOGIC_OP_NO_OP, + 1, + &attState, + {1.0f, 1.0f, 1.0f, 1.0f}}; + + VkDynamicState dynstates[] = {VK_DYNAMIC_STATE_VIEWPORT}; + + VkPipelineDynamicStateCreateInfo dyn = { + VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, + NULL, + 0, + ARRAY_COUNT(dynstates), + dynstates, + }; + + VkGraphicsPipelineCreateInfo pipeInfo = { + VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, + NULL, + 0, + 2, + stages, + &vi, + &ia, + NULL, // tess + &vp, + &rs, + &msaa, + &ds, + &cb, + &dyn, + m_TexDisplayPipeLayout, + m_CustomTexRP, + 0, // sub pass + VK_NULL_HANDLE, // base pipeline handle + -1, // base pipeline index + }; + + VkResult vkr = m_pDriver->vkCreateGraphicsPipelines(dev, VK_NULL_HANDLE, 1, &pipeInfo, NULL, + &m_CustomTexPipeline); + RDCASSERTEQUAL(vkr, VK_SUCCESS); +} + FloatVector VulkanDebugManager::InterpretVertex(byte *data, uint32_t vert, MeshDisplay cfg, byte *end, bool &valid) { diff --git a/renderdoc/driver/vulkan/vk_debug.h b/renderdoc/driver/vulkan/vk_debug.h index 18683f1e3..252adfaa8 100644 --- a/renderdoc/driver/vulkan/vk_debug.h +++ b/renderdoc/driver/vulkan/vk_debug.h @@ -124,6 +124,9 @@ public: uint32_t PickVertex(uint32_t eventID, MeshDisplay cfg, uint32_t x, uint32_t y, uint32_t w, uint32_t h); + void CreateCustomShaderTex(uint32_t width, uint32_t height); + void CreateCustomShaderPipeline(ResourceId shader); + struct GPUBuffer { enum CreateFlags @@ -195,6 +198,7 @@ public: VkWriteDescriptorSet m_TexDisplayDummyWrites[12]; VkDescriptorImageInfo m_TexDisplayDummyInfos[12]; VkDeviceMemory m_TexDisplayDummyMemory; + VkShaderModule m_BlitVSModule; VkDescriptorSet GetTexDisplayDescSet() { @@ -202,6 +206,16 @@ public: return m_TexDisplayDescSet[m_TexDisplayNextSet]; } + uint32_t m_CustomTexWidth, m_CustomTexHeight; + VkDeviceSize m_CustomTexMemSize; + VkImage m_CustomTexImg; + VkImageView m_CustomTexImgView; + VkDeviceMemory m_CustomTexMem; + VkFramebuffer m_CustomTexFB; + VkRenderPass m_CustomTexRP; + ResourceId m_CustomTexShader; + VkPipeline m_CustomTexPipeline; + VkDeviceMemory m_PickPixelImageMem; VkImage m_PickPixelImage; VkImageView m_PickPixelImageView; diff --git a/renderdoc/driver/vulkan/vk_replay.cpp b/renderdoc/driver/vulkan/vk_replay.cpp index a7443f0f0..a1f0ea06e 100644 --- a/renderdoc/driver/vulkan/vk_replay.cpp +++ b/renderdoc/driver/vulkan/vk_replay.cpp @@ -1211,6 +1211,29 @@ bool VulkanReplay::RenderTextureInternal(TextureDisplay cfg, VkRenderPassBeginIn data->RawOutput = cfg.rawoutput ? 1 : 0; + if(cfg.CustomShader != ResourceId()) + { + // must match struct declared in user shader (see documentation / Shader Viewer window helper + // menus) + struct CustomTexDisplayUBOData + { + Vec4u texDim; + uint32_t selectedMip; + uint32_t texType; + uint32_t padding[2]; + }; + + CustomTexDisplayUBOData *customData = (CustomTexDisplayUBOData *)data; + + customData->texDim.x = iminfo.extent.width; + customData->texDim.y = iminfo.extent.height; + customData->texDim.z = iminfo.extent.depth; + customData->texDim.w = iminfo.mipLevels; + customData->selectedMip = cfg.mip; + customData->padding[0] = customData->padding[1] = 0; + customData->texType = (uint32_t)textype; + } + GetDebugManager()->m_TexDisplayUBO.Unmap(); VkDescriptorImageInfo imdesc = {0}; @@ -1288,10 +1311,20 @@ bool VulkanReplay::RenderTextureInternal(TextureDisplay cfg, VkRenderPassBeginIn vt->CmdBeginRenderPass(Unwrap(cmd), &rpbegin, VK_SUBPASS_CONTENTS_INLINE); VkPipeline pipe = GetDebugManager()->m_TexDisplayPipeline; - if(f32render) + + if(cfg.CustomShader != ResourceId()) + { + GetDebugManager()->CreateCustomShaderPipeline(cfg.CustomShader); + pipe = GetDebugManager()->m_CustomTexPipeline; + } + else if(f32render) + { pipe = GetDebugManager()->m_TexDisplayF32Pipeline; + } else if(!cfg.rawoutput && cfg.CustomShader == ResourceId()) + { pipe = GetDebugManager()->m_TexDisplayBlendPipeline; + } vt->CmdBindPipeline(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, Unwrap(pipe)); vt->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, @@ -4353,17 +4386,6 @@ void VulkanReplay::SetContextFilter(ResourceId id, uint32_t firstDefEv, uint32_t RDCERR("Should never hit SetContextFilter"); } -void VulkanReplay::FreeTargetResource(ResourceId id) -{ - // won't get hit until BuildTargetShader is implemented - VULKANNOTIMP("FreeTargetResource"); -} - -void VulkanReplay::FreeCustomShader(ResourceId id) -{ - VULKANNOTIMP("FreeCustomShader"); -} - MeshFormat VulkanReplay::GetPostVSBuffers(uint32_t eventID, uint32_t instID, MeshDataStage stage) { return GetDebugManager()->GetPostVSBuffers(eventID, instID, stage); @@ -4896,16 +4918,114 @@ byte *VulkanReplay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t m return ret; } -void VulkanReplay::ReplaceResource(ResourceId from, ResourceId to) +void VulkanReplay::BuildCustomShader(string source, string entry, const uint32_t compileFlags, + ShaderStageType type, ResourceId *id, string *errors) { - // won't get hit until BuildTargetShader is implemented - VULKANNOTIMP("ReplaceResource"); + SPIRVShaderStage stage = eSPIRVInvalid; + + switch(type) + { + case eShaderStage_Vertex: stage = eSPIRVVertex; break; + case eShaderStage_Hull: stage = eSPIRVTessControl; break; + case eShaderStage_Domain: stage = eSPIRVTessEvaluation; break; + case eShaderStage_Geometry: stage = eSPIRVGeometry; break; + case eShaderStage_Pixel: stage = eSPIRVFragment; break; + case eShaderStage_Compute: stage = eSPIRVCompute; break; + default: + RDCERR("Unexpected type in BuildShader!"); + *id = ResourceId(); + return; + } + + vector sources; + sources.push_back(source); + vector spirv; + + string output = CompileSPIRV(stage, sources, spirv); + + if(spirv.empty()) + { + *id = ResourceId(); + *errors = output; + return; + } + + VkShaderModuleCreateInfo modinfo = { + VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, + NULL, + 0, + spirv.size() * sizeof(uint32_t), + &spirv[0], + }; + + VkShaderModule module; + VkResult vkr = m_pDriver->vkCreateShaderModule(m_pDriver->GetDev(), &modinfo, NULL, &module); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + + *id = GetResID(module); } -void VulkanReplay::RemoveReplacement(ResourceId id) +void VulkanReplay::FreeCustomShader(ResourceId id) { - // won't get hit until BuildTargetShader is implemented - VULKANNOTIMP("RemoveReplacement"); + if(id == ResourceId()) + return; + + m_pDriver->ReleaseResource(GetResourceManager()->GetCurrentResource(id)); +} + +ResourceId VulkanReplay::ApplyCustomShader(ResourceId shader, ResourceId texid, uint32_t mip) +{ + if(shader == ResourceId() || texid == ResourceId()) + return ResourceId(); + + VulkanCreationInfo::Image &iminfo = m_pDriver->m_CreationInfo.m_Image[texid]; + + GetDebugManager()->CreateCustomShaderTex(iminfo.extent.width, iminfo.extent.height); + + int oldW = m_DebugWidth, oldH = m_DebugHeight; + + m_DebugWidth = iminfo.extent.width; + m_DebugHeight = iminfo.extent.height; + + TextureDisplay disp; + disp.Red = disp.Green = disp.Blue = disp.Alpha = true; + disp.FlipY = false; + disp.offx = 0.0f; + disp.offy = 0.0f; + disp.CustomShader = shader; + disp.texid = texid; + disp.lightBackgroundColour = disp.darkBackgroundColour = FloatVector(0, 0, 0, 0); + disp.HDRMul = -1.0f; + disp.linearDisplayAsGamma = true; + disp.mip = mip; + disp.sampleIdx = 0; + disp.overlay = eTexOverlay_None; + disp.rangemin = 0.0f; + disp.rangemax = 1.0f; + disp.rawoutput = false; + disp.scale = 1.0f; + disp.sliceFace = 0; + + VkClearValue clearval = {{{0.0f, 0.0f, 0.0f, 1.0f}}}; + VkRenderPassBeginInfo rpbegin = { + VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, + NULL, + Unwrap(GetDebugManager()->m_CustomTexRP), + Unwrap(GetDebugManager()->m_CustomTexFB), + {{ + 0, 0, + }, + {iminfo.extent.width, iminfo.extent.height}}, + 1, + &clearval, + }; + + RenderTextureInternal(disp, rpbegin, false); + + m_DebugWidth = oldW; + m_DebugHeight = oldH; + + return GetResID(GetDebugManager()->m_CustomTexImg); } void VulkanReplay::BuildTargetShader(string source, string entry, const uint32_t compileFlags, @@ -4918,10 +5038,22 @@ void VulkanReplay::BuildTargetShader(string source, string entry, const uint32_t *id = ResourceId(); } -void VulkanReplay::BuildCustomShader(string source, string entry, const uint32_t compileFlags, - ShaderStageType type, ResourceId *id, string *errors) +void VulkanReplay::ReplaceResource(ResourceId from, ResourceId to) { - VULKANNOTIMP("BuildCustomShader"); + // won't get hit until BuildTargetShader is implemented + VULKANNOTIMP("ReplaceResource"); +} + +void VulkanReplay::RemoveReplacement(ResourceId id) +{ + // won't get hit until BuildTargetShader is implemented + VULKANNOTIMP("RemoveReplacement"); +} + +void VulkanReplay::FreeTargetResource(ResourceId id) +{ + // won't get hit until BuildTargetShader is implemented + VULKANNOTIMP("FreeTargetResource"); } vector VulkanReplay::PixelHistory(vector events, ResourceId target, @@ -4953,12 +5085,6 @@ ShaderDebugTrace VulkanReplay::DebugThread(uint32_t eventID, uint32_t groupid[3] return ShaderDebugTrace(); } -ResourceId VulkanReplay::ApplyCustomShader(ResourceId shader, ResourceId texid, uint32_t mip) -{ - VULKANNOTIMP("ApplyCustomShader"); - return ResourceId(); -} - ResourceId VulkanReplay::CreateProxyTexture(FetchTexture templateTex) { VULKANNOTIMP("CreateProxyTexture"); diff --git a/renderdocui/Windows/ShaderViewer.cs b/renderdocui/Windows/ShaderViewer.cs index ca9b1919a..be772b0b6 100644 --- a/renderdocui/Windows/ShaderViewer.cs +++ b/renderdocui/Windows/ShaderViewer.cs @@ -2041,6 +2041,17 @@ namespace renderdocui.Windows } } + private void InsertVulkanUBO() + { + CurrentScintilla.InsertText(0, String.Format("layout(binding = 0, std140) uniform RENDERDOC_Uniforms{0}" + + "{{{0}" + + " uvec4 TexDim;{0}" + + " uint SelectedMip;{0}" + + " int TextureType;{0}" + + "}} RENDERDOC;{0}{0}", Environment.NewLine)); + } + + private void textureDimensionsToolStripMenuItem_Click(object sender, EventArgs e) { if (CurrentScintilla == null) @@ -2050,6 +2061,8 @@ namespace renderdocui.Windows CurrentScintilla.InsertText(0, "uint4 RENDERDOC_TexDim; // xyz == width, height, depth. w == # mips" + Environment.NewLine + Environment.NewLine); else if (m_Core.APIProps.pipelineType == APIPipelineStateType.OpenGL) CurrentScintilla.InsertText(0, "uvec4 RENDERDOC_TexDim; // xyz == width, height, depth. w == # mips" + Environment.NewLine + Environment.NewLine); + else if (m_Core.APIProps.pipelineType == APIPipelineStateType.Vulkan) + InsertVulkanUBO(); CurrentScintilla.CurrentPos = 0; } @@ -2058,7 +2071,10 @@ namespace renderdocui.Windows if (CurrentScintilla == null) return; - CurrentScintilla.InsertText(0, "uint RENDERDOC_SelectedMip; // selected mip in UI" + Environment.NewLine + Environment.NewLine); + if (m_Core.APIProps.pipelineType == APIPipelineStateType.Vulkan) + InsertVulkanUBO(); + else + CurrentScintilla.InsertText(0, "uint RENDERDOC_SelectedMip; // selected mip in UI" + Environment.NewLine + Environment.NewLine); CurrentScintilla.CurrentPos = 0; } @@ -2071,6 +2087,8 @@ namespace renderdocui.Windows CurrentScintilla.InsertText(0, "uint RENDERDOC_TextureType; // 1 = 1D, 2 = 2D, 3 = 3D, 4 = Depth, 5 = Depth + Stencil, 6 = Depth (MS), 7 = Depth + Stencil (MS)" + Environment.NewLine + Environment.NewLine); else if (m_Core.APIProps.pipelineType == APIPipelineStateType.OpenGL) CurrentScintilla.InsertText(0, "uint RENDERDOC_TextureType; // 1 = 1D, 2 = 2D, 3 = 3D, 4 = Cube, 5 = 1DArray, 6 = 2DArray, 7 = CubeArray, 8 = Rect, 9 = Buffer, 10 = 2DMS" + Environment.NewLine + Environment.NewLine); + else if (m_Core.APIProps.pipelineType == APIPipelineStateType.Vulkan) + InsertVulkanUBO(); CurrentScintilla.CurrentPos = 0; } @@ -2157,6 +2175,27 @@ namespace renderdocui.Windows "layout (binding = 9) uniform samplerBuffer texBuffer;" + Environment.NewLine + "layout (binding = 10) uniform sampler2DMS tex2DMS;" + Environment.NewLine + Environment.NewLine); } + else if (m_Core.APIProps.pipelineType == APIPipelineStateType.Vulkan) + { + CurrentScintilla.InsertText(0, "// Textures" + Environment.NewLine + + "// Floating point samplers" + Environment.NewLine + + "layout(binding = 6) uniform sampler1DArray tex1DArray;" + Environment.NewLine + + "layout(binding = 7) uniform sampler2DArray tex2DArray;" + Environment.NewLine + + "layout(binding = 8) uniform sampler3D tex3D;" + Environment.NewLine + + "layout(binding = 9) uniform sampler2DMS tex2DMS;" + Environment.NewLine + + "" + Environment.NewLine + + "// Unsigned int samplers" + Environment.NewLine + + "layout(binding = 11) uniform usampler1DArray texUInt1DArray;" + Environment.NewLine + + "layout(binding = 12) uniform usampler2DArray texUInt2DArray;" + Environment.NewLine + + "layout(binding = 13) uniform usampler3D texUInt3D;" + Environment.NewLine + + "layout(binding = 14) uniform usampler2DMS texUInt2DMS;" + Environment.NewLine + + "" + Environment.NewLine + + "// Int samplers" + Environment.NewLine + + "layout(binding = 16) uniform isampler1DArray texSInt1DArray;" + Environment.NewLine + + "layout(binding = 17) uniform isampler2DArray texSInt2DArray;" + Environment.NewLine + + "layout(binding = 18) uniform isampler3D texSInt3D;" + Environment.NewLine + + "layout(binding = 19) uniform isampler2DMS texSInt2DMS;" + Environment.NewLine + Environment.NewLine); + } CurrentScintilla.CurrentPos = 0; }