Correctly handle programs that don't create graphics queues

This commit is contained in:
baldurk
2022-06-21 15:31:41 +01:00
parent 2020a71cf1
commit 7d9a1a05b8
18 changed files with 655 additions and 144 deletions
+13
View File
@@ -2252,6 +2252,19 @@ void WrappedID3D12Device::StartFrameCapture(DeviceOwnedWindow devWnd)
RDCLOG("Starting capture");
if(m_Queue == NULL)
{
RDCLOG("Creating direct queue as none was found in the application");
// pretend this is the application's call and just release - everything else will be handled the
// same (the queue will be kept alive internally)
ID3D12CommandQueue *q = NULL;
D3D12_COMMAND_QUEUE_DESC desc = {};
desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
CreateCommandQueue(&desc, __uuidof(ID3D12CommandQueue), (void **)&q);
q->Release();
}
WrappedID3D12CommandAllocator::PauseResets();
m_CaptureTimer.Restart();
+8
View File
@@ -1796,6 +1796,14 @@ void WrappedVulkan::StartFrameCapture(DeviceOwnedWindow devWnd)
RDCLOG("Starting capture");
if(m_Queue == VK_NULL_HANDLE && m_QueueFamilyIdx != ~0U)
{
RDCLOG("Creating desired queue as none was obtained by the application");
VkQueue q = VK_NULL_HANDLE;
vkGetDeviceQueue(m_Device, m_QueueFamilyIdx, 0, &q);
}
Atomic::Dec32(&m_ReuseEnabled);
m_CaptureTimer.Restart();
+1
View File
@@ -12,6 +12,7 @@ set(VULKAN_SRC
vk/vk_adv_cbuffer_zoo.cpp
vk/vk_buffer_truncation.cpp
vk/vk_cbuffer_zoo.cpp
vk/vk_compute_only.cpp
vk/vk_custom_border_color.cpp
vk/vk_dedicated_allocation.cpp
vk/vk_descriptor_index.cpp
@@ -0,0 +1,149 @@
/******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2020-2022 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 "d3d12_test.h"
RD_TEST(D3D12_Compute_Only, D3D12GraphicsTest)
{
static constexpr const char *Description =
"Test that uses a compute only queue with no graphics queue";
std::string compute = R"EOSHADER(
cbuffer blah : register(b0)
{
uint4 mult;
};
RWStructuredBuffer<uint4> bufin : register(u0);
RWStructuredBuffer<uint4> bufout : register(u1);
[numthreads(1,1,1)]
void main()
{
bufout[0].x += bufin[0].x * mult.x;
bufout[0].y += bufin[0].y * mult.y;
bufout[0].z += bufin[0].z * mult.z;
bufout[0].w += bufin[0].w * mult.w;
}
)EOSHADER";
int main()
{
headless = true;
queueType = D3D12_COMMAND_LIST_TYPE_COMPUTE;
// initialise, create window, create device, etc
if(!Init())
return 3;
ID3DBlobPtr csblob = Compile(compute, "main", "cs_5_0");
ID3D12RootSignaturePtr sig = MakeSig({
uavParam(D3D12_SHADER_VISIBILITY_ALL, 0, 0), uavParam(D3D12_SHADER_VISIBILITY_ALL, 0, 1),
constParam(D3D12_SHADER_VISIBILITY_ALL, 0, 0, 4),
tableParam(D3D12_SHADER_VISIBILITY_ALL, D3D12_DESCRIPTOR_RANGE_TYPE_UAV, 0, 2, 1, 3),
});
ID3D12PipelineStatePtr pso = MakePSO().RootSig(sig).CS(csblob);
ID3D12ResourcePtr bufin = MakeBuffer().Size(1024).UAV();
ID3D12ResourcePtr bufout = MakeBuffer().Size(1024).UAV();
bufin->SetName(L"bufin");
bufout->SetName(L"bufout");
ID3D12ResourcePtr tex = MakeTexture(DXGI_FORMAT_R32G32B32A32_FLOAT, 8, 8)
.InitialState(D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE)
.UAV();
tex->SetName(L"tex");
{
ID3D12GraphicsCommandListPtr cmd = GetCommandBuffer();
Reset(cmd);
float col[] = {0.25f, 0.5f, 0.75f, 1.0f};
D3D12_RECT rect = {};
rect.right = rect.bottom = 8;
cmd->ClearUnorderedAccessViewFloat(
MakeUAV(tex).Format(DXGI_FORMAT_R32G32B32A32_FLOAT).CreateGPU(3),
MakeUAV(tex).Format(DXGI_FORMAT_R32G32B32A32_FLOAT).CreateClearCPU(3), tex, col, 1, &rect);
cmd->Close();
Submit({cmd});
}
if(rdoc)
rdoc->StartFrameCapture(NULL, NULL);
{
ID3D12GraphicsCommandListPtr cmd = GetCommandBuffer();
Reset(cmd);
uint32_t a[4] = {111, 111, 111, 111};
uint32_t b[4] = {222, 222, 222, 222};
D3D12_RECT rect = {};
rect.right = 1024;
rect.bottom = 1;
cmd->ClearUnorderedAccessViewUint(
MakeUAV(bufin).Format(DXGI_FORMAT_R32G32B32A32_UINT).CreateGPU(0),
MakeUAV(bufin).Format(DXGI_FORMAT_R32G32B32A32_UINT).CreateClearCPU(0), bufin, a, 1, &rect);
cmd->ClearUnorderedAccessViewUint(
MakeUAV(bufout).Format(DXGI_FORMAT_R32G32B32A32_UINT).CreateGPU(1),
MakeUAV(bufout).Format(DXGI_FORMAT_R32G32B32A32_UINT).CreateClearCPU(1), bufin, b, 1,
&rect);
setMarker(cmd, "Pre-Dispatch");
cmd->SetComputeRootSignature(sig);
cmd->SetPipelineState(pso);
cmd->SetDescriptorHeaps(1, &m_CBVUAVSRV.GetInterfacePtr());
cmd->SetComputeRootUnorderedAccessView(0, bufin->GetGPUVirtualAddress());
cmd->SetComputeRootUnorderedAccessView(1, bufout->GetGPUVirtualAddress());
cmd->SetComputeRoot32BitConstant(2, 5, 0);
cmd->SetComputeRoot32BitConstant(2, 6, 1);
cmd->SetComputeRoot32BitConstant(2, 7, 2);
cmd->SetComputeRoot32BitConstant(2, 8, 3);
cmd->SetComputeRootDescriptorTable(3, m_CBVUAVSRV->GetGPUDescriptorHandleForHeapStart());
cmd->Dispatch(1, 1, 1);
setMarker(cmd, "Post-Dispatch");
cmd->Close();
Submit({cmd});
}
if(rdoc)
rdoc->EndFrameCapture(NULL, NULL);
GPUSync();
return 0;
}
};
REGISTER_TEST();
+13
View File
@@ -156,6 +156,19 @@ D3D12_ROOT_PARAMETER1 cbvParam(D3D12_SHADER_VISIBILITY vis, UINT space, UINT reg
return ret;
}
D3D12_ROOT_PARAMETER1 uavParam(D3D12_SHADER_VISIBILITY vis, UINT space, UINT reg)
{
D3D12_ROOT_PARAMETER1 ret;
ret.ShaderVisibility = vis;
ret.ParameterType = D3D12_ROOT_PARAMETER_TYPE_UAV;
ret.Descriptor.RegisterSpace = space;
ret.Descriptor.ShaderRegister = reg;
ret.Descriptor.Flags = D3D12_ROOT_DESCRIPTOR_FLAG_NONE;
return ret;
}
D3D12_ROOT_PARAMETER1 constParam(D3D12_SHADER_VISIBILITY vis, UINT space, UINT reg, UINT num)
{
D3D12_ROOT_PARAMETER1 ret;
+1
View File
@@ -265,6 +265,7 @@ private:
};
D3D12_ROOT_PARAMETER1 cbvParam(D3D12_SHADER_VISIBILITY vis, UINT space, UINT reg);
D3D12_ROOT_PARAMETER1 uavParam(D3D12_SHADER_VISIBILITY vis, UINT space, UINT reg);
D3D12_ROOT_PARAMETER1 constParam(D3D12_SHADER_VISIBILITY vis, UINT space, UINT reg, UINT num);
+6 -6
View File
@@ -316,7 +316,7 @@ void D3D12GraphicsTest::PostDeviceCreate()
{
{
D3D12_COMMAND_QUEUE_DESC desc = {};
desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
desc.Type = queueType;
dev->CreateCommandQueue(&desc, __uuidof(ID3D12CommandQueue), (void **)&queue);
}
@@ -325,13 +325,13 @@ void D3D12GraphicsTest::PostDeviceCreate()
m_GPUSyncFence->SetName(L"GPUSync fence");
CHECK_HR(dev->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT,
__uuidof(ID3D12CommandAllocator), (void **)&m_Alloc));
CHECK_HR(
dev->CreateCommandAllocator(queueType, __uuidof(ID3D12CommandAllocator), (void **)&m_Alloc));
m_Alloc->SetName(L"Command allocator");
CHECK_HR(dev->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_Alloc, NULL,
__uuidof(ID3D12GraphicsCommandList), (void **)&m_DebugList));
CHECK_HR(dev->CreateCommandList(0, queueType, m_Alloc, NULL, __uuidof(ID3D12GraphicsCommandList),
(void **)&m_DebugList));
// command buffers are allocated opened, close it immediately.
m_DebugList->Close();
@@ -1349,7 +1349,7 @@ ID3D12GraphicsCommandListPtr D3D12GraphicsTest::GetCommandBuffer()
if(freeCommandBuffers.empty())
{
ID3D12GraphicsCommandListPtr list = NULL;
CHECK_HR(dev->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_Alloc, NULL,
CHECK_HR(dev->CreateCommandList(0, queueType, m_Alloc, NULL,
__uuidof(ID3D12GraphicsCommandList), (void **)&list));
// list starts opened, close it
list->Close();
+1
View File
@@ -226,6 +226,7 @@ struct D3D12GraphicsTest : public GraphicsTest
ID3D12CommandAllocatorPtr m_Alloc;
ID3D12GraphicsCommandListPtr m_DebugList;
D3D12_COMMAND_LIST_TYPE queueType = D3D12_COMMAND_LIST_TYPE_DIRECT;
ID3D12CommandQueuePtr queue;
D3D12_FEATURE_DATA_D3D12_OPTIONS opts = {};
+2
View File
@@ -179,6 +179,7 @@
<ClCompile Include="d3d12\d3d12_amd_shader_extensions.cpp" />
<ClCompile Include="d3d12\d3d12_buffer_truncation.cpp" />
<ClCompile Include="d3d12\d3d12_cbuffer_zoo.cpp" />
<ClCompile Include="d3d12\d3d12_compute_only.cpp" />
<ClCompile Include="d3d12\d3d12_descriptor_indexing.cpp" />
<ClCompile Include="d3d12\d3d12_discard_zoo.cpp" />
<ClCompile Include="d3d12\d3d12_draw_zoo.cpp" />
@@ -280,6 +281,7 @@
<ClCompile Include="main.cpp" />
<ClCompile Include="test_common.cpp" />
<ClCompile Include="texture_zoo.cpp" />
<ClCompile Include="vk\vk_compute_only.cpp" />
<ClCompile Include="vk\vk_custom_border_color.cpp" />
<ClCompile Include="vk\vk_dedicated_allocation.cpp" />
<ClCompile Include="vk\vk_descriptor_reuse.cpp" />
+6
View File
@@ -628,6 +628,12 @@
<ClCompile Include="gl\gl_depth_bounds.cpp">
<Filter>OpenGL\demos</Filter>
</ClCompile>
<ClCompile Include="vk\vk_compute_only.cpp">
<Filter>Vulkan\demos</Filter>
</ClCompile>
<ClCompile Include="d3d12\d3d12_compute_only.cpp">
<Filter>D3D12\demos</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Filter Include="D3D11">
+182
View File
@@ -0,0 +1,182 @@
/******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2019-2022 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_test.h"
RD_TEST(VK_Compute_Only, VulkanGraphicsTest)
{
static constexpr const char *Description =
"Test that uses a compute only queue with no graphics queue.";
const std::string comp = R"EOSHADER(
#version 450 core
layout(push_constant) uniform PushData
{
uvec4 data;
} push;
layout(binding = 0, std430) buffer inbuftype {
uvec4 data[];
} inbuf;
layout(binding = 1, std430) buffer outbuftype {
uvec4 data[];
} outbuf;
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
void main()
{
outbuf.data[0].x += inbuf.data[0].x * push.data.x;
outbuf.data[0].y += inbuf.data[0].y * push.data.y;
outbuf.data[0].z += inbuf.data[0].z * push.data.z;
outbuf.data[0].w += inbuf.data[0].w * push.data.w;
}
)EOSHADER";
int main()
{
headless = true;
queueFlagsRequired = VK_QUEUE_COMPUTE_BIT;
queueFlagsBanned = VK_QUEUE_GRAPHICS_BIT;
// initialise, create window, create context, etc
if(!Init())
return 3;
VkDescriptorSetLayout setLayout = createDescriptorSetLayout(vkh::DescriptorSetLayoutCreateInfo({
{0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT},
{1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT},
{2, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_COMPUTE_BIT},
}));
VkPipelineLayout layout = createPipelineLayout(vkh::PipelineLayoutCreateInfo(
{setLayout},
{
vkh::PushConstantRange(VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(Vec4i)),
}));
VkPipeline pipe = createComputePipeline(vkh::ComputePipelineCreateInfo(
layout, CompileShaderModule(comp, ShaderLang::glsl, ShaderStage::comp, "main")));
AllocatedImage tex(
this, vkh::ImageCreateInfo(4, 4, 0, VK_FORMAT_R32G32B32A32_SFLOAT,
VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_STORAGE_BIT),
VmaAllocationCreateInfo({0, VMA_MEMORY_USAGE_GPU_ONLY}));
setName(tex.image, "tex");
VkImageView view = createImageView(
vkh::ImageViewCreateInfo(tex.image, VK_IMAGE_VIEW_TYPE_2D, VK_FORMAT_R32G32B32A32_SFLOAT));
AllocatedBuffer bufin(this, vkh::BufferCreateInfo(1024, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
VK_BUFFER_USAGE_TRANSFER_DST_BIT),
VmaAllocationCreateInfo({0, VMA_MEMORY_USAGE_CPU_TO_GPU}));
AllocatedBuffer bufout(this, vkh::BufferCreateInfo(1024, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
VK_BUFFER_USAGE_TRANSFER_DST_BIT),
VmaAllocationCreateInfo({0, VMA_MEMORY_USAGE_CPU_TO_GPU}));
setName(bufin.buffer, "bufin");
setName(bufout.buffer, "bufout");
VkDescriptorSet set = allocateDescriptorSet(setLayout);
vkh::updateDescriptorSets(
device, {
vkh::WriteDescriptorSet(set, 0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
{vkh::DescriptorBufferInfo(bufin.buffer)}),
vkh::WriteDescriptorSet(set, 1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
{vkh::DescriptorBufferInfo(bufout.buffer)}),
vkh::WriteDescriptorSet(
set, 2, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
{vkh::DescriptorImageInfo(view, VK_IMAGE_LAYOUT_GENERAL, VK_NULL_HANDLE)}),
});
// clear the buffers
{
VkCommandBuffer cmd = GetCommandBuffer();
vkBeginCommandBuffer(cmd, vkh::CommandBufferBeginInfo());
vkCmdFillBuffer(cmd, bufin.buffer, 0, 1024, 111);
vkCmdFillBuffer(cmd, bufout.buffer, 0, 1024, 222);
vkh::cmdPipelineBarrier(
cmd,
{
vkh::ImageMemoryBarrier(0, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_GENERAL, tex.image),
},
{
vkh::BufferMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT,
bufin.buffer, 0, 1024),
vkh::BufferMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_WRITE_BIT,
bufout.buffer, 0, 1024),
});
vkCmdClearColorImage(cmd, tex.image, VK_IMAGE_LAYOUT_GENERAL,
vkh::ClearColorValue(0.25f, 0.5f, 0.75f, 1.0f), 1,
vkh::ImageSubresourceRange());
vkEndCommandBuffer(cmd);
Submit(0, 1, {cmd});
}
if(rdoc)
rdoc->StartFrameCapture(NULL, NULL);
{
VkCommandBuffer cmd = GetCommandBuffer();
vkBeginCommandBuffer(cmd, vkh::CommandBufferBeginInfo());
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, pipe);
vkh::cmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, layout, 0, {set}, {});
setMarker(cmd, "Pre-Dispatch");
Vec4i push = {5, 6, 7, 8};
vkCmdPushConstants(cmd, layout, VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(Vec4i), &push);
vkCmdDispatch(cmd, 1, 1, 1);
setMarker(cmd, "Post-Dispatch");
vkEndCommandBuffer(cmd);
Submit(0, 1, {cmd});
}
if(rdoc)
rdoc->EndFrameCapture(NULL, NULL);
return 0;
}
};
REGISTER_TEST();
+1 -1
View File
@@ -143,7 +143,7 @@ RD_TEST(VK_Multi_Present, VulkanGraphicsTest)
vkEndCommandBuffer(cmd);
Submit(0, 1, {cmd}, {}, win);
win->Submit(0, 1, {cmd}, {}, queue);
}
VulkanWindow::MultiPresent(queue, presentWindows);
@@ -129,9 +129,9 @@ RD_TEST(VK_Multi_Thread_Windows, VulkanGraphicsTest)
vkEndCommandBuffer(cmd);
Submit(0, 1, {cmd}, {}, win, q);
win->Submit(0, 1, {cmd}, {}, q);
Present(win, q);
win->Present(q);
} while(win);
};
+1 -1
View File
@@ -278,7 +278,7 @@ RD_TEST(VK_Synchronization_2, VulkanGraphicsTest)
vkEndCommandBuffer(cmd);
Submit(0, 1, {cmd}, {}, NULL, VK_NULL_HANDLE, true);
Submit(0, 1, {cmd});
Present();
+168 -122
View File
@@ -586,15 +586,15 @@ bool VulkanGraphicsTest::Init()
std::vector<VkQueueFamilyProperties> queueProps;
vkh::getQueueFamilyProperties(queueProps, phys);
VkQueueFlags required = VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT;
// if no queue has been selected, find it now
if(queueFamilyIndex == ~0U)
{
// try to find an exact match first
for(uint32_t q = 0; q < queueProps.size(); q++)
{
VkQueueFlags flags = queueProps[q].queueFlags;
if((flags & required) == required)
if(flags == queueFlagsRequired)
{
queueFamilyIndex = q;
queueCount = 1;
@@ -605,7 +605,23 @@ bool VulkanGraphicsTest::Init()
if(queueFamilyIndex == ~0U)
{
TEST_ERROR("No graphics/compute queues available");
// if we didn't find an exact match, look for any that does satisfy what we want
for(uint32_t q = 0; q < queueProps.size(); q++)
{
VkQueueFlags flags = queueProps[q].queueFlags;
if(((flags & queueFlagsRequired) == queueFlagsRequired) && ((flags & queueFlagsBanned) == 0))
{
queueFamilyIndex = q;
queueCount = 1;
break;
}
}
}
if(queueFamilyIndex == ~0U)
{
TEST_ERROR("No satisfactory queue family available");
return false;
}
@@ -638,13 +654,17 @@ bool VulkanGraphicsTest::Init()
volkLoadDevice(device);
vkGetDeviceQueue(device, queueFamilyIndex, 0, &queue);
mainWindow = MakeWindow(screenWidth, screenHeight, "Autotesting");
if(!mainWindow->Initialised())
if(!headless)
{
TEST_ERROR("Error creating surface");
return false;
};
mainWindow = MakeWindow(screenWidth, screenHeight, "Autotesting");
if(!mainWindow->Initialised())
{
TEST_ERROR("Error creating surface");
return false;
}
}
VmaVulkanFunctions funcs = {
vkGetPhysicalDeviceProperties,
@@ -680,6 +700,8 @@ bool VulkanGraphicsTest::Init()
TEST_LOG("Running Vulkan test on %s (version %d.%d)", physProperties.deviceName,
VK_VERSION_MAJOR(physProperties.apiVersion), VK_VERSION_MINOR(physProperties.apiVersion));
headlessCmds = new VulkanCommands(this);
return true;
}
@@ -738,6 +760,9 @@ void VulkanGraphicsTest::Shutdown()
vmaDestroyAllocator(allocator);
if(headlessCmds)
delete headlessCmds;
delete mainWindow;
vkDestroyDevice(device, NULL);
@@ -789,27 +814,17 @@ void VulkanGraphicsTest::FinishUsingBackbuffer(VkCommandBuffer cmd, VkAccessFlag
}
void VulkanGraphicsTest::Submit(int index, int totalSubmits, const std::vector<VkCommandBuffer> &cmds,
const std::vector<VkCommandBuffer> &seccmds, VulkanWindow *window,
VkQueue q, bool sync2)
const std::vector<VkCommandBuffer> &seccmds)
{
if(window == NULL)
window = mainWindow;
if(q == VK_NULL_HANDLE)
q = queue;
window->Submit(index, totalSubmits, cmds, seccmds, q, sync2);
if(mainWindow)
mainWindow->Submit(index, totalSubmits, cmds, seccmds, queue);
else
headlessCmds->Submit(cmds, seccmds, queue, VK_NULL_HANDLE, VK_NULL_HANDLE);
}
void VulkanGraphicsTest::Present(VulkanWindow *window, VkQueue q)
void VulkanGraphicsTest::Present()
{
if(!window)
window = mainWindow;
if(q == VK_NULL_HANDLE)
q = queue;
window->Present(q);
mainWindow->Present(queue);
}
VkPipelineShaderStageCreateInfo VulkanGraphicsTest::CompileShaderModule(
@@ -845,25 +860,10 @@ VkCommandBuffer VulkanGraphicsTest::GetCommandBuffer(VkCommandBufferLevel level,
if(window == NULL)
window = mainWindow;
return window->GetCommandBuffer(level);
}
if(window)
return window->GetCommandBuffer(level);
VkCommandBuffer VulkanWindow::GetCommandBuffer(VkCommandBufferLevel level)
{
std::vector<VkCommandBuffer> &buflist = freeCommandBuffers[level];
if(buflist.empty())
{
buflist.resize(4);
CHECK_VKR(vkAllocateCommandBuffers(
m_Test->device, vkh::CommandBufferAllocateInfo(cmdPool, 4, level), &buflist[0]));
}
VkCommandBuffer ret = buflist.back();
buflist.pop_back();
return ret;
return headlessCmds->GetCommandBuffer(level);
}
template <>
@@ -1136,8 +1136,117 @@ VkSampler VulkanGraphicsTest::createSampler(const VkSamplerCreateInfo *info)
return ret;
}
VulkanCommands::VulkanCommands(VulkanGraphicsTest *test)
{
m_Test = test;
CHECK_VKR(vkCreateCommandPool(
m_Test->device, vkh::CommandPoolCreateInfo(VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
m_Test->queueFamilyIndex),
NULL, &cmdPool));
}
VulkanCommands::~VulkanCommands()
{
vkDestroyCommandPool(m_Test->device, cmdPool, NULL);
for(VkFence fence : fences)
vkDestroyFence(m_Test->device, fence, NULL);
}
VkCommandBuffer VulkanCommands::GetCommandBuffer(VkCommandBufferLevel level)
{
std::vector<VkCommandBuffer> &buflist = freeCommandBuffers[level];
if(buflist.empty())
{
buflist.resize(4);
CHECK_VKR(vkAllocateCommandBuffers(
m_Test->device, vkh::CommandBufferAllocateInfo(cmdPool, 4, level), &buflist[0]));
}
VkCommandBuffer ret = buflist.back();
buflist.pop_back();
return ret;
}
void VulkanCommands::Submit(const std::vector<VkCommandBuffer> &cmds,
const std::vector<VkCommandBuffer> &seccmds, VkQueue q,
VkSemaphore wait, VkSemaphore signal)
{
VkFence fence;
CHECK_VKR(vkCreateFence(m_Test->device, vkh::FenceCreateInfo(), NULL, &fence));
fences.insert(fence);
if(m_Test->hasExt(VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME))
{
VkSubmitInfo2KHR submit = {VK_STRUCTURE_TYPE_SUBMIT_INFO_2_KHR};
std::vector<VkCommandBufferSubmitInfoKHR> cmdSubmits;
for(VkCommandBuffer cmd : cmds)
cmdSubmits.push_back({VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO_KHR, NULL, cmd, 0});
submit.commandBufferInfoCount = (uint32_t)cmdSubmits.size();
submit.pCommandBufferInfos = cmdSubmits.data();
VkSemaphoreSubmitInfoKHR waitInfo = {}, signalInfo = {};
if(wait != VK_NULL_HANDLE)
{
waitInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO_KHR;
waitInfo.semaphore = wait;
waitInfo.stageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT_KHR;
submit.waitSemaphoreInfoCount = 1;
submit.pWaitSemaphoreInfos = &waitInfo;
}
if(signal != VK_NULL_HANDLE)
{
signalInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO_KHR;
signalInfo.semaphore = signal;
signalInfo.stageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT_KHR;
submit.signalSemaphoreInfoCount = 1;
submit.pSignalSemaphoreInfos = &signalInfo;
}
CHECK_VKR(vkQueueSubmit2KHR(q, 1, &submit, fence));
}
else
{
VkPipelineStageFlags waitStage = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
VkSubmitInfo submit = vkh::SubmitInfo(cmds);
if(wait != VK_NULL_HANDLE)
{
submit.waitSemaphoreCount = 1;
submit.pWaitDstStageMask = &waitStage;
submit.pWaitSemaphores = &wait;
}
if(signal != VK_NULL_HANDLE)
{
submit.signalSemaphoreCount = 1;
submit.pSignalSemaphores = &signal;
}
CHECK_VKR(vkQueueSubmit(q, 1, &submit, fence));
}
for(const VkCommandBuffer &cmd : cmds)
pendingCommandBuffers[0].push_back(std::make_pair(cmd, fence));
for(const VkCommandBuffer &cmd : seccmds)
pendingCommandBuffers[1].push_back(std::make_pair(cmd, fence));
}
VulkanWindow::VulkanWindow(VulkanGraphicsTest *test, GraphicsWindow *win)
: GraphicsWindow(win->title)
: GraphicsWindow(win->title), VulkanCommands(test)
{
m_Test = test;
m_Win = win;
@@ -1145,10 +1254,6 @@ VulkanWindow::VulkanWindow(VulkanGraphicsTest *test, GraphicsWindow *win)
{
std::lock_guard<std::mutex> lock(m_Test->mutex);
CHECK_VKR(vkCreateCommandPool(
m_Test->device, vkh::CommandPoolCreateInfo(VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT),
NULL, &cmdPool));
CHECK_VKR(
vkCreateSemaphore(m_Test->device, vkh::SemaphoreCreateInfo(), NULL, &renderStartSemaphore));
CHECK_VKR(
@@ -1193,11 +1298,6 @@ VulkanWindow::~VulkanWindow()
vkDestroySemaphore(m_Test->device, renderStartSemaphore, NULL);
vkDestroySemaphore(m_Test->device, renderEndSemaphore, NULL);
vkDestroyCommandPool(m_Test->device, cmdPool, NULL);
for(VkFence fence : fences)
vkDestroyFence(m_Test->device, fence, NULL);
if(surface)
vkDestroySurfaceKHR(m_Test->instance, surface, NULL);
}
@@ -1328,75 +1428,16 @@ void VulkanWindow::Acquire()
}
void VulkanWindow::Submit(int index, int totalSubmits, const std::vector<VkCommandBuffer> &cmds,
const std::vector<VkCommandBuffer> &seccmds, VkQueue q, bool sync2)
const std::vector<VkCommandBuffer> &seccmds, VkQueue q)
{
VkFence fence;
CHECK_VKR(vkCreateFence(m_Test->device, vkh::FenceCreateInfo(), NULL, &fence));
VkSemaphore signal = VK_NULL_HANDLE, wait = VK_NULL_HANDLE;
fences.insert(fence);
if(index == 0)
wait = renderStartSemaphore;
if(index == totalSubmits - 1)
signal = renderEndSemaphore;
if(sync2)
{
VkSubmitInfo2KHR submit = {VK_STRUCTURE_TYPE_SUBMIT_INFO_2_KHR};
std::vector<VkCommandBufferSubmitInfoKHR> cmdSubmits;
for(VkCommandBuffer cmd : cmds)
cmdSubmits.push_back({VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO_KHR, NULL, cmd, 0});
submit.commandBufferInfoCount = (uint32_t)cmdSubmits.size();
submit.pCommandBufferInfos = cmdSubmits.data();
VkSemaphoreSubmitInfoKHR renderStart = {}, renderEnd = {};
if(index == 0)
{
renderStart.sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO_KHR;
renderStart.semaphore = renderStartSemaphore;
renderStart.stageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT_KHR;
submit.waitSemaphoreInfoCount = 1;
submit.pWaitSemaphoreInfos = &renderStart;
}
if(index == totalSubmits - 1)
{
renderEnd.sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO_KHR;
renderEnd.semaphore = renderEndSemaphore;
renderEnd.stageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT_KHR;
submit.signalSemaphoreInfoCount = 1;
submit.pSignalSemaphoreInfos = &renderEnd;
}
CHECK_VKR(vkQueueSubmit2KHR(q, 1, &submit, fence));
}
else
{
VkPipelineStageFlags waitStage = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
VkSubmitInfo submit = vkh::SubmitInfo(cmds);
if(index == 0)
{
submit.waitSemaphoreCount = 1;
submit.pWaitDstStageMask = &waitStage;
submit.pWaitSemaphores = &renderStartSemaphore;
}
if(index == totalSubmits - 1)
{
submit.signalSemaphoreCount = 1;
submit.pSignalSemaphores = &renderEndSemaphore;
}
CHECK_VKR(vkQueueSubmit(q, 1, &submit, fence));
}
for(const VkCommandBuffer &cmd : cmds)
pendingCommandBuffers[0].push_back(std::make_pair(cmd, fence));
for(const VkCommandBuffer &cmd : seccmds)
pendingCommandBuffers[1].push_back(std::make_pair(cmd, fence));
VulkanCommands::Submit(cmds, seccmds, q, wait, signal);
}
void VulkanWindow::MultiPresent(VkQueue queue, std::vector<VulkanWindow *> windows)
@@ -1463,6 +1504,13 @@ void VulkanWindow::PostPresent(VkResult vkr)
CHECK_VKR(queuePresentError);
}
VulkanCommands::ProcessCompletions();
Acquire();
}
void VulkanCommands::ProcessCompletions()
{
std::set<VkFence> doneFences;
std::map<VkFence, VkResult> fenceStatus;
@@ -1494,8 +1542,6 @@ void VulkanWindow::PostPresent(VkResult vkr)
vkDestroyFence(m_Test->device, *it, NULL);
fences.erase(*it);
}
Acquire();
}
void VulkanWindow::DestroySwapchain()
+29 -12
View File
@@ -107,7 +107,27 @@ struct AllocatedImage
struct VulkanGraphicsTest;
struct VulkanWindow : public GraphicsWindow
struct VulkanCommands
{
public:
VulkanCommands(VulkanGraphicsTest *test);
~VulkanCommands();
VkCommandBuffer GetCommandBuffer(VkCommandBufferLevel level);
void Submit(const std::vector<VkCommandBuffer> &cmds, const std::vector<VkCommandBuffer> &seccmds,
VkQueue q, VkSemaphore wait, VkSemaphore signal);
void ProcessCompletions();
private:
VulkanGraphicsTest *m_Test;
VkCommandPool cmdPool;
std::set<VkFence> fences;
std::vector<VkCommandBuffer> freeCommandBuffers[2];
std::vector<std::pair<VkCommandBuffer, VkFence>> pendingCommandBuffers[2];
};
struct VulkanWindow : public GraphicsWindow, public VulkanCommands
{
VkFormat format;
uint32_t imgIndex = 0;
@@ -139,9 +159,8 @@ struct VulkanWindow : public GraphicsWindow
return fbs[idx];
}
bool Initialised() { return swap != VK_NULL_HANDLE; }
VkCommandBuffer GetCommandBuffer(VkCommandBufferLevel level);
void Submit(int index, int totalSubmits, const std::vector<VkCommandBuffer> &cmds,
const std::vector<VkCommandBuffer> &seccmds, VkQueue q, bool sync2);
const std::vector<VkCommandBuffer> &seccmds, VkQueue q);
static void MultiPresent(VkQueue queue, std::vector<VulkanWindow *> windows);
void Present(VkQueue q);
@@ -162,12 +181,6 @@ private:
VkSemaphore renderStartSemaphore = VK_NULL_HANDLE, renderEndSemaphore = VK_NULL_HANDLE;
std::vector<VkFramebuffer> fbs;
VkCommandPool cmdPool;
std::set<VkFence> fences;
std::vector<VkCommandBuffer> freeCommandBuffers[2];
std::vector<std::pair<VkCommandBuffer, VkFence>> pendingCommandBuffers[2];
GraphicsWindow *m_Win;
VulkanGraphicsTest *m_Test;
};
@@ -189,9 +202,8 @@ struct VulkanGraphicsTest : public GraphicsTest
void FinishUsingBackbuffer(VkCommandBuffer cmd, VkAccessFlags prevUse, VkImageLayout layout,
VulkanWindow *window = NULL);
void Submit(int index, int totalSubmits, const std::vector<VkCommandBuffer> &cmds,
const std::vector<VkCommandBuffer> &seccmds = {}, VulkanWindow *window = NULL,
VkQueue q = VK_NULL_HANDLE, bool sync2 = false);
void Present(VulkanWindow *window = NULL, VkQueue q = VK_NULL_HANDLE);
const std::vector<VkCommandBuffer> &seccmds = {});
void Present();
VkPipelineShaderStageCreateInfo CompileShaderModule(
const std::string &source_text, ShaderLang lang, ShaderStage stage,
@@ -256,6 +268,9 @@ struct VulkanGraphicsTest : public GraphicsTest
// optional extensions, will be added to devExts if supported (allows fallback paths)
std::vector<const char *> optDevExts;
VkQueueFlags queueFlagsRequired = VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT;
VkQueueFlags queueFlagsBanned = 0;
bool hasExt(const char *ext);
// a custom struct to pass to vkDeviceCreateInfo::pNext
@@ -290,6 +305,8 @@ struct VulkanGraphicsTest : public GraphicsTest
VulkanWindow *mainWindow = NULL;
VulkanCommands *headlessCmds = NULL;
// VMA
bool vmaDedicated = false;
VmaAllocator allocator = VK_NULL_HANDLE;
@@ -0,0 +1,36 @@
import renderdoc as rd
import rdtest
import struct
class D3D12_Compute_Only(rdtest.TestCase):
demos_test_name = 'D3D12_Compute_Only'
def check_capture(self):
tex = self.get_resource_by_name("tex").resourceId
bufin = self.get_resource_by_name("bufin").resourceId
bufout = self.get_resource_by_name("bufout").resourceId
self.check_pixel_value(tex, 0, 0, [0.25, 0.5, 0.75, 1.0])
self.controller.SetFrameEvent(self.find_action("Pre-Dispatch").eventId, True)
uints = struct.unpack_from('=4L', self.controller.GetBufferData(bufin, 0, 0), 0)
if not rdtest.value_compare(uints, [111, 111, 111, 111]):
raise rdtest.TestFailureException(
'bufin data is incorrect before dispatch: {}'.format(uints))
uints = struct.unpack_from('=4L', self.controller.GetBufferData(bufout, 0, 0), 0)
if not rdtest.value_compare(uints, [222, 222, 222, 222]):
raise rdtest.TestFailureException(
'bufin data is incorrect before dispatch: {}'.format(uints))
self.controller.SetFrameEvent(self.find_action("Post-Dispatch").eventId, True)
uints = struct.unpack_from('=4L', self.controller.GetBufferData(bufout, 0, 0), 0)
if not rdtest.value_compare(uints, [777, 888, 999, 1110]):
raise rdtest.TestFailureException(
'bufin data is incorrect after dispatch: {}'.format(uints))
+36
View File
@@ -0,0 +1,36 @@
import renderdoc as rd
import rdtest
import struct
class VK_Compute_Only(rdtest.TestCase):
demos_test_name = 'VK_Compute_Only'
def check_capture(self):
tex = self.get_resource_by_name("tex").resourceId
bufin = self.get_resource_by_name("bufin").resourceId
bufout = self.get_resource_by_name("bufout").resourceId
self.check_pixel_value(tex, 0, 0, [0.25, 0.5, 0.75, 1.0])
self.controller.SetFrameEvent(self.find_action("Pre-Dispatch").eventId, True)
uints = struct.unpack_from('=4L', self.controller.GetBufferData(bufin, 0, 0), 0)
if not rdtest.value_compare(uints, [111, 111, 111, 111]):
raise rdtest.TestFailureException(
'bufin data is incorrect before dispatch: {}'.format(uints))
uints = struct.unpack_from('=4L', self.controller.GetBufferData(bufout, 0, 0), 0)
if not rdtest.value_compare(uints, [222, 222, 222, 222]):
raise rdtest.TestFailureException(
'bufout data is incorrect before dispatch: {}'.format(uints))
self.controller.SetFrameEvent(self.find_action("Post-Dispatch").eventId, True)
uints = struct.unpack_from('=4L', self.controller.GetBufferData(bufout, 0, 0), 0)
if not rdtest.value_compare(uints, [777, 888, 999, 1110]):
raise rdtest.TestFailureException(
'bufout data is incorrect after dispatch: {}'.format(uints))