From d9d90097ad1de388746a84d1aa9d6947699ed7d0 Mon Sep 17 00:00:00 2001 From: baldurk Date: Thu, 3 Sep 2015 11:48:29 +0200 Subject: [PATCH] Start tracking current state --- qrenderdoc/qrenderdoc.pro | 2 +- renderdoc/api/replay/renderdoc_replay.h | 1 + renderdoc/api/replay/vk_pipestate.h | 227 ++++++++++++++++++++++++ renderdoc/driver/vulkan/vk_core.cpp | 56 ++++++ renderdoc/driver/vulkan/vk_core.h | 50 +++++- renderdoc/driver/vulkan/vk_replay.h | 1 + 6 files changed, 335 insertions(+), 2 deletions(-) create mode 100644 renderdoc/api/replay/vk_pipestate.h diff --git a/qrenderdoc/qrenderdoc.pro b/qrenderdoc/qrenderdoc.pro index dce9a8421..624add9c0 100644 --- a/qrenderdoc/qrenderdoc.pro +++ b/qrenderdoc/qrenderdoc.pro @@ -53,7 +53,7 @@ win32 { LIBS += -L$$_PRO_FILE_PWD_/../renderdoc -lrenderdoc QMAKE_LFLAGS += '-Wl,-rpath,\'\$$ORIGIN\'' - QMAKE_CXXFLAGS += -std=c++11 -Wno-unused-parameter + QMAKE_CXXFLAGS += -std=c++11 -Wno-unused-parameter -Wno-reorder QT += x11extras diff --git a/renderdoc/api/replay/renderdoc_replay.h b/renderdoc/api/replay/renderdoc_replay.h index 40cc7230c..1892c526a 100644 --- a/renderdoc/api/replay/renderdoc_replay.h +++ b/renderdoc/api/replay/renderdoc_replay.h @@ -104,6 +104,7 @@ struct ResourceId #include "d3d11_pipestate.h" #include "gl_pipestate.h" +#include "vk_pipestate.h" // for C++ expose the interface as a virtual interface #ifdef __cplusplus diff --git a/renderdoc/api/replay/vk_pipestate.h b/renderdoc/api/replay/vk_pipestate.h new file mode 100644 index 000000000..17e6ad07c --- /dev/null +++ b/renderdoc/api/replay/vk_pipestate.h @@ -0,0 +1,227 @@ +/****************************************************************************** + * 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. + ******************************************************************************/ + +#pragma once + +struct VulkanPipelineState +{ + VulkanPipelineState() : pipelineFlags(0) {} + + ResourceId pipeline; + uint32_t pipelineFlags; + + // VKTODOMED renderpass/subpass? + + struct InputAssembly + { + InputAssembly() : primitiveRestartEnable(false) {} + + bool32 primitiveRestartEnable; + + struct IndexBuffer + { + IndexBuffer() : offs(0) {} + ResourceId buf; + uint64_t offs; + // byte width is latched per-draw for GL + } ibuffer; + } IA; + + struct VertexInput + { + struct Attribute + { + Attribute() : binding(0), format(), byteoffset(0) {} + uint32_t binding; + ResourceFormat format; + uint32_t byteoffset; + }; + rdctype::array attrs; + + struct Binding + { + Binding() : vbufferBinding(0), bytestride(0), perInstance(false) {} + uint32_t vbufferBinding; // VKTODO I believe this is the meaning + uint32_t bytestride; + bool32 perInstance; + }; + rdctype::array binds; + + struct VertexBuffer + { + VertexBuffer() : offset(0) {} + ResourceId buffer; + uint64_t offset; + }; + rdctype::array vbuffers; + } VI; + + struct ShaderStage + { + ShaderStage() : Shader(), ShaderDetails(NULL), customName(false) {} + ResourceId Shader; + rdctype::str ShaderName; + bool32 customName; + ShaderReflection *ShaderDetails; + // VKTODOMED this might no longer make sense + ShaderBindpointMapping BindpointMapping; + + ShaderStageType stage; + + // VKTODOMED specialization info + } VS, TCS, TES, GS, FS, CS; + + struct Tessellation + { + Tessellation() : numControlPoints(0) { } + uint32_t numControlPoints; + } Tess; + + struct ViewportScissor + { + ResourceId state; + + struct Viewport + { + Viewport() : x(0), y(0), width(0), height(0), mindepth(0), maxdepth(0) {} + float x, y, width, height, mindepth, maxdepth; + } vp; + + struct Scissor + { + Scissor() : x(0), y(0), width(0), height(0) {} + int32_t x, y, width, height; + } scissor; + }; + + rdctype::array viewportScissors; + + struct Raster + { + Raster() + : depthClipEnable(false), rasterizerDiscardEnable(false), FrontCCW(false), FillMode(eFill_Solid), CullMode(eCull_None) + , depthBias(0), depthBiasClamp(0), slopeScaledDepthBias(0), lineWidth(0) {} + + bool32 depthClipEnable, rasterizerDiscardEnable, FrontCCW; + TriangleFillMode FillMode; + TriangleCullMode CullMode; + + // from dynamic state + ResourceId state; + float depthBias, depthBiasClamp, slopeScaledDepthBias, lineWidth; + } RS; + + struct MultiSample + { + MultiSample() : rasterSamples(0), sampleShadingEnable(false), minSampleShading(0), sampleMask(~0U) {} + uint32_t rasterSamples; + bool32 sampleShadingEnable; + float minSampleShading; + uint32_t sampleMask; + } MSAA; + + struct ColorBlend + { + bool32 alphaToCoverageEnable, logicOpEnable; + rdctype::str logicOp; + + struct Attachment + { + Attachment() : blendEnable(false), writeMask(0) + { + blendConst[0] = blendConst[1] = blendConst[2] = blendConst[3] = 0.0f; + } + + bool32 blendEnable; + + struct BlendOp + { + rdctype::str Source; + rdctype::str Destination; + rdctype::str Operation; + } blend, alphaBlend; + + uint8_t writeMask; + + ResourceId state; + float blendConst[4]; + }; + rdctype::array attachments; + } CB; + + struct DepthStencil + { + DepthStencil() + : testEnable(false), writeEnable(false), boundsEnable(false), stencilTestEnable(false) + , minDepthBounds(0), maxDepthBounds(0) {} + + bool32 testEnable, writeEnable, boundsEnable; + rdctype::str compareOp; + + bool32 stencilTestEnable; + struct StencilOp + { + StencilOp() : mask(0), ref(0) {} + rdctype::str failOp; + rdctype::str depthFailOp; + rdctype::str passOp; + rdctype::str func; + uint32_t mask; + uint32_t ref; + } front, back; + + ResourceId state; + float minDepthBounds, maxDepthBounds; + } DS; + + struct CurrentPass + { + struct RenderPass + { + ResourceId obj; + // VKTODOMED renderpass and subpass information here + } renderpass; + + struct Framebuffer + { + Framebuffer() : width(0), height(0), layers(0) {} + ResourceId obj; + + struct Attachment + { + ResourceId view; + // VKTODOLOW need layout here? + }; + rdctype::array attachments; + + uint32_t width, height, layers; + } framebuffer; + + struct RenderArea + { + RenderArea() : x(0), y(0), width(0), height(0) {} + int32_t x, y, width, height; + } renderArea; + } Pass; +}; diff --git a/renderdoc/driver/vulkan/vk_core.cpp b/renderdoc/driver/vulkan/vk_core.cpp index c38a260d0..6906124c5 100644 --- a/renderdoc/driver/vulkan/vk_core.cpp +++ b/renderdoc/driver/vulkan/vk_core.cpp @@ -3833,7 +3833,13 @@ bool WrappedVulkan::Serialise_vkCmdBindPipeline( pipeline = (VkPipeline)GetResourceManager()->GetLiveResource(pipeid).handle; if(IsPartialCmd(cmdid) && InPartialRange()) + { m_Real.vkCmdBindPipeline(PartialCmdBuf(), bind, pipeline); + if(bind == VK_PIPELINE_BIND_POINT_GRAPHICS) + m_PartialReplayData.state.graphics.pipeline = pipeid; + else + m_PartialReplayData.state.compute.pipeline = pipeid; + } } else if(m_State == READING) { @@ -3903,7 +3909,22 @@ bool WrappedVulkan::Serialise_vkCmdBindDescriptorSets( layout = (VkPipelineLayout)GetResourceManager()->GetLiveResource(layoutid).handle; if(IsPartialCmd(cmdid) && InPartialRange()) + { m_Real.vkCmdBindDescriptorSets(PartialCmdBuf(), bind, layout, first, numSets, sets, offsCount, offs); + + vector &descsets = + (bind == VK_PIPELINE_BIND_POINT_GRAPHICS) + ? m_PartialReplayData.state.graphics.descSets + : m_PartialReplayData.state.compute.descSets; + + // expand as necessary + if(descsets.size() < first + numSets) + descsets.resize(first + numSets); + + // VKTODOMED use layout to bake in dynamic offsets? + for(uint32_t i=0; i < numSets; i++) + descsets[first+i] = descriptorIDs[i]; + } } else if(m_State == READING) { @@ -3960,7 +3981,10 @@ bool WrappedVulkan::Serialise_vkCmdBindDynamicViewportState( dynamicViewportState = (VkDynamicViewportState)GetResourceManager()->GetLiveResource(stateid).handle; if(IsPartialCmd(cmdid) && InPartialRange()) + { m_Real.vkCmdBindDynamicViewportState(PartialCmdBuf(), dynamicViewportState); + m_PartialReplayData.state.dynamicVP = stateid; + } } else if(m_State == READING) { @@ -4003,7 +4027,10 @@ bool WrappedVulkan::Serialise_vkCmdBindDynamicRasterState( dynamicRasterState = (VkDynamicRasterState)GetResourceManager()->GetLiveResource(stateid).handle; if(IsPartialCmd(cmdid) && InPartialRange()) + { m_Real.vkCmdBindDynamicRasterState(PartialCmdBuf(), dynamicRasterState); + m_PartialReplayData.state.dynamicRS = stateid; + } } else if(m_State == READING) { @@ -4046,7 +4073,10 @@ bool WrappedVulkan::Serialise_vkCmdBindDynamicColorBlendState( dynamicColorBlendState = (VkDynamicColorBlendState)GetResourceManager()->GetLiveResource(stateid).handle; if(IsPartialCmd(cmdid) && InPartialRange()) + { m_Real.vkCmdBindDynamicColorBlendState(PartialCmdBuf(), dynamicColorBlendState); + m_PartialReplayData.state.dynamicCB = stateid; + } } else if(m_State == READING) { @@ -4089,7 +4119,10 @@ bool WrappedVulkan::Serialise_vkCmdBindDynamicDepthStencilState( dynamicDepthStencilState = (VkDynamicDepthStencilState)GetResourceManager()->GetLiveResource(stateid).handle; if(IsPartialCmd(cmdid) && InPartialRange()) + { m_Real.vkCmdBindDynamicDepthStencilState(PartialCmdBuf(), dynamicDepthStencilState); + m_PartialReplayData.state.dynamicDS = stateid; + } } else if(m_State == READING) { @@ -4131,6 +4164,7 @@ bool WrappedVulkan::Serialise_vkCmdBindVertexBuffers( SERIALISE_ELEMENT(uint32_t, start, startBinding); SERIALISE_ELEMENT(uint32_t, count, bindingCount); + vector bufids; vector bufs; vector offs; @@ -4149,6 +4183,7 @@ bool WrappedVulkan::Serialise_vkCmdBindVertexBuffers( if(m_State < WRITING) { + bufids.push_back(id); bufs.push_back((VkBuffer)GetResourceManager()->GetLiveResource(id).handle); offs.push_back(o); } @@ -4157,7 +4192,18 @@ bool WrappedVulkan::Serialise_vkCmdBindVertexBuffers( if(m_State == EXECUTING) { if(IsPartialCmd(cmdid) && InPartialRange()) + { m_Real.vkCmdBindVertexBuffers(PartialCmdBuf(), start, count, &bufs[0], &offs[0]); + + if(m_PartialReplayData.state.vbuffers.size() < start + count) + m_PartialReplayData.state.vbuffers.resize(start + count); + + for(uint32_t i=0; i < count; i++) + { + m_PartialReplayData.state.vbuffers[start + i].buf = bufids[i]; + m_PartialReplayData.state.vbuffers[start + i].offs = offs[i]; + } + } } else if(m_State == READING) { @@ -4208,7 +4254,13 @@ bool WrappedVulkan::Serialise_vkCmdBindIndexBuffer( buffer = (VkBuffer)GetResourceManager()->GetLiveResource(bufid).handle; if(IsPartialCmd(cmdid) && InPartialRange()) + { m_Real.vkCmdBindIndexBuffer(PartialCmdBuf(), buffer, offs, idxType); + + m_PartialReplayData.state.ibuffer.buf = bufid; + m_PartialReplayData.state.ibuffer.offs = offs; + m_PartialReplayData.state.ibuffer.bytewidth = idxType == VK_INDEX_TYPE_UINT32 ? 4 : 2; + } } else if(m_State == READING) { @@ -5348,6 +5400,7 @@ void WrappedVulkan::ContextReplayLog(LogState readType, uint32_t startEventID, u RDCASSERT(m_PartialReplayData.resultPartialCmdBuffer == VK_NULL_HANDLE); m_PartialReplayData.partialParent = ResourceId(); m_PartialReplayData.baseEvent = 0; + m_PartialReplayData.state = PartialReplayData::StateVector(); } else if(m_State == READING) { @@ -7011,6 +7064,9 @@ void WrappedVulkan::AddDrawcall(FetchDrawcall d, bool hasEvents) draw.depthOut = ResourceId(); + // VKTODOHIGH set index byte width here + // VKTODOHIGH set topology here + m_CurDrawcallID++; if(hasEvents) { diff --git a/renderdoc/driver/vulkan/vk_core.h b/renderdoc/driver/vulkan/vk_core.h index a06adad34..6831fcbd8 100644 --- a/renderdoc/driver/vulkan/vk_core.h +++ b/renderdoc/driver/vulkan/vk_core.h @@ -187,7 +187,7 @@ private: // on capture). ResourceId m_CurCmdBufferID; - struct + struct PartialReplayData { // if we're doing a partial replay, by definition only one command // buffer will be partial at any one time. While replaying through @@ -233,6 +233,54 @@ private: // reach the vkEndCommandBuffer that we also need to end a render // pass. bool renderPassActive; + + // There is only a state while currently partially replaying, it's + // undefined/empty otherwise. + // All IDs are original IDs, not live. + struct StateVector + { + StateVector() + { + compute.pipeline = graphics.pipeline = + dynamicVP = dynamicRS = dynamicCB = dynamicDS = ResourceId(); + compute.descSets.clear(); + graphics.descSets.clear(); + + RDCEraseEl(ibuffer); + vbuffers.clear(); + } + + ResourceId dynamicVP; + ResourceId dynamicRS; + ResourceId dynamicCB; + ResourceId dynamicDS; + + ResourceId renderPass; + ResourceId framebuffer; + VkRect2D renderArea; + + struct + { + ResourceId pipeline; + // VKTODOMED might need something more sophisticated here, for + // dynamic offsets + vector descSets; + } compute, graphics; + + struct IdxBuffer + { + ResourceId buf; + VkDeviceSize offs; + int bytewidth; + } ibuffer; + + struct VertBuffer + { + ResourceId buf; + VkDeviceSize offs; + }; + vector vbuffers; + } state; } m_PartialReplayData; bool IsPartialCmd(ResourceId cmdid) { return cmdid == m_PartialReplayData.partialParent; } diff --git a/renderdoc/driver/vulkan/vk_replay.h b/renderdoc/driver/vulkan/vk_replay.h index fd1f1e7b9..17ed2395c 100644 --- a/renderdoc/driver/vulkan/vk_replay.h +++ b/renderdoc/driver/vulkan/vk_replay.h @@ -82,6 +82,7 @@ class VulkanReplay : public IReplayDriver void SavePipelineState(); D3D11PipelineState GetD3D11PipelineState() { return m_D3D11PipelineState; } GLPipelineState GetGLPipelineState() { return GLPipelineState(); } + VulkanPipelineState GetVulkanPipelineState() { return VulkanPipelineState(); } void FreeTargetResource(ResourceId id);