diff --git a/renderdoc/core/core.cpp b/renderdoc/core/core.cpp index 428852117..216e88f76 100644 --- a/renderdoc/core/core.cpp +++ b/renderdoc/core/core.cpp @@ -475,6 +475,10 @@ bool RenderDoc::ShouldTriggerCapture(uint32_t frameNumber) m_Cap = false; + // Hack while no keyboard input supported on xcb + if(frameNumber == 10) + return true; + set frames; frames.swap(m_QueuedFrameCaptures); for(auto it=frames.begin(); it != frames.end(); ++it) diff --git a/renderdoc/driver/vulkan/vk_hooks_linux.cpp b/renderdoc/driver/vulkan/vk_hooks_linux.cpp index a28e8a713..b36ca0d7c 100644 --- a/renderdoc/driver/vulkan/vk_hooks_linux.cpp +++ b/renderdoc/driver/vulkan/vk_hooks_linux.cpp @@ -34,9 +34,6 @@ #include "common/threading.h" #include "serialise/string_utils.h" -// bit of a hack -namespace Keyboard { void CloneDisplay(Display *dpy); } - void *libvulkandlsymHandle = RTLD_NEXT; // default to RTLD_NEXT, but overwritten if app calls dlopen() on real libvulkan // don't want these definitions, the only place we'll use these is as parameter/variable names @@ -189,11 +186,6 @@ class VulkanHook : LibraryHook if(libName) LinuxHookLibrary("libvulkan.so", &libHooked); - // SUUUUPer hack. I guess Keyboard needs to support - // xcb connections as well, and init it whenever - // a WSI swapchain gets created on it - Keyboard::CloneDisplay(XOpenDisplay(NULL)); - bool success = SetupHooks(VK); if(!success) return false; diff --git a/renderdoc/driver/vulkan/vk_replay.cpp b/renderdoc/driver/vulkan/vk_replay.cpp index 0e8ee650f..512d40529 100644 --- a/renderdoc/driver/vulkan/vk_replay.cpp +++ b/renderdoc/driver/vulkan/vk_replay.cpp @@ -22,6 +22,9 @@ * THE SOFTWARE. ******************************************************************************/ +#include +#include + #include "vk_replay.h" #include "vk_core.h" #include "vk_resources.h" @@ -29,15 +32,23 @@ #include "serialise/string_utils.h" VulkanReplay::OutputWindow::OutputWindow() : wnd(NULL_WND_HANDLE), width(0), height(0), - colimg(VK_NULL_HANDLE), colmem(VK_NULL_HANDLE), dsimg(VK_NULL_HANDLE), dsmem(VK_NULL_HANDLE) + dsimg(VK_NULL_HANDLE), dsmem(VK_NULL_HANDLE) { + swap = VK_NULL_HANDLE; + for(size_t i=0; i < ARRAY_COUNT(colimg); i++) + { + colimg[i] = VK_NULL_HANDLE; + colview[i] = VK_NULL_HANDLE; + } + VkImageMemoryBarrier t = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, NULL, 0, 0, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_UNDEFINED, 0, 0, VK_NULL_HANDLE, { VK_IMAGE_ASPECT_COLOR, 0, 1, 0, 1 } }; - coltrans = t; + for(size_t i=0; i < ARRAY_COUNT(coltrans); i++) + coltrans[i] = t; t.subresourceRange.aspect = VK_IMAGE_ASPECT_DEPTH; depthtrans = t; @@ -48,31 +59,99 @@ VulkanReplay::OutputWindow::OutputWindow() : wnd(NULL_WND_HANDLE), width(0), hei void VulkanReplay::OutputWindow::SetCol(VkDeviceMemory mem, VkImage img) { - colmem = mem; - colimg = img; - coltrans.image = img; - coltrans.oldLayout = coltrans.newLayout = VK_IMAGE_LAYOUT_UNDEFINED; } void VulkanReplay::OutputWindow::SetDS(VkDeviceMemory mem, VkImage img) { - dsmem = mem; - dsimg = img; - depthtrans.image = stenciltrans.image = img; - depthtrans.oldLayout = depthtrans.newLayout = - stenciltrans.oldLayout = stenciltrans.newLayout = VK_IMAGE_LAYOUT_UNDEFINED; } void VulkanReplay::OutputWindow::MakeTargets(const VulkanFunctions &vk, VkDevice device, bool depth) { - if(colimg != VK_NULL_HANDLE) - { - VkAttachmentViewCreateInfo info = { - VK_STRUCTURE_TYPE_ATTACHMENT_VIEW_CREATE_INFO, NULL, - colimg, VK_FORMAT_R8G8B8A8_UNORM, 0, 0, 1, - 0 }; + vk.vkDeviceWaitIdle(device); - vk.vkCreateAttachmentView(device, &info, &colview); + for(size_t i=0; i < ARRAY_COUNT(colimg); i++) + { + if(colimg[i] != VK_NULL_HANDLE) + { + vk.vkDestroyAttachmentView(device, colview[i]); + colimg[i] = VK_NULL_HANDLE; + colview[i] = VK_NULL_HANDLE; + } + } + + if(dsimg != VK_NULL_HANDLE) + { + vk.vkDestroyAttachmentView(device, dsview); + vk.vkDestroyImage(device, dsimg); + vk.vkFreeMemory(device, dsmem); + + dsview = VK_NULL_HANDLE; + dsimg = VK_NULL_HANDLE; + dsmem = VK_NULL_HANDLE; + } + + VkSwapChainWSI old = swap; + + VkPlatformHandleXcbWSI handle; + handle.connection = connection; + handle.root = screen->root; + + VkSurfaceDescriptionWindowWSI surfDesc = { VK_STRUCTURE_TYPE_SURFACE_DESCRIPTION_WINDOW_WSI, NULL, VK_PLATFORM_X11_WSI, &handle, &wnd }; + + VkSwapChainCreateInfoWSI swapInfo = { + VK_STRUCTURE_TYPE_SWAP_CHAIN_CREATE_INFO_WSI, NULL, (VkSurfaceDescriptionWSI *)&surfDesc, + 2, VK_FORMAT_B8G8R8A8_UNORM, { width, height }, 0, + VK_SURFACE_TRANSFORM_NONE_WSI, 1, VK_PRESENT_MODE_IMMEDIATE_WSI, + old, true, + }; + + VkResult res = vk.vkCreateSwapChainWSI(device, &swapInfo, &swap); + RDCASSERT(res == VK_SUCCESS); + + if(old != VK_NULL_HANDLE) + vk.vkDestroySwapChainWSI(device, old); + + size_t sz; + res = vk.vkGetSwapChainInfoWSI(device, swap, VK_SWAP_CHAIN_INFO_TYPE_IMAGES_WSI, &sz, NULL); + RDCASSERT(res == VK_SUCCESS); + + numImgs = sz/sizeof(VkSwapChainImagePropertiesWSI); + + VkSwapChainImagePropertiesWSI* imgs = new VkSwapChainImagePropertiesWSI[numImgs]; + res = vk.vkGetSwapChainInfoWSI(device, swap, VK_SWAP_CHAIN_INFO_TYPE_IMAGES_WSI, &sz, imgs); + RDCASSERT(res == VK_SUCCESS); + + for(size_t i=0; i < numImgs; i++) + { + colimg[i] = imgs[i].image; + coltrans[i].image = imgs[i].image; + coltrans[i].oldLayout = coltrans[i].newLayout = VK_IMAGE_LAYOUT_UNDEFINED; + } + + if(depth) + { + VULKANNOTIMP("Allocating depth-stencil image"); + + /* + dsmem = mem; + dsimg = img; + depthtrans.image = stenciltrans.image = img; + depthtrans.oldLayout = depthtrans.newLayout = + stenciltrans.oldLayout = stenciltrans.newLayout = VK_IMAGE_LAYOUT_UNDEFINED; + */ + } + + for(uint32_t i=0; i < numImgs; i++) + { + if(colimg[i] != VK_NULL_HANDLE) + { + VkAttachmentViewCreateInfo info = { + VK_STRUCTURE_TYPE_ATTACHMENT_VIEW_CREATE_INFO, NULL, + colimg[i], VK_FORMAT_B8G8R8A8_UNORM, 0, 0, 1, + 0 }; + + vk.vkCreateAttachmentView(device, &info, &colview[i]); + } } if(dsimg != VK_NULL_HANDLE) @@ -84,11 +163,6 @@ void VulkanReplay::OutputWindow::MakeTargets(const VulkanFunctions &vk, VkDevice vk.vkCreateAttachmentView(device, &info, &dsview); } - - if(depth) - { - VULKANNOTIMP("Allocating depth-stencil image"); - } } VulkanReplay::VulkanReplay() @@ -213,12 +287,12 @@ void VulkanReplay::RenderCheckerboard(Vec3f light, Vec3f dark) VkResult res = vk.vkBeginCommandBuffer(cmd, &beginInfo); - outw.coltrans.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - vk.vkCmdPipelineBarrier(cmd, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, false, 1, (const void **)&outw.coltrans); - outw.coltrans.oldLayout = outw.coltrans.newLayout; + outw.curcoltrans->newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + vk.vkCmdPipelineBarrier(cmd, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, false, 1, (void **)&outw.curcoltrans); + outw.curcoltrans->oldLayout = outw.curcoltrans->newLayout; VkClearColorValue clearColor = { { RANDF(0.0f, 1.0f), RANDF(0.0f, 1.0f), RANDF(0.0f, 1.0f), 1.0f, } }; - vk.vkCmdClearColorImage(cmd, outw.colimg, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, &clearColor, 1, &outw.coltrans.subresourceRange); + vk.vkCmdClearColorImage(cmd, outw.colimg[outw.curidx], VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, &clearColor, 1, &outw.curcoltrans->subresourceRange); res = vk.vkEndCommandBuffer(cmd); @@ -263,29 +337,7 @@ bool VulkanReplay::CheckResizeOutputWindow(uint64_t id) { bool depth = (outw.dsimg != VK_NULL_HANDLE); - if(outw.colimg != VK_NULL_HANDLE) - m_pDriver->m_Real.vkDestroyImage(m_pDriver->GetDev(), outw.colimg); - - if(outw.dsimg != VK_NULL_HANDLE) - m_pDriver->m_Real.vkDestroyImage(m_pDriver->GetDev(), outw.dsimg); - - // VKTODO: update WSI code - - /* - VkDeviceMemory mem = VK_NULL_HANDLE; - VkImage img = VK_NULL_HANDLE; - - VkResult vk = GetImage - - outw.SetCol(mem, img); - - if(vk != VK_SUCCESS) - { - RDCERR("Error creating new resized image: %x", vk); - } - outw.MakeTargets(m_pDriver->m_Real, m_pDriver->GetDev(), depth); - */ } return true; @@ -298,6 +350,30 @@ void VulkanReplay::BindOutputWindow(uint64_t id, bool depth) { m_ActiveWinID = id; m_BindDepth = depth; + + auto it = m_OutputWindows.find(id); + if(id == 0 || it == m_OutputWindows.end()) + return; + + OutputWindow &outw = it->second; + + VkDevice dev = m_pDriver->GetDev(); + VkCmdBuffer cmd = m_pDriver->GetCmd(); + VkQueue q = m_pDriver->GetQ(); + const VulkanFunctions &vk = m_pDriver->m_Real; + + VkSemaphore sem; + VkSemaphoreCreateInfo semInfo = { VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, NULL, VK_FENCE_CREATE_SIGNALED_BIT }; + + vk.vkCreateSemaphore(dev, &semInfo, &sem); + + vk.vkAcquireNextImageWSI(dev, outw.swap, UINT64_MAX, sem, &outw.curidx); + + outw.curcoltrans = &outw.coltrans[outw.curidx]; + + vk.vkQueueWaitSemaphore(q, sem); + + vk.vkDestroySemaphore(dev, sem); } void VulkanReplay::ClearOutputWindowColour(uint64_t id, float col[4]) @@ -332,6 +408,8 @@ void VulkanReplay::FlipOutputWindow(uint64_t id) VkQueue q = m_pDriver->GetQ(); const VulkanFunctions &vk = m_pDriver->m_Real; + // copy fake backbuffer into actual backbuffer +#if 0 ResourceId resid; VkImage fakeBBIm = VK_NULL_HANDLE; VkDeviceMemory fakeBBMem = VK_NULL_HANDLE; @@ -345,12 +423,14 @@ void VulkanReplay::FlipOutputWindow(uint64_t id) vk.vkBeginCommandBuffer(cmd, 0); - vk.vkCmdPipelineBarrier(cmd, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, false, 1, (const void * const*)&fakeTrans); + void *barrier = (void *)&fakeTrans; + + vk.vkCmdPipelineBarrier(cmd, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, false, 1, &barrier); fakeTrans.oldLayout = fakeTrans.newLayout; - outw.coltrans.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DESTINATION_OPTIMAL; - vk.vkCmdPipelineBarrier(cmd, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, false, 1, (const void * const*)&outw.coltrans); - outw.coltrans.oldLayout = outw.coltrans.newLayout; + outw.curcoltrans->newLayout = VK_IMAGE_LAYOUT_TRANSFER_DESTINATION_OPTIMAL; + vk.vkCmdPipelineBarrier(cmd, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, false, 1, &outw.curcoltrans); + outw.curcoltrans->oldLayout = outw.curcoltrans->newLayout; VkImageCopy region = { { VK_IMAGE_ASPECT_COLOR, 0, 0}, { 0, 0, 0 }, @@ -360,21 +440,24 @@ void VulkanReplay::FlipOutputWindow(uint64_t id) vk.vkCmdCopyImage(cmd, fakeBBIm, VK_IMAGE_LAYOUT_TRANSFER_SOURCE_OPTIMAL, outw.colimg, VK_IMAGE_LAYOUT_TRANSFER_DESTINATION_OPTIMAL, 1, ®ion); fakeTrans.newLayout = VK_IMAGE_LAYOUT_PRESENT_SOURCE_WSI; - vk.vkCmdPipelineBarrier(cmd, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, false, 1, (const void * const*)&fakeTrans); + vk.vkCmdPipelineBarrier(cmd, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, false, 1, &barrier); - outw.coltrans.newLayout = VK_IMAGE_LAYOUT_PRESENT_SOURCE_WSI; - vk.vkCmdPipelineBarrier(cmd, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, false, 1, (const void * const*)&outw.coltrans); - outw.coltrans.oldLayout = outw.coltrans.newLayout; + outw.curcoltrans->newLayout = VK_IMAGE_LAYOUT_PRESENT_SOURCE_WSI; + vk.vkCmdPipelineBarrier(cmd, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, false, 1, &outw.curcoltrans); + outw.curcoltrans->oldLayout = outw.curcoltrans->newLayout; vk.vkEndCommandBuffer(cmd); vk.vkQueueSubmit(q, 1, &cmd, VK_NULL_HANDLE); +#endif - // VKTODO: update WSI code - /* - // present final image - Present(); - */ + { + VkPresentInfoWSI presentInfo = { VK_STRUCTURE_TYPE_QUEUE_PRESENT_INFO_WSI, NULL, 1, &outw.swap, &outw.curidx }; + + vk.vkQueuePresentWSI(q, &presentInfo); + + vk.vkQueueWaitIdle(q); + } vk.vkDeviceWaitIdle(dev); } @@ -387,11 +470,25 @@ void VulkanReplay::DestroyOutputWindow(uint64_t id) OutputWindow &outw = it->second; - if(outw.colimg != VK_NULL_HANDLE) - m_pDriver->m_Real.vkDestroyImage(m_pDriver->GetDev(), outw.colimg); + const VulkanFunctions &vk = m_pDriver->m_Real; + VkDevice device = m_pDriver->GetDev(); + + for(size_t i=0; i < ARRAY_COUNT(outw.colimg); i++) + { + if(outw.colimg[i] != VK_NULL_HANDLE) + { + vk.vkDestroyAttachmentView(device, outw.colview[i]); + } + } if(outw.dsimg != VK_NULL_HANDLE) - m_pDriver->m_Real.vkDestroyImage(m_pDriver->GetDev(), outw.dsimg); + { + vk.vkDestroyAttachmentView(device, outw.dsview); + vk.vkDestroyImage(device, outw.dsimg); + vk.vkFreeMemory(device, outw.dsmem); + } + + vk.vkDestroySwapChainWSI(device, outw.swap); m_OutputWindows.erase(it); } @@ -411,22 +508,6 @@ uint64_t VulkanReplay::MakeOutputWindow(void *wn, bool depth) m_OutputWindows[id].width = w; m_OutputWindows[id].height = h; - // VKTODO: update WSI code - /* - - VkDeviceMemory mem = VK_NULL_HANDLE; - VkImage img = VK_NULL_HANDLE; - - VkResult vk = GetImage() - - m_OutputWindows[id].SetCol(mem, img); - - if(vk != VK_SUCCESS) - { - RDCERR("Error creating new resized image: %x", vk); - } - */ - m_OutputWindows[id].MakeTargets(m_pDriver->m_Real, m_pDriver->GetDev(), depth); } @@ -477,7 +558,7 @@ FetchTexture VulkanReplay::GetTexture(ResourceId id) ret.format.special = false; ret.format.specialFormat = eSpecial_Unknown; ret.format.srgbCorrected = false; - ret.format.strname = "R8G8B8A8_UNORM"; + ret.format.strname = "B8G8R8A8_UNORM"; return ret; } diff --git a/renderdoc/driver/vulkan/vk_replay.h b/renderdoc/driver/vulkan/vk_replay.h index 8ea6e2e95..be1a79ca6 100644 --- a/renderdoc/driver/vulkan/vk_replay.h +++ b/renderdoc/driver/vulkan/vk_replay.h @@ -37,9 +37,9 @@ #elif defined(__linux__) -#include -#define WINDOW_HANDLE_DECL Display *display; Drawable wnd; -#define NULL_WND_HANDLE 0 +#include +#define WINDOW_HANDLE_DECL xcb_connection_t *connection; xcb_screen_t *screen; xcb_window_t wnd; +#define NULL_WND_HANDLE xcb_window_t(0) #endif @@ -170,10 +170,14 @@ class VulkanReplay : public IReplayDriver int32_t width, height; - VkImage colimg; - VkDeviceMemory colmem; - VkAttachmentView colview; - VkImageMemoryBarrier coltrans; + VkSwapChainWSI swap; + uint32_t numImgs; + VkImage colimg[8]; + VkAttachmentView colview[8]; + VkImageMemoryBarrier coltrans[8]; + VkImageMemoryBarrier *curcoltrans; + uint32_t curidx; + VkImage dsimg; VkDeviceMemory dsmem; VkAttachmentView dsview; diff --git a/renderdoc/driver/vulkan/vk_replay_linux.cpp b/renderdoc/driver/vulkan/vk_replay_linux.cpp index 05906f1b5..a21127ceb 100644 --- a/renderdoc/driver/vulkan/vk_replay_linux.cpp +++ b/renderdoc/driver/vulkan/vk_replay_linux.cpp @@ -28,8 +28,9 @@ void VulkanReplay::OutputWindow::SetWindowHandle(void *wn) { void **displayAndDrawable = (void **)wn; - display = (Display *)displayAndDrawable[0]; - wnd = (Window)displayAndDrawable[1]; + connection = (xcb_connection_t *)displayAndDrawable[0]; + screen = (xcb_screen_t *)displayAndDrawable[1]; + wnd = (xcb_window_t)(size_t)displayAndDrawable[2]; } void VulkanReplay::GetOutputWindowDimensions(uint64_t id, int32_t &w, int32_t &h) @@ -39,13 +40,13 @@ void VulkanReplay::GetOutputWindowDimensions(uint64_t id, int32_t &w, int32_t &h OutputWindow &outw = m_OutputWindows[id]; - Window rootwin; - int x, y; - unsigned int width, height, border, depth; - XGetGeometry(outw.display, outw.wnd, &rootwin, &x, &y, &width, &height, &border, &depth); + xcb_get_geometry_cookie_t geomCookie = xcb_get_geometry (outw.connection, outw.wnd); // window is a xcb_drawable_t + xcb_get_geometry_reply_t *geom = xcb_get_geometry_reply (outw.connection, geomCookie, NULL); - w = (int32_t)width; - h = (int32_t)height; + w = (int32_t)geom->width; + h = (int32_t)geom->height; + + free(geom); } bool VulkanReplay::IsOutputWindowVisible(uint64_t id)