mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-10-08 13:21:45 +00:00
6752 lines
202 KiB
C++
6752 lines
202 KiB
C++
/******************************************************************************
|
|
* 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.
|
|
******************************************************************************/
|
|
|
|
#include "vk_core.h"
|
|
#include "serialise/string_utils.h"
|
|
|
|
// VKTODOLOW dirty buffers should propagate through to their memory somehow
|
|
// images can be separately dirty since we can't just copy their memory
|
|
// (tiling could be different)
|
|
|
|
static bool operator <(const VkExtensionProperties &a, const VkExtensionProperties &b)
|
|
{
|
|
int cmp = strcmp(a.extName, b.extName);
|
|
if(cmp == 0)
|
|
return a.specVersion < b.specVersion;
|
|
|
|
return cmp < 0;
|
|
}
|
|
|
|
// VKTODOLOW assertion of structure types, handling of pNext or assert == NULL
|
|
|
|
const char *VkChunkNames[] =
|
|
{
|
|
"WrappedVulkan::Initialisation",
|
|
"vkCreateInstance",
|
|
"vkInitAndEnumerateGpus",
|
|
"vkCreateDevice",
|
|
"vkGetDeviceQueue",
|
|
|
|
"vkAllocMemory",
|
|
"vkUnmapMemory",
|
|
"vkFreeMemory",
|
|
|
|
"vkCreateCommandPool",
|
|
"vkResetCommandPool",
|
|
|
|
"vkCreateCommandBuffer",
|
|
"vkCreateFramebuffer",
|
|
"vkCreateRenderPass",
|
|
"vkCreateDescriptorPool",
|
|
"vkCreateDescriptorSet",
|
|
"vkCreateDescriptorSetLayout",
|
|
"vkCreateBuffer",
|
|
"vkCreateBufferView",
|
|
"vkCreateImage",
|
|
"vkCreateImageView",
|
|
"vkCreateAttachmentView",
|
|
"vkCreateDepthTargetView",
|
|
"vkCreateDynamicViewportState",
|
|
"vkCreateDynamicRasterState",
|
|
"vkCreateDynamicBlendState",
|
|
"vkCreateDynamicDepthStencilState",
|
|
"vkCreateSampler",
|
|
"vkCreateShader",
|
|
"vkCreateShaderModule",
|
|
"vkCreatePipelineLayout",
|
|
"vkCreatePipelineCache",
|
|
"vkCreateGraphicsPipelines",
|
|
"vkCreateComputePipelines",
|
|
"vkGetSwapChainInfoWSI",
|
|
|
|
"vkCreateSemaphore",
|
|
"vkCreateFence",
|
|
"vkGetFenceStatus",
|
|
"vkWaitForFences",
|
|
|
|
"vkAllocDescriptorSets",
|
|
"vkUpdateDescriptorSets",
|
|
|
|
"vkResetCommandBuffer",
|
|
"vkBeginCommandBuffer",
|
|
"vkEndCommandBuffer",
|
|
|
|
"vkQueueSignalSemaphore",
|
|
"vkQueueWaitSemaphore",
|
|
"vkQueueWaitIdle",
|
|
"vkDeviceWaitIdle",
|
|
|
|
"vkQueueSubmit",
|
|
"vkBindBufferMemory",
|
|
"vkBindImageMemory",
|
|
|
|
"vkCmdBeginRenderPass",
|
|
"vkCmdEndRenderPass",
|
|
|
|
"vkCmdBindPipeline",
|
|
"vkCmdBindDynamicViewportState",
|
|
"vkCmdBindDynamicRasterState",
|
|
"vkCmdBindDynamicColorBlendState",
|
|
"vkCmdBindDynamicDepthStencilState",
|
|
"vkCmdBindDescriptorSet",
|
|
"vkCmdBindVertexBuffers",
|
|
"vkCmdBindIndexBuffer",
|
|
"vkCmdCopyBufferToImage",
|
|
"vkCmdCopyImageToBuffer",
|
|
"vkCmdCopyBuffer",
|
|
"vkCmdCopyImage",
|
|
"vkCmdBlitImage",
|
|
"vkCmdClearColorImage",
|
|
"vkCmdClearDepthStencilImage",
|
|
"vkCmdClearColorAttachment",
|
|
"vkCmdClearDepthStencilAttachment",
|
|
"vkCmdPipelineBarrier",
|
|
"vkCmdResolveImage",
|
|
"vkCmdWriteTimestamp",
|
|
"vkCmdDraw",
|
|
"vkCmdDrawIndirect",
|
|
"vkCmdDrawIndexed",
|
|
"vkCmdDrawIndexedIndirect",
|
|
"vkCmdDispatch",
|
|
"vkCmdDispatchIndirect",
|
|
|
|
"vkCmdDbgMarkerBegin",
|
|
"vkCmdDbgMarker", // no equivalent function at the moment
|
|
"vkCmdDbgMarkerEnd",
|
|
|
|
"vkCreateSwapChainWSI",
|
|
|
|
"Capture",
|
|
"BeginCapture",
|
|
"EndCapture",
|
|
};
|
|
|
|
VkInitParams::VkInitParams()
|
|
{
|
|
SerialiseVersion = VK_SERIALISE_VERSION;
|
|
}
|
|
|
|
ReplayCreateStatus VkInitParams::Serialise()
|
|
{
|
|
SERIALISE_ELEMENT(uint32_t, ver, VK_SERIALISE_VERSION); SerialiseVersion = ver;
|
|
|
|
if(ver != VK_SERIALISE_VERSION)
|
|
{
|
|
RDCERR("Incompatible Vulkan serialise version, expected %d got %d", VK_SERIALISE_VERSION, ver);
|
|
return eReplayCreate_APIIncompatibleVersion;
|
|
}
|
|
|
|
m_pSerialiser->Serialise("AppName", AppName);
|
|
m_pSerialiser->Serialise("EngineName", EngineName);
|
|
m_pSerialiser->Serialise("AppVersion", AppVersion);
|
|
m_pSerialiser->Serialise("EngineVersion", EngineVersion);
|
|
m_pSerialiser->Serialise("APIVersion", APIVersion);
|
|
|
|
m_pSerialiser->Serialise("Layers", Layers);
|
|
m_pSerialiser->Serialise("Extensions", Extensions);
|
|
|
|
m_pSerialiser->Serialise("InstanceID", InstanceID);
|
|
|
|
return eReplayCreate_Success;
|
|
}
|
|
|
|
void VkInitParams::Set(const VkInstanceCreateInfo* pCreateInfo, ResourceId inst)
|
|
{
|
|
RDCASSERT(pCreateInfo);
|
|
|
|
if(pCreateInfo->pAppInfo)
|
|
{
|
|
// VKTODOLOW handle app info next pointer
|
|
RDCASSERT(pCreateInfo->pAppInfo->pNext == NULL);
|
|
|
|
AppName = pCreateInfo->pAppInfo->pAppName ? pCreateInfo->pAppInfo->pAppName : "";
|
|
EngineName = pCreateInfo->pAppInfo->pEngineName ? pCreateInfo->pAppInfo->pEngineName : "";
|
|
|
|
AppVersion = pCreateInfo->pAppInfo->appVersion;
|
|
EngineVersion = pCreateInfo->pAppInfo->engineVersion;
|
|
APIVersion = pCreateInfo->pAppInfo->apiVersion;
|
|
}
|
|
else
|
|
{
|
|
AppName = "";
|
|
EngineName = "";
|
|
|
|
AppVersion = 0;
|
|
EngineVersion = 0;
|
|
APIVersion = 0;
|
|
}
|
|
|
|
Layers.resize(pCreateInfo->layerCount);
|
|
Extensions.resize(pCreateInfo->extensionCount);
|
|
|
|
for(uint32_t i=0; i < pCreateInfo->layerCount; i++)
|
|
Layers[i] = pCreateInfo->ppEnabledLayerNames[i];
|
|
|
|
for(uint32_t i=0; i < pCreateInfo->extensionCount; i++)
|
|
Extensions[i] = pCreateInfo->ppEnabledExtensionNames[i];
|
|
|
|
InstanceID = inst;
|
|
}
|
|
|
|
void WrappedVulkan::Initialise(VkInitParams ¶ms)
|
|
{
|
|
params.AppName = string("RenderDoc (") + params.AppName + ")";
|
|
params.EngineName = string("RenderDoc (") + params.EngineName + ")";
|
|
|
|
// VKTODOLOW verify that layers/extensions are available
|
|
|
|
const char **layerscstr = new const char *[params.Layers.size()];
|
|
for(size_t i=0; i < params.Layers.size(); i++)
|
|
layerscstr[i] = params.Layers[i].c_str();
|
|
|
|
#if defined(FORCE_VALIDATION_LAYER)
|
|
params.Extensions.push_back("DEBUG_REPORT");
|
|
#endif
|
|
|
|
const char **extscstr = new const char *[params.Extensions.size()];
|
|
for(size_t i=0; i < params.Extensions.size(); i++)
|
|
extscstr[i] = params.Extensions[i].c_str();
|
|
|
|
VkApplicationInfo appinfo = {
|
|
/*.sType =*/ VK_STRUCTURE_TYPE_APPLICATION_INFO,
|
|
/*.pNext =*/ NULL,
|
|
/*.pAppName =*/ params.AppName.c_str(),
|
|
/*.appVersion =*/ params.AppVersion,
|
|
/*.pEngineName =*/ params.EngineName.c_str(),
|
|
/*.engineVersion =*/ params.EngineVersion,
|
|
/*.apiVersion =*/ VK_API_VERSION,
|
|
};
|
|
// VKTODOLOW handle other API version different to ours
|
|
RDCASSERT(params.APIVersion == VK_API_VERSION);
|
|
VkInstanceCreateInfo instinfo = {
|
|
/*.sType =*/ VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
|
|
/*.pNext =*/ NULL,
|
|
/*.pAppInfo =*/ &appinfo,
|
|
/*.pAllocCb =*/ NULL,
|
|
/*.layerCount =*/ (uint32_t)params.Layers.size(),
|
|
/*.ppEnabledLayerNames =*/ layerscstr,
|
|
/*.extensionCount =*/ (uint32_t)params.Extensions.size(),
|
|
/*.ppEnabledExtensionNames =*/ extscstr,
|
|
};
|
|
|
|
VkInstance inst;
|
|
|
|
VkResult ret = m_Real.vkCreateInstance(&instinfo, &inst);
|
|
|
|
GetResourceManager()->RegisterResource(MakeRes(inst));
|
|
GetResourceManager()->AddLiveResource(params.InstanceID, MakeRes(inst));
|
|
|
|
SAFE_DELETE_ARRAY(layerscstr);
|
|
SAFE_DELETE_ARRAY(extscstr);
|
|
}
|
|
|
|
WrappedVulkan::WrappedVulkan(const VulkanFunctions &real, const char *logFilename)
|
|
: m_Real(real)
|
|
{
|
|
#if defined(RELEASE)
|
|
const bool debugSerialiser = false;
|
|
#else
|
|
const bool debugSerialiser = true;
|
|
#endif
|
|
|
|
if(RenderDoc::Inst().IsReplayApp())
|
|
{
|
|
m_State = READING;
|
|
if(logFilename)
|
|
{
|
|
m_pSerialiser = new Serialiser(logFilename, Serialiser::READING, debugSerialiser);
|
|
}
|
|
else
|
|
{
|
|
byte dummy[4];
|
|
m_pSerialiser = new Serialiser(4, dummy, false);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_State = WRITING_IDLE;
|
|
m_pSerialiser = new Serialiser(NULL, Serialiser::WRITING, debugSerialiser);
|
|
}
|
|
|
|
#define AddExtSupport(list, name, version) { VkExtensionProperties props = { name, version }; list.push_back(props); }
|
|
|
|
AddExtSupport(globalExts.renderdoc, "VK_Renderdoc", 0);
|
|
AddExtSupport(globalExts.renderdoc, "VK_WSI_swapchain", 0);
|
|
|
|
#undef AddExtSupport
|
|
|
|
m_SwapPhysDevice = -1;
|
|
|
|
uint32_t extCount = 0;
|
|
m_Real.vkGetGlobalExtensionProperties(NULL, &extCount, NULL);
|
|
|
|
globalExts.driver.resize(extCount);
|
|
m_Real.vkGetGlobalExtensionProperties(NULL, &extCount, &globalExts.driver[0]);
|
|
|
|
std::sort(globalExts.driver.begin(), globalExts.driver.end());
|
|
|
|
for(size_t i=0; i < globalExts.driver.size(); i++)
|
|
RDCDEBUG("Driver Ext %d: %s", i, globalExts.driver[i].extName);
|
|
|
|
// intersection of extensions
|
|
{
|
|
size_t len = RDCMIN(globalExts.renderdoc.size(), globalExts.driver.size());
|
|
for(size_t i=0, j=0; i < globalExts.renderdoc.size() && j < globalExts.driver.size(); )
|
|
{
|
|
string a = globalExts.renderdoc[i].extName;
|
|
string b = globalExts.driver[j].extName;
|
|
|
|
if(a == b)
|
|
{
|
|
globalExts.extensions.push_back(globalExts.renderdoc[i]);
|
|
i++;
|
|
j++;
|
|
}
|
|
else if(a < b)
|
|
{
|
|
i++;
|
|
}
|
|
else if(b < a)
|
|
{
|
|
j++;
|
|
}
|
|
}
|
|
}
|
|
|
|
m_Replay.SetDriver(this);
|
|
|
|
m_FrameCounter = 0;
|
|
|
|
m_FrameTimer.Restart();
|
|
|
|
m_TotalTime = m_AvgFrametime = m_MinFrametime = m_MaxFrametime = 0.0;
|
|
|
|
m_CurEventID = 1;
|
|
m_CurDrawcallID = 1;
|
|
|
|
m_DrawcallStack.push_back(&m_ParentDrawcall);
|
|
|
|
m_FakeBBImgId = ResourceId();
|
|
m_FakeBBIm = VK_NULL_HANDLE;
|
|
m_FakeBBMem = VK_NULL_HANDLE;
|
|
|
|
m_ResourceManager = new VulkanResourceManager(m_State, m_pSerialiser, this);
|
|
|
|
m_ContextResourceID = GetResourceManager()->RegisterResource(VkResource(eResSpecial, VK_NULL_HANDLE));
|
|
|
|
if(!RenderDoc::Inst().IsReplayApp())
|
|
{
|
|
m_ContextRecord = GetResourceManager()->AddResourceRecord(m_ContextResourceID);
|
|
m_ContextRecord->DataInSerialiser = false;
|
|
m_ContextRecord->Length = 0;
|
|
m_ContextRecord->NumSubResources = 0;
|
|
m_ContextRecord->SpecialResource = true;
|
|
m_ContextRecord->SubResources = NULL;
|
|
}
|
|
else
|
|
{
|
|
m_ContextRecord = NULL;
|
|
|
|
ResourceIDGen::SetReplayResourceIDs();
|
|
}
|
|
|
|
RDCDEBUG("Debug Text enabled - for development! remove before release!");
|
|
m_pSerialiser->SetDebugText(true);
|
|
|
|
m_pSerialiser->SetChunkNameLookup(&GetChunkName);
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Compile time asserts
|
|
|
|
RDCCOMPILE_ASSERT(ARRAY_COUNT(VkChunkNames) == NUM_VULKAN_CHUNKS-FIRST_CHUNK_ID, "Not right number of chunk names");
|
|
}
|
|
|
|
WrappedVulkan::~WrappedVulkan()
|
|
{
|
|
#if defined(FORCE_VALIDATION_LAYER)
|
|
if(m_MsgCallback != VK_NULL_HANDLE)
|
|
{
|
|
// VKTODOMED [0] isn't right..
|
|
m_Real.vkDbgDestroyMsgCallback(m_PhysicalReplayData[0].inst, m_MsgCallback);
|
|
}
|
|
#endif
|
|
|
|
// VKTODOMED clean up replay resources here?
|
|
}
|
|
|
|
const char * WrappedVulkan::GetChunkName(uint32_t idx)
|
|
{
|
|
if(idx < FIRST_CHUNK_ID || idx >= NUM_VULKAN_CHUNKS)
|
|
return "<unknown>";
|
|
return VkChunkNames[idx-FIRST_CHUNK_ID];
|
|
}
|
|
|
|
VkResult WrappedVulkan::vkCreateInstance(
|
|
const VkInstanceCreateInfo* pCreateInfo,
|
|
VkInstance* pInstance)
|
|
{
|
|
if(pCreateInfo == NULL)
|
|
return VK_ERROR_INVALID_POINTER;
|
|
|
|
RDCASSERT(pCreateInfo->pNext == NULL);
|
|
|
|
VkInstance inst;
|
|
|
|
VkResult ret = m_Real.vkCreateInstance(pCreateInfo, &inst);
|
|
|
|
if(ret != VK_SUCCESS)
|
|
return ret;
|
|
|
|
#if !defined(RELEASE)
|
|
if(m_State >= WRITING)
|
|
{
|
|
CaptureOptions &opts = (CaptureOptions &)RenderDoc::Inst().GetCaptureOptions();
|
|
opts.DebugDeviceMode = true;
|
|
}
|
|
#endif
|
|
|
|
// VKTODOLOW we should try and fetch vkDbgCreateMsgCallback ourselves if it isn't
|
|
// already loaded
|
|
if(RenderDoc::Inst().GetCaptureOptions().DebugDeviceMode && m_Real.vkDbgCreateMsgCallback)
|
|
{
|
|
VkFlags flags = VK_DBG_REPORT_INFO_BIT |
|
|
VK_DBG_REPORT_WARN_BIT |
|
|
VK_DBG_REPORT_PERF_WARN_BIT |
|
|
VK_DBG_REPORT_ERROR_BIT |
|
|
VK_DBG_REPORT_DEBUG_BIT;
|
|
m_Real.vkDbgCreateMsgCallback(inst, flags, &DebugCallbackStatic, this, &m_MsgCallback);
|
|
}
|
|
|
|
GetResourceManager()->RegisterResource(MakeRes(inst));
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
ResourceId instID = GetResourceManager()->GetID(MakeRes(inst));
|
|
m_InitParams.Set(pCreateInfo, instID);
|
|
m_InstanceRecord = GetResourceManager()->AddResourceRecord(instID);
|
|
}
|
|
|
|
*pInstance = inst;
|
|
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
VkResult WrappedVulkan::vkDestroyInstance(
|
|
VkInstance instance)
|
|
{
|
|
VkResult ret = m_Real.vkDestroyInstance(instance);
|
|
|
|
if(ret != VK_SUCCESS)
|
|
return ret;
|
|
|
|
if(RenderDoc::Inst().GetCaptureOptions().DebugDeviceMode && m_MsgCallback != VK_NULL_HANDLE)
|
|
{
|
|
m_Real.vkDbgDestroyMsgCallback(instance, m_MsgCallback);
|
|
}
|
|
|
|
GetResourceManager()->UnregisterResource(MakeRes(instance));
|
|
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
bool WrappedVulkan::Serialise_vkEnumeratePhysicalDevices(
|
|
VkInstance instance,
|
|
uint32_t* pPhysicalDeviceCount,
|
|
VkPhysicalDevice* pPhysicalDevices)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, inst, GetResourceManager()->GetID(MakeRes(instance)));
|
|
|
|
SERIALISE_ELEMENT(uint32_t, physCount, *pPhysicalDeviceCount);
|
|
|
|
uint32_t count;
|
|
VkPhysicalDevice devices[8]; // VKTODOLOW: dynamically allocate
|
|
if(m_State < WRITING)
|
|
{
|
|
instance = (VkInstance)GetResourceManager()->GetLiveResource(inst).handle;
|
|
VkResult ret = m_Real.vkEnumeratePhysicalDevices(instance, &count, devices);
|
|
RDCASSERT(ret == VK_SUCCESS);
|
|
|
|
// VKTODOLOW match up physical devices to those available on replay
|
|
}
|
|
|
|
for(uint32_t i=0; i < physCount; i++)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, physId, GetResourceManager()->GetID(MakeRes(pPhysicalDevices[i])));
|
|
|
|
VkPhysicalDevice pd = VK_NULL_HANDLE;
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
pd = pPhysicalDevices[i];
|
|
}
|
|
else
|
|
{
|
|
pd = devices[i];
|
|
|
|
GetResourceManager()->RegisterResource(MakeRes(devices[i]));
|
|
GetResourceManager()->AddLiveResource(physId, MakeRes(devices[i]));
|
|
}
|
|
|
|
ReplayData data;
|
|
data.inst = instance;
|
|
data.phys = pd;
|
|
m_PhysicalReplayData.push_back(data);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
VkResult WrappedVulkan::vkEnumeratePhysicalDevices(
|
|
VkInstance instance,
|
|
uint32_t* pPhysicalDeviceCount,
|
|
VkPhysicalDevice* pPhysicalDevices)
|
|
{
|
|
uint32_t count;
|
|
VkPhysicalDevice devices[8]; // VKTODOLOW: dynamically allocate
|
|
VkResult ret = m_Real.vkEnumeratePhysicalDevices(instance, &count, devices);
|
|
|
|
if(ret != VK_SUCCESS)
|
|
return ret;
|
|
|
|
for(uint32_t i=0; i < count; i++)
|
|
{
|
|
GetResourceManager()->RegisterResource(MakeRes(devices[i]));
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
SCOPED_SERIALISE_CONTEXT(ENUM_PHYSICALS);
|
|
Serialise_vkEnumeratePhysicalDevices(instance, &count, &devices[i]);
|
|
|
|
m_InstanceRecord->AddChunk(scope.Get());
|
|
}
|
|
}
|
|
|
|
if(pPhysicalDeviceCount) *pPhysicalDeviceCount = count;
|
|
if(pPhysicalDevices) memcpy(pPhysicalDevices, devices, count*sizeof(VkPhysicalDevice));
|
|
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
bool WrappedVulkan::Serialise_vkCreateDevice(
|
|
VkPhysicalDevice physicalDevice,
|
|
const VkDeviceCreateInfo* pCreateInfo,
|
|
VkDevice* pDevice)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, physId, GetResourceManager()->GetID(MakeRes(physicalDevice)));
|
|
SERIALISE_ELEMENT(VkDeviceCreateInfo, createInfo, *pCreateInfo);
|
|
SERIALISE_ELEMENT(ResourceId, devId, GetResourceManager()->GetID(MakeRes(*pDevice)));
|
|
|
|
if(m_State == READING)
|
|
{
|
|
physicalDevice = (VkPhysicalDevice)GetResourceManager()->GetLiveResource(physId).handle;
|
|
|
|
VkDevice device;
|
|
|
|
// VKTODOHIGH: find a queue that supports graphics/compute/dma, and if one doesn't exist, add it.
|
|
|
|
// VKTODOLOW: check that extensions supported in capture (from createInfo) are supported in replay
|
|
|
|
VkResult ret = m_Real.vkCreateDevice(physicalDevice, &createInfo, &device);
|
|
|
|
VkResource res = MakeRes(device);
|
|
|
|
GetResourceManager()->RegisterResource(res);
|
|
GetResourceManager()->AddLiveResource(devId, res);
|
|
|
|
bool found = false;
|
|
|
|
for(size_t i=0; i < m_PhysicalReplayData.size(); i++)
|
|
{
|
|
if(m_PhysicalReplayData[i].phys == physicalDevice)
|
|
{
|
|
// VKTODOHIGH super ultra mega hyper hack of great justice
|
|
void PopulateDeviceHooks(VkDevice d, VkInstance i);
|
|
PopulateDeviceHooks(device, m_PhysicalReplayData[i].inst);
|
|
|
|
m_PhysicalReplayData[i].dev = device;
|
|
// VKTODOHIGH: shouldn't be 0, 0
|
|
m_Real.vkGetDeviceQueue(device, 0, 0, &m_PhysicalReplayData[i].q);
|
|
|
|
// VKTODOHIGH queueFamilyIndex
|
|
VkCmdPoolCreateInfo poolInfo = { VK_STRUCTURE_TYPE_CMD_POOL_CREATE_INFO, NULL, 0, 0 };
|
|
m_Real.vkCreateCommandPool(device, &poolInfo, &m_PhysicalReplayData[i].cmdpool);
|
|
|
|
VkCmdBufferCreateInfo cmdInfo = { VK_STRUCTURE_TYPE_CMD_BUFFER_CREATE_INFO, NULL, m_PhysicalReplayData[i].cmdpool, VK_CMD_BUFFER_LEVEL_PRIMARY, 0 };
|
|
m_Real.vkCreateCommandBuffer(device, &cmdInfo, &m_PhysicalReplayData[i].cmd);
|
|
|
|
#if defined(FORCE_VALIDATION_LAYER)
|
|
if(m_Real.vkDbgCreateMsgCallback)
|
|
{
|
|
VkFlags flags = VK_DBG_REPORT_INFO_BIT |
|
|
VK_DBG_REPORT_WARN_BIT |
|
|
VK_DBG_REPORT_PERF_WARN_BIT |
|
|
VK_DBG_REPORT_ERROR_BIT |
|
|
VK_DBG_REPORT_DEBUG_BIT;
|
|
m_Real.vkDbgCreateMsgCallback(m_PhysicalReplayData[i].inst, flags, &DebugCallbackStatic, this, &m_MsgCallback);
|
|
RDCLOG("Created dbg callback");
|
|
}
|
|
else
|
|
{
|
|
RDCLOG("No dbg callback");
|
|
}
|
|
#endif
|
|
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(!found)
|
|
RDCERR("Couldn't find VkPhysicalDevice for vkCreateDevice!");
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
VkResult WrappedVulkan::vkCreateDevice(
|
|
VkPhysicalDevice physicalDevice,
|
|
const VkDeviceCreateInfo* pCreateInfo,
|
|
VkDevice* pDevice)
|
|
{
|
|
VkDeviceCreateInfo createInfo = *pCreateInfo;
|
|
|
|
// VKTODOHIGH: find a queue that supports all capabilities, and if one doesn't exist, add it.
|
|
bool found = false;
|
|
|
|
RDCDEBUG("Might want to fiddle with createinfo - e.g. to remove VK_RenderDoc from set of extensions or similar");
|
|
|
|
VkResult ret = m_Real.vkCreateDevice(physicalDevice, &createInfo, pDevice);
|
|
|
|
if(ret == VK_SUCCESS)
|
|
{
|
|
found = false;
|
|
|
|
for(size_t i=0; i < m_PhysicalReplayData.size(); i++)
|
|
{
|
|
if(m_PhysicalReplayData[i].phys == physicalDevice)
|
|
{
|
|
m_PhysicalReplayData[i].dev = *pDevice;
|
|
// VKTODOHIGH: shouldn't be 0, 0
|
|
m_Real.vkGetDeviceQueue(*pDevice, 0, 0, &m_PhysicalReplayData[i].q);
|
|
|
|
// VKTODOHIGH queueFamilyIndex
|
|
VkCmdPoolCreateInfo poolInfo = { VK_STRUCTURE_TYPE_CMD_POOL_CREATE_INFO, NULL, 0, 0 };
|
|
m_Real.vkCreateCommandPool(*pDevice, &poolInfo, &m_PhysicalReplayData[i].cmdpool);
|
|
|
|
VkCmdBufferCreateInfo cmdInfo = { VK_STRUCTURE_TYPE_CMD_BUFFER_CREATE_INFO, NULL, m_PhysicalReplayData[i].cmdpool, VK_CMD_BUFFER_LEVEL_PRIMARY, 0 };
|
|
m_Real.vkCreateCommandBuffer(*pDevice, &cmdInfo, &m_PhysicalReplayData[i].cmd);
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(!found)
|
|
RDCERR("Couldn't find VkPhysicalDevice for vkCreateDevice!");
|
|
|
|
VkResource res = MakeRes(*pDevice);
|
|
ResourceId id = GetResourceManager()->RegisterResource(res);
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
Chunk *chunk = NULL;
|
|
|
|
{
|
|
SCOPED_SERIALISE_CONTEXT(CREATE_DEVICE);
|
|
Serialise_vkCreateDevice(physicalDevice, &createInfo, pDevice);
|
|
|
|
chunk = scope.Get();
|
|
}
|
|
|
|
m_InstanceRecord->AddChunk(chunk);
|
|
}
|
|
else
|
|
{
|
|
GetResourceManager()->AddLiveResource(id, res);
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
VkResult WrappedVulkan::vkDestroyDevice(VkDevice device)
|
|
{
|
|
// VKTODOHIGH this stuff should all be in vkDestroyInstance
|
|
if(m_State >= WRITING)
|
|
{
|
|
for(size_t i=0; i < m_PhysicalReplayData.size(); i++)
|
|
{
|
|
if(m_PhysicalReplayData[i].dev == device)
|
|
{
|
|
if(i == (size_t)m_SwapPhysDevice)
|
|
{
|
|
// VKTODOHIGH m_InstanceRecord
|
|
|
|
if(m_ContextRecord)
|
|
{
|
|
RDCASSERT(m_ContextRecord->GetRefCount() == 1);
|
|
m_ContextRecord->Delete(GetResourceManager());
|
|
m_ContextRecord = NULL;
|
|
}
|
|
|
|
m_ResourceManager->Shutdown();
|
|
|
|
m_ContextRecord = GetResourceManager()->AddResourceRecord(m_ContextResourceID);
|
|
m_ContextRecord->DataInSerialiser = false;
|
|
m_ContextRecord->Length = 0;
|
|
m_ContextRecord->NumSubResources = 0;
|
|
m_ContextRecord->SpecialResource = true;
|
|
m_ContextRecord->SubResources = NULL;
|
|
}
|
|
|
|
if(m_PhysicalReplayData[i].cmd != VK_NULL_HANDLE)
|
|
m_Real.vkDestroyCommandBuffer(device, m_PhysicalReplayData[i].cmd);
|
|
|
|
m_PhysicalReplayData[i] = ReplayData();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
VkResult ret = m_Real.vkDestroyDevice(device);
|
|
|
|
GetResourceManager()->UnregisterResource(MakeRes(device));
|
|
|
|
return ret;
|
|
}
|
|
|
|
VkResult WrappedVulkan::vkGetPhysicalDeviceFeatures(
|
|
VkPhysicalDevice physicalDevice,
|
|
VkPhysicalDeviceFeatures* pFeatures)
|
|
{
|
|
return m_Real.vkGetPhysicalDeviceFeatures(physicalDevice, pFeatures);
|
|
}
|
|
|
|
VkResult WrappedVulkan::vkGetPhysicalDeviceFormatProperties(
|
|
VkPhysicalDevice physicalDevice,
|
|
VkFormat format,
|
|
VkFormatProperties* pFormatProperties)
|
|
{
|
|
return m_Real.vkGetPhysicalDeviceFormatProperties(physicalDevice, format, pFormatProperties);
|
|
}
|
|
|
|
VkResult WrappedVulkan::vkGetPhysicalDeviceImageFormatProperties(
|
|
VkPhysicalDevice physicalDevice,
|
|
VkFormat format,
|
|
VkImageType type,
|
|
VkImageTiling tiling,
|
|
VkImageUsageFlags usage,
|
|
VkImageFormatProperties* pImageFormatProperties)
|
|
{
|
|
return m_Real.vkGetPhysicalDeviceImageFormatProperties(physicalDevice, format, type, tiling, usage, pImageFormatProperties);
|
|
}
|
|
|
|
VkResult WrappedVulkan::vkGetPhysicalDeviceLimits(
|
|
VkPhysicalDevice physicalDevice,
|
|
VkPhysicalDeviceLimits* pLimits)
|
|
{
|
|
return m_Real.vkGetPhysicalDeviceLimits(physicalDevice, pLimits);
|
|
}
|
|
|
|
VkResult WrappedVulkan::vkGetPhysicalDeviceProperties(
|
|
VkPhysicalDevice physicalDevice,
|
|
VkPhysicalDeviceProperties* pProperties)
|
|
{
|
|
return m_Real.vkGetPhysicalDeviceProperties(physicalDevice, pProperties);
|
|
}
|
|
|
|
VkResult WrappedVulkan::vkGetPhysicalDeviceQueueCount(
|
|
VkPhysicalDevice physicalDevice,
|
|
uint32_t* pCount)
|
|
{
|
|
return m_Real.vkGetPhysicalDeviceQueueCount(physicalDevice, pCount);
|
|
}
|
|
|
|
VkResult WrappedVulkan::vkGetPhysicalDeviceQueueProperties(
|
|
VkPhysicalDevice physicalDevice,
|
|
uint32_t count,
|
|
VkPhysicalDeviceQueueProperties* pQueueProperties)
|
|
{
|
|
return m_Real.vkGetPhysicalDeviceQueueProperties(physicalDevice, count, pQueueProperties);
|
|
}
|
|
|
|
VkResult WrappedVulkan::vkGetPhysicalDeviceMemoryProperties(
|
|
VkPhysicalDevice physicalDevice,
|
|
VkPhysicalDeviceMemoryProperties* pMemoryProperties)
|
|
{
|
|
return m_Real.vkGetPhysicalDeviceMemoryProperties(physicalDevice, pMemoryProperties);
|
|
}
|
|
|
|
VkResult WrappedVulkan::vkGetImageSubresourceLayout(
|
|
VkDevice device,
|
|
VkImage image,
|
|
const VkImageSubresource* pSubresource,
|
|
VkSubresourceLayout* pLayout)
|
|
{
|
|
return m_Real.vkGetImageSubresourceLayout(device, image, pSubresource, pLayout);
|
|
}
|
|
|
|
VkResult WrappedVulkan::vkGetBufferMemoryRequirements(
|
|
VkDevice device,
|
|
VkBuffer buffer,
|
|
VkMemoryRequirements* pMemoryRequirements)
|
|
{
|
|
return m_Real.vkGetBufferMemoryRequirements(device, buffer, pMemoryRequirements);
|
|
}
|
|
|
|
VkResult WrappedVulkan::vkGetImageMemoryRequirements(
|
|
VkDevice device,
|
|
VkImage image,
|
|
VkMemoryRequirements* pMemoryRequirements)
|
|
{
|
|
return m_Real.vkGetImageMemoryRequirements(device, image, pMemoryRequirements);
|
|
}
|
|
|
|
VkResult WrappedVulkan::vkGetGlobalExtensionProperties(
|
|
const char* pLayerName,
|
|
uint32_t* pCount,
|
|
VkExtensionProperties* pProperties)
|
|
{
|
|
if(pLayerName == NULL)
|
|
{
|
|
if(pCount) *pCount = uint32_t(globalExts.extensions.size());
|
|
if(pProperties)
|
|
memcpy(pProperties, &globalExts.extensions[0], sizeof(VkExtensionProperties)*globalExts.extensions.size());
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
return m_Real.vkGetGlobalExtensionProperties(pLayerName, pCount, pProperties);
|
|
}
|
|
|
|
void WrappedVulkan::DestroyObject(VkResource res, ResourceId id)
|
|
{
|
|
GetResourceManager()->MarkCleanResource(id);
|
|
VkResourceRecord *record = GetResourceManager()->GetResourceRecord(id);
|
|
if(record)
|
|
record->Delete(GetResourceManager());
|
|
GetResourceManager()->UnregisterResource(res);
|
|
|
|
if(m_ImageInfo.find(id) != m_ImageInfo.end())
|
|
m_ImageInfo.erase(id);
|
|
}
|
|
|
|
#define DESTROY_IMPL(type, func) \
|
|
VkResult WrappedVulkan::func(VkDevice device, type obj) \
|
|
{ \
|
|
DestroyObject(MakeRes(obj), GetResourceManager()->GetID(MakeRes(obj))); \
|
|
return m_Real.func(device, obj); \
|
|
}
|
|
|
|
DESTROY_IMPL(VkBuffer, vkDestroyBuffer)
|
|
DESTROY_IMPL(VkBufferView, vkDestroyBufferView)
|
|
DESTROY_IMPL(VkImage, vkDestroyImage)
|
|
DESTROY_IMPL(VkImageView, vkDestroyImageView)
|
|
DESTROY_IMPL(VkAttachmentView, vkDestroyAttachmentView)
|
|
DESTROY_IMPL(VkShader, vkDestroyShader)
|
|
DESTROY_IMPL(VkShaderModule, vkDestroyShaderModule)
|
|
DESTROY_IMPL(VkPipeline, vkDestroyPipeline)
|
|
DESTROY_IMPL(VkPipelineCache, vkDestroyPipelineCache)
|
|
DESTROY_IMPL(VkPipelineLayout, vkDestroyPipelineLayout)
|
|
DESTROY_IMPL(VkSampler, vkDestroySampler)
|
|
DESTROY_IMPL(VkDescriptorSetLayout, vkDestroyDescriptorSetLayout)
|
|
DESTROY_IMPL(VkDescriptorPool, vkDestroyDescriptorPool)
|
|
DESTROY_IMPL(VkDynamicViewportState, vkDestroyDynamicViewportState)
|
|
DESTROY_IMPL(VkDynamicRasterState, vkDestroyDynamicRasterState)
|
|
DESTROY_IMPL(VkDynamicColorBlendState, vkDestroyDynamicColorBlendState)
|
|
DESTROY_IMPL(VkDynamicDepthStencilState, vkDestroyDynamicDepthStencilState)
|
|
DESTROY_IMPL(VkSemaphore, vkDestroySemaphore)
|
|
DESTROY_IMPL(VkCmdPool, vkDestroyCommandPool)
|
|
DESTROY_IMPL(VkCmdBuffer, vkDestroyCommandBuffer)
|
|
DESTROY_IMPL(VkFramebuffer, vkDestroyFramebuffer)
|
|
DESTROY_IMPL(VkRenderPass, vkDestroyRenderPass)
|
|
DESTROY_IMPL(VkSwapChainWSI, vkDestroySwapChainWSI)
|
|
|
|
#undef DESTROY_IMPL
|
|
|
|
bool WrappedVulkan::Serialise_vkGetDeviceQueue(
|
|
VkDevice device,
|
|
uint32_t queueNodeIndex,
|
|
uint32_t queueIndex,
|
|
VkQueue* pQueue)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, devId, GetResourceManager()->GetID(MakeRes(device)));
|
|
SERIALISE_ELEMENT(uint32_t, nodeIdx, queueNodeIndex);
|
|
SERIALISE_ELEMENT(uint32_t, idx, queueIndex);
|
|
SERIALISE_ELEMENT(ResourceId, queueId, GetResourceManager()->GetID(MakeRes(*pQueue)));
|
|
|
|
if(m_State == READING)
|
|
{
|
|
VkQueue queue;
|
|
VkResult ret = m_Real.vkGetDeviceQueue((VkDevice)GetResourceManager()->GetLiveResource(devId).handle, nodeIdx, idx, &queue);
|
|
|
|
VkResource res = MakeRes(queue);
|
|
|
|
GetResourceManager()->RegisterResource(res);
|
|
GetResourceManager()->AddLiveResource(queueId, res);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
VkResult WrappedVulkan::vkGetDeviceQueue(
|
|
VkDevice device,
|
|
uint32_t queueNodeIndex,
|
|
uint32_t queueIndex,
|
|
VkQueue* pQueue)
|
|
{
|
|
VkResult ret = m_Real.vkGetDeviceQueue(device, queueNodeIndex, queueIndex, pQueue);
|
|
|
|
if(ret == VK_SUCCESS)
|
|
{
|
|
VkResource res = MakeRes(*pQueue);
|
|
ResourceId id = GetResourceManager()->RegisterResource(res);
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
Chunk *chunk = NULL;
|
|
|
|
{
|
|
SCOPED_SERIALISE_CONTEXT(GET_DEVICE_QUEUE);
|
|
Serialise_vkGetDeviceQueue(device, queueNodeIndex, queueIndex, pQueue);
|
|
|
|
chunk = scope.Get();
|
|
}
|
|
|
|
VkResourceRecord *record = GetResourceManager()->AddResourceRecord(id);
|
|
RDCASSERT(record);
|
|
|
|
record->AddChunk(chunk);
|
|
}
|
|
else
|
|
{
|
|
GetResourceManager()->AddLiveResource(id, res);
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool WrappedVulkan::Serialise_vkQueueSubmit(
|
|
VkQueue queue,
|
|
uint32_t cmdBufferCount,
|
|
const VkCmdBuffer* pCmdBuffers,
|
|
VkFence fence)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, queueId, GetResourceManager()->GetID(MakeRes(queue)));
|
|
SERIALISE_ELEMENT(ResourceId, fenceId, fence != VK_NULL_HANDLE ? GetResourceManager()->GetID(MakeRes(fence)) : ResourceId());
|
|
|
|
SERIALISE_ELEMENT(uint32_t, numCmds, cmdBufferCount);
|
|
|
|
vector<ResourceId> cmdIds;
|
|
VkCmdBuffer *cmds = m_State >= WRITING ? NULL : new VkCmdBuffer[numCmds];
|
|
for(uint32_t i=0; i < numCmds; i++)
|
|
{
|
|
ResourceId bakedId;
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
VkResourceRecord *record = GetResourceManager()->GetResourceRecord(MakeRes(pCmdBuffers[i]));
|
|
RDCASSERT(record->bakedCommands);
|
|
if(record->bakedCommands)
|
|
bakedId = record->bakedCommands->GetResourceID();
|
|
}
|
|
|
|
SERIALISE_ELEMENT(ResourceId, id, bakedId);
|
|
|
|
if(m_State < WRITING)
|
|
{
|
|
cmdIds.push_back(id);
|
|
|
|
cmds[i] = id != ResourceId()
|
|
? (VkCmdBuffer)GetResourceManager()->GetLiveResource(id).handle
|
|
: NULL;
|
|
}
|
|
}
|
|
|
|
if(m_State < WRITING)
|
|
{
|
|
queue = (VkQueue)GetResourceManager()->GetLiveResource(queueId).handle;
|
|
if(fenceId != ResourceId())
|
|
fence = (VkFence)GetResourceManager()->GetLiveResource(fenceId).handle;
|
|
else
|
|
fence = VK_NULL_HANDLE;
|
|
|
|
m_SubmittedFences.insert(fenceId);
|
|
|
|
m_Real.vkQueueSubmit(queue, numCmds, cmds, fence);
|
|
|
|
for(uint32_t i=0; i < numCmds; i++)
|
|
{
|
|
ResourceId cmd = GetResourceManager()->GetID(MakeRes(cmds[i]));
|
|
GetResourceManager()->ApplyTransitions(m_CmdBufferInfo[cmd].imgtransitions, m_ImageInfo);
|
|
}
|
|
|
|
delete[] cmds;
|
|
}
|
|
|
|
const string desc = m_pSerialiser->GetDebugStr();
|
|
|
|
if(m_State == READING)
|
|
{
|
|
AddEvent(QUEUE_SUBMIT, desc);
|
|
string name = "vkQueueSubmit(" +
|
|
ToStr::Get(numCmds) + ")";
|
|
|
|
FetchDrawcall draw;
|
|
draw.name = name;
|
|
|
|
draw.flags |= eDraw_PushMarker;
|
|
|
|
AddDrawcall(draw, true);
|
|
|
|
// add command buffer draws under here
|
|
m_DrawcallStack.push_back(&m_DrawcallStack.back()->children.back());
|
|
|
|
m_CurEventID++;
|
|
|
|
for(uint32_t c=0; c < numCmds; c++)
|
|
{
|
|
AddEvent(QUEUE_SUBMIT, "");
|
|
string name = "[" + ToStr::Get(cmdIds[c]) + "]";
|
|
|
|
FetchDrawcall draw;
|
|
draw.name = name;
|
|
|
|
draw.flags |= eDraw_PushMarker;
|
|
|
|
AddDrawcall(draw, true);
|
|
|
|
DrawcallTreeNode &d = m_DrawcallStack.back()->children.back();
|
|
|
|
// copy DrawcallTreeNode children
|
|
d.children = m_CmdBufferInfo[cmdIds[c]].draw->children;
|
|
|
|
// assign new event and drawIDs
|
|
RefreshIDs(d.children);
|
|
|
|
m_CurEventID++;
|
|
}
|
|
|
|
// done adding command buffers
|
|
m_DrawcallStack.pop_back();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void WrappedVulkan::RefreshIDs(vector<DrawcallTreeNode> &nodes)
|
|
{
|
|
// assign new drawcall IDs
|
|
for(size_t i=0; i < nodes.size(); i++)
|
|
{
|
|
m_CurEventID++;
|
|
|
|
nodes[i].draw.eventID = m_CurEventID;
|
|
nodes[i].draw.drawcallID = m_CurDrawcallID;
|
|
|
|
for(int32_t e=0; e < nodes[i].draw.events.count; e++)
|
|
{
|
|
m_CurEventID++;
|
|
nodes[i].draw.events[e].eventID = m_CurEventID;
|
|
}
|
|
|
|
// markers don't increment drawcall ID
|
|
if((nodes[i].draw.flags & (eDraw_SetMarker|eDraw_PushMarker)) == 0)
|
|
m_CurDrawcallID++;
|
|
|
|
RefreshIDs(nodes[i].children);
|
|
}
|
|
}
|
|
|
|
VkResult WrappedVulkan::vkQueueSubmit(
|
|
VkQueue queue,
|
|
uint32_t cmdBufferCount,
|
|
const VkCmdBuffer* pCmdBuffers,
|
|
VkFence fence)
|
|
{
|
|
VkResult ret = m_Real.vkQueueSubmit(queue, cmdBufferCount, pCmdBuffers, fence);
|
|
|
|
if(m_State == WRITING_CAPFRAME)
|
|
{
|
|
SCOPED_SERIALISE_CONTEXT(QUEUE_SUBMIT);
|
|
Serialise_vkQueueSubmit(queue, cmdBufferCount, pCmdBuffers, fence);
|
|
|
|
m_ContextRecord->AddChunk(scope.Get());
|
|
}
|
|
|
|
for(uint32_t i=0; i < cmdBufferCount; i++)
|
|
{
|
|
ResourceId cmd = GetResourceManager()->GetID(MakeRes(pCmdBuffers[i]));
|
|
GetResourceManager()->ApplyTransitions(m_CmdBufferInfo[cmd].imgtransitions, m_ImageInfo);
|
|
|
|
VkResourceRecord *record = GetResourceManager()->GetResourceRecord(cmd);
|
|
for(auto it = record->bakedCommands->dirtied.begin(); it != record->bakedCommands->dirtied.end(); ++it)
|
|
GetResourceManager()->MarkDirtyResource(*it);
|
|
|
|
if(m_State == WRITING_CAPFRAME)
|
|
{
|
|
// pull in frame refs from this baked command buffer
|
|
record->bakedCommands->AddResourceReferences(GetResourceManager());
|
|
|
|
// ref the parent command buffer by itself, this will pull in the cmd buffer pool
|
|
GetResourceManager()->MarkResourceFrameReferenced(record->GetResourceID(), eFrameRef_Read);
|
|
|
|
m_ContextRecord->AddParent(record->bakedCommands);
|
|
}
|
|
|
|
record->dirtied.clear();
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool WrappedVulkan::Serialise_vkQueueSignalSemaphore(VkQueue queue, VkSemaphore semaphore)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, qid, GetResourceManager()->GetID(MakeRes(queue)));
|
|
SERIALISE_ELEMENT(ResourceId, sid, GetResourceManager()->GetID(MakeRes(semaphore)));
|
|
|
|
if(m_State < WRITING)
|
|
{
|
|
m_Real.vkQueueSignalSemaphore((VkQueue)GetResourceManager()->GetLiveResource(qid).handle,
|
|
(VkSemaphore)GetResourceManager()->GetLiveResource(sid).handle);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
VkResult WrappedVulkan::vkQueueSignalSemaphore(VkQueue queue, VkSemaphore semaphore)
|
|
{
|
|
VkResult ret = m_Real.vkQueueSignalSemaphore(queue, semaphore);
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
SCOPED_SERIALISE_CONTEXT(QUEUE_SIGNAL_SEMAPHORE);
|
|
Serialise_vkQueueSignalSemaphore(queue, semaphore);
|
|
|
|
m_ContextRecord->AddChunk(scope.Get());
|
|
GetResourceManager()->MarkResourceFrameReferenced(MakeRes(queue), eFrameRef_Read);
|
|
GetResourceManager()->MarkResourceFrameReferenced(MakeRes(semaphore), eFrameRef_Read);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool WrappedVulkan::Serialise_vkQueueWaitSemaphore(VkQueue queue, VkSemaphore semaphore)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, qid, GetResourceManager()->GetID(MakeRes(queue)));
|
|
SERIALISE_ELEMENT(ResourceId, sid, GetResourceManager()->GetID(MakeRes(semaphore)));
|
|
|
|
if(m_State < WRITING)
|
|
{
|
|
m_Real.vkQueueWaitSemaphore((VkQueue)GetResourceManager()->GetLiveResource(qid).handle,
|
|
(VkSemaphore)GetResourceManager()->GetLiveResource(sid).handle);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
VkResult WrappedVulkan::vkQueueWaitSemaphore(VkQueue queue, VkSemaphore semaphore)
|
|
{
|
|
VkResult ret = m_Real.vkQueueWaitSemaphore(queue, semaphore);
|
|
|
|
if(m_State >= WRITING_CAPFRAME)
|
|
{
|
|
SCOPED_SERIALISE_CONTEXT(QUEUE_WAIT_SEMAPHORE);
|
|
Serialise_vkQueueWaitSemaphore(queue, semaphore);
|
|
|
|
m_ContextRecord->AddChunk(scope.Get());
|
|
GetResourceManager()->MarkResourceFrameReferenced(MakeRes(queue), eFrameRef_Read);
|
|
GetResourceManager()->MarkResourceFrameReferenced(MakeRes(semaphore), eFrameRef_Read);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool WrappedVulkan::Serialise_vkQueueWaitIdle(VkQueue queue)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, id, GetResourceManager()->GetID(MakeRes(queue)));
|
|
|
|
if(m_State < WRITING_CAPFRAME)
|
|
{
|
|
m_Real.vkQueueWaitIdle((VkQueue)GetResourceManager()->GetLiveResource(id).handle);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
VkResult WrappedVulkan::vkQueueWaitIdle(VkQueue queue)
|
|
{
|
|
VkResult ret = m_Real.vkQueueWaitIdle(queue);
|
|
|
|
if(m_State >= WRITING_CAPFRAME)
|
|
{
|
|
SCOPED_SERIALISE_CONTEXT(QUEUE_WAIT_IDLE);
|
|
Serialise_vkQueueWaitIdle(queue);
|
|
|
|
m_ContextRecord->AddChunk(scope.Get());
|
|
GetResourceManager()->MarkResourceFrameReferenced(MakeRes(queue), eFrameRef_Read);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool WrappedVulkan::Serialise_vkDeviceWaitIdle(VkDevice device)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, id, GetResourceManager()->GetID(MakeRes(device)));
|
|
|
|
if(m_State < WRITING)
|
|
{
|
|
m_Real.vkDeviceWaitIdle((VkDevice)GetResourceManager()->GetLiveResource(id).handle);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
VkResult WrappedVulkan::vkDeviceWaitIdle(VkDevice device)
|
|
{
|
|
VkResult ret = m_Real.vkDeviceWaitIdle(device);
|
|
|
|
if(m_State >= WRITING_CAPFRAME)
|
|
{
|
|
SCOPED_SERIALISE_CONTEXT(DEVICE_WAIT_IDLE);
|
|
Serialise_vkDeviceWaitIdle(device);
|
|
|
|
m_ContextRecord->AddChunk(scope.Get());
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
// Memory functions
|
|
|
|
bool WrappedVulkan::Serialise_vkAllocMemory(
|
|
VkDevice device,
|
|
const VkMemoryAllocInfo* pAllocInfo,
|
|
VkDeviceMemory* pMem)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, devId, GetResourceManager()->GetID(MakeRes(device)));
|
|
SERIALISE_ELEMENT(VkMemoryAllocInfo, info, *pAllocInfo);
|
|
SERIALISE_ELEMENT(ResourceId, id, GetResourceManager()->GetID(MakeRes(*pMem)));
|
|
|
|
if(m_State == READING)
|
|
{
|
|
VkDeviceMemory mem = VK_NULL_HANDLE;
|
|
|
|
VkResult ret = m_Real.vkAllocMemory((VkDevice)GetResourceManager()->GetLiveResource(devId).handle, &info, &mem);
|
|
|
|
ResourceId live;
|
|
|
|
if(ret != VK_SUCCESS)
|
|
{
|
|
RDCERR("Failed on resource serialise-creation, VkResult: 0x%08x", ret);
|
|
}
|
|
else
|
|
{
|
|
live = GetResourceManager()->RegisterResource(MakeRes(mem));
|
|
GetResourceManager()->AddLiveResource(id, MakeRes(mem));
|
|
|
|
m_MemoryInfo[live].size = info.allocationSize;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
VkResult WrappedVulkan::vkAllocMemory(
|
|
VkDevice device,
|
|
const VkMemoryAllocInfo* pAllocInfo,
|
|
VkDeviceMemory* pMem)
|
|
{
|
|
VkResult ret = m_Real.vkAllocMemory(device, pAllocInfo, pMem);
|
|
|
|
if(ret == VK_SUCCESS)
|
|
{
|
|
VkResource res = MakeRes(*pMem);
|
|
ResourceId id = GetResourceManager()->RegisterResource(res);
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
Chunk *chunk = NULL;
|
|
|
|
{
|
|
SCOPED_SERIALISE_CONTEXT(ALLOC_MEM);
|
|
Serialise_vkAllocMemory(device, pAllocInfo, pMem);
|
|
|
|
chunk = scope.Get();
|
|
}
|
|
|
|
// create resource record for gpu memory
|
|
VkResourceRecord *record = GetResourceManager()->AddResourceRecord(id);
|
|
RDCASSERT(record);
|
|
|
|
record->AddChunk(chunk);
|
|
}
|
|
else
|
|
{
|
|
GetResourceManager()->AddLiveResource(id, res);
|
|
}
|
|
|
|
m_MemoryInfo[id].size = pAllocInfo->allocationSize;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
VkResult WrappedVulkan::vkFreeMemory(
|
|
VkDevice device,
|
|
VkDeviceMemory mem)
|
|
{
|
|
// VKTODOMED I don't think I need to serialise this.
|
|
// the resource record just stays around until there are
|
|
// no references (which should be the same since lifetime
|
|
// tracking is app responsibility)
|
|
// we just need to clean up after ourselves on replay
|
|
ResourceId id = GetResourceManager()->GetID(MakeRes(mem));
|
|
m_MemoryInfo.erase(id);
|
|
GetResourceManager()->MarkCleanResource(id);
|
|
VkResourceRecord *record = GetResourceManager()->GetResourceRecord(id);
|
|
if(record)
|
|
record->Delete(GetResourceManager());
|
|
GetResourceManager()->UnregisterResource(MakeRes(mem));
|
|
|
|
return m_Real.vkFreeMemory(device, mem);
|
|
}
|
|
|
|
VkResult WrappedVulkan::vkMapMemory(
|
|
VkDevice device,
|
|
VkDeviceMemory mem,
|
|
VkDeviceSize offset,
|
|
VkDeviceSize size,
|
|
VkMemoryMapFlags flags,
|
|
void** ppData)
|
|
{
|
|
VkResult ret = m_Real.vkMapMemory(device, mem, offset, size, flags, ppData);
|
|
|
|
if(ret == VK_SUCCESS && ppData)
|
|
{
|
|
ResourceId id = GetResourceManager()->GetID(MakeRes(mem));
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
auto it = m_MemoryInfo.find(id);
|
|
if(it == m_MemoryInfo.end())
|
|
{
|
|
RDCERR("vkMapMemory for unknown memory handle");
|
|
}
|
|
else
|
|
{
|
|
// VKTODOHIGH handle multiple maps
|
|
it->second.mappedPtr = *ppData;
|
|
it->second.mapOffset = offset;
|
|
it->second.mapSize = size == 0 ? it->second.size : size;
|
|
it->second.mapFlags = flags;
|
|
}
|
|
}
|
|
else if(m_State >= WRITING)
|
|
{
|
|
GetResourceManager()->MarkDirtyResource(id);
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool WrappedVulkan::Serialise_vkUnmapMemory(
|
|
VkDevice device,
|
|
VkDeviceMemory mem)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, devId, GetResourceManager()->GetID(MakeRes(device)));
|
|
SERIALISE_ELEMENT(ResourceId, id, GetResourceManager()->GetID(MakeRes(mem)));
|
|
|
|
auto it = m_MemoryInfo.find(id);
|
|
|
|
SERIALISE_ELEMENT(VkMemoryMapFlags, flags, it->second.mapFlags);
|
|
SERIALISE_ELEMENT(uint64_t, memOffset, it->second.mapOffset);
|
|
SERIALISE_ELEMENT(uint64_t, memSize, it->second.mapSize);
|
|
|
|
// VKTODOHIGH: this is really horrible - this could be write-combined memory that we're
|
|
// reading from to get the latest data. This saves on having to fetch the data some
|
|
// other way and provide an interception buffer to the app, but is awful.
|
|
// we're also not doing any diff range checks, just serialising the whole memory region.
|
|
// In vulkan the common case will be one memory region for a large number of distinct
|
|
// bits of data so most maps will not change the whole region.
|
|
SERIALISE_ELEMENT_BUF(byte*, data, (byte *)it->second.mappedPtr + it->second.mapOffset, (size_t)memSize);
|
|
|
|
if(m_State < WRITING)
|
|
{
|
|
device = (VkDevice)GetResourceManager()->GetLiveResource(devId).handle;
|
|
mem = (VkDeviceMemory)GetResourceManager()->GetLiveResource(id).handle;
|
|
|
|
void *mapPtr = NULL;
|
|
VkResult ret = m_Real.vkMapMemory(device, mem, memOffset, memSize, flags, &mapPtr);
|
|
|
|
if(ret != VK_SUCCESS)
|
|
{
|
|
RDCERR("Error mapping memory on replay: 0x%08x", ret);
|
|
}
|
|
else
|
|
{
|
|
memcpy((byte *)mapPtr+memOffset, data, (size_t)memSize);
|
|
|
|
ret = m_Real.vkUnmapMemory(device, mem);
|
|
|
|
if(ret != VK_SUCCESS)
|
|
RDCERR("Error unmapping memory on replay: 0x%08x", ret);
|
|
}
|
|
|
|
SAFE_DELETE_ARRAY(data);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
VkResult WrappedVulkan::vkUnmapMemory(
|
|
VkDevice device,
|
|
VkDeviceMemory mem)
|
|
{
|
|
VkResult ret = m_Real.vkUnmapMemory(device, mem);
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
ResourceId id = GetResourceManager()->GetID(MakeRes(mem));
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
auto it = m_MemoryInfo.find(id);
|
|
if(it == m_MemoryInfo.end())
|
|
{
|
|
RDCERR("vkMapMemory for unknown memory handle");
|
|
}
|
|
else
|
|
{
|
|
if(ret == VK_SUCCESS && m_State >= WRITING_CAPFRAME)
|
|
{
|
|
SCOPED_SERIALISE_CONTEXT(UNMAP_MEM);
|
|
Serialise_vkUnmapMemory(device, mem);
|
|
|
|
VkResourceRecord *record = GetResourceManager()->GetResourceRecord(MakeRes(mem));
|
|
|
|
if(m_State == WRITING_IDLE)
|
|
{
|
|
record->AddChunk(scope.Get());
|
|
}
|
|
else
|
|
{
|
|
m_ContextRecord->AddChunk(scope.Get());
|
|
GetResourceManager()->MarkResourceFrameReferenced(MakeRes(mem), eFrameRef_Write);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
GetResourceManager()->MarkDirtyResource(MakeRes(mem));
|
|
}
|
|
|
|
it->second.mappedPtr = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
// Generic API object functions
|
|
|
|
bool WrappedVulkan::Serialise_vkBindBufferMemory(
|
|
VkDevice device,
|
|
VkBuffer buffer,
|
|
VkDeviceMemory mem,
|
|
VkDeviceSize memOffset)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, devId, GetResourceManager()->GetID(MakeRes(device)));
|
|
SERIALISE_ELEMENT(ResourceId, bufId, GetResourceManager()->GetID(MakeRes(buffer)));
|
|
SERIALISE_ELEMENT(ResourceId, memId, GetResourceManager()->GetID(MakeRes(mem)));
|
|
SERIALISE_ELEMENT(uint64_t, offs, memOffset);
|
|
|
|
if(m_State < WRITING)
|
|
{
|
|
device = (VkDevice)GetResourceManager()->GetLiveResource(devId).handle;
|
|
buffer = (VkBuffer)GetResourceManager()->GetLiveResource(bufId).handle;
|
|
mem = (VkDeviceMemory)GetResourceManager()->GetLiveResource(memId).handle;
|
|
|
|
m_Real.vkBindBufferMemory(device, buffer, mem, offs);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
VkResult WrappedVulkan::vkBindBufferMemory(
|
|
VkDevice device,
|
|
VkBuffer buffer,
|
|
VkDeviceMemory mem,
|
|
VkDeviceSize memOffset)
|
|
{
|
|
VkResourceRecord *record = GetResourceManager()->GetResourceRecord(MakeRes(buffer));
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
Chunk *chunk = NULL;
|
|
|
|
{
|
|
SCOPED_SERIALISE_CONTEXT(BIND_BUFFER_MEM);
|
|
Serialise_vkBindBufferMemory(device, buffer, mem, memOffset);
|
|
|
|
chunk = scope.Get();
|
|
}
|
|
|
|
if(m_State == WRITING_CAPFRAME)
|
|
{
|
|
m_ContextRecord->AddChunk(chunk);
|
|
|
|
GetResourceManager()->MarkResourceFrameReferenced(MakeRes(buffer), eFrameRef_Write);
|
|
GetResourceManager()->MarkResourceFrameReferenced(MakeRes(mem), eFrameRef_Read);
|
|
}
|
|
else
|
|
{
|
|
record->AddChunk(chunk);
|
|
}
|
|
|
|
record->SetMemoryRecord(GetResourceManager()->GetResourceRecord(MakeRes(mem)));
|
|
}
|
|
|
|
return m_Real.vkBindBufferMemory(device, buffer, mem, memOffset);
|
|
}
|
|
|
|
bool WrappedVulkan::Serialise_vkBindImageMemory(
|
|
VkDevice device,
|
|
VkImage image,
|
|
VkDeviceMemory mem,
|
|
VkDeviceSize memOffset)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, devId, GetResourceManager()->GetID(MakeRes(device)));
|
|
SERIALISE_ELEMENT(ResourceId, imgId, GetResourceManager()->GetID(MakeRes(image)));
|
|
SERIALISE_ELEMENT(ResourceId, memId, GetResourceManager()->GetID(MakeRes(mem)));
|
|
SERIALISE_ELEMENT(uint64_t, offs, memOffset);
|
|
|
|
if(m_State < WRITING)
|
|
{
|
|
device = (VkDevice)GetResourceManager()->GetLiveResource(devId).handle;
|
|
image = (VkImage)GetResourceManager()->GetLiveResource(imgId).handle;
|
|
mem = (VkDeviceMemory)GetResourceManager()->GetLiveResource(memId).handle;
|
|
|
|
m_Real.vkBindImageMemory(device, image, mem, offs);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
VkResult WrappedVulkan::vkBindImageMemory(
|
|
VkDevice device,
|
|
VkImage image,
|
|
VkDeviceMemory mem,
|
|
VkDeviceSize memOffset)
|
|
{
|
|
VkResourceRecord *record = GetResourceManager()->GetResourceRecord(MakeRes(image));
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
Chunk *chunk = NULL;
|
|
|
|
{
|
|
SCOPED_SERIALISE_CONTEXT(BIND_IMAGE_MEM);
|
|
Serialise_vkBindImageMemory(device, image, mem, memOffset);
|
|
|
|
chunk = scope.Get();
|
|
}
|
|
|
|
if(m_State == WRITING_CAPFRAME)
|
|
{
|
|
m_ContextRecord->AddChunk(chunk);
|
|
|
|
GetResourceManager()->MarkResourceFrameReferenced(MakeRes(image), eFrameRef_Write);
|
|
GetResourceManager()->MarkResourceFrameReferenced(MakeRes(mem), eFrameRef_Read);
|
|
}
|
|
else
|
|
{
|
|
record->AddChunk(chunk);
|
|
}
|
|
|
|
record->SetMemoryRecord(GetResourceManager()->GetResourceRecord(MakeRes(mem)));
|
|
}
|
|
|
|
return m_Real.vkBindImageMemory(device, image, mem, memOffset);
|
|
}
|
|
|
|
bool WrappedVulkan::Serialise_vkCreateBuffer(
|
|
VkDevice device,
|
|
const VkBufferCreateInfo* pCreateInfo,
|
|
VkBuffer* pBuffer)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, devId, GetResourceManager()->GetID(MakeRes(device)));
|
|
SERIALISE_ELEMENT(VkBufferCreateInfo, info, *pCreateInfo);
|
|
SERIALISE_ELEMENT(ResourceId, id, GetResourceManager()->GetID(MakeRes(*pBuffer)));
|
|
|
|
if(m_State == READING)
|
|
{
|
|
VkBuffer buf = VK_NULL_HANDLE;
|
|
|
|
VkResult ret = m_Real.vkCreateBuffer((VkDevice)GetResourceManager()->GetLiveResource(devId).handle, &info, &buf);
|
|
|
|
if(ret != VK_SUCCESS)
|
|
{
|
|
RDCERR("Failed on resource serialise-creation, VkResult: 0x%08x", ret);
|
|
}
|
|
else
|
|
{
|
|
ResourceId live = GetResourceManager()->RegisterResource(MakeRes(buf));
|
|
GetResourceManager()->AddLiveResource(id, MakeRes(buf));
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
VkResult WrappedVulkan::vkCreateBuffer(
|
|
VkDevice device,
|
|
const VkBufferCreateInfo* pCreateInfo,
|
|
VkBuffer* pBuffer)
|
|
{
|
|
VkResult ret = m_Real.vkCreateBuffer(device, pCreateInfo, pBuffer);
|
|
|
|
if(ret == VK_SUCCESS)
|
|
{
|
|
VkResource res = MakeRes(*pBuffer);
|
|
ResourceId id = GetResourceManager()->RegisterResource(res);
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
Chunk *chunk = NULL;
|
|
|
|
{
|
|
SCOPED_SERIALISE_CONTEXT(CREATE_BUFFER);
|
|
Serialise_vkCreateBuffer(device, pCreateInfo, pBuffer);
|
|
|
|
chunk = scope.Get();
|
|
}
|
|
|
|
VkResourceRecord *record = GetResourceManager()->AddResourceRecord(id);
|
|
record->AddChunk(chunk);
|
|
}
|
|
else
|
|
{
|
|
GetResourceManager()->AddLiveResource(id, res);
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool WrappedVulkan::Serialise_vkCreateBufferView(
|
|
VkDevice device,
|
|
const VkBufferViewCreateInfo* pCreateInfo,
|
|
VkBufferView* pView)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, devId, GetResourceManager()->GetID(MakeRes(device)));
|
|
SERIALISE_ELEMENT(VkBufferViewCreateInfo, info, *pCreateInfo);
|
|
SERIALISE_ELEMENT(ResourceId, id, GetResourceManager()->GetID(MakeRes(*pView)));
|
|
|
|
if(m_State == READING)
|
|
{
|
|
VkBufferView view = VK_NULL_HANDLE;
|
|
|
|
VkResult ret = m_Real.vkCreateBufferView((VkDevice)GetResourceManager()->GetLiveResource(devId).handle, &info, &view);
|
|
|
|
if(ret != VK_SUCCESS)
|
|
{
|
|
RDCERR("Failed on resource serialise-creation, VkResult: 0x%08x", ret);
|
|
}
|
|
else
|
|
{
|
|
ResourceId live = GetResourceManager()->RegisterResource(MakeRes(view));
|
|
GetResourceManager()->AddLiveResource(id, MakeRes(view));
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
VkResult WrappedVulkan::vkCreateBufferView(
|
|
VkDevice device,
|
|
const VkBufferViewCreateInfo* pCreateInfo,
|
|
VkBufferView* pView)
|
|
{
|
|
VkResult ret = m_Real.vkCreateBufferView(device, pCreateInfo, pView);
|
|
|
|
if(ret == VK_SUCCESS)
|
|
{
|
|
VkResource res = MakeRes(*pView);
|
|
ResourceId id = GetResourceManager()->RegisterResource(res);
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
Chunk *chunk = NULL;
|
|
|
|
{
|
|
SCOPED_SERIALISE_CONTEXT(CREATE_BUFFER_VIEW);
|
|
Serialise_vkCreateBufferView(device, pCreateInfo, pView);
|
|
|
|
chunk = scope.Get();
|
|
}
|
|
|
|
VkResourceRecord *record = GetResourceManager()->AddResourceRecord(id);
|
|
record->AddChunk(chunk);
|
|
record->AddParent(GetResourceManager()->GetResourceRecord(MakeRes(pCreateInfo->buffer)));
|
|
}
|
|
else
|
|
{
|
|
GetResourceManager()->AddLiveResource(id, res);
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool WrappedVulkan::Serialise_vkCreateImage(
|
|
VkDevice device,
|
|
const VkImageCreateInfo* pCreateInfo,
|
|
VkImage* pImage)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, devId, GetResourceManager()->GetID(MakeRes(device)));
|
|
SERIALISE_ELEMENT(VkImageCreateInfo, info, *pCreateInfo);
|
|
SERIALISE_ELEMENT(ResourceId, id, GetResourceManager()->GetID(MakeRes(*pImage)));
|
|
|
|
if(m_State == READING)
|
|
{
|
|
VkImage img = VK_NULL_HANDLE;
|
|
|
|
VkResult ret = m_Real.vkCreateImage((VkDevice)GetResourceManager()->GetLiveResource(devId).handle, &info, &img);
|
|
|
|
if(ret != VK_SUCCESS)
|
|
{
|
|
RDCERR("Failed on resource serialise-creation, VkResult: 0x%08x", ret);
|
|
}
|
|
else
|
|
{
|
|
ResourceId live = GetResourceManager()->RegisterResource(MakeRes(img));
|
|
GetResourceManager()->AddLiveResource(id, MakeRes(img));
|
|
|
|
m_ImageInfo[live].format = info.format;
|
|
m_ImageInfo[live].extent = info.extent;
|
|
m_ImageInfo[live].mipLevels = info.mipLevels;
|
|
m_ImageInfo[live].arraySize = info.arraySize;
|
|
|
|
VkImageSubresourceRange range;
|
|
range.baseMipLevel = range.baseArraySlice = 0;
|
|
range.mipLevels = info.mipLevels;
|
|
range.arraySize = info.arraySize;
|
|
if(info.imageType == VK_IMAGE_TYPE_3D)
|
|
range.arraySize = info.extent.depth;
|
|
|
|
m_ImageInfo[live].subresourceStates.clear();
|
|
|
|
if(!IsDepthStencilFormat(info.format))
|
|
{
|
|
range.aspect = VK_IMAGE_ASPECT_COLOR; m_ImageInfo[live].subresourceStates.push_back(ImageRegionState(range, UNTRANSITIONED_IMG_STATE, VK_IMAGE_LAYOUT_UNDEFINED));
|
|
}
|
|
else
|
|
{
|
|
range.aspect = VK_IMAGE_ASPECT_DEPTH; m_ImageInfo[live].subresourceStates.push_back(ImageRegionState(range, UNTRANSITIONED_IMG_STATE, VK_IMAGE_LAYOUT_UNDEFINED));
|
|
range.aspect = VK_IMAGE_ASPECT_STENCIL;m_ImageInfo[live].subresourceStates.push_back(ImageRegionState(range, UNTRANSITIONED_IMG_STATE, VK_IMAGE_LAYOUT_UNDEFINED));
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
VkResult WrappedVulkan::vkCreateImage(
|
|
VkDevice device,
|
|
const VkImageCreateInfo* pCreateInfo,
|
|
VkImage* pImage)
|
|
{
|
|
VkResult ret = m_Real.vkCreateImage(device, pCreateInfo, pImage);
|
|
|
|
if(ret == VK_SUCCESS)
|
|
{
|
|
VkResource res = MakeRes(*pImage);
|
|
ResourceId id = GetResourceManager()->RegisterResource(res);
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
Chunk *chunk = NULL;
|
|
|
|
{
|
|
SCOPED_SERIALISE_CONTEXT(CREATE_IMAGE);
|
|
Serialise_vkCreateImage(device, pCreateInfo, pImage);
|
|
|
|
chunk = scope.Get();
|
|
}
|
|
|
|
VkResourceRecord *record = GetResourceManager()->AddResourceRecord(id);
|
|
record->AddChunk(chunk);
|
|
}
|
|
else
|
|
{
|
|
GetResourceManager()->AddLiveResource(id, res);
|
|
}
|
|
|
|
m_ImageInfo[id].format = pCreateInfo->format;
|
|
m_ImageInfo[id].extent = pCreateInfo->extent;
|
|
m_ImageInfo[id].mipLevels = pCreateInfo->mipLevels;
|
|
m_ImageInfo[id].arraySize = pCreateInfo->arraySize;
|
|
|
|
VkImageSubresourceRange range;
|
|
range.baseMipLevel = range.baseArraySlice = 0;
|
|
range.mipLevels = pCreateInfo->mipLevels;
|
|
range.arraySize = pCreateInfo->arraySize;
|
|
if(pCreateInfo->imageType == VK_IMAGE_TYPE_3D)
|
|
range.arraySize = pCreateInfo->extent.depth;
|
|
|
|
m_ImageInfo[id].subresourceStates.clear();
|
|
|
|
if(!IsDepthStencilFormat(pCreateInfo->format))
|
|
{
|
|
range.aspect = VK_IMAGE_ASPECT_COLOR; m_ImageInfo[id].subresourceStates.push_back(ImageRegionState(range, UNTRANSITIONED_IMG_STATE, VK_IMAGE_LAYOUT_UNDEFINED));
|
|
}
|
|
else
|
|
{
|
|
range.aspect = VK_IMAGE_ASPECT_DEPTH; m_ImageInfo[id].subresourceStates.push_back(ImageRegionState(range, UNTRANSITIONED_IMG_STATE, VK_IMAGE_LAYOUT_UNDEFINED));
|
|
range.aspect = VK_IMAGE_ASPECT_STENCIL;m_ImageInfo[id].subresourceStates.push_back(ImageRegionState(range, UNTRANSITIONED_IMG_STATE, VK_IMAGE_LAYOUT_UNDEFINED));
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
// Image view functions
|
|
|
|
bool WrappedVulkan::Serialise_vkCreateImageView(
|
|
VkDevice device,
|
|
const VkImageViewCreateInfo* pCreateInfo,
|
|
VkImageView* pView)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, devId, GetResourceManager()->GetID(MakeRes(device)));
|
|
SERIALISE_ELEMENT(VkImageViewCreateInfo, info, *pCreateInfo);
|
|
SERIALISE_ELEMENT(ResourceId, id, GetResourceManager()->GetID(MakeRes(*pView)));
|
|
|
|
if(m_State == READING)
|
|
{
|
|
VkImageView view = VK_NULL_HANDLE;
|
|
|
|
VkResult ret = m_Real.vkCreateImageView((VkDevice)GetResourceManager()->GetLiveResource(devId).handle, &info, &view);
|
|
|
|
if(ret != VK_SUCCESS)
|
|
{
|
|
RDCERR("Failed on resource serialise-creation, VkResult: 0x%08x", ret);
|
|
}
|
|
else
|
|
{
|
|
ResourceId live = GetResourceManager()->RegisterResource(MakeRes(view));
|
|
GetResourceManager()->AddLiveResource(id, MakeRes(view));
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
VkResult WrappedVulkan::vkCreateImageView(
|
|
VkDevice device,
|
|
const VkImageViewCreateInfo* pCreateInfo,
|
|
VkImageView* pView)
|
|
{
|
|
VkResult ret = m_Real.vkCreateImageView(device, pCreateInfo, pView);
|
|
|
|
if(ret == VK_SUCCESS)
|
|
{
|
|
VkResource res = MakeRes(*pView);
|
|
ResourceId id = GetResourceManager()->RegisterResource(res);
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
Chunk *chunk = NULL;
|
|
|
|
{
|
|
SCOPED_SERIALISE_CONTEXT(CREATE_IMAGE_VIEW);
|
|
Serialise_vkCreateImageView(device, pCreateInfo, pView);
|
|
|
|
chunk = scope.Get();
|
|
}
|
|
|
|
VkResourceRecord *record = GetResourceManager()->AddResourceRecord(id);
|
|
record->AddChunk(chunk);
|
|
record->AddParent(GetResourceManager()->GetResourceRecord(MakeRes(pCreateInfo->image)));
|
|
}
|
|
else
|
|
{
|
|
GetResourceManager()->AddLiveResource(id, res);
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool WrappedVulkan::Serialise_vkCreateAttachmentView(
|
|
VkDevice device,
|
|
const VkAttachmentViewCreateInfo* pCreateInfo,
|
|
VkAttachmentView* pView)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, devId, GetResourceManager()->GetID(MakeRes(device)));
|
|
SERIALISE_ELEMENT(VkAttachmentViewCreateInfo, info, *pCreateInfo);
|
|
SERIALISE_ELEMENT(ResourceId, id, GetResourceManager()->GetID(MakeRes(*pView)));
|
|
|
|
if(m_State == READING)
|
|
{
|
|
VkAttachmentView view = VK_NULL_HANDLE;
|
|
|
|
VkResult ret = m_Real.vkCreateAttachmentView((VkDevice)GetResourceManager()->GetLiveResource(devId).handle, &info, &view);
|
|
|
|
if(ret != VK_SUCCESS)
|
|
{
|
|
RDCERR("Failed on resource serialise-creation, VkResult: 0x%08x", ret);
|
|
}
|
|
else
|
|
{
|
|
ResourceId live = GetResourceManager()->RegisterResource(MakeRes(view));
|
|
GetResourceManager()->AddLiveResource(id, MakeRes(view));
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
VkResult WrappedVulkan::vkCreateAttachmentView(
|
|
VkDevice device,
|
|
const VkAttachmentViewCreateInfo* pCreateInfo,
|
|
VkAttachmentView* pView)
|
|
{
|
|
VkResult ret = m_Real.vkCreateAttachmentView(device, pCreateInfo, pView);
|
|
|
|
if(ret == VK_SUCCESS)
|
|
{
|
|
VkResource res = MakeRes(*pView);
|
|
ResourceId id = GetResourceManager()->RegisterResource(res);
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
Chunk *chunk = NULL;
|
|
|
|
{
|
|
SCOPED_SERIALISE_CONTEXT(CREATE_ATTACHMENT_VIEW);
|
|
Serialise_vkCreateAttachmentView(device, pCreateInfo, pView);
|
|
|
|
chunk = scope.Get();
|
|
}
|
|
|
|
VkResourceRecord *record = GetResourceManager()->AddResourceRecord(id);
|
|
record->AddChunk(chunk);
|
|
record->AddParent(GetResourceManager()->GetResourceRecord(MakeRes(pCreateInfo->image)));
|
|
}
|
|
else
|
|
{
|
|
GetResourceManager()->AddLiveResource(id, res);
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
// Shader functions
|
|
|
|
bool WrappedVulkan::Serialise_vkCreateShaderModule(
|
|
VkDevice device,
|
|
const VkShaderModuleCreateInfo* pCreateInfo,
|
|
VkShaderModule* pShaderModule)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, devId, GetResourceManager()->GetID(MakeRes(device)));
|
|
SERIALISE_ELEMENT(VkShaderModuleCreateInfo, info, *pCreateInfo);
|
|
SERIALISE_ELEMENT(ResourceId, id, GetResourceManager()->GetID(MakeRes(*pShaderModule)));
|
|
|
|
if(m_State == READING)
|
|
{
|
|
VkShaderModule sh = VK_NULL_HANDLE;
|
|
|
|
VkResult ret = m_Real.vkCreateShaderModule((VkDevice)GetResourceManager()->GetLiveResource(devId).handle, &info, &sh);
|
|
|
|
if(ret != VK_SUCCESS)
|
|
{
|
|
RDCERR("Failed on resource serialise-creation, VkResult: 0x%08x", ret);
|
|
}
|
|
else
|
|
{
|
|
ResourceId live = GetResourceManager()->RegisterResource(MakeRes(sh));
|
|
GetResourceManager()->AddLiveResource(id, MakeRes(sh));
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
VkResult WrappedVulkan::vkCreateShaderModule(
|
|
VkDevice device,
|
|
const VkShaderModuleCreateInfo* pCreateInfo,
|
|
VkShaderModule* pShaderModule)
|
|
{
|
|
VkResult ret = m_Real.vkCreateShaderModule(device, pCreateInfo, pShaderModule);
|
|
|
|
if(ret == VK_SUCCESS)
|
|
{
|
|
VkResource res = MakeRes(*pShaderModule);
|
|
ResourceId id = GetResourceManager()->RegisterResource(res);
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
Chunk *chunk = NULL;
|
|
|
|
{
|
|
SCOPED_SERIALISE_CONTEXT(CREATE_SHADER_MODULE);
|
|
Serialise_vkCreateShaderModule(device, pCreateInfo, pShaderModule);
|
|
|
|
chunk = scope.Get();
|
|
}
|
|
|
|
VkResourceRecord *record = GetResourceManager()->AddResourceRecord(id);
|
|
record->AddChunk(chunk);
|
|
}
|
|
else
|
|
{
|
|
GetResourceManager()->AddLiveResource(id, res);
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool WrappedVulkan::Serialise_vkCreateShader(
|
|
VkDevice device,
|
|
const VkShaderCreateInfo* pCreateInfo,
|
|
VkShader* pShader)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, devId, GetResourceManager()->GetID(MakeRes(device)));
|
|
SERIALISE_ELEMENT(VkShaderCreateInfo, info, *pCreateInfo);
|
|
SERIALISE_ELEMENT(ResourceId, id, GetResourceManager()->GetID(MakeRes(*pShader)));
|
|
|
|
if(m_State == READING)
|
|
{
|
|
VkShader sh = VK_NULL_HANDLE;
|
|
|
|
VkResult ret = m_Real.vkCreateShader((VkDevice)GetResourceManager()->GetLiveResource(devId).handle, &info, &sh);
|
|
|
|
if(ret != VK_SUCCESS)
|
|
{
|
|
RDCERR("Failed on resource serialise-creation, VkResult: 0x%08x", ret);
|
|
}
|
|
else
|
|
{
|
|
ResourceId live = GetResourceManager()->RegisterResource(MakeRes(sh));
|
|
GetResourceManager()->AddLiveResource(id, MakeRes(sh));
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
VkResult WrappedVulkan::vkCreateShader(
|
|
VkDevice device,
|
|
const VkShaderCreateInfo* pCreateInfo,
|
|
VkShader* pShader)
|
|
{
|
|
VkResult ret = m_Real.vkCreateShader(device, pCreateInfo, pShader);
|
|
|
|
if(ret == VK_SUCCESS)
|
|
{
|
|
VkResource res = MakeRes(*pShader);
|
|
ResourceId id = GetResourceManager()->RegisterResource(res);
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
Chunk *chunk = NULL;
|
|
|
|
{
|
|
SCOPED_SERIALISE_CONTEXT(CREATE_SHADER);
|
|
Serialise_vkCreateShader(device, pCreateInfo, pShader);
|
|
|
|
chunk = scope.Get();
|
|
}
|
|
|
|
VkResourceRecord *record = GetResourceManager()->AddResourceRecord(id);
|
|
record->AddChunk(chunk);
|
|
|
|
VkResourceRecord *modulerecord = GetResourceManager()->GetResourceRecord(MakeRes(pCreateInfo->module));
|
|
record->AddParent(modulerecord);
|
|
}
|
|
else
|
|
{
|
|
GetResourceManager()->AddLiveResource(id, res);
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
// Pipeline functions
|
|
|
|
bool WrappedVulkan::Serialise_vkCreatePipelineCache(
|
|
VkDevice device,
|
|
const VkPipelineCacheCreateInfo* pCreateInfo,
|
|
VkPipelineCache* pPipelineCache)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, devId, GetResourceManager()->GetID(MakeRes(device)));
|
|
SERIALISE_ELEMENT(VkPipelineCacheCreateInfo, info, *pCreateInfo);
|
|
SERIALISE_ELEMENT(ResourceId, id, GetResourceManager()->GetID(MakeRes(*pPipelineCache)));
|
|
|
|
if(m_State == READING)
|
|
{
|
|
VkPipelineCache cache = VK_NULL_HANDLE;
|
|
|
|
VkResult ret = m_Real.vkCreatePipelineCache((VkDevice)GetResourceManager()->GetLiveResource(devId).handle, &info, &cache);
|
|
|
|
if(ret != VK_SUCCESS)
|
|
{
|
|
RDCERR("Failed on resource serialise-creation, VkResult: 0x%08x", ret);
|
|
}
|
|
else
|
|
{
|
|
ResourceId live = GetResourceManager()->RegisterResource(MakeRes(cache));
|
|
GetResourceManager()->AddLiveResource(id, MakeRes(cache));
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
VkResult WrappedVulkan::vkCreatePipelineCache(
|
|
VkDevice device,
|
|
const VkPipelineCacheCreateInfo* pCreateInfo,
|
|
VkPipelineCache* pPipelineCache)
|
|
{
|
|
VkResult ret = m_Real.vkCreatePipelineCache(device, pCreateInfo, pPipelineCache);
|
|
|
|
if(ret == VK_SUCCESS)
|
|
{
|
|
VkResource res = MakeRes(*pPipelineCache);
|
|
ResourceId id = GetResourceManager()->RegisterResource(res);
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
Chunk *chunk = NULL;
|
|
|
|
{
|
|
SCOPED_SERIALISE_CONTEXT(CREATE_PIPE_CACHE);
|
|
Serialise_vkCreatePipelineCache(device, pCreateInfo, pPipelineCache);
|
|
|
|
chunk = scope.Get();
|
|
}
|
|
|
|
VkResourceRecord *record = GetResourceManager()->AddResourceRecord(id);
|
|
record->AddChunk(chunk);
|
|
}
|
|
else
|
|
{
|
|
GetResourceManager()->AddLiveResource(id, res);
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool WrappedVulkan::Serialise_vkCreateGraphicsPipelines(
|
|
VkDevice device,
|
|
VkPipelineCache pipelineCache,
|
|
uint32_t count,
|
|
const VkGraphicsPipelineCreateInfo* pCreateInfos,
|
|
VkPipeline* pPipelines)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, devId, GetResourceManager()->GetID(MakeRes(device)));
|
|
SERIALISE_ELEMENT(ResourceId, cacheId, GetResourceManager()->GetID(MakeRes(pipelineCache)));
|
|
SERIALISE_ELEMENT(VkGraphicsPipelineCreateInfo, info, *pCreateInfos);
|
|
SERIALISE_ELEMENT(ResourceId, id, GetResourceManager()->GetID(MakeRes(*pPipelines)));
|
|
|
|
if(m_State == READING)
|
|
{
|
|
VkPipeline pipe = VK_NULL_HANDLE;
|
|
|
|
device = (VkDevice)GetResourceManager()->GetLiveResource(devId).handle;
|
|
pipelineCache = (VkPipelineCache)GetResourceManager()->GetLiveResource(cacheId).handle;
|
|
|
|
VkResult ret = m_Real.vkCreateGraphicsPipelines(device, pipelineCache, 1, &info, &pipe);
|
|
|
|
if(ret != VK_SUCCESS)
|
|
{
|
|
RDCERR("Failed on resource serialise-creation, VkResult: 0x%08x", ret);
|
|
}
|
|
else
|
|
{
|
|
ResourceId live = GetResourceManager()->RegisterResource(MakeRes(pipe));
|
|
GetResourceManager()->AddLiveResource(id, MakeRes(pipe));
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
VkResult WrappedVulkan::vkCreateGraphicsPipelines(
|
|
VkDevice device,
|
|
VkPipelineCache pipelineCache,
|
|
uint32_t count,
|
|
const VkGraphicsPipelineCreateInfo* pCreateInfos,
|
|
VkPipeline* pPipelines)
|
|
{
|
|
VkResult ret = m_Real.vkCreateGraphicsPipelines(device, pipelineCache, count, pCreateInfos, pPipelines);
|
|
|
|
if(ret == VK_SUCCESS)
|
|
{
|
|
for(uint32_t i=0; i < count; i++)
|
|
{
|
|
VkResource res = MakeRes(pPipelines[i]);
|
|
ResourceId id = GetResourceManager()->RegisterResource(res);
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
Chunk *chunk = NULL;
|
|
|
|
{
|
|
SCOPED_SERIALISE_CONTEXT(CREATE_GRAPHICS_PIPE);
|
|
Serialise_vkCreateGraphicsPipelines(device, pipelineCache, 1, &pCreateInfos[i], &pPipelines[i]);
|
|
|
|
chunk = scope.Get();
|
|
}
|
|
|
|
VkResourceRecord *record = GetResourceManager()->AddResourceRecord(id);
|
|
record->AddChunk(chunk);
|
|
|
|
VkResourceRecord *cacherecord = GetResourceManager()->GetResourceRecord(MakeRes(pipelineCache));
|
|
record->AddParent(cacherecord);
|
|
|
|
VkResourceRecord *layoutrecord = GetResourceManager()->GetResourceRecord(MakeRes(pCreateInfos->layout));
|
|
record->AddParent(layoutrecord);
|
|
|
|
for(uint32_t i=0; i < pCreateInfos->stageCount; i++)
|
|
{
|
|
VkResourceRecord *shaderrecord = GetResourceManager()->GetResourceRecord(MakeRes(pCreateInfos->pStages[i].shader));
|
|
record->AddParent(shaderrecord);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
GetResourceManager()->AddLiveResource(id, res);
|
|
}
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool WrappedVulkan::Serialise_vkCreateDescriptorPool(
|
|
VkDevice device,
|
|
VkDescriptorPoolUsage poolUsage,
|
|
uint32_t maxSets,
|
|
const VkDescriptorPoolCreateInfo* pCreateInfo,
|
|
VkDescriptorPool* pDescriptorPool)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, devId, GetResourceManager()->GetID(MakeRes(device)));
|
|
SERIALISE_ELEMENT(VkDescriptorPoolUsage, pooluse, poolUsage);
|
|
SERIALISE_ELEMENT(uint32_t, maxs, maxSets);
|
|
SERIALISE_ELEMENT(VkDescriptorPoolCreateInfo, info, *pCreateInfo);
|
|
SERIALISE_ELEMENT(ResourceId, id, GetResourceManager()->GetID(MakeRes(*pDescriptorPool)));
|
|
|
|
if(m_State == READING)
|
|
{
|
|
VkDescriptorPool pool = VK_NULL_HANDLE;
|
|
|
|
device = (VkDevice)GetResourceManager()->GetLiveResource(devId).handle;
|
|
|
|
VkResult ret = m_Real.vkCreateDescriptorPool(device, pooluse, maxs, &info, &pool);
|
|
|
|
if(ret != VK_SUCCESS)
|
|
{
|
|
RDCERR("Failed on resource serialise-creation, VkResult: 0x%08x", ret);
|
|
}
|
|
else
|
|
{
|
|
ResourceId live = GetResourceManager()->RegisterResource(MakeRes(pool));
|
|
GetResourceManager()->AddLiveResource(id, MakeRes(pool));
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
VkResult WrappedVulkan::vkCreateDescriptorPool(
|
|
VkDevice device,
|
|
VkDescriptorPoolUsage poolUsage,
|
|
uint32_t maxSets,
|
|
const VkDescriptorPoolCreateInfo* pCreateInfo,
|
|
VkDescriptorPool* pDescriptorPool)
|
|
{
|
|
VkResult ret = m_Real.vkCreateDescriptorPool(device, poolUsage, maxSets, pCreateInfo, pDescriptorPool);
|
|
|
|
if(ret == VK_SUCCESS)
|
|
{
|
|
VkResource res = MakeRes(*pDescriptorPool);
|
|
ResourceId id = GetResourceManager()->RegisterResource(res);
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
Chunk *chunk = NULL;
|
|
|
|
{
|
|
SCOPED_SERIALISE_CONTEXT(CREATE_DESCRIPTOR_POOL);
|
|
Serialise_vkCreateDescriptorPool(device, poolUsage, maxSets, pCreateInfo, pDescriptorPool);
|
|
|
|
chunk = scope.Get();
|
|
}
|
|
|
|
VkResourceRecord *record = GetResourceManager()->AddResourceRecord(id);
|
|
record->AddChunk(chunk);
|
|
}
|
|
else
|
|
{
|
|
GetResourceManager()->AddLiveResource(id, res);
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool WrappedVulkan::Serialise_vkCreateDescriptorSetLayout(
|
|
VkDevice device,
|
|
const VkDescriptorSetLayoutCreateInfo* pCreateInfo,
|
|
VkDescriptorSetLayout* pSetLayout)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, devId, GetResourceManager()->GetID(MakeRes(device)));
|
|
SERIALISE_ELEMENT(VkDescriptorSetLayoutCreateInfo, info, *pCreateInfo);
|
|
SERIALISE_ELEMENT(ResourceId, id, GetResourceManager()->GetID(MakeRes(*pSetLayout)));
|
|
|
|
if(m_State == READING)
|
|
{
|
|
VkDescriptorSetLayout layout = VK_NULL_HANDLE;
|
|
|
|
device = (VkDevice)GetResourceManager()->GetLiveResource(devId).handle;
|
|
|
|
VkResult ret = m_Real.vkCreateDescriptorSetLayout(device, &info, &layout);
|
|
|
|
if(ret != VK_SUCCESS)
|
|
{
|
|
RDCERR("Failed on resource serialise-creation, VkResult: 0x%08x", ret);
|
|
}
|
|
else
|
|
{
|
|
ResourceId live = GetResourceManager()->RegisterResource(MakeRes(layout));
|
|
GetResourceManager()->AddLiveResource(id, MakeRes(layout));
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
VkResult WrappedVulkan::vkCreateDescriptorSetLayout(
|
|
VkDevice device,
|
|
const VkDescriptorSetLayoutCreateInfo* pCreateInfo,
|
|
VkDescriptorSetLayout* pSetLayout)
|
|
{
|
|
VkResult ret = m_Real.vkCreateDescriptorSetLayout(device, pCreateInfo, pSetLayout);
|
|
|
|
if(ret == VK_SUCCESS)
|
|
{
|
|
VkResource res = MakeRes(*pSetLayout);
|
|
ResourceId id = GetResourceManager()->RegisterResource(res);
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
Chunk *chunk = NULL;
|
|
|
|
{
|
|
SCOPED_SERIALISE_CONTEXT(CREATE_DESCRIPTOR_SET_LAYOUT);
|
|
Serialise_vkCreateDescriptorSetLayout(device, pCreateInfo, pSetLayout);
|
|
|
|
chunk = scope.Get();
|
|
}
|
|
|
|
VkResourceRecord *record = GetResourceManager()->AddResourceRecord(id);
|
|
record->AddChunk(chunk);
|
|
}
|
|
else
|
|
{
|
|
GetResourceManager()->AddLiveResource(id, res);
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool WrappedVulkan::Serialise_vkCreatePipelineLayout(
|
|
VkDevice device,
|
|
const VkPipelineLayoutCreateInfo* pCreateInfo,
|
|
VkPipelineLayout* pPipelineLayout)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, devId, GetResourceManager()->GetID(MakeRes(device)));
|
|
SERIALISE_ELEMENT(VkPipelineLayoutCreateInfo, info, *pCreateInfo);
|
|
SERIALISE_ELEMENT(ResourceId, id, GetResourceManager()->GetID(MakeRes(*pPipelineLayout)));
|
|
|
|
if(m_State == READING)
|
|
{
|
|
VkPipelineLayout layout = VK_NULL_HANDLE;
|
|
|
|
device = (VkDevice)GetResourceManager()->GetLiveResource(devId).handle;
|
|
|
|
VkResult ret = m_Real.vkCreatePipelineLayout(device, &info, &layout);
|
|
|
|
if(ret != VK_SUCCESS)
|
|
{
|
|
RDCERR("Failed on resource serialise-creation, VkResult: 0x%08x", ret);
|
|
}
|
|
else
|
|
{
|
|
ResourceId live = GetResourceManager()->RegisterResource(MakeRes(layout));
|
|
GetResourceManager()->AddLiveResource(id, MakeRes(layout));
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
VkResult WrappedVulkan::vkCreatePipelineLayout(
|
|
VkDevice device,
|
|
const VkPipelineLayoutCreateInfo* pCreateInfo,
|
|
VkPipelineLayout* pPipelineLayout)
|
|
{
|
|
VkResult ret = m_Real.vkCreatePipelineLayout(device, pCreateInfo, pPipelineLayout);
|
|
|
|
if(ret == VK_SUCCESS)
|
|
{
|
|
VkResource res = MakeRes(*pPipelineLayout);
|
|
ResourceId id = GetResourceManager()->RegisterResource(res);
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
Chunk *chunk = NULL;
|
|
|
|
{
|
|
SCOPED_SERIALISE_CONTEXT(CREATE_PIPE_LAYOUT);
|
|
Serialise_vkCreatePipelineLayout(device, pCreateInfo, pPipelineLayout);
|
|
|
|
chunk = scope.Get();
|
|
}
|
|
|
|
VkResourceRecord *record = GetResourceManager()->AddResourceRecord(id);
|
|
record->AddChunk(chunk);
|
|
}
|
|
else
|
|
{
|
|
GetResourceManager()->AddLiveResource(id, res);
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
// Sampler functions
|
|
|
|
bool WrappedVulkan::Serialise_vkCreateSampler(
|
|
VkDevice device,
|
|
const VkSamplerCreateInfo* pCreateInfo,
|
|
VkSampler* pSampler)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, devId, GetResourceManager()->GetID(MakeRes(device)));
|
|
SERIALISE_ELEMENT(VkSamplerCreateInfo, info, *pCreateInfo);
|
|
SERIALISE_ELEMENT(ResourceId, id, GetResourceManager()->GetID(MakeRes(*pSampler)));
|
|
|
|
if(m_State == READING)
|
|
{
|
|
VkSampler samp = VK_NULL_HANDLE;
|
|
|
|
VkResult ret = m_Real.vkCreateSampler((VkDevice)GetResourceManager()->GetLiveResource(devId).handle, &info, &samp);
|
|
|
|
if(ret != VK_SUCCESS)
|
|
{
|
|
RDCERR("Failed on resource serialise-creation, VkResult: 0x%08x", ret);
|
|
}
|
|
else
|
|
{
|
|
ResourceId live = GetResourceManager()->RegisterResource(MakeRes(samp));
|
|
GetResourceManager()->AddLiveResource(id, MakeRes(samp));
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
VkResult WrappedVulkan::vkCreateSampler(
|
|
VkDevice device,
|
|
const VkSamplerCreateInfo* pCreateInfo,
|
|
VkSampler* pSampler)
|
|
{
|
|
VkResult ret = m_Real.vkCreateSampler(device, pCreateInfo, pSampler);
|
|
|
|
if(ret == VK_SUCCESS)
|
|
{
|
|
VkResource res = MakeRes(*pSampler);
|
|
ResourceId id = GetResourceManager()->RegisterResource(res);
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
Chunk *chunk = NULL;
|
|
|
|
{
|
|
SCOPED_SERIALISE_CONTEXT(CREATE_SAMPLER);
|
|
Serialise_vkCreateSampler(device, pCreateInfo, pSampler);
|
|
|
|
chunk = scope.Get();
|
|
}
|
|
|
|
VkResourceRecord *record = GetResourceManager()->AddResourceRecord(id);
|
|
record->AddChunk(chunk);
|
|
}
|
|
else
|
|
{
|
|
GetResourceManager()->AddLiveResource(id, res);
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool WrappedVulkan::Serialise_vkCreateSemaphore(
|
|
VkDevice device,
|
|
const VkSemaphoreCreateInfo* pCreateInfo,
|
|
VkSemaphore* pSemaphore)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, devId, GetResourceManager()->GetID(MakeRes(device)));
|
|
SERIALISE_ELEMENT(VkSemaphoreCreateInfo, info, *pCreateInfo);
|
|
SERIALISE_ELEMENT(ResourceId, id, GetResourceManager()->GetID(MakeRes(*pSemaphore)));
|
|
|
|
if(m_State == READING)
|
|
{
|
|
VkSemaphore sem = VK_NULL_HANDLE;
|
|
|
|
VkResult ret = m_Real.vkCreateSemaphore((VkDevice)GetResourceManager()->GetLiveResource(devId).handle, &info, &sem);
|
|
|
|
if(ret != VK_SUCCESS)
|
|
{
|
|
RDCERR("Failed on resource serialise-creation, VkResult: 0x%08x", ret);
|
|
}
|
|
else
|
|
{
|
|
ResourceId live = GetResourceManager()->RegisterResource(MakeRes(sem));
|
|
GetResourceManager()->AddLiveResource(id, MakeRes(sem));
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
VkResult WrappedVulkan::vkCreateSemaphore(
|
|
VkDevice device,
|
|
const VkSemaphoreCreateInfo* pCreateInfo,
|
|
VkSemaphore* pSemaphore)
|
|
{
|
|
VkResult ret = m_Real.vkCreateSemaphore(device, pCreateInfo, pSemaphore);
|
|
|
|
if(ret == VK_SUCCESS)
|
|
{
|
|
VkResource res = MakeRes(*pSemaphore);
|
|
ResourceId id = GetResourceManager()->RegisterResource(res);
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
Chunk *chunk = NULL;
|
|
|
|
{
|
|
SCOPED_SERIALISE_CONTEXT(CREATE_SEMAPHORE);
|
|
Serialise_vkCreateSemaphore(device, pCreateInfo, pSemaphore);
|
|
|
|
chunk = scope.Get();
|
|
}
|
|
|
|
VkResourceRecord *record = GetResourceManager()->AddResourceRecord(id);
|
|
record->AddChunk(chunk);
|
|
}
|
|
else
|
|
{
|
|
GetResourceManager()->AddLiveResource(id, res);
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool WrappedVulkan::Serialise_vkCreateFramebuffer(
|
|
VkDevice device,
|
|
const VkFramebufferCreateInfo* pCreateInfo,
|
|
VkFramebuffer* pFramebuffer)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, devId, GetResourceManager()->GetID(MakeRes(device)));
|
|
SERIALISE_ELEMENT(VkFramebufferCreateInfo, info, *pCreateInfo);
|
|
SERIALISE_ELEMENT(ResourceId, id, GetResourceManager()->GetID(MakeRes(*pFramebuffer)));
|
|
|
|
if(m_State == READING)
|
|
{
|
|
VkFramebuffer fb = VK_NULL_HANDLE;
|
|
|
|
VkResult ret = m_Real.vkCreateFramebuffer((VkDevice)GetResourceManager()->GetLiveResource(devId).handle, &info, &fb);
|
|
|
|
if(ret != VK_SUCCESS)
|
|
{
|
|
RDCERR("Failed on resource serialise-creation, VkResult: 0x%08x", ret);
|
|
}
|
|
else
|
|
{
|
|
ResourceId live = GetResourceManager()->RegisterResource(MakeRes(fb));
|
|
GetResourceManager()->AddLiveResource(id, MakeRes(fb));
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
VkResult WrappedVulkan::vkCreateFramebuffer(
|
|
VkDevice device,
|
|
const VkFramebufferCreateInfo* pCreateInfo,
|
|
VkFramebuffer* pFramebuffer)
|
|
{
|
|
VkResult ret = m_Real.vkCreateFramebuffer(device, pCreateInfo, pFramebuffer);
|
|
|
|
if(ret == VK_SUCCESS)
|
|
{
|
|
VkResource res = MakeRes(*pFramebuffer);
|
|
ResourceId id = GetResourceManager()->RegisterResource(res);
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
Chunk *chunk = NULL;
|
|
|
|
{
|
|
SCOPED_SERIALISE_CONTEXT(CREATE_FRAMEBUFFER);
|
|
Serialise_vkCreateFramebuffer(device, pCreateInfo, pFramebuffer);
|
|
|
|
chunk = scope.Get();
|
|
}
|
|
|
|
VkResourceRecord *record = GetResourceManager()->AddResourceRecord(id);
|
|
record->AddChunk(chunk);
|
|
|
|
for(uint32_t i=0; i < pCreateInfo->attachmentCount; i++)
|
|
{
|
|
record->AddParent(GetResourceManager()->GetResourceRecord(MakeRes(pCreateInfo->pAttachments[i].view)));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
GetResourceManager()->AddLiveResource(id, res);
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool WrappedVulkan::Serialise_vkCreateRenderPass(
|
|
VkDevice device,
|
|
const VkRenderPassCreateInfo* pCreateInfo,
|
|
VkRenderPass* pRenderPass)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, devId, GetResourceManager()->GetID(MakeRes(device)));
|
|
SERIALISE_ELEMENT(VkRenderPassCreateInfo, info, *pCreateInfo);
|
|
SERIALISE_ELEMENT(ResourceId, id, GetResourceManager()->GetID(MakeRes(*pRenderPass)));
|
|
|
|
if(m_State == READING)
|
|
{
|
|
VkRenderPass rp = VK_NULL_HANDLE;
|
|
|
|
VkResult ret = m_Real.vkCreateRenderPass((VkDevice)GetResourceManager()->GetLiveResource(devId).handle, &info, &rp);
|
|
|
|
if(ret != VK_SUCCESS)
|
|
{
|
|
RDCERR("Failed on resource serialise-creation, VkResult: 0x%08x", ret);
|
|
}
|
|
else
|
|
{
|
|
ResourceId live = GetResourceManager()->RegisterResource(MakeRes(rp));
|
|
GetResourceManager()->AddLiveResource(id, MakeRes(rp));
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
VkResult WrappedVulkan::vkCreateRenderPass(
|
|
VkDevice device,
|
|
const VkRenderPassCreateInfo* pCreateInfo,
|
|
VkRenderPass* pRenderPass)
|
|
{
|
|
VkResult ret = m_Real.vkCreateRenderPass(device, pCreateInfo, pRenderPass);
|
|
|
|
if(ret == VK_SUCCESS)
|
|
{
|
|
VkResource res = MakeRes(*pRenderPass);
|
|
ResourceId id = GetResourceManager()->RegisterResource(res);
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
Chunk *chunk = NULL;
|
|
|
|
{
|
|
SCOPED_SERIALISE_CONTEXT(CREATE_RENDERPASS);
|
|
Serialise_vkCreateRenderPass(device, pCreateInfo, pRenderPass);
|
|
|
|
chunk = scope.Get();
|
|
}
|
|
|
|
VkResourceRecord *record = GetResourceManager()->AddResourceRecord(id);
|
|
record->AddChunk(chunk);
|
|
}
|
|
else
|
|
{
|
|
GetResourceManager()->AddLiveResource(id, res);
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
// State object functions
|
|
|
|
bool WrappedVulkan::Serialise_vkCreateDynamicViewportState(
|
|
VkDevice device,
|
|
const VkDynamicViewportStateCreateInfo* pCreateInfo,
|
|
VkDynamicViewportState* pState)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, devId, GetResourceManager()->GetID(MakeRes(device)));
|
|
SERIALISE_ELEMENT(VkDynamicViewportStateCreateInfo, info, *pCreateInfo);
|
|
SERIALISE_ELEMENT(ResourceId, id, GetResourceManager()->GetID(MakeRes(*pState)));
|
|
|
|
if(m_State == READING)
|
|
{
|
|
VkDynamicViewportState state = VK_NULL_HANDLE;
|
|
|
|
VkResult ret = m_Real.vkCreateDynamicViewportState((VkDevice)GetResourceManager()->GetLiveResource(devId).handle, &info, &state);
|
|
|
|
if(ret != VK_SUCCESS)
|
|
{
|
|
RDCERR("Failed on resource serialise-creation, VkResult: 0x%08x", ret);
|
|
}
|
|
else
|
|
{
|
|
ResourceId live = GetResourceManager()->RegisterResource(MakeRes(state));
|
|
GetResourceManager()->AddLiveResource(id, MakeRes(state));
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
VkResult WrappedVulkan::vkCreateDynamicViewportState(
|
|
VkDevice device,
|
|
const VkDynamicViewportStateCreateInfo* pCreateInfo,
|
|
VkDynamicViewportState* pState)
|
|
{
|
|
VkResult ret = m_Real.vkCreateDynamicViewportState(device, pCreateInfo, pState);
|
|
|
|
if(ret == VK_SUCCESS)
|
|
{
|
|
VkResource res = MakeRes(*pState);
|
|
ResourceId id = GetResourceManager()->RegisterResource(res);
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
Chunk *chunk = NULL;
|
|
|
|
{
|
|
SCOPED_SERIALISE_CONTEXT(CREATE_VIEWPORT_STATE);
|
|
Serialise_vkCreateDynamicViewportState(device, pCreateInfo, pState);
|
|
|
|
chunk = scope.Get();
|
|
}
|
|
|
|
VkResourceRecord *record = GetResourceManager()->AddResourceRecord(id);
|
|
record->AddChunk(chunk);
|
|
}
|
|
else
|
|
{
|
|
GetResourceManager()->AddLiveResource(id, res);
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool WrappedVulkan::Serialise_vkCreateDynamicRasterState(
|
|
VkDevice device,
|
|
const VkDynamicRasterStateCreateInfo* pCreateInfo,
|
|
VkDynamicRasterState* pState)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, devId, GetResourceManager()->GetID(MakeRes(device)));
|
|
SERIALISE_ELEMENT(VkDynamicRasterStateCreateInfo, info, *pCreateInfo);
|
|
SERIALISE_ELEMENT(ResourceId, id, GetResourceManager()->GetID(MakeRes(*pState)));
|
|
|
|
if(m_State == READING)
|
|
{
|
|
VkDynamicRasterState state = VK_NULL_HANDLE;
|
|
|
|
VkResult ret = m_Real.vkCreateDynamicRasterState((VkDevice)GetResourceManager()->GetLiveResource(devId).handle, &info, &state);
|
|
|
|
if(ret != VK_SUCCESS)
|
|
{
|
|
RDCERR("Failed on resource serialise-creation, VkResult: 0x%08x", ret);
|
|
}
|
|
else
|
|
{
|
|
ResourceId live = GetResourceManager()->RegisterResource(MakeRes(state));
|
|
GetResourceManager()->AddLiveResource(id, MakeRes(state));
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
VkResult WrappedVulkan::vkCreateDynamicRasterState(
|
|
VkDevice device,
|
|
const VkDynamicRasterStateCreateInfo* pCreateInfo,
|
|
VkDynamicRasterState* pState)
|
|
{
|
|
VkResult ret = m_Real.vkCreateDynamicRasterState(device, pCreateInfo, pState);
|
|
|
|
if(ret == VK_SUCCESS)
|
|
{
|
|
VkResource res = MakeRes(*pState);
|
|
ResourceId id = GetResourceManager()->RegisterResource(res);
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
Chunk *chunk = NULL;
|
|
|
|
{
|
|
SCOPED_SERIALISE_CONTEXT(CREATE_RASTER_STATE);
|
|
Serialise_vkCreateDynamicRasterState(device, pCreateInfo, pState);
|
|
|
|
chunk = scope.Get();
|
|
}
|
|
|
|
VkResourceRecord *record = GetResourceManager()->AddResourceRecord(id);
|
|
record->AddChunk(chunk);
|
|
}
|
|
else
|
|
{
|
|
GetResourceManager()->AddLiveResource(id, res);
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool WrappedVulkan::Serialise_vkCreateDynamicColorBlendState(
|
|
VkDevice device,
|
|
const VkDynamicColorBlendStateCreateInfo* pCreateInfo,
|
|
VkDynamicColorBlendState* pState)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, devId, GetResourceManager()->GetID(MakeRes(device)));
|
|
SERIALISE_ELEMENT(VkDynamicColorBlendStateCreateInfo, info, *pCreateInfo);
|
|
SERIALISE_ELEMENT(ResourceId, id, GetResourceManager()->GetID(MakeRes(*pState)));
|
|
|
|
if(m_State == READING)
|
|
{
|
|
VkDynamicColorBlendState state = VK_NULL_HANDLE;
|
|
|
|
VkResult ret = m_Real.vkCreateDynamicColorBlendState((VkDevice)GetResourceManager()->GetLiveResource(devId).handle, &info, &state);
|
|
|
|
if(ret != VK_SUCCESS)
|
|
{
|
|
RDCERR("Failed on resource serialise-creation, VkResult: 0x%08x", ret);
|
|
}
|
|
else
|
|
{
|
|
ResourceId live = GetResourceManager()->RegisterResource(MakeRes(state));
|
|
GetResourceManager()->AddLiveResource(id, MakeRes(state));
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
VkResult WrappedVulkan::vkCreateDynamicColorBlendState(
|
|
VkDevice device,
|
|
const VkDynamicColorBlendStateCreateInfo* pCreateInfo,
|
|
VkDynamicColorBlendState* pState)
|
|
{
|
|
VkResult ret = m_Real.vkCreateDynamicColorBlendState(device, pCreateInfo, pState);
|
|
|
|
if(ret == VK_SUCCESS)
|
|
{
|
|
VkResource res = MakeRes(*pState);
|
|
ResourceId id = GetResourceManager()->RegisterResource(res);
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
Chunk *chunk = NULL;
|
|
|
|
{
|
|
SCOPED_SERIALISE_CONTEXT(CREATE_BLEND_STATE);
|
|
Serialise_vkCreateDynamicColorBlendState(device, pCreateInfo, pState);
|
|
|
|
chunk = scope.Get();
|
|
}
|
|
|
|
VkResourceRecord *record = GetResourceManager()->AddResourceRecord(id);
|
|
record->AddChunk(chunk);
|
|
}
|
|
else
|
|
{
|
|
GetResourceManager()->AddLiveResource(id, res);
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool WrappedVulkan::Serialise_vkCreateDynamicDepthStencilState(
|
|
VkDevice device,
|
|
const VkDynamicDepthStencilStateCreateInfo* pCreateInfo,
|
|
VkDynamicDepthStencilState* pState)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, devId, GetResourceManager()->GetID(MakeRes(device)));
|
|
SERIALISE_ELEMENT(VkDynamicDepthStencilStateCreateInfo, info, *pCreateInfo);
|
|
SERIALISE_ELEMENT(ResourceId, id, GetResourceManager()->GetID(MakeRes(*pState)));
|
|
|
|
if(m_State == READING)
|
|
{
|
|
VkDynamicDepthStencilState state = VK_NULL_HANDLE;
|
|
|
|
VkResult ret = m_Real.vkCreateDynamicDepthStencilState((VkDevice)GetResourceManager()->GetLiveResource(devId).handle, &info, &state);
|
|
|
|
if(ret != VK_SUCCESS)
|
|
{
|
|
RDCERR("Failed on resource serialise-creation, VkResult: 0x%08x", ret);
|
|
}
|
|
else
|
|
{
|
|
ResourceId live = GetResourceManager()->RegisterResource(MakeRes(state));
|
|
GetResourceManager()->AddLiveResource(id, MakeRes(state));
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
VkResult WrappedVulkan::vkCreateDynamicDepthStencilState(
|
|
VkDevice device,
|
|
const VkDynamicDepthStencilStateCreateInfo* pCreateInfo,
|
|
VkDynamicDepthStencilState* pState)
|
|
{
|
|
VkResult ret = m_Real.vkCreateDynamicDepthStencilState(device, pCreateInfo, pState);
|
|
|
|
if(ret == VK_SUCCESS)
|
|
{
|
|
VkResource res = MakeRes(*pState);
|
|
ResourceId id = GetResourceManager()->RegisterResource(res);
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
Chunk *chunk = NULL;
|
|
|
|
{
|
|
SCOPED_SERIALISE_CONTEXT(CREATE_DEPTH_STATE);
|
|
Serialise_vkCreateDynamicDepthStencilState(device, pCreateInfo, pState);
|
|
|
|
chunk = scope.Get();
|
|
}
|
|
|
|
VkResourceRecord *record = GetResourceManager()->AddResourceRecord(id);
|
|
record->AddChunk(chunk);
|
|
}
|
|
else
|
|
{
|
|
GetResourceManager()->AddLiveResource(id, res);
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
// Command pool functions
|
|
|
|
bool WrappedVulkan::Serialise_vkCreateCommandPool(
|
|
VkDevice device,
|
|
const VkCmdPoolCreateInfo* pCreateInfo,
|
|
VkCmdPool* pCmdPool)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, devId, GetResourceManager()->GetID(MakeRes(device)));
|
|
SERIALISE_ELEMENT(VkCmdPoolCreateInfo, info, *pCreateInfo);
|
|
SERIALISE_ELEMENT(ResourceId, id, GetResourceManager()->GetID(MakeRes(*pCmdPool)));
|
|
|
|
if(m_State == READING)
|
|
{
|
|
VkCmdPool pool = VK_NULL_HANDLE;
|
|
|
|
VkResult ret = m_Real.vkCreateCommandPool((VkDevice)GetResourceManager()->GetLiveResource(devId).handle, &info, &pool);
|
|
|
|
if(ret != VK_SUCCESS)
|
|
{
|
|
RDCERR("Failed on resource serialise-creation, VkResult: 0x%08x", ret);
|
|
}
|
|
else
|
|
{
|
|
ResourceId live = GetResourceManager()->RegisterResource(MakeRes(pool));
|
|
GetResourceManager()->AddLiveResource(id, MakeRes(pool));
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
VkResult WrappedVulkan::vkCreateCommandPool(
|
|
VkDevice device,
|
|
const VkCmdPoolCreateInfo* pCreateInfo,
|
|
VkCmdPool* pCmdPool)
|
|
{
|
|
VkResult ret = m_Real.vkCreateCommandPool(device, pCreateInfo, pCmdPool);
|
|
|
|
if(ret == VK_SUCCESS)
|
|
{
|
|
VkResource res = MakeRes(*pCmdPool);
|
|
ResourceId id = GetResourceManager()->RegisterResource(res);
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
Chunk *chunk = NULL;
|
|
|
|
{
|
|
SCOPED_SERIALISE_CONTEXT(CREATE_CMD_POOL);
|
|
Serialise_vkCreateCommandPool(device, pCreateInfo, pCmdPool);
|
|
|
|
chunk = scope.Get();
|
|
}
|
|
|
|
VkResourceRecord *record = GetResourceManager()->AddResourceRecord(id);
|
|
record->AddChunk(chunk);
|
|
}
|
|
else
|
|
{
|
|
GetResourceManager()->AddLiveResource(id, res);
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
VkResult WrappedVulkan::vkResetCommandPool(
|
|
VkDevice device,
|
|
VkCmdPool cmdPool,
|
|
VkCmdPoolResetFlags flags)
|
|
{
|
|
// VKTODOMED do I need to serialise this? just a driver hint..
|
|
return m_Real.vkResetCommandPool(device, cmdPool, flags);
|
|
}
|
|
|
|
|
|
// Command buffer functions
|
|
|
|
VkResult WrappedVulkan::vkCreateCommandBuffer(
|
|
VkDevice device,
|
|
const VkCmdBufferCreateInfo* pCreateInfo,
|
|
VkCmdBuffer* pCmdBuffer)
|
|
{
|
|
VkResult ret = m_Real.vkCreateCommandBuffer(device, pCreateInfo, pCmdBuffer);
|
|
|
|
if(ret == VK_SUCCESS)
|
|
{
|
|
VkResource res = MakeRes(*pCmdBuffer);
|
|
ResourceId id = GetResourceManager()->RegisterResource(res);
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
VkResourceRecord *record = GetResourceManager()->AddResourceRecord(id);
|
|
|
|
record->bakedCommands = NULL;
|
|
|
|
record->AddParent(GetResourceManager()->GetResourceRecord(MakeRes(pCreateInfo->cmdPool)));
|
|
|
|
// we don't serialise this as we never create this command buffer directly.
|
|
// Instead we create a command buffer for each baked list that we find.
|
|
}
|
|
else
|
|
{
|
|
GetResourceManager()->AddLiveResource(id, res);
|
|
}
|
|
|
|
m_CmdBufferInfo[id].device = device;
|
|
m_CmdBufferInfo[id].createInfo = *pCreateInfo;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool WrappedVulkan::Serialise_vkAllocDescriptorSets(
|
|
VkDevice device,
|
|
VkDescriptorPool descriptorPool,
|
|
VkDescriptorSetUsage setUsage,
|
|
uint32_t count,
|
|
const VkDescriptorSetLayout* pSetLayouts,
|
|
VkDescriptorSet* pDescriptorSets,
|
|
uint32_t* pCount)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, devId, GetResourceManager()->GetID(MakeRes(device)));
|
|
SERIALISE_ELEMENT(ResourceId, poolId, GetResourceManager()->GetID(MakeRes(descriptorPool)));
|
|
SERIALISE_ELEMENT(VkDescriptorSetUsage, usage, setUsage);
|
|
SERIALISE_ELEMENT(ResourceId, layoutId, GetResourceManager()->GetID(MakeRes(*pSetLayouts)));
|
|
SERIALISE_ELEMENT(ResourceId, id, GetResourceManager()->GetID(MakeRes(*pDescriptorSets)));
|
|
|
|
if(m_State == READING)
|
|
{
|
|
VkDescriptorSet descset = VK_NULL_HANDLE;
|
|
|
|
device = (VkDevice)GetResourceManager()->GetLiveResource(devId).handle;
|
|
descriptorPool = (VkDescriptorPool)GetResourceManager()->GetLiveResource(poolId).handle;
|
|
VkDescriptorSetLayout layout = (VkDescriptorSetLayout)GetResourceManager()->GetLiveResource(layoutId).handle;
|
|
|
|
uint32_t cnt = 0;
|
|
VkResult ret = m_Real.vkAllocDescriptorSets(device, descriptorPool, usage, 1, &layout, &descset, &cnt);
|
|
|
|
if(ret != VK_SUCCESS)
|
|
{
|
|
RDCERR("Failed on resource serialise-creation, VkResult: 0x%08x", ret);
|
|
}
|
|
else
|
|
{
|
|
ResourceId live = GetResourceManager()->RegisterResource(MakeRes(descset));
|
|
GetResourceManager()->AddLiveResource(id, MakeRes(descset));
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
VkResult WrappedVulkan::vkAllocDescriptorSets(
|
|
VkDevice device,
|
|
VkDescriptorPool descriptorPool,
|
|
VkDescriptorSetUsage setUsage,
|
|
uint32_t count,
|
|
const VkDescriptorSetLayout* pSetLayouts,
|
|
VkDescriptorSet* pDescriptorSets,
|
|
uint32_t* pCount)
|
|
{
|
|
VkResult ret = m_Real.vkAllocDescriptorSets(device, descriptorPool, setUsage, count, pSetLayouts, pDescriptorSets, pCount);
|
|
|
|
RDCASSERT(pCount == NULL || *pCount == count); // VKTODOMED: find out what *pCount < count means
|
|
|
|
if(ret == VK_SUCCESS)
|
|
{
|
|
for(uint32_t i=0; i < count; i++)
|
|
{
|
|
VkResource res = MakeRes(pDescriptorSets[i]);
|
|
ResourceId id = GetResourceManager()->RegisterResource(res);
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
Chunk *chunk = NULL;
|
|
|
|
{
|
|
SCOPED_SERIALISE_CONTEXT(ALLOC_DESC_SET);
|
|
Serialise_vkAllocDescriptorSets(device, descriptorPool, setUsage, 1, &pSetLayouts[i], &pDescriptorSets[i], NULL);
|
|
|
|
chunk = scope.Get();
|
|
}
|
|
|
|
VkResourceRecord *record = GetResourceManager()->AddResourceRecord(id);
|
|
record->AddChunk(chunk);
|
|
|
|
record->AddParent(GetResourceManager()->GetResourceRecord(MakeRes(descriptorPool)));
|
|
record->AddParent(GetResourceManager()->GetResourceRecord(MakeRes(pSetLayouts[i])));
|
|
}
|
|
else
|
|
{
|
|
GetResourceManager()->AddLiveResource(id, res);
|
|
}
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
VkResult WrappedVulkan::vkFreeDescriptorSets(
|
|
VkDevice device,
|
|
VkDescriptorPool descriptorPool,
|
|
uint32_t count,
|
|
const VkDescriptorSet* pDescriptorSets)
|
|
{
|
|
VkResult ret = m_Real.vkFreeDescriptorSets(device, descriptorPool, count, pDescriptorSets);
|
|
|
|
if(ret == VK_SUCCESS)
|
|
{
|
|
for(uint32_t i=0; i < count; i++)
|
|
{
|
|
VkResource res = MakeRes(pDescriptorSets[i]);
|
|
ResourceId id = GetResourceManager()->GetID(res);
|
|
|
|
GetResourceManager()->MarkCleanResource(id);
|
|
VkResourceRecord *record = GetResourceManager()->GetResourceRecord(id);
|
|
if(record)
|
|
record->Delete(GetResourceManager());
|
|
GetResourceManager()->UnregisterResource(res);
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool WrappedVulkan::Serialise_vkUpdateDescriptorSets(
|
|
VkDevice device,
|
|
uint32_t writeCount,
|
|
const VkWriteDescriptorSet* pDescriptorWrites,
|
|
uint32_t copyCount,
|
|
const VkCopyDescriptorSet* pDescriptorCopies)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, devId, GetResourceManager()->GetID(MakeRes(device)));
|
|
SERIALISE_ELEMENT(bool, writes, writeCount == 1);
|
|
|
|
VkWriteDescriptorSet writeDesc;
|
|
VkCopyDescriptorSet copyDesc;
|
|
if(writes)
|
|
{
|
|
SERIALISE_ELEMENT(VkWriteDescriptorSet, w, *pDescriptorWrites);
|
|
writeDesc = w;
|
|
}
|
|
else
|
|
{
|
|
SERIALISE_ELEMENT(VkCopyDescriptorSet, c, *pDescriptorCopies);
|
|
copyDesc = c;
|
|
}
|
|
|
|
if(m_State < WRITING)
|
|
{
|
|
device = (VkDevice)GetResourceManager()->GetLiveResource(devId).handle;
|
|
|
|
if(writes)
|
|
m_Real.vkUpdateDescriptorSets(device, 1, &writeDesc, 0, NULL);
|
|
else
|
|
m_Real.vkUpdateDescriptorSets(device, 0, NULL, 1, ©Desc);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
VkResult WrappedVulkan::vkUpdateDescriptorSets(
|
|
VkDevice device,
|
|
uint32_t writeCount,
|
|
const VkWriteDescriptorSet* pDescriptorWrites,
|
|
uint32_t copyCount,
|
|
const VkCopyDescriptorSet* pDescriptorCopies)
|
|
{
|
|
VkResult ret = m_Real.vkUpdateDescriptorSets(device, writeCount, pDescriptorWrites, copyCount, pDescriptorCopies);
|
|
|
|
if(ret == VK_SUCCESS && m_State >= WRITING)
|
|
{
|
|
for(uint32_t i=0; i < writeCount; i++)
|
|
{
|
|
VkResourceRecord *record = GetResourceManager()->GetResourceRecord(MakeRes(pDescriptorWrites[i].destSet));
|
|
|
|
Chunk *chunk = NULL;
|
|
|
|
{
|
|
SCOPED_SERIALISE_CONTEXT(UPDATE_DESC_SET);
|
|
Serialise_vkUpdateDescriptorSets(device, 1, &pDescriptorWrites[i], 0, NULL);
|
|
|
|
chunk = scope.Get();
|
|
}
|
|
|
|
// VKTODOHIGH these shouldn't be accumulate-serialised, they should be
|
|
// tracked in memory by recording updates, and force-initial stated
|
|
|
|
record->AddChunk(chunk);
|
|
|
|
// VKTODOHIGH shouldn't add parents here, these should be more like SetMemoryRecord
|
|
// as it's transient/updated.
|
|
|
|
for(uint32_t d=0; d < pDescriptorWrites[i].count; d++)
|
|
{
|
|
if(pDescriptorWrites[i].pDescriptors[d].bufferView != VK_NULL_HANDLE)
|
|
record->AddParent(GetResourceManager()->GetResourceRecord(MakeRes(pDescriptorWrites[i].pDescriptors[d].bufferView)));
|
|
if(pDescriptorWrites[i].pDescriptors[d].sampler != VK_NULL_HANDLE)
|
|
record->AddParent(GetResourceManager()->GetResourceRecord(MakeRes(pDescriptorWrites[i].pDescriptors[d].sampler)));
|
|
if(pDescriptorWrites[i].pDescriptors[d].imageView != VK_NULL_HANDLE)
|
|
record->AddParent(GetResourceManager()->GetResourceRecord(MakeRes(pDescriptorWrites[i].pDescriptors[d].imageView)));
|
|
if(pDescriptorWrites[i].pDescriptors[d].attachmentView != VK_NULL_HANDLE)
|
|
record->AddParent(GetResourceManager()->GetResourceRecord(MakeRes(pDescriptorWrites[i].pDescriptors[d].attachmentView)));
|
|
}
|
|
}
|
|
|
|
for(uint32_t i=0; i < copyCount; i++)
|
|
{
|
|
VkResourceRecord *record = GetResourceManager()->GetResourceRecord(MakeRes(pDescriptorCopies[i].destSet));
|
|
|
|
Chunk *chunk = NULL;
|
|
|
|
{
|
|
SCOPED_SERIALISE_CONTEXT(UPDATE_DESC_SET);
|
|
Serialise_vkUpdateDescriptorSets(device, 0, NULL, 1, &pDescriptorCopies[i]);
|
|
|
|
chunk = scope.Get();
|
|
}
|
|
|
|
// VKTODOHIGH these shouldn't be accumulate-serialised, they should be
|
|
// tracked in memory by recording updates, and force-initial stated
|
|
|
|
record->AddChunk(chunk);
|
|
|
|
// VKTODOHIGH need to addparent the source descriptors (similar to above, not quite
|
|
// addparent actually)
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool WrappedVulkan::Serialise_vkBeginCommandBuffer(
|
|
VkCmdBuffer cmdBuffer,
|
|
const VkCmdBufferBeginInfo* pBeginInfo)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, cmdId, GetResourceManager()->GetID(MakeRes(cmdBuffer)));
|
|
|
|
ResourceId bakedCmdId;
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
VkResourceRecord *record = GetResourceManager()->GetResourceRecord(cmdId);
|
|
RDCASSERT(record->bakedCommands);
|
|
if(record->bakedCommands)
|
|
bakedCmdId = record->bakedCommands->GetResourceID();
|
|
}
|
|
|
|
SERIALISE_ELEMENT(VkCmdBufferBeginInfo, info, *pBeginInfo);
|
|
SERIALISE_ELEMENT(ResourceId, bakeId, bakedCmdId);
|
|
|
|
VkCmdBufferCreateInfo createInfo;
|
|
VkDevice device = VK_NULL_HANDLE;
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
device = m_CmdBufferInfo[cmdId].device;
|
|
createInfo = m_CmdBufferInfo[cmdId].createInfo;
|
|
}
|
|
|
|
SERIALISE_ELEMENT(ResourceId, devId, GetResourceManager()->GetID(MakeRes(device)));
|
|
m_pSerialiser->Serialise("createInfo", createInfo);
|
|
|
|
if(m_State == EXECUTING)
|
|
{
|
|
// VKTODOHIGH check if we want to partial-replay this cmd buffer
|
|
}
|
|
else if(m_State == READING)
|
|
{
|
|
// remove one-time submit flag as we will want to submit many
|
|
info.flags &= ~VK_CMD_BUFFER_OPTIMIZE_ONE_TIME_SUBMIT_BIT;
|
|
|
|
VkCmdBuffer cmd = VK_NULL_HANDLE;
|
|
|
|
if(!GetResourceManager()->HasLiveResource(bakeId))
|
|
{
|
|
VkResult ret = m_Real.vkCreateCommandBuffer((VkDevice)GetResourceManager()->GetLiveResource(devId).handle, &createInfo, &cmd);
|
|
|
|
if(ret != VK_SUCCESS)
|
|
{
|
|
RDCERR("Failed on resource serialise-creation, VkResult: 0x%08x", ret);
|
|
}
|
|
else
|
|
{
|
|
ResourceId live = GetResourceManager()->RegisterResource(MakeRes(cmd));
|
|
GetResourceManager()->AddLiveResource(bakeId, MakeRes(cmd));
|
|
}
|
|
|
|
// whenever a vkCmd command-building chunk asks for the command buffer, it
|
|
// will get our baked version.
|
|
GetResourceManager()->ReplaceResource(cmdId, bakeId);
|
|
}
|
|
else
|
|
{
|
|
cmd = (VkCmdBuffer)GetResourceManager()->GetLiveResource(bakeId).handle;
|
|
}
|
|
|
|
{
|
|
ResourceId liveBaked = GetResourceManager()->GetLiveID(bakeId);
|
|
m_CmdBufferInfo[liveBaked].device = VK_NULL_HANDLE;
|
|
}
|
|
|
|
m_Real.vkBeginCommandBuffer(cmd, &info);
|
|
|
|
m_LastCmdBufferID = bakeId;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
VkResult WrappedVulkan::vkBeginCommandBuffer(
|
|
VkCmdBuffer cmdBuffer,
|
|
const VkCmdBufferBeginInfo* pBeginInfo)
|
|
{
|
|
VkResourceRecord *record = GetResourceManager()->GetResourceRecord(MakeRes(cmdBuffer));
|
|
RDCASSERT(record);
|
|
|
|
if(record)
|
|
{
|
|
if(record->bakedCommands)
|
|
record->bakedCommands->Delete(GetResourceManager());
|
|
|
|
ResourceId bakedId = ResourceIDGen::GetNewUniqueID();
|
|
|
|
// VKTODOLOW: shouldn't depend on 'id' being a uint64_t member
|
|
VkResource res(eResCmdBufferBake, bakedId.id);
|
|
|
|
record->bakedCommands = GetResourceManager()->AddResourceRecord(res, bakedId);
|
|
|
|
{
|
|
SCOPED_SERIALISE_CONTEXT(BEGIN_CMD_BUFFER);
|
|
Serialise_vkBeginCommandBuffer(cmdBuffer, pBeginInfo);
|
|
|
|
record->AddChunk(scope.Get());
|
|
}
|
|
}
|
|
|
|
return m_Real.vkBeginCommandBuffer(cmdBuffer, pBeginInfo);
|
|
}
|
|
|
|
bool WrappedVulkan::Serialise_vkEndCommandBuffer(VkCmdBuffer cmdBuffer)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, cmdId, GetResourceManager()->GetID(MakeRes(cmdBuffer)));
|
|
|
|
ResourceId bakedCmdId;
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
VkResourceRecord *record = GetResourceManager()->GetResourceRecord(cmdId);
|
|
RDCASSERT(record->bakedCommands);
|
|
if(record->bakedCommands)
|
|
bakedCmdId = record->bakedCommands->GetResourceID();
|
|
}
|
|
|
|
SERIALISE_ELEMENT(ResourceId, bakeId, bakedCmdId);
|
|
|
|
if(m_State == EXECUTING)
|
|
{
|
|
// VKTODOHIGH check if we want to partial-replay this cmd buffer
|
|
}
|
|
else if(m_State == READING)
|
|
{
|
|
VkCmdBuffer cmd = (VkCmdBuffer)GetResourceManager()->GetLiveResource(bakeId).handle;
|
|
|
|
GetResourceManager()->RemoveReplacement(cmdId);
|
|
|
|
m_Real.vkEndCommandBuffer(cmd);
|
|
|
|
if(!m_CurEvents.empty())
|
|
{
|
|
FetchDrawcall draw;
|
|
draw.name = "API Calls";
|
|
draw.flags |= eDraw_SetMarker;
|
|
|
|
AddDrawcall(draw, true);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
VkResult WrappedVulkan::vkEndCommandBuffer(VkCmdBuffer cmdBuffer)
|
|
{
|
|
VkResourceRecord *record = GetResourceManager()->GetResourceRecord(MakeRes(cmdBuffer));
|
|
RDCASSERT(record);
|
|
|
|
if(record)
|
|
{
|
|
RDCASSERT(record->bakedCommands);
|
|
|
|
{
|
|
SCOPED_SERIALISE_CONTEXT(END_CMD_BUFFER);
|
|
Serialise_vkEndCommandBuffer(cmdBuffer);
|
|
|
|
record->AddChunk(scope.Get());
|
|
}
|
|
|
|
record->Bake();
|
|
}
|
|
|
|
return m_Real.vkEndCommandBuffer(cmdBuffer);
|
|
}
|
|
|
|
bool WrappedVulkan::Serialise_vkResetCommandBuffer(VkCmdBuffer cmdBuffer, VkCmdBufferResetFlags flags)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, cmdId, GetResourceManager()->GetID(MakeRes(cmdBuffer)));
|
|
SERIALISE_ELEMENT(VkCmdBufferResetFlags, fl, flags);
|
|
|
|
ResourceId bakedCmdId;
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
VkResourceRecord *record = GetResourceManager()->GetResourceRecord(cmdId);
|
|
RDCASSERT(record->bakedCommands);
|
|
if(record->bakedCommands)
|
|
bakedCmdId = record->bakedCommands->GetResourceID();
|
|
}
|
|
|
|
SERIALISE_ELEMENT(ResourceId, bakeId, bakedCmdId);
|
|
|
|
VkCmdBufferCreateInfo info;
|
|
VkDevice device = VK_NULL_HANDLE;
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
device = m_CmdBufferInfo[cmdId].device;
|
|
info = m_CmdBufferInfo[cmdId].createInfo;
|
|
}
|
|
|
|
SERIALISE_ELEMENT(ResourceId, devId, GetResourceManager()->GetID(MakeRes(device)));
|
|
m_pSerialiser->Serialise("createInfo", info);
|
|
|
|
if(m_State == EXECUTING)
|
|
{
|
|
// VKTODOHIGH check if we want to partial-replay this cmd buffer
|
|
}
|
|
else if(m_State == READING)
|
|
{
|
|
VkCmdBuffer cmd = VK_NULL_HANDLE;
|
|
|
|
if(!GetResourceManager()->HasLiveResource(bakeId))
|
|
{
|
|
VkResult ret = m_Real.vkCreateCommandBuffer((VkDevice)GetResourceManager()->GetLiveResource(devId).handle, &info, &cmd);
|
|
|
|
if(ret != VK_SUCCESS)
|
|
{
|
|
RDCERR("Failed on resource serialise-creation, VkResult: 0x%08x", ret);
|
|
}
|
|
else
|
|
{
|
|
ResourceId live = GetResourceManager()->RegisterResource(MakeRes(cmd));
|
|
GetResourceManager()->AddLiveResource(bakeId, MakeRes(cmd));
|
|
}
|
|
|
|
// whenever a vkCmd command-building chunk asks for the command buffer, it
|
|
// will get our baked version.
|
|
GetResourceManager()->ReplaceResource(cmdId, bakeId);
|
|
}
|
|
else
|
|
{
|
|
cmd = (VkCmdBuffer)GetResourceManager()->GetLiveResource(bakeId).handle;
|
|
}
|
|
|
|
{
|
|
ResourceId liveBaked = GetResourceManager()->GetLiveID(bakeId);
|
|
m_CmdBufferInfo[liveBaked].device = VK_NULL_HANDLE;
|
|
}
|
|
|
|
m_Real.vkResetCommandBuffer(cmd, fl);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
VkResult WrappedVulkan::vkResetCommandBuffer(
|
|
VkCmdBuffer cmdBuffer,
|
|
VkCmdBufferResetFlags flags)
|
|
{
|
|
VkResourceRecord *record = GetResourceManager()->GetResourceRecord(MakeRes(cmdBuffer));
|
|
RDCASSERT(record);
|
|
|
|
if(record)
|
|
{
|
|
if(record->bakedCommands)
|
|
record->bakedCommands->Delete(GetResourceManager());
|
|
|
|
ResourceId bakedId = ResourceIDGen::GetNewUniqueID();
|
|
|
|
// VKTODOLOW: shouldn't depend on 'id' being a uint64_t member
|
|
VkResource res(eResCmdBufferBake, bakedId.id);
|
|
|
|
record->bakedCommands = GetResourceManager()->AddResourceRecord(res, bakedId);
|
|
|
|
{
|
|
SCOPED_SERIALISE_CONTEXT(RESET_CMD_BUFFER);
|
|
Serialise_vkResetCommandBuffer(cmdBuffer, flags);
|
|
|
|
record->AddChunk(scope.Get());
|
|
}
|
|
}
|
|
|
|
return m_Real.vkResetCommandBuffer(cmdBuffer, flags);
|
|
}
|
|
|
|
// Command buffer building functions
|
|
|
|
bool WrappedVulkan::Serialise_vkCmdBeginRenderPass(
|
|
VkCmdBuffer cmdBuffer,
|
|
const VkRenderPassBeginInfo* pRenderPassBegin,
|
|
VkRenderPassContents contents)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, cmdid, GetResourceManager()->GetID(MakeRes(cmdBuffer)));
|
|
SERIALISE_ELEMENT(VkRenderPassBeginInfo, beginInfo, *pRenderPassBegin);
|
|
SERIALISE_ELEMENT(VkRenderPassContents, cont, contents);
|
|
|
|
if(m_State == EXECUTING)
|
|
{
|
|
// VKTODOHIGH check if we want to partial-replay this cmd buffer
|
|
}
|
|
else if(m_State == READING)
|
|
{
|
|
cmdBuffer = (VkCmdBuffer)GetResourceManager()->GetLiveResource(cmdid).handle;
|
|
|
|
m_Real.vkCmdBeginRenderPass(cmdBuffer, &beginInfo, cont);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void WrappedVulkan::vkCmdBeginRenderPass(
|
|
VkCmdBuffer cmdBuffer,
|
|
const VkRenderPassBeginInfo* pRenderPassBegin,
|
|
VkRenderPassContents contents)
|
|
{
|
|
m_Real.vkCmdBeginRenderPass(cmdBuffer, pRenderPassBegin, contents);
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
VkResourceRecord *record = GetResourceManager()->GetResourceRecord(MakeRes(cmdBuffer));
|
|
|
|
SCOPED_SERIALISE_CONTEXT(BEGIN_RENDERPASS);
|
|
Serialise_vkCmdBeginRenderPass(cmdBuffer, pRenderPassBegin, contents);
|
|
|
|
record->AddChunk(scope.Get());
|
|
record->MarkResourceFrameReferenced(GetResourceManager()->GetID(MakeRes(pRenderPassBegin->renderPass)), eFrameRef_Read);
|
|
// VKTODOMED should mark framebuffer read and attachments write
|
|
record->MarkResourceFrameReferenced(GetResourceManager()->GetID(MakeRes(pRenderPassBegin->framebuffer)), eFrameRef_Write);
|
|
}
|
|
}
|
|
|
|
bool WrappedVulkan::Serialise_vkCmdEndRenderPass(
|
|
VkCmdBuffer cmdBuffer)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, cmdid, GetResourceManager()->GetID(MakeRes(cmdBuffer)));
|
|
|
|
if(m_State == EXECUTING)
|
|
{
|
|
// VKTODOHIGH check if we want to partial-replay this cmd buffer
|
|
}
|
|
else if(m_State == READING)
|
|
{
|
|
cmdBuffer = (VkCmdBuffer)GetResourceManager()->GetLiveResource(cmdid).handle;
|
|
|
|
m_Real.vkCmdEndRenderPass(cmdBuffer);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void WrappedVulkan::vkCmdEndRenderPass(
|
|
VkCmdBuffer cmdBuffer)
|
|
{
|
|
m_Real.vkCmdEndRenderPass(cmdBuffer);
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
VkResourceRecord *record = GetResourceManager()->GetResourceRecord(MakeRes(cmdBuffer));
|
|
|
|
SCOPED_SERIALISE_CONTEXT(END_RENDERPASS);
|
|
Serialise_vkCmdEndRenderPass(cmdBuffer);
|
|
|
|
record->AddChunk(scope.Get());
|
|
}
|
|
}
|
|
|
|
bool WrappedVulkan::Serialise_vkCmdBindPipeline(
|
|
VkCmdBuffer cmdBuffer,
|
|
VkPipelineBindPoint pipelineBindPoint,
|
|
VkPipeline pipeline)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, cmdid, GetResourceManager()->GetID(MakeRes(cmdBuffer)));
|
|
SERIALISE_ELEMENT(VkPipelineBindPoint, bind, pipelineBindPoint);
|
|
SERIALISE_ELEMENT(ResourceId, pipeid, GetResourceManager()->GetID(MakeRes(pipeline)));
|
|
|
|
if(m_State == EXECUTING)
|
|
{
|
|
// VKTODOHIGH check if we want to partial-replay this cmd buffer
|
|
}
|
|
else if(m_State == READING)
|
|
{
|
|
cmdBuffer = (VkCmdBuffer)GetResourceManager()->GetLiveResource(cmdid).handle;
|
|
pipeline = (VkPipeline)GetResourceManager()->GetLiveResource(pipeid).handle;
|
|
|
|
m_Real.vkCmdBindPipeline(cmdBuffer, bind, pipeline);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void WrappedVulkan::vkCmdBindPipeline(
|
|
VkCmdBuffer cmdBuffer,
|
|
VkPipelineBindPoint pipelineBindPoint,
|
|
VkPipeline pipeline)
|
|
{
|
|
m_Real.vkCmdBindPipeline(cmdBuffer, pipelineBindPoint, pipeline);
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
VkResourceRecord *record = GetResourceManager()->GetResourceRecord(MakeRes(cmdBuffer));
|
|
|
|
SCOPED_SERIALISE_CONTEXT(BIND_PIPELINE);
|
|
Serialise_vkCmdBindPipeline(cmdBuffer, pipelineBindPoint, pipeline);
|
|
|
|
record->AddChunk(scope.Get());
|
|
record->MarkResourceFrameReferenced(GetResourceManager()->GetID(MakeRes(pipeline)), eFrameRef_Read);
|
|
}
|
|
}
|
|
|
|
bool WrappedVulkan::Serialise_vkCmdBindDescriptorSets(
|
|
VkCmdBuffer cmdBuffer,
|
|
VkPipelineBindPoint pipelineBindPoint,
|
|
VkPipelineLayout layout,
|
|
uint32_t firstSet,
|
|
uint32_t setCount,
|
|
const VkDescriptorSet* pDescriptorSets,
|
|
uint32_t dynamicOffsetCount,
|
|
const uint32_t* pDynamicOffsets)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, cmdid, GetResourceManager()->GetID(MakeRes(cmdBuffer)));
|
|
SERIALISE_ELEMENT(ResourceId, layoutid, GetResourceManager()->GetID(MakeRes(layout)));
|
|
SERIALISE_ELEMENT(VkPipelineBindPoint, bind, pipelineBindPoint);
|
|
SERIALISE_ELEMENT(uint32_t, first, firstSet);
|
|
|
|
SERIALISE_ELEMENT(uint32_t, numSets, setCount);
|
|
|
|
ResourceId *descriptorIDs = new ResourceId[numSets];
|
|
|
|
VkDescriptorSet *sets = (VkDescriptorSet *)pDescriptorSets;
|
|
if(m_State < WRITING)
|
|
sets = new VkDescriptorSet[numSets];
|
|
|
|
for(uint32_t i=0; i < numSets; i++)
|
|
{
|
|
if(m_State >= WRITING) descriptorIDs[i] = GetResourceManager()->GetID(MakeRes(sets[i]));
|
|
m_pSerialiser->Serialise("DescriptorSet", descriptorIDs[i]);
|
|
if(m_State < WRITING) sets[i] = (VkDescriptorSet)GetResourceManager()->GetLiveResource(descriptorIDs[i]).handle;
|
|
}
|
|
|
|
SERIALISE_ELEMENT(uint32_t, offsCount, dynamicOffsetCount);
|
|
SERIALISE_ELEMENT_ARR_OPT(uint32_t, offs, pDynamicOffsets, offsCount, offsCount > 0);
|
|
|
|
if(m_State == EXECUTING)
|
|
{
|
|
// VKTODOHIGH check if we want to partial-replay this cmd buffer
|
|
}
|
|
else if(m_State == READING)
|
|
{
|
|
cmdBuffer = (VkCmdBuffer)GetResourceManager()->GetLiveResource(cmdid).handle;
|
|
layout = (VkPipelineLayout)GetResourceManager()->GetLiveResource(layoutid).handle;
|
|
|
|
m_Real.vkCmdBindDescriptorSets(cmdBuffer, bind, layout, first, numSets, sets, offsCount, offs);
|
|
|
|
SAFE_DELETE_ARRAY(sets);
|
|
}
|
|
|
|
SAFE_DELETE_ARRAY(descriptorIDs);
|
|
SAFE_DELETE_ARRAY(offs);
|
|
|
|
return true;
|
|
}
|
|
|
|
void WrappedVulkan::vkCmdBindDescriptorSets(
|
|
VkCmdBuffer cmdBuffer,
|
|
VkPipelineBindPoint pipelineBindPoint,
|
|
VkPipelineLayout layout,
|
|
uint32_t firstSet,
|
|
uint32_t setCount,
|
|
const VkDescriptorSet* pDescriptorSets,
|
|
uint32_t dynamicOffsetCount,
|
|
const uint32_t* pDynamicOffsets)
|
|
{
|
|
m_Real.vkCmdBindDescriptorSets(cmdBuffer, pipelineBindPoint, layout, firstSet, setCount, pDescriptorSets, dynamicOffsetCount, pDynamicOffsets);
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
VkResourceRecord *record = GetResourceManager()->GetResourceRecord(MakeRes(cmdBuffer));
|
|
|
|
SCOPED_SERIALISE_CONTEXT(BIND_DESCRIPTOR_SET);
|
|
Serialise_vkCmdBindDescriptorSets(cmdBuffer, pipelineBindPoint, layout, firstSet, setCount, pDescriptorSets, dynamicOffsetCount, pDynamicOffsets);
|
|
|
|
record->AddChunk(scope.Get());
|
|
record->MarkResourceFrameReferenced(GetResourceManager()->GetID(MakeRes(layout)), eFrameRef_Read);
|
|
for(uint32_t i=0; i < setCount; i++)
|
|
record->MarkResourceFrameReferenced(GetResourceManager()->GetID(MakeRes(pDescriptorSets[i])), eFrameRef_Read);
|
|
}
|
|
}
|
|
|
|
bool WrappedVulkan::Serialise_vkCmdBindDynamicViewportState(
|
|
VkCmdBuffer cmdBuffer,
|
|
VkDynamicViewportState dynamicViewportState)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, cmdid, GetResourceManager()->GetID(MakeRes(cmdBuffer)));
|
|
SERIALISE_ELEMENT(ResourceId, stateid, GetResourceManager()->GetID(MakeRes(dynamicViewportState)));
|
|
|
|
if(m_State == EXECUTING)
|
|
{
|
|
// VKTODOHIGH check if we want to partial-replay this cmd buffer
|
|
}
|
|
else if(m_State == READING)
|
|
{
|
|
cmdBuffer = (VkCmdBuffer)GetResourceManager()->GetLiveResource(cmdid).handle;
|
|
dynamicViewportState = (VkDynamicViewportState)GetResourceManager()->GetLiveResource(stateid).handle;
|
|
|
|
m_Real.vkCmdBindDynamicViewportState(cmdBuffer, dynamicViewportState);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void WrappedVulkan::vkCmdBindDynamicViewportState(
|
|
VkCmdBuffer cmdBuffer,
|
|
VkDynamicViewportState dynamicViewportState)
|
|
{
|
|
m_Real.vkCmdBindDynamicViewportState(cmdBuffer, dynamicViewportState);
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
VkResourceRecord *record = GetResourceManager()->GetResourceRecord(MakeRes(cmdBuffer));
|
|
|
|
SCOPED_SERIALISE_CONTEXT(BIND_VP_STATE);
|
|
Serialise_vkCmdBindDynamicViewportState(cmdBuffer, dynamicViewportState);
|
|
|
|
record->AddChunk(scope.Get());
|
|
record->MarkResourceFrameReferenced(GetResourceManager()->GetID(MakeRes(dynamicViewportState)), eFrameRef_Read);
|
|
}
|
|
}
|
|
|
|
bool WrappedVulkan::Serialise_vkCmdBindDynamicRasterState(
|
|
VkCmdBuffer cmdBuffer,
|
|
VkDynamicRasterState dynamicRasterState)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, cmdid, GetResourceManager()->GetID(MakeRes(cmdBuffer)));
|
|
SERIALISE_ELEMENT(ResourceId, stateid, GetResourceManager()->GetID(MakeRes(dynamicRasterState)));
|
|
|
|
if(m_State == EXECUTING)
|
|
{
|
|
// VKTODOHIGH check if we want to partial-replay this cmd buffer
|
|
}
|
|
else if(m_State == READING)
|
|
{
|
|
cmdBuffer = (VkCmdBuffer)GetResourceManager()->GetLiveResource(cmdid).handle;
|
|
dynamicRasterState = (VkDynamicRasterState)GetResourceManager()->GetLiveResource(stateid).handle;
|
|
|
|
m_Real.vkCmdBindDynamicRasterState(cmdBuffer, dynamicRasterState);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void WrappedVulkan::vkCmdBindDynamicRasterState(
|
|
VkCmdBuffer cmdBuffer,
|
|
VkDynamicRasterState dynamicRasterState)
|
|
{
|
|
m_Real.vkCmdBindDynamicRasterState(cmdBuffer, dynamicRasterState);
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
VkResourceRecord *record = GetResourceManager()->GetResourceRecord(MakeRes(cmdBuffer));
|
|
|
|
SCOPED_SERIALISE_CONTEXT(BIND_RS_STATE);
|
|
Serialise_vkCmdBindDynamicRasterState(cmdBuffer, dynamicRasterState);
|
|
|
|
record->AddChunk(scope.Get());
|
|
record->MarkResourceFrameReferenced(GetResourceManager()->GetID(MakeRes(dynamicRasterState)), eFrameRef_Read);
|
|
}
|
|
}
|
|
|
|
bool WrappedVulkan::Serialise_vkCmdBindDynamicColorBlendState(
|
|
VkCmdBuffer cmdBuffer,
|
|
VkDynamicColorBlendState dynamicColorBlendState)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, cmdid, GetResourceManager()->GetID(MakeRes(cmdBuffer)));
|
|
SERIALISE_ELEMENT(ResourceId, stateid, GetResourceManager()->GetID(MakeRes(dynamicColorBlendState)));
|
|
|
|
if(m_State == EXECUTING)
|
|
{
|
|
// VKTODOHIGH check if we want to partial-replay this cmd buffer
|
|
}
|
|
else if(m_State == READING)
|
|
{
|
|
cmdBuffer = (VkCmdBuffer)GetResourceManager()->GetLiveResource(cmdid).handle;
|
|
dynamicColorBlendState = (VkDynamicColorBlendState)GetResourceManager()->GetLiveResource(stateid).handle;
|
|
|
|
m_Real.vkCmdBindDynamicColorBlendState(cmdBuffer, dynamicColorBlendState);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void WrappedVulkan::vkCmdBindDynamicColorBlendState(
|
|
VkCmdBuffer cmdBuffer,
|
|
VkDynamicColorBlendState dynamicColorBlendState)
|
|
{
|
|
m_Real.vkCmdBindDynamicColorBlendState(cmdBuffer, dynamicColorBlendState);
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
VkResourceRecord *record = GetResourceManager()->GetResourceRecord(MakeRes(cmdBuffer));
|
|
|
|
SCOPED_SERIALISE_CONTEXT(BIND_CB_STATE);
|
|
Serialise_vkCmdBindDynamicColorBlendState(cmdBuffer, dynamicColorBlendState);
|
|
|
|
record->AddChunk(scope.Get());
|
|
record->MarkResourceFrameReferenced(GetResourceManager()->GetID(MakeRes(dynamicColorBlendState)), eFrameRef_Read);
|
|
}
|
|
}
|
|
|
|
bool WrappedVulkan::Serialise_vkCmdBindDynamicDepthStencilState(
|
|
VkCmdBuffer cmdBuffer,
|
|
VkDynamicDepthStencilState dynamicDepthStencilState)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, cmdid, GetResourceManager()->GetID(MakeRes(cmdBuffer)));
|
|
SERIALISE_ELEMENT(ResourceId, stateid, GetResourceManager()->GetID(MakeRes(dynamicDepthStencilState)));
|
|
|
|
if(m_State == EXECUTING)
|
|
{
|
|
// VKTODOHIGH check if we want to partial-replay this cmd buffer
|
|
}
|
|
else if(m_State == READING)
|
|
{
|
|
cmdBuffer = (VkCmdBuffer)GetResourceManager()->GetLiveResource(cmdid).handle;
|
|
dynamicDepthStencilState = (VkDynamicDepthStencilState)GetResourceManager()->GetLiveResource(stateid).handle;
|
|
|
|
m_Real.vkCmdBindDynamicDepthStencilState(cmdBuffer, dynamicDepthStencilState);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void WrappedVulkan::vkCmdBindDynamicDepthStencilState(
|
|
VkCmdBuffer cmdBuffer,
|
|
VkDynamicDepthStencilState dynamicDepthStencilState)
|
|
{
|
|
m_Real.vkCmdBindDynamicDepthStencilState(cmdBuffer, dynamicDepthStencilState);
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
VkResourceRecord *record = GetResourceManager()->GetResourceRecord(MakeRes(cmdBuffer));
|
|
|
|
SCOPED_SERIALISE_CONTEXT(BIND_DS_STATE);
|
|
Serialise_vkCmdBindDynamicDepthStencilState(cmdBuffer, dynamicDepthStencilState);
|
|
|
|
record->AddChunk(scope.Get());
|
|
record->MarkResourceFrameReferenced(GetResourceManager()->GetID(MakeRes(dynamicDepthStencilState)), eFrameRef_Read);
|
|
}
|
|
}
|
|
|
|
bool WrappedVulkan::Serialise_vkCmdBindVertexBuffers(
|
|
VkCmdBuffer cmdBuffer,
|
|
uint32_t startBinding,
|
|
uint32_t bindingCount,
|
|
const VkBuffer* pBuffers,
|
|
const VkDeviceSize* pOffsets)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, cmdid, GetResourceManager()->GetID(MakeRes(cmdBuffer)));
|
|
SERIALISE_ELEMENT(uint32_t, start, startBinding);
|
|
SERIALISE_ELEMENT(uint32_t, count, bindingCount);
|
|
|
|
vector<VkBuffer> bufs;
|
|
vector<VkDeviceSize> offs;
|
|
|
|
for(uint32_t i=0; i < count; i++)
|
|
{
|
|
ResourceId id;
|
|
VkDeviceSize o;
|
|
if(m_State >= WRITING)
|
|
{
|
|
id = GetResourceManager()->GetID(MakeRes(pBuffers[i]));
|
|
o = pOffsets[i];
|
|
}
|
|
|
|
m_pSerialiser->Serialise("pBuffers[]", id);
|
|
m_pSerialiser->Serialise("pOffsets[]", o);
|
|
|
|
if(m_State < WRITING)
|
|
{
|
|
bufs.push_back((VkBuffer)GetResourceManager()->GetLiveResource(id).handle);
|
|
offs.push_back(o);
|
|
}
|
|
}
|
|
|
|
if(m_State == EXECUTING)
|
|
{
|
|
// VKTODOHIGH check if we want to partial-replay this cmd buffer
|
|
}
|
|
else if(m_State == READING)
|
|
{
|
|
cmdBuffer = (VkCmdBuffer)GetResourceManager()->GetLiveResource(cmdid).handle;
|
|
|
|
m_Real.vkCmdBindVertexBuffers(cmdBuffer, start, count, &bufs[0], &offs[0]);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void WrappedVulkan::vkCmdBindVertexBuffers(
|
|
VkCmdBuffer cmdBuffer,
|
|
uint32_t startBinding,
|
|
uint32_t bindingCount,
|
|
const VkBuffer* pBuffers,
|
|
const VkDeviceSize* pOffsets)
|
|
{
|
|
m_Real.vkCmdBindVertexBuffers(cmdBuffer, startBinding, bindingCount, pBuffers, pOffsets);
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
VkResourceRecord *record = GetResourceManager()->GetResourceRecord(MakeRes(cmdBuffer));
|
|
|
|
SCOPED_SERIALISE_CONTEXT(BIND_VERTEX_BUFFERS);
|
|
Serialise_vkCmdBindVertexBuffers(cmdBuffer, startBinding, bindingCount, pBuffers, pOffsets);
|
|
|
|
record->AddChunk(scope.Get());
|
|
for(uint32_t i=0; i < bindingCount; i++)
|
|
record->MarkResourceFrameReferenced(GetResourceManager()->GetID(MakeRes(pBuffers[i])), eFrameRef_Read);
|
|
}
|
|
}
|
|
|
|
|
|
bool WrappedVulkan::Serialise_vkCmdBindIndexBuffer(
|
|
VkCmdBuffer cmdBuffer,
|
|
VkBuffer buffer,
|
|
VkDeviceSize offset,
|
|
VkIndexType indexType)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, cmdid, GetResourceManager()->GetID(MakeRes(cmdBuffer)));
|
|
SERIALISE_ELEMENT(ResourceId, bufid, GetResourceManager()->GetID(MakeRes(buffer)));
|
|
SERIALISE_ELEMENT(uint64_t, offs, offset);
|
|
SERIALISE_ELEMENT(VkIndexType, idxType, indexType);
|
|
|
|
if(m_State == EXECUTING)
|
|
{
|
|
// VKTODOHIGH check if we want to partial-replay this cmd buffer
|
|
}
|
|
else if(m_State == READING)
|
|
{
|
|
cmdBuffer = (VkCmdBuffer)GetResourceManager()->GetLiveResource(cmdid).handle;
|
|
buffer = (VkBuffer)GetResourceManager()->GetLiveResource(bufid).handle;
|
|
|
|
m_Real.vkCmdBindIndexBuffer(cmdBuffer, buffer, offs, idxType);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void WrappedVulkan::vkCmdBindIndexBuffer(
|
|
VkCmdBuffer cmdBuffer,
|
|
VkBuffer buffer,
|
|
VkDeviceSize offset,
|
|
VkIndexType indexType)
|
|
{
|
|
m_Real.vkCmdBindIndexBuffer(cmdBuffer, buffer, offset, indexType);
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
VkResourceRecord *record = GetResourceManager()->GetResourceRecord(MakeRes(cmdBuffer));
|
|
|
|
SCOPED_SERIALISE_CONTEXT(BIND_INDEX_BUFFER);
|
|
Serialise_vkCmdBindIndexBuffer(cmdBuffer, buffer, offset, indexType);
|
|
|
|
record->AddChunk(scope.Get());
|
|
record->MarkResourceFrameReferenced(GetResourceManager()->GetID(MakeRes(buffer)), eFrameRef_Read);
|
|
}
|
|
}
|
|
|
|
bool WrappedVulkan::Serialise_vkCmdDraw(
|
|
VkCmdBuffer cmdBuffer,
|
|
uint32_t firstVertex,
|
|
uint32_t vertexCount,
|
|
uint32_t firstInstance,
|
|
uint32_t instanceCount)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, cmdid, GetResourceManager()->GetID(MakeRes(cmdBuffer)));
|
|
SERIALISE_ELEMENT(uint32_t, firstVtx, firstVertex);
|
|
SERIALISE_ELEMENT(uint32_t, vtxCount, vertexCount);
|
|
SERIALISE_ELEMENT(uint32_t, firstInst, firstInstance);
|
|
SERIALISE_ELEMENT(uint32_t, instCount, instanceCount);
|
|
|
|
if(m_State == EXECUTING)
|
|
{
|
|
// VKTODOHIGH check if we want to partial-replay this cmd buffer
|
|
}
|
|
else if(m_State == READING)
|
|
{
|
|
VkCmdBuffer buf = (VkCmdBuffer)GetResourceManager()->GetLiveResource(cmdid).handle;
|
|
|
|
m_Real.vkCmdDraw(buf, firstVtx, vtxCount, firstInst, instCount);
|
|
|
|
const string desc = m_pSerialiser->GetDebugStr();
|
|
|
|
{
|
|
AddEvent(DRAW, desc);
|
|
string name = "vkCmdDraw(" +
|
|
ToStr::Get(vtxCount) + "," +
|
|
ToStr::Get(instCount) + ")";
|
|
|
|
FetchDrawcall draw;
|
|
draw.name = name;
|
|
draw.numIndices = vtxCount;
|
|
draw.numInstances = instCount;
|
|
draw.indexOffset = 0;
|
|
draw.vertexOffset = firstVtx;
|
|
draw.instanceOffset = firstInst;
|
|
|
|
draw.flags |= eDraw_Drawcall;
|
|
|
|
AddDrawcall(draw, true);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void WrappedVulkan::vkCmdDraw(
|
|
VkCmdBuffer cmdBuffer,
|
|
uint32_t firstVertex,
|
|
uint32_t vertexCount,
|
|
uint32_t firstInstance,
|
|
uint32_t instanceCount)
|
|
{
|
|
m_Real.vkCmdDraw(cmdBuffer, firstVertex, vertexCount, firstInstance, instanceCount);
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
VkResourceRecord *record = GetResourceManager()->GetResourceRecord(MakeRes(cmdBuffer));
|
|
|
|
SCOPED_SERIALISE_CONTEXT(DRAW);
|
|
Serialise_vkCmdDraw(cmdBuffer, firstVertex, vertexCount, firstInstance, instanceCount);
|
|
|
|
record->AddChunk(scope.Get());
|
|
}
|
|
}
|
|
|
|
bool WrappedVulkan::Serialise_vkCmdBlitImage(
|
|
VkCmdBuffer cmdBuffer,
|
|
VkImage srcImage,
|
|
VkImageLayout srcImageLayout,
|
|
VkImage destImage,
|
|
VkImageLayout destImageLayout,
|
|
uint32_t regionCount,
|
|
const VkImageBlit* pRegions,
|
|
VkTexFilter filter)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, cmdid, GetResourceManager()->GetID(MakeRes(cmdBuffer)));
|
|
SERIALISE_ELEMENT(ResourceId, srcid, GetResourceManager()->GetID(MakeRes(srcImage)));
|
|
SERIALISE_ELEMENT(VkImageLayout, srclayout, srcImageLayout);
|
|
SERIALISE_ELEMENT(ResourceId, dstid, GetResourceManager()->GetID(MakeRes(destImage)));
|
|
SERIALISE_ELEMENT(VkImageLayout, dstlayout, destImageLayout);
|
|
|
|
SERIALISE_ELEMENT(VkTexFilter, f, filter);
|
|
|
|
SERIALISE_ELEMENT(uint32_t, count, regionCount);
|
|
SERIALISE_ELEMENT_ARR(VkImageBlit, regions, pRegions, count);
|
|
|
|
if(m_State == EXECUTING)
|
|
{
|
|
// VKTODOHIGH check if we want to partial-replay this cmd buffer
|
|
}
|
|
else if(m_State == READING)
|
|
{
|
|
cmdBuffer = (VkCmdBuffer)GetResourceManager()->GetLiveResource(cmdid).handle;
|
|
srcImage = (VkImage)GetResourceManager()->GetLiveResource(srcid).handle;
|
|
destImage = (VkImage)GetResourceManager()->GetLiveResource(dstid).handle;
|
|
|
|
m_Real.vkCmdBlitImage(cmdBuffer, srcImage, srclayout, destImage, dstlayout, count, regions, f);
|
|
}
|
|
|
|
SAFE_DELETE_ARRAY(regions);
|
|
|
|
return true;
|
|
}
|
|
|
|
void WrappedVulkan::vkCmdBlitImage(
|
|
VkCmdBuffer cmdBuffer,
|
|
VkImage srcImage,
|
|
VkImageLayout srcImageLayout,
|
|
VkImage destImage,
|
|
VkImageLayout destImageLayout,
|
|
uint32_t regionCount,
|
|
const VkImageBlit* pRegions,
|
|
VkTexFilter filter)
|
|
{
|
|
m_Real.vkCmdBlitImage(cmdBuffer, srcImage, srcImageLayout, destImage, destImageLayout, regionCount, pRegions, filter);
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
VkResourceRecord *record = GetResourceManager()->GetResourceRecord(MakeRes(cmdBuffer));
|
|
|
|
SCOPED_SERIALISE_CONTEXT(BLIT_IMG);
|
|
Serialise_vkCmdBlitImage(cmdBuffer, srcImage, srcImageLayout, destImage, destImageLayout, regionCount, pRegions, filter);
|
|
|
|
record->AddChunk(scope.Get());
|
|
|
|
record->dirtied.insert(GetResourceManager()->GetID(MakeRes(destImage)));
|
|
record->MarkResourceFrameReferenced(GetResourceManager()->GetID(MakeRes(srcImage)), eFrameRef_Read);
|
|
record->MarkResourceFrameReferenced(GetResourceManager()->GetID(MakeRes(destImage)), eFrameRef_Write);
|
|
}
|
|
}
|
|
|
|
bool WrappedVulkan::Serialise_vkCmdCopyImage(
|
|
VkCmdBuffer cmdBuffer,
|
|
VkImage srcImage,
|
|
VkImageLayout srcImageLayout,
|
|
VkImage destImage,
|
|
VkImageLayout destImageLayout,
|
|
uint32_t regionCount,
|
|
const VkImageCopy* pRegions)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, cmdid, GetResourceManager()->GetID(MakeRes(cmdBuffer)));
|
|
SERIALISE_ELEMENT(ResourceId, srcid, GetResourceManager()->GetID(MakeRes(srcImage)));
|
|
SERIALISE_ELEMENT(VkImageLayout, srclayout, srcImageLayout);
|
|
SERIALISE_ELEMENT(ResourceId, dstid, GetResourceManager()->GetID(MakeRes(destImage)));
|
|
SERIALISE_ELEMENT(VkImageLayout, dstlayout, destImageLayout);
|
|
|
|
SERIALISE_ELEMENT(uint32_t, count, regionCount);
|
|
SERIALISE_ELEMENT_ARR(VkImageCopy, regions, pRegions, count);
|
|
|
|
if(m_State == EXECUTING)
|
|
{
|
|
// VKTODOHIGH check if we want to partial-replay this cmd buffer
|
|
}
|
|
else if(m_State == READING)
|
|
{
|
|
cmdBuffer = (VkCmdBuffer)GetResourceManager()->GetLiveResource(cmdid).handle;
|
|
srcImage = (VkImage)GetResourceManager()->GetLiveResource(srcid).handle;
|
|
destImage = (VkImage)GetResourceManager()->GetLiveResource(dstid).handle;
|
|
|
|
m_Real.vkCmdCopyImage(cmdBuffer, srcImage, srclayout, destImage, dstlayout, count, regions);
|
|
}
|
|
|
|
SAFE_DELETE_ARRAY(regions);
|
|
|
|
return true;
|
|
}
|
|
|
|
void WrappedVulkan::vkCmdCopyImage(
|
|
VkCmdBuffer cmdBuffer,
|
|
VkImage srcImage,
|
|
VkImageLayout srcImageLayout,
|
|
VkImage destImage,
|
|
VkImageLayout destImageLayout,
|
|
uint32_t regionCount,
|
|
const VkImageCopy* pRegions)
|
|
{
|
|
m_Real.vkCmdCopyImage(cmdBuffer, srcImage, srcImageLayout, destImage, destImageLayout, regionCount, pRegions);
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
VkResourceRecord *record = GetResourceManager()->GetResourceRecord(MakeRes(cmdBuffer));
|
|
|
|
SCOPED_SERIALISE_CONTEXT(COPY_IMG);
|
|
Serialise_vkCmdCopyImage(cmdBuffer, srcImage, srcImageLayout, destImage, destImageLayout, regionCount, pRegions);
|
|
|
|
record->AddChunk(scope.Get());
|
|
record->MarkResourceFrameReferenced(GetResourceManager()->GetID(MakeRes(srcImage)), eFrameRef_Read);
|
|
record->MarkResourceFrameReferenced(GetResourceManager()->GetID(MakeRes(destImage)), eFrameRef_Write);
|
|
|
|
// VKTODOHIGH init states not implemented yet...
|
|
//record->dirtied.insert(GetResourceManager()->GetID(MakeRes(destImage)));
|
|
}
|
|
}
|
|
|
|
bool WrappedVulkan::Serialise_vkCmdCopyBufferToImage(
|
|
VkCmdBuffer cmdBuffer,
|
|
VkBuffer srcBuffer,
|
|
VkImage destImage,
|
|
VkImageLayout destImageLayout,
|
|
uint32_t regionCount,
|
|
const VkBufferImageCopy* pRegions)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, cmdid, GetResourceManager()->GetID(MakeRes(cmdBuffer)));
|
|
SERIALISE_ELEMENT(ResourceId, bufid, GetResourceManager()->GetID(MakeRes(srcBuffer)));
|
|
SERIALISE_ELEMENT(ResourceId, imgid, GetResourceManager()->GetID(MakeRes(destImage)));
|
|
|
|
SERIALISE_ELEMENT(uint32_t, count, regionCount);
|
|
SERIALISE_ELEMENT_ARR(VkBufferImageCopy, regions, pRegions, count);
|
|
|
|
if(m_State == EXECUTING)
|
|
{
|
|
// VKTODOHIGH check if we want to partial-replay this cmd buffer
|
|
}
|
|
else if(m_State == READING)
|
|
{
|
|
cmdBuffer = (VkCmdBuffer)GetResourceManager()->GetLiveResource(cmdid).handle;
|
|
srcBuffer = (VkBuffer)GetResourceManager()->GetLiveResource(bufid).handle;
|
|
destImage = (VkImage)GetResourceManager()->GetLiveResource(imgid).handle;
|
|
|
|
m_Real.vkCmdCopyBufferToImage(cmdBuffer, srcBuffer, destImage, destImageLayout, count, regions);
|
|
}
|
|
|
|
SAFE_DELETE_ARRAY(regions);
|
|
|
|
return true;
|
|
}
|
|
|
|
void WrappedVulkan::vkCmdCopyBufferToImage(
|
|
VkCmdBuffer cmdBuffer,
|
|
VkBuffer srcBuffer,
|
|
VkImage destImage,
|
|
VkImageLayout destImageLayout,
|
|
uint32_t regionCount,
|
|
const VkBufferImageCopy* pRegions)
|
|
{
|
|
m_Real.vkCmdCopyBufferToImage(cmdBuffer, srcBuffer, destImage, destImageLayout, regionCount, pRegions);
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
VkResourceRecord *record = GetResourceManager()->GetResourceRecord(MakeRes(cmdBuffer));
|
|
|
|
SCOPED_SERIALISE_CONTEXT(COPY_BUF2IMG);
|
|
Serialise_vkCmdCopyBufferToImage(cmdBuffer, srcBuffer, destImage, destImageLayout, regionCount, pRegions);
|
|
|
|
record->AddChunk(scope.Get());
|
|
|
|
record->dirtied.insert(GetResourceManager()->GetID(MakeRes(destImage)));
|
|
record->MarkResourceFrameReferenced(GetResourceManager()->GetID(MakeRes(srcBuffer)), eFrameRef_Read);
|
|
record->MarkResourceFrameReferenced(GetResourceManager()->GetID(MakeRes(destImage)), eFrameRef_Write);
|
|
}
|
|
}
|
|
|
|
bool WrappedVulkan::Serialise_vkCmdCopyImageToBuffer(
|
|
VkCmdBuffer cmdBuffer,
|
|
VkImage srcImage,
|
|
VkImageLayout srcImageLayout,
|
|
VkBuffer destBuffer,
|
|
uint32_t regionCount,
|
|
const VkBufferImageCopy* pRegions)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, cmdid, GetResourceManager()->GetID(MakeRes(cmdBuffer)));
|
|
SERIALISE_ELEMENT(ResourceId, bufid, GetResourceManager()->GetID(MakeRes(destBuffer)));
|
|
SERIALISE_ELEMENT(ResourceId, imgid, GetResourceManager()->GetID(MakeRes(srcImage)));
|
|
|
|
SERIALISE_ELEMENT(VkImageLayout, layout, srcImageLayout);
|
|
|
|
SERIALISE_ELEMENT(uint32_t, count, regionCount);
|
|
SERIALISE_ELEMENT_ARR(VkBufferImageCopy, regions, pRegions, count);
|
|
|
|
if(m_State == EXECUTING)
|
|
{
|
|
// VKTODOHIGH check if we want to partial-replay this cmd buffer
|
|
}
|
|
else if(m_State == READING)
|
|
{
|
|
cmdBuffer = (VkCmdBuffer)GetResourceManager()->GetLiveResource(cmdid).handle;
|
|
srcImage = (VkImage)GetResourceManager()->GetLiveResource(imgid).handle;
|
|
destBuffer = (VkBuffer)GetResourceManager()->GetLiveResource(bufid).handle;
|
|
|
|
m_Real.vkCmdCopyImageToBuffer(cmdBuffer, srcImage, layout, destBuffer, count, regions);
|
|
}
|
|
|
|
SAFE_DELETE_ARRAY(regions);
|
|
|
|
return true;
|
|
}
|
|
|
|
void WrappedVulkan::vkCmdCopyImageToBuffer(
|
|
VkCmdBuffer cmdBuffer,
|
|
VkImage srcImage,
|
|
VkImageLayout srcImageLayout,
|
|
VkBuffer destBuffer,
|
|
uint32_t regionCount,
|
|
const VkBufferImageCopy* pRegions)
|
|
{
|
|
m_Real.vkCmdCopyImageToBuffer(cmdBuffer, srcImage, srcImageLayout, destBuffer, regionCount, pRegions);
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
VkResourceRecord *record = GetResourceManager()->GetResourceRecord(MakeRes(cmdBuffer));
|
|
|
|
SCOPED_SERIALISE_CONTEXT(COPY_IMG2BUF);
|
|
Serialise_vkCmdCopyImageToBuffer(cmdBuffer, srcImage, srcImageLayout, destBuffer, regionCount, pRegions);
|
|
|
|
record->AddChunk(scope.Get());
|
|
record->MarkResourceFrameReferenced(GetResourceManager()->GetID(MakeRes(srcImage)), eFrameRef_Read);
|
|
record->MarkResourceFrameReferenced(GetResourceManager()->GetID(MakeRes(destBuffer)), eFrameRef_Write);
|
|
|
|
// VKTODOMED: need to dirty the memory bound to the buffer?
|
|
record->dirtied.insert(GetResourceManager()->GetID(MakeRes(destBuffer)));
|
|
}
|
|
}
|
|
|
|
bool WrappedVulkan::Serialise_vkCmdCopyBuffer(
|
|
VkCmdBuffer cmdBuffer,
|
|
VkBuffer srcBuffer,
|
|
VkBuffer destBuffer,
|
|
uint32_t regionCount,
|
|
const VkBufferCopy* pRegions)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, cmdid, GetResourceManager()->GetID(MakeRes(cmdBuffer)));
|
|
SERIALISE_ELEMENT(ResourceId, srcid, GetResourceManager()->GetID(MakeRes(srcBuffer)));
|
|
SERIALISE_ELEMENT(ResourceId, dstid, GetResourceManager()->GetID(MakeRes(destBuffer)));
|
|
|
|
SERIALISE_ELEMENT(uint32_t, count, regionCount);
|
|
SERIALISE_ELEMENT_ARR(VkBufferCopy, regions, pRegions, count);
|
|
|
|
if(m_State == EXECUTING)
|
|
{
|
|
// VKTODOHIGH check if we want to partial-replay this cmd buffer
|
|
}
|
|
else if(m_State == READING)
|
|
{
|
|
cmdBuffer = (VkCmdBuffer)GetResourceManager()->GetLiveResource(cmdid).handle;
|
|
srcBuffer = (VkBuffer)GetResourceManager()->GetLiveResource(srcid).handle;
|
|
destBuffer = (VkBuffer)GetResourceManager()->GetLiveResource(dstid).handle;
|
|
|
|
m_Real.vkCmdCopyBuffer(cmdBuffer, srcBuffer, destBuffer, count, regions);
|
|
}
|
|
|
|
SAFE_DELETE_ARRAY(regions);
|
|
|
|
return true;
|
|
}
|
|
|
|
void WrappedVulkan::vkCmdCopyBuffer(
|
|
VkCmdBuffer cmdBuffer,
|
|
VkBuffer srcBuffer,
|
|
VkBuffer destBuffer,
|
|
uint32_t regionCount,
|
|
const VkBufferCopy* pRegions)
|
|
{
|
|
m_Real.vkCmdCopyBuffer(cmdBuffer, srcBuffer, destBuffer, regionCount, pRegions);
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
VkResourceRecord *record = GetResourceManager()->GetResourceRecord(MakeRes(cmdBuffer));
|
|
|
|
SCOPED_SERIALISE_CONTEXT(COPY_BUF);
|
|
Serialise_vkCmdCopyBuffer(cmdBuffer, srcBuffer, destBuffer, regionCount, pRegions);
|
|
|
|
record->AddChunk(scope.Get());
|
|
record->MarkResourceFrameReferenced(GetResourceManager()->GetID(MakeRes(srcBuffer)), eFrameRef_Read);
|
|
record->MarkResourceFrameReferenced(GetResourceManager()->GetID(MakeRes(destBuffer)), eFrameRef_Write);
|
|
|
|
// VKTODOMED: need to dirty the memory bound to the buffer?
|
|
record->dirtied.insert(GetResourceManager()->GetID(MakeRes(destBuffer)));
|
|
}
|
|
}
|
|
|
|
bool WrappedVulkan::Serialise_vkCmdClearColorImage(
|
|
VkCmdBuffer cmdBuffer,
|
|
VkImage image,
|
|
VkImageLayout imageLayout,
|
|
const VkClearColorValue* pColor,
|
|
uint32_t rangeCount,
|
|
const VkImageSubresourceRange* pRanges)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, cmdid, GetResourceManager()->GetID(MakeRes(cmdBuffer)));
|
|
SERIALISE_ELEMENT(ResourceId, imgid, GetResourceManager()->GetID(MakeRes(image)));
|
|
SERIALISE_ELEMENT(VkImageLayout, layout, imageLayout);
|
|
SERIALISE_ELEMENT(VkClearColorValue, col, *pColor);
|
|
|
|
SERIALISE_ELEMENT(uint32_t, count, rangeCount);
|
|
SERIALISE_ELEMENT_ARR(VkImageSubresourceRange, ranges, pRanges, count);
|
|
|
|
if(m_State == EXECUTING)
|
|
{
|
|
// VKTODOHIGH check if we want to partial-replay this cmd buffer
|
|
}
|
|
else if(m_State == READING)
|
|
{
|
|
cmdBuffer = (VkCmdBuffer)GetResourceManager()->GetLiveResource(cmdid).handle;
|
|
image = (VkImage)GetResourceManager()->GetLiveResource(imgid).handle;
|
|
|
|
m_Real.vkCmdClearColorImage(cmdBuffer, image, layout, &col, count, ranges);
|
|
}
|
|
|
|
SAFE_DELETE_ARRAY(ranges);
|
|
|
|
return true;
|
|
}
|
|
|
|
void WrappedVulkan::vkCmdClearColorImage(
|
|
VkCmdBuffer cmdBuffer,
|
|
VkImage image,
|
|
VkImageLayout imageLayout,
|
|
const VkClearColorValue* pColor,
|
|
uint32_t rangeCount,
|
|
const VkImageSubresourceRange* pRanges)
|
|
{
|
|
m_Real.vkCmdClearColorImage(cmdBuffer, image, imageLayout, pColor, rangeCount, pRanges);
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
VkResourceRecord *record = GetResourceManager()->GetResourceRecord(MakeRes(cmdBuffer));
|
|
|
|
SCOPED_SERIALISE_CONTEXT(CLEAR_COLOR);
|
|
Serialise_vkCmdClearColorImage(cmdBuffer, image, imageLayout, pColor, rangeCount, pRanges);
|
|
|
|
record->AddChunk(scope.Get());
|
|
record->MarkResourceFrameReferenced(GetResourceManager()->GetID(MakeRes(image)), eFrameRef_Write);
|
|
}
|
|
}
|
|
|
|
bool WrappedVulkan::Serialise_vkCmdClearDepthStencilImage(
|
|
VkCmdBuffer cmdBuffer,
|
|
VkImage image,
|
|
VkImageLayout imageLayout,
|
|
float depth,
|
|
uint32_t stencil,
|
|
uint32_t rangeCount,
|
|
const VkImageSubresourceRange* pRanges)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, cmdid, GetResourceManager()->GetID(MakeRes(cmdBuffer)));
|
|
SERIALISE_ELEMENT(ResourceId, imgid, GetResourceManager()->GetID(MakeRes(image)));
|
|
SERIALISE_ELEMENT(VkImageLayout, l, imageLayout);
|
|
SERIALISE_ELEMENT(float, d, depth);
|
|
SERIALISE_ELEMENT(byte, s, stencil);
|
|
SERIALISE_ELEMENT(uint32_t, count, rangeCount);
|
|
SERIALISE_ELEMENT_ARR(VkImageSubresourceRange, ranges, pRanges, count);
|
|
|
|
if(m_State == EXECUTING)
|
|
{
|
|
// VKTODOHIGH check if we want to partial-replay this cmd buffer
|
|
}
|
|
else if(m_State == READING)
|
|
{
|
|
cmdBuffer = (VkCmdBuffer)GetResourceManager()->GetLiveResource(cmdid).handle;
|
|
image = (VkImage)GetResourceManager()->GetLiveResource(imgid).handle;
|
|
|
|
m_Real.vkCmdClearDepthStencilImage(cmdBuffer, image, l, d, s, count, ranges);
|
|
}
|
|
|
|
SAFE_DELETE_ARRAY(ranges);
|
|
|
|
return true;
|
|
}
|
|
|
|
void WrappedVulkan::vkCmdClearDepthStencilImage(
|
|
VkCmdBuffer cmdBuffer,
|
|
VkImage image,
|
|
VkImageLayout imageLayout,
|
|
float depth,
|
|
uint32_t stencil,
|
|
uint32_t rangeCount,
|
|
const VkImageSubresourceRange* pRanges)
|
|
{
|
|
m_Real.vkCmdClearDepthStencilImage(cmdBuffer, image, imageLayout, depth, stencil, rangeCount, pRanges);
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
VkResourceRecord *record = GetResourceManager()->GetResourceRecord(MakeRes(cmdBuffer));
|
|
|
|
SCOPED_SERIALISE_CONTEXT(CLEAR_DEPTHSTENCIL);
|
|
Serialise_vkCmdClearDepthStencilImage(cmdBuffer, image, imageLayout, depth, stencil, rangeCount, pRanges);
|
|
|
|
record->AddChunk(scope.Get());
|
|
record->MarkResourceFrameReferenced(GetResourceManager()->GetID(MakeRes(image)), eFrameRef_Write);
|
|
}
|
|
}
|
|
|
|
bool WrappedVulkan::Serialise_vkCmdClearColorAttachment(
|
|
VkCmdBuffer cmdBuffer,
|
|
uint32_t colorAttachment,
|
|
VkImageLayout imageLayout,
|
|
const VkClearColorValue* pColor,
|
|
uint32_t rectCount,
|
|
const VkRect3D* pRects)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, cmdid, GetResourceManager()->GetID(MakeRes(cmdBuffer)));
|
|
SERIALISE_ELEMENT(uint32_t, att, colorAttachment);
|
|
SERIALISE_ELEMENT(VkImageLayout, layout, imageLayout);
|
|
SERIALISE_ELEMENT(VkClearColorValue, col, *pColor);
|
|
|
|
SERIALISE_ELEMENT(uint32_t, count, rectCount);
|
|
SERIALISE_ELEMENT_ARR(VkRect3D, rects, pRects, count);
|
|
|
|
if(m_State == EXECUTING)
|
|
{
|
|
// VKTODOHIGH check if we want to partial-replay this cmd buffer
|
|
}
|
|
else if(m_State == READING)
|
|
{
|
|
cmdBuffer = (VkCmdBuffer)GetResourceManager()->GetLiveResource(cmdid).handle;
|
|
|
|
m_Real.vkCmdClearColorAttachment(cmdBuffer, att, layout, &col, count, rects);
|
|
}
|
|
|
|
SAFE_DELETE_ARRAY(rects);
|
|
|
|
return true;
|
|
}
|
|
|
|
void WrappedVulkan::vkCmdClearColorAttachment(
|
|
VkCmdBuffer cmdBuffer,
|
|
uint32_t colorAttachment,
|
|
VkImageLayout imageLayout,
|
|
const VkClearColorValue* pColor,
|
|
uint32_t rectCount,
|
|
const VkRect3D* pRects)
|
|
{
|
|
m_Real.vkCmdClearColorAttachment(cmdBuffer, colorAttachment, imageLayout, pColor, rectCount, pRects);
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
VkResourceRecord *record = GetResourceManager()->GetResourceRecord(MakeRes(cmdBuffer));
|
|
|
|
SCOPED_SERIALISE_CONTEXT(CLEAR_COLOR_ATTACH);
|
|
Serialise_vkCmdClearColorAttachment(cmdBuffer, colorAttachment, imageLayout, pColor, rectCount, pRects);
|
|
|
|
record->AddChunk(scope.Get());
|
|
// VKTODOHIGH mark referenced the image under the attachment
|
|
//record->MarkResourceFrameReferenced(GetResourceManager()->GetID(MakeRes(image)), eFrameRef_Write);
|
|
}
|
|
}
|
|
|
|
bool WrappedVulkan::Serialise_vkCmdClearDepthStencilAttachment(
|
|
VkCmdBuffer cmdBuffer,
|
|
VkImageAspectFlags imageAspectMask,
|
|
VkImageLayout imageLayout,
|
|
float depth,
|
|
uint32_t stencil,
|
|
uint32_t rectCount,
|
|
const VkRect3D* pRects)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, cmdid, GetResourceManager()->GetID(MakeRes(cmdBuffer)));
|
|
SERIALISE_ELEMENT(VkImageAspectFlags, asp, imageAspectMask);
|
|
SERIALISE_ELEMENT(VkImageLayout, lay, imageLayout);
|
|
SERIALISE_ELEMENT(float, d, depth);
|
|
SERIALISE_ELEMENT(byte, s, stencil);
|
|
SERIALISE_ELEMENT(uint32_t, count, rectCount);
|
|
SERIALISE_ELEMENT_ARR(VkRect3D, rects, pRects, count);
|
|
|
|
if(m_State == EXECUTING)
|
|
{
|
|
// VKTODOHIGH check if we want to partial-replay this cmd buffer
|
|
}
|
|
else if(m_State == READING)
|
|
{
|
|
cmdBuffer = (VkCmdBuffer)GetResourceManager()->GetLiveResource(cmdid).handle;
|
|
|
|
m_Real.vkCmdClearDepthStencilAttachment(cmdBuffer, asp, lay, d, s, count, rects);
|
|
}
|
|
|
|
SAFE_DELETE_ARRAY(rects);
|
|
|
|
return true;
|
|
}
|
|
|
|
void WrappedVulkan::vkCmdClearDepthStencilAttachment(
|
|
VkCmdBuffer cmdBuffer,
|
|
VkImageAspectFlags imageAspectMask,
|
|
VkImageLayout imageLayout,
|
|
float depth,
|
|
uint32_t stencil,
|
|
uint32_t rectCount,
|
|
const VkRect3D* pRects)
|
|
{
|
|
m_Real.vkCmdClearDepthStencilAttachment(cmdBuffer, imageAspectMask, imageLayout, depth, stencil, rectCount, pRects);
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
VkResourceRecord *record = GetResourceManager()->GetResourceRecord(MakeRes(cmdBuffer));
|
|
|
|
SCOPED_SERIALISE_CONTEXT(CLEAR_DEPTHSTENCIL_ATTACH);
|
|
Serialise_vkCmdClearDepthStencilAttachment(cmdBuffer, imageAspectMask, imageLayout, depth, stencil, rectCount, pRects);
|
|
|
|
record->AddChunk(scope.Get());
|
|
// VKTODOHIGH mark referenced the image under the attachment
|
|
//record->MarkResourceFrameReferenced(GetResourceManager()->GetID(MakeRes(image)), eFrameRef_Write);
|
|
}
|
|
}
|
|
|
|
bool WrappedVulkan::Serialise_vkCmdPipelineBarrier(
|
|
VkCmdBuffer cmdBuffer,
|
|
VkPipelineStageFlags srcStageMask,
|
|
VkPipelineStageFlags destStageMask,
|
|
VkBool32 byRegion,
|
|
uint32_t memBarrierCount,
|
|
const void* const* ppMemBarriers)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, cmdid, GetResourceManager()->GetID(MakeRes(cmdBuffer)));
|
|
SERIALISE_ELEMENT(VkPipelineStageFlags, src, srcStageMask);
|
|
SERIALISE_ELEMENT(VkPipelineStageFlags, dest, destStageMask);
|
|
|
|
SERIALISE_ELEMENT(VkBool32, region, byRegion);
|
|
|
|
SERIALISE_ELEMENT(uint32_t, memCount, memBarrierCount);
|
|
|
|
vector<VkGenericStruct*> mems;
|
|
vector<VkImageMemoryBarrier> imTrans;
|
|
|
|
for(uint32_t i=0; i < memCount; i++)
|
|
{
|
|
SERIALISE_ELEMENT(VkStructureType, stype, ((VkGenericStruct *)ppMemBarriers[i])->type);
|
|
|
|
if(stype == VK_STRUCTURE_TYPE_MEMORY_BARRIER)
|
|
{
|
|
SERIALISE_ELEMENT(VkMemoryBarrier, barrier, *((VkMemoryBarrier *)ppMemBarriers[i]));
|
|
|
|
if(m_State < WRITING)
|
|
mems.push_back((VkGenericStruct *)new VkMemoryBarrier(barrier));
|
|
}
|
|
else if(stype == VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER)
|
|
{
|
|
SERIALISE_ELEMENT(VkBufferMemoryBarrier, barrier, *((VkBufferMemoryBarrier *)ppMemBarriers[i]));
|
|
|
|
if(m_State < WRITING)
|
|
mems.push_back((VkGenericStruct *)new VkBufferMemoryBarrier(barrier));
|
|
}
|
|
else if(stype == VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER)
|
|
{
|
|
SERIALISE_ELEMENT(VkImageMemoryBarrier, barrier, *((VkImageMemoryBarrier *)ppMemBarriers[i]));
|
|
|
|
if(m_State < WRITING)
|
|
{
|
|
mems.push_back((VkGenericStruct *)new VkImageMemoryBarrier(barrier));
|
|
imTrans.push_back(barrier);
|
|
}
|
|
}
|
|
}
|
|
|
|
if(m_State == EXECUTING)
|
|
{
|
|
// VKTODOHIGH check if we want to partial-replay this cmd buffer
|
|
}
|
|
else if(m_State == READING)
|
|
{
|
|
cmdBuffer = (VkCmdBuffer)GetResourceManager()->GetLiveResource(cmdid).handle;
|
|
|
|
m_Real.vkCmdPipelineBarrier(cmdBuffer, src, dest, region, memCount, (const void **)&mems[0]);
|
|
|
|
ResourceId cmd = GetResourceManager()->GetID(MakeRes(cmdBuffer));
|
|
GetResourceManager()->RecordTransitions(m_CmdBufferInfo[cmd].imgtransitions, m_ImageInfo, (uint32_t)imTrans.size(), &imTrans[0]);
|
|
}
|
|
|
|
for(size_t i=0; i < mems.size(); i++)
|
|
delete mems[i];
|
|
|
|
return true;
|
|
}
|
|
|
|
void WrappedVulkan::vkCmdPipelineBarrier(
|
|
VkCmdBuffer cmdBuffer,
|
|
VkPipelineStageFlags srcStageMask,
|
|
VkPipelineStageFlags destStageMask,
|
|
VkBool32 byRegion,
|
|
uint32_t memBarrierCount,
|
|
const void* const* ppMemBarriers)
|
|
{
|
|
m_Real.vkCmdPipelineBarrier(cmdBuffer, srcStageMask, destStageMask, byRegion, memBarrierCount, ppMemBarriers);
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
VkResourceRecord *record = GetResourceManager()->GetResourceRecord(MakeRes(cmdBuffer));
|
|
|
|
SCOPED_SERIALISE_CONTEXT(PIPELINE_BARRIER);
|
|
Serialise_vkCmdPipelineBarrier(cmdBuffer, srcStageMask, destStageMask, byRegion, memBarrierCount, ppMemBarriers);
|
|
|
|
record->AddChunk(scope.Get());
|
|
|
|
vector<VkImageMemoryBarrier> imTrans;
|
|
|
|
for(uint32_t i=0; i < memBarrierCount; i++)
|
|
{
|
|
VkStructureType stype = ((VkGenericStruct *)ppMemBarriers[i])->type;
|
|
|
|
if(stype == VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER)
|
|
imTrans.push_back(*((VkImageMemoryBarrier *)ppMemBarriers[i]));
|
|
}
|
|
|
|
ResourceId cmd = GetResourceManager()->GetID(MakeRes(cmdBuffer));
|
|
GetResourceManager()->RecordTransitions(m_CmdBufferInfo[cmd].imgtransitions, m_ImageInfo, (uint32_t)imTrans.size(), &imTrans[0]);
|
|
|
|
// VKTODOMED do we need to mark frame referenced the resources in the barrier? if they're not referenced
|
|
// elsewhere, perhaps they can be dropped
|
|
}
|
|
}
|
|
|
|
VkResult WrappedVulkan::vkDbgCreateMsgCallback(
|
|
VkInstance instance,
|
|
VkFlags msgFlags,
|
|
const PFN_vkDbgMsgCallback pfnMsgCallback,
|
|
void* pUserData,
|
|
VkDbgMsgCallback* pMsgCallback)
|
|
{
|
|
return m_Real.vkDbgCreateMsgCallback(instance, msgFlags, pfnMsgCallback, pUserData, pMsgCallback);
|
|
}
|
|
|
|
VkResult WrappedVulkan::vkDbgDestroyMsgCallback(
|
|
VkInstance instance,
|
|
VkDbgMsgCallback msgCallback)
|
|
{
|
|
return m_Real.vkDbgDestroyMsgCallback(instance, msgCallback);
|
|
}
|
|
|
|
bool WrappedVulkan::Serialise_vkCmdDbgMarkerBegin(
|
|
VkCmdBuffer cmdBuffer,
|
|
const char* pMarker)
|
|
{
|
|
string name = pMarker ? string(pMarker) : "";
|
|
|
|
SERIALISE_ELEMENT(ResourceId, cmdid, GetResourceManager()->GetID(MakeRes(cmdBuffer)));
|
|
m_pSerialiser->Serialise("Name", name);
|
|
|
|
if(m_State == READING)
|
|
{
|
|
FetchDrawcall draw;
|
|
draw.name = name;
|
|
draw.flags |= eDraw_PushMarker;
|
|
|
|
AddDrawcall(draw, false);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void WrappedVulkan::vkCmdDbgMarkerBegin(
|
|
VkCmdBuffer cmdBuffer,
|
|
const char* pMarker)
|
|
{
|
|
if(m_State == WRITING_CAPFRAME)
|
|
{
|
|
VkResourceRecord *record = GetResourceManager()->GetResourceRecord(MakeRes(cmdBuffer));
|
|
|
|
SCOPED_SERIALISE_CONTEXT(BEGIN_EVENT);
|
|
Serialise_vkCmdDbgMarkerBegin(cmdBuffer, pMarker);
|
|
|
|
record->AddChunk(scope.Get());
|
|
}
|
|
}
|
|
|
|
bool WrappedVulkan::Serialise_vkCmdDbgMarkerEnd(VkCmdBuffer cmdBuffer)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, cmdid, GetResourceManager()->GetID(MakeRes(cmdBuffer)));
|
|
|
|
if(m_State == READING && !m_CurEvents.empty())
|
|
{
|
|
FetchDrawcall draw;
|
|
draw.name = "API Calls";
|
|
draw.flags |= eDraw_SetMarker;
|
|
|
|
AddDrawcall(draw, true);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void WrappedVulkan::vkCmdDbgMarkerEnd(
|
|
VkCmdBuffer cmdBuffer)
|
|
{
|
|
if(m_State == WRITING_CAPFRAME)
|
|
{
|
|
VkResourceRecord *record = GetResourceManager()->GetResourceRecord(MakeRes(cmdBuffer));
|
|
|
|
SCOPED_SERIALISE_CONTEXT(END_EVENT);
|
|
Serialise_vkCmdDbgMarkerEnd(cmdBuffer);
|
|
|
|
record->AddChunk(scope.Get());
|
|
}
|
|
}
|
|
|
|
bool WrappedVulkan::ReleaseResource(VkResource res)
|
|
{
|
|
// VKTODOHIGH: release resource with device from resource record
|
|
|
|
return true;
|
|
}
|
|
|
|
void WrappedVulkan::Serialise_CaptureScope(uint64_t offset)
|
|
{
|
|
SERIALISE_ELEMENT(uint32_t, FrameNumber, m_FrameCounter);
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
GetResourceManager()->Serialise_InitialContentsNeeded();
|
|
}
|
|
else
|
|
{
|
|
FetchFrameRecord record;
|
|
record.frameInfo.fileOffset = offset;
|
|
record.frameInfo.firstEvent = 1;//m_pImmediateContext->GetEventID();
|
|
record.frameInfo.frameNumber = FrameNumber;
|
|
record.frameInfo.immContextId = GetResourceManager()->GetOriginalID(m_ContextResourceID);
|
|
m_FrameRecord.push_back(record);
|
|
|
|
GetResourceManager()->CreateInitialContents();
|
|
}
|
|
}
|
|
|
|
void WrappedVulkan::EndCaptureFrame(VkImage presentImage)
|
|
{
|
|
SCOPED_SERIALISE_CONTEXT(CONTEXT_CAPTURE_FOOTER);
|
|
|
|
SERIALISE_ELEMENT(ResourceId, bbid, GetResourceManager()->GetID(MakeRes(presentImage)));
|
|
|
|
RDCASSERT(presentImage != VK_NULL_HANDLE);
|
|
|
|
bool HasCallstack = RenderDoc::Inst().GetCaptureOptions().CaptureCallstacks != 0;
|
|
m_pSerialiser->Serialise("HasCallstack", HasCallstack);
|
|
|
|
if(HasCallstack)
|
|
{
|
|
Callstack::Stackwalk *call = Callstack::Collect();
|
|
|
|
RDCASSERT(call->NumLevels() < 0xff);
|
|
|
|
size_t numLevels = call->NumLevels();
|
|
uint64_t *stack = (uint64_t *)call->GetAddrs();
|
|
|
|
m_pSerialiser->SerialisePODArray("callstack", stack, numLevels);
|
|
|
|
delete call;
|
|
}
|
|
|
|
m_ContextRecord->AddChunk(scope.Get());
|
|
}
|
|
|
|
void WrappedVulkan::AttemptCapture()
|
|
{
|
|
m_State = WRITING_CAPFRAME;
|
|
|
|
{
|
|
RDCDEBUG("Immediate Context %llu Attempting capture", GetContextResourceID());
|
|
|
|
//m_SuccessfulCapture = true;
|
|
|
|
m_ContextRecord->LockChunks();
|
|
while(m_ContextRecord->HasChunks())
|
|
{
|
|
Chunk *chunk = m_ContextRecord->GetLastChunk();
|
|
|
|
SAFE_DELETE(chunk);
|
|
m_ContextRecord->PopChunk();
|
|
}
|
|
m_ContextRecord->UnlockChunks();
|
|
}
|
|
}
|
|
|
|
bool WrappedVulkan::Serialise_BeginCaptureFrame(bool applyInitialState)
|
|
{
|
|
if(m_State < WRITING && !applyInitialState)
|
|
{
|
|
m_pSerialiser->SkipCurrentChunk();
|
|
return true;
|
|
}
|
|
|
|
vector<VkImageMemoryBarrier> imgTransitions;
|
|
|
|
GetResourceManager()->SerialiseImageStates(m_pSerialiser, m_ImageInfo, imgTransitions);
|
|
|
|
if(applyInitialState && !imgTransitions.empty())
|
|
{
|
|
VkCmdBuffer cmd = GetCmd();
|
|
|
|
VkCmdBufferBeginInfo beginInfo = { VK_STRUCTURE_TYPE_CMD_BUFFER_BEGIN_INFO, NULL, VK_CMD_BUFFER_OPTIMIZE_SMALL_BATCH_BIT | VK_CMD_BUFFER_OPTIMIZE_ONE_TIME_SUBMIT_BIT };
|
|
|
|
m_Real.vkBeginCommandBuffer(cmd, &beginInfo);
|
|
|
|
VkPipelineStageFlags src_stages = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
|
VkPipelineStageFlags dest_stages = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
|
|
|
if(!imgTransitions.empty())
|
|
{
|
|
vector<void *> barriers;
|
|
for(size_t i=0; i < imgTransitions.size(); i++)
|
|
barriers.push_back(&imgTransitions[i]);
|
|
m_Real.vkCmdPipelineBarrier(cmd, src_stages, dest_stages, false, (uint32_t)imgTransitions.size(), (const void *const *)&barriers[0]);
|
|
}
|
|
|
|
m_Real.vkEndCommandBuffer(cmd);
|
|
m_Real.vkQueueSubmit(GetQ(), 1, &cmd, VK_NULL_HANDLE);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void WrappedVulkan::BeginCaptureFrame()
|
|
{
|
|
SCOPED_SERIALISE_CONTEXT(CONTEXT_CAPTURE_HEADER);
|
|
|
|
Serialise_BeginCaptureFrame(false);
|
|
|
|
m_ContextRecord->AddChunk(scope.Get(), 1);
|
|
}
|
|
|
|
void WrappedVulkan::FinishCapture()
|
|
{
|
|
m_State = WRITING_IDLE;
|
|
|
|
//m_SuccessfulCapture = false;
|
|
|
|
m_Real.vkDeviceWaitIdle(GetDev());
|
|
}
|
|
|
|
void WrappedVulkan::ReadLogInitialisation()
|
|
{
|
|
uint64_t lastFrame = 0;
|
|
uint64_t firstFrame = 0;
|
|
|
|
m_pSerialiser->SetDebugText(true);
|
|
|
|
m_pSerialiser->Rewind();
|
|
|
|
while(!m_pSerialiser->AtEnd())
|
|
{
|
|
m_pSerialiser->SkipToChunk(CAPTURE_SCOPE);
|
|
|
|
// found a capture chunk
|
|
if(!m_pSerialiser->AtEnd())
|
|
{
|
|
lastFrame = m_pSerialiser->GetOffset();
|
|
if(firstFrame == 0)
|
|
firstFrame = m_pSerialiser->GetOffset();
|
|
|
|
// skip this chunk
|
|
m_pSerialiser->PushContext(NULL, CAPTURE_SCOPE, false);
|
|
m_pSerialiser->SkipCurrentChunk();
|
|
m_pSerialiser->PopContext(NULL, CAPTURE_SCOPE);
|
|
}
|
|
}
|
|
|
|
m_pSerialiser->Rewind();
|
|
|
|
int chunkIdx = 0;
|
|
|
|
struct chunkinfo
|
|
{
|
|
chunkinfo() : count(0), total(0.0) {}
|
|
int count;
|
|
double total;
|
|
};
|
|
|
|
map<VulkanChunkType,chunkinfo> chunkInfos;
|
|
|
|
SCOPED_TIMER("chunk initialisation");
|
|
|
|
while(1)
|
|
{
|
|
PerformanceTimer timer;
|
|
|
|
uint64_t offset = m_pSerialiser->GetOffset();
|
|
|
|
VulkanChunkType context = (VulkanChunkType)m_pSerialiser->PushContext(NULL, 1, false);
|
|
|
|
if(context == CAPTURE_SCOPE)
|
|
{
|
|
// immediately read rest of log into memory
|
|
m_pSerialiser->SetPersistentBlock(offset);
|
|
}
|
|
|
|
chunkIdx++;
|
|
|
|
ProcessChunk(offset, context);
|
|
|
|
m_pSerialiser->PopContext(NULL, context);
|
|
|
|
RenderDoc::Inst().SetProgress(FileInitialRead, float(m_pSerialiser->GetOffset())/float(m_pSerialiser->GetSize()));
|
|
|
|
if(context == CAPTURE_SCOPE)
|
|
{
|
|
GetResourceManager()->ApplyInitialContents();
|
|
|
|
ContextReplayLog(READING, 0, 0, false);
|
|
|
|
if(m_pSerialiser->GetOffset() > lastFrame)
|
|
break;
|
|
}
|
|
|
|
chunkInfos[context].total += timer.GetMilliseconds();
|
|
chunkInfos[context].count++;
|
|
|
|
if(m_pSerialiser->AtEnd())
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
for(auto it=chunkInfos.begin(); it != chunkInfos.end(); ++it)
|
|
{
|
|
RDCDEBUG("%hs: %.3f total time in %d chunks - %.3f average",
|
|
GetChunkName(it->first), it->second.total, it->second.count,
|
|
it->second.total/double(it->second.count));
|
|
}
|
|
|
|
RDCDEBUG("Allocating %llu persistant bytes of memory for the log.", m_pSerialiser->GetSize() - firstFrame);
|
|
|
|
m_pSerialiser->SetDebugText(false);
|
|
|
|
RDCASSERT(m_SwapPhysDevice >= 0 &&
|
|
m_PhysicalReplayData[m_SwapPhysDevice].dev != VK_NULL_HANDLE &&
|
|
m_PhysicalReplayData[m_SwapPhysDevice].q != VK_NULL_HANDLE &&
|
|
m_PhysicalReplayData[m_SwapPhysDevice].cmd != VK_NULL_HANDLE &&
|
|
m_PhysicalReplayData[m_SwapPhysDevice].cmdpool != VK_NULL_HANDLE);
|
|
}
|
|
|
|
void WrappedVulkan::ContextReplayLog(LogState readType, uint32_t startEventID, uint32_t endEventID, bool partial)
|
|
{
|
|
m_State = readType;
|
|
|
|
VulkanChunkType header = (VulkanChunkType)m_pSerialiser->PushContext(NULL, 1, false);
|
|
RDCASSERT(header == CONTEXT_CAPTURE_HEADER);
|
|
|
|
WrappedVulkan *context = this;
|
|
|
|
Serialise_BeginCaptureFrame(!partial);
|
|
|
|
m_Real.vkDeviceWaitIdle(GetDev());
|
|
|
|
m_pSerialiser->PopContext(NULL, header);
|
|
|
|
m_CurEvents.clear();
|
|
|
|
if(m_State == EXECUTING)
|
|
{
|
|
FetchAPIEvent ev = GetEvent(startEventID);
|
|
m_CurEventID = ev.eventID;
|
|
m_pSerialiser->SetOffset(ev.fileOffset);
|
|
}
|
|
else if(m_State == READING)
|
|
{
|
|
m_CurEventID = 1;
|
|
}
|
|
|
|
if(m_State == EXECUTING)
|
|
{
|
|
}
|
|
|
|
// VKTODOMED I think this is a legacy concept that doesn't really mean anything anymore,
|
|
// even on GL/D3D11. Creates are all shifted before the frame, only command bfufers remain
|
|
// in vulkan
|
|
//GetResourceManager()->MarkInFrame(true);
|
|
|
|
while(1)
|
|
{
|
|
if(m_State == EXECUTING && m_CurEventID > endEventID)
|
|
{
|
|
// we can just break out if we've done all the events desired.
|
|
break;
|
|
}
|
|
|
|
uint64_t offset = m_pSerialiser->GetOffset();
|
|
|
|
VulkanChunkType context = (VulkanChunkType)m_pSerialiser->PushContext(NULL, 1, false);
|
|
|
|
ContextProcessChunk(offset, context, false);
|
|
|
|
RenderDoc::Inst().SetProgress(FileInitialRead, float(offset)/float(m_pSerialiser->GetSize()));
|
|
|
|
// for now just abort after capture scope. Really we'd need to support multiple frames
|
|
// but for now this will do.
|
|
if(context == CONTEXT_CAPTURE_FOOTER)
|
|
break;
|
|
|
|
m_CurEventID++;
|
|
}
|
|
|
|
if(m_State == READING)
|
|
{
|
|
GetFrameRecord().back().drawcallList = m_ParentDrawcall.Bake();
|
|
|
|
m_ParentDrawcall.children.clear();
|
|
}
|
|
|
|
// VKTODOMED See above
|
|
//GetResourceManager()->MarkInFrame(false);
|
|
|
|
m_State = READING;
|
|
}
|
|
|
|
void WrappedVulkan::ContextProcessChunk(uint64_t offset, VulkanChunkType chunk, bool forceExecute)
|
|
{
|
|
m_CurChunkOffset = offset;
|
|
|
|
uint64_t cOffs = m_pSerialiser->GetOffset();
|
|
|
|
WrappedVulkan *context = this;
|
|
|
|
LogState state = context->m_State;
|
|
|
|
if(forceExecute)
|
|
context->m_State = EXECUTING;
|
|
else
|
|
context->m_State = m_State;
|
|
|
|
m_AddedDrawcall = false;
|
|
|
|
ProcessChunk(offset, chunk);
|
|
|
|
m_pSerialiser->PopContext(NULL, chunk);
|
|
|
|
if(context->m_State == READING && chunk == SET_MARKER)
|
|
{
|
|
// no push/pop necessary
|
|
}
|
|
else if(context->m_State == READING && chunk == BEGIN_EVENT)
|
|
{
|
|
// push down the drawcallstack to the latest drawcall
|
|
context->m_DrawcallStack.push_back(&context->m_DrawcallStack.back()->children.back());
|
|
}
|
|
else if(context->m_State == READING && chunk == BEGIN_CMD_BUFFER)
|
|
{
|
|
DrawcallTreeNode *draw = new DrawcallTreeNode;
|
|
|
|
RDCASSERT(m_LastCmdBufferID != ResourceId());
|
|
m_CmdBufferInfo[m_LastCmdBufferID].draw = draw;
|
|
|
|
context->m_DrawcallStack.push_back(draw);
|
|
}
|
|
else if(context->m_State == READING && (chunk == END_EVENT || chunk == END_CMD_BUFFER))
|
|
{
|
|
// refuse to pop off further than the root drawcall (mismatched begin/end events e.g.)
|
|
RDCASSERT(context->m_DrawcallStack.size() > 1);
|
|
if(context->m_DrawcallStack.size() > 1)
|
|
context->m_DrawcallStack.pop_back();
|
|
}
|
|
else if(context->m_State == READING)
|
|
{
|
|
if(!m_AddedDrawcall)
|
|
context->AddEvent(chunk, m_pSerialiser->GetDebugStr());
|
|
}
|
|
|
|
m_AddedDrawcall = false;
|
|
|
|
if(forceExecute)
|
|
context->m_State = state;
|
|
}
|
|
|
|
bool WrappedVulkan::Serialise_vkCmdDrawIndexed(
|
|
VkCmdBuffer cmdBuffer,
|
|
uint32_t firstIndex,
|
|
uint32_t indexCount,
|
|
int32_t vertexOffset,
|
|
uint32_t firstInstance,
|
|
uint32_t instanceCount)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, cmdid, GetResourceManager()->GetID(MakeRes(cmdBuffer)));
|
|
SERIALISE_ELEMENT(uint32_t, firstIdx, firstIndex);
|
|
SERIALISE_ELEMENT(uint32_t, idxCount, indexCount);
|
|
SERIALISE_ELEMENT(int32_t, vtxOffs, vertexOffset);
|
|
SERIALISE_ELEMENT(uint32_t, firstInst, firstInstance);
|
|
SERIALISE_ELEMENT(uint32_t, instCount, instanceCount);
|
|
|
|
if(m_State == EXECUTING)
|
|
{
|
|
// VKTODOHIGH check if we want to partial-replay this cmd buffer
|
|
}
|
|
else if(m_State == READING)
|
|
{
|
|
VkCmdBuffer buf = (VkCmdBuffer)GetResourceManager()->GetLiveResource(cmdid).handle;
|
|
|
|
m_Real.vkCmdDrawIndexed(buf, firstIdx, idxCount, vtxOffs, firstInst, instCount);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void WrappedVulkan::vkCmdDrawIndexed(
|
|
VkCmdBuffer cmdBuffer,
|
|
uint32_t firstIndex,
|
|
uint32_t indexCount,
|
|
int32_t vertexOffset,
|
|
uint32_t firstInstance,
|
|
uint32_t instanceCount)
|
|
{
|
|
m_Real.vkCmdDrawIndexed(cmdBuffer, firstIndex, indexCount, vertexOffset, firstInstance, instanceCount);
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
VkResourceRecord *record = GetResourceManager()->GetResourceRecord(MakeRes(cmdBuffer));
|
|
|
|
SCOPED_SERIALISE_CONTEXT(DRAW_INDEXED);
|
|
Serialise_vkCmdDrawIndexed(cmdBuffer, firstIndex, indexCount, vertexOffset, firstInstance, instanceCount);
|
|
|
|
record->AddChunk(scope.Get());
|
|
}
|
|
}
|
|
|
|
bool WrappedVulkan::Serialise_vkCmdDrawIndirect(
|
|
VkCmdBuffer cmdBuffer,
|
|
VkBuffer buffer,
|
|
VkDeviceSize offset,
|
|
uint32_t count,
|
|
uint32_t stride)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, cmdid, GetResourceManager()->GetID(MakeRes(cmdBuffer)));
|
|
SERIALISE_ELEMENT(ResourceId, bufid, GetResourceManager()->GetID(MakeRes(buffer)));
|
|
SERIALISE_ELEMENT(uint64_t, offs, offset);
|
|
|
|
SERIALISE_ELEMENT(uint32_t, cnt, count);
|
|
SERIALISE_ELEMENT(uint32_t, strd, stride);
|
|
|
|
if(m_State == EXECUTING)
|
|
{
|
|
// VKTODOHIGH check if we want to partial-replay this cmd buffer
|
|
}
|
|
else if(m_State == READING)
|
|
{
|
|
cmdBuffer = (VkCmdBuffer)GetResourceManager()->GetLiveResource(cmdid).handle;
|
|
buffer = (VkBuffer)GetResourceManager()->GetLiveResource(bufid).handle;
|
|
|
|
m_Real.vkCmdDrawIndirect(cmdBuffer, buffer, offs, cnt, strd);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void WrappedVulkan::vkCmdDrawIndirect(
|
|
VkCmdBuffer cmdBuffer,
|
|
VkBuffer buffer,
|
|
VkDeviceSize offset,
|
|
uint32_t count,
|
|
uint32_t stride)
|
|
{
|
|
m_Real.vkCmdDrawIndirect(cmdBuffer, buffer, offset, count, stride);
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
VkResourceRecord *record = GetResourceManager()->GetResourceRecord(MakeRes(cmdBuffer));
|
|
|
|
SCOPED_SERIALISE_CONTEXT(DRAW_INDIRECT);
|
|
Serialise_vkCmdDrawIndirect(cmdBuffer, buffer, offset, count, stride);
|
|
|
|
record->AddChunk(scope.Get());
|
|
}
|
|
}
|
|
|
|
bool WrappedVulkan::Serialise_vkCmdDrawIndexedIndirect(
|
|
VkCmdBuffer cmdBuffer,
|
|
VkBuffer buffer,
|
|
VkDeviceSize offset,
|
|
uint32_t count,
|
|
uint32_t stride)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, cmdid, GetResourceManager()->GetID(MakeRes(cmdBuffer)));
|
|
SERIALISE_ELEMENT(ResourceId, bufid, GetResourceManager()->GetID(MakeRes(buffer)));
|
|
SERIALISE_ELEMENT(uint64_t, offs, offset);
|
|
|
|
SERIALISE_ELEMENT(uint32_t, cnt, count);
|
|
SERIALISE_ELEMENT(uint32_t, strd, stride);
|
|
|
|
if(m_State == EXECUTING)
|
|
{
|
|
// VKTODOHIGH check if we want to partial-replay this cmd buffer
|
|
}
|
|
else if(m_State == READING)
|
|
{
|
|
cmdBuffer = (VkCmdBuffer)GetResourceManager()->GetLiveResource(cmdid).handle;
|
|
buffer = (VkBuffer)GetResourceManager()->GetLiveResource(bufid).handle;
|
|
|
|
m_Real.vkCmdDrawIndexedIndirect(cmdBuffer, buffer, offs, cnt, strd);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void WrappedVulkan::vkCmdDrawIndexedIndirect(
|
|
VkCmdBuffer cmdBuffer,
|
|
VkBuffer buffer,
|
|
VkDeviceSize offset,
|
|
uint32_t count,
|
|
uint32_t stride)
|
|
{
|
|
m_Real.vkCmdDrawIndexedIndirect(cmdBuffer, buffer, offset, count, stride);
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
VkResourceRecord *record = GetResourceManager()->GetResourceRecord(MakeRes(cmdBuffer));
|
|
|
|
SCOPED_SERIALISE_CONTEXT(DRAW_INDEXED_INDIRECT);
|
|
Serialise_vkCmdDrawIndexedIndirect(cmdBuffer, buffer, offset, count, stride);
|
|
|
|
record->AddChunk(scope.Get());
|
|
}
|
|
}
|
|
|
|
bool WrappedVulkan::Serialise_vkCmdDispatch(
|
|
VkCmdBuffer cmdBuffer,
|
|
uint32_t x,
|
|
uint32_t y,
|
|
uint32_t z)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, cmdid, GetResourceManager()->GetID(MakeRes(cmdBuffer)));
|
|
SERIALISE_ELEMENT(uint32_t, X, x);
|
|
SERIALISE_ELEMENT(uint32_t, Y, y);
|
|
SERIALISE_ELEMENT(uint32_t, Z, z);
|
|
|
|
if(m_State == EXECUTING)
|
|
{
|
|
// VKTODOHIGH check if we want to partial-replay this cmd buffer
|
|
}
|
|
else if(m_State == READING)
|
|
{
|
|
cmdBuffer = (VkCmdBuffer)GetResourceManager()->GetLiveResource(cmdid).handle;
|
|
|
|
m_Real.vkCmdDispatch(cmdBuffer, X, Y, Z);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void WrappedVulkan::vkCmdDispatch(
|
|
VkCmdBuffer cmdBuffer,
|
|
uint32_t x,
|
|
uint32_t y,
|
|
uint32_t z)
|
|
{
|
|
m_Real.vkCmdDispatch(cmdBuffer, x, y, z);
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
VkResourceRecord *record = GetResourceManager()->GetResourceRecord(MakeRes(cmdBuffer));
|
|
|
|
SCOPED_SERIALISE_CONTEXT(DISPATCH);
|
|
Serialise_vkCmdDispatch(cmdBuffer, x, y, z);
|
|
|
|
record->AddChunk(scope.Get());
|
|
}
|
|
}
|
|
|
|
bool WrappedVulkan::Serialise_vkCmdDispatchIndirect(
|
|
VkCmdBuffer cmdBuffer,
|
|
VkBuffer buffer,
|
|
VkDeviceSize offset)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, cmdid, GetResourceManager()->GetID(MakeRes(cmdBuffer)));
|
|
SERIALISE_ELEMENT(ResourceId, bufid, GetResourceManager()->GetID(MakeRes(buffer)));
|
|
SERIALISE_ELEMENT(uint64_t, offs, offset);
|
|
|
|
if(m_State == EXECUTING)
|
|
{
|
|
// VKTODOHIGH check if we want to partial-replay this cmd buffer
|
|
}
|
|
else if(m_State == READING)
|
|
{
|
|
cmdBuffer = (VkCmdBuffer)GetResourceManager()->GetLiveResource(cmdid).handle;
|
|
buffer = (VkBuffer)GetResourceManager()->GetLiveResource(bufid).handle;
|
|
|
|
m_Real.vkCmdDispatchIndirect(cmdBuffer, buffer, offs);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void WrappedVulkan::vkCmdDispatchIndirect(
|
|
VkCmdBuffer cmdBuffer,
|
|
VkBuffer buffer,
|
|
VkDeviceSize offset)
|
|
{
|
|
m_Real.vkCmdDispatchIndirect(cmdBuffer, buffer, offset);
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
VkResourceRecord *record = GetResourceManager()->GetResourceRecord(MakeRes(cmdBuffer));
|
|
|
|
SCOPED_SERIALISE_CONTEXT(DISPATCH_INDIRECT);
|
|
Serialise_vkCmdDispatchIndirect(cmdBuffer, buffer, offset);
|
|
|
|
record->AddChunk(scope.Get());
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
// WSI extension
|
|
|
|
VkResult WrappedVulkan::vkGetPhysicalDeviceSurfaceSupportWSI(
|
|
VkPhysicalDevice physicalDevice,
|
|
uint32_t queueFamilyIndex,
|
|
const VkSurfaceDescriptionWSI* pSurfaceDescription,
|
|
VkBool32* pSupported)
|
|
{
|
|
return m_Real.vkGetPhysicalDeviceSurfaceSupportWSI(physicalDevice, queueFamilyIndex, pSurfaceDescription, pSupported);
|
|
}
|
|
|
|
VkResult WrappedVulkan::vkGetSurfaceInfoWSI(
|
|
VkDevice device,
|
|
const VkSurfaceDescriptionWSI* pSurfaceDescription,
|
|
VkSurfaceInfoTypeWSI infoType,
|
|
size_t* pDataSize,
|
|
void* pData)
|
|
{
|
|
return m_Real.vkGetSurfaceInfoWSI(device, pSurfaceDescription, infoType, pDataSize, pData);
|
|
}
|
|
|
|
bool WrappedVulkan::Serialise_vkGetSwapChainInfoWSI(
|
|
VkDevice device,
|
|
VkSwapChainWSI swapChain,
|
|
VkSwapChainInfoTypeWSI infoType,
|
|
size_t* pDataSize,
|
|
void* pData)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, devId, GetResourceManager()->GetID(MakeRes(device)));
|
|
SERIALISE_ELEMENT(ResourceId, swapId, GetResourceManager()->GetID(MakeRes(swapChain)));
|
|
VkSwapChainImagePropertiesWSI *image = (VkSwapChainImagePropertiesWSI *)pData;
|
|
SERIALISE_ELEMENT(size_t, idx, *pDataSize);
|
|
SERIALISE_ELEMENT(ResourceId, id, GetResourceManager()->GetID(MakeRes(image->image)));
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
RDCASSERT(infoType == VK_SWAP_CHAIN_INFO_TYPE_IMAGES_WSI);
|
|
}
|
|
|
|
if(m_State == READING)
|
|
{
|
|
// VKTODOLOW what if num images is less than on capture?
|
|
RDCASSERT(idx < m_SwapChainInfo[swapId].images.size());
|
|
VkImage im = m_SwapChainInfo[swapId].images[idx].im;
|
|
|
|
GetResourceManager()->AddLiveResource(id, MakeRes(im));
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
VkResult WrappedVulkan::vkGetSwapChainInfoWSI(
|
|
VkDevice device,
|
|
VkSwapChainWSI swapChain,
|
|
VkSwapChainInfoTypeWSI infoType,
|
|
size_t* pDataSize,
|
|
void* pData)
|
|
{
|
|
// make sure we always get the size
|
|
size_t dummySize = 0;
|
|
if(pDataSize == NULL)
|
|
pDataSize = &dummySize;
|
|
|
|
VkResult ret = m_Real.vkGetSwapChainInfoWSI(device, swapChain, infoType, pDataSize, pData);
|
|
|
|
if(infoType == VK_SWAP_CHAIN_INFO_TYPE_IMAGES_WSI && pData && m_State >= WRITING)
|
|
{
|
|
VkSwapChainImagePropertiesWSI *images = (VkSwapChainImagePropertiesWSI *)pData;
|
|
size_t numImages = (*pDataSize)/sizeof(VkSwapChainImagePropertiesWSI);
|
|
|
|
for(size_t i=0; i < numImages; i++)
|
|
{
|
|
VkResource res = MakeRes(images[i].image);
|
|
|
|
// already registered
|
|
if(GetResourceManager()->GetID(res) != ResourceId())
|
|
continue;
|
|
|
|
ResourceId id = GetResourceManager()->RegisterResource(res);
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
Chunk *chunk = NULL;
|
|
|
|
{
|
|
SCOPED_SERIALISE_CONTEXT(PRESENT_IMAGE);
|
|
Serialise_vkGetSwapChainInfoWSI(device, swapChain, infoType, &i, (void *)&images[i]);
|
|
|
|
chunk = scope.Get();
|
|
}
|
|
|
|
VkResourceRecord *record = GetResourceManager()->AddResourceRecord(id);
|
|
record->AddChunk(chunk);
|
|
|
|
// we invert the usual scheme - we make the swapchain record take parent refs
|
|
// on these images, so that we can just ref the swapchain on present and pull
|
|
// in all the images
|
|
GetResourceManager()->GetResourceRecord(MakeRes(swapChain))->AddParent(record);
|
|
}
|
|
else
|
|
{
|
|
GetResourceManager()->AddLiveResource(id, res);
|
|
}
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
VkResult WrappedVulkan::vkAcquireNextImageWSI(
|
|
VkDevice device,
|
|
VkSwapChainWSI swapChain,
|
|
uint64_t timeout,
|
|
VkSemaphore semaphore,
|
|
uint32_t* pImageIndex)
|
|
{
|
|
// VKTODOLOW: does this need to be intercepted/serialised?
|
|
return m_Real.vkAcquireNextImageWSI(device, swapChain, timeout, semaphore, pImageIndex);
|
|
}
|
|
|
|
bool WrappedVulkan::Serialise_vkCreateSwapChainWSI(
|
|
VkDevice device,
|
|
const VkSwapChainCreateInfoWSI* pCreateInfo,
|
|
VkSwapChainWSI* pSwapChain)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, devId, GetResourceManager()->GetID(MakeRes(device)));
|
|
SERIALISE_ELEMENT(VkSwapChainCreateInfoWSI, info, *pCreateInfo);
|
|
SERIALISE_ELEMENT(ResourceId, id, GetResourceManager()->GetID(MakeRes(*pSwapChain)));
|
|
|
|
VkFormat fmt = VK_FORMAT_UNDEFINED;
|
|
uint32_t numIms = 0;
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
VkResult res = VK_SUCCESS;
|
|
|
|
size_t swapChainImagesSize;
|
|
res = m_Real.vkGetSwapChainInfoWSI(device, *pSwapChain, VK_SWAP_CHAIN_INFO_TYPE_IMAGES_WSI, &swapChainImagesSize, NULL);
|
|
RDCASSERT(res == VK_SUCCESS);
|
|
|
|
numIms = uint32_t(swapChainImagesSize/sizeof(VkSwapChainImagePropertiesWSI));
|
|
|
|
fmt = VK_FORMAT_B8G8R8A8_UNORM;
|
|
|
|
// VKTODOMED: need to get proper formats - needs surface description
|
|
/*
|
|
size_t formatsSize;
|
|
res = m_Real.vkGetSurfaceInfoWSI(device, (VkSurfaceDescriptionWSI *), VK_SURFACE_INFO_TYPE_FORMATS_WSI, &formatsSize, NULL);
|
|
RDCASSERT(res == VK_SUCCESS);
|
|
VkSurfaceFormatPropertiesWSI *surfFormats = (VkSurfaceFormatPropertiesWSI *)malloc(formatsSize);
|
|
res = m_Real.vkGetSurfaceInfoWSI(demo->device, (VkSurfaceDescriptionWSI *) , VK_SURFACE_INFO_TYPE_FORMATS_WSI, &formatsSize, surfFormats);
|
|
RDCASSERT(res == VK_SUCCESS);
|
|
*/
|
|
}
|
|
|
|
SERIALISE_ELEMENT(VkFormat, imFormat, fmt);
|
|
SERIALISE_ELEMENT(uint32_t, numSwapImages, numIms);
|
|
|
|
m_SwapChainInfo[id].format = imFormat;
|
|
m_SwapChainInfo[id].extent = info.imageExtent;
|
|
m_SwapChainInfo[id].arraySize = info.imageArraySize;
|
|
|
|
m_SwapChainInfo[id].images.resize(numSwapImages);
|
|
|
|
if(m_State == READING)
|
|
{
|
|
RDCASSERT(imFormat == info.imageFormat);
|
|
|
|
VkDevice dev = (VkDevice)GetResourceManager()->GetLiveResource(devId).handle;
|
|
|
|
const VkImageCreateInfo imInfo = {
|
|
/*.sType =*/ VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
|
|
/*.pNext =*/ NULL,
|
|
/*.imageType =*/ VK_IMAGE_TYPE_2D,
|
|
/*.format =*/ imFormat,
|
|
/*.extent =*/ { info.imageExtent.width, info.imageExtent.height, 1 },
|
|
/*.mipLevels =*/ 1,
|
|
/*.arraySize =*/ info.imageArraySize,
|
|
/*.samples =*/ 1,
|
|
/*.tiling =*/ VK_IMAGE_TILING_OPTIMAL,
|
|
/*.usage =*/
|
|
VK_IMAGE_USAGE_TRANSFER_SOURCE_BIT|
|
|
VK_IMAGE_USAGE_TRANSFER_DESTINATION_BIT|
|
|
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT|
|
|
VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT,
|
|
/*.flags =*/ 0,
|
|
};
|
|
|
|
for(size_t i=0; i < m_PhysicalReplayData.size(); i++)
|
|
{
|
|
if(m_PhysicalReplayData[i].dev == dev)
|
|
m_SwapPhysDevice = (int)i;
|
|
}
|
|
|
|
for(uint32_t i=0; i < numSwapImages; i++)
|
|
{
|
|
VkDeviceMemory mem = VK_NULL_HANDLE;
|
|
VkImage im = VK_NULL_HANDLE;
|
|
|
|
VkResult res = m_Real.vkCreateImage(dev, &imInfo, &im);
|
|
RDCASSERT(res == VK_SUCCESS);
|
|
|
|
VkMemoryRequirements mrq = {0};
|
|
|
|
res = m_Real.vkGetImageMemoryRequirements(dev, im, &mrq);
|
|
RDCASSERT(res == VK_SUCCESS);
|
|
|
|
VkMemoryAllocInfo allocInfo = {
|
|
/*.sType =*/ VK_STRUCTURE_TYPE_MEMORY_ALLOC_INFO,
|
|
/*.pNext =*/ NULL,
|
|
/*.allocationSize =*/ mrq.size,
|
|
/*.memoryTypeIndex =*/ 0, // VKTODOHIGH find appropriate memory type index
|
|
};
|
|
|
|
res = m_Real.vkAllocMemory(dev, &allocInfo, &mem);
|
|
RDCASSERT(res == VK_SUCCESS);
|
|
|
|
res = m_Real.vkBindImageMemory(dev, im, mem, 0);
|
|
RDCASSERT(res == VK_SUCCESS);
|
|
|
|
GetResourceManager()->RegisterResource(MakeRes(mem));
|
|
ResourceId liveId = GetResourceManager()->RegisterResource(MakeRes(im));
|
|
|
|
// image live ID will be assigned separately in Serialise_vkGetSwapChainInfoWSI
|
|
// memory doesn't have a live ID
|
|
|
|
m_SwapChainInfo[id].images[i].mem = mem;
|
|
m_SwapChainInfo[id].images[i].im = im;
|
|
|
|
// fill out image info so we track resource state transitions
|
|
m_ImageInfo[liveId].mem = mem;
|
|
m_ImageInfo[liveId].format = imFormat;
|
|
m_ImageInfo[liveId].extent.width = info.imageExtent.width;
|
|
m_ImageInfo[liveId].extent.height = info.imageExtent.height;
|
|
m_ImageInfo[liveId].extent.depth = 1;
|
|
m_ImageInfo[liveId].mipLevels = 1;
|
|
m_ImageInfo[liveId].arraySize = info.imageArraySize;
|
|
|
|
VkImageSubresourceRange range;
|
|
range.baseMipLevel = range.baseArraySlice = 0;
|
|
range.mipLevels = 1;
|
|
range.arraySize = info.imageArraySize;
|
|
range.aspect = VK_IMAGE_ASPECT_COLOR;
|
|
|
|
m_ImageInfo[liveId].subresourceStates.clear();
|
|
m_ImageInfo[liveId].subresourceStates.push_back(ImageRegionState(range, UNTRANSITIONED_IMG_STATE, VK_IMAGE_LAYOUT_UNDEFINED));
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
VkResult WrappedVulkan::vkCreateSwapChainWSI(
|
|
VkDevice device,
|
|
const VkSwapChainCreateInfoWSI* pCreateInfo,
|
|
VkSwapChainWSI* pSwapChain)
|
|
{
|
|
VkResult ret = m_Real.vkCreateSwapChainWSI(device, pCreateInfo, pSwapChain);
|
|
|
|
if(ret == VK_SUCCESS)
|
|
{
|
|
VkResource res = MakeRes(*pSwapChain);
|
|
ResourceId id = GetResourceManager()->RegisterResource(res);
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
Chunk *chunk = NULL;
|
|
|
|
{
|
|
SCOPED_SERIALISE_CONTEXT(CREATE_SWAP_BUFFER);
|
|
Serialise_vkCreateSwapChainWSI(device, pCreateInfo, pSwapChain);
|
|
|
|
chunk = scope.Get();
|
|
}
|
|
|
|
VkResourceRecord *record = GetResourceManager()->AddResourceRecord(id);
|
|
record->AddChunk(chunk);
|
|
|
|
for(size_t i=0; i < m_PhysicalReplayData.size(); i++)
|
|
{
|
|
if(m_PhysicalReplayData[i].dev == device)
|
|
m_SwapPhysDevice = (int)i;
|
|
}
|
|
|
|
// serialise out the swap chain images
|
|
{
|
|
size_t swapChainImagesSize;
|
|
VkResult ret = m_Real.vkGetSwapChainInfoWSI(device, *pSwapChain, VK_SWAP_CHAIN_INFO_TYPE_IMAGES_WSI, &swapChainImagesSize, NULL);
|
|
RDCASSERT(ret == VK_SUCCESS);
|
|
|
|
uint32_t numSwapImages = uint32_t(swapChainImagesSize)/sizeof(VkSwapChainImagePropertiesWSI);
|
|
|
|
VkSwapChainImagePropertiesWSI* images = new VkSwapChainImagePropertiesWSI[numSwapImages];
|
|
|
|
// go through our own function so we assign these images IDs
|
|
ret = vkGetSwapChainInfoWSI(device, *pSwapChain, VK_SWAP_CHAIN_INFO_TYPE_IMAGES_WSI, &swapChainImagesSize, images);
|
|
RDCASSERT(ret == VK_SUCCESS);
|
|
|
|
for(uint32_t i=0; i < numSwapImages; i++)
|
|
{
|
|
// memory doesn't exist for genuine WSI created images
|
|
m_SwapChainInfo[id].images[i].mem = VK_NULL_HANDLE;
|
|
m_SwapChainInfo[id].images[i].im = images[i].image;
|
|
|
|
ResourceId imid = GetResourceManager()->GetID(MakeRes(images[i].image));
|
|
|
|
// fill out image info so we track resource state transitions
|
|
m_ImageInfo[imid].format = pCreateInfo->imageFormat;
|
|
m_ImageInfo[imid].extent.width = pCreateInfo->imageExtent.width;
|
|
m_ImageInfo[imid].extent.height = pCreateInfo->imageExtent.height;
|
|
m_ImageInfo[imid].extent.depth = 1;
|
|
m_ImageInfo[imid].mipLevels = 1;
|
|
m_ImageInfo[imid].arraySize = pCreateInfo->imageArraySize;
|
|
|
|
VkImageSubresourceRange range;
|
|
range.baseMipLevel = range.baseArraySlice = 0;
|
|
range.mipLevels = 1;
|
|
range.arraySize = pCreateInfo->imageArraySize;
|
|
range.aspect = VK_IMAGE_ASPECT_COLOR;
|
|
|
|
m_ImageInfo[imid].subresourceStates.clear();
|
|
m_ImageInfo[imid].subresourceStates.push_back(ImageRegionState(range, UNTRANSITIONED_IMG_STATE, VK_IMAGE_LAYOUT_UNDEFINED));
|
|
}
|
|
|
|
SAFE_DELETE_ARRAY(images);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
GetResourceManager()->AddLiveResource(id, res);
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
VkResult WrappedVulkan::vkQueuePresentWSI(
|
|
VkQueue queue,
|
|
VkPresentInfoWSI* pPresentInfo)
|
|
{
|
|
VkResult ret = m_Real.vkQueuePresentWSI(queue, pPresentInfo);
|
|
|
|
if(ret != VK_SUCCESS || pPresentInfo->swapChainCount == 0)
|
|
return ret;
|
|
|
|
RenderDoc::Inst().SetCurrentDriver(RDC_Vulkan);
|
|
|
|
if(m_State == WRITING_IDLE)
|
|
RenderDoc::Inst().Tick();
|
|
|
|
m_FrameCounter++; // first present becomes frame #1, this function is at the end of the frame
|
|
|
|
if(pPresentInfo->swapChainCount > 1 && (m_FrameCounter % 100) == 0)
|
|
{
|
|
RDCWARN("Presenting multiple swapchains at once - only first will be processed");
|
|
}
|
|
|
|
if(m_State == WRITING_IDLE)
|
|
{
|
|
m_FrameTimes.push_back(m_FrameTimer.GetMilliseconds());
|
|
m_TotalTime += m_FrameTimes.back();
|
|
m_FrameTimer.Restart();
|
|
|
|
// update every second
|
|
if(m_TotalTime > 1000.0)
|
|
{
|
|
m_MinFrametime = 10000.0;
|
|
m_MaxFrametime = 0.0;
|
|
m_AvgFrametime = 0.0;
|
|
|
|
m_TotalTime = 0.0;
|
|
|
|
for(size_t i=0; i < m_FrameTimes.size(); i++)
|
|
{
|
|
m_AvgFrametime += m_FrameTimes[i];
|
|
if(m_FrameTimes[i] < m_MinFrametime)
|
|
m_MinFrametime = m_FrameTimes[i];
|
|
if(m_FrameTimes[i] > m_MaxFrametime)
|
|
m_MaxFrametime = m_FrameTimes[i];
|
|
}
|
|
|
|
m_AvgFrametime /= double(m_FrameTimes.size());
|
|
|
|
m_FrameTimes.clear();
|
|
|
|
RDCLOG("Frame: %d. F12/PrtScr to capture. %.2lf ms (%.2lf .. %.2lf) (%.0lf FPS)",
|
|
m_FrameCounter, m_AvgFrametime, m_MinFrametime, m_MaxFrametime, 1000.0f/m_AvgFrametime);
|
|
for(size_t i=0; i < m_FrameRecord.size(); i++)
|
|
RDCLOG("Captured Frame %d. Multiple frame capture not supported.\n", m_FrameRecord[i].frameInfo.frameNumber);
|
|
#if !defined(RELEASE)
|
|
RDCLOG("%llu chunks - %.2f MB", Chunk::NumLiveChunks(), float(Chunk::TotalMem())/1024.0f/1024.0f);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
// kill any current capture
|
|
if(m_State == WRITING_CAPFRAME)
|
|
{
|
|
//if(HasSuccessfulCapture())
|
|
{
|
|
RDCLOG("Finished capture, Frame %u", m_FrameCounter);
|
|
|
|
ResourceId swapid = GetResourceManager()->GetID(MakeRes(pPresentInfo->swapChains[0]));
|
|
|
|
GetResourceManager()->MarkResourceFrameReferenced(swapid, eFrameRef_Read);
|
|
|
|
// VKTODOLOW handle present info pNext
|
|
RDCASSERT(pPresentInfo->pNext == NULL);
|
|
|
|
VkImage backbuffer = m_SwapChainInfo[swapid].images[pPresentInfo->imageIndices[0]].im;
|
|
|
|
EndCaptureFrame(backbuffer);
|
|
FinishCapture();
|
|
|
|
Serialiser *m_pFileSerialiser = RenderDoc::Inst().OpenWriteSerialiser(m_FrameCounter, &m_InitParams, NULL, 0, 0, 0);
|
|
|
|
{
|
|
SCOPED_SERIALISE_CONTEXT(DEVICE_INIT);
|
|
|
|
SERIALISE_ELEMENT(ResourceId, immContextId, m_ContextResourceID);
|
|
|
|
m_pFileSerialiser->Insert(scope.Get(true));
|
|
}
|
|
|
|
RDCDEBUG("Inserting Resource Serialisers");
|
|
|
|
GetResourceManager()->InsertReferencedChunks(m_pFileSerialiser);
|
|
|
|
GetResourceManager()->InsertInitialContentsChunks(m_pFileSerialiser);
|
|
|
|
RDCDEBUG("Creating Capture Scope");
|
|
|
|
{
|
|
SCOPED_SERIALISE_CONTEXT(CAPTURE_SCOPE);
|
|
|
|
Serialise_CaptureScope(0);
|
|
|
|
m_pFileSerialiser->Insert(scope.Get(true));
|
|
}
|
|
|
|
{
|
|
RDCDEBUG("Getting Resource Record");
|
|
|
|
VkResourceRecord *record = GetResourceManager()->GetResourceRecord(m_ContextResourceID);
|
|
|
|
RDCDEBUG("Accumulating context resource list");
|
|
|
|
map<int32_t, Chunk *> recordlist;
|
|
record->Insert(recordlist);
|
|
|
|
RDCDEBUG("Flushing %u records to file serialiser", (uint32_t)recordlist.size());
|
|
|
|
for(auto it = recordlist.begin(); it != recordlist.end(); ++it)
|
|
m_pFileSerialiser->Insert(it->second);
|
|
|
|
RDCDEBUG("Done");
|
|
}
|
|
|
|
m_CurFileSize += m_pFileSerialiser->FlushToDisk();
|
|
|
|
RenderDoc::Inst().SuccessfullyWrittenLog();
|
|
|
|
SAFE_DELETE(m_pFileSerialiser);
|
|
|
|
m_State = WRITING_IDLE;
|
|
|
|
GetResourceManager()->MarkUnwrittenResources();
|
|
|
|
GetResourceManager()->ClearReferencedResources();
|
|
}
|
|
}
|
|
|
|
if(RenderDoc::Inst().ShouldTriggerCapture(m_FrameCounter) && m_State == WRITING_IDLE && m_FrameRecord.empty())
|
|
{
|
|
m_State = WRITING_CAPFRAME;
|
|
|
|
FetchFrameRecord record;
|
|
record.frameInfo.frameNumber = m_FrameCounter+1;
|
|
m_FrameRecord.push_back(record);
|
|
|
|
GetResourceManager()->ClearReferencedResources();
|
|
|
|
GetResourceManager()->MarkResourceFrameReferenced(m_InstanceRecord->GetResourceID(), eFrameRef_Read);
|
|
GetResourceManager()->PrepareInitialContents();
|
|
|
|
AttemptCapture();
|
|
BeginCaptureFrame();
|
|
|
|
RDCLOG("Starting capture, frame %u", m_FrameCounter);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool WrappedVulkan::Prepare_InitialState(VkResource res)
|
|
{
|
|
ResourceId id = GetResourceManager()->GetID(res);
|
|
|
|
RDCLOG("Prepare_InitialState %llu", id);
|
|
|
|
if(res.Namespace == eResDescriptorSet)
|
|
{
|
|
RDCUNIMPLEMENTED("descriptor set initial states not implemented");
|
|
|
|
// VKTODOHIGH: need to figure out the format/serialisation of these
|
|
return true;
|
|
}
|
|
else if(res.Namespace == eResDeviceMemory)
|
|
{
|
|
if(m_MemoryInfo.find(id) == m_MemoryInfo.end())
|
|
{
|
|
RDCERR("Couldn't find memory info");
|
|
return false;
|
|
}
|
|
|
|
MemState &meminfo = m_MemoryInfo[id];
|
|
|
|
VkResult vkr = VK_SUCCESS;
|
|
|
|
VkDevice d = GetDev();
|
|
VkQueue q = GetQ();
|
|
VkCmdBuffer cmd = GetCmd();
|
|
|
|
VkDeviceMemory mem = VK_NULL_HANDLE;
|
|
|
|
VkMemoryAllocInfo allocInfo = {
|
|
/*.sType =*/ VK_STRUCTURE_TYPE_MEMORY_ALLOC_INFO,
|
|
/*.pNext =*/ NULL,
|
|
/*.allocationSize =*/ meminfo.size,
|
|
/*.memoryTypeIndex =*/ 0,
|
|
};
|
|
// VKTODOHIGH memory type index needs to be host-visible for copy back
|
|
|
|
vkr = m_Real.vkAllocMemory(d, &allocInfo, &mem);
|
|
RDCASSERT(vkr == VK_SUCCESS);
|
|
|
|
VkCmdBufferBeginInfo beginInfo = { VK_STRUCTURE_TYPE_CMD_BUFFER_BEGIN_INFO, NULL, VK_CMD_BUFFER_OPTIMIZE_SMALL_BATCH_BIT | VK_CMD_BUFFER_OPTIMIZE_ONE_TIME_SUBMIT_BIT };
|
|
|
|
vkr = m_Real.vkBeginCommandBuffer(cmd, &beginInfo);
|
|
RDCASSERT(vkr == VK_SUCCESS);
|
|
|
|
VkBufferCreateInfo bufInfo = {
|
|
VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, NULL,
|
|
meminfo.size, VK_BUFFER_USAGE_GENERAL, 0,
|
|
VK_SHARING_MODE_EXCLUSIVE, 0, NULL,
|
|
};
|
|
|
|
VkBuffer srcBuf, dstBuf;
|
|
|
|
vkr = m_Real.vkCreateBuffer(d, &bufInfo, &srcBuf);
|
|
RDCASSERT(vkr == VK_SUCCESS);
|
|
vkr = m_Real.vkCreateBuffer(d, &bufInfo, &dstBuf);
|
|
RDCASSERT(vkr == VK_SUCCESS);
|
|
|
|
vkr = m_Real.vkBindBufferMemory(d, srcBuf, (VkDeviceMemory)res.handle, 0);
|
|
RDCASSERT(vkr == VK_SUCCESS);
|
|
vkr = m_Real.vkBindBufferMemory(d, dstBuf, mem, 0);
|
|
RDCASSERT(vkr == VK_SUCCESS);
|
|
|
|
VkBufferCopy region = { 0, 0, meminfo.size };
|
|
|
|
m_Real.vkCmdCopyBuffer(cmd, srcBuf, dstBuf, 1, ®ion);
|
|
|
|
vkr = m_Real.vkEndCommandBuffer(cmd);
|
|
RDCASSERT(vkr == VK_SUCCESS);
|
|
|
|
vkr = m_Real.vkQueueSubmit(q, 1, &cmd, VK_NULL_HANDLE);
|
|
RDCASSERT(vkr == VK_SUCCESS);
|
|
|
|
// VKTODOMED would be nice to store a fence too at this point
|
|
// so we can sync on that on serialise rather than syncing
|
|
// every time.
|
|
m_Real.vkQueueWaitIdle(q);
|
|
|
|
m_Real.vkDestroyBuffer(d, srcBuf);
|
|
m_Real.vkDestroyBuffer(d, dstBuf);
|
|
|
|
GetResourceManager()->SetInitialContents(id, VulkanResourceManager::InitialContentData(MakeRes(mem), (uint32_t)meminfo.size, NULL));
|
|
|
|
return true;
|
|
}
|
|
else if(res.Namespace == eResImage)
|
|
{
|
|
RDCUNIMPLEMENTED("image initial states not implemented");
|
|
|
|
if(m_ImageInfo.find(id) == m_ImageInfo.end())
|
|
{
|
|
RDCERR("Couldn't find image info");
|
|
return false;
|
|
}
|
|
|
|
// VKTODOHIGH: need to copy off contents to memory somewhere else
|
|
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
RDCERR("Unhandled resource type %d", res.Namespace);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool WrappedVulkan::Serialise_InitialState(VkResource res)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, id, GetResourceManager()->GetID(res));
|
|
|
|
if(m_State < WRITING) res = GetResourceManager()->GetLiveResource(id);
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
VulkanResourceManager::InitialContentData initContents = GetResourceManager()->GetInitialContents(id);
|
|
|
|
if(res.Namespace == eResDescriptorSet)
|
|
{
|
|
RDCUNIMPLEMENTED("descriptor set initial states not implemented");
|
|
|
|
// VKTODOHIGH: need to figure out the format/serialisation of these
|
|
}
|
|
else if(res.Namespace == eResImage || res.Namespace == eResDeviceMemory)
|
|
{
|
|
VkDevice d = GetDev();
|
|
|
|
byte *ptr = NULL;
|
|
m_Real.vkMapMemory(d, (VkDeviceMemory)initContents.resource.handle, 0, 0, 0, (void **)&ptr);
|
|
|
|
size_t dataSize = (size_t)initContents.num;
|
|
|
|
m_pSerialiser->SerialiseBuffer("data", ptr, dataSize);
|
|
|
|
m_Real.vkUnmapMemory(d, (VkDeviceMemory)initContents.resource.handle);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(res.Namespace == eResDescriptorSet)
|
|
{
|
|
RDCUNIMPLEMENTED("Descriptor set initial states not implemented");
|
|
}
|
|
else if(res.Namespace == eResImage || res.Namespace == eResDeviceMemory)
|
|
{
|
|
byte *data = NULL;
|
|
size_t dataSize = 0;
|
|
m_pSerialiser->SerialiseBuffer("data", data, dataSize);
|
|
|
|
VkResult vkr = VK_SUCCESS;
|
|
|
|
VkDevice d = GetDev();
|
|
|
|
VkDeviceMemory mem = VK_NULL_HANDLE;
|
|
|
|
VkMemoryAllocInfo allocInfo = {
|
|
/*.sType =*/ VK_STRUCTURE_TYPE_MEMORY_ALLOC_INFO,
|
|
/*.pNext =*/ NULL,
|
|
/*.allocationSize =*/ dataSize,
|
|
/*.memoryTypeIndex =*/ 0,
|
|
};
|
|
// VKTODOHIGH memory type index needs to be host-visible for copy
|
|
|
|
vkr = m_Real.vkAllocMemory(d, &allocInfo, &mem);
|
|
RDCASSERT(vkr == VK_SUCCESS);
|
|
|
|
VkBufferCreateInfo bufInfo = {
|
|
VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, NULL,
|
|
dataSize, VK_BUFFER_USAGE_GENERAL, 0,
|
|
VK_SHARING_MODE_EXCLUSIVE, 0, NULL,
|
|
};
|
|
|
|
VkBuffer buf;
|
|
|
|
vkr = m_Real.vkCreateBuffer(d, &bufInfo, &buf);
|
|
RDCASSERT(vkr == VK_SUCCESS);
|
|
|
|
vkr = m_Real.vkBindBufferMemory(d, buf, mem, 0);
|
|
RDCASSERT(vkr == VK_SUCCESS);
|
|
|
|
byte *ptr = NULL;
|
|
m_Real.vkMapMemory(d, mem, 0, 0, 0, (void **)&ptr);
|
|
|
|
// VKTODOLOW could deserialise directly into this ptr if we serialised
|
|
// size separately.
|
|
memcpy(ptr, data, dataSize);
|
|
|
|
m_Real.vkUnmapMemory(d, mem);
|
|
|
|
// VKTODOMED leaking the memory here! needs to be cleaned up with the buffer
|
|
GetResourceManager()->SetInitialContents(id, VulkanResourceManager::InitialContentData(MakeRes(buf), eInitialContents_Copy, NULL));
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void WrappedVulkan::Create_InitialState(ResourceId id, VkResource live, bool hasData)
|
|
{
|
|
if(live.Namespace == eResDescriptorSet)
|
|
{
|
|
RDCERR("Unexpected attempt to create initial state for descriptor set");
|
|
}
|
|
else if(live.Namespace == eResImage)
|
|
{
|
|
RDCUNIMPLEMENTED("image initial states not implemented");
|
|
|
|
if(m_ImageInfo.find(id) == m_ImageInfo.end())
|
|
{
|
|
RDCERR("Couldn't find image info");
|
|
return;
|
|
}
|
|
|
|
VkResource z(MakeNullResource);
|
|
|
|
ImgState &img = m_ImageInfo[id];
|
|
|
|
if(img.subresourceStates[0].range.aspect == VK_IMAGE_ASPECT_COLOR)
|
|
GetResourceManager()->SetInitialContents(id, VulkanResourceManager::InitialContentData(z, eInitialContents_ClearColorImage, NULL));
|
|
else
|
|
GetResourceManager()->SetInitialContents(id, VulkanResourceManager::InitialContentData(z, eInitialContents_ClearDepthStencilImage, NULL));
|
|
}
|
|
else if(live.Namespace == eResDeviceMemory)
|
|
{
|
|
RDCERR("Unexpected attempt to create initial state for memory");
|
|
}
|
|
else if(live.Namespace == eResFramebuffer)
|
|
{
|
|
RDCWARN("Framebuffer without initial state! should clear all attachments");
|
|
}
|
|
else
|
|
{
|
|
RDCERR("Unhandled resource type %d", live.Namespace);
|
|
}
|
|
}
|
|
|
|
void WrappedVulkan::Apply_InitialState(VkResource live, VulkanResourceManager::InitialContentData initial)
|
|
{
|
|
if(live.Namespace == eResDescriptorSet)
|
|
{
|
|
// VKTODOHIGH: need to figure out the format/serialisation of these
|
|
RDCUNIMPLEMENTED("descriptor set initial states not implemented");
|
|
}
|
|
else if(live.Namespace == eResDeviceMemory)
|
|
{
|
|
ResourceId id = GetResourceManager()->GetID(live);
|
|
|
|
if(m_MemoryInfo.find(id) == m_MemoryInfo.end())
|
|
{
|
|
RDCERR("Couldn't find memory info");
|
|
return;
|
|
}
|
|
|
|
MemState &meminfo = m_MemoryInfo[id];
|
|
|
|
VkBuffer srcBuf = (VkBuffer)initial.resource.handle;
|
|
VkDeviceMemory dstMem = (VkDeviceMemory)live.handle;
|
|
|
|
VkResult vkr = VK_SUCCESS;
|
|
|
|
VkDevice d = GetDev();
|
|
VkQueue q = GetQ();
|
|
VkCmdBuffer cmd = GetCmd();
|
|
|
|
VkCmdBufferBeginInfo beginInfo = { VK_STRUCTURE_TYPE_CMD_BUFFER_BEGIN_INFO, NULL, VK_CMD_BUFFER_OPTIMIZE_SMALL_BATCH_BIT | VK_CMD_BUFFER_OPTIMIZE_ONE_TIME_SUBMIT_BIT };
|
|
|
|
vkr = m_Real.vkBeginCommandBuffer(cmd, &beginInfo);
|
|
RDCASSERT(vkr == VK_SUCCESS);
|
|
|
|
VkBufferCreateInfo bufInfo = {
|
|
VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, NULL,
|
|
meminfo.size, VK_BUFFER_USAGE_GENERAL, 0,
|
|
VK_SHARING_MODE_EXCLUSIVE, 0, NULL,
|
|
};
|
|
|
|
VkBuffer dstBuf;
|
|
|
|
// VKTODOMED this should be created once up front, not every time
|
|
vkr = m_Real.vkCreateBuffer(d, &bufInfo, &dstBuf);
|
|
RDCASSERT(vkr == VK_SUCCESS);
|
|
|
|
vkr = m_Real.vkBindBufferMemory(d, dstBuf, dstMem, 0);
|
|
RDCASSERT(vkr == VK_SUCCESS);
|
|
|
|
VkBufferCopy region = { 0, 0, meminfo.size };
|
|
|
|
m_Real.vkCmdCopyBuffer(cmd, srcBuf, dstBuf, 1, ®ion);
|
|
|
|
vkr = m_Real.vkEndCommandBuffer(cmd);
|
|
RDCASSERT(vkr == VK_SUCCESS);
|
|
|
|
vkr = m_Real.vkQueueSubmit(q, 1, &cmd, VK_NULL_HANDLE);
|
|
RDCASSERT(vkr == VK_SUCCESS);
|
|
|
|
// VKTODOMED would be nice to store a fence too at this point
|
|
// so we can sync on that on serialise rather than syncing
|
|
// every time.
|
|
m_Real.vkQueueWaitIdle(q);
|
|
|
|
m_Real.vkDestroyBuffer(d, dstBuf);
|
|
}
|
|
else if(live.Namespace == eResImage)
|
|
{
|
|
// VKTODOHIGH: need to copy initial copy to live
|
|
RDCUNIMPLEMENTED("image initial states not implemented");
|
|
}
|
|
else
|
|
{
|
|
RDCERR("Unhandled resource type %d", live.Namespace);
|
|
}
|
|
}
|
|
|
|
void WrappedVulkan::ProcessChunk(uint64_t offset, VulkanChunkType context)
|
|
{
|
|
switch(context)
|
|
{
|
|
case DEVICE_INIT:
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, immContextId, ResourceId());
|
|
|
|
GetResourceManager()->AddLiveResource(immContextId, VkResource(eResSpecial, VK_NULL_HANDLE));
|
|
break;
|
|
}
|
|
case ENUM_PHYSICALS:
|
|
Serialise_vkEnumeratePhysicalDevices(NULL, NULL, NULL);
|
|
break;
|
|
case CREATE_DEVICE:
|
|
Serialise_vkCreateDevice(VK_NULL_HANDLE, NULL, NULL);
|
|
break;
|
|
case GET_DEVICE_QUEUE:
|
|
Serialise_vkGetDeviceQueue(VK_NULL_HANDLE, 0, 0, NULL);
|
|
break;
|
|
|
|
case ALLOC_MEM:
|
|
Serialise_vkAllocMemory(VK_NULL_HANDLE, NULL, NULL);
|
|
break;
|
|
case UNMAP_MEM:
|
|
Serialise_vkUnmapMemory(VK_NULL_HANDLE, VK_NULL_HANDLE);
|
|
break;
|
|
case FREE_MEM:
|
|
// VKTODOMED see vkFreeMemory
|
|
//Serialise_vkFreeMemory(VK_NULL_HANDLE, VK_NULL_HANDLE);
|
|
//break;
|
|
case CREATE_CMD_POOL:
|
|
Serialise_vkCreateCommandPool(VK_NULL_HANDLE, NULL, NULL);
|
|
break;
|
|
case CREATE_CMD_BUFFER:
|
|
RDCERR("vkCreateCommandBuffer should not be serialised directly");
|
|
break;
|
|
case CREATE_FRAMEBUFFER:
|
|
Serialise_vkCreateFramebuffer(VK_NULL_HANDLE, NULL, NULL);
|
|
break;
|
|
case CREATE_RENDERPASS:
|
|
Serialise_vkCreateRenderPass(VK_NULL_HANDLE, NULL, NULL);
|
|
break;
|
|
case CREATE_DESCRIPTOR_POOL:
|
|
Serialise_vkCreateDescriptorPool(VK_NULL_HANDLE, VK_DESCRIPTOR_POOL_USAGE_MAX_ENUM, 0, NULL, NULL);
|
|
break;
|
|
case CREATE_DESCRIPTOR_SET:
|
|
Serialise_vkAllocDescriptorSets(VK_NULL_HANDLE, VK_NULL_HANDLE, VK_DESCRIPTOR_SET_USAGE_MAX_ENUM, 0, NULL, NULL, NULL);
|
|
break;
|
|
case CREATE_DESCRIPTOR_SET_LAYOUT:
|
|
Serialise_vkCreateDescriptorSetLayout(VK_NULL_HANDLE, NULL, NULL);
|
|
break;
|
|
case CREATE_BUFFER:
|
|
Serialise_vkCreateBuffer(VK_NULL_HANDLE, NULL, NULL);
|
|
break;
|
|
case CREATE_BUFFER_VIEW:
|
|
Serialise_vkCreateBufferView(VK_NULL_HANDLE, NULL, NULL);
|
|
break;
|
|
case CREATE_IMAGE:
|
|
Serialise_vkCreateImage(VK_NULL_HANDLE, NULL, NULL);
|
|
break;
|
|
case CREATE_IMAGE_VIEW:
|
|
Serialise_vkCreateImageView(VK_NULL_HANDLE, NULL, NULL);
|
|
break;
|
|
case CREATE_ATTACHMENT_VIEW:
|
|
Serialise_vkCreateAttachmentView(VK_NULL_HANDLE, NULL, NULL);
|
|
break;
|
|
case CREATE_VIEWPORT_STATE:
|
|
Serialise_vkCreateDynamicViewportState(VK_NULL_HANDLE, NULL, NULL);
|
|
break;
|
|
case CREATE_RASTER_STATE:
|
|
Serialise_vkCreateDynamicRasterState(VK_NULL_HANDLE, NULL, NULL);
|
|
break;
|
|
case CREATE_BLEND_STATE:
|
|
Serialise_vkCreateDynamicColorBlendState(VK_NULL_HANDLE, NULL, NULL);
|
|
break;
|
|
case CREATE_DEPTH_STATE:
|
|
Serialise_vkCreateDynamicDepthStencilState(VK_NULL_HANDLE, NULL, NULL);
|
|
break;
|
|
case CREATE_SAMPLER:
|
|
Serialise_vkCreateSampler(VK_NULL_HANDLE, NULL, NULL);
|
|
break;
|
|
case CREATE_SHADER:
|
|
Serialise_vkCreateShader(VK_NULL_HANDLE, NULL, NULL);
|
|
break;
|
|
case CREATE_SHADER_MODULE:
|
|
Serialise_vkCreateShaderModule(VK_NULL_HANDLE, NULL, NULL);
|
|
break;
|
|
case CREATE_PIPE_LAYOUT:
|
|
Serialise_vkCreatePipelineLayout(VK_NULL_HANDLE, NULL, NULL);
|
|
break;
|
|
case CREATE_PIPE_CACHE:
|
|
Serialise_vkCreatePipelineCache(VK_NULL_HANDLE, NULL, NULL);
|
|
break;
|
|
case CREATE_GRAPHICS_PIPE:
|
|
Serialise_vkCreateGraphicsPipelines(VK_NULL_HANDLE, VK_NULL_HANDLE, 0, NULL, NULL);
|
|
break;
|
|
case CREATE_COMPUTE_PIPE:
|
|
//VKTODOMED:
|
|
//Serialise_vkCreateComputePipelines(VK_NULL_HANDLE, NULL, NULL);
|
|
break;
|
|
case PRESENT_IMAGE:
|
|
Serialise_vkGetSwapChainInfoWSI(VK_NULL_HANDLE, VK_NULL_HANDLE, VK_SWAP_CHAIN_INFO_TYPE_MAX_ENUM_WSI, NULL, NULL);
|
|
break;
|
|
|
|
case CREATE_SEMAPHORE:
|
|
Serialise_vkCreateSemaphore(VK_NULL_HANDLE, NULL, NULL);
|
|
break;
|
|
case CREATE_FENCE:
|
|
//VKTODOMED:
|
|
//Serialise_vkCreateFence(VK_NULL_HANDLE, NULL, NULL);
|
|
break;
|
|
case GET_FENCE_STATUS:
|
|
//VKTODOMED:
|
|
//Serialise_vkGetFenceStatus(VK_NULL_HANDLE);
|
|
break;
|
|
case WAIT_FENCES:
|
|
//VKTODOMED:
|
|
//Serialise_vkWaitForFences(VK_NULL_HANDLE, 0, NULL, VK_FALSE, 0.0f);
|
|
break;
|
|
|
|
case ALLOC_DESC_SET:
|
|
Serialise_vkAllocDescriptorSets(VK_NULL_HANDLE, VK_NULL_HANDLE, VK_DESCRIPTOR_SET_USAGE_MAX_ENUM, 0, NULL, NULL, NULL);
|
|
break;
|
|
case UPDATE_DESC_SET:
|
|
Serialise_vkUpdateDescriptorSets(VK_NULL_HANDLE, 0, NULL, 0, NULL);
|
|
break;
|
|
|
|
case RESET_CMD_BUFFER:
|
|
Serialise_vkResetCommandBuffer(VK_NULL_HANDLE, 0);
|
|
break;
|
|
case BEGIN_CMD_BUFFER:
|
|
Serialise_vkBeginCommandBuffer(VK_NULL_HANDLE, NULL);
|
|
break;
|
|
case END_CMD_BUFFER:
|
|
Serialise_vkEndCommandBuffer(VK_NULL_HANDLE);
|
|
break;
|
|
|
|
case QUEUE_SIGNAL_SEMAPHORE:
|
|
Serialise_vkQueueSignalSemaphore(VK_NULL_HANDLE, VK_NULL_HANDLE);
|
|
break;
|
|
case QUEUE_WAIT_SEMAPHORE:
|
|
Serialise_vkQueueWaitSemaphore(VK_NULL_HANDLE, VK_NULL_HANDLE);
|
|
break;
|
|
case QUEUE_WAIT_IDLE:
|
|
Serialise_vkQueueWaitIdle(VK_NULL_HANDLE);
|
|
break;
|
|
case DEVICE_WAIT_IDLE:
|
|
Serialise_vkDeviceWaitIdle(VK_NULL_HANDLE);
|
|
break;
|
|
|
|
case QUEUE_SUBMIT:
|
|
Serialise_vkQueueSubmit(VK_NULL_HANDLE, 0, NULL, VK_NULL_HANDLE);
|
|
break;
|
|
case BIND_BUFFER_MEM:
|
|
Serialise_vkBindBufferMemory(VK_NULL_HANDLE, VK_NULL_HANDLE, VK_NULL_HANDLE, 0);
|
|
break;
|
|
case BIND_IMAGE_MEM:
|
|
Serialise_vkBindImageMemory(VK_NULL_HANDLE, VK_NULL_HANDLE, VK_NULL_HANDLE, 0);
|
|
break;
|
|
|
|
case BEGIN_RENDERPASS:
|
|
Serialise_vkCmdBeginRenderPass(VK_NULL_HANDLE, NULL, VK_RENDER_PASS_CONTENTS_MAX_ENUM);
|
|
break;
|
|
case END_RENDERPASS:
|
|
Serialise_vkCmdEndRenderPass(VK_NULL_HANDLE);
|
|
break;
|
|
|
|
case BIND_PIPELINE:
|
|
Serialise_vkCmdBindPipeline(VK_NULL_HANDLE, VK_PIPELINE_BIND_POINT_MAX_ENUM, VK_NULL_HANDLE);
|
|
break;
|
|
case BIND_VP_STATE:
|
|
Serialise_vkCmdBindDynamicViewportState(VK_NULL_HANDLE, VK_NULL_HANDLE);
|
|
break;
|
|
case BIND_RS_STATE:
|
|
Serialise_vkCmdBindDynamicRasterState(VK_NULL_HANDLE, VK_NULL_HANDLE);
|
|
break;
|
|
case BIND_CB_STATE:
|
|
Serialise_vkCmdBindDynamicColorBlendState(VK_NULL_HANDLE, VK_NULL_HANDLE);
|
|
break;
|
|
case BIND_DS_STATE:
|
|
Serialise_vkCmdBindDynamicDepthStencilState(VK_NULL_HANDLE, VK_NULL_HANDLE);
|
|
break;
|
|
case BIND_DESCRIPTOR_SET:
|
|
Serialise_vkCmdBindDescriptorSets(VK_NULL_HANDLE, VK_PIPELINE_BIND_POINT_MAX_ENUM, VK_NULL_HANDLE, 0, 0, NULL, 0, NULL);
|
|
break;
|
|
case BIND_INDEX_BUFFER:
|
|
Serialise_vkCmdBindIndexBuffer(VK_NULL_HANDLE, VK_NULL_HANDLE, 0, VK_INDEX_TYPE_MAX_ENUM);
|
|
break;
|
|
case BIND_VERTEX_BUFFERS:
|
|
Serialise_vkCmdBindVertexBuffers(VK_NULL_HANDLE, 0, 0, NULL, NULL);
|
|
break;
|
|
case COPY_BUF2IMG:
|
|
Serialise_vkCmdCopyBufferToImage(VK_NULL_HANDLE, VK_NULL_HANDLE, VK_NULL_HANDLE, VK_IMAGE_LAYOUT_MAX_ENUM, 0, NULL);
|
|
break;
|
|
case COPY_IMG2BUF:
|
|
Serialise_vkCmdCopyImageToBuffer(VK_NULL_HANDLE, VK_NULL_HANDLE, VK_IMAGE_LAYOUT_MAX_ENUM, VK_NULL_HANDLE, 0, NULL);
|
|
break;
|
|
case COPY_IMG:
|
|
Serialise_vkCmdCopyImage(VK_NULL_HANDLE, VK_NULL_HANDLE, VK_IMAGE_LAYOUT_MAX_ENUM, VK_NULL_HANDLE, VK_IMAGE_LAYOUT_MAX_ENUM, 0, NULL);
|
|
break;
|
|
case COPY_BUF:
|
|
Serialise_vkCmdCopyBuffer(VK_NULL_HANDLE, VK_NULL_HANDLE, VK_NULL_HANDLE, 0, NULL);
|
|
break;
|
|
case CLEAR_COLOR:
|
|
Serialise_vkCmdClearColorImage(VK_NULL_HANDLE, VK_NULL_HANDLE, VK_IMAGE_LAYOUT_MAX_ENUM, NULL, 0, NULL);
|
|
break;
|
|
case CLEAR_DEPTHSTENCIL:
|
|
Serialise_vkCmdClearDepthStencilImage(VK_NULL_HANDLE, VK_NULL_HANDLE, VK_IMAGE_LAYOUT_MAX_ENUM, 0.0f, 0, 0, NULL);
|
|
break;
|
|
case CLEAR_COLOR_ATTACH:
|
|
Serialise_vkCmdClearColorAttachment(VK_NULL_HANDLE, VK_NULL_HANDLE, VK_IMAGE_LAYOUT_MAX_ENUM, NULL, 0, NULL);
|
|
break;
|
|
case CLEAR_DEPTHSTENCIL_ATTACH:
|
|
Serialise_vkCmdClearDepthStencilAttachment(VK_NULL_HANDLE, VK_NULL_HANDLE, VK_IMAGE_LAYOUT_MAX_ENUM, 0.0f, 0, 0, NULL);
|
|
break;
|
|
case PIPELINE_BARRIER:
|
|
Serialise_vkCmdPipelineBarrier(VK_NULL_HANDLE, 0, 0, VK_FALSE, 0, NULL);
|
|
break;
|
|
case RESOLVE_IMAGE:
|
|
//VKTODOMED:
|
|
//Serialise_vkCmdResolveImage(VK_NULL_HANDLE, VK_NULL_HANDLE, VK_NULL_HANDLE, 0, NULL);
|
|
break;
|
|
case WRITE_TIMESTAMP:
|
|
//VKTODOMED:
|
|
//Serialise_vkCmdWriteTimestamp(VK_NULL_HANDLE, VK_TIMESTAMP_TYPE_MAX_ENUM, VK_NULL_HANDLE, 0);
|
|
break;
|
|
case DRAW:
|
|
Serialise_vkCmdDraw(VK_NULL_HANDLE, 0, 0, 0, 0);
|
|
break;
|
|
case DRAW_INDIRECT:
|
|
Serialise_vkCmdDrawIndirect(VK_NULL_HANDLE, VK_NULL_HANDLE, VK_NULL_HANDLE, 0, 0);
|
|
break;
|
|
case DRAW_INDEXED:
|
|
Serialise_vkCmdDrawIndexed(VK_NULL_HANDLE, 0, 0, 0, 0, 0);
|
|
break;
|
|
case DRAW_INDEXED_INDIRECT:
|
|
Serialise_vkCmdDrawIndexedIndirect(VK_NULL_HANDLE, VK_NULL_HANDLE, VK_NULL_HANDLE, 0, 0);
|
|
break;
|
|
case DISPATCH:
|
|
Serialise_vkCmdDispatch(VK_NULL_HANDLE, 0, 0, 0);
|
|
break;
|
|
case DISPATCH_INDIRECT:
|
|
Serialise_vkCmdDispatchIndirect(VK_NULL_HANDLE, VK_NULL_HANDLE, 0);
|
|
break;
|
|
|
|
case BEGIN_EVENT:
|
|
Serialise_vkCmdDbgMarkerBegin(VK_NULL_HANDLE, NULL);
|
|
break;
|
|
case SET_MARKER:
|
|
RDCFATAL("No such function vkCmdDbgMarker");
|
|
break;
|
|
case END_EVENT:
|
|
Serialise_vkCmdDbgMarkerEnd(VK_NULL_HANDLE);
|
|
break;
|
|
|
|
case CREATE_SWAP_BUFFER:
|
|
Serialise_vkCreateSwapChainWSI(VK_NULL_HANDLE, NULL, NULL);
|
|
break;
|
|
|
|
case CAPTURE_SCOPE:
|
|
Serialise_CaptureScope(offset);
|
|
break;
|
|
case CONTEXT_CAPTURE_FOOTER:
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, bbid, ResourceId());
|
|
|
|
ResourceId liveBBid = GetResourceManager()->GetLiveID(bbid);
|
|
|
|
m_FakeBBImgId = bbid;
|
|
m_FakeBBIm = (VkImage)GetResourceManager()->GetLiveResource(bbid).handle;
|
|
m_FakeBBMem = m_ImageInfo[liveBBid].mem;
|
|
|
|
bool HasCallstack = false;
|
|
m_pSerialiser->Serialise("HasCallstack", HasCallstack);
|
|
|
|
if(HasCallstack)
|
|
{
|
|
size_t numLevels = 0;
|
|
uint64_t *stack = NULL;
|
|
|
|
m_pSerialiser->SerialisePODArray("callstack", stack, numLevels);
|
|
|
|
m_pSerialiser->SetCallstack(stack, numLevels);
|
|
|
|
SAFE_DELETE_ARRAY(stack);
|
|
}
|
|
|
|
if(m_State == READING)
|
|
{
|
|
AddEvent(CONTEXT_CAPTURE_FOOTER, "vkQueuePresentWSI()");
|
|
|
|
FetchDrawcall draw;
|
|
draw.name = "vkQueuePresentWSI()";
|
|
draw.flags |= eDraw_Present;
|
|
|
|
AddDrawcall(draw, true);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
// ignore system chunks
|
|
if((int)context == (int)INITIAL_CONTENTS)
|
|
Serialise_InitialState(VkResource(MakeNullResource));
|
|
else if((int)context < (int)FIRST_CHUNK_ID)
|
|
m_pSerialiser->SkipCurrentChunk();
|
|
else
|
|
RDCERR("Unrecognised Chunk type %d", context);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void WrappedVulkan::ReplayLog(uint32_t frameID, uint32_t startEventID, uint32_t endEventID, ReplayLogType replayType)
|
|
{
|
|
RDCASSERT(frameID < (uint32_t)m_FrameRecord.size());
|
|
|
|
uint64_t offs = m_FrameRecord[frameID].frameInfo.fileOffset;
|
|
|
|
m_pSerialiser->SetOffset(offs);
|
|
|
|
bool partial = true;
|
|
|
|
if(startEventID == 0 && (replayType == eReplay_WithoutDraw || replayType == eReplay_Full))
|
|
{
|
|
startEventID = m_FrameRecord[frameID].frameInfo.firstEvent;
|
|
partial = false;
|
|
}
|
|
|
|
VulkanChunkType header = (VulkanChunkType)m_pSerialiser->PushContext(NULL, 1, false);
|
|
|
|
RDCASSERT(header == CAPTURE_SCOPE);
|
|
|
|
m_pSerialiser->SkipCurrentChunk();
|
|
|
|
m_pSerialiser->PopContext(NULL, header);
|
|
|
|
if(!partial)
|
|
{
|
|
GetResourceManager()->ApplyInitialContents();
|
|
GetResourceManager()->ReleaseInFrameResources();
|
|
|
|
// VKTODOLOW temp hack - clear backbuffer to magenta
|
|
// just so we can see if we are replaying or not.
|
|
if(m_FakeBBImgId != ResourceId())
|
|
{
|
|
VkDevice dev = GetDev();
|
|
VkCmdBuffer cmd = GetCmd();
|
|
VkQueue q = GetQ();
|
|
const VulkanFunctions &vk = m_Real;
|
|
|
|
VkCmdBufferBeginInfo beginInfo = { VK_STRUCTURE_TYPE_CMD_BUFFER_BEGIN_INFO, NULL, VK_CMD_BUFFER_OPTIMIZE_SMALL_BATCH_BIT | VK_CMD_BUFFER_OPTIMIZE_ONE_TIME_SUBMIT_BIT };
|
|
|
|
VkResult res = vk.vkBeginCommandBuffer(cmd, &beginInfo);
|
|
|
|
ImgState &st = m_ImageInfo[GetResourceManager()->GetLiveID(m_FakeBBImgId)];
|
|
RDCASSERT(st.subresourceStates.size() == 1);
|
|
|
|
VkImageMemoryBarrier t;
|
|
t.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
|
t.pNext = NULL;
|
|
t.inputMask = 0;
|
|
t.outputMask = 0;
|
|
t.srcQueueFamilyIndex = 0;
|
|
t.destQueueFamilyIndex = 0;
|
|
t.image = m_FakeBBIm;
|
|
t.oldLayout = st.subresourceStates[0].state;
|
|
t.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
|
t.subresourceRange = st.subresourceStates[0].range;
|
|
|
|
void *barrier = (void *)&t;
|
|
|
|
st.subresourceStates[0].state = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
|
vk.vkCmdPipelineBarrier(cmd, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, false, 1, (void **)&barrier);
|
|
|
|
VkClearColorValue clearColor = { { 1.0f, 0.0f, 1.0f, 1.0f, } };
|
|
vk.vkCmdClearColorImage(cmd, m_FakeBBIm, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, &clearColor, 1, &t.subresourceRange);
|
|
|
|
res = vk.vkEndCommandBuffer(cmd);
|
|
|
|
res = vk.vkQueueSubmit(q, 1, &cmd, VK_NULL_HANDLE);
|
|
}
|
|
}
|
|
|
|
{
|
|
if(replayType == eReplay_Full)
|
|
ContextReplayLog(EXECUTING, startEventID, endEventID, partial);
|
|
else if(replayType == eReplay_WithoutDraw)
|
|
ContextReplayLog(EXECUTING, startEventID, RDCMAX(1U,endEventID)-1, partial);
|
|
else if(replayType == eReplay_OnlyDraw)
|
|
ContextReplayLog(EXECUTING, endEventID, endEventID, partial);
|
|
else
|
|
RDCFATAL("Unexpected replay type");
|
|
}
|
|
}
|
|
|
|
void WrappedVulkan::DebugCallback(
|
|
VkFlags msgFlags,
|
|
VkDbgObjectType objType,
|
|
uint64_t srcObject,
|
|
size_t location,
|
|
int32_t msgCode,
|
|
const char* pLayerPrefix,
|
|
const char* pMsg)
|
|
{
|
|
RDCWARN("debug message:\n%s", pMsg);
|
|
}
|
|
|
|
void WrappedVulkan::AddDrawcall(FetchDrawcall d, bool hasEvents)
|
|
{
|
|
if(d.context == ResourceId()) d.context = GetResourceManager()->GetOriginalID(m_ContextResourceID);
|
|
|
|
m_AddedDrawcall = true;
|
|
|
|
WrappedVulkan *context = this;
|
|
|
|
FetchDrawcall draw = d;
|
|
draw.eventID = m_CurEventID;
|
|
draw.drawcallID = m_CurDrawcallID;
|
|
|
|
for(int i=0; i < 8; i++)
|
|
draw.outputs[i] = ResourceId();
|
|
|
|
draw.depthOut = ResourceId();
|
|
|
|
m_CurDrawcallID++;
|
|
if(hasEvents)
|
|
{
|
|
vector<FetchAPIEvent> evs;
|
|
evs.reserve(m_CurEvents.size());
|
|
for(size_t i=0; i < m_CurEvents.size(); )
|
|
{
|
|
if(m_CurEvents[i].context == draw.context)
|
|
{
|
|
evs.push_back(m_CurEvents[i]);
|
|
m_CurEvents.erase(m_CurEvents.begin()+i);
|
|
}
|
|
else
|
|
{
|
|
i++;
|
|
}
|
|
}
|
|
|
|
draw.events = evs;
|
|
}
|
|
|
|
//AddUsage(draw);
|
|
|
|
// should have at least the root drawcall here, push this drawcall
|
|
// onto the back's children list.
|
|
if(!context->m_DrawcallStack.empty())
|
|
{
|
|
DrawcallTreeNode node(draw);
|
|
node.children.insert(node.children.begin(), draw.children.elems, draw.children.elems+draw.children.count);
|
|
context->m_DrawcallStack.back()->children.push_back(node);
|
|
}
|
|
else
|
|
RDCERR("Somehow lost drawcall stack!");
|
|
}
|
|
|
|
void WrappedVulkan::AddEvent(VulkanChunkType type, string description, ResourceId ctx)
|
|
{
|
|
if(ctx == ResourceId()) ctx = GetResourceManager()->GetOriginalID(m_ContextResourceID);
|
|
|
|
FetchAPIEvent apievent;
|
|
|
|
apievent.context = ctx;
|
|
apievent.fileOffset = m_CurChunkOffset;
|
|
apievent.eventID = m_CurEventID;
|
|
|
|
apievent.eventDesc = description;
|
|
|
|
Callstack::Stackwalk *stack = m_pSerialiser->GetLastCallstack();
|
|
if(stack)
|
|
{
|
|
create_array(apievent.callstack, stack->NumLevels());
|
|
memcpy(apievent.callstack.elems, stack->GetAddrs(), sizeof(uint64_t)*stack->NumLevels());
|
|
}
|
|
|
|
m_CurEvents.push_back(apievent);
|
|
|
|
if(m_State == READING)
|
|
m_Events.push_back(apievent);
|
|
}
|
|
|
|
FetchAPIEvent WrappedVulkan::GetEvent(uint32_t eventID)
|
|
{
|
|
for(size_t i=m_Events.size()-1; i > 0; i--)
|
|
{
|
|
if(m_Events[i].eventID <= eventID)
|
|
return m_Events[i];
|
|
}
|
|
|
|
return m_Events[0];
|
|
}
|