Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion test_apps/cube_handle_vk_linux/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,10 @@ FetchContent_Declare(
# v2.27.0: window-space / HUD swapchains prefer the _SRGB sibling of
# R8G8B8A8 (dxr::ChooseWindowSpaceSwapchainFormat; ADR-044 §7,
# displayxr-common#72) — a UNORM HUD of encoded bytes was encoded twice.
GIT_TAG v2.27.0
# v2.28.0: dxr::VkFrameRing (common/vk_frame_ring.h) — N frames in flight,
# one vkQueueSubmit per frame (INV-4.10, #1917). The Vulkan cubes use it.
# v2.29.0: dxr::CursorDepth (common/cursor_depth.h, ADR-046 Amendment 2).
GIT_TAG v2.29.0
GIT_SHALLOW TRUE
)
FetchContent_MakeAvailable(displayxr_common)
Expand Down
96 changes: 46 additions & 50 deletions test_apps/cube_handle_vk_linux/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
#include <X11/keysym.h>

#include <vulkan/vulkan.h>
#include <vk_frame_ring.h>

#define XR_USE_GRAPHICS_API_VULKAN
#include <openxr/openxr.h>
Expand Down Expand Up @@ -1013,9 +1014,10 @@ struct VkRenderer {
uint32_t fbWidth = 0;
uint32_t fbHeight = 0;

VkCommandPool commandPool = VK_NULL_HANDLE;
VkCommandBuffer commandBuffer = VK_NULL_HANDLE;
VkFence frameFence = VK_NULL_HANDLE;
VkCommandPool commandPool = VK_NULL_HANDLE; // init-time texture uploads only
// INV-4.10 / #1917: N frames in flight, one submit per frame, never a wait
// on the frame just submitted (replaces the old single cmd + frameFence).
dxr::VkFrameRing ring;

float cubeRotation = 0.0f;

Expand Down Expand Up @@ -1115,12 +1117,32 @@ static bool InitializeVkRenderer(VkRenderer& renderer, VkDevice device, VkPhysic
subpass.pColorAttachments = &colorRef;
subpass.pDepthStencilAttachment = &depthRef;

// The single depth image is shared by every frame; with N frames in
// flight (INV-4.10) the next frame's depth clear must wait for the
// previous frame's depth writes (WAW), and the colour layout
// transition must wait for colour output.
VkSubpassDependency dep = {};
dep.srcSubpass = VK_SUBPASS_EXTERNAL;
dep.dstSubpass = 0;
dep.srcStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT |
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dep.dstStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT |
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dep.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
dep.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;

VkRenderPassCreateInfo rpInfo = {};
rpInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
rpInfo.attachmentCount = 2;
rpInfo.pAttachments = attachments;
rpInfo.subpassCount = 1;
rpInfo.pSubpasses = &subpass;
rpInfo.dependencyCount = 1;
rpInfo.pDependencies = &dep;

if (vkCreateRenderPass(device, &rpInfo, nullptr, &renderer.renderPass) != VK_SUCCESS) {
LOG_ERROR("Failed to create render pass");
Expand Down Expand Up @@ -1476,7 +1498,7 @@ static bool InitializeVkRenderer(VkRenderer& renderer, VkDevice device, VkPhysic
memcpy(data, gridVerts.data(), (size_t)gridBufSize);
vkUnmapMemory(device, renderer.gridVertexMemory);

// Command pool + command buffer
// Command pool (init-time texture uploads)
{
VkCommandPoolCreateInfo poolInfo = {};
poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
Expand All @@ -1487,27 +1509,13 @@ static bool InitializeVkRenderer(VkRenderer& renderer, VkDevice device, VkPhysic
LOG_ERROR("Failed to create command pool");
return false;
}

VkCommandBufferAllocateInfo allocInfo = {};
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
allocInfo.commandPool = renderer.commandPool;
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
allocInfo.commandBufferCount = 1;

if (vkAllocateCommandBuffers(device, &allocInfo, &renderer.commandBuffer) != VK_SUCCESS) {
LOG_ERROR("Failed to allocate command buffer");
return false;
}
}

// Frame fence
// Frame ring (per-frame command buffers + fences)
{
VkFenceCreateInfo fenceInfo = {};
fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;

if (vkCreateFence(device, &fenceInfo, nullptr, &renderer.frameFence) != VK_SUCCESS) {
LOG_ERROR("Failed to create fence");
dxr::VkFrameRing::Config ringCfg; // default 3 frames in flight; push constants, no UBO
if (!renderer.ring.init(device, physDevice, queue, queueFamilyIndex, ringCfg)) {
LOG_ERROR("Failed to create frame ring");
return false;
}
}
Expand Down Expand Up @@ -1701,19 +1709,12 @@ static void RenderScene(
VkRenderer& renderer, uint32_t imageIndex,
const EyeRenderParams* eyes, int eyeCount)
{
VkDevice device = renderer.device;

// Wait for previous frame
vkWaitForFences(device, 1, &renderer.frameFence, VK_TRUE, UINT64_MAX);
vkResetFences(device, 1, &renderer.frameFence);

// Begin command buffer
VkCommandBuffer cmd = renderer.commandBuffer;
vkResetCommandBuffer(cmd, 0);
VkCommandBufferBeginInfo beginInfo = {};
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
vkBeginCommandBuffer(cmd, &beginInfo);
// Waits only the slot used N frames ago (INV-4.10), resets + begins its cmd
VkCommandBuffer cmd = renderer.ring.beginFrame();
if (cmd == VK_NULL_HANDLE) {
LOG_ERROR("Frame ring beginFrame failed");
return;
}

// Begin render pass with full SBS framebuffer
VkClearValue clearValues[2] = {};
Expand Down Expand Up @@ -1819,23 +1820,20 @@ static void RenderScene(
}

vkCmdEndRenderPass(cmd);
vkEndCommandBuffer(cmd);

// Submit
VkSubmitInfo submitInfo = {};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &cmd;

vkQueueSubmit(renderer.graphicsQueue, 1, &submitInfo, renderer.frameFence);

// Wait for completion before returning (runtime needs the image ready)
vkWaitForFences(device, 1, &renderer.frameFence, VK_TRUE, UINT64_MAX);
// ONE submit with the slot fence, no wait. The caller releases the
// swapchain image after this; the runtime composes on the same queue, so
// this work is ordered ahead of it.
VkResult submitResult = renderer.ring.endFrame();
if (submitResult != VK_SUCCESS) {
LOG_ERROR("Frame submit failed: %d", (int)submitResult);
}
}

static void CleanupVkRenderer(VkRenderer& renderer) {
if (!renderer.device) return;

renderer.ring.waitAll();
vkDeviceWaitIdle(renderer.device);

for (auto fb : renderer.framebuffers)
Expand All @@ -1859,10 +1857,7 @@ static void CleanupVkRenderer(VkRenderer& renderer) {
renderer.depthMemory = VK_NULL_HANDLE;
}

if (renderer.frameFence) {
vkDestroyFence(renderer.device, renderer.frameFence, nullptr);
renderer.frameFence = VK_NULL_HANDLE;
}
renderer.ring.destroy();
if (renderer.commandPool) {
vkDestroyCommandPool(renderer.device, renderer.commandPool, nullptr);
renderer.commandPool = VK_NULL_HANDLE;
Expand Down Expand Up @@ -3083,6 +3078,7 @@ int main(int argc, char** argv) {
VkRenderer vkRenderer = {};
if (!InitializeVkRenderer(vkRenderer, vkDevice, physDevice, graphicsQueue, queueFamilyIndex, colorFormat)) {
LOG_ERROR("Vulkan renderer initialization failed");
vkRenderer.ring.destroy(); // before vkDestroyDevice (dtor would run after)
CleanupOpenXR(xr);
vkDestroyDevice(vkDevice, nullptr);
vkDestroyInstance(vkInstance, nullptr);
Expand Down
5 changes: 4 additions & 1 deletion test_apps/cube_zones_vk_linux/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,10 @@ FetchContent_Declare(
# v2.27.0: window-space / HUD swapchains prefer the _SRGB sibling of
# R8G8B8A8 (dxr::ChooseWindowSpaceSwapchainFormat; ADR-044 §7,
# displayxr-common#72) — a UNORM HUD of encoded bytes was encoded twice.
GIT_TAG v2.27.0
# v2.28.0: dxr::VkFrameRing (common/vk_frame_ring.h) — N frames in flight,
# one vkQueueSubmit per frame (INV-4.10, #1917). The Vulkan cubes use it.
# v2.29.0: dxr::CursorDepth (common/cursor_depth.h, ADR-046 Amendment 2).
GIT_TAG v2.29.0
GIT_SHALLOW TRUE
)
FetchContent_MakeAvailable(displayxr_common)
Expand Down
Loading
Loading