mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-07-08 16:50:44 +00:00
Implement quad overdraw display modes (not quite 100% yet)
This commit is contained in:
@@ -31,7 +31,6 @@ Known Issues
|
||||
|
||||
* Memory/image barriers are as yet unverified, potentially could lead to bad capture or replay.
|
||||
* Sparse images with mips or array slices will not properly replay
|
||||
* 'Quad overdraw' debug overlays aren't implemented.
|
||||
|
||||
Future work, post 1.0
|
||||
========
|
||||
|
||||
@@ -62,5 +62,7 @@ DECLARE_EMBED(spv_histogram_comp);
|
||||
DECLARE_EMBED(spv_outline_frag);
|
||||
DECLARE_EMBED(spv_debuguniforms_h);
|
||||
DECLARE_EMBED(spv_texsample_h);
|
||||
DECLARE_EMBED(spv_quadresolve_frag);
|
||||
DECLARE_EMBED(spv_quadwrite_frag);
|
||||
|
||||
#undef DECLARE_EMBED
|
||||
|
||||
@@ -146,6 +146,8 @@ RESOURCE_spv_histogram_comp TYPE_EMBED "spv/histogram.comp"
|
||||
RESOURCE_spv_outline_frag TYPE_EMBED "spv/outline.frag"
|
||||
RESOURCE_spv_debuguniforms_h TYPE_EMBED "spv/debuguniforms.h"
|
||||
RESOURCE_spv_texsample_h TYPE_EMBED "spv/texsample.h"
|
||||
RESOURCE_spv_quadresolve_frag TYPE_EMBED "spv/quadresolve.frag"
|
||||
RESOURCE_spv_quadwrite_frag TYPE_EMBED "spv/quadwrite.frag"
|
||||
|
||||
#ifndef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -48,6 +48,8 @@
|
||||
#define RESOURCE_spv_outline_frag 415
|
||||
#define RESOURCE_spv_debuguniforms_h 416
|
||||
#define RESOURCE_spv_texsample_h 417
|
||||
#define RESOURCE_spv_quadresolve_frag 418
|
||||
#define RESOURCE_spv_quadwrite_frag 419
|
||||
|
||||
#if !defined(STRINGIZE)
|
||||
#define STRINGIZE2(a) #a
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
/******************************************************************************
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015 Baldur Karlsson
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Below shaders courtesy of Stephen Hill (@self_shadow), converted to glsl trivially
|
||||
//
|
||||
// http://blog.selfshadow.com/2012/11/12/counting-quads/
|
||||
// https://github.com/selfshadow/demos/blob/master/QuadShading/QuadShading.fx
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
layout(binding = 0, r32ui) uniform coherent uimage2DArray overdrawImage;
|
||||
|
||||
#define NUM_RAMP_COLOURS 128
|
||||
|
||||
layout(binding = 1) uniform OverdrawRampColors
|
||||
{
|
||||
vec4 colors[NUM_RAMP_COLOURS];
|
||||
} ramp;
|
||||
|
||||
vec4 ToColour(uint v)
|
||||
{
|
||||
return ramp.colors[min(v, uint(NUM_RAMP_COLOURS-1))];
|
||||
}
|
||||
|
||||
layout (location = 0) out vec4 color_out;
|
||||
|
||||
void main()
|
||||
{
|
||||
ivec2 quad = ivec2(gl_FragCoord.xy*0.5f);
|
||||
|
||||
uint overdraw = 0;
|
||||
for(uint i = 0; i < 4; i++)
|
||||
overdraw += imageLoad(overdrawImage, ivec3(quad, i)).x/(i + 1);
|
||||
|
||||
color_out = ToColour(overdraw);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Above shaders courtesy of Stephen Hill (@self_shadow), converted to glsl trivially
|
||||
//
|
||||
// http://blog.selfshadow.com/2012/11/12/counting-quads/
|
||||
// https://github.com/selfshadow/demos/blob/master/QuadShading/QuadShading.fx
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -0,0 +1,64 @@
|
||||
/******************************************************************************
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015 Baldur Karlsson
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
// outer code will hoist this up to just after the #version
|
||||
//#extension GL_ARB_derivative_control : require
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Below shaders courtesy of Stephen Hill (@self_shadow), converted to glsl trivially
|
||||
//
|
||||
// http://blog.selfshadow.com/2012/11/12/counting-quads/
|
||||
// https://github.com/selfshadow/demos/blob/master/QuadShading/QuadShading.fx
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// descriptor set will be patched from 0 to whichever descriptor set we're using in code
|
||||
layout(set = 0, binding = 0, r32ui) uniform coherent uimage2DArray overdrawImage;
|
||||
layout(early_fragment_tests) in;
|
||||
|
||||
void main()
|
||||
{
|
||||
uint c0 = uint(gl_SampleMaskIn[0]);
|
||||
|
||||
// Obtain coverage for all pixels in the quad, via 'message passing'*.
|
||||
// (* For more details, see:
|
||||
// "Shader Amortization using Pixel Quad Message Passing", Eric Penner, GPU Pro 2.)
|
||||
uvec2 p = uvec2(uint(gl_FragCoord.x) & 1u, uint(gl_FragCoord.y) & 1u);
|
||||
ivec2 sign = ivec2(p.x > 0u ? -1 : 1, p.y > 0u ? -1 : 1);
|
||||
uint c1 = c0 + sign.x*int(dFdxFine(c0));
|
||||
uint c2 = c0 + sign.y*int(dFdyFine(c0));
|
||||
uint c3 = c2 + sign.x*int(dFdxFine(c2));
|
||||
|
||||
// Count the live pixels, minus 1 (zero indexing)
|
||||
uint pixelCount = c0 + c1 + c2 + c3 - 1;
|
||||
|
||||
ivec3 quad = ivec3(gl_FragCoord.xy*0.5, pixelCount);
|
||||
imageAtomicAdd(overdrawImage, quad, 1);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Above shaders courtesy of Stephen Hill (@self_shadow), converted to glsl trivially
|
||||
//
|
||||
// http://blog.selfshadow.com/2012/11/12/counting-quads/
|
||||
// https://github.com/selfshadow/demos/blob/master/QuadShading/QuadShading.fx
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -98,8 +98,24 @@ struct DrawcallTreeNode
|
||||
|
||||
struct DrawcallCallback
|
||||
{
|
||||
virtual void PreDraw(uint32_t eid) = 0;
|
||||
virtual void PostDraw(uint32_t eid) = 0;
|
||||
// the three callbacks are used to allow the callback implementor to either
|
||||
// do a modified draw before or after the real thing.
|
||||
//
|
||||
// PreDraw()
|
||||
// do draw call as specified by the log
|
||||
// PostDraw()
|
||||
// if PostDraw() returns true:
|
||||
// do draw call again
|
||||
// PostRedraw()
|
||||
//
|
||||
// So either the modification happens in PreDraw, the modified draw happens,
|
||||
// then in PostDraw() the implementation can elect to undo the modifications
|
||||
// and do the real draw by returning true. OR they can do nothing in PreDraw,
|
||||
// do the real draw, then in PostDraw return true to apply the modifications
|
||||
// which are then undone in PostRedraw.
|
||||
virtual void PreDraw(uint32_t eid, VkCommandBuffer cmd) = 0;
|
||||
virtual bool PostDraw(uint32_t eid, VkCommandBuffer cmd) = 0;
|
||||
virtual void PostRedraw(uint32_t eid, VkCommandBuffer cmd) = 0;
|
||||
};
|
||||
|
||||
class WrappedVulkan : public IFrameCapturer
|
||||
@@ -241,17 +257,6 @@ private:
|
||||
vector<VkDeviceMemory> m_CleanupMems;
|
||||
vector<VkEvent> m_CleanupEvents;
|
||||
|
||||
// return the pre-selected device and queue
|
||||
VkDevice GetDev() { RDCASSERT(m_Device != VK_NULL_HANDLE); return m_Device; }
|
||||
VkQueue GetQ() { RDCASSERT(m_Device != VK_NULL_HANDLE); return m_Queue; }
|
||||
VkInstance GetInstance() { RDCASSERT(m_Instance != VK_NULL_HANDLE); return m_Instance; }
|
||||
VkPhysicalDevice GetPhysDev() { RDCASSERT(m_PhysicalDevice != VK_NULL_HANDLE); return m_PhysicalDevice; }
|
||||
VkCommandBuffer GetNextCmd();
|
||||
void SubmitCmds();
|
||||
VkSemaphore GetNextSemaphore();
|
||||
void SubmitSemaphores();
|
||||
void FlushQ();
|
||||
|
||||
const VkPhysicalDeviceFeatures &GetDeviceFeatures()
|
||||
{ return m_PhysicalDeviceData.features; }
|
||||
const VkPhysicalDeviceProperties &GetDeviceProps()
|
||||
@@ -483,6 +488,8 @@ public:
|
||||
|
||||
VulkanResourceManager *GetResourceManager() { return m_ResourceManager; }
|
||||
VulkanDebugManager *GetDebugManager() { return m_DebugManager; }
|
||||
|
||||
LogState GetState() { return m_State; }
|
||||
|
||||
VulkanReplay *GetReplay() { return &m_Replay; }
|
||||
|
||||
@@ -503,6 +510,19 @@ public:
|
||||
FetchAPIEvent GetEvent(uint32_t eventID);
|
||||
const FetchDrawcall *GetDrawcall(uint32_t frameID, uint32_t eventID);
|
||||
|
||||
// return the pre-selected device and queue
|
||||
VkDevice GetDev() { RDCASSERT(m_Device != VK_NULL_HANDLE); return m_Device; }
|
||||
VkQueue GetQ() { RDCASSERT(m_Device != VK_NULL_HANDLE); return m_Queue; }
|
||||
VkInstance GetInstance() { RDCASSERT(m_Instance != VK_NULL_HANDLE); return m_Instance; }
|
||||
VkPhysicalDevice GetPhysDev() { RDCASSERT(m_PhysicalDevice != VK_NULL_HANDLE); return m_PhysicalDevice; }
|
||||
VkCommandBuffer GetNextCmd();
|
||||
void SubmitCmds();
|
||||
VkSemaphore GetNextSemaphore();
|
||||
void SubmitSemaphores();
|
||||
void FlushQ();
|
||||
|
||||
VulkanRenderState &GetRenderState() { return m_RenderState; }
|
||||
|
||||
void SetDrawcallCB(DrawcallCallback *cb) { m_DrawcallCallback = cb; }
|
||||
|
||||
// Device initialization
|
||||
|
||||
@@ -240,6 +240,7 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver, VkDevice dev)
|
||||
{
|
||||
// VKTODOLOW needs tidy up - isn't scalable. Needs more classes like UBO above.
|
||||
m_pDriver = driver;
|
||||
m_State = m_pDriver->GetState();
|
||||
|
||||
m_ResourceManager = m_pDriver->GetResourceManager();
|
||||
|
||||
@@ -281,6 +282,11 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver, VkDevice dev)
|
||||
m_OverlayNoDepthRP = VK_NULL_HANDLE;
|
||||
RDCEraseEl(m_OverlayDim);
|
||||
m_OverlayMemSize = 0;
|
||||
|
||||
m_QuadDescSetLayout = VK_NULL_HANDLE;
|
||||
m_QuadResolvePipeLayout = VK_NULL_HANDLE;
|
||||
m_QuadDescSet = VK_NULL_HANDLE;
|
||||
m_QuadResolvePipeline = VK_NULL_HANDLE;
|
||||
|
||||
m_MeshDescSetLayout = VK_NULL_HANDLE;
|
||||
m_MeshPipeLayout = VK_NULL_HANDLE;
|
||||
@@ -299,6 +305,9 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver, VkDevice dev)
|
||||
m_OutlineDescSet = VK_NULL_HANDLE;
|
||||
m_OutlinePipeline = VK_NULL_HANDLE;
|
||||
|
||||
m_MeshFetchDescSetLayout = VK_NULL_HANDLE;
|
||||
m_MeshFetchDescSet = VK_NULL_HANDLE;
|
||||
|
||||
m_Device = dev;
|
||||
|
||||
bool success = LoadShaderCache("vkshaders.cache", m_ShaderCacheMagic, m_ShaderCacheVersion, m_ShaderCache, ShaderCacheCallbacks);
|
||||
@@ -367,6 +376,7 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver, VkDevice dev)
|
||||
GetResourceManager()->WrapResource(Unwrap(dev), m_OutlineDescSetLayout);
|
||||
}
|
||||
|
||||
if(m_State < WRITING)
|
||||
{
|
||||
VkDescriptorSetLayoutBinding layoutBinding[] = {
|
||||
{ 0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, NULL, }
|
||||
@@ -432,6 +442,24 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver, VkDevice dev)
|
||||
|
||||
GetResourceManager()->WrapResource(Unwrap(dev), m_TextDescSetLayout);
|
||||
}
|
||||
|
||||
if(m_State < WRITING)
|
||||
{
|
||||
VkDescriptorSetLayoutBinding layoutBinding[] = {
|
||||
{ 0, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_ALL, NULL, },
|
||||
{ 1, 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],
|
||||
};
|
||||
|
||||
// because this will go through partial replay, needs proper creation info etc so we go through our wrapped
|
||||
// function
|
||||
vkr = m_pDriver->vkCreateDescriptorSetLayout(dev, &descsetLayoutInfo, NULL, &m_QuadDescSetLayout);
|
||||
RDCASSERT(vkr == VK_SUCCESS);
|
||||
}
|
||||
|
||||
{
|
||||
VkDescriptorSetLayoutBinding layoutBinding[] = {
|
||||
@@ -477,6 +505,14 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver, VkDevice dev)
|
||||
|
||||
GetResourceManager()->WrapResource(Unwrap(dev), m_TextPipeLayout);
|
||||
|
||||
pipeLayoutInfo.pSetLayouts = &m_QuadDescSetLayout;
|
||||
|
||||
if(m_State < WRITING)
|
||||
{
|
||||
vkr = m_pDriver->vkCreatePipelineLayout(dev, &pipeLayoutInfo, NULL, &m_QuadResolvePipeLayout);
|
||||
RDCASSERT(vkr == VK_SUCCESS);
|
||||
}
|
||||
|
||||
pipeLayoutInfo.pSetLayouts = UnwrapPtr(m_OutlineDescSetLayout);
|
||||
|
||||
vkr = vt->CreatePipelineLayout(Unwrap(dev), &pipeLayoutInfo, NULL, &m_OutlinePipeLayout);
|
||||
@@ -507,7 +543,7 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver, VkDevice dev)
|
||||
|
||||
VkDescriptorPoolCreateInfo descpoolInfo = {
|
||||
VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, NULL,
|
||||
0, 8+ARRAY_COUNT(m_TexDisplayDescSet),
|
||||
0, 9+ARRAY_COUNT(m_TexDisplayDescSet),
|
||||
ARRAY_COUNT(descPoolTypes), &descPoolTypes[0],
|
||||
};
|
||||
|
||||
@@ -542,6 +578,15 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver, VkDevice dev)
|
||||
|
||||
GetResourceManager()->WrapResource(Unwrap(dev), m_TextDescSet);
|
||||
|
||||
if(m_State < WRITING)
|
||||
{
|
||||
descAllocInfo.pSetLayouts = UnwrapPtr(m_QuadDescSetLayout);
|
||||
vkr = vt->AllocateDescriptorSets(Unwrap(dev), &descAllocInfo, &m_QuadDescSet);
|
||||
RDCASSERT(vkr == VK_SUCCESS);
|
||||
|
||||
GetResourceManager()->WrapResource(Unwrap(dev), m_QuadDescSet);
|
||||
}
|
||||
|
||||
descAllocInfo.pSetLayouts = UnwrapPtr(m_OutlineDescSetLayout);
|
||||
vkr = vt->AllocateDescriptorSets(Unwrap(dev), &descAllocInfo, &m_OutlineDescSet);
|
||||
RDCASSERT(vkr == VK_SUCCESS);
|
||||
@@ -565,11 +610,14 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver, VkDevice dev)
|
||||
|
||||
GetResourceManager()->WrapResource(Unwrap(dev), m_HistogramDescSet[1]);
|
||||
|
||||
descAllocInfo.pSetLayouts = UnwrapPtr(m_MeshFetchDescSetLayout);
|
||||
vkr = vt->AllocateDescriptorSets(Unwrap(dev), &descAllocInfo, &m_MeshFetchDescSet);
|
||||
RDCASSERT(vkr == VK_SUCCESS);
|
||||
|
||||
GetResourceManager()->WrapResource(Unwrap(dev), m_MeshFetchDescSet);
|
||||
if(m_State < WRITING)
|
||||
{
|
||||
descAllocInfo.pSetLayouts = UnwrapPtr(m_MeshFetchDescSetLayout);
|
||||
vkr = vt->AllocateDescriptorSets(Unwrap(dev), &descAllocInfo, &m_MeshFetchDescSet);
|
||||
RDCASSERT(vkr == VK_SUCCESS);
|
||||
|
||||
GetResourceManager()->WrapResource(Unwrap(dev), m_MeshFetchDescSet);
|
||||
}
|
||||
|
||||
m_ReadbackWindow.Create(driver, dev, STAGE_BUFFER_BYTE_SIZE, 1, GPUBuffer::eGPUBufferReadback);
|
||||
|
||||
@@ -600,6 +648,8 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver, VkDevice dev)
|
||||
GetEmbeddedResource(spv_minmaxresult_comp),
|
||||
GetEmbeddedResource(spv_histogram_comp),
|
||||
GetEmbeddedResource(spv_outline_frag),
|
||||
GetEmbeddedResource(spv_quadresolve_frag),
|
||||
GetEmbeddedResource(spv_quadwrite_frag),
|
||||
};
|
||||
|
||||
SPIRVShaderStage shaderStages[] = {
|
||||
@@ -615,6 +665,8 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver, VkDevice dev)
|
||||
eSPIRVCompute,
|
||||
eSPIRVCompute,
|
||||
eSPIRVFragment,
|
||||
eSPIRVFragment,
|
||||
eSPIRVFragment,
|
||||
};
|
||||
|
||||
enum shaderIdx
|
||||
@@ -631,6 +683,8 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver, VkDevice dev)
|
||||
MINMAXRESULTCS,
|
||||
HISTOGRAMCS,
|
||||
OUTLINEFS,
|
||||
QUADRESOLVEFS,
|
||||
QUADWRITEFS,
|
||||
NUM_SHADERS,
|
||||
};
|
||||
|
||||
@@ -656,12 +710,28 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver, VkDevice dev)
|
||||
|
||||
for(size_t i=0; i < ARRAY_COUNT(module); i++)
|
||||
{
|
||||
sources[0] = "#version 430 core\n";
|
||||
sources[2] = "";
|
||||
sources[3] = shaderSources[i];
|
||||
|
||||
if(sources[3].find("#include \"texsample.h\"") != string::npos)
|
||||
sources[2] = GetEmbeddedResource(spv_texsample_h);
|
||||
|
||||
// hoist up any #extension directives
|
||||
size_t extsearch = 0;
|
||||
do
|
||||
{
|
||||
extsearch = sources[3].find("#extension", extsearch);
|
||||
|
||||
if(extsearch == string::npos)
|
||||
break;
|
||||
|
||||
size_t begin = extsearch;
|
||||
extsearch = sources[3].find('\n', extsearch);
|
||||
|
||||
sources[0] += sources[3].substr(begin, extsearch-begin+1);
|
||||
} while(extsearch != string::npos);
|
||||
|
||||
string err = GetSPIRVBlob(shaderStages[i], sources, &shaderSPIRV[i]);
|
||||
RDCASSERT(err.empty() && shaderSPIRV[i]);
|
||||
|
||||
@@ -669,6 +739,9 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver, VkDevice dev)
|
||||
VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, NULL, 0,
|
||||
shaderSPIRV[i]->size()*sizeof(uint32_t), &(*shaderSPIRV[i])[0],
|
||||
};
|
||||
|
||||
if(i == QUADWRITEFS)
|
||||
m_QuadSPIRV = shaderSPIRV[i];
|
||||
|
||||
vkr = vt->CreateShaderModule(Unwrap(dev), &modinfo, NULL, &module[i]);
|
||||
RDCASSERT(vkr == VK_SUCCESS);
|
||||
@@ -679,6 +752,7 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver, VkDevice dev)
|
||||
m_CacheShaders = false;
|
||||
|
||||
VkRenderPass RGBA32RP, RGBA8RP, RGBA16RP, RGBA8MSRP; // compatible render passes for creating pipelines
|
||||
VkRenderPass wrappedRGBA8RP;
|
||||
|
||||
{
|
||||
VkAttachmentDescription attDesc = {
|
||||
@@ -707,6 +781,9 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver, VkDevice dev)
|
||||
};
|
||||
|
||||
vt->CreateRenderPass(Unwrap(dev), &rpinfo, NULL, &RGBA8RP);
|
||||
|
||||
if(m_State < WRITING)
|
||||
m_pDriver->vkCreateRenderPass(dev, &rpinfo, NULL, &wrappedRGBA8RP);
|
||||
|
||||
attDesc.format = VK_FORMAT_R32G32B32A32_SFLOAT;
|
||||
|
||||
@@ -873,6 +950,20 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver, VkDevice dev)
|
||||
|
||||
GetResourceManager()->WrapResource(Unwrap(dev), m_OutlinePipeline);
|
||||
|
||||
attState.blendEnable = false;
|
||||
|
||||
stages[0].module = module[BLITVS];
|
||||
stages[1].module = module[QUADRESOLVEFS];
|
||||
|
||||
pipeInfo.layout = m_QuadResolvePipeLayout;
|
||||
pipeInfo.renderPass = wrappedRGBA8RP;
|
||||
|
||||
if(m_State < WRITING)
|
||||
{
|
||||
vkr = m_pDriver->vkCreateGraphicsPipelines(dev, VK_NULL_HANDLE, 1, &pipeInfo, NULL, &m_QuadResolvePipeline);
|
||||
RDCASSERT(vkr == VK_SUCCESS);
|
||||
}
|
||||
|
||||
VkComputePipelineCreateInfo compPipeInfo = {
|
||||
VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, NULL, 0,
|
||||
{ VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, NULL, 0, VK_SHADER_STAGE_COMPUTE_BIT, VK_NULL_HANDLE, "main", NULL },
|
||||
@@ -905,6 +996,8 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver, VkDevice dev)
|
||||
vt->DestroyRenderPass(Unwrap(dev), RGBA32RP, NULL);
|
||||
vt->DestroyRenderPass(Unwrap(dev), RGBA8RP, NULL);
|
||||
vt->DestroyRenderPass(Unwrap(dev), RGBA8MSRP, NULL);
|
||||
if(m_State < WRITING)
|
||||
m_pDriver->vkDestroyRenderPass(dev, wrappedRGBA8RP, NULL);
|
||||
|
||||
for(size_t i=0; i < ARRAY_COUNT(module); i++)
|
||||
{
|
||||
@@ -1070,6 +1163,13 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver, VkDevice dev)
|
||||
|
||||
m_TextGlyphUBO.Unmap(vt, dev);
|
||||
}
|
||||
|
||||
m_OverdrawRampUBO.Create(driver, dev, 2048, 1, 0); // no ring needed, fixed data
|
||||
RDCCOMPILE_ASSERT(sizeof(overdrawRamp) <= 2048, "overdraw ramp uniforms size");
|
||||
|
||||
void *ramp = m_OverdrawRampUBO.Map(vt, dev, (uint32_t *)NULL);
|
||||
memcpy(ramp, overdrawRamp, sizeof(overdrawRamp));
|
||||
m_OverdrawRampUBO.Unmap(vt, dev);
|
||||
|
||||
// pick pixel data
|
||||
{
|
||||
@@ -1251,7 +1351,7 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver, VkDevice dev)
|
||||
// don't need to ring this, as we hard-sync for readback anyway
|
||||
m_HistogramUBO.Create(driver, dev, sizeof(HistogramUBOData), 1, 0);
|
||||
|
||||
VkDescriptorBufferInfo bufInfo[6];
|
||||
VkDescriptorBufferInfo bufInfo[7];
|
||||
RDCEraseEl(bufInfo);
|
||||
|
||||
// tex display is updated right before rendering
|
||||
@@ -1262,6 +1362,7 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver, VkDevice dev)
|
||||
m_TextStringUBO.FillDescriptor(bufInfo[3]);
|
||||
m_MeshUBO.FillDescriptor(bufInfo[4]);
|
||||
m_OutlineUBO.FillDescriptor(bufInfo[5]);
|
||||
m_OverdrawRampUBO.FillDescriptor(bufInfo[6]);
|
||||
|
||||
VkDescriptorImageInfo atlasImInfo;
|
||||
atlasImInfo.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
@@ -1304,9 +1405,16 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver, VkDevice dev)
|
||||
Unwrap(m_OutlineDescSet), 0, 0, 1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
|
||||
NULL, &bufInfo[5], NULL
|
||||
},
|
||||
{
|
||||
VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, NULL,
|
||||
Unwrap(m_QuadDescSet), 1, 0, 1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
||||
NULL, &bufInfo[6], NULL
|
||||
},
|
||||
};
|
||||
|
||||
vt->UpdateDescriptorSets(Unwrap(dev), ARRAY_COUNT(writeSet), writeSet, 0, NULL);
|
||||
uint32_t writeCount = ARRAY_COUNT(writeSet);
|
||||
if(m_State >= WRITING) writeCount--; // don't write to m_QuadDescSet when it's not allocated
|
||||
vt->UpdateDescriptorSets(Unwrap(dev), writeCount, writeSet, 0, NULL);
|
||||
|
||||
vt->EndCommandBuffer(Unwrap(cmd));
|
||||
}
|
||||
@@ -1367,7 +1475,11 @@ VulkanDebugManager::~VulkanDebugManager()
|
||||
GetResourceManager()->ReleaseWrappedResource(m_TextDescSet);
|
||||
GetResourceManager()->ReleaseWrappedResource(m_MeshDescSet);
|
||||
GetResourceManager()->ReleaseWrappedResource(m_OutlineDescSet);
|
||||
GetResourceManager()->ReleaseWrappedResource(m_MeshFetchDescSet);
|
||||
if(m_QuadDescSet)
|
||||
{
|
||||
GetResourceManager()->ReleaseWrappedResource(m_MeshFetchDescSet);
|
||||
GetResourceManager()->ReleaseWrappedResource(m_QuadDescSet);
|
||||
}
|
||||
|
||||
for(size_t i=0; i < ARRAY_COUNT(m_HistogramDescSet); i++)
|
||||
GetResourceManager()->ReleaseWrappedResource(m_HistogramDescSet[i]);
|
||||
@@ -1597,6 +1709,8 @@ VulkanDebugManager::~VulkanDebugManager()
|
||||
m_HistogramReadback.Destroy(vt, dev);
|
||||
m_HistogramUBO.Destroy(vt, dev);
|
||||
|
||||
m_OverdrawRampUBO.Destroy(vt, dev);
|
||||
|
||||
// overlay & postvs resources are allocated through driver
|
||||
if(m_MeshFetchDescSetLayout != VK_NULL_HANDLE)
|
||||
m_pDriver->vkDestroyDescriptorSetLayout(dev, m_MeshFetchDescSetLayout, NULL);
|
||||
@@ -1615,6 +1729,15 @@ VulkanDebugManager::~VulkanDebugManager()
|
||||
|
||||
if(m_OverlayImageMem != VK_NULL_HANDLE)
|
||||
m_pDriver->vkFreeMemory(dev, m_OverlayImageMem, NULL);
|
||||
|
||||
if(m_QuadDescSetLayout != VK_NULL_HANDLE)
|
||||
m_pDriver->vkDestroyDescriptorSetLayout(dev, m_QuadDescSetLayout, NULL);
|
||||
|
||||
if(m_QuadResolvePipeLayout != VK_NULL_HANDLE)
|
||||
m_pDriver->vkDestroyPipelineLayout(dev, m_QuadResolvePipeLayout, NULL);
|
||||
|
||||
if(m_QuadResolvePipeline != VK_NULL_HANDLE)
|
||||
m_pDriver->vkDestroyPipeline(dev, m_QuadResolvePipeline, NULL);
|
||||
}
|
||||
|
||||
void VulkanDebugManager::BeginText(const TextPrintState &textstate)
|
||||
@@ -2003,6 +2126,203 @@ void VulkanDebugManager::PatchFixedColShader(VkShaderModule &mod, float col[4])
|
||||
RDCASSERT(vkr == VK_SUCCESS);
|
||||
}
|
||||
|
||||
struct QuadOverdrawCallback : public DrawcallCallback
|
||||
{
|
||||
QuadOverdrawCallback(WrappedVulkan *vk, uint32_t frameID, const vector<uint32_t> &events)
|
||||
: m_pDriver(vk)
|
||||
, m_pDebug(vk->GetDebugManager())
|
||||
, m_FrameID(frameID)
|
||||
, m_Events(events)
|
||||
, m_PrevState(VulkanCreationInfo())
|
||||
{ m_pDriver->SetDrawcallCB(this); }
|
||||
~QuadOverdrawCallback()
|
||||
{ m_pDriver->SetDrawcallCB(NULL); }
|
||||
|
||||
void PreDraw(uint32_t eid, VkCommandBuffer cmd)
|
||||
{
|
||||
if(std::find(m_Events.begin(), m_Events.end(), eid) == m_Events.end())
|
||||
return;
|
||||
|
||||
// we customise the pipeline to disable framebuffer writes, but perform normal testing
|
||||
// and substitute our quad calculation fragment shader that writes to a storage image
|
||||
// that is bound in a new descriptor set.
|
||||
|
||||
VkResult vkr = VK_SUCCESS;
|
||||
|
||||
m_PrevState = m_pDriver->GetRenderState();
|
||||
VulkanRenderState &pipestate = m_pDriver->GetRenderState();
|
||||
|
||||
// check cache first
|
||||
VkPipeline pipe = m_PipelineCache[pipestate.graphics.pipeline];
|
||||
|
||||
// if we don't get a hit, create a modified pipeline
|
||||
if(pipe == VK_NULL_HANDLE)
|
||||
{
|
||||
VulkanCreationInfo &c = pipestate.m_CreationInfo;
|
||||
|
||||
VulkanCreationInfo::Pipeline &p = c.m_Pipeline[pipestate.graphics.pipeline];
|
||||
|
||||
VkDescriptorSetLayout *descSetLayouts;
|
||||
|
||||
// descSet will be the index of our new descriptor set
|
||||
uint32_t descSet = (uint32_t)c.m_PipelineLayout[p.layout].descSetLayouts.size();
|
||||
|
||||
descSetLayouts = new VkDescriptorSetLayout[descSet+1];
|
||||
|
||||
for(uint32_t i=0; i < descSet; i++)
|
||||
descSetLayouts[i] = m_pDriver->GetResourceManager()->GetCurrentHandle<VkDescriptorSetLayout>(c.m_PipelineLayout[p.layout].descSetLayouts[i]);
|
||||
|
||||
// this layout has storage image and
|
||||
descSetLayouts[descSet] = m_pDebug->m_QuadDescSetLayout;
|
||||
|
||||
const vector<VkPushConstantRange> &push = c.m_PipelineLayout[p.layout].pushRanges;
|
||||
|
||||
VkPipelineLayoutCreateInfo pipeLayoutInfo = {
|
||||
VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, NULL, 0,
|
||||
descSet+1, descSetLayouts,
|
||||
(uint32_t)push.size(), push.empty() ? NULL : &push[0],
|
||||
};
|
||||
|
||||
// create pipeline layout with same descriptor set layouts, plus our mesh output set
|
||||
VkPipelineLayout pipeLayout;
|
||||
vkr = m_pDriver->vkCreatePipelineLayout(m_pDriver->GetDev(), &pipeLayoutInfo, NULL, &pipeLayout);
|
||||
RDCASSERT(vkr == VK_SUCCESS);
|
||||
|
||||
SAFE_DELETE_ARRAY(descSetLayouts);
|
||||
|
||||
VkGraphicsPipelineCreateInfo pipeCreateInfo;
|
||||
m_pDebug->MakeGraphicsPipelineInfo(pipeCreateInfo, pipestate.graphics.pipeline);
|
||||
|
||||
// repoint pipeline layout
|
||||
pipeCreateInfo.layout = pipeLayout;
|
||||
|
||||
// disable colour writes/blends
|
||||
VkPipelineColorBlendStateCreateInfo *cb = (VkPipelineColorBlendStateCreateInfo *)pipeCreateInfo.pColorBlendState;
|
||||
for(uint32_t i=0; i < cb->attachmentCount; i++)
|
||||
{
|
||||
VkPipelineColorBlendAttachmentState *att = (VkPipelineColorBlendAttachmentState *)&cb->pAttachments[i];
|
||||
att->blendEnable = false;
|
||||
att->colorWriteMask = 0x0;
|
||||
}
|
||||
|
||||
// disable tests and depth/stencil writes
|
||||
VkPipelineDepthStencilStateCreateInfo *ds = (VkPipelineDepthStencilStateCreateInfo *)pipeCreateInfo.pDepthStencilState;
|
||||
ds->depthTestEnable = false;
|
||||
ds->depthWriteEnable = false;
|
||||
ds->stencilTestEnable = false;
|
||||
ds->depthBoundsTestEnable = false;
|
||||
ds->front.passOp = ds->front.failOp = ds->front.depthFailOp = VK_STENCIL_OP_KEEP;
|
||||
ds->back.passOp = ds->back.failOp = ds->back.depthFailOp = VK_STENCIL_OP_KEEP;
|
||||
|
||||
// don't discard
|
||||
VkPipelineRasterizationStateCreateInfo *rs = (VkPipelineRasterizationStateCreateInfo *)pipeCreateInfo.pRasterizationState;
|
||||
rs->rasterizerDiscardEnable = false;
|
||||
|
||||
vector<uint32_t> spirv = *m_pDebug->m_QuadSPIRV;
|
||||
|
||||
// patch spirv, change descriptor set to descSet value
|
||||
size_t it = 5;
|
||||
while(it < spirv.size())
|
||||
{
|
||||
uint16_t WordCount = spirv[it]>>spv::WordCountShift;
|
||||
spv::Op opcode = spv::Op(spirv[it]&spv::OpCodeMask);
|
||||
|
||||
if(opcode == spv::OpDecorate && spirv[it+2] == spv::DecorationDescriptorSet)
|
||||
{
|
||||
spirv[it+3] = descSet;
|
||||
break;
|
||||
}
|
||||
|
||||
it += WordCount;
|
||||
}
|
||||
|
||||
VkShaderModuleCreateInfo modinfo = {
|
||||
VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, NULL, 0,
|
||||
spirv.size()*sizeof(uint32_t), &spirv[0],
|
||||
};
|
||||
|
||||
VkShaderModule module;
|
||||
|
||||
VkDevice dev = m_pDriver->GetDev();
|
||||
|
||||
vkr = ObjDisp(dev)->CreateShaderModule(Unwrap(dev), &modinfo, NULL, &module);
|
||||
RDCASSERT(vkr == VK_SUCCESS);
|
||||
|
||||
m_pDriver->GetResourceManager()->WrapResource(Unwrap(dev), module);
|
||||
|
||||
bool found = false;
|
||||
for(uint32_t i=0; i < pipeCreateInfo.stageCount; i++)
|
||||
{
|
||||
VkPipelineShaderStageCreateInfo &sh = (VkPipelineShaderStageCreateInfo &)pipeCreateInfo.pStages[i];
|
||||
if(sh.stage == VK_SHADER_STAGE_FRAGMENT_BIT)
|
||||
{
|
||||
sh.module = module;
|
||||
sh.pName = "main";
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!found)
|
||||
{
|
||||
// we know this is safe because it's pointing to a static array that's
|
||||
// big enough for all shaders
|
||||
|
||||
VkPipelineShaderStageCreateInfo &sh = (VkPipelineShaderStageCreateInfo &)pipeCreateInfo.pStages[pipeCreateInfo.stageCount++];
|
||||
sh.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||
sh.pNext = NULL;
|
||||
sh.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
sh.module = module;
|
||||
sh.pName = "main";
|
||||
sh.pSpecializationInfo = NULL;
|
||||
}
|
||||
|
||||
vkr = m_pDriver->vkCreateGraphicsPipelines(dev, VK_NULL_HANDLE, 1, &pipeCreateInfo, NULL, &pipe);
|
||||
RDCASSERT(vkr == VK_SUCCESS);
|
||||
|
||||
ObjDisp(dev)->DestroyShaderModule(Unwrap(dev), Unwrap(module), NULL);
|
||||
m_pDriver->GetResourceManager()->ReleaseWrappedResource(module);
|
||||
|
||||
m_PipelineCache[pipestate.graphics.pipeline] = pipe;
|
||||
}
|
||||
|
||||
// modify state for first draw call
|
||||
pipestate.graphics.pipeline = GetResID(pipe);
|
||||
pipestate.graphics.descSets.push_back(GetResID(m_pDebug->m_QuadDescSet));
|
||||
|
||||
if(cmd)
|
||||
pipestate.BindPipeline(cmd);
|
||||
}
|
||||
|
||||
bool PostDraw(uint32_t eid, VkCommandBuffer cmd)
|
||||
{
|
||||
if(std::find(m_Events.begin(), m_Events.end(), eid) == m_Events.end())
|
||||
return false;
|
||||
|
||||
// restore the render state and go ahead with the real draw
|
||||
m_pDriver->GetRenderState() = m_PrevState;
|
||||
|
||||
RDCASSERT(cmd);
|
||||
m_pDriver->GetRenderState().BindPipeline(cmd);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void PostRedraw(uint32_t eid, VkCommandBuffer cmd)
|
||||
{
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
uint32_t m_FrameID;
|
||||
WrappedVulkan *m_pDriver;
|
||||
VulkanDebugManager *m_pDebug;
|
||||
const vector<uint32_t> &m_Events;
|
||||
|
||||
// cache modified pipelines
|
||||
map<ResourceId, VkPipeline> m_PipelineCache;
|
||||
VulkanRenderState m_PrevState;
|
||||
};
|
||||
|
||||
ResourceId VulkanDebugManager::RenderOverlay(ResourceId texid, TextureDisplayOverlay overlay, uint32_t frameID, uint32_t eventID, const vector<uint32_t> &passEvents)
|
||||
{
|
||||
const VkLayerDispatchTable *vt = ObjDisp(m_Device);
|
||||
@@ -2788,6 +3108,195 @@ ResourceId VulkanDebugManager::RenderOverlay(ResourceId texid, TextureDisplayOve
|
||||
m_pDriver->vkDestroyFramebuffer(m_Device, depthFB, NULL);
|
||||
}
|
||||
}
|
||||
else if(overlay == eTexOverlay_QuadOverdrawPass || overlay == eTexOverlay_QuadOverdrawDraw)
|
||||
{
|
||||
VulkanRenderState prevstate = m_pDriver->m_RenderState;
|
||||
|
||||
{
|
||||
SCOPED_TIMER("Quad Overdraw");
|
||||
|
||||
float black[] = { 0.0f, 0.0f, 0.0f, 0.0f };
|
||||
vt->CmdClearColorImage(Unwrap(cmd), Unwrap(m_OverlayImage), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, (VkClearColorValue *)black, 1, &subresourceRange);
|
||||
|
||||
vector<uint32_t> events = passEvents;
|
||||
|
||||
if(overlay == eTexOverlay_QuadOverdrawDraw)
|
||||
events.clear();
|
||||
|
||||
events.push_back(eventID);
|
||||
|
||||
VkImage quadImg;
|
||||
VkDeviceMemory quadImgMem;
|
||||
VkImageView quadImgView;
|
||||
|
||||
VkImageCreateInfo imInfo = {
|
||||
VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, NULL, 0,
|
||||
VK_IMAGE_TYPE_2D, VK_FORMAT_R32_UINT,
|
||||
{ RDCMAX(1, m_OverlayDim.width>>1), RDCMAX(1, m_OverlayDim.height>>1), 1 },
|
||||
1, 4, VK_SAMPLE_COUNT_1_BIT,
|
||||
VK_IMAGE_TILING_OPTIMAL,
|
||||
VK_IMAGE_USAGE_TRANSFER_DST_BIT|VK_IMAGE_USAGE_STORAGE_BIT|VK_IMAGE_USAGE_SAMPLED_BIT,
|
||||
VK_SHARING_MODE_EXCLUSIVE, 0, NULL,
|
||||
VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
};
|
||||
|
||||
VkResult vkr = m_pDriver->vkCreateImage(m_Device, &imInfo, NULL, &quadImg);
|
||||
RDCASSERT(vkr == VK_SUCCESS);
|
||||
|
||||
VkMemoryRequirements mrq = {0};
|
||||
|
||||
m_pDriver->vkGetImageMemoryRequirements(m_Device, quadImg, &mrq);
|
||||
|
||||
VkMemoryAllocateInfo allocInfo = {
|
||||
VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, NULL,
|
||||
mrq.size, m_pDriver->GetGPULocalMemoryIndex(mrq.memoryTypeBits),
|
||||
};
|
||||
|
||||
vkr = m_pDriver->vkAllocateMemory(m_Device, &allocInfo, NULL, &quadImgMem);
|
||||
RDCASSERT(vkr == VK_SUCCESS);
|
||||
|
||||
vkr = m_pDriver->vkBindImageMemory(m_Device, quadImg, quadImgMem, 0);
|
||||
RDCASSERT(vkr == VK_SUCCESS);
|
||||
|
||||
VkImageViewCreateInfo viewinfo = {
|
||||
VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, NULL,
|
||||
0, quadImg, VK_IMAGE_VIEW_TYPE_2D_ARRAY,
|
||||
VK_FORMAT_R32_UINT,
|
||||
{ VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_ONE },
|
||||
{ VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 4 },
|
||||
};
|
||||
|
||||
vkr = m_pDriver->vkCreateImageView(m_Device, &viewinfo, NULL, &quadImgView);
|
||||
RDCASSERT(vkr == VK_SUCCESS);
|
||||
|
||||
// update descriptor to point to our R32 result image
|
||||
VkDescriptorImageInfo imdesc = { 0 };
|
||||
imdesc.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
imdesc.sampler = VK_NULL_HANDLE;
|
||||
imdesc.imageView = Unwrap(quadImgView);
|
||||
|
||||
VkWriteDescriptorSet write = {
|
||||
VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, NULL,
|
||||
Unwrap(m_QuadDescSet), 0, 0, 1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
|
||||
&imdesc, NULL, NULL
|
||||
};
|
||||
vt->UpdateDescriptorSets(Unwrap(m_Device), 1, &write, 0, NULL);
|
||||
|
||||
VkImageMemoryBarrier quadImBarrier = {
|
||||
VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, NULL,
|
||||
0, VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL,
|
||||
VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED,
|
||||
Unwrap(quadImg),
|
||||
{ VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 4 }
|
||||
};
|
||||
|
||||
void *barrier = &quadImBarrier;
|
||||
|
||||
// clear all to black
|
||||
vt->CmdPipelineBarrier(Unwrap(cmd), VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, false, 1, &barrier);
|
||||
vt->CmdClearColorImage(Unwrap(cmd), Unwrap(quadImg), VK_IMAGE_LAYOUT_GENERAL, (VkClearColorValue *)&black, 1, &quadImBarrier.subresourceRange);
|
||||
|
||||
quadImBarrier.srcAccessMask = quadImBarrier.dstAccessMask;
|
||||
quadImBarrier.oldLayout = quadImBarrier.newLayout;
|
||||
|
||||
quadImBarrier.dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
|
||||
|
||||
// set to general layout, for load/store operations
|
||||
vt->CmdPipelineBarrier(Unwrap(cmd), VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, false, 1, &barrier);
|
||||
|
||||
// end this cmd buffer so the image is in the right state for the next part
|
||||
vkr = vt->EndCommandBuffer(Unwrap(cmd));
|
||||
RDCASSERT(vkr == VK_SUCCESS);
|
||||
|
||||
if(overlay == eTexOverlay_QuadOverdrawPass)
|
||||
m_pDriver->ReplayLog(frameID, 0, events[0], eReplay_WithoutDraw);
|
||||
|
||||
// declare callback struct here
|
||||
QuadOverdrawCallback cb(m_pDriver, frameID, events);
|
||||
|
||||
if(overlay == eTexOverlay_QuadOverdrawPass)
|
||||
{
|
||||
m_pDriver->ReplayLog(frameID, events.front(), events.back(), eReplay_Full);
|
||||
}
|
||||
else
|
||||
{
|
||||
// don't have the driver call the callback
|
||||
m_pDriver->SetDrawcallCB(NULL);
|
||||
|
||||
// call PreDraw to set up per-draw changed state without binding anything
|
||||
cb.PreDraw(events.back(), NULL);
|
||||
|
||||
// do the single drawcall, which will bind the pipeline above
|
||||
m_pDriver->ReplayLog(frameID, events.front(), events.back(), eReplay_OnlyDraw);
|
||||
}
|
||||
|
||||
// resolve pass
|
||||
{
|
||||
cmd = m_pDriver->GetNextCmd();
|
||||
|
||||
vkr = vt->BeginCommandBuffer(Unwrap(cmd), &beginInfo);
|
||||
RDCASSERT(vkr == VK_SUCCESS);
|
||||
|
||||
quadImBarrier.srcAccessMask = quadImBarrier.dstAccessMask;
|
||||
quadImBarrier.oldLayout = quadImBarrier.newLayout;
|
||||
|
||||
quadImBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
|
||||
// wait for writing to finish
|
||||
vt->CmdPipelineBarrier(Unwrap(cmd), VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, false, 1, &barrier);
|
||||
|
||||
VkClearValue clearval = {0};
|
||||
VkRenderPassBeginInfo rpbegin = {
|
||||
VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, NULL,
|
||||
Unwrap(m_OverlayNoDepthRP), Unwrap(m_OverlayNoDepthFB),
|
||||
m_pDriver->m_RenderState.renderArea,
|
||||
1, &clearval,
|
||||
};
|
||||
vt->CmdBeginRenderPass(Unwrap(cmd), &rpbegin, VK_SUBPASS_CONTENTS_INLINE);
|
||||
|
||||
vt->CmdBindPipeline(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, Unwrap(m_QuadResolvePipeline));
|
||||
vt->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, Unwrap(m_QuadResolvePipeLayout), 0, 1, UnwrapPtr(m_QuadDescSet), 0, NULL);
|
||||
|
||||
VkViewport viewport = {
|
||||
0.0f, 0.0f,
|
||||
(float)m_OverlayDim.width,
|
||||
(float)m_OverlayDim.height,
|
||||
0.0f, 1.0f
|
||||
};
|
||||
vt->CmdSetViewport(Unwrap(cmd), 1, &viewport);
|
||||
|
||||
vt->CmdDraw(Unwrap(cmd), 4, 1, 0, 0);
|
||||
vt->CmdEndRenderPass(Unwrap(cmd));
|
||||
|
||||
vkr = vt->EndCommandBuffer(Unwrap(cmd));
|
||||
RDCASSERT(vkr == VK_SUCCESS);
|
||||
}
|
||||
|
||||
m_pDriver->SubmitCmds();
|
||||
m_pDriver->FlushQ();
|
||||
|
||||
m_pDriver->vkDestroyImageView(m_Device, quadImgView, NULL);
|
||||
m_pDriver->vkDestroyImage(m_Device, quadImg, NULL);
|
||||
m_pDriver->vkFreeMemory(m_Device, quadImgMem, NULL);
|
||||
|
||||
for(auto it=cb.m_PipelineCache.begin(); it != cb.m_PipelineCache.end(); ++it)
|
||||
{
|
||||
m_pDriver->vkDestroyPipeline(m_Device, it->second, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
// restore back to normal
|
||||
if(overlay == eTexOverlay_QuadOverdrawPass)
|
||||
m_pDriver->ReplayLog(frameID, 0, eventID, eReplay_WithoutDraw);
|
||||
else
|
||||
m_pDriver->m_RenderState = prevstate;
|
||||
|
||||
cmd = m_pDriver->GetNextCmd();
|
||||
|
||||
vkr = vt->BeginCommandBuffer(Unwrap(cmd), &beginInfo);
|
||||
RDCASSERT(vkr == VK_SUCCESS);
|
||||
}
|
||||
|
||||
vkr = vt->EndCommandBuffer(Unwrap(cmd));
|
||||
RDCASSERT(vkr == VK_SUCCESS);
|
||||
|
||||
@@ -197,6 +197,13 @@ class VulkanDebugManager
|
||||
VkRenderPass m_OverlayNoDepthRP;
|
||||
VkExtent2D m_OverlayDim;
|
||||
VkDeviceSize m_OverlayMemSize;
|
||||
|
||||
GPUBuffer m_OverdrawRampUBO;
|
||||
VkDescriptorSetLayout m_QuadDescSetLayout;
|
||||
VkDescriptorSet m_QuadDescSet;
|
||||
VkPipelineLayout m_QuadResolvePipeLayout;
|
||||
VkPipeline m_QuadResolvePipeline;
|
||||
vector<uint32_t> *m_QuadSPIRV;
|
||||
|
||||
VkDescriptorSetLayout m_MeshDescSetLayout;
|
||||
VkPipelineLayout m_MeshPipeLayout;
|
||||
@@ -227,7 +234,7 @@ class VulkanDebugManager
|
||||
VkDescriptorSet m_MeshFetchDescSet;
|
||||
|
||||
MeshDisplayPipelines CacheMeshDisplayPipelines(const MeshFormat &primary, const MeshFormat &secondary);
|
||||
|
||||
void MakeGraphicsPipelineInfo(VkGraphicsPipelineCreateInfo &pipeCreateInfo, ResourceId pipeline);
|
||||
private:
|
||||
void InitDebugData();
|
||||
void ShutdownDebugData();
|
||||
@@ -245,10 +252,11 @@ class VulkanDebugManager
|
||||
void PatchFixedColShader(VkShaderModule &mod, float col[4]);
|
||||
|
||||
void RenderTextInternal(const TextPrintState &textstate, float x, float y, const char *text);
|
||||
void MakeGraphicsPipelineInfo(VkGraphicsPipelineCreateInfo &pipeCreateInfo, ResourceId pipeline);
|
||||
static const int FONT_TEX_WIDTH = 256;
|
||||
static const int FONT_TEX_HEIGHT = 128;
|
||||
|
||||
LogState m_State;
|
||||
|
||||
float m_FontCharAspect;
|
||||
float m_FontCharSize;
|
||||
|
||||
|
||||
@@ -3787,13 +3787,18 @@ struct InitPostVSCallback : public DrawcallCallback
|
||||
~InitPostVSCallback()
|
||||
{ m_pDriver->SetDrawcallCB(NULL); }
|
||||
|
||||
void PreDraw(uint32_t eid)
|
||||
void PreDraw(uint32_t eid, VkCommandBuffer cmd)
|
||||
{
|
||||
if(std::find(m_Events.begin(), m_Events.end(), eid) != m_Events.end())
|
||||
m_pReplay->InitPostVSBuffers(m_FrameID, eid);
|
||||
}
|
||||
|
||||
void PostDraw(uint32_t eid)
|
||||
bool PostDraw(uint32_t eid, VkCommandBuffer cmd)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void PostRedraw(uint32_t eid, VkCommandBuffer cmd)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -109,6 +109,35 @@ void VulkanRenderState::BeginRenderPassAndApplyState(VkCommandBuffer cmd)
|
||||
for(uint32_t i=0; i < subpass; i++)
|
||||
ObjDisp(cmd)->CmdNextSubpass(Unwrap(cmd), VK_SUBPASS_CONTENTS_INLINE);
|
||||
|
||||
BindPipeline(cmd);
|
||||
|
||||
if(!views.empty())
|
||||
ObjDisp(cmd)->CmdSetViewport(Unwrap(cmd), (uint32_t)views.size(), &views[0]);
|
||||
if(!scissors.empty())
|
||||
ObjDisp(cmd)->CmdSetScissor(Unwrap(cmd), (uint32_t)scissors.size(), &scissors[0]);
|
||||
|
||||
ObjDisp(cmd)->CmdSetBlendConstants(Unwrap(cmd), blendConst);
|
||||
ObjDisp(cmd)->CmdSetDepthBounds(Unwrap(cmd), mindepth, maxdepth);
|
||||
ObjDisp(cmd)->CmdSetLineWidth(Unwrap(cmd), lineWidth);
|
||||
ObjDisp(cmd)->CmdSetDepthBias(Unwrap(cmd), bias.depth, bias.biasclamp, bias.slope);
|
||||
|
||||
ObjDisp(cmd)->CmdSetStencilReference(Unwrap(cmd), VK_STENCIL_FACE_BACK_BIT, back.ref);
|
||||
ObjDisp(cmd)->CmdSetStencilCompareMask(Unwrap(cmd), VK_STENCIL_FACE_BACK_BIT, back.compare);
|
||||
ObjDisp(cmd)->CmdSetStencilWriteMask(Unwrap(cmd), VK_STENCIL_FACE_BACK_BIT, back.write);
|
||||
|
||||
ObjDisp(cmd)->CmdSetStencilReference(Unwrap(cmd), VK_STENCIL_FACE_FRONT_BIT, front.ref);
|
||||
ObjDisp(cmd)->CmdSetStencilCompareMask(Unwrap(cmd), VK_STENCIL_FACE_FRONT_BIT, front.compare);
|
||||
ObjDisp(cmd)->CmdSetStencilWriteMask(Unwrap(cmd), VK_STENCIL_FACE_FRONT_BIT, front.write);
|
||||
|
||||
if(ibuffer.buf != ResourceId())
|
||||
ObjDisp(cmd)->CmdBindIndexBuffer(Unwrap(cmd), Unwrap(GetResourceManager()->GetCurrentHandle<VkBuffer>(ibuffer.buf)), ibuffer.offs, ibuffer.bytewidth == 4 ? VK_INDEX_TYPE_UINT32 : VK_INDEX_TYPE_UINT16);
|
||||
|
||||
for(size_t i=0; i < vbuffers.size(); i++)
|
||||
ObjDisp(cmd)->CmdBindVertexBuffers(Unwrap(cmd), (uint32_t)i, 1, UnwrapPtr(GetResourceManager()->GetCurrentHandle<VkBuffer>(vbuffers[i].buf)), &vbuffers[i].offs);
|
||||
}
|
||||
|
||||
void VulkanRenderState::BindPipeline(VkCommandBuffer cmd)
|
||||
{
|
||||
if(graphics.pipeline != ResourceId())
|
||||
{
|
||||
ObjDisp(cmd)->CmdBindPipeline(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, Unwrap(GetResourceManager()->GetCurrentHandle<VkPipeline>(graphics.pipeline)));
|
||||
@@ -150,6 +179,12 @@ void VulkanRenderState::BeginRenderPassAndApplyState(VkCommandBuffer cmd)
|
||||
ResourceId pipeLayoutId = m_CreationInfo.m_Pipeline[compute.pipeline].layout;
|
||||
VkPipelineLayout layout = GetResourceManager()->GetCurrentHandle<VkPipelineLayout>(pipeLayoutId);
|
||||
|
||||
const vector<VkPushConstantRange> &pushRanges = m_CreationInfo.m_PipelineLayout[pipeLayoutId].pushRanges;
|
||||
|
||||
// only set push constant ranges that the layout uses
|
||||
for(size_t i=0; i < pushRanges.size(); i++)
|
||||
ObjDisp(cmd)->CmdPushConstants(Unwrap(cmd), Unwrap(layout), pushRanges[i].stageFlags, pushRanges[i].offset, pushRanges[i].size, pushconsts+pushRanges[i].offset);
|
||||
|
||||
const vector<ResourceId> &descSetLayouts = m_CreationInfo.m_PipelineLayout[pipeLayoutId].descSetLayouts;
|
||||
|
||||
for(size_t i=0; i < descSetLayouts.size(); i++)
|
||||
@@ -158,34 +193,10 @@ void VulkanRenderState::BeginRenderPassAndApplyState(VkCommandBuffer cmd)
|
||||
|
||||
if(compute.descSets[i] != ResourceId())
|
||||
{
|
||||
ObjDisp(cmd)->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, Unwrap(layout), (uint32_t)i,
|
||||
ObjDisp(cmd)->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_COMPUTE, Unwrap(layout), (uint32_t)i,
|
||||
1, UnwrapPtr(GetResourceManager()->GetCurrentHandle<VkDescriptorSet>(compute.descSets[i])),
|
||||
descLayout.dynamicCount, descLayout.dynamicCount == 0 ? NULL : &compute.offsets[i][0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!views.empty())
|
||||
ObjDisp(cmd)->CmdSetViewport(Unwrap(cmd), (uint32_t)views.size(), &views[0]);
|
||||
if(!scissors.empty())
|
||||
ObjDisp(cmd)->CmdSetScissor(Unwrap(cmd), (uint32_t)scissors.size(), &scissors[0]);
|
||||
|
||||
ObjDisp(cmd)->CmdSetBlendConstants(Unwrap(cmd), blendConst);
|
||||
ObjDisp(cmd)->CmdSetDepthBounds(Unwrap(cmd), mindepth, maxdepth);
|
||||
ObjDisp(cmd)->CmdSetLineWidth(Unwrap(cmd), lineWidth);
|
||||
ObjDisp(cmd)->CmdSetDepthBias(Unwrap(cmd), bias.depth, bias.biasclamp, bias.slope);
|
||||
|
||||
ObjDisp(cmd)->CmdSetStencilReference(Unwrap(cmd), VK_STENCIL_FACE_BACK_BIT, back.ref);
|
||||
ObjDisp(cmd)->CmdSetStencilCompareMask(Unwrap(cmd), VK_STENCIL_FACE_BACK_BIT, back.compare);
|
||||
ObjDisp(cmd)->CmdSetStencilWriteMask(Unwrap(cmd), VK_STENCIL_FACE_BACK_BIT, back.write);
|
||||
|
||||
ObjDisp(cmd)->CmdSetStencilReference(Unwrap(cmd), VK_STENCIL_FACE_FRONT_BIT, front.ref);
|
||||
ObjDisp(cmd)->CmdSetStencilCompareMask(Unwrap(cmd), VK_STENCIL_FACE_FRONT_BIT, front.compare);
|
||||
ObjDisp(cmd)->CmdSetStencilWriteMask(Unwrap(cmd), VK_STENCIL_FACE_FRONT_BIT, front.write);
|
||||
|
||||
if(ibuffer.buf != ResourceId())
|
||||
ObjDisp(cmd)->CmdBindIndexBuffer(Unwrap(cmd), Unwrap(GetResourceManager()->GetCurrentHandle<VkBuffer>(ibuffer.buf)), ibuffer.offs, ibuffer.bytewidth == 4 ? VK_INDEX_TYPE_UINT32 : VK_INDEX_TYPE_UINT16);
|
||||
|
||||
for(size_t i=0; i < vbuffers.size(); i++)
|
||||
ObjDisp(cmd)->CmdBindVertexBuffers(Unwrap(cmd), (uint32_t)i, 1, UnwrapPtr(GetResourceManager()->GetCurrentHandle<VkBuffer>(vbuffers[i].buf)), &vbuffers[i].offs);
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ struct VulkanRenderState
|
||||
VulkanRenderState(VulkanCreationInfo &createInfo);
|
||||
VulkanRenderState &operator =(const VulkanRenderState &o);
|
||||
void BeginRenderPassAndApplyState(VkCommandBuffer cmd);
|
||||
void BindPipeline(VkCommandBuffer cmd);
|
||||
|
||||
// dynamic state
|
||||
vector<VkViewport> views;
|
||||
|
||||
@@ -45,12 +45,20 @@ bool WrappedVulkan::Serialise_vkCmdDraw(
|
||||
{
|
||||
if(IsPartialCmd(cmdid) && InPartialRange())
|
||||
{
|
||||
if(m_DrawcallCallback) m_DrawcallCallback->PreDraw(m_RootEventID);
|
||||
|
||||
commandBuffer = PartialCmdBuf();
|
||||
|
||||
if(m_DrawcallCallback) m_DrawcallCallback->PreDraw(m_RootEventID, commandBuffer);
|
||||
|
||||
ObjDisp(commandBuffer)->CmdDraw(Unwrap(commandBuffer), vtxCount, instCount, firstVtx, firstInst);
|
||||
|
||||
if(m_DrawcallCallback) m_DrawcallCallback->PostDraw(m_RootEventID);
|
||||
if(m_DrawcallCallback)
|
||||
{
|
||||
if(m_DrawcallCallback->PostDraw(m_RootEventID, commandBuffer))
|
||||
{
|
||||
ObjDisp(commandBuffer)->CmdDraw(Unwrap(commandBuffer), vtxCount, instCount, firstVtx, firstInst);
|
||||
m_DrawcallCallback->PostRedraw(m_RootEventID, commandBuffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(m_State == READING)
|
||||
@@ -979,12 +987,20 @@ bool WrappedVulkan::Serialise_vkCmdDrawIndexed(
|
||||
{
|
||||
if(IsPartialCmd(cmdid) && InPartialRange())
|
||||
{
|
||||
if(m_DrawcallCallback) m_DrawcallCallback->PreDraw(m_RootEventID);
|
||||
|
||||
commandBuffer = PartialCmdBuf();
|
||||
|
||||
if(m_DrawcallCallback) m_DrawcallCallback->PreDraw(m_RootEventID, commandBuffer);
|
||||
|
||||
ObjDisp(commandBuffer)->CmdDrawIndexed(Unwrap(commandBuffer), idxCount, instCount, firstIdx, vtxOffs, firstInst);
|
||||
|
||||
if(m_DrawcallCallback) m_DrawcallCallback->PostDraw(m_RootEventID);
|
||||
if(m_DrawcallCallback)
|
||||
{
|
||||
if(m_DrawcallCallback->PostDraw(m_RootEventID, commandBuffer))
|
||||
{
|
||||
ObjDisp(commandBuffer)->CmdDrawIndexed(Unwrap(commandBuffer), idxCount, instCount, firstIdx, vtxOffs, firstInst);
|
||||
m_DrawcallCallback->PostRedraw(m_RootEventID, commandBuffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(m_State == READING)
|
||||
|
||||
@@ -370,6 +370,8 @@
|
||||
<None Include="data\spv\minmaxresult.comp" />
|
||||
<None Include="data\spv\minmaxtile.comp" />
|
||||
<None Include="data\spv\outline.frag" />
|
||||
<None Include="data\spv\quadresolve.frag" />
|
||||
<None Include="data\spv\quadwrite.frag" />
|
||||
<None Include="data\spv\texdisplay.frag" />
|
||||
<None Include="data\spv\text.frag" />
|
||||
<None Include="data\spv\text.vert" />
|
||||
|
||||
@@ -478,6 +478,12 @@
|
||||
<None Include="data\spv\outline.frag">
|
||||
<Filter>Resources\spv</Filter>
|
||||
</None>
|
||||
<None Include="data\spv\quadwrite.frag">
|
||||
<Filter>Resources\spv</Filter>
|
||||
</None>
|
||||
<None Include="data\spv\quadresolve.frag">
|
||||
<Filter>Resources\spv</Filter>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="data\renderdoc.rc">
|
||||
|
||||
Reference in New Issue
Block a user