mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-09-25 15:16:22 +00:00
Add multiqueue support for Vulkan. Closes #373
This commit is contained in:
@@ -1250,7 +1250,7 @@ bool WrappedID3D12GraphicsCommandList2::Serialise_OMSetRenderTargets(
|
||||
|
||||
std::vector<D3D12Descriptor> RTVs;
|
||||
|
||||
if(ser.VersionCheck(0x5))
|
||||
if(ser.VersionAtLeast(0x5))
|
||||
{
|
||||
if(ser.IsWriting())
|
||||
{
|
||||
@@ -1286,7 +1286,7 @@ bool WrappedID3D12GraphicsCommandList2::Serialise_OMSetRenderTargets(
|
||||
|
||||
D3D12Descriptor DSV = {};
|
||||
|
||||
if(ser.VersionCheck(0x5))
|
||||
if(ser.VersionAtLeast(0x5))
|
||||
{
|
||||
// read and serialise the D3D12Descriptor contents directly, as the call has semantics of
|
||||
// consuming the descriptor immediately.
|
||||
@@ -4321,7 +4321,7 @@ bool WrappedID3D12GraphicsCommandList2::Serialise_ClearDepthStencilView(
|
||||
{
|
||||
ID3D12GraphicsCommandList *pCommandList = this;
|
||||
SERIALISE_ELEMENT(pCommandList);
|
||||
if(ser.VersionCheck(0x5))
|
||||
if(ser.VersionAtLeast(0x5))
|
||||
{
|
||||
// read and serialise the D3D12Descriptor contents directly, as the call has semantics of
|
||||
// consuming the descriptor immediately
|
||||
@@ -4420,7 +4420,7 @@ bool WrappedID3D12GraphicsCommandList2::Serialise_ClearRenderTargetView(
|
||||
{
|
||||
ID3D12GraphicsCommandList *pCommandList = this;
|
||||
SERIALISE_ELEMENT(pCommandList);
|
||||
if(ser.VersionCheck(0x5))
|
||||
if(ser.VersionAtLeast(0x5))
|
||||
{
|
||||
// read and serialise the D3D12Descriptor contents directly, as the call has semantics of
|
||||
// consuming the descriptor immediately
|
||||
@@ -4515,7 +4515,7 @@ bool WrappedID3D12GraphicsCommandList2::Serialise_ClearUnorderedAccessViewUint(
|
||||
ID3D12GraphicsCommandList *pCommandList = this;
|
||||
SERIALISE_ELEMENT(pCommandList);
|
||||
SERIALISE_ELEMENT(ViewGPUHandleInCurrentHeap);
|
||||
if(ser.VersionCheck(0x5))
|
||||
if(ser.VersionAtLeast(0x5))
|
||||
{
|
||||
// read and serialise the D3D12Descriptor contents directly, as the call has semantics of
|
||||
// consuming the descriptor immediately. This is only true for the CPU-side handle
|
||||
@@ -4620,7 +4620,7 @@ bool WrappedID3D12GraphicsCommandList2::Serialise_ClearUnorderedAccessViewFloat(
|
||||
ID3D12GraphicsCommandList *pCommandList = this;
|
||||
SERIALISE_ELEMENT(pCommandList);
|
||||
SERIALISE_ELEMENT(ViewGPUHandleInCurrentHeap);
|
||||
if(ser.VersionCheck(0x5))
|
||||
if(ser.VersionAtLeast(0x5))
|
||||
{
|
||||
// read and serialise the D3D12Descriptor contents directly, as the call has semantics of
|
||||
// consuming the descriptor immediately. This is only true for the CPU-side handle
|
||||
|
||||
@@ -237,6 +237,11 @@ bool VkInitParams::IsSupportedVersion(uint64_t ver)
|
||||
if(ver == CurrentVersion)
|
||||
return true;
|
||||
|
||||
// 0xC -> 0xD - supported multiple queues. This didn't cause a large change to the serialisation
|
||||
// but there were some slight inconsistencies that required a version bump
|
||||
if(ver == 0xC)
|
||||
return true;
|
||||
|
||||
// 0xB -> 0xC - generally this is when we started serialising pNext chains that older RenderDoc
|
||||
// couldn't support. But we don't need any special backwards compatibiltiy code as it's just added
|
||||
// serialisation.
|
||||
@@ -755,16 +760,6 @@ void ReplacePresentableImageLayout(VkImageLayout &layout)
|
||||
layout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
}
|
||||
|
||||
void ReplaceExternalQueueFamily(uint32_t &srcQueueFamily, uint32_t &dstQueueFamily)
|
||||
{
|
||||
if(srcQueueFamily == VK_QUEUE_FAMILY_EXTERNAL || dstQueueFamily == VK_QUEUE_FAMILY_EXTERNAL)
|
||||
{
|
||||
// we should ignore this family transition since we're not synchronising with an
|
||||
// external access.
|
||||
srcQueueFamily = dstQueueFamily = VK_QUEUE_FAMILY_IGNORED;
|
||||
}
|
||||
}
|
||||
|
||||
int SampleCount(VkSampleCountFlagBits countFlag)
|
||||
{
|
||||
switch(countFlag)
|
||||
|
||||
@@ -30,8 +30,6 @@
|
||||
// MULTIDEVICE - parts of the code that will need to be updated to support
|
||||
// multiple devices or queues.
|
||||
|
||||
// SHARING - as above, for handling resource sharing between queues
|
||||
|
||||
#include "common/common.h"
|
||||
|
||||
#define VK_NO_PROTOTYPES
|
||||
@@ -104,7 +102,6 @@ StencilOperation MakeStencilOp(VkStencilOp op);
|
||||
VkAccessFlags MakeAccessMask(VkImageLayout layout);
|
||||
|
||||
void ReplacePresentableImageLayout(VkImageLayout &layout);
|
||||
void ReplaceExternalQueueFamily(uint32_t &srcQueueFamily, uint32_t &dstQueueFamily);
|
||||
|
||||
void DoPipelineBarrier(VkCommandBuffer cmd, uint32_t count, VkImageMemoryBarrier *barriers);
|
||||
void DoPipelineBarrier(VkCommandBuffer cmd, uint32_t count, VkBufferMemoryBarrier *barriers);
|
||||
|
||||
@@ -141,7 +141,6 @@ WrappedVulkan::WrappedVulkan() : m_RenderState(this, &m_CreationInfo)
|
||||
m_Device = VK_NULL_HANDLE;
|
||||
m_Queue = VK_NULL_HANDLE;
|
||||
m_QueueFamilyIdx = 0;
|
||||
m_SupportedQueueFamily = 0;
|
||||
m_DbgMsgCallback = VK_NULL_HANDLE;
|
||||
|
||||
m_HeaderChunk = NULL;
|
||||
@@ -208,9 +207,13 @@ VkCommandBuffer WrappedVulkan::GetNextCmd()
|
||||
}
|
||||
else
|
||||
{
|
||||
VkCommandBufferAllocateInfo cmdInfo = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, NULL,
|
||||
Unwrap(m_InternalCmds.cmdpool),
|
||||
VK_COMMAND_BUFFER_LEVEL_PRIMARY, 1};
|
||||
VkCommandBufferAllocateInfo cmdInfo = {
|
||||
VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
|
||||
NULL,
|
||||
Unwrap(m_InternalCmds.cmdpool),
|
||||
VK_COMMAND_BUFFER_LEVEL_PRIMARY,
|
||||
1,
|
||||
};
|
||||
VkResult vkr = ObjDisp(m_Device)->AllocateCommandBuffers(Unwrap(m_Device), &cmdInfo, &ret);
|
||||
|
||||
if(m_SetDeviceLoaderData)
|
||||
@@ -339,6 +342,51 @@ void WrappedVulkan::FlushQ()
|
||||
}
|
||||
}
|
||||
|
||||
VkCommandBuffer WrappedVulkan::GetExtQueueCmd(uint32_t queueFamilyIdx)
|
||||
{
|
||||
if(queueFamilyIdx >= m_ExternalQueues.size())
|
||||
{
|
||||
RDCERR("Unsupported queue family %u", queueFamilyIdx);
|
||||
return VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
VkCommandBuffer buf = m_ExternalQueues[queueFamilyIdx].buffer;
|
||||
|
||||
ObjDisp(buf)->ResetCommandBuffer(Unwrap(buf), 0);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
void WrappedVulkan::SubmitAndFlushExtQueue(uint32_t queueFamilyIdx)
|
||||
{
|
||||
if(queueFamilyIdx >= m_ExternalQueues.size())
|
||||
{
|
||||
RDCERR("Unsupported queue family %u", queueFamilyIdx);
|
||||
return;
|
||||
}
|
||||
|
||||
VkCommandBuffer buf = Unwrap(m_ExternalQueues[queueFamilyIdx].buffer);
|
||||
|
||||
VkSubmitInfo submitInfo = {
|
||||
VK_STRUCTURE_TYPE_SUBMIT_INFO,
|
||||
NULL,
|
||||
0,
|
||||
NULL,
|
||||
NULL, // wait semaphores
|
||||
1,
|
||||
&buf, // command buffers
|
||||
0,
|
||||
NULL, // signal semaphores
|
||||
};
|
||||
|
||||
VkQueue q = m_ExternalQueues[queueFamilyIdx].queue;
|
||||
|
||||
VkResult vkr = ObjDisp(q)->QueueSubmit(Unwrap(q), 1, &submitInfo, VK_NULL_HANDLE);
|
||||
RDCASSERTEQUAL(vkr, VK_SUCCESS);
|
||||
|
||||
ObjDisp(q)->QueueWaitIdle(Unwrap(q));
|
||||
}
|
||||
|
||||
uint32_t WrappedVulkan::HandlePreCallback(VkCommandBuffer commandBuffer, DrawFlags type,
|
||||
uint32_t multiDrawOffset)
|
||||
{
|
||||
@@ -1032,6 +1080,38 @@ void WrappedVulkan::StartFrameCapture(void *dev, void *wnd)
|
||||
// and go into the frame record.
|
||||
{
|
||||
SCOPED_LOCK(m_CapTransitionLock);
|
||||
|
||||
// wait for all work to finish and apply a memory barrier to ensure all memory is visible
|
||||
for(size_t i = 0; i < m_QueueFamilies.size(); i++)
|
||||
{
|
||||
for(uint32_t q = 0; q < m_QueueFamilyCounts[i]; q++)
|
||||
{
|
||||
if(m_QueueFamilies[i][q] != VK_NULL_HANDLE)
|
||||
ObjDisp(m_QueueFamilies[i][q])->QueueWaitIdle(Unwrap(m_QueueFamilies[i][q]));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
VkMemoryBarrier memBarrier = {
|
||||
VK_STRUCTURE_TYPE_MEMORY_BARRIER, NULL, VK_ACCESS_ALL_WRITE_BITS, VK_ACCESS_ALL_READ_BITS,
|
||||
};
|
||||
|
||||
VkCommandBuffer cmd = GetNextCmd();
|
||||
|
||||
VkResult vkr = VK_SUCCESS;
|
||||
|
||||
VkCommandBufferBeginInfo beginInfo = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, NULL,
|
||||
VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT};
|
||||
|
||||
vkr = ObjDisp(cmd)->BeginCommandBuffer(Unwrap(cmd), &beginInfo);
|
||||
RDCASSERTEQUAL(vkr, VK_SUCCESS);
|
||||
|
||||
DoPipelineBarrier(cmd, 1, &memBarrier);
|
||||
|
||||
vkr = ObjDisp(cmd)->EndCommandBuffer(Unwrap(cmd));
|
||||
RDCASSERTEQUAL(vkr, VK_SUCCESS);
|
||||
}
|
||||
|
||||
GetResourceManager()->PrepareInitialContents();
|
||||
|
||||
RDCDEBUG("Attempting capture");
|
||||
@@ -1886,8 +1966,8 @@ ReplayStatus WrappedVulkan::ContextReplayLog(CaptureState readType, uint32_t sta
|
||||
for(size_t i = 0; i < m_CleanupEvents.size(); i++)
|
||||
ObjDisp(GetDev())->DestroyEvent(Unwrap(GetDev()), m_CleanupEvents[i], NULL);
|
||||
|
||||
vkFreeCommandBuffers(GetDev(), m_InternalCmds.cmdpool, (uint32_t)m_RerecordCmdList.size(),
|
||||
m_RerecordCmdList.data());
|
||||
for(const std::pair<VkCommandPool, VkCommandBuffer> &rerecord : m_RerecordCmdList)
|
||||
vkFreeCommandBuffers(GetDev(), rerecord.first, 1, &rerecord.second);
|
||||
}
|
||||
|
||||
m_CleanupEvents.clear();
|
||||
|
||||
@@ -55,7 +55,7 @@ struct VkInitParams
|
||||
uint32_t GetSerialiseSize();
|
||||
|
||||
// check if a frame capture section version is supported
|
||||
static const uint64_t CurrentVersion = 0xC;
|
||||
static const uint64_t CurrentVersion = 0xD;
|
||||
static bool IsSupportedVersion(uint64_t ver);
|
||||
};
|
||||
|
||||
@@ -68,7 +68,7 @@ struct VulkanDrawcallTreeNode
|
||||
DrawcallDescription draw;
|
||||
vector<VulkanDrawcallTreeNode> children;
|
||||
|
||||
vector<pair<ResourceId, EventUsage> > resourceUsage;
|
||||
vector<pair<ResourceId, EventUsage>> resourceUsage;
|
||||
|
||||
vector<ResourceId> executedCmds;
|
||||
|
||||
@@ -305,6 +305,7 @@ private:
|
||||
RDCEraseEl(props);
|
||||
RDCEraseEl(memProps);
|
||||
RDCEraseEl(fmtprops);
|
||||
RDCEraseEl(queueProps);
|
||||
}
|
||||
|
||||
uint32_t GetMemoryIndex(uint32_t resourceRequiredBitmask, uint32_t allocRequiredProps,
|
||||
@@ -325,19 +326,31 @@ private:
|
||||
VkPhysicalDeviceProperties props;
|
||||
VkPhysicalDeviceMemoryProperties memProps;
|
||||
VkFormatProperties fmtprops[VK_FORMAT_RANGE_SIZE];
|
||||
|
||||
uint32_t queueCount = 0;
|
||||
VkQueueFamilyProperties queueProps[16];
|
||||
};
|
||||
|
||||
PFN_vkSetDeviceLoaderData m_SetDeviceLoaderData;
|
||||
|
||||
VkInstance m_Instance; // the instance corresponding to this WrappedVulkan
|
||||
VkDebugReportCallbackEXT m_DbgMsgCallback; // the instance's dbg msg callback handle
|
||||
VkPhysicalDevice m_PhysicalDevice; // the physical device we created m_Device with
|
||||
VkDevice m_Device; // the device used for our own command buffer work
|
||||
PhysicalDeviceData
|
||||
m_PhysicalDeviceData; // the data about the physical device used for the above device;
|
||||
uint32_t
|
||||
m_QueueFamilyIdx; // the family index that we've selected in CreateDevice for our queue
|
||||
VkQueue m_Queue; // the queue used for our own command buffer work
|
||||
// the instance corresponding to this WrappedVulkan
|
||||
VkInstance m_Instance;
|
||||
// the instance's dbg msg callback handle
|
||||
VkDebugReportCallbackEXT m_DbgMsgCallback;
|
||||
// the physical device we created m_Device with
|
||||
VkPhysicalDevice m_PhysicalDevice;
|
||||
// the device used for our own command buffer work
|
||||
VkDevice m_Device;
|
||||
// the data about the physical device used for the above device
|
||||
PhysicalDeviceData m_PhysicalDeviceData;
|
||||
// the family index that we've selected in CreateDevice for our queue. During replay, this is an
|
||||
// index in the replay-time queues, not the capture-time queues (i.e. after remapping)
|
||||
uint32_t m_QueueFamilyIdx;
|
||||
// the queue used for our own command buffer work
|
||||
VkQueue m_Queue;
|
||||
// the last queue that submitted something during replay, to allow correct sync between
|
||||
// submissions
|
||||
VkQueue m_PrevQueue;
|
||||
|
||||
// the physical devices. At capture time this is trivial, just the enumerated devices.
|
||||
// At replay time this is re-ordered from the real list to try and match
|
||||
@@ -350,14 +363,33 @@ private:
|
||||
vector<VkPhysicalDevice> m_ReplayPhysicalDevices;
|
||||
vector<bool> m_ReplayPhysicalDevicesUsed;
|
||||
|
||||
// the single queue family supported for each physical device
|
||||
vector<pair<uint32_t, VkQueueFamilyProperties> > m_SupportedQueueFamilies;
|
||||
|
||||
// the supported queue family for the created device
|
||||
uint32_t m_SupportedQueueFamily;
|
||||
|
||||
// the queue families (an array of count for each) for the created device
|
||||
vector<VkQueue *> m_QueueFamilies;
|
||||
vector<uint32_t> m_QueueFamilyCounts;
|
||||
|
||||
// a small amount of helper code during capture for handling resources on different queues in init
|
||||
// states
|
||||
struct ExternalQueue
|
||||
{
|
||||
VkQueue queue = VK_NULL_HANDLE;
|
||||
VkCommandPool pool = VK_NULL_HANDLE;
|
||||
VkCommandBuffer buffer = VK_NULL_HANDLE;
|
||||
};
|
||||
vector<ExternalQueue> m_ExternalQueues;
|
||||
|
||||
VkCommandBuffer GetExtQueueCmd(uint32_t queueFamilyIdx);
|
||||
void SubmitAndFlushExtQueue(uint32_t queueFamilyIdx);
|
||||
|
||||
struct QueueRemap
|
||||
{
|
||||
uint32_t family;
|
||||
uint32_t index;
|
||||
};
|
||||
|
||||
// for each queue family in the original captured physical device, we have a remapping vector.
|
||||
// Each element in the vector is an available queue in that family, and the uint64 is packed as
|
||||
// (targetQueueFamily << 32) | (targetQueueIndex)
|
||||
std::vector<QueueRemap> m_QueueRemapping[16];
|
||||
|
||||
vector<uint32_t *> m_MemIdxMaps;
|
||||
void RemapMemoryIndices(VkPhysicalDeviceMemoryProperties *memProps, uint32_t **memIdxMap);
|
||||
@@ -405,7 +437,7 @@ private:
|
||||
|
||||
// Per memory scope, the size of the next allocation. This allows us to balance number of memory
|
||||
// allocation objects with size by incrementally allocating larger blocks.
|
||||
VkDeviceSize m_MemoryBlockSize[arraydim<MemoryScope>()];
|
||||
VkDeviceSize m_MemoryBlockSize[arraydim<MemoryScope>()] = {};
|
||||
|
||||
MemoryAllocation AllocateMemoryForResource(VkImage im, MemoryScope scope, MemoryType type);
|
||||
MemoryAllocation AllocateMemoryForResource(VkBuffer buf, MemoryScope scope, MemoryType type);
|
||||
@@ -450,7 +482,7 @@ private:
|
||||
|
||||
int markerCount;
|
||||
|
||||
std::vector<std::pair<ResourceId, EventUsage> > resourceUsage;
|
||||
std::vector<std::pair<ResourceId, EventUsage>> resourceUsage;
|
||||
|
||||
struct CmdBufferState
|
||||
{
|
||||
@@ -472,7 +504,7 @@ private:
|
||||
uint32_t subpass = 0;
|
||||
} state;
|
||||
|
||||
std::vector<std::pair<ResourceId, ImageRegionState> > imgbarriers;
|
||||
std::vector<std::pair<ResourceId, ImageRegionState>> imgbarriers;
|
||||
|
||||
ResourceId pushDescriptorID[64];
|
||||
|
||||
@@ -546,7 +578,7 @@ private:
|
||||
// event IDs, since they could be submitted multiple times in the frame and we don't want to
|
||||
// rebase all of them each time.
|
||||
// Map from bakeID -> vector<Submission>
|
||||
std::map<ResourceId, std::vector<Submission> > cmdBufferSubmits;
|
||||
std::map<ResourceId, std::vector<Submission>> cmdBufferSubmits;
|
||||
|
||||
// identifies the baked ID of the command buffer that's actually partial at each level.
|
||||
ResourceId partialParent;
|
||||
@@ -573,7 +605,7 @@ private:
|
||||
// we store the list here, since we need to keep all command buffers until the whole replay is
|
||||
// finished, but if a command buffer is re-recorded multiple times it would be overwritten in the
|
||||
// above map
|
||||
std::vector<VkCommandBuffer> m_RerecordCmdList;
|
||||
std::vector<std::pair<VkCommandPool, VkCommandBuffer>> m_RerecordCmdList;
|
||||
|
||||
// There is only a state while currently partially replaying, it's
|
||||
// undefined/empty otherwise.
|
||||
@@ -629,7 +661,7 @@ private:
|
||||
// immutable creation data
|
||||
VulkanCreationInfo m_CreationInfo;
|
||||
|
||||
map<ResourceId, vector<EventUsage> > m_ResourceUses;
|
||||
map<ResourceId, vector<EventUsage>> m_ResourceUses;
|
||||
|
||||
// returns thread-local temporary memory
|
||||
byte *GetTempMemory(size_t s);
|
||||
@@ -781,6 +813,8 @@ public:
|
||||
void Create_InitialState(ResourceId id, WrappedVkRes *live, bool hasData);
|
||||
void Apply_InitialState(WrappedVkRes *live, VkInitialContents initial);
|
||||
|
||||
void RemapQueueFamilyIndices(uint32_t &srcQueueFamily, uint32_t &dstQueueFamily);
|
||||
|
||||
bool ReleaseResource(WrappedVkRes *res);
|
||||
|
||||
ReplayStatus Initialise(VkInitParams ¶ms, uint64_t sectionVersion);
|
||||
|
||||
@@ -438,4 +438,7 @@ struct VulkanCreationInfo
|
||||
map<ResourceId, SwapchainInfo> m_SwapChain;
|
||||
map<ResourceId, DescSetLayout> m_DescSetLayout;
|
||||
map<ResourceId, DescUpdateTemplate> m_DescUpdateTemplate;
|
||||
|
||||
// just contains the queueFamilyIndex (after remapping)
|
||||
map<ResourceId, uint32_t> m_Queue;
|
||||
};
|
||||
|
||||
@@ -109,12 +109,20 @@ bool WrappedVulkan::Prepare_InitialState(WrappedVkRes *res)
|
||||
// INITSTATEBATCH
|
||||
VkCommandBuffer cmd = GetNextCmd();
|
||||
|
||||
VkCommandBuffer extQCmd = VK_NULL_HANDLE;
|
||||
|
||||
ImageLayouts *layout = NULL;
|
||||
{
|
||||
SCOPED_LOCK(m_ImageLayoutsLock);
|
||||
layout = &m_ImageLayouts[im->id];
|
||||
}
|
||||
|
||||
if(layout->queueFamilyIndex != m_QueueFamilyIdx)
|
||||
{
|
||||
// get a command buffer for giving up ownership before the copy and acquiring it afterwards.
|
||||
extQCmd = GetExtQueueCmd(layout->queueFamilyIndex);
|
||||
}
|
||||
|
||||
// must ensure offset remains valid. Must be multiple of block size, or 4, depending on format
|
||||
VkDeviceSize bufAlignment = 4;
|
||||
if(IsBlockFormat(layout->format))
|
||||
@@ -212,6 +220,12 @@ bool WrappedVulkan::Prepare_InitialState(WrappedVkRes *res)
|
||||
vkr = ObjDisp(d)->BeginCommandBuffer(Unwrap(cmd), &beginInfo);
|
||||
RDCASSERTEQUAL(vkr, VK_SUCCESS);
|
||||
|
||||
if(extQCmd != VK_NULL_HANDLE)
|
||||
{
|
||||
vkr = ObjDisp(d)->BeginCommandBuffer(Unwrap(extQCmd), &beginInfo);
|
||||
RDCASSERTEQUAL(vkr, VK_SUCCESS);
|
||||
}
|
||||
|
||||
VkImageAspectFlags aspectFlags = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
if(IsStencilOnlyFormat(layout->format))
|
||||
aspectFlags = VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||
@@ -225,10 +239,11 @@ bool WrappedVulkan::Prepare_InitialState(WrappedVkRes *res)
|
||||
0,
|
||||
VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
||||
VK_QUEUE_FAMILY_IGNORED,
|
||||
VK_QUEUE_FAMILY_IGNORED,
|
||||
layout->queueFamilyIndex,
|
||||
m_QueueFamilyIdx,
|
||||
realim,
|
||||
{aspectFlags, 0, (uint32_t)layout->levelCount, 0, (uint32_t)numLayers}};
|
||||
{aspectFlags, 0, (uint32_t)layout->levelCount, 0, (uint32_t)numLayers},
|
||||
};
|
||||
|
||||
if(aspectFlags == VK_IMAGE_ASPECT_DEPTH_BIT && !IsDepthOnlyFormat(layout->format))
|
||||
srcimBarrier.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||
@@ -248,21 +263,34 @@ bool WrappedVulkan::Prepare_InitialState(WrappedVkRes *res)
|
||||
srcimBarrier.subresourceRange = layout->subresourceStates[si].subresourceRange;
|
||||
srcimBarrier.oldLayout = layout->subresourceStates[si].newLayout;
|
||||
DoPipelineBarrier(cmd, 1, &srcimBarrier);
|
||||
|
||||
if(srcimBarrier.srcQueueFamilyIndex != srcimBarrier.dstQueueFamilyIndex)
|
||||
DoPipelineBarrier(extQCmd, 1, &srcimBarrier);
|
||||
}
|
||||
|
||||
if(extQCmd != VK_NULL_HANDLE)
|
||||
{
|
||||
vkr = ObjDisp(d)->EndCommandBuffer(Unwrap(extQCmd));
|
||||
RDCASSERTEQUAL(vkr, VK_SUCCESS);
|
||||
|
||||
SubmitAndFlushExtQueue(layout->queueFamilyIndex);
|
||||
}
|
||||
|
||||
if(arrayIm != VK_NULL_HANDLE)
|
||||
{
|
||||
VkImageMemoryBarrier arrayimBarrier = {VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||
NULL,
|
||||
0,
|
||||
0,
|
||||
VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
VK_IMAGE_LAYOUT_GENERAL,
|
||||
VK_QUEUE_FAMILY_IGNORED,
|
||||
VK_QUEUE_FAMILY_IGNORED,
|
||||
Unwrap(arrayIm),
|
||||
{srcimBarrier.subresourceRange.aspectMask, 0,
|
||||
VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS}};
|
||||
VkImageMemoryBarrier arrayimBarrier = {
|
||||
VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||
NULL,
|
||||
0,
|
||||
0,
|
||||
VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
VK_IMAGE_LAYOUT_GENERAL,
|
||||
VK_QUEUE_FAMILY_IGNORED,
|
||||
VK_QUEUE_FAMILY_IGNORED,
|
||||
Unwrap(arrayIm),
|
||||
{srcimBarrier.subresourceRange.aspectMask, 0, VK_REMAINING_MIP_LEVELS, 0,
|
||||
VK_REMAINING_ARRAY_LAYERS},
|
||||
};
|
||||
|
||||
DoPipelineBarrier(cmd, 1, &arrayimBarrier);
|
||||
|
||||
@@ -346,15 +374,35 @@ bool WrappedVulkan::Prepare_InitialState(WrappedVkRes *res)
|
||||
// transfer back to whatever it was
|
||||
srcimBarrier.oldLayout = srcimBarrier.newLayout;
|
||||
|
||||
// on whatever queue
|
||||
std::swap(srcimBarrier.srcQueueFamilyIndex, srcimBarrier.dstQueueFamilyIndex);
|
||||
|
||||
srcimBarrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
|
||||
srcimBarrier.dstAccessMask = 0;
|
||||
|
||||
if(extQCmd != VK_NULL_HANDLE)
|
||||
{
|
||||
vkr = ObjDisp(d)->BeginCommandBuffer(Unwrap(extQCmd), &beginInfo);
|
||||
RDCASSERTEQUAL(vkr, VK_SUCCESS);
|
||||
}
|
||||
|
||||
for(size_t si = 0; si < layout->subresourceStates.size(); si++)
|
||||
{
|
||||
srcimBarrier.subresourceRange = layout->subresourceStates[si].subresourceRange;
|
||||
srcimBarrier.newLayout = layout->subresourceStates[si].newLayout;
|
||||
srcimBarrier.dstAccessMask = MakeAccessMask(srcimBarrier.newLayout);
|
||||
DoPipelineBarrier(cmd, 1, &srcimBarrier);
|
||||
|
||||
if(srcimBarrier.srcQueueFamilyIndex != srcimBarrier.dstQueueFamilyIndex)
|
||||
DoPipelineBarrier(extQCmd, 1, &srcimBarrier);
|
||||
}
|
||||
|
||||
if(extQCmd != VK_NULL_HANDLE)
|
||||
{
|
||||
vkr = ObjDisp(d)->EndCommandBuffer(Unwrap(extQCmd));
|
||||
RDCASSERTEQUAL(vkr, VK_SUCCESS);
|
||||
|
||||
SubmitAndFlushExtQueue(layout->queueFamilyIndex);
|
||||
}
|
||||
|
||||
vkr = ObjDisp(d)->EndCommandBuffer(Unwrap(cmd));
|
||||
@@ -401,9 +449,17 @@ bool WrappedVulkan::Prepare_InitialState(WrappedVkRes *res)
|
||||
VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
||||
};
|
||||
|
||||
// we make the buffer concurrently accessible by all queue families to not invalidate the
|
||||
// contents of the memory we're reading back from.
|
||||
bufInfo.sharingMode = VK_SHARING_MODE_CONCURRENT;
|
||||
bufInfo.queueFamilyIndexCount = m_PhysicalDeviceData.queueCount;
|
||||
std::vector<uint32_t> queues;
|
||||
for(uint32_t i = 0; i < bufInfo.queueFamilyIndexCount; i++)
|
||||
queues.push_back(i);
|
||||
bufInfo.pQueueFamilyIndices = queues.data();
|
||||
|
||||
// since this happens during capture, we don't want to start serialising extra buffer creates,
|
||||
// so
|
||||
// we manually create & then just wrap.
|
||||
// so we manually create & then just wrap.
|
||||
VkBuffer srcBuf, dstBuf;
|
||||
|
||||
bufInfo.size = datasize;
|
||||
|
||||
@@ -60,6 +60,8 @@ void VulkanResourceManager::RecordSingleBarrier(vector<pair<ResourceId, ImageReg
|
||||
if(it->first != id)
|
||||
break;
|
||||
|
||||
it->second.dstQueueFamilyIndex = t.dstQueueFamilyIndex;
|
||||
|
||||
{
|
||||
// we've found a range that completely matches our region, doesn't matter if that's
|
||||
// a whole image and the barrier is the whole image, or it's one subresource.
|
||||
@@ -185,7 +187,8 @@ void VulkanResourceManager::RecordSingleBarrier(vector<pair<ResourceId, ImageReg
|
||||
VkImageSubresourceRange subRange = t.subresourceRange;
|
||||
subRange.levelCount = nummips;
|
||||
subRange.layerCount = numslices;
|
||||
dststates.insert(it, std::make_pair(id, ImageRegionState(subRange, t.oldLayout, t.newLayout)));
|
||||
dststates.insert(it, std::make_pair(id, ImageRegionState(VK_QUEUE_FAMILY_IGNORED, subRange,
|
||||
t.oldLayout, t.newLayout)));
|
||||
}
|
||||
|
||||
void VulkanResourceManager::RecordBarriers(vector<pair<ResourceId, ImageRegionState> > &states,
|
||||
@@ -280,9 +283,9 @@ void VulkanResourceManager::SerialiseImageStates(SerialiserType &ser,
|
||||
// to get images into the right layout
|
||||
t.srcAccessMask = 0;
|
||||
t.dstAccessMask = 0;
|
||||
// MULTIDEVICE need to handle multiple queues
|
||||
t.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
t.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
t.srcQueueFamilyIndex = ImageState.queueFamilyIndex;
|
||||
t.dstQueueFamilyIndex = ImageState.queueFamilyIndex;
|
||||
m_Core->RemapQueueFamilyIndices(t.srcQueueFamilyIndex, t.dstQueueFamilyIndex);
|
||||
t.image = Unwrap(GetCurrentHandle<VkImage>(liveid));
|
||||
t.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
ReplacePresentableImageLayout(state.newLayout);
|
||||
@@ -297,7 +300,8 @@ void VulkanResourceManager::SerialiseImageStates(SerialiserType &ser,
|
||||
srcit++;
|
||||
}
|
||||
|
||||
ApplyBarriers(vec, states);
|
||||
// we don't have to specify a queue here because all of the images have a specific queue above
|
||||
ApplyBarriers(VK_QUEUE_FAMILY_IGNORED, vec, states);
|
||||
|
||||
for(size_t i = 0; i < vec.size(); i++)
|
||||
barriers[i].oldLayout = vec[i].second.oldLayout;
|
||||
@@ -376,7 +380,8 @@ void VulkanResourceManager::MarkSparseMapReferenced(SparseMapping *sparse)
|
||||
}
|
||||
}
|
||||
|
||||
void VulkanResourceManager::ApplyBarriers(vector<pair<ResourceId, ImageRegionState> > &states,
|
||||
void VulkanResourceManager::ApplyBarriers(uint32_t queueFamilyIndex,
|
||||
vector<pair<ResourceId, ImageRegionState> > &states,
|
||||
map<ResourceId, ImageLayouts> &layouts)
|
||||
{
|
||||
TRDBG("Applying %u barriers", (uint32_t)states.size());
|
||||
@@ -396,6 +401,13 @@ void VulkanResourceManager::ApplyBarriers(vector<pair<ResourceId, ImageRegionSta
|
||||
continue;
|
||||
}
|
||||
|
||||
// apply any ownership transfer
|
||||
stit->second.queueFamilyIndex = t.dstQueueFamilyIndex;
|
||||
|
||||
// if there's no ownership transfer, it's implicitly owned by the current queue
|
||||
if(t.dstQueueFamilyIndex == VK_QUEUE_FAMILY_IGNORED)
|
||||
stit->second.queueFamilyIndex = queueFamilyIndex;
|
||||
|
||||
uint32_t nummips = t.subresourceRange.levelCount;
|
||||
uint32_t numslices = t.subresourceRange.layerCount;
|
||||
if(nummips == VK_REMAINING_MIP_LEVELS)
|
||||
|
||||
@@ -253,7 +253,7 @@ public:
|
||||
void MergeBarriers(vector<pair<ResourceId, ImageRegionState> > &dststates,
|
||||
vector<pair<ResourceId, ImageRegionState> > &srcstates);
|
||||
|
||||
void ApplyBarriers(vector<pair<ResourceId, ImageRegionState> > &states,
|
||||
void ApplyBarriers(uint32_t queueFamilyIndex, vector<pair<ResourceId, ImageRegionState> > &states,
|
||||
map<ResourceId, ImageLayouts> &layouts);
|
||||
|
||||
template <typename SerialiserType>
|
||||
|
||||
@@ -830,7 +830,10 @@ VkResourceType IdentifyTypeByPtr(WrappedVkRes *ptr);
|
||||
|
||||
struct ImageRegionState
|
||||
{
|
||||
ImageRegionState() : oldLayout(UNKNOWN_PREV_IMG_LAYOUT), newLayout(UNKNOWN_PREV_IMG_LAYOUT)
|
||||
ImageRegionState()
|
||||
: dstQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED),
|
||||
oldLayout(UNKNOWN_PREV_IMG_LAYOUT),
|
||||
newLayout(UNKNOWN_PREV_IMG_LAYOUT)
|
||||
{
|
||||
subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
subresourceRange.baseArrayLayer = 0;
|
||||
@@ -838,11 +841,12 @@ struct ImageRegionState
|
||||
subresourceRange.baseMipLevel = 0;
|
||||
subresourceRange.levelCount = 0;
|
||||
}
|
||||
ImageRegionState(VkImageSubresourceRange r, VkImageLayout pr, VkImageLayout st)
|
||||
: subresourceRange(r), oldLayout(pr), newLayout(st)
|
||||
ImageRegionState(uint32_t queueIndex, VkImageSubresourceRange r, VkImageLayout pr, VkImageLayout st)
|
||||
: dstQueueFamilyIndex(queueIndex), subresourceRange(r), oldLayout(pr), newLayout(st)
|
||||
{
|
||||
}
|
||||
|
||||
uint32_t dstQueueFamilyIndex;
|
||||
VkImageSubresourceRange subresourceRange;
|
||||
VkImageLayout oldLayout;
|
||||
VkImageLayout newLayout;
|
||||
@@ -1101,6 +1105,7 @@ public:
|
||||
PipelineLayoutData *pipeLayoutInfo; // only for pipeline layouts
|
||||
DescriptorSetData *descInfo; // only for descriptor sets and descriptor set layouts
|
||||
DescUpdateTemplate *descTemplateInfo; // only for descriptor update templates
|
||||
uint32_t queueFamilyIndex; // only for queues
|
||||
};
|
||||
|
||||
VkResourceRecord *bakedCommands;
|
||||
@@ -1193,6 +1198,7 @@ struct ImageLayouts
|
||||
extent.width = extent.height = extent.depth = 1;
|
||||
}
|
||||
|
||||
uint32_t queueFamilyIndex = 0;
|
||||
vector<ImageRegionState> subresourceStates;
|
||||
int layerCount, levelCount, sampleCount;
|
||||
VkExtent3D extent;
|
||||
|
||||
@@ -610,7 +610,7 @@ void DoSerialise(SerialiserType &ser, VkPhysicalDeviceSparseProperties &el)
|
||||
template <typename SerialiserType>
|
||||
void DoSerialise(SerialiserType &ser, VkQueueFamilyProperties &el)
|
||||
{
|
||||
SERIALISE_MEMBER(queueFlags);
|
||||
SERIALISE_MEMBER_TYPED(VkQueueFlagBits, queueFlags);
|
||||
SERIALISE_MEMBER(queueCount);
|
||||
SERIALISE_MEMBER(timestampValidBits);
|
||||
SERIALISE_MEMBER(minImageTransferGranularity);
|
||||
@@ -2132,9 +2132,19 @@ void DoSerialise(SerialiserType &ser, VkSwapchainCreateInfoKHR &el)
|
||||
SERIALISE_MEMBER(imageUsage);
|
||||
SERIALISE_MEMBER(imageSharingMode);
|
||||
|
||||
// SHARING: queueFamilyCount, pQueueFamilyIndices
|
||||
SERIALISE_MEMBER_EMPTY(queueFamilyIndexCount);
|
||||
SERIALISE_MEMBER_ARRAY_EMPTY(pQueueFamilyIndices);
|
||||
// pQueueFamilyIndices should *only* be read if the sharing mode is concurrent, and if the capture
|
||||
// is new (old captures always ignored these fields)
|
||||
if(ser.VersionAtLeast(0xD) && el.imageSharingMode == VK_SHARING_MODE_CONCURRENT)
|
||||
{
|
||||
SERIALISE_MEMBER(queueFamilyIndexCount);
|
||||
SERIALISE_MEMBER_ARRAY(pQueueFamilyIndices, queueFamilyIndexCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
// otherwise do a dummy serialise so the struct is the same either way
|
||||
SERIALISE_MEMBER_EMPTY(queueFamilyIndexCount);
|
||||
SERIALISE_MEMBER_ARRAY_EMPTY(pQueueFamilyIndices);
|
||||
}
|
||||
|
||||
SERIALISE_MEMBER(preTransform);
|
||||
SERIALISE_MEMBER(compositeAlpha);
|
||||
@@ -2189,6 +2199,11 @@ void DoSerialise(SerialiserType &ser, DescriptorSetSlot &el)
|
||||
template <typename SerialiserType>
|
||||
void DoSerialise(SerialiserType &ser, ImageRegionState &el)
|
||||
{
|
||||
if(ser.VersionAtLeast(0xD))
|
||||
{
|
||||
// added in 0xD
|
||||
SERIALISE_MEMBER(dstQueueFamilyIndex);
|
||||
}
|
||||
SERIALISE_MEMBER(subresourceRange);
|
||||
SERIALISE_MEMBER(oldLayout);
|
||||
SERIALISE_MEMBER(newLayout);
|
||||
@@ -2197,6 +2212,11 @@ void DoSerialise(SerialiserType &ser, ImageRegionState &el)
|
||||
template <typename SerialiserType>
|
||||
void DoSerialise(SerialiserType &ser, ImageLayouts &el)
|
||||
{
|
||||
if(ser.VersionAtLeast(0xD))
|
||||
{
|
||||
// added in 0xD
|
||||
SERIALISE_MEMBER(queueFamilyIndex);
|
||||
}
|
||||
SERIALISE_MEMBER(subresourceStates);
|
||||
SERIALISE_MEMBER(layerCount);
|
||||
SERIALISE_MEMBER(levelCount);
|
||||
|
||||
@@ -361,6 +361,9 @@ bool WrappedVulkan::Serialise_vkCreateCommandPool(SerialiserType &ser, VkDevice
|
||||
{
|
||||
VkCommandPool pool = VK_NULL_HANDLE;
|
||||
|
||||
// remap the queue family index
|
||||
CreateInfo.queueFamilyIndex = m_QueueRemapping[CreateInfo.queueFamilyIndex][0].family;
|
||||
|
||||
VkResult ret = ObjDisp(device)->CreateCommandPool(Unwrap(device), &CreateInfo, NULL, &pool);
|
||||
|
||||
if(ret != VK_SUCCESS)
|
||||
@@ -677,10 +680,6 @@ bool WrappedVulkan::Serialise_vkBeginCommandBuffer(SerialiserType &ser, VkComman
|
||||
|
||||
if(rerecord)
|
||||
{
|
||||
// pull all re-recorded commands from our own device and command pool for easier cleanup
|
||||
device = GetDev();
|
||||
AllocateInfo.commandPool = m_InternalCmds.cmdpool;
|
||||
|
||||
VkCommandBuffer cmd = VK_NULL_HANDLE;
|
||||
VkCommandBufferAllocateInfo unwrappedInfo = AllocateInfo;
|
||||
unwrappedInfo.commandPool = Unwrap(unwrappedInfo.commandPool);
|
||||
@@ -708,7 +707,7 @@ bool WrappedVulkan::Serialise_vkBeginCommandBuffer(SerialiserType &ser, VkComman
|
||||
m_RerecordCmds[BakedCommandBuffer] = cmd;
|
||||
m_RerecordCmds[m_LastCmdBufferID] = cmd;
|
||||
|
||||
m_RerecordCmdList.push_back(cmd);
|
||||
m_RerecordCmdList.push_back({AllocateInfo.commandPool, cmd});
|
||||
|
||||
m_BakedCmdBufferInfo[GetResID(cmd)].level = AllocateInfo.level;
|
||||
m_BakedCmdBufferInfo[GetResID(cmd)].beginFlags = BeginInfo.flags;
|
||||
@@ -2079,6 +2078,9 @@ bool WrappedVulkan::Serialise_vkCmdPipelineBarrier(
|
||||
{
|
||||
bufBarriers.push_back(pBufferMemoryBarriers[i]);
|
||||
bufBarriers.back().buffer = Unwrap(bufBarriers.back().buffer);
|
||||
|
||||
RemapQueueFamilyIndices(bufBarriers.back().srcQueueFamilyIndex,
|
||||
bufBarriers.back().dstQueueFamilyIndex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2093,8 +2095,8 @@ bool WrappedVulkan::Serialise_vkCmdPipelineBarrier(
|
||||
ReplacePresentableImageLayout(imgBarriers.back().oldLayout);
|
||||
ReplacePresentableImageLayout(imgBarriers.back().newLayout);
|
||||
|
||||
ReplaceExternalQueueFamily(imgBarriers.back().srcQueueFamilyIndex,
|
||||
imgBarriers.back().dstQueueFamilyIndex);
|
||||
RemapQueueFamilyIndices(imgBarriers.back().srcQueueFamilyIndex,
|
||||
imgBarriers.back().dstQueueFamilyIndex);
|
||||
|
||||
if(IsLoading(m_State))
|
||||
{
|
||||
@@ -2518,10 +2520,13 @@ bool WrappedVulkan::Serialise_vkCmdExecuteCommands(SerialiserType &ser, VkComman
|
||||
->CmdExecuteCommands(Unwrap(commandBuffer), commandBufferCount,
|
||||
UnwrapArray(pCommandBuffers, commandBufferCount));
|
||||
|
||||
// apply barriers
|
||||
// merge barriers into parent command buffer
|
||||
for(uint32_t i = 0; i < commandBufferCount; i++)
|
||||
GetResourceManager()->ApplyBarriers(
|
||||
m_BakedCmdBufferInfo[GetResID(pCommandBuffers[i])].imgbarriers, m_ImageLayouts);
|
||||
{
|
||||
GetResourceManager()->MergeBarriers(
|
||||
m_BakedCmdBufferInfo[GetResID(commandBuffer)].imgbarriers,
|
||||
m_BakedCmdBufferInfo[GetResID(pCommandBuffers[i])].imgbarriers);
|
||||
}
|
||||
|
||||
AddEvent();
|
||||
|
||||
@@ -2702,8 +2707,9 @@ bool WrappedVulkan::Serialise_vkCmdExecuteCommands(SerialiserType &ser, VkComman
|
||||
#endif
|
||||
rerecordedCmds.push_back(Unwrap(cmd));
|
||||
|
||||
GetResourceManager()->ApplyBarriers(m_BakedCmdBufferInfo[rerecord].imgbarriers,
|
||||
m_ImageLayouts);
|
||||
GetResourceManager()->MergeBarriers(
|
||||
m_BakedCmdBufferInfo[GetResID(commandBuffer)].imgbarriers,
|
||||
m_BakedCmdBufferInfo[rerecord].imgbarriers);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -42,6 +42,31 @@ static VkApplicationInfo renderdocAppInfo = {
|
||||
VK_API_VERSION_1_0,
|
||||
};
|
||||
|
||||
// we store the index in the loader table, since it won't be dereferenced and other parts of the
|
||||
// code expect to copy it into a wrapped object
|
||||
static VkPhysicalDevice MakePhysicalDeviceHandleFromIndex(uint32_t physDeviceIndex)
|
||||
{
|
||||
static uintptr_t loaderTable(0x100 + physDeviceIndex);
|
||||
return VkPhysicalDevice(&loaderTable);
|
||||
}
|
||||
|
||||
static uint32_t GetPhysicalDeviceIndexFromHandle(VkPhysicalDevice physicalDevice)
|
||||
{
|
||||
return uint32_t((uintptr_t)LayerDisp(physicalDevice) - 0x100);
|
||||
}
|
||||
|
||||
static bool CheckTransferGranularity(VkExtent3D required, VkExtent3D check)
|
||||
{
|
||||
// if the required granularity is (0,0,0) then any is fine - the requirement is always satisfied.
|
||||
if(required.width == required.height && required.height == required.depth && required.depth == 0)
|
||||
return true;
|
||||
|
||||
// otherwise, each dimension must be <= the required dimension (i.e. more fine-grained) to support
|
||||
// any copies we might do.
|
||||
return check.width <= required.width && check.height <= required.height &&
|
||||
check.depth <= required.depth;
|
||||
}
|
||||
|
||||
// vk_dispatchtables.cpp
|
||||
void InitDeviceTable(VkDevice dev, PFN_vkGetDeviceProcAddr gpa);
|
||||
void InitInstanceTable(VkInstance inst, PFN_vkGetInstanceProcAddr gpa);
|
||||
@@ -292,7 +317,7 @@ ReplayStatus WrappedVulkan::Initialise(VkInitParams ¶ms, uint64_t sectionVer
|
||||
m_PhysicalDevice = VK_NULL_HANDLE;
|
||||
m_Device = VK_NULL_HANDLE;
|
||||
m_QueueFamilyIdx = ~0U;
|
||||
m_Queue = VK_NULL_HANDLE;
|
||||
m_PrevQueue = m_Queue = VK_NULL_HANDLE;
|
||||
m_InternalCmds.Reset();
|
||||
|
||||
if(ObjDisp(m_Instance)->CreateDebugReportCallbackEXT)
|
||||
@@ -483,7 +508,7 @@ VkResult WrappedVulkan::vkCreateInstance(const VkInstanceCreateInfo *pCreateInfo
|
||||
m_PhysicalDevice = VK_NULL_HANDLE;
|
||||
m_Device = VK_NULL_HANDLE;
|
||||
m_QueueFamilyIdx = ~0U;
|
||||
m_Queue = VK_NULL_HANDLE;
|
||||
m_PrevQueue = m_Queue = VK_NULL_HANDLE;
|
||||
m_InternalCmds.Reset();
|
||||
|
||||
if(ObjDisp(m_Instance)->CreateDebugReportCallbackEXT)
|
||||
@@ -540,6 +565,14 @@ void WrappedVulkan::Shutdown()
|
||||
GetResourceManager()->ReleaseWrappedResource(m_InternalCmds.freesems[i]);
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < m_ExternalQueues.size(); i++)
|
||||
{
|
||||
GetResourceManager()->ReleaseWrappedResource(m_ExternalQueues[i].buffer);
|
||||
|
||||
ObjDisp(m_Device)->DestroyCommandPool(Unwrap(m_Device), Unwrap(m_ExternalQueues[i].pool), NULL);
|
||||
GetResourceManager()->ReleaseWrappedResource(m_ExternalQueues[i].pool);
|
||||
}
|
||||
|
||||
FreeAllMemory(MemoryScope::InitialContents);
|
||||
|
||||
// we do more in Shutdown than the equivalent vkDestroyInstance since on replay there's
|
||||
@@ -626,7 +659,7 @@ bool WrappedVulkan::Serialise_vkEnumeratePhysicalDevices(SerialiserType &ser, Vk
|
||||
VkPhysicalDeviceMemoryProperties memProps;
|
||||
VkPhysicalDeviceFeatures physFeatures;
|
||||
uint32_t queueCount = 0;
|
||||
VkQueueFamilyProperties queueProps[16];
|
||||
VkQueueFamilyProperties queueProps[16] = {};
|
||||
|
||||
if(ser.IsWriting())
|
||||
{
|
||||
@@ -641,7 +674,7 @@ bool WrappedVulkan::Serialise_vkEnumeratePhysicalDevices(SerialiserType &ser, Vk
|
||||
|
||||
if(queueCount > 16)
|
||||
{
|
||||
RDCWARN("More than 16 queues");
|
||||
RDCERR("More than 16 queue families");
|
||||
queueCount = 16;
|
||||
}
|
||||
|
||||
@@ -676,6 +709,9 @@ bool WrappedVulkan::Serialise_vkEnumeratePhysicalDevices(SerialiserType &ser, Vk
|
||||
m_OriginalPhysicalDevices[PhysicalDeviceIndex].props = physProps;
|
||||
m_OriginalPhysicalDevices[PhysicalDeviceIndex].memProps = memProps;
|
||||
m_OriginalPhysicalDevices[PhysicalDeviceIndex].features = physFeatures;
|
||||
m_OriginalPhysicalDevices[PhysicalDeviceIndex].queueCount = queueCount;
|
||||
memcpy(m_OriginalPhysicalDevices[PhysicalDeviceIndex].queueProps, queueProps,
|
||||
sizeof(queueProps));
|
||||
}
|
||||
|
||||
// match up physical devices to those available on replay as best as possible. In general
|
||||
@@ -754,11 +790,25 @@ bool WrappedVulkan::Serialise_vkEnumeratePhysicalDevices(SerialiserType &ser, Vk
|
||||
|
||||
pd = m_ReplayPhysicalDevices[bestIdx];
|
||||
|
||||
if(!m_ReplayPhysicalDevicesUsed[bestIdx])
|
||||
GetResourceManager()->AddLiveResource(PhysicalDevice, pd);
|
||||
else
|
||||
GetResourceManager()->ReplaceResource(PhysicalDevice,
|
||||
GetResourceManager()->GetOriginalID(GetResID(pd)));
|
||||
{
|
||||
VkPhysicalDevice fakeDevice = MakePhysicalDeviceHandleFromIndex(PhysicalDeviceIndex);
|
||||
|
||||
ResourceId id = ResourceIDGen::GetNewUniqueID();
|
||||
WrappedVkPhysicalDevice *wrapped = new WrappedVkPhysicalDevice(fakeDevice, id);
|
||||
|
||||
GetResourceManager()->AddCurrentResource(id, wrapped);
|
||||
|
||||
if(IsReplayMode(m_State))
|
||||
GetResourceManager()->AddWrapper(wrapped, ToTypedHandle(fakeDevice));
|
||||
|
||||
fakeDevice = (VkPhysicalDevice)wrapped;
|
||||
|
||||
// we want to preserve the separate physical devices until we actually need the real handle,
|
||||
// so don't remap multiple capture-time physical devices to one replay-time physical device
|
||||
// yet. See below in Serialise_vkCreateDevice where this is decoded.
|
||||
// Note this allocation is pooled so we don't have to explicitly delete it.
|
||||
GetResourceManager()->AddLiveResource(PhysicalDevice, fakeDevice);
|
||||
}
|
||||
|
||||
AddResource(PhysicalDevice, ResourceType::Device, "Physical Device");
|
||||
DerivedResource(m_Instance, PhysicalDevice);
|
||||
@@ -810,7 +860,6 @@ VkResult WrappedVulkan::vkEnumeratePhysicalDevices(VkInstance instance,
|
||||
RDCASSERTEQUAL(vkr, VK_SUCCESS);
|
||||
|
||||
m_PhysicalDevices.resize(count);
|
||||
m_SupportedQueueFamilies.resize(count);
|
||||
|
||||
for(uint32_t i = 0; i < count; i++)
|
||||
{
|
||||
@@ -863,92 +912,6 @@ VkResult WrappedVulkan::vkEnumeratePhysicalDevices(VkInstance instance,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// find the queue with the most bits set and only report that one
|
||||
|
||||
{
|
||||
uint32_t queuecount = 0;
|
||||
ObjDisp(m_PhysicalDevices[i])
|
||||
->GetPhysicalDeviceQueueFamilyProperties(Unwrap(m_PhysicalDevices[i]), &queuecount, NULL);
|
||||
|
||||
VkQueueFamilyProperties *props = new VkQueueFamilyProperties[queuecount];
|
||||
ObjDisp(m_PhysicalDevices[i])
|
||||
->GetPhysicalDeviceQueueFamilyProperties(Unwrap(m_PhysicalDevices[i]), &queuecount, props);
|
||||
|
||||
uint32_t best = 0;
|
||||
|
||||
// don't need to explicitly check for transfer, because graphics bit
|
||||
// implies it. We do have to check for compute bit, because there might
|
||||
// be a graphics only queue - it just means we have to keep looking
|
||||
// to find the grpahics & compute queue family which is guaranteed.
|
||||
for(uint32_t q = 1; q < queuecount; q++)
|
||||
{
|
||||
// compare current against the known best
|
||||
VkQueueFamilyProperties ¤tProps = props[q];
|
||||
VkQueueFamilyProperties &bestProps = props[best];
|
||||
|
||||
const bool currentGraphics = (currentProps.queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0;
|
||||
const bool currentCompute = (currentProps.queueFlags & VK_QUEUE_COMPUTE_BIT) != 0;
|
||||
const bool currentSparse = (currentProps.queueFlags & VK_QUEUE_SPARSE_BINDING_BIT) != 0;
|
||||
|
||||
const bool bestGraphics = (bestProps.queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0;
|
||||
const bool bestCompute = (bestProps.queueFlags & VK_QUEUE_COMPUTE_BIT) != 0;
|
||||
const bool bestSparse = (bestProps.queueFlags & VK_QUEUE_SPARSE_BINDING_BIT) != 0;
|
||||
|
||||
// if one has graphics bit set, but the other doesn't
|
||||
if(currentGraphics != bestGraphics)
|
||||
{
|
||||
// if current has graphics but best doesn't, we have a new best
|
||||
if(currentGraphics)
|
||||
best = q;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(currentCompute != bestCompute)
|
||||
{
|
||||
// if current has compute but best doesn't, we have a new best
|
||||
if(currentCompute)
|
||||
best = q;
|
||||
continue;
|
||||
}
|
||||
|
||||
// if we've gotten here, both best and current have graphics and compute. Check
|
||||
// to see if the current is somehow better than best (in the case of a tie, we
|
||||
// keep the lower index of queue).
|
||||
|
||||
if(currentSparse != bestSparse)
|
||||
{
|
||||
if(currentSparse)
|
||||
best = q;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(currentProps.timestampValidBits != bestProps.timestampValidBits)
|
||||
{
|
||||
if(currentProps.timestampValidBits > bestProps.timestampValidBits)
|
||||
best = q;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(currentProps.minImageTransferGranularity.width <
|
||||
bestProps.minImageTransferGranularity.width ||
|
||||
currentProps.minImageTransferGranularity.height <
|
||||
bestProps.minImageTransferGranularity.height ||
|
||||
currentProps.minImageTransferGranularity.depth <
|
||||
bestProps.minImageTransferGranularity.depth)
|
||||
{
|
||||
best = q;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// only report a single available queue in this family
|
||||
props[best].queueCount = 1;
|
||||
|
||||
m_SupportedQueueFamilies[i] = std::make_pair(best, props[best]);
|
||||
|
||||
SAFE_DELETE_ARRAY(props);
|
||||
}
|
||||
}
|
||||
|
||||
if(pPhysicalDeviceCount)
|
||||
@@ -971,12 +934,25 @@ bool WrappedVulkan::Serialise_vkCreateDevice(SerialiserType &ser, VkPhysicalDevi
|
||||
SERIALISE_ELEMENT_LOCAL(CreateInfo, *pCreateInfo);
|
||||
SERIALISE_ELEMENT_OPT(pAllocator);
|
||||
SERIALISE_ELEMENT_LOCAL(Device, GetResID(*pDevice)).TypedAs("VkDevice");
|
||||
SERIALISE_ELEMENT(m_SupportedQueueFamily).Hidden();
|
||||
|
||||
if(ser.VersionLess(0xD))
|
||||
{
|
||||
uint32_t supportedQueueFamily; // no longer used
|
||||
SERIALISE_ELEMENT(supportedQueueFamily).Hidden();
|
||||
}
|
||||
|
||||
SERIALISE_CHECK_READ_ERRORS();
|
||||
|
||||
if(IsReplayingAndReading())
|
||||
{
|
||||
// kept around only to call DerivedResource below, as this is the resource that actually has an
|
||||
// original resource ID.
|
||||
VkPhysicalDevice origPhysDevice = physicalDevice;
|
||||
|
||||
// see above in Serialise_vkEnumeratePhysicalDevices where this is encoded
|
||||
uint32_t physicalDeviceIndex = GetPhysicalDeviceIndexFromHandle(Unwrap(physicalDevice));
|
||||
physicalDevice = m_ReplayPhysicalDevices[physicalDeviceIndex];
|
||||
|
||||
// we must make any modifications locally, so the free of pointers
|
||||
// in the serialised VkDeviceCreateInfo don't double-free
|
||||
VkDeviceCreateInfo createInfo = CreateInfo;
|
||||
@@ -1099,18 +1075,224 @@ bool WrappedVulkan::Serialise_vkCreateDevice(SerialiserType &ser, VkPhysicalDevi
|
||||
uint32_t qCount = 0;
|
||||
ObjDisp(physicalDevice)->GetPhysicalDeviceQueueFamilyProperties(Unwrap(physicalDevice), &qCount, NULL);
|
||||
|
||||
VkQueueFamilyProperties *props = new VkQueueFamilyProperties[qCount];
|
||||
if(qCount > 16)
|
||||
{
|
||||
RDCERR("Unexpected number of queue families: %u", qCount);
|
||||
qCount = 16;
|
||||
}
|
||||
|
||||
VkQueueFamilyProperties props[16] = {};
|
||||
ObjDisp(physicalDevice)
|
||||
->GetPhysicalDeviceQueueFamilyProperties(Unwrap(physicalDevice), &qCount, props);
|
||||
|
||||
// to aid the search algorithm below, we apply implied transfer bit onto the queue properties.
|
||||
for(uint32_t i = 0; i < qCount; i++)
|
||||
{
|
||||
if(props[i].queueFlags & (VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT))
|
||||
props[i].queueFlags |= VK_QUEUE_TRANSFER_BIT;
|
||||
}
|
||||
|
||||
PhysicalDeviceData &origData = m_OriginalPhysicalDevices[physicalDeviceIndex];
|
||||
|
||||
uint32_t origQCount = origData.queueCount;
|
||||
VkQueueFamilyProperties *origprops = origData.queueProps;
|
||||
|
||||
// create queue remapping
|
||||
for(uint32_t origQIndex = 0; origQIndex < origQCount; origQIndex++)
|
||||
{
|
||||
m_QueueRemapping[origQIndex].resize(origprops[origQIndex].queueCount);
|
||||
RDCLOG("Capture describes queue family %u:", origQIndex);
|
||||
RDCLOG(" - %u queues available with %s", origprops[origQIndex].queueCount,
|
||||
ToStr(VkQueueFlagBits(origprops[origQIndex].queueFlags)).c_str());
|
||||
RDCLOG(" %u timestamp bits (%u,%u,%u) granularity",
|
||||
origprops[origQIndex].timestampValidBits,
|
||||
origprops[origQIndex].minImageTransferGranularity.width,
|
||||
origprops[origQIndex].minImageTransferGranularity.height,
|
||||
origprops[origQIndex].minImageTransferGranularity.depth);
|
||||
|
||||
// find the best queue family to map to. We try and find the closest match that is at least
|
||||
// good enough. We want to try and preserve families that were separate before but we need to
|
||||
// ensure the remapped queue family is at least as good as it was at capture time.
|
||||
uint32_t destFamily = 0;
|
||||
|
||||
{
|
||||
// we categorise the original queue as one of four types: universal
|
||||
// (graphics/compute/transfer), graphics/transfer only (rare), compute-only
|
||||
// (compute/transfer) or transfer-only (transfer). We try first to find an exact match, then
|
||||
// move progressively up the priority list to find a broader and broader match.
|
||||
// We don't care about sparse binding - it's just treated as a requirement.
|
||||
enum class SearchType
|
||||
{
|
||||
Failed,
|
||||
Universal,
|
||||
GraphicsTransfer,
|
||||
ComputeTransfer,
|
||||
GraphicsOrComputeTransfer,
|
||||
TransferOnly,
|
||||
} search;
|
||||
|
||||
VkQueueFlags mask = (VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT);
|
||||
|
||||
switch(origprops[origQIndex].queueFlags & mask)
|
||||
{
|
||||
case VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT:
|
||||
case VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT:
|
||||
search = SearchType::Universal;
|
||||
break;
|
||||
case VK_QUEUE_GRAPHICS_BIT:
|
||||
case VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_TRANSFER_BIT:
|
||||
search = SearchType::GraphicsTransfer;
|
||||
break;
|
||||
case VK_QUEUE_COMPUTE_BIT:
|
||||
case VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT:
|
||||
search = SearchType::ComputeTransfer;
|
||||
break;
|
||||
case VK_QUEUE_TRANSFER_BIT: search = SearchType::TransferOnly; break;
|
||||
default:
|
||||
search = SearchType::Failed;
|
||||
RDCERR("Unexpected set of flags: %s",
|
||||
ToStr(VkQueueFlagBits(origprops[origQIndex].queueFlags & mask)).c_str());
|
||||
break;
|
||||
}
|
||||
|
||||
bool needSparse = (origprops[origQIndex].queueFlags & VK_QUEUE_SPARSE_BINDING_BIT) != 0;
|
||||
VkExtent3D needGranularity = origprops[origQIndex].minImageTransferGranularity;
|
||||
|
||||
while(search != SearchType::Failed)
|
||||
{
|
||||
bool found = false;
|
||||
|
||||
for(uint32_t replayQIndex = 0; replayQIndex < qCount; replayQIndex++)
|
||||
{
|
||||
// ignore queues that couldn't satisfy the required transfer granularity
|
||||
if(!CheckTransferGranularity(needGranularity,
|
||||
props[replayQIndex].minImageTransferGranularity))
|
||||
continue;
|
||||
|
||||
// ignore queues that don't have sparse binding, if we need that
|
||||
if(needSparse && ((props[replayQIndex].queueFlags & VK_QUEUE_SPARSE_BINDING_BIT) == 0))
|
||||
continue;
|
||||
|
||||
switch(search)
|
||||
{
|
||||
case SearchType::Failed: break;
|
||||
case SearchType::Universal:
|
||||
if((props[replayQIndex].queueFlags & mask) ==
|
||||
(VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT))
|
||||
{
|
||||
destFamily = replayQIndex;
|
||||
found = true;
|
||||
}
|
||||
break;
|
||||
case SearchType::GraphicsTransfer:
|
||||
if((props[replayQIndex].queueFlags & mask) ==
|
||||
(VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_TRANSFER_BIT))
|
||||
{
|
||||
destFamily = replayQIndex;
|
||||
found = true;
|
||||
}
|
||||
break;
|
||||
case SearchType::ComputeTransfer:
|
||||
if((props[replayQIndex].queueFlags & mask) ==
|
||||
(VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT))
|
||||
{
|
||||
destFamily = replayQIndex;
|
||||
found = true;
|
||||
}
|
||||
break;
|
||||
case SearchType::GraphicsOrComputeTransfer:
|
||||
if((props[replayQIndex].queueFlags & mask) ==
|
||||
(VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT) ||
|
||||
(props[replayQIndex].queueFlags & mask) ==
|
||||
(VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_TRANSFER_BIT))
|
||||
{
|
||||
destFamily = replayQIndex;
|
||||
found = true;
|
||||
}
|
||||
break;
|
||||
case SearchType::TransferOnly:
|
||||
if((props[replayQIndex].queueFlags & mask) == VK_QUEUE_TRANSFER_BIT)
|
||||
{
|
||||
destFamily = replayQIndex;
|
||||
found = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if(found)
|
||||
break;
|
||||
}
|
||||
|
||||
if(found)
|
||||
break;
|
||||
|
||||
// no such queue family found, fall back to the next type of queue to search for
|
||||
switch(search)
|
||||
{
|
||||
case SearchType::Failed: break;
|
||||
case SearchType::Universal: search = SearchType::Failed; break;
|
||||
case SearchType::GraphicsTransfer:
|
||||
case SearchType::ComputeTransfer:
|
||||
case SearchType::GraphicsOrComputeTransfer:
|
||||
// if we didn't find a graphics or compute (and transfer) queue, we have to look for a
|
||||
// universal one
|
||||
search = SearchType::Universal;
|
||||
break;
|
||||
case SearchType::TransferOnly:
|
||||
// when falling back from looking for a transfer-only queue, we consider either
|
||||
// graphics-only or compute-only as better candidates before universal
|
||||
search = SearchType::GraphicsOrComputeTransfer;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RDCLOG("Remapping to queue family %u:", destFamily);
|
||||
RDCLOG(" - %u queues available with %s", props[destFamily].queueCount,
|
||||
ToStr(VkQueueFlagBits(props[destFamily].queueFlags)).c_str());
|
||||
RDCLOG(" %u timestamp bits (%u,%u,%u) granularity", props[destFamily].timestampValidBits,
|
||||
props[destFamily].minImageTransferGranularity.width,
|
||||
props[destFamily].minImageTransferGranularity.height,
|
||||
props[destFamily].minImageTransferGranularity.depth);
|
||||
|
||||
// loop over the queues, wrapping around if necessary to provide enough queues. The idea being
|
||||
// an application is more likely to use early queues than later ones, so if there aren't
|
||||
// enough queues in the family then we should prioritise giving unique queues to the early
|
||||
// indices
|
||||
for(uint32_t q = 0; q < origprops[origQIndex].queueCount; q++)
|
||||
{
|
||||
m_QueueRemapping[origQIndex][q] = {destFamily, q % props[destFamily].queueCount};
|
||||
}
|
||||
}
|
||||
|
||||
// now apply the remapping to the requested queues
|
||||
for(uint32_t i = 0; i < createInfo.queueCreateInfoCount; i++)
|
||||
{
|
||||
VkDeviceQueueCreateInfo &queueCreate =
|
||||
(VkDeviceQueueCreateInfo &)createInfo.pQueueCreateInfos[i];
|
||||
|
||||
uint32_t queueFamily = queueCreate.queueFamilyIndex;
|
||||
queueFamily = m_QueueRemapping[queueFamily][0].family;
|
||||
queueCreate.queueFamilyIndex = queueFamily;
|
||||
uint32_t queueCount = RDCMIN(queueCreate.queueCount, props[queueFamily].queueCount);
|
||||
|
||||
if(queueCount < queueCreate.queueCount)
|
||||
RDCWARN("Truncating queue family request from %u queues to %u queues",
|
||||
queueCreate.queueCount, queueCount);
|
||||
|
||||
queueCreate.queueCount = queueCount;
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
uint32_t qFamilyIdx = 0;
|
||||
VkQueueFlags search = (VK_QUEUE_GRAPHICS_BIT);
|
||||
|
||||
// we need graphics, and if there is a graphics queue there must be a graphics & compute queue.
|
||||
VkQueueFlags search = (VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT);
|
||||
|
||||
// for queue priorities, if we need it
|
||||
float one = 1.0f;
|
||||
|
||||
// if we need to change the requested queues, it will point to this
|
||||
// if we need to add a new requested queues, it will point to this
|
||||
VkDeviceQueueCreateInfo *modQueues = NULL;
|
||||
|
||||
for(uint32_t i = 0; i < createInfo.queueCreateInfoCount; i++)
|
||||
@@ -1144,7 +1326,6 @@ bool WrappedVulkan::Serialise_vkCreateDevice(SerialiserType &ser, VkPhysicalDevi
|
||||
|
||||
if(!found)
|
||||
{
|
||||
SAFE_DELETE_ARRAY(props);
|
||||
RDCERR(
|
||||
"Can't add a queue with required properties for RenderDoc! Unsupported configuration");
|
||||
}
|
||||
@@ -1164,8 +1345,6 @@ bool WrappedVulkan::Serialise_vkCreateDevice(SerialiserType &ser, VkPhysicalDevi
|
||||
}
|
||||
}
|
||||
|
||||
SAFE_DELETE_ARRAY(props);
|
||||
|
||||
VkPhysicalDeviceFeatures enabledFeatures = {0};
|
||||
if(createInfo.pEnabledFeatures != NULL)
|
||||
enabledFeatures = *createInfo.pEnabledFeatures;
|
||||
@@ -1323,7 +1502,7 @@ bool WrappedVulkan::Serialise_vkCreateDevice(SerialiserType &ser, VkPhysicalDevi
|
||||
GetResourceManager()->AddLiveResource(Device, device);
|
||||
|
||||
AddResource(Device, ResourceType::Device, "Device");
|
||||
DerivedResource(physicalDevice, Device);
|
||||
DerivedResource(origPhysDevice, Device);
|
||||
|
||||
InstanceDeviceInfo extInfo;
|
||||
|
||||
@@ -1379,6 +1558,9 @@ bool WrappedVulkan::Serialise_vkCreateDevice(SerialiserType &ser, VkPhysicalDevi
|
||||
->GetPhysicalDeviceFormatProperties(Unwrap(physicalDevice), VkFormat(i),
|
||||
&m_PhysicalDeviceData.fmtprops[i]);
|
||||
|
||||
m_PhysicalDeviceData.queueCount = qCount;
|
||||
memcpy(m_PhysicalDeviceData.queueProps, props, qCount * sizeof(VkQueueFamilyProperties));
|
||||
|
||||
m_PhysicalDeviceData.readbackMemIndex =
|
||||
m_PhysicalDeviceData.GetMemoryIndex(~0U, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, 0);
|
||||
m_PhysicalDeviceData.uploadMemIndex =
|
||||
@@ -1428,7 +1610,9 @@ VkResult WrappedVulkan::vkCreateDevice(VkPhysicalDevice physicalDevice,
|
||||
// find a queue that supports all capabilities, and if one doesn't exist, add it.
|
||||
bool found = false;
|
||||
uint32_t qFamilyIdx = 0;
|
||||
VkQueueFlags search = (VK_QUEUE_GRAPHICS_BIT);
|
||||
|
||||
// we need graphics, and if there is a graphics queue there must be a graphics & compute queue.
|
||||
VkQueueFlags search = (VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT);
|
||||
|
||||
// for queue priorities, if we need it
|
||||
float one = 1.0f;
|
||||
@@ -1485,25 +1669,21 @@ VkResult WrappedVulkan::vkCreateDevice(VkPhysicalDevice physicalDevice,
|
||||
createInfo.queueCreateInfoCount++;
|
||||
}
|
||||
|
||||
SAFE_DELETE_ARRAY(props);
|
||||
|
||||
m_QueueFamilies.resize(createInfo.queueCreateInfoCount);
|
||||
m_QueueFamilyCounts.resize(createInfo.queueCreateInfoCount);
|
||||
for(size_t i = 0; i < createInfo.queueCreateInfoCount; i++)
|
||||
{
|
||||
uint32_t family = createInfo.pQueueCreateInfos[i].queueFamilyIndex;
|
||||
uint32_t count = createInfo.pQueueCreateInfos[i].queueCount;
|
||||
m_QueueFamilies.resize(RDCMAX(m_QueueFamilies.size(), size_t(family + 1)));
|
||||
m_QueueFamilyCounts.resize(RDCMAX(m_QueueFamilies.size(), size_t(family + 1)));
|
||||
|
||||
m_QueueFamilies[family] = new VkQueue[count];
|
||||
m_QueueFamilyCounts[family] = count;
|
||||
for(uint32_t q = 0; q < count; q++)
|
||||
m_QueueFamilies[family][q] = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
// find the matching physical device
|
||||
for(size_t i = 0; i < m_PhysicalDevices.size(); i++)
|
||||
if(m_PhysicalDevices[i] == physicalDevice)
|
||||
m_SupportedQueueFamily = m_SupportedQueueFamilies[i].first;
|
||||
|
||||
VkLayerDeviceCreateInfo *layerCreateInfo = (VkLayerDeviceCreateInfo *)pCreateInfo->pNext;
|
||||
|
||||
// step through the chain of pNext until we get to the link info
|
||||
@@ -1516,6 +1696,7 @@ VkResult WrappedVulkan::vkCreateDevice(VkPhysicalDevice physicalDevice,
|
||||
|
||||
if(layerCreateInfo == NULL)
|
||||
{
|
||||
SAFE_DELETE_ARRAY(props);
|
||||
RDCERR("Couldn't find loader device create info, which is required. Incompatible loader?");
|
||||
return VK_ERROR_INITIALIZATION_FAILED;
|
||||
}
|
||||
@@ -1679,6 +1860,38 @@ VkResult WrappedVulkan::vkCreateDevice(VkPhysicalDevice physicalDevice,
|
||||
GetResourceManager()->WrapResource(Unwrap(device), m_InternalCmds.cmdpool);
|
||||
}
|
||||
|
||||
// for each queue family that isn't our own, create a command pool and command buffer on that
|
||||
// queue
|
||||
for(uint32_t i = 0; i < createInfo.queueCreateInfoCount; i++)
|
||||
{
|
||||
uint32_t qidx = createInfo.pQueueCreateInfos[i].queueFamilyIndex;
|
||||
m_ExternalQueues.resize(RDCMAX((uint32_t)m_ExternalQueues.size(), qidx + 1));
|
||||
|
||||
VkCommandPoolCreateInfo poolInfo = {
|
||||
VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, NULL,
|
||||
VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, qidx,
|
||||
};
|
||||
vkr = ObjDisp(device)->CreateCommandPool(Unwrap(device), &poolInfo, NULL,
|
||||
&m_ExternalQueues[qidx].pool);
|
||||
RDCASSERTEQUAL(vkr, VK_SUCCESS);
|
||||
|
||||
GetResourceManager()->WrapResource(Unwrap(device), m_ExternalQueues[qidx].pool);
|
||||
|
||||
VkCommandBufferAllocateInfo cmdInfo = {
|
||||
VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
|
||||
NULL,
|
||||
Unwrap(m_ExternalQueues[qidx].pool),
|
||||
VK_COMMAND_BUFFER_LEVEL_PRIMARY,
|
||||
1,
|
||||
};
|
||||
|
||||
vkr = ObjDisp(device)->AllocateCommandBuffers(Unwrap(device), &cmdInfo,
|
||||
&m_ExternalQueues[qidx].buffer);
|
||||
RDCASSERTEQUAL(vkr, VK_SUCCESS);
|
||||
|
||||
GetResourceManager()->WrapResource(Unwrap(device), m_ExternalQueues[qidx].buffer);
|
||||
}
|
||||
|
||||
ObjDisp(physicalDevice)
|
||||
->GetPhysicalDeviceProperties(Unwrap(physicalDevice), &m_PhysicalDeviceData.props);
|
||||
|
||||
@@ -1700,6 +1913,9 @@ VkResult WrappedVulkan::vkCreateDevice(VkPhysicalDevice physicalDevice,
|
||||
m_PhysicalDeviceData.GPULocalMemIndex = m_PhysicalDeviceData.GetMemoryIndex(
|
||||
~0U, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
|
||||
|
||||
m_PhysicalDeviceData.queueCount = qCount;
|
||||
memcpy(m_PhysicalDeviceData.queueProps, props, qCount * sizeof(VkQueueFamilyProperties));
|
||||
|
||||
m_PhysicalDeviceData.fakeMemProps = GetRecord(physicalDevice)->memProps;
|
||||
|
||||
m_ShaderCache = new VulkanShaderCache(this);
|
||||
@@ -1709,6 +1925,7 @@ VkResult WrappedVulkan::vkCreateDevice(VkPhysicalDevice physicalDevice,
|
||||
m_DebugManager = new VulkanDebugManager(this);
|
||||
}
|
||||
|
||||
SAFE_DELETE_ARRAY(props);
|
||||
SAFE_DELETE_ARRAY(modQueues);
|
||||
|
||||
return ret;
|
||||
@@ -1751,10 +1968,21 @@ void WrappedVulkan::vkDestroyDevice(VkDevice device, const VkAllocationCallbacks
|
||||
GetResourceManager()->ReleaseWrappedResource(m_InternalCmds.freesems[i]);
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < m_ExternalQueues.size(); i++)
|
||||
{
|
||||
if(m_ExternalQueues[i].buffer != VK_NULL_HANDLE)
|
||||
{
|
||||
GetResourceManager()->ReleaseWrappedResource(m_ExternalQueues[i].buffer);
|
||||
|
||||
ObjDisp(m_Device)->DestroyCommandPool(Unwrap(m_Device), Unwrap(m_ExternalQueues[i].pool), NULL);
|
||||
GetResourceManager()->ReleaseWrappedResource(m_ExternalQueues[i].pool);
|
||||
}
|
||||
}
|
||||
|
||||
m_InternalCmds.Reset();
|
||||
|
||||
m_QueueFamilyIdx = ~0U;
|
||||
m_Queue = VK_NULL_HANDLE;
|
||||
m_PrevQueue = m_Queue = VK_NULL_HANDLE;
|
||||
|
||||
// destroy the API device immediately. There should be no more
|
||||
// resources left in the resource manager device/physical device/instance.
|
||||
|
||||
@@ -87,17 +87,16 @@ void WrappedVulkan::vkGetPhysicalDeviceProperties(VkPhysicalDevice physicalDevic
|
||||
void WrappedVulkan::vkGetPhysicalDeviceQueueFamilyProperties(
|
||||
VkPhysicalDevice physicalDevice, uint32_t *pCount, VkQueueFamilyProperties *pQueueFamilyProperties)
|
||||
{
|
||||
// pretend to only have one queue, the one with graphics capability
|
||||
if(pCount)
|
||||
*pCount = 1;
|
||||
// report the actual physical device properties - this will be remapped on replay if necessary
|
||||
ObjDisp(physicalDevice)
|
||||
->GetPhysicalDeviceQueueFamilyProperties(Unwrap(physicalDevice), pCount,
|
||||
pQueueFamilyProperties);
|
||||
|
||||
if(pQueueFamilyProperties)
|
||||
// remove any protected bits that might be set
|
||||
if(pCount && pQueueFamilyProperties)
|
||||
{
|
||||
// find the matching physical device
|
||||
for(size_t i = 0; i < m_PhysicalDevices.size(); i++)
|
||||
if(m_PhysicalDevices[i] == physicalDevice)
|
||||
*pQueueFamilyProperties = m_SupportedQueueFamilies[i].second;
|
||||
return;
|
||||
for(uint32_t i = 0; i < *pCount; i++)
|
||||
pQueueFamilyProperties[i].queueFlags &= ~VK_QUEUE_PROTECTED_BIT;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -39,13 +39,20 @@ bool WrappedVulkan::Serialise_vkGetDeviceQueue(SerialiserType &ser, VkDevice dev
|
||||
if(IsReplayingAndReading())
|
||||
{
|
||||
VkQueue queue;
|
||||
// MULTIQUEUE - re-map the queue family/index instead of using the supported family
|
||||
ObjDisp(device)->GetDeviceQueue(Unwrap(device), m_SupportedQueueFamily, 0, &queue);
|
||||
|
||||
uint32_t remapFamily = m_QueueRemapping[queueFamilyIndex][queueIndex].family;
|
||||
uint32_t remapIndex = m_QueueRemapping[queueFamilyIndex][queueIndex].index;
|
||||
|
||||
if(remapFamily != queueFamilyIndex || remapIndex != queueIndex)
|
||||
RDCLOG("Remapped Queue %u/%u from capture to %u/%u on replay", queueFamilyIndex, queueIndex,
|
||||
remapFamily, remapIndex);
|
||||
|
||||
ObjDisp(device)->GetDeviceQueue(Unwrap(device), remapFamily, remapIndex, &queue);
|
||||
|
||||
GetResourceManager()->WrapResource(Unwrap(device), queue);
|
||||
GetResourceManager()->AddLiveResource(Queue, queue);
|
||||
|
||||
if(queueFamilyIndex == m_QueueFamilyIdx)
|
||||
if(remapFamily == m_QueueFamilyIdx && m_Queue == VK_NULL_HANDLE)
|
||||
{
|
||||
m_Queue = queue;
|
||||
|
||||
@@ -54,6 +61,8 @@ bool WrappedVulkan::Serialise_vkGetDeviceQueue(SerialiserType &ser, VkDevice dev
|
||||
SubmitCmds();
|
||||
}
|
||||
|
||||
m_CreationInfo.m_Queue[GetResID(queue)] = remapFamily;
|
||||
|
||||
AddResource(Queue, ResourceType::Queue, "Queue");
|
||||
DerivedResource(device, Queue);
|
||||
}
|
||||
@@ -101,6 +110,8 @@ void WrappedVulkan::vkGetDeviceQueue(VkDevice device, uint32_t queueFamilyIndex,
|
||||
VkResourceRecord *record = GetResourceManager()->AddResourceRecord(*pQueue);
|
||||
RDCASSERT(record);
|
||||
|
||||
record->queueFamilyIndex = queueFamilyIndex;
|
||||
|
||||
VkResourceRecord *instrecord = GetRecord(m_Instance);
|
||||
|
||||
// treat queues as pool members of the instance (ie. freed when the instance dies)
|
||||
@@ -115,6 +126,16 @@ void WrappedVulkan::vkGetDeviceQueue(VkDevice device, uint32_t queueFamilyIndex,
|
||||
|
||||
m_QueueFamilies[queueFamilyIndex][queueIndex] = *pQueue;
|
||||
|
||||
if(queueFamilyIndex < m_ExternalQueues.size())
|
||||
{
|
||||
if(m_ExternalQueues[queueFamilyIndex].queue == VK_NULL_HANDLE)
|
||||
m_ExternalQueues[queueFamilyIndex].queue = *pQueue;
|
||||
}
|
||||
else
|
||||
{
|
||||
RDCERR("Unexpected queue family index %u", queueFamilyIndex);
|
||||
}
|
||||
|
||||
if(queueFamilyIndex == m_QueueFamilyIdx)
|
||||
{
|
||||
m_Queue = *pQueue;
|
||||
@@ -142,6 +163,18 @@ bool WrappedVulkan::Serialise_vkQueueSubmit(SerialiserType &ser, VkQueue queue,
|
||||
|
||||
if(IsReplayingAndReading())
|
||||
{
|
||||
// if there are multiple queue submissions in flight, wait for the previous queue to finish
|
||||
// before executing this, as we don't have the sync information to properly sync.
|
||||
if(m_PrevQueue != queue)
|
||||
{
|
||||
RDCDEBUG("Previous queue execution was on queue %llu, now executing %llu, syncing GPU",
|
||||
GetResID(m_PrevQueue), GetResID(queue));
|
||||
if(m_PrevQueue != VK_NULL_HANDLE)
|
||||
ObjDisp(m_PrevQueue)->QueueWaitIdle(Unwrap(m_PrevQueue));
|
||||
|
||||
m_PrevQueue = queue;
|
||||
}
|
||||
|
||||
// if we ever waited on any semaphores, wait for idle here.
|
||||
bool doWait = false;
|
||||
for(uint32_t i = 0; i < submitCount; i++)
|
||||
@@ -205,7 +238,8 @@ bool WrappedVulkan::Serialise_vkQueueSubmit(SerialiserType &ser, VkQueue queue,
|
||||
|
||||
BakedCmdBufferInfo &cmdBufInfo = m_BakedCmdBufferInfo[cmd];
|
||||
|
||||
GetResourceManager()->ApplyBarriers(m_BakedCmdBufferInfo[cmd].imgbarriers, m_ImageLayouts);
|
||||
GetResourceManager()->ApplyBarriers(m_CreationInfo.m_Queue[GetResID(queue)],
|
||||
m_BakedCmdBufferInfo[cmd].imgbarriers, m_ImageLayouts);
|
||||
|
||||
std::string name = StringFormat::Fmt("=> %s[%u]: vkBeginCommandBuffer(%s)",
|
||||
basename.c_str(), c, ToStr(cmd).c_str());
|
||||
@@ -334,7 +368,8 @@ bool WrappedVulkan::Serialise_vkQueueSubmit(SerialiserType &ser, VkQueue queue,
|
||||
#endif
|
||||
rerecordedCmds.push_back(Unwrap(cmd));
|
||||
|
||||
GetResourceManager()->ApplyBarriers(m_BakedCmdBufferInfo[rerecord].imgbarriers,
|
||||
GetResourceManager()->ApplyBarriers(m_CreationInfo.m_Queue[GetResID(queue)],
|
||||
m_BakedCmdBufferInfo[rerecord].imgbarriers,
|
||||
m_ImageLayouts);
|
||||
}
|
||||
else
|
||||
@@ -509,6 +544,8 @@ VkResult WrappedVulkan::vkQueueSubmit(VkQueue queue, uint32_t submitCount,
|
||||
bool capframe = false;
|
||||
set<ResourceId> refdIDs;
|
||||
|
||||
VkResourceRecord *queueRecord = GetRecord(queue);
|
||||
|
||||
for(uint32_t s = 0; s < submitCount; s++)
|
||||
{
|
||||
for(uint32_t i = 0; i < pSubmits[s].commandBufferCount; i++)
|
||||
@@ -519,7 +556,8 @@ VkResult WrappedVulkan::vkQueueSubmit(VkQueue queue, uint32_t submitCount,
|
||||
|
||||
{
|
||||
SCOPED_LOCK(m_ImageLayoutsLock);
|
||||
GetResourceManager()->ApplyBarriers(record->bakedCommands->cmdInfo->imgbarriers,
|
||||
GetResourceManager()->ApplyBarriers(queueRecord->queueFamilyIndex,
|
||||
record->bakedCommands->cmdInfo->imgbarriers,
|
||||
m_ImageLayouts);
|
||||
}
|
||||
|
||||
@@ -1202,17 +1240,24 @@ bool WrappedVulkan::Serialise_vkGetDeviceQueue2(SerialiserType &ser, VkDevice de
|
||||
if(IsReplayingAndReading())
|
||||
{
|
||||
uint32_t queueFamilyIndex = QueueInfo.queueFamilyIndex;
|
||||
uint32_t queueIndex = QueueInfo.queueIndex;
|
||||
|
||||
uint32_t remapFamily = m_QueueRemapping[queueFamilyIndex][queueIndex].family;
|
||||
uint32_t remapIndex = m_QueueRemapping[queueFamilyIndex][queueIndex].index;
|
||||
|
||||
if(remapFamily != queueFamilyIndex || remapIndex != queueIndex)
|
||||
RDCLOG("Remapped Queue %u/%u from capture to %u/%u on replay", queueFamilyIndex, queueIndex,
|
||||
remapFamily, remapIndex);
|
||||
|
||||
VkQueue queue;
|
||||
// MULTIQUEUE - re-map the queue family/index instead of using the supported family
|
||||
QueueInfo.queueFamilyIndex = m_SupportedQueueFamily;
|
||||
QueueInfo.queueIndex = 0;
|
||||
QueueInfo.queueFamilyIndex = remapFamily;
|
||||
QueueInfo.queueIndex = remapIndex;
|
||||
ObjDisp(device)->GetDeviceQueue2(Unwrap(device), &QueueInfo, &queue);
|
||||
|
||||
GetResourceManager()->WrapResource(Unwrap(device), queue);
|
||||
GetResourceManager()->AddLiveResource(Queue, queue);
|
||||
|
||||
if(queueFamilyIndex == m_QueueFamilyIdx)
|
||||
if(remapFamily == m_QueueFamilyIdx && m_Queue == VK_NULL_HANDLE)
|
||||
{
|
||||
m_Queue = queue;
|
||||
|
||||
@@ -1221,6 +1266,8 @@ bool WrappedVulkan::Serialise_vkGetDeviceQueue2(SerialiserType &ser, VkDevice de
|
||||
SubmitCmds();
|
||||
}
|
||||
|
||||
m_CreationInfo.m_Queue[GetResID(queue)] = remapFamily;
|
||||
|
||||
AddResource(Queue, ResourceType::Queue, "Queue");
|
||||
DerivedResource(device, Queue);
|
||||
}
|
||||
@@ -1267,6 +1314,8 @@ void WrappedVulkan::vkGetDeviceQueue2(VkDevice device, const VkDeviceQueueInfo2
|
||||
VkResourceRecord *record = GetResourceManager()->AddResourceRecord(*pQueue);
|
||||
RDCASSERT(record);
|
||||
|
||||
record->queueFamilyIndex = pQueueInfo->queueFamilyIndex;
|
||||
|
||||
VkResourceRecord *instrecord = GetRecord(m_Instance);
|
||||
|
||||
// treat queues as pool members of the instance (ie. freed when the instance dies)
|
||||
@@ -1281,6 +1330,16 @@ void WrappedVulkan::vkGetDeviceQueue2(VkDevice device, const VkDeviceQueueInfo2
|
||||
|
||||
m_QueueFamilies[pQueueInfo->queueFamilyIndex][pQueueInfo->queueIndex] = *pQueue;
|
||||
|
||||
if(pQueueInfo->queueFamilyIndex < m_ExternalQueues.size())
|
||||
{
|
||||
if(m_ExternalQueues[pQueueInfo->queueFamilyIndex].queue == VK_NULL_HANDLE)
|
||||
m_ExternalQueues[pQueueInfo->queueFamilyIndex].queue = *pQueue;
|
||||
}
|
||||
else
|
||||
{
|
||||
RDCERR("Unexpected queue family index %u", pQueueInfo->queueFamilyIndex);
|
||||
}
|
||||
|
||||
if(pQueueInfo->queueFamilyIndex == m_QueueFamilyIdx)
|
||||
{
|
||||
m_Queue = *pQueue;
|
||||
|
||||
@@ -1009,6 +1009,14 @@ bool WrappedVulkan::Serialise_vkCreateBuffer(SerialiserType &ser, VkDevice devic
|
||||
// ensure we can always readback from buffers
|
||||
CreateInfo.usage |= VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
|
||||
|
||||
// remap the queue family indices
|
||||
if(CreateInfo.sharingMode == VK_SHARING_MODE_EXCLUSIVE)
|
||||
{
|
||||
uint32_t *queueFamiles = (uint32_t *)CreateInfo.pQueueFamilyIndices;
|
||||
for(uint32_t q = 0; q < CreateInfo.queueFamilyIndexCount; q++)
|
||||
queueFamiles[q] = m_QueueRemapping[queueFamiles[q]][0].family;
|
||||
}
|
||||
|
||||
VkBufferCreateInfo patched = CreateInfo;
|
||||
|
||||
byte *tempMem = GetTempMemory(GetNextPatchSize(patched.pNext));
|
||||
@@ -1062,8 +1070,6 @@ VkResult WrappedVulkan::vkCreateBuffer(VkDevice device, const VkBufferCreateInfo
|
||||
SERIALISE_TIME_CALL(
|
||||
ret = ObjDisp(device)->CreateBuffer(Unwrap(device), &adjusted_info, pAllocator, pBuffer));
|
||||
|
||||
// SHARING: pCreateInfo sharingMode, queueFamilyCount, pQueueFamilyIndices
|
||||
|
||||
if(ret == VK_SUCCESS)
|
||||
{
|
||||
ResourceId id = GetResourceManager()->WrapResource(Unwrap(device), *pBuffer);
|
||||
@@ -1255,6 +1261,14 @@ bool WrappedVulkan::Serialise_vkCreateImage(SerialiserType &ser, VkDevice device
|
||||
VK_IMAGE_USAGE_TRANSFER_DST_BIT;
|
||||
CreateInfo.usage &= ~VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT;
|
||||
|
||||
// remap the queue family indices
|
||||
if(CreateInfo.sharingMode == VK_SHARING_MODE_EXCLUSIVE)
|
||||
{
|
||||
uint32_t *queueFamiles = (uint32_t *)CreateInfo.pQueueFamilyIndices;
|
||||
for(uint32_t q = 0; q < CreateInfo.queueFamilyIndexCount; q++)
|
||||
queueFamiles[q] = m_QueueRemapping[queueFamiles[q]][0].family;
|
||||
}
|
||||
|
||||
// ensure we can cast multisampled images, for copying to arrays
|
||||
if((int)CreateInfo.samples > 1)
|
||||
{
|
||||
@@ -1328,8 +1342,8 @@ bool WrappedVulkan::Serialise_vkCreateImage(SerialiserType &ser, VkDevice device
|
||||
else if(IsDepthOrStencilFormat(CreateInfo.format))
|
||||
range.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||
|
||||
layouts.subresourceStates.push_back(
|
||||
ImageRegionState(range, UNKNOWN_PREV_IMG_LAYOUT, VK_IMAGE_LAYOUT_UNDEFINED));
|
||||
layouts.subresourceStates.push_back(ImageRegionState(
|
||||
VK_QUEUE_FAMILY_IGNORED, range, UNKNOWN_PREV_IMG_LAYOUT, VK_IMAGE_LAYOUT_UNDEFINED));
|
||||
}
|
||||
|
||||
const char *prefix = "Image";
|
||||
@@ -1412,8 +1426,6 @@ VkResult WrappedVulkan::vkCreateImage(VkDevice device, const VkImageCreateInfo *
|
||||
SERIALISE_TIME_CALL(
|
||||
ret = ObjDisp(device)->CreateImage(Unwrap(device), &createInfo_adjusted, pAllocator, pImage));
|
||||
|
||||
// SHARING: pCreateInfo sharingMode, queueFamilyCount, pQueueFamilyIndices
|
||||
|
||||
if(ret == VK_SUCCESS)
|
||||
{
|
||||
ResourceId id = GetResourceManager()->WrapResource(Unwrap(device), *pImage);
|
||||
@@ -1556,8 +1568,8 @@ VkResult WrappedVulkan::vkCreateImage(VkDevice device, const VkImageCreateInfo *
|
||||
else if(IsDepthOrStencilFormat(pCreateInfo->format))
|
||||
range.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||
|
||||
layout->subresourceStates.push_back(
|
||||
ImageRegionState(range, UNKNOWN_PREV_IMG_LAYOUT, VK_IMAGE_LAYOUT_UNDEFINED));
|
||||
layout->subresourceStates.push_back(ImageRegionState(
|
||||
VK_QUEUE_FAMILY_IGNORED, range, UNKNOWN_PREV_IMG_LAYOUT, VK_IMAGE_LAYOUT_UNDEFINED));
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
@@ -71,6 +71,30 @@
|
||||
*
|
||||
*/
|
||||
|
||||
void WrappedVulkan::RemapQueueFamilyIndices(uint32_t &srcQueueFamily, uint32_t &dstQueueFamily)
|
||||
{
|
||||
if(srcQueueFamily == VK_QUEUE_FAMILY_EXTERNAL || dstQueueFamily == VK_QUEUE_FAMILY_EXTERNAL)
|
||||
{
|
||||
// we should ignore this family transition since we're not synchronising with an
|
||||
// external access.
|
||||
srcQueueFamily = dstQueueFamily = VK_QUEUE_FAMILY_IGNORED;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(srcQueueFamily != VK_QUEUE_FAMILY_IGNORED)
|
||||
{
|
||||
RDCASSERT(srcQueueFamily < ARRAY_COUNT(m_QueueRemapping), srcQueueFamily);
|
||||
srcQueueFamily = m_QueueRemapping[srcQueueFamily][0].family;
|
||||
}
|
||||
|
||||
if(dstQueueFamily != VK_QUEUE_FAMILY_IGNORED)
|
||||
{
|
||||
RDCASSERT(dstQueueFamily < ARRAY_COUNT(m_QueueRemapping), dstQueueFamily);
|
||||
dstQueueFamily = m_QueueRemapping[dstQueueFamily][0].family;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename SerialiserType>
|
||||
bool WrappedVulkan::Serialise_vkCreateFence(SerialiserType &ser, VkDevice device,
|
||||
const VkFenceCreateInfo *pCreateInfo,
|
||||
@@ -740,6 +764,9 @@ bool WrappedVulkan::Serialise_vkCmdWaitEvents(
|
||||
{
|
||||
bufBarriers.push_back(pBufferMemoryBarriers[i]);
|
||||
bufBarriers.back().buffer = Unwrap(bufBarriers.back().buffer);
|
||||
|
||||
RemapQueueFamilyIndices(bufBarriers.back().srcQueueFamilyIndex,
|
||||
bufBarriers.back().dstQueueFamilyIndex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -752,8 +779,8 @@ bool WrappedVulkan::Serialise_vkCmdWaitEvents(
|
||||
ReplacePresentableImageLayout(imgBarriers.back().oldLayout);
|
||||
ReplacePresentableImageLayout(imgBarriers.back().newLayout);
|
||||
|
||||
ReplaceExternalQueueFamily(imgBarriers.back().srcQueueFamilyIndex,
|
||||
imgBarriers.back().dstQueueFamilyIndex);
|
||||
RemapQueueFamilyIndices(imgBarriers.back().srcQueueFamilyIndex,
|
||||
imgBarriers.back().dstQueueFamilyIndex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -338,8 +338,8 @@ bool WrappedVulkan::Serialise_vkCreateSwapchainKHR(SerialiserType &ser, VkDevice
|
||||
VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
|
||||
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | CreateInfo.imageUsage,
|
||||
CreateInfo.imageSharingMode,
|
||||
0,
|
||||
NULL,
|
||||
CreateInfo.queueFamilyIndexCount,
|
||||
CreateInfo.pQueueFamilyIndices,
|
||||
VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
};
|
||||
|
||||
@@ -407,8 +407,8 @@ bool WrappedVulkan::Serialise_vkCreateSwapchainKHR(SerialiserType &ser, VkDevice
|
||||
m_ImageLayouts[liveId].format = iminfo.format;
|
||||
|
||||
m_ImageLayouts[liveId].subresourceStates.clear();
|
||||
m_ImageLayouts[liveId].subresourceStates.push_back(
|
||||
ImageRegionState(range, UNKNOWN_PREV_IMG_LAYOUT, VK_IMAGE_LAYOUT_UNDEFINED));
|
||||
m_ImageLayouts[liveId].subresourceStates.push_back(ImageRegionState(
|
||||
VK_QUEUE_FAMILY_IGNORED, range, UNKNOWN_PREV_IMG_LAYOUT, VK_IMAGE_LAYOUT_UNDEFINED));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -540,8 +540,8 @@ void WrappedVulkan::WrapAndProcessCreatedSwapchain(VkDevice device,
|
||||
{
|
||||
SCOPED_LOCK(m_ImageLayoutsLock);
|
||||
m_ImageLayouts[imid].subresourceStates.clear();
|
||||
m_ImageLayouts[imid].subresourceStates.push_back(
|
||||
ImageRegionState(range, UNKNOWN_PREV_IMG_LAYOUT, VK_IMAGE_LAYOUT_UNDEFINED));
|
||||
m_ImageLayouts[imid].subresourceStates.push_back(ImageRegionState(
|
||||
VK_QUEUE_FAMILY_IGNORED, range, UNKNOWN_PREV_IMG_LAYOUT, VK_IMAGE_LAYOUT_UNDEFINED));
|
||||
}
|
||||
|
||||
{
|
||||
@@ -679,6 +679,8 @@ VkResult WrappedVulkan::vkQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR
|
||||
VkImage im = swapInfo.images[pPresentInfo->pImageIndices[0]].im;
|
||||
VkFramebuffer fb = swapInfo.images[pPresentInfo->pImageIndices[0]].fb;
|
||||
|
||||
uint32_t swapQueueIndex = m_ImageLayouts[GetResID(im)].queueFamilyIndex;
|
||||
|
||||
VkLayerDispatchTable *vt = ObjDisp(GetDev());
|
||||
|
||||
TextPrintState textstate = {
|
||||
@@ -696,22 +698,38 @@ VkResult WrappedVulkan::vkQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR
|
||||
VkResult vkr = vt->BeginCommandBuffer(Unwrap(textstate.cmd), &beginInfo);
|
||||
RDCASSERTEQUAL(vkr, VK_SUCCESS);
|
||||
|
||||
VkImageMemoryBarrier bbBarrier = {VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||
NULL,
|
||||
0,
|
||||
0,
|
||||
VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
|
||||
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
||||
VK_QUEUE_FAMILY_IGNORED,
|
||||
VK_QUEUE_FAMILY_IGNORED,
|
||||
Unwrap(im),
|
||||
{VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}};
|
||||
VkImageMemoryBarrier bbBarrier = {
|
||||
VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||
NULL,
|
||||
0,
|
||||
0,
|
||||
VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
|
||||
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
||||
swapQueueIndex,
|
||||
m_QueueFamilyIdx,
|
||||
Unwrap(im),
|
||||
{VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1},
|
||||
};
|
||||
|
||||
bbBarrier.srcAccessMask = VK_ACCESS_ALL_READ_BITS;
|
||||
bbBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
|
||||
DoPipelineBarrier(textstate.cmd, 1, &bbBarrier);
|
||||
|
||||
if(swapQueueIndex != m_QueueFamilyIdx)
|
||||
{
|
||||
VkCommandBuffer extQCmd = GetExtQueueCmd(swapQueueIndex);
|
||||
|
||||
vkr = vt->BeginCommandBuffer(Unwrap(extQCmd), &beginInfo);
|
||||
RDCASSERTEQUAL(vkr, VK_SUCCESS);
|
||||
|
||||
DoPipelineBarrier(extQCmd, 1, &bbBarrier);
|
||||
|
||||
ObjDisp(extQCmd)->EndCommandBuffer(Unwrap(extQCmd));
|
||||
|
||||
SubmitAndFlushExtQueue(swapQueueIndex);
|
||||
}
|
||||
|
||||
m_TextRenderer->BeginText(textstate);
|
||||
|
||||
int flags = activeWindow ? RenderDoc::eOverlay_ActiveWindow : 0;
|
||||
@@ -722,6 +740,7 @@ VkResult WrappedVulkan::vkQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR
|
||||
|
||||
m_TextRenderer->EndText(textstate);
|
||||
|
||||
std::swap(bbBarrier.srcQueueFamilyIndex, bbBarrier.dstQueueFamilyIndex);
|
||||
std::swap(bbBarrier.oldLayout, bbBarrier.newLayout);
|
||||
bbBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
bbBarrier.dstAccessMask = VK_ACCESS_ALL_READ_BITS;
|
||||
@@ -732,6 +751,20 @@ VkResult WrappedVulkan::vkQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR
|
||||
|
||||
SubmitCmds();
|
||||
|
||||
if(swapQueueIndex != m_QueueFamilyIdx)
|
||||
{
|
||||
VkCommandBuffer extQCmd = GetExtQueueCmd(swapQueueIndex);
|
||||
|
||||
vkr = vt->BeginCommandBuffer(Unwrap(extQCmd), &beginInfo);
|
||||
RDCASSERTEQUAL(vkr, VK_SUCCESS);
|
||||
|
||||
DoPipelineBarrier(extQCmd, 1, &bbBarrier);
|
||||
|
||||
ObjDisp(extQCmd)->EndCommandBuffer(Unwrap(extQCmd));
|
||||
|
||||
SubmitAndFlushExtQueue(swapQueueIndex);
|
||||
}
|
||||
|
||||
FlushQ();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,7 +131,8 @@ public:
|
||||
|
||||
void SetVersion(uint64_t version) { m_Version = version; }
|
||||
// assume that we always write the latest version, so on writing the version check always passes.
|
||||
bool VersionCheck(uint64_t req) { return IsWriting() || m_Version >= req; }
|
||||
bool VersionAtLeast(uint64_t req) const { return IsWriting() || m_Version >= req; }
|
||||
bool VersionLess(uint64_t req) const { return IsReading() && m_Version < req; }
|
||||
// enable 'streaming mode' for ephemeral transfers like temporary I/O over sockets, where there's
|
||||
// no need for the chunk length - avoids needing to seek internally in a stream that might not
|
||||
// support seeking to fixup lengths, while also not requiring conservative length estimates
|
||||
|
||||
Reference in New Issue
Block a user