From a6381b95c00090a86913cc5bc47dc56ddf7ac900 Mon Sep 17 00:00:00 2001 From: Sean Purcell Date: Tue, 31 Jul 2018 11:08:32 -0400 Subject: [PATCH 01/12] Add support for rendering to a surface in virtual swapchain - Only Android supported for now --- .../cc/base_swapchain.cpp | 287 ++++++++++++++++++ .../vk_virtual_swapchain/cc/base_swapchain.h | 67 ++++ core/vulkan/vk_virtual_swapchain/cc/layer.cpp | 17 +- core/vulkan/vk_virtual_swapchain/cc/layer.h | 16 + .../vk_virtual_swapchain/cc/platform.cpp | 38 +++ .../vulkan/vk_virtual_swapchain/cc/platform.h | 30 ++ .../vk_virtual_swapchain/cc/swapchain.cpp | 6 + .../vk_virtual_swapchain/cc/swapchain.h | 3 +- .../cc/virtual_swapchain.cpp | 20 +- .../cc/virtual_swapchain.h | 23 +- 10 files changed, 503 insertions(+), 4 deletions(-) create mode 100644 core/vulkan/vk_virtual_swapchain/cc/base_swapchain.cpp create mode 100644 core/vulkan/vk_virtual_swapchain/cc/base_swapchain.h create mode 100644 core/vulkan/vk_virtual_swapchain/cc/platform.cpp create mode 100644 core/vulkan/vk_virtual_swapchain/cc/platform.h diff --git a/core/vulkan/vk_virtual_swapchain/cc/base_swapchain.cpp b/core/vulkan/vk_virtual_swapchain/cc/base_swapchain.cpp new file mode 100644 index 0000000000..1096e9b99d --- /dev/null +++ b/core/vulkan/vk_virtual_swapchain/cc/base_swapchain.cpp @@ -0,0 +1,287 @@ +/* + * Copyright (C) 2018 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "platform.h" + +#include "base_swapchain.h" + +namespace swapchain { + +BaseSwapchain::BaseSwapchain(VkInstance instance, VkDevice device, uint32_t queue, + VkCommandPool command_pool, uint32_t num_images, + const InstanceData *instance_functions, + const DeviceData *device_functions, + const VkSwapchainCreateInfoKHR *swapchain_info, + const VkAllocationCallbacks *pAllocator, + const void *platform_info) + : instance_(instance), + device_(device), + instance_functions_(instance_functions), + device_functions_(device_functions), + swapchain_info_(*swapchain_info) +{ + + if (platform_info == nullptr) { + return; + } + + CreateSurface(instance_functions, instance, platform_info, pAllocator, &surface_); + if (surface_ == 0) { + // Surface creation failed + return; + } + + { + // Create the swapchain + VkSwapchainCreateInfoKHR createInfo = { + VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, // sType + nullptr, // pNext + 0, // flags + surface_, // surface + num_images, // minImageCount + swapchain_info_.imageFormat, // imageFormat + swapchain_info_.imageColorSpace, // imageColorSpace + swapchain_info_.imageExtent, // imageExtent + swapchain_info_.imageArrayLayers, // arrayLayers + VK_IMAGE_USAGE_TRANSFER_DST_BIT, // imageUsage + VK_SHARING_MODE_EXCLUSIVE, // imageSharingMode, + 0, // queueFamilyIndexCount + nullptr, // pQueueFamilyIndices + swapchain_info_.preTransform, // preTransform + swapchain_info_.compositeAlpha, // compositeAlpha + VK_PRESENT_MODE_FIFO_KHR, // presentMode + VK_TRUE, // clipped + 0, // oldSwapchain + }; + if (device_functions_->vkCreateSwapchainKHR(device_, &createInfo, pAllocator, &swapchain_) != VK_SUCCESS) { + // Creating swapchain failed + swapchain_ = 0; + return; + } + } + + uint32_t numImages = 0; + device_functions_->vkGetSwapchainImagesKHR(device, swapchain_, &numImages, nullptr); + images_.resize(numImages); + device_functions_->vkGetSwapchainImagesKHR(device, swapchain_, &numImages, images_.data()); + + VkCommandBufferAllocateInfo command_buffer_info = { + VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, // sType + nullptr, // pNext + command_pool, // commandPool + VK_COMMAND_BUFFER_LEVEL_PRIMARY, // level + 1, // commandBufferCount + }; + device_functions_->vkAllocateCommandBuffers(device, &command_buffer_info, &command_buffer_); + set_dispatch_from_parent(command_buffer_, device); + + { + VkSemaphoreCreateInfo createInfo = { + VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, // sType + nullptr, // pNext + 0, // flags + }; + if (device_functions_->vkCreateSemaphore(device_, &createInfo, pAllocator, + &acquire_semaphore_) != VK_SUCCESS) { + return; + } + if (device_functions_->vkCreateSemaphore(device_, &createInfo, pAllocator, + &blit_semaphore_) != VK_SUCCESS) { + return; + } + } + { + VkFenceCreateInfo createInfo = { + VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, // sType + nullptr, // pNext + 0, // flags + }; + if (device_functions_->vkCreateFence(device_, &createInfo, pAllocator, + &blit_fence_) != VK_SUCCESS) { + return; + } + } +} + +void BaseSwapchain::Destroy(const VkAllocationCallbacks *pAllocator) { + device_functions_->vkDestroySemaphore(device_, acquire_semaphore_, pAllocator); + acquire_semaphore_ = VK_NULL_HANDLE; + + device_functions_->vkDestroySemaphore(device_, blit_semaphore_, pAllocator); + blit_semaphore_ = VK_NULL_HANDLE; + + device_functions_->vkDestroyFence(device_, blit_fence_, pAllocator); + blit_fence_ = VK_NULL_HANDLE; + + device_functions_->vkDestroySwapchainKHR(device_, swapchain_, pAllocator); + swapchain_ = VK_NULL_HANDLE; + + instance_functions_->vkDestroySurfaceKHR(instance_, surface_, pAllocator); + surface_ = VK_NULL_HANDLE; +} + +VkResult BaseSwapchain::PresentFrom(VkQueue queue, VkImage image) { + std::unique_lock guard(present_lock_); + VkResult res; + uint32_t index = 0; + // TODO: the error return values here aren't necessarily valid return values + // for VkQueueSubmit + if ((res = device_functions_->vkAcquireNextImageKHR(device_, swapchain_, 0, acquire_semaphore_, + VK_NULL_HANDLE, &index)) != VK_SUCCESS) { + return res; + } + + if ((res = device_functions_->vkResetCommandBuffer(command_buffer_, 0)) != VK_SUCCESS) { + return res; + } + VkCommandBufferBeginInfo beginInfo = { + VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, // sType + 0, // pNext + VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, // flags + nullptr, // pInheritanceInfo + }; + if ((res = device_functions_->vkBeginCommandBuffer(command_buffer_, &beginInfo)) != VK_SUCCESS) { + return res; + } + + // The source image is already in VK_IMAGE_LAYOUT_TRANSFER_SRC, we need to + // transition our image between VK_IMAGE_LAYOUT_TRANSFER_DST and + // VK_IMAGE_LAYOUT_SHADER_PRESENT_KHR + VkImageMemoryBarrier initialBarrier = { + VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType + nullptr, // pNext + 0, // srcAccessFlags + VK_ACCESS_TRANSFER_WRITE_BIT, // dstAccessFlags + VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, // oldLayout + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // newLayout + VK_QUEUE_FAMILY_IGNORED, // srcQueueFamilyIndex + VK_QUEUE_FAMILY_IGNORED, // dstQueueFamilyIndex + images_[index], // image + VkImageSubresourceRange { + VK_IMAGE_ASPECT_COLOR_BIT, // aspectMask + 0, // baseMipLevel + 1, // levelCount + 0, // baseArrayLayer + swapchain_info_.imageArrayLayers, // layerCount + }, // subresourceRange + }; + + device_functions_->vkCmdPipelineBarrier( + command_buffer_, + 0, // srcStageMask + VK_PIPELINE_STAGE_TRANSFER_BIT, // dstStageMask + 0, // dependencyFlags + 0, // memoryBarrierCount + nullptr, // pMemoryBarriers + 0, // bufferMemoryBarrierCount + nullptr, // pBufferMemoryBarriers + 1, // imageMemoryBarrierCount + &initialBarrier // pImageMemoryBarriers + ); + + VkImageSubresourceLayers subresource = { + VK_IMAGE_ASPECT_COLOR_BIT, // aspectMask + 0, // mipLevel + 0, // baseArrayLayer + swapchain_info_.imageArrayLayers, // layerCount + }; + VkOffset3D offsets[2] = { + { 0, 0, 0, }, + { (int32_t)swapchain_info_.imageExtent.width, + (int32_t)swapchain_info_.imageExtent.height, + 1, + }, + }; + VkImageBlit blit = { + subresource, + { offsets[0], offsets[1] }, + subresource, + { offsets[0], offsets[1] }, + }; + device_functions_->vkCmdBlitImage( + command_buffer_, + image, // srcImage + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // srcImageLayout + images_[index], // dstImage + VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, // dstImageLayout + 1, // regionCount + &blit, // pRegions + VK_FILTER_NEAREST // filter + ); + + VkImageMemoryBarrier finalBarrier = initialBarrier; + finalBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + finalBarrier.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT; + finalBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + finalBarrier.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + + device_functions_->vkCmdPipelineBarrier( + command_buffer_, + VK_PIPELINE_STAGE_TRANSFER_BIT, // srcStageMask + 0, // dstStageMask + 0, // dependencyFlags + 0, // memoryBarrierCount + nullptr, // pMemoryBarriers + 0, // bufferMemoryBarrierCount + nullptr, // pBufferMemoryBarriers + 1, // imageMemoryBarrierCount + &finalBarrier // pImageMemoryBarriers + ); + + if ((res = device_functions_->vkEndCommandBuffer(command_buffer_)) != + VK_SUCCESS) { + return res; + } + + VkPipelineStageFlags waitStage = VK_PIPELINE_STAGE_TRANSFER_BIT; + VkSubmitInfo submitInfo = { + VK_STRUCTURE_TYPE_SUBMIT_INFO, // sType + 0, // pNext + 1, // waitSemaphoreCount + &acquire_semaphore_, // pWaitSemaphores + &waitStage, // pWaitDstStageMask + 1, // commandBufferCount + &command_buffer_, // pCommandBuffers + 1, // signalSemaphoreCount + &blit_semaphore_, // pSignalSemaphores + }; + auto queue_functions = GetGlobalContext().GetQueueData(queue); + if ((res = queue_functions->vkQueueSubmit(queue, 1, &submitInfo, + blit_fence_)) != VK_SUCCESS) { + return res; + } + + VkPresentInfoKHR presentInfo = { + VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, // sType + 0, // pNext + 1, // waitSemaphoreCount + &blit_semaphore_, // waitSemaphores + 1, // swapchainCount + &swapchain_, // pSwapchains, + &index, // pImageIndices + nullptr, // pResults + }; + if ((res = queue_functions->vkQueuePresentKHR(queue, &presentInfo)) != + VK_SUCCESS) { + return res; + } + + device_functions_->vkWaitForFences(device_, 1, &blit_fence_, VK_TRUE, + 0xFFFFFFFFFFFFFFFFULL); + device_functions_->vkResetFences(device_, 1, &blit_fence_); + return VK_SUCCESS; +} +} diff --git a/core/vulkan/vk_virtual_swapchain/cc/base_swapchain.h b/core/vulkan/vk_virtual_swapchain/cc/base_swapchain.h new file mode 100644 index 0000000000..cf8a35b911 --- /dev/null +++ b/core/vulkan/vk_virtual_swapchain/cc/base_swapchain.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2018 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef VK_BASE_SWAPCHAIN_VIRTUAL_SWAPCHAIN_H_ +#define VK_BASE_SWAPCHAIN_VIRTUAL_SWAPCHAIN_H_ + +#include +#include +#include +#include +#include "layer.h" + +namespace swapchain { +// The BaseSwapchain handles blitting presenting images to the original surface +class BaseSwapchain { + public: + BaseSwapchain(VkInstance instance, VkDevice device, uint32_t queue, + VkCommandPool command_pool, uint32_t num_images, + const InstanceData *instance_functions, + const DeviceData *device_functions, + const VkSwapchainCreateInfoKHR *swapchain_info, + const VkAllocationCallbacks *pAllocator, + const void *platform_info); + void Destroy(const VkAllocationCallbacks *pAllocator); + VkResult PresentFrom(VkQueue queue, VkImage image); + private: + VkInstance instance_; + VkDevice device_; + const InstanceData *instance_functions_; + const DeviceData *device_functions_; + VkSwapchainCreateInfoKHR swapchain_info_; + + threading::mutex present_lock_; + + // The real surface to present to. + VkSurfaceKHR surface_; + // The real swapchain to present to. + VkSwapchainKHR swapchain_; + // The swapchain images to blit to. + std::vector images_; + // The semaphores to signal when the acquire is completed. + VkSemaphore acquire_semaphore_; + // The semaphores to signal when the blit is completed. + VkSemaphore blit_semaphore_; + // The fence to signal when the blit is completed, so the host can return. + VkFence blit_fence_; + // The command buffers to use to blit. We need several in case someone + // submits while a previous one is still pending. + VkCommandBuffer command_buffer_; +}; + +} + +#endif // VK_BASE_SWAPCHAIN_VIRTUAL_SWAPCHAIN_H_ diff --git a/core/vulkan/vk_virtual_swapchain/cc/layer.cpp b/core/vulkan/vk_virtual_swapchain/cc/layer.cpp index 63d87619df..6e6b40929a 100644 --- a/core/vulkan/vk_virtual_swapchain/cc/layer.cpp +++ b/core/vulkan/vk_virtual_swapchain/cc/layer.cpp @@ -135,6 +135,11 @@ VKAPI_ATTR VkResult VKAPI_CALL vkCreateInstance( GET_PROC(vkGetPhysicalDeviceProperties); GET_PROC(vkGetPhysicalDeviceMemoryProperties); +#ifdef VK_USE_PLATFORM_ANDROID_KHR + GET_PROC(vkCreateAndroidSurfaceKHR); +#endif + GET_PROC(vkDestroySurfaceKHR); + #undef GET_PROC // Add this instance, along with the vkGetInstanceProcAddr to our // map. This way when someone calls vkGetInstanceProcAddr, we can forward @@ -217,6 +222,8 @@ vkCreateDevice(VkPhysicalDevice gpu, const VkDeviceCreateInfo *pCreateInfo, GET_PROC(vkUnmapMemory); GET_PROC(vkInvalidateMappedMemoryRanges); + GET_PROC(vkCreateSemaphore); + GET_PROC(vkDestroySemaphore); GET_PROC(vkCreateFence); GET_PROC(vkGetFenceStatus); GET_PROC(vkWaitForFences); @@ -240,8 +247,10 @@ vkCreateDevice(VkPhysicalDevice gpu, const VkDeviceCreateInfo *pCreateInfo, GET_PROC(vkBeginCommandBuffer); GET_PROC(vkEndCommandBuffer); + GET_PROC(vkResetCommandBuffer); GET_PROC(vkCmdCopyImageToBuffer); + GET_PROC(vkCmdBlitImage); GET_PROC(vkCmdPipelineBarrier); GET_PROC(vkCmdWaitEvents); GET_PROC(vkCreateRenderPass); @@ -249,6 +258,12 @@ vkCreateDevice(VkPhysicalDevice gpu, const VkDeviceCreateInfo *pCreateInfo, GET_PROC(vkQueueSubmit); GET_PROC(vkDestroyDevice); + GET_PROC(vkCreateSwapchainKHR); + GET_PROC(vkGetSwapchainImagesKHR); + GET_PROC(vkAcquireNextImageKHR); + GET_PROC(vkQueuePresentKHR); + GET_PROC(vkDestroySwapchainKHR); + #undef GET_PROC // Add this device, along with the vkGetDeviceProcAddr to our map. @@ -272,7 +287,7 @@ vkCreateDevice(VkPhysicalDevice gpu, const VkDeviceCreateInfo *pCreateInfo, *pDevice, pCreateInfo->pQueueCreateInfos[i].queueFamilyIndex, j, &q); set_dispatch_from_parent(q, *pDevice); - (*queue_map)[q] = {*pDevice, data.vkQueueSubmit}; + (*queue_map)[q] = {*pDevice, data.vkQueueSubmit, data.vkQueuePresentKHR}; } } } diff --git a/core/vulkan/vk_virtual_swapchain/cc/layer.h b/core/vulkan/vk_virtual_swapchain/cc/layer.h index d07e70d075..c5a329d3b7 100644 --- a/core/vulkan/vk_virtual_swapchain/cc/layer.h +++ b/core/vulkan/vk_virtual_swapchain/cc/layer.h @@ -49,6 +49,11 @@ struct InstanceData { PFN_vkGetPhysicalDeviceProperties vkGetPhysicalDeviceProperties; PFN_vkGetPhysicalDeviceMemoryProperties vkGetPhysicalDeviceMemoryProperties; +#ifdef VK_USE_PLATFORM_ANDROID_KHR + PFN_vkCreateAndroidSurfaceKHR vkCreateAndroidSurfaceKHR; +#endif + PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR; + // All of the physical devices associated with this instance. std::vector physical_devices_; }; @@ -81,6 +86,8 @@ struct DeviceData { PFN_vkUnmapMemory vkUnmapMemory; PFN_vkInvalidateMappedMemoryRanges vkInvalidateMappedMemoryRanges; + PFN_vkCreateSemaphore vkCreateSemaphore; + PFN_vkDestroySemaphore vkDestroySemaphore; PFN_vkCreateFence vkCreateFence; PFN_vkGetFenceStatus vkGetFenceStatus; PFN_vkWaitForFences vkWaitForFences; @@ -104,19 +111,28 @@ struct DeviceData { PFN_vkBeginCommandBuffer vkBeginCommandBuffer; PFN_vkEndCommandBuffer vkEndCommandBuffer; + PFN_vkResetCommandBuffer vkResetCommandBuffer; PFN_vkCmdCopyImageToBuffer vkCmdCopyImageToBuffer; + PFN_vkCmdBlitImage vkCmdBlitImage; PFN_vkCmdPipelineBarrier vkCmdPipelineBarrier; PFN_vkCmdWaitEvents vkCmdWaitEvents; PFN_vkCreateRenderPass vkCreateRenderPass; PFN_vkQueueSubmit vkQueueSubmit; + PFN_vkQueuePresentKHR vkQueuePresentKHR; PFN_vkDestroyDevice vkDestroyDevice; + + PFN_vkCreateSwapchainKHR vkCreateSwapchainKHR; + PFN_vkGetSwapchainImagesKHR vkGetSwapchainImagesKHR; + PFN_vkAcquireNextImageKHR vkAcquireNextImageKHR; + PFN_vkDestroySwapchainKHR vkDestroySwapchainKHR; }; struct QueueData { VkDevice device_; PFN_vkQueueSubmit vkQueueSubmit; + PFN_vkQueuePresentKHR vkQueuePresentKHR; }; // All context functions return a context token. diff --git a/core/vulkan/vk_virtual_swapchain/cc/platform.cpp b/core/vulkan/vk_virtual_swapchain/cc/platform.cpp new file mode 100644 index 0000000000..4a25044e36 --- /dev/null +++ b/core/vulkan/vk_virtual_swapchain/cc/platform.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2018 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include "platform.h" + +namespace swapchain { + +void CreateSurface(const InstanceData* functions, VkInstance instance, const void* data, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface) { +#ifdef VK_USE_PLATFORM_ANDROID_KHR + { + auto pCreateInfo = static_cast(data); + if (pCreateInfo->sType == VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR) { + // Attempt to create android surface + if (functions->vkCreateAndroidSurfaceKHR(instance, pCreateInfo, pAllocator, pSurface) != VK_SUCCESS) { + *pSurface = 0; + } + } + } +#else + *pSurface = 0; +#endif +} + +} diff --git a/core/vulkan/vk_virtual_swapchain/cc/platform.h b/core/vulkan/vk_virtual_swapchain/cc/platform.h new file mode 100644 index 0000000000..43be01611a --- /dev/null +++ b/core/vulkan/vk_virtual_swapchain/cc/platform.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2018 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef VK_VIRTUAL_SWAPCHAIN_PLATFORM_H_ +#define VK_VIRTUAL_SWAPCHAIN_PLATFORM_H_ + +#include "vulkan/vulkan.h" + +#include "layer.h" + +namespace swapchain { + +void CreateSurface(const InstanceData* functions, VkInstance instance, const void* data, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); + +} + +#endif // VK_VIRTUAL_SWAPCHAIN_PLATFORM_H_ diff --git a/core/vulkan/vk_virtual_swapchain/cc/swapchain.cpp b/core/vulkan/vk_virtual_swapchain/cc/swapchain.cpp index bfae426548..e20f48caa3 100644 --- a/core/vulkan/vk_virtual_swapchain/cc/swapchain.cpp +++ b/core/vulkan/vk_virtual_swapchain/cc/swapchain.cpp @@ -209,6 +209,11 @@ VKAPI_ATTR VkResult VKAPI_CALL vkCreateSwapchainKHR( pNext = static_cast(pNext->pNext)) { if (pNext->sType == VIRTUAL_SWAPCHAIN_CREATE_PNEXT) { swp->SetAlwaysGetAcquiredImage(true); + if (pNext->surfaceCreateInfo) { + swp->CreateBaseSwapchain(pdd.instance_, &inst_dat, + pAllocator, pNext->surfaceCreateInfo); + } + break; } } @@ -328,6 +333,7 @@ vkQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR *pPresentInfo) { res |= GetGlobalContext().GetQueueData(queue)->vkQueueSubmit( queue, 1, &submitInfo, swp->GetFence(image_index)); + res |= swp->PresentToSurface(queue, image_index); swp->NotifySubmitted(image_index); } diff --git a/core/vulkan/vk_virtual_swapchain/cc/swapchain.h b/core/vulkan/vk_virtual_swapchain/cc/swapchain.h index 9b131a87d8..45a8a9da79 100644 --- a/core/vulkan/vk_virtual_swapchain/cc/swapchain.h +++ b/core/vulkan/vk_virtual_swapchain/cc/swapchain.h @@ -27,7 +27,8 @@ void RegisterInstance(VkInstance instance, const InstanceData &data); static const uint32_t VIRTUAL_SWAPCHAIN_CREATE_PNEXT = 0xFFFFFFAA; struct CreateNext { uint32_t sType; - void *pNext; + const void *pNext; + void *surfaceCreateInfo; }; // All of the following functions are the same as the Vulkan functions diff --git a/core/vulkan/vk_virtual_swapchain/cc/virtual_swapchain.cpp b/core/vulkan/vk_virtual_swapchain/cc/virtual_swapchain.cpp index a16d825ae0..4a4c771b15 100644 --- a/core/vulkan/vk_virtual_swapchain/cc/virtual_swapchain.cpp +++ b/core/vulkan/vk_virtual_swapchain/cc/virtual_swapchain.cpp @@ -67,7 +67,8 @@ VirtualSwapchain::VirtualSwapchain( functions_(functions), pending_image_timeout_in_milliseconds_( pending_image_timeout_in_milliseconds), - always_get_acquired_image_(always_get_acquired_image) { + always_get_acquired_image_(always_get_acquired_image), + base_swapchain_(nullptr) { VkPhysicalDeviceMemoryProperties properties = *memory_properties; build_swapchain_image_data_ = [this, properties, pAllocator]() { SwapchainImageData image_data; @@ -286,6 +287,10 @@ void VirtualSwapchain::Destroy(const VkAllocationCallbacks *pAllocator) { functions_->vkDestroyFence(device_, image_data_[i].fence_, pAllocator); } + if (base_swapchain_) { + base_swapchain_->Destroy(pAllocator); + } + functions_->vkDestroyCommandPool(device_, command_pool_, pAllocator); } @@ -390,4 +395,17 @@ uint32_t VirtualSwapchain::ImageByteSize() const { // more dynamic. return width_ * height_ * 4; } + +void VirtualSwapchain::CreateBaseSwapchain(VkInstance instance, + const InstanceData *instance_functions, + const VkAllocationCallbacks *pAllocator, + const void *platform_info) { + base_swapchain_ = std::unique_ptr( + new BaseSwapchain(instance, device_, queue_, + command_pool_, num_images_, + instance_functions, functions_, + &swapchain_info_, + pAllocator, + platform_info)); +} } // namespace swapchain diff --git a/core/vulkan/vk_virtual_swapchain/cc/virtual_swapchain.h b/core/vulkan/vk_virtual_swapchain/cc/virtual_swapchain.h index b26e45eda7..e8c1a55594 100644 --- a/core/vulkan/vk_virtual_swapchain/cc/virtual_swapchain.h +++ b/core/vulkan/vk_virtual_swapchain/cc/virtual_swapchain.h @@ -21,7 +21,9 @@ #include #include #include +#include #include +#include "base_swapchain.h" #include "layer.h" namespace swapchain { @@ -79,6 +81,22 @@ class VirtualSwapchain { VkCommandBuffer &GetCommandBuffer(size_t i) { return image_data_[i].command_buffer_; } + + // If we have create info, create a surface to render to. + void CreateBaseSwapchain(VkInstance instance, + const InstanceData *instance_functions_, + const VkAllocationCallbacks *pAllocator, + const void *platform_info); + + // If we have a base surface, blit and present the image to that. + VkResult PresentToSurface(VkQueue queue, size_t i) { + if (!base_swapchain_) { + return VK_SUCCESS; + } + + return base_swapchain_->PresentFrom(queue, image_data_[i].image_); + } + // When the commands associated with an image have been submitted to // a VkQueue, NotifySubmitted must be called to inform the swapchain // that the image in question is no longer needed. @@ -178,7 +196,7 @@ class VirtualSwapchain { // This is how many milliseconds we should wait for an image before waking up // and seeing if we should shut down. const uint32_t pending_image_timeout_in_milliseconds_; - // A flag to indicate whether GetImage() always wasit for the acquired image + // A flag to indicate whether GetImage() always waits for the acquired image // specified with the value pointed by the index pointer. When set to true, // GetImage() will wait until the acquired image is ready to use. When set to // false, GetImage() will write the index of a randomly free image to the @@ -186,6 +204,9 @@ class VirtualSwapchain { bool always_get_acquired_image_; // Function to build swapchain images std::function build_swapchain_image_data_; + + // The actual surface and swapchain if we're using one. + std::unique_ptr base_swapchain_; }; } // namespace swapchain From 16d4d10d2126510f50534e6023d219264cddebd4 Mon Sep 17 00:00:00 2001 From: Sean Purcell Date: Tue, 31 Jul 2018 11:12:11 -0400 Subject: [PATCH 02/12] GAPIR: Pass surface create info if available and enabled --- cmd/gapir/cc/main.cpp | 14 +++++++ .../vk_virtual_swapchain/cc/BUILD.bazel | 18 +++++++++ gapir/cc/BUILD.bazel | 1 + gapir/cc/surface.cpp | 36 +++++++++++++++++ gapir/cc/surface.h | 37 +++++++++++++++++ .../api/templates/vulkan_gfx_api_extras.tmpl | 40 +++++++++++++++---- 6 files changed, 138 insertions(+), 8 deletions(-) create mode 100644 gapir/cc/surface.cpp create mode 100644 gapir/cc/surface.h diff --git a/cmd/gapir/cc/main.cpp b/cmd/gapir/cc/main.cpp index 3d6d504ce3..b0a73d9cc6 100644 --- a/cmd/gapir/cc/main.cpp +++ b/cmd/gapir/cc/main.cpp @@ -22,6 +22,7 @@ #include "gapir/cc/resource_in_memory_cache.h" #include "gapir/cc/resource_requester.h" #include "gapir/cc/server.h" +#include "gapir/cc/surface.h" #include "core/cc/crash_handler.h" #include "core/cc/debugger.h" @@ -129,6 +130,17 @@ const char* pipeName() { #endif } +void android_process(struct android_app* app, int32_t cmd) { + switch (cmd) { + case APP_CMD_INIT_WINDOW: { + gapir::android_window = app->window; + __android_log_print(ANDROID_LOG_DEBUG, "GAPIR", + "Received window: %p\n", gapir::android_window); + break; + } + } +} + // Main function for android void android_main(struct android_app* app) { MemoryManager memoryManager(memorySizes); @@ -156,6 +168,8 @@ void android_main(struct android_app* app) { GAPID_ERROR("Chmod failed!"); } + app->onAppCmd = android_process; + bool alive = true; while (alive) { int ident; diff --git a/core/vulkan/vk_virtual_swapchain/cc/BUILD.bazel b/core/vulkan/vk_virtual_swapchain/cc/BUILD.bazel index ed70d1077d..0367105d68 100644 --- a/core/vulkan/vk_virtual_swapchain/cc/BUILD.bazel +++ b/core/vulkan/vk_virtual_swapchain/cc/BUILD.bazel @@ -43,6 +43,24 @@ cc_library( ], ) +cc_library( + name = "headers", + srcs = glob([ + "*.h", + ]), + copts = cc_copts() + select({ + "//tools/build:linux": ["-DVK_USE_PLATFORM_XCB_KHR"], + "//tools/build:darwin": [], + "//tools/build:windows": ["-DVK_USE_PLATFORM_WIN32_KHR"], + # Android + "//conditions:default": ["-DVK_USE_PLATFORM_ANDROID_KHR"], + }), + visibility = ["//visibility:public"], + deps = [ + "//core/vulkan/cc/include/vulkan", + ], +) + cc_dynamic_library( name = "libVkLayer_VirtualSwapchain", visibility = ["//visibility:public"], diff --git a/gapir/cc/BUILD.bazel b/gapir/cc/BUILD.bazel index 2350366601..037908e9b2 100644 --- a/gapir/cc/BUILD.bazel +++ b/gapir/cc/BUILD.bazel @@ -110,6 +110,7 @@ cc_library( "//gapir/replay_service:proto", "//gapir/replay_service:vm", "@com_github_grpc_grpc//:grpc++", + "//core/vulkan/vk_virtual_swapchain/cc:headers", ] + select({ "//tools/build:darwin": [":darwin_renderer"], "//conditions:default": [], diff --git a/gapir/cc/surface.cpp b/gapir/cc/surface.cpp new file mode 100644 index 0000000000..f858f06bfa --- /dev/null +++ b/gapir/cc/surface.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2018 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "core/cc/target.h" + +#include "surface.h" + +namespace gapir { + +#if TARGET_OS == GAPID_OS_ANDROID +ANativeWindow* android_window; + +#endif // TARGET_OS == GAPID_OS_ANDROID + +void* SurfaceInfo() { +#if TARGET_OS == GAPID_OS_ANDROID + return (void*)android_window; +#else + return nullptr; +#endif +} + +} // namespace gapir diff --git a/gapir/cc/surface.h b/gapir/cc/surface.h new file mode 100644 index 0000000000..2fd9156cad --- /dev/null +++ b/gapir/cc/surface.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2018 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef GAPIR_SURFACE_H +#define GAPIR_SURFACE_H + +#include "core/cc/target.h" + +#if TARGET_OS == GAPID_OS_ANDROID +class ANativeWindow; +#endif // TARGET_OS == GAPID_OS_ANDROID + +namespace gapir { + +#if TARGET_OS == GAPID_OS_ANDROID +extern ANativeWindow* android_window; +#endif // TARGET_OS == GAPID_OS_ANDROID + +// Get the platform-specific data pointer to create the surface +void* SurfaceInfo(); + +} // namespace gapir + +#endif // GAPIR_SURFACE_H diff --git a/gapis/api/templates/vulkan_gfx_api_extras.tmpl b/gapis/api/templates/vulkan_gfx_api_extras.tmpl index b3310dff7f..a7900d31cd 100644 --- a/gapis/api/templates/vulkan_gfx_api_extras.tmpl +++ b/gapis/api/templates/vulkan_gfx_api_extras.tmpl @@ -32,11 +32,14 @@ #include "gapir/cc/vulkan_gfx_api.h" ¶ #include "gapir/cc/interpreter.h" - #include "gapir/cc/stack.h" #include "gapir/cc/renderer.h" + #include "gapir/cc/stack.h" + #include "gapir/cc/surface.h" ¶ #include "core/cc/get_vulkan_proc_address.h" #include "core/cc/log.h" +¶ + #include "core/vulkan/vk_virtual_swapchain/cc/swapchain.h" ¶ #include #include @@ -330,8 +333,6 @@ bool Vulkan::replayCreateVkDeviceImpl(Stack* stack, size_val physicalDevice, } } ¶ - static const uint32_t VIRTUAL_SWAPCHAIN_CREATE_PNEXT = 0xFFFFFFAA; - bool Vulkan::replayCreateSwapchain(Stack* stack, bool pushReturn) { auto pSwapchain = stack->pop(); auto pAllocator = stack->pop(); @@ -339,11 +340,34 @@ bool Vulkan::replayCreateVkDeviceImpl(Stack* stack, size_val physicalDevice, auto device = stack->pop(); auto newCreateInfo = *pCreateInfo; - struct { - uint32_t sType; - const void* pNext; - } pNextStruct = {VIRTUAL_SWAPCHAIN_CREATE_PNEXT, pCreateInfo->pNext}; - newCreateInfo.pNext = &pNextStruct; + swapchain::CreateNext vsPNext; +#if TARGET_OS == GAPID_OS_ANDROID + VkAndroidSurfaceCreateInfoKHR surfaceInfo = {}; +#endif + for (auto pNext = static_cast(newCreateInfo.pNext); + pNext != nullptr; + pNext = static_cast(pNext->pNext)) { + if (pNext->sType == swapchain::VIRTUAL_SWAPCHAIN_CREATE_PNEXT) { + if (pNext->surfaceCreateInfo) { + // Copy any extra fields + vsPNext = *pNext; + + void* data = SurfaceInfo(); + void* createInfo = nullptr; + if (data != nullptr) { +#if TARGET_OS == GAPID_OS_ANDROID + createInfo = &surfaceInfo; + surfaceInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR; + surfaceInfo.window = (ANativeWindow*)data; +#endif + } + vsPNext.surfaceCreateInfo = createInfo; + vsPNext.pNext = newCreateInfo.pNext; + newCreateInfo.pNext = &vsPNext; + } + break; + } + } stack->push(device); stack->push(&newCreateInfo); From e4c2f8d490dabffd10a2e94e40cb147d063ac19e Mon Sep 17 00:00:00 2001 From: Sean Purcell Date: Tue, 31 Jul 2018 11:16:42 -0400 Subject: [PATCH 03/12] Add configuration option to enable rendering replay to surface --- gapis/api/gles/replay.go | 2 + gapis/api/gvr/gvr.go | 2 + gapis/api/vulkan/BUILD.bazel | 5 ++- gapis/api/vulkan/api/enums.api | 3 ++ gapis/api/vulkan/custom_replay.go | 26 ++++++++++++ .../vulkan/extensions/virtual_swapchain.api | 19 +++++++++ gapis/api/vulkan/replay.go | 42 +++++++++++++++++-- gapis/api/vulkan/replay.proto | 23 ++++++++++ gapis/api/vulkan/synthetic.api | 16 +++++++ gapis/api/vulkan/vulkan.api | 1 + gapis/replay/interfaces.go | 2 + gapis/resolve/framebuffer_attachment_data.go | 1 + gapis/resolve/report.go | 2 +- gapis/service/path/path.go | 4 +- gapis/service/path/path.proto | 2 + gapis/service/service.proto | 1 + 16 files changed, 143 insertions(+), 8 deletions(-) create mode 100644 gapis/api/vulkan/extensions/virtual_swapchain.api create mode 100644 gapis/api/vulkan/replay.proto diff --git a/gapis/api/gles/replay.go b/gapis/api/gles/replay.go index d87212d1c5..6191a8037f 100644 --- a/gapis/api/gles/replay.go +++ b/gapis/api/gles/replay.go @@ -249,6 +249,7 @@ func (a API) QueryIssues( ctx context.Context, intent replay.Intent, mgr *replay.Manager, + displayToSurface bool, hints *service.UsageHints) ([]replay.Issue, error) { c, r := issuesConfig{}, issuesRequest{} @@ -269,6 +270,7 @@ func (a API) QueryFramebufferAttachment( framebufferIndex uint32, drawMode service.DrawMode, disableReplayOptimization bool, + displayToSurface bool, hints *service.UsageHints) (*image.Data, error) { if len(after) > 1 { diff --git a/gapis/api/gvr/gvr.go b/gapis/api/gvr/gvr.go index ce42bc1ac5..4389917422 100644 --- a/gapis/api/gvr/gvr.go +++ b/gapis/api/gvr/gvr.go @@ -61,6 +61,7 @@ func (API) QueryFramebufferAttachment( framebufferIndex uint32, drawMode service.DrawMode, disableReplayOptimization bool, + displayToSurface bool, hints *service.UsageHints) (*image.Data, error) { if framebufferIndex == 0 { @@ -80,6 +81,7 @@ func (API) QueryFramebufferAttachment( framebufferIndex, drawMode, disableReplayOptimization, + displayToSurface, hints, ) } diff --git a/gapis/api/vulkan/BUILD.bazel b/gapis/api/vulkan/BUILD.bazel index a7016ecb71..19f59eaaea 100644 --- a/gapis/api/vulkan/BUILD.bazel +++ b/gapis/api/vulkan/BUILD.bazel @@ -130,7 +130,10 @@ go_library( proto_library( name = "vulkan_proto", - srcs = ["resolvables.proto"], + srcs = [ + "replay.proto", + "resolvables.proto", + ], visibility = ["//visibility:public"], ) diff --git a/gapis/api/vulkan/api/enums.api b/gapis/api/vulkan/api/enums.api index 71ef443d98..a09cf601e3 100644 --- a/gapis/api/vulkan/api/enums.api +++ b/gapis/api/vulkan/api/enums.api @@ -281,6 +281,9 @@ enum VkStructureType { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES = 1000168000, VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_SUPPORT = 1000168001, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETER_FEATURES = 1000063000, + + // Virtual Swapchain + VK_STRUCTURE_TYPE_VIRTUAL_SWAPCHAIN_PNEXT = 0xFFFFFFAA, } @analyze_usage diff --git a/gapis/api/vulkan/custom_replay.go b/gapis/api/vulkan/custom_replay.go index b008d384ca..85960699c1 100644 --- a/gapis/api/vulkan/custom_replay.go +++ b/gapis/api/vulkan/custom_replay.go @@ -18,6 +18,7 @@ import ( "context" "strings" + "github.com/google/gapid/core/log" "github.com/google/gapid/gapis/api" "github.com/google/gapid/gapis/memory" "github.com/google/gapid/gapis/replay/builder" @@ -373,6 +374,31 @@ func (a *VkCreateSwapchainKHR) Mutate(ctx context.Context, id api.CmdID, s *api. cb := CommandBuilder{Thread: a.Thread(), Arena: s.Arena} hijack := cb.ReplayCreateSwapchain(a.Device(), a.PCreateInfo(), a.PAllocator(), a.PSwapchain(), a.Result()) hijack.Extras().MustClone(a.Extras().All()...) + + a.Extras().Observations().ApplyReads(s.Memory.ApplicationPool()) + info := a.PCreateInfo().MustRead(ctx, a, s, nil) + pNext := NewVirtualSwapchainPNext(s.Arena, + VkStructureType_VK_STRUCTURE_TYPE_VIRTUAL_SWAPCHAIN_PNEXT, // sType + info.PNext(), // pNext + 0, // surfaceCreateInfo + ) + for _, extra := range a.Extras().All() { + if _, ok := extra.(*DisplayToSurface); ok { + log.D(ctx, "Activating display to surface") + pNext.SetSurfaceCreateInfo(1) + } + } + pNextData := s.AllocDataOrPanic(ctx, pNext) + defer pNextData.Free() + + info.SetPNext(NewVoidᶜᵖ(pNextData.Ptr())) + infoData := s.AllocDataOrPanic(ctx, info) + defer infoData.Free() + hijack.SetPCreateInfo(NewVkSwapchainCreateInfoKHRᶜᵖ(infoData.Ptr())) + + hijack.AddRead(pNextData.Data()) + hijack.AddRead(infoData.Data()) + err := hijack.Mutate(ctx, id, s, b) return err diff --git a/gapis/api/vulkan/extensions/virtual_swapchain.api b/gapis/api/vulkan/extensions/virtual_swapchain.api new file mode 100644 index 0000000000..e4c6a0fcdc --- /dev/null +++ b/gapis/api/vulkan/extensions/virtual_swapchain.api @@ -0,0 +1,19 @@ +// Copyright (C) 2018 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +class VirtualSwapchainPNext { + VkStructureType sType + const void* pNext + const void* surfaceCreateInfo +} diff --git a/gapis/api/vulkan/replay.go b/gapis/api/vulkan/replay.go index 6962007f69..5eccdb222d 100644 --- a/gapis/api/vulkan/replay.go +++ b/gapis/api/vulkan/replay.go @@ -120,6 +120,7 @@ type framebufferRequest struct { framebufferIndex uint32 out chan imgRes wireframeOverlay bool + displayToSurface bool } type deadCodeEliminationInfo struct { @@ -440,12 +441,32 @@ func (t *destroyResourcesAtEOS) Flush(ctx context.Context, out transform.Writer) } } +// DisplayToSurface is a transformation that enables rendering during replay to +// the original surface. +func (t *DisplayToSurface) Transform(ctx context.Context, id api.CmdID, cmd api.Cmd, out transform.Writer) { + if c, ok := cmd.(*VkCreateSwapchainKHR); ok { + newCmd := c.Clone(out.State().Arena) + newCmd.extras = api.CmdExtras{} + // Add an extra to indicate to custom_replay to add a flag to + // the virtual swapchain pNext + newCmd.extras = append(api.CmdExtras{t}, cmd.Extras().All()...) + out.MutateAndWrite(ctx, id, newCmd) + } else { + out.MutateAndWrite(ctx, id, cmd) + } +} + +func (t *DisplayToSurface) Flush(ctx context.Context, out transform.Writer) { +} + // issuesConfig is a replay.Config used by issuesRequests. -type issuesConfig struct{} +type issuesConfig struct { +} // issuesRequest requests all issues found during replay to be reported to out. type issuesRequest struct { - out chan<- replay.Issue + out chan<- replay.Issue + displayToSurface bool } func (a API) Replay( @@ -519,6 +540,7 @@ func (a API) Replay( } wire := false + doDisplayToSurface := false var overdraw *stencilOverdraw for _, rr := range rrs { @@ -533,6 +555,9 @@ func (a API) Replay( } issues.reportTo(rr.Result) optimize = false + if req.displayToSurface { + doDisplayToSurface = true + } case framebufferRequest: @@ -584,6 +609,9 @@ func (a API) Replay( readFramebuffer.Color(after, req.width, req.height, req.framebufferIndex, rr.Result) } } + if req.displayToSurface { + doDisplayToSurface = true + } } } @@ -601,6 +629,10 @@ func (a API) Replay( transforms.Add(wireframe(ctx)) } + if doDisplayToSurface { + transforms.Add(&DisplayToSurface{}) + } + if issues != nil { transforms.Add(issues) // Issue reporting required. } else { @@ -659,6 +691,7 @@ func (a API) QueryFramebufferAttachment( framebufferIndex uint32, drawMode service.DrawMode, disableReplayOptimization bool, + displayToSurface bool, hints *service.UsageHints) (*image.Data, error) { s, err := resolve.SyncData(ctx, intent.Capture) @@ -695,7 +728,7 @@ func (a API) QueryFramebufferAttachment( c := drawConfig{beginIndex, endIndex, subcommand, drawMode, disableReplayOptimization} out := make(chan imgRes, 1) - r := framebufferRequest{after: after, width: width, height: height, framebufferIndex: framebufferIndex, attachment: attachment, out: out} + r := framebufferRequest{after: after, width: width, height: height, framebufferIndex: framebufferIndex, attachment: attachment, out: out, displayToSurface: displayToSurface} res, err := mgr.Replay(ctx, intent, c, r, a, hints) if err != nil { return nil, err @@ -707,9 +740,10 @@ func (a API) QueryIssues( ctx context.Context, intent replay.Intent, mgr *replay.Manager, + displayToSurface bool, hints *service.UsageHints) ([]replay.Issue, error) { - c, r := issuesConfig{}, issuesRequest{} + c, r := issuesConfig{}, issuesRequest{displayToSurface: displayToSurface} res, err := mgr.Replay(ctx, intent, c, r, a, hints) if err != nil { return nil, err diff --git a/gapis/api/vulkan/replay.proto b/gapis/api/vulkan/replay.proto new file mode 100644 index 0000000000..4d1c5a460e --- /dev/null +++ b/gapis/api/vulkan/replay.proto @@ -0,0 +1,23 @@ +// Copyright (C) 2018 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package vulkan; +option go_package = "github.com/google/gapid/gapis/api/vulkan"; + +// DisplayToSurface is an extra added to VkCreateSwapchainKHR to indicate the +// replay should display to the original surface. +message DisplayToSurface { +} diff --git a/gapis/api/vulkan/synthetic.api b/gapis/api/vulkan/synthetic.api index 0fb7e0c30c..435089ab02 100644 --- a/gapis/api/vulkan/synthetic.api +++ b/gapis/api/vulkan/synthetic.api @@ -164,6 +164,22 @@ cmd VkResult ReplayCreateSwapchain( VkSwapchainKHR* pSwapchain) { if !(device in Devices) { vkErrorInvalidDevice(device) } if pCreateInfo == null { vkErrorNullPointer("VkSwapchainCreateInfoKHR") } + // Handle pNext + createInfo := pCreateInfo[0] + if createInfo.pNext != null { + numPNext := numberOfPNext(createInfo.pNext) + next := MutableVoidPtr(as!void*(createInfo.pNext)) + for i in (0 .. numPNext) { + sType := as!const VkStructureType*(next.Ptr)[0:1][0] + switch sType { + case VK_STRUCTURE_TYPE_VIRTUAL_SWAPCHAIN_PNEXT: { + ext := as!VirtualSwapchainPNext*(next.Ptr)[0:1][0] + _ = ext.surfaceCreateInfo + } + } + next.Ptr = as!VulkanStructHeader*(next.Ptr)[0:1][0].PNext + } + } create_info := pCreateInfo[0] queueFamilyIndices := create_info.pQueueFamilyIndices[0:create_info.queueFamilyIndexCount] diff --git a/gapis/api/vulkan/vulkan.api b/gapis/api/vulkan/vulkan.api index 72cf4e9e70..e542b073ae 100644 --- a/gapis/api/vulkan/vulkan.api +++ b/gapis/api/vulkan/vulkan.api @@ -76,6 +76,7 @@ import "extensions/khr_get_surface_capabilities2.api" import "extensions/khr_surface.api" import "extensions/khr_swapchain.api" import "extensions/nv_dedicated_allocation.api" +import "extensions/virtual_swapchain.api" import "android/vulkan_android.api" import "linux/vulkan_linux.api" diff --git a/gapis/replay/interfaces.go b/gapis/replay/interfaces.go index 992539da7a..c15aae442d 100644 --- a/gapis/replay/interfaces.go +++ b/gapis/replay/interfaces.go @@ -44,6 +44,7 @@ type QueryIssues interface { ctx context.Context, intent Intent, mgr *Manager, + displayToSurface bool, hints *service.UsageHints) ([]Issue, error) } @@ -61,6 +62,7 @@ type QueryFramebufferAttachment interface { framebufferIndex uint32, drawMode service.DrawMode, disableReplayOptimization bool, + displayToSurface bool, hints *service.UsageHints) (*image.Data, error) } diff --git a/gapis/resolve/framebuffer_attachment_data.go b/gapis/resolve/framebuffer_attachment_data.go index 44855c2efb..1953490bb7 100644 --- a/gapis/resolve/framebuffer_attachment_data.go +++ b/gapis/resolve/framebuffer_attachment_data.go @@ -65,6 +65,7 @@ func (r *FramebufferAttachmentBytesResolvable) Resolve(ctx context.Context) (int r.FramebufferIndex, r.DrawMode, r.ReplaySettings.DisableReplayOptimization, + r.ReplaySettings.DisplayToSurface, r.Hints, ) if err != nil { diff --git a/gapis/resolve/report.go b/gapis/resolve/report.go index e98974d6f3..b90e5f425b 100644 --- a/gapis/resolve/report.go +++ b/gapis/resolve/report.go @@ -100,7 +100,7 @@ func (r *ReportResolvable) Resolve(ctx context.Context) (interface{}, error) { hints := &service.UsageHints{Background: true} for _, a := range c.APIs { if qi, ok := a.(replay.QueryIssues); ok { - apiIssues, err := qi.QueryIssues(ctx, intent, mgr, hints) + apiIssues, err := qi.QueryIssues(ctx, intent, mgr, r.Path.DisplayToSurface, hints) if err != nil { issue := replay.Issue{ Command: api.CmdNoID, diff --git a/gapis/service/path/path.go b/gapis/service/path/path.go index 9129e433e3..08fd015868 100644 --- a/gapis/service/path/path.go +++ b/gapis/service/path/path.go @@ -533,8 +533,8 @@ func (n *Capture) Resources() *Resources { } // Report returns the path node to the capture's report. -func (n *Capture) Report(d *Device, f *CommandFilter) *Report { - return &Report{Capture: n, Device: d, Filter: f} +func (n *Capture) Report(d *Device, f *CommandFilter, display bool) *Report { + return &Report{Capture: n, Device: d, Filter: f, DisplayToSurface: display} } // Contexts returns the path node to the capture's contexts. diff --git a/gapis/service/path/path.proto b/gapis/service/path/path.proto index d30115fc65..4ad7492e67 100644 --- a/gapis/service/path/path.proto +++ b/gapis/service/path/path.proto @@ -371,6 +371,8 @@ message Report { Device device = 2; // The optional filter to apply to the report items. CommandFilter filter = 3; + // Whether to display the replay to the original surface while in progress. + bool display_to_surface = 4; } // Resources is a path to a list of resources used in a capture. diff --git a/gapis/service/service.proto b/gapis/service/service.proto index a1bc95f65c..967500daad 100644 --- a/gapis/service/service.proto +++ b/gapis/service/service.proto @@ -293,6 +293,7 @@ message GetDevicesForReplayResponse { message ReplaySettings { path.Device device = 1; bool disable_replay_optimization = 2; + bool display_to_surface = 3; } message GetFramebufferAttachmentRequest { From 48dcca69284104b30c3cdb7fcb6582a86a600bd2 Mon Sep 17 00:00:00 2001 From: Sean Purcell Date: Tue, 31 Jul 2018 11:16:57 -0400 Subject: [PATCH 04/12] Add display to surface flags to gapit replay clients --- cmd/gapit/flags.go | 11 +++++++---- cmd/gapit/report.go | 3 ++- cmd/gapit/screenshot.go | 1 + cmd/gapit/sxs_video.go | 2 +- cmd/gapit/video.go | 5 +++-- 5 files changed, 14 insertions(+), 8 deletions(-) diff --git a/cmd/gapit/flags.go b/cmd/gapit/flags.go index 89a1447c1b..fcab0816b8 100644 --- a/cmd/gapit/flags.go +++ b/cmd/gapit/flags.go @@ -100,9 +100,10 @@ type ( DeviceFlags } ReportFlags struct { - Gapis GapisFlags - Gapir GapirFlags - Out string `help:"output report path"` + Gapis GapisFlags + Gapir GapirFlags + Out string `help:"output report path"` + DisplayToSurface bool `help:"display the frames rendered in the replay back to the surface"` CommandFilterFlags } VideoFlags struct { @@ -122,7 +123,8 @@ type ( Count int `help:"number of frames after Start to capture: -1 for all frames"` Minimum int `help:"_return error when less than this number of frames is found"` } - NoOpt bool `help:"disables optimization of the replay stream"` + NoOpt bool `help:"disables optimization of the replay stream"` + DisplayToSurface bool `help:"display the frames rendered in the replay back to the surface"` CommandFilterFlags } DumpShadersFlags struct { @@ -235,6 +237,7 @@ type ( Max struct { Overdraw int `help:"the amount of overdraw to map to white in the output"` } + DisplayToSurface bool `help:"display the frames rendered in the replay back to the surface"` CommandFilterFlags } UnpackFlags struct { diff --git a/cmd/gapit/report.go b/cmd/gapit/report.go index c4b2e708c2..908aedc3c8 100644 --- a/cmd/gapit/report.go +++ b/cmd/gapit/report.go @@ -97,7 +97,8 @@ func (verb *reportVerb) Run(ctx context.Context, flags flag.FlagSet) error { } commands := boxedCommands.(*service.Commands).List - boxedReport, err := client.Get(ctx, capturePath.Report(device, filter).Path()) + boxedReport, err := client.Get(ctx, capturePath.Report(device, filter, + verb.DisplayToSurface).Path()) if err != nil { return log.Err(ctx, err, "Failed to acquire the capture's report") } diff --git a/cmd/gapit/screenshot.go b/cmd/gapit/screenshot.go index a963c6b7aa..868d7bb5d8 100644 --- a/cmd/gapit/screenshot.go +++ b/cmd/gapit/screenshot.go @@ -122,6 +122,7 @@ func (verb *screenshotVerb) getSingleFrame(ctx context.Context, cmd *path.Comman &service.ReplaySettings{ Device: device, DisableReplayOptimization: verb.NoOpt, + DisplayToSurface: verb.DisplayToSurface, }, cmd, attachment, settings, nil) if err != nil { diff --git a/cmd/gapit/sxs_video.go b/cmd/gapit/sxs_video.go index 0bf0c70432..0e89bc8346 100644 --- a/cmd/gapit/sxs_video.go +++ b/cmd/gapit/sxs_video.go @@ -171,7 +171,7 @@ func (verb *videoVerb) sxsVideoSource( Stride: int(v.fbo.Width) * 4, Rect: image.Rect(0, 0, int(v.fbo.Width), int(v.fbo.Height)), } - if frame, err := getFrame(ctx, verb.Max.Width, verb.Max.Height, v.command, device, client, verb.NoOpt); err == nil { + if frame, err := getFrame(ctx, verb.Max.Width, verb.Max.Height, v.command, device, client, verb.NoOpt, verb.DisplayToSurface); err == nil { v.rendered = frame } else { v.renderError = err diff --git a/cmd/gapit/video.go b/cmd/gapit/video.go index 9b2193d349..d77557b158 100644 --- a/cmd/gapit/video.go +++ b/cmd/gapit/video.go @@ -129,7 +129,7 @@ func (verb *videoVerb) regularVideoSource( for i, e := range eofEvents { i, e := i, e executor(ctx, func(ctx context.Context) error { - if frame, err := getFrame(ctx, verb.Max.Width, verb.Max.Height, e.Command, device, client, verb.NoOpt); err == nil { + if frame, err := getFrame(ctx, verb.Max.Width, verb.Max.Height, e.Command, device, client, verb.NoOpt, verb.DisplayToSurface); err == nil { rendered[i] = flipImg(frame) } else { errors[i] = err @@ -327,12 +327,13 @@ func (verb *videoVerb) encodeVideo(ctx context.Context, filepath string, vidFun return nil } -func getFrame(ctx context.Context, maxWidth, maxHeight int, cmd *path.Command, device *path.Device, client service.Service, noOpt bool) (*image.NRGBA, error) { +func getFrame(ctx context.Context, maxWidth, maxHeight int, cmd *path.Command, device *path.Device, client service.Service, noOpt bool, display bool) (*image.NRGBA, error) { ctx = log.V{"cmd": cmd.Indices}.Bind(ctx) settings := &service.RenderSettings{MaxWidth: uint32(maxWidth), MaxHeight: uint32(maxHeight)} iip, err := client.GetFramebufferAttachment(ctx, &service.ReplaySettings{ Device: device, DisableReplayOptimization: noOpt, + DisplayToSurface: display, }, cmd, api.FramebufferAttachment_Color0, settings, nil) if err != nil { return nil, log.Errf(ctx, err, "GetFramebufferAttachment failed at %v", cmd) From c608100832678405eda14891e9ae0ca821b1554b Mon Sep 17 00:00:00 2001 From: Sean Purcell Date: Tue, 31 Jul 2018 13:06:45 -0400 Subject: [PATCH 05/12] Remove vkWaitForFences for base swapchain present --- .../cc/base_swapchain.cpp | 163 ++++++++++++------ .../vk_virtual_swapchain/cc/base_swapchain.h | 16 +- core/vulkan/vk_virtual_swapchain/cc/layer.cpp | 3 +- .../vk_virtual_swapchain/cc/swapchain.cpp | 10 +- .../cc/virtual_swapchain.h | 12 +- 5 files changed, 136 insertions(+), 68 deletions(-) diff --git a/core/vulkan/vk_virtual_swapchain/cc/base_swapchain.cpp b/core/vulkan/vk_virtual_swapchain/cc/base_swapchain.cpp index 1096e9b99d..bdfcfa76fe 100644 --- a/core/vulkan/vk_virtual_swapchain/cc/base_swapchain.cpp +++ b/core/vulkan/vk_virtual_swapchain/cc/base_swapchain.cpp @@ -20,6 +20,49 @@ namespace swapchain { +namespace { +VkResult createSemaphore( + const DeviceData *device_functions, + VkDevice device, + const VkAllocationCallbacks *pAllocator, + VkSemaphore* pSem) { + VkSemaphoreCreateInfo createInfo = { + VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, // sType + nullptr, // pNext + 0, // flags + }; + return device_functions->vkCreateSemaphore(device, &createInfo, pAllocator, + pSem); +} +VkResult createSemaphores( + const DeviceData *device_functions, + VkDevice device, + const VkAllocationCallbacks *pAllocator, + size_t count, + std::vector& sems) { + sems.resize(count); + for (VkSemaphore& sem : sems) { + VkResult res; + if ((res = createSemaphore(device_functions, device, pAllocator, &sem)) != + VK_SUCCESS) { + return res; + } + } + return VK_SUCCESS; +} + +void destroySemaphores( + const DeviceData *device_functions, + VkDevice device, + const VkAllocationCallbacks *pAllocator, + std::vector& sems) { + for (VkSemaphore sem : sems) { + device_functions->vkDestroySemaphore(device, sem, pAllocator); + } + sems.clear(); +} +} + BaseSwapchain::BaseSwapchain(VkInstance instance, VkDevice device, uint32_t queue, VkCommandPool command_pool, uint32_t num_images, const InstanceData *instance_functions, @@ -73,78 +116,77 @@ BaseSwapchain::BaseSwapchain(VkInstance instance, VkDevice device, uint32_t queu } } - uint32_t numImages = 0; - device_functions_->vkGetSwapchainImagesKHR(device, swapchain_, &numImages, nullptr); - images_.resize(numImages); - device_functions_->vkGetSwapchainImagesKHR(device, swapchain_, &numImages, images_.data()); + uint32_t num_base_images = 0; + device_functions_->vkGetSwapchainImagesKHR(device, swapchain_, &num_base_images, nullptr); + images_.resize(num_base_images); + device_functions_->vkGetSwapchainImagesKHR(device, swapchain_, &num_base_images, images_.data()); + // Create a command buffer for each virtual image to blit from VkCommandBufferAllocateInfo command_buffer_info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, // sType nullptr, // pNext command_pool, // commandPool VK_COMMAND_BUFFER_LEVEL_PRIMARY, // level - 1, // commandBufferCount + num_images, // commandBufferCount }; - device_functions_->vkAllocateCommandBuffers(device, &command_buffer_info, &command_buffer_); - set_dispatch_from_parent(command_buffer_, device); + command_buffers_.resize(num_images); + if (device_functions_->vkAllocateCommandBuffers(device, &command_buffer_info, + command_buffers_.data()) != + VK_SUCCESS) { + return; + } + for (VkCommandBuffer cmdbuf : command_buffers_) { + set_dispatch_from_parent(cmdbuf, device); + } - { - VkSemaphoreCreateInfo createInfo = { - VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, // sType - nullptr, // pNext - 0, // flags - }; - if (device_functions_->vkCreateSemaphore(device_, &createInfo, pAllocator, - &acquire_semaphore_) != VK_SUCCESS) { - return; - } - if (device_functions_->vkCreateSemaphore(device_, &createInfo, pAllocator, - &blit_semaphore_) != VK_SUCCESS) { - return; - } + if (createSemaphore(device_functions_, device_, pAllocator, + &acquire_semaphore_) != VK_SUCCESS) { + return; } - { - VkFenceCreateInfo createInfo = { - VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, // sType - nullptr, // pNext - 0, // flags - }; - if (device_functions_->vkCreateFence(device_, &createInfo, pAllocator, - &blit_fence_) != VK_SUCCESS) { - return; - } + if (createSemaphores(device_functions_, device_, pAllocator, num_images, + blit_semaphores_) != VK_SUCCESS) { + return; } + if (createSemaphores(device_functions_, device_, pAllocator, num_images, + present_semaphores_) != VK_SUCCESS) { + return; + } + + is_pending_.resize(num_images); } void BaseSwapchain::Destroy(const VkAllocationCallbacks *pAllocator) { device_functions_->vkDestroySemaphore(device_, acquire_semaphore_, pAllocator); acquire_semaphore_ = VK_NULL_HANDLE; - device_functions_->vkDestroySemaphore(device_, blit_semaphore_, pAllocator); - blit_semaphore_ = VK_NULL_HANDLE; - - device_functions_->vkDestroyFence(device_, blit_fence_, pAllocator); - blit_fence_ = VK_NULL_HANDLE; + destroySemaphores(device_functions_, device_, pAllocator, blit_semaphores_); + destroySemaphores(device_functions_, device_, pAllocator, present_semaphores_); device_functions_->vkDestroySwapchainKHR(device_, swapchain_, pAllocator); swapchain_ = VK_NULL_HANDLE; instance_functions_->vkDestroySurfaceKHR(instance_, surface_, pAllocator); surface_ = VK_NULL_HANDLE; + + images_.clear(); + + is_pending_.clear(); + command_buffers_.clear(); } -VkResult BaseSwapchain::PresentFrom(VkQueue queue, VkImage image) { +VkResult BaseSwapchain::PresentFrom(VkQueue queue, size_t index, VkImage image) { std::unique_lock guard(present_lock_); VkResult res; - uint32_t index = 0; + uint32_t base_index = 0; // TODO: the error return values here aren't necessarily valid return values // for VkQueueSubmit if ((res = device_functions_->vkAcquireNextImageKHR(device_, swapchain_, 0, acquire_semaphore_, - VK_NULL_HANDLE, &index)) != VK_SUCCESS) { + VK_NULL_HANDLE, &base_index)) != VK_SUCCESS) { return res; } - if ((res = device_functions_->vkResetCommandBuffer(command_buffer_, 0)) != VK_SUCCESS) { + VkCommandBuffer cmdbuf = command_buffers_[index]; + if ((res = device_functions_->vkResetCommandBuffer(cmdbuf, 0)) != VK_SUCCESS) { return res; } VkCommandBufferBeginInfo beginInfo = { @@ -153,7 +195,7 @@ VkResult BaseSwapchain::PresentFrom(VkQueue queue, VkImage image) { VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, // flags nullptr, // pInheritanceInfo }; - if ((res = device_functions_->vkBeginCommandBuffer(command_buffer_, &beginInfo)) != VK_SUCCESS) { + if ((res = device_functions_->vkBeginCommandBuffer(cmdbuf, &beginInfo)) != VK_SUCCESS) { return res; } @@ -169,7 +211,7 @@ VkResult BaseSwapchain::PresentFrom(VkQueue queue, VkImage image) { VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // newLayout VK_QUEUE_FAMILY_IGNORED, // srcQueueFamilyIndex VK_QUEUE_FAMILY_IGNORED, // dstQueueFamilyIndex - images_[index], // image + images_[base_index], // image VkImageSubresourceRange { VK_IMAGE_ASPECT_COLOR_BIT, // aspectMask 0, // baseMipLevel @@ -180,7 +222,7 @@ VkResult BaseSwapchain::PresentFrom(VkQueue queue, VkImage image) { }; device_functions_->vkCmdPipelineBarrier( - command_buffer_, + cmdbuf, 0, // srcStageMask VK_PIPELINE_STAGE_TRANSFER_BIT, // dstStageMask 0, // dependencyFlags @@ -212,10 +254,10 @@ VkResult BaseSwapchain::PresentFrom(VkQueue queue, VkImage image) { { offsets[0], offsets[1] }, }; device_functions_->vkCmdBlitImage( - command_buffer_, + cmdbuf, image, // srcImage VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // srcImageLayout - images_[index], // dstImage + images_[base_index], // dstImage VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, // dstImageLayout 1, // regionCount &blit, // pRegions @@ -229,7 +271,7 @@ VkResult BaseSwapchain::PresentFrom(VkQueue queue, VkImage image) { finalBarrier.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; device_functions_->vkCmdPipelineBarrier( - command_buffer_, + cmdbuf, VK_PIPELINE_STAGE_TRANSFER_BIT, // srcStageMask 0, // dstStageMask 0, // dependencyFlags @@ -241,11 +283,13 @@ VkResult BaseSwapchain::PresentFrom(VkQueue queue, VkImage image) { &finalBarrier // pImageMemoryBarriers ); - if ((res = device_functions_->vkEndCommandBuffer(command_buffer_)) != + if ((res = device_functions_->vkEndCommandBuffer(cmdbuf)) != VK_SUCCESS) { return res; } + VkSemaphore signal_semaphores[] = {blit_semaphores_[index], + present_semaphores_[index]}; VkPipelineStageFlags waitStage = VK_PIPELINE_STAGE_TRANSFER_BIT; VkSubmitInfo submitInfo = { VK_STRUCTURE_TYPE_SUBMIT_INFO, // sType @@ -254,34 +298,39 @@ VkResult BaseSwapchain::PresentFrom(VkQueue queue, VkImage image) { &acquire_semaphore_, // pWaitSemaphores &waitStage, // pWaitDstStageMask 1, // commandBufferCount - &command_buffer_, // pCommandBuffers - 1, // signalSemaphoreCount - &blit_semaphore_, // pSignalSemaphores + &cmdbuf, // pCommandBuffers + 2, // signalSemaphoreCount + signal_semaphores, // pSignalSemaphores }; auto queue_functions = GetGlobalContext().GetQueueData(queue); if ((res = queue_functions->vkQueueSubmit(queue, 1, &submitInfo, - blit_fence_)) != VK_SUCCESS) { + VK_NULL_HANDLE)) != VK_SUCCESS) { return res; } + is_pending_[index] = true; VkPresentInfoKHR presentInfo = { VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, // sType 0, // pNext 1, // waitSemaphoreCount - &blit_semaphore_, // waitSemaphores + &present_semaphores_[index], // waitSemaphores 1, // swapchainCount &swapchain_, // pSwapchains, - &index, // pImageIndices + &base_index, // pImageIndices nullptr, // pResults }; if ((res = queue_functions->vkQueuePresentKHR(queue, &presentInfo)) != VK_SUCCESS) { return res; } - - device_functions_->vkWaitForFences(device_, 1, &blit_fence_, VK_TRUE, - 0xFFFFFFFFFFFFFFFFULL); - device_functions_->vkResetFences(device_, 1, &blit_fence_); return VK_SUCCESS; } + +VkSemaphore BaseSwapchain::BlitWaitSemaphore(size_t index) { + if (!is_pending_[index]) { + return VK_NULL_HANDLE; + } + is_pending_[index] = false; + return blit_semaphores_[index]; +} } diff --git a/core/vulkan/vk_virtual_swapchain/cc/base_swapchain.h b/core/vulkan/vk_virtual_swapchain/cc/base_swapchain.h index cf8a35b911..5c258db000 100644 --- a/core/vulkan/vk_virtual_swapchain/cc/base_swapchain.h +++ b/core/vulkan/vk_virtual_swapchain/cc/base_swapchain.h @@ -19,7 +19,6 @@ #include #include -#include #include #include "layer.h" @@ -35,7 +34,8 @@ class BaseSwapchain { const VkAllocationCallbacks *pAllocator, const void *platform_info); void Destroy(const VkAllocationCallbacks *pAllocator); - VkResult PresentFrom(VkQueue queue, VkImage image); + VkResult PresentFrom(VkQueue queue, size_t index, VkImage image); + VkSemaphore BlitWaitSemaphore(size_t index); private: VkInstance instance_; VkDevice device_; @@ -54,12 +54,16 @@ class BaseSwapchain { // The semaphores to signal when the acquire is completed. VkSemaphore acquire_semaphore_; // The semaphores to signal when the blit is completed. - VkSemaphore blit_semaphore_; - // The fence to signal when the blit is completed, so the host can return. - VkFence blit_fence_; + std::vector blit_semaphores_; + // The semaphores that will be signaled when the blit is complete and will be + // waited on by the queue present + std::vector present_semaphores_; + // Whether the semaphores at a given index are currently pending and should + // have their blit semaphore waited on before acquiring. + std::vector is_pending_; // The command buffers to use to blit. We need several in case someone // submits while a previous one is still pending. - VkCommandBuffer command_buffer_; + std::vector command_buffers_; }; } diff --git a/core/vulkan/vk_virtual_swapchain/cc/layer.cpp b/core/vulkan/vk_virtual_swapchain/cc/layer.cpp index 6e6b40929a..bfff858b0a 100644 --- a/core/vulkan/vk_virtual_swapchain/cc/layer.cpp +++ b/core/vulkan/vk_virtual_swapchain/cc/layer.cpp @@ -287,7 +287,8 @@ vkCreateDevice(VkPhysicalDevice gpu, const VkDeviceCreateInfo *pCreateInfo, *pDevice, pCreateInfo->pQueueCreateInfos[i].queueFamilyIndex, j, &q); set_dispatch_from_parent(q, *pDevice); - (*queue_map)[q] = {*pDevice, data.vkQueueSubmit, data.vkQueuePresentKHR}; + (*queue_map)[q] = {*pDevice, data.vkQueueSubmit, + data.vkQueuePresentKHR}; } } } diff --git a/core/vulkan/vk_virtual_swapchain/cc/swapchain.cpp b/core/vulkan/vk_virtual_swapchain/cc/swapchain.cpp index e20f48caa3..ddf6078c84 100644 --- a/core/vulkan/vk_virtual_swapchain/cc/swapchain.cpp +++ b/core/vulkan/vk_virtual_swapchain/cc/swapchain.cpp @@ -294,11 +294,15 @@ VKAPI_ATTR VkResult VKAPI_CALL vkAcquireNextImageKHR( bool has_semaphore = semaphore != VK_NULL_HANDLE; + VkSemaphore wait_semaphore = swp->GetAcquireWaitSemaphore(*pImageIndex); + VkPipelineStageFlags wait_stage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; + bool has_wait_semaphore = wait_semaphore != VK_NULL_HANDLE; + VkSubmitInfo info{VK_STRUCTURE_TYPE_SUBMIT_INFO, // sType nullptr, // pNext - 0, // waitSemaphoreCount - nullptr, // waitSemaphores - nullptr, // waitDstStageMask + (has_wait_semaphore ? 1u : 0u), // waitSemaphoreCount + (has_wait_semaphore ? &wait_semaphore : nullptr), // pWaitSemaphores + (has_wait_semaphore ? &wait_stage : nullptr), // pWaitDstStageMask 0, // commandBufferCount nullptr, // pCommandBuffers (has_semaphore ? 1u : 0u), // semaphoreCount diff --git a/core/vulkan/vk_virtual_swapchain/cc/virtual_swapchain.h b/core/vulkan/vk_virtual_swapchain/cc/virtual_swapchain.h index e8c1a55594..9a877478c4 100644 --- a/core/vulkan/vk_virtual_swapchain/cc/virtual_swapchain.h +++ b/core/vulkan/vk_virtual_swapchain/cc/virtual_swapchain.h @@ -94,7 +94,17 @@ class VirtualSwapchain { return VK_SUCCESS; } - return base_swapchain_->PresentFrom(queue, image_data_[i].image_); + return base_swapchain_->PresentFrom(queue, i, image_data_[i].image_); + } + + // If we have a real base swapchain we need it to be done with its blit before + // we can acquire it again. + VkSemaphore GetAcquireWaitSemaphore(size_t i) { + if (!base_swapchain_) { + return VK_NULL_HANDLE; + } + + return base_swapchain_->BlitWaitSemaphore(i); } // When the commands associated with an image have been submitted to From d6e05f8631d796839e98e19129c77d4121d0be21 Mon Sep 17 00:00:00 2001 From: Sean Purcell Date: Tue, 31 Jul 2018 13:07:26 -0400 Subject: [PATCH 06/12] Apply clang format --- cmd/gapir/cc/main.cpp | 4 +- .../cc/base_swapchain.cpp | 284 +++++++++--------- .../vk_virtual_swapchain/cc/base_swapchain.h | 5 +- .../vk_virtual_swapchain/cc/platform.cpp | 13 +- .../vulkan/vk_virtual_swapchain/cc/platform.h | 6 +- .../vk_virtual_swapchain/cc/swapchain.cpp | 23 +- .../cc/virtual_swapchain.cpp | 17 +- 7 files changed, 180 insertions(+), 172 deletions(-) diff --git a/cmd/gapir/cc/main.cpp b/cmd/gapir/cc/main.cpp index b0a73d9cc6..44a43ce649 100644 --- a/cmd/gapir/cc/main.cpp +++ b/cmd/gapir/cc/main.cpp @@ -134,8 +134,8 @@ void android_process(struct android_app* app, int32_t cmd) { switch (cmd) { case APP_CMD_INIT_WINDOW: { gapir::android_window = app->window; - __android_log_print(ANDROID_LOG_DEBUG, "GAPIR", - "Received window: %p\n", gapir::android_window); + __android_log_print(ANDROID_LOG_DEBUG, "GAPIR", "Received window: %p\n", + gapir::android_window); break; } } diff --git a/core/vulkan/vk_virtual_swapchain/cc/base_swapchain.cpp b/core/vulkan/vk_virtual_swapchain/cc/base_swapchain.cpp index bdfcfa76fe..04067080da 100644 --- a/core/vulkan/vk_virtual_swapchain/cc/base_swapchain.cpp +++ b/core/vulkan/vk_virtual_swapchain/cc/base_swapchain.cpp @@ -21,27 +21,22 @@ namespace swapchain { namespace { -VkResult createSemaphore( - const DeviceData *device_functions, - VkDevice device, - const VkAllocationCallbacks *pAllocator, - VkSemaphore* pSem) { +VkResult createSemaphore(const DeviceData *device_functions, VkDevice device, + const VkAllocationCallbacks *pAllocator, + VkSemaphore *pSem) { VkSemaphoreCreateInfo createInfo = { - VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, // sType - nullptr, // pNext - 0, // flags + VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, // sType + nullptr, // pNext + 0, // flags }; return device_functions->vkCreateSemaphore(device, &createInfo, pAllocator, pSem); } -VkResult createSemaphores( - const DeviceData *device_functions, - VkDevice device, - const VkAllocationCallbacks *pAllocator, - size_t count, - std::vector& sems) { +VkResult createSemaphores(const DeviceData *device_functions, VkDevice device, + const VkAllocationCallbacks *pAllocator, size_t count, + std::vector &sems) { sems.resize(count); - for (VkSemaphore& sem : sems) { + for (VkSemaphore &sem : sems) { VkResult res; if ((res = createSemaphore(device_functions, device, pAllocator, &sem)) != VK_SUCCESS) { @@ -51,20 +46,19 @@ VkResult createSemaphores( return VK_SUCCESS; } -void destroySemaphores( - const DeviceData *device_functions, - VkDevice device, - const VkAllocationCallbacks *pAllocator, - std::vector& sems) { +void destroySemaphores(const DeviceData *device_functions, VkDevice device, + const VkAllocationCallbacks *pAllocator, + std::vector &sems) { for (VkSemaphore sem : sems) { device_functions->vkDestroySemaphore(device, sem, pAllocator); } sems.clear(); } -} +} // namespace -BaseSwapchain::BaseSwapchain(VkInstance instance, VkDevice device, uint32_t queue, - VkCommandPool command_pool, uint32_t num_images, +BaseSwapchain::BaseSwapchain(VkInstance instance, VkDevice device, + uint32_t queue, VkCommandPool command_pool, + uint32_t num_images, const InstanceData *instance_functions, const DeviceData *device_functions, const VkSwapchainCreateInfoKHR *swapchain_info, @@ -74,14 +68,13 @@ BaseSwapchain::BaseSwapchain(VkInstance instance, VkDevice device, uint32_t queu device_(device), instance_functions_(instance_functions), device_functions_(device_functions), - swapchain_info_(*swapchain_info) -{ - + swapchain_info_(*swapchain_info) { if (platform_info == nullptr) { return; } - CreateSurface(instance_functions, instance, platform_info, pAllocator, &surface_); + CreateSurface(instance_functions, instance, platform_info, pAllocator, + &surface_); if (surface_ == 0) { // Surface creation failed return; @@ -90,26 +83,27 @@ BaseSwapchain::BaseSwapchain(VkInstance instance, VkDevice device, uint32_t queu { // Create the swapchain VkSwapchainCreateInfoKHR createInfo = { - VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, // sType - nullptr, // pNext - 0, // flags - surface_, // surface - num_images, // minImageCount - swapchain_info_.imageFormat, // imageFormat - swapchain_info_.imageColorSpace, // imageColorSpace - swapchain_info_.imageExtent, // imageExtent - swapchain_info_.imageArrayLayers, // arrayLayers - VK_IMAGE_USAGE_TRANSFER_DST_BIT, // imageUsage - VK_SHARING_MODE_EXCLUSIVE, // imageSharingMode, - 0, // queueFamilyIndexCount - nullptr, // pQueueFamilyIndices - swapchain_info_.preTransform, // preTransform - swapchain_info_.compositeAlpha, // compositeAlpha - VK_PRESENT_MODE_FIFO_KHR, // presentMode - VK_TRUE, // clipped - 0, // oldSwapchain + VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, // sType + nullptr, // pNext + 0, // flags + surface_, // surface + num_images, // minImageCount + swapchain_info_.imageFormat, // imageFormat + swapchain_info_.imageColorSpace, // imageColorSpace + swapchain_info_.imageExtent, // imageExtent + swapchain_info_.imageArrayLayers, // arrayLayers + VK_IMAGE_USAGE_TRANSFER_DST_BIT, // imageUsage + VK_SHARING_MODE_EXCLUSIVE, // imageSharingMode, + 0, // queueFamilyIndexCount + nullptr, // pQueueFamilyIndices + swapchain_info_.preTransform, // preTransform + swapchain_info_.compositeAlpha, // compositeAlpha + VK_PRESENT_MODE_FIFO_KHR, // presentMode + VK_TRUE, // clipped + 0, // oldSwapchain }; - if (device_functions_->vkCreateSwapchainKHR(device_, &createInfo, pAllocator, &swapchain_) != VK_SUCCESS) { + if (device_functions_->vkCreateSwapchainKHR( + device_, &createInfo, pAllocator, &swapchain_) != VK_SUCCESS) { // Creating swapchain failed swapchain_ = 0; return; @@ -117,17 +111,19 @@ BaseSwapchain::BaseSwapchain(VkInstance instance, VkDevice device, uint32_t queu } uint32_t num_base_images = 0; - device_functions_->vkGetSwapchainImagesKHR(device, swapchain_, &num_base_images, nullptr); + device_functions_->vkGetSwapchainImagesKHR(device, swapchain_, + &num_base_images, nullptr); images_.resize(num_base_images); - device_functions_->vkGetSwapchainImagesKHR(device, swapchain_, &num_base_images, images_.data()); + device_functions_->vkGetSwapchainImagesKHR(device, swapchain_, + &num_base_images, images_.data()); // Create a command buffer for each virtual image to blit from VkCommandBufferAllocateInfo command_buffer_info = { - VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, // sType - nullptr, // pNext - command_pool, // commandPool - VK_COMMAND_BUFFER_LEVEL_PRIMARY, // level - num_images, // commandBufferCount + VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, // sType + nullptr, // pNext + command_pool, // commandPool + VK_COMMAND_BUFFER_LEVEL_PRIMARY, // level + num_images, // commandBufferCount }; command_buffers_.resize(num_images); if (device_functions_->vkAllocateCommandBuffers(device, &command_buffer_info, @@ -156,11 +152,13 @@ BaseSwapchain::BaseSwapchain(VkInstance instance, VkDevice device, uint32_t queu } void BaseSwapchain::Destroy(const VkAllocationCallbacks *pAllocator) { - device_functions_->vkDestroySemaphore(device_, acquire_semaphore_, pAllocator); + device_functions_->vkDestroySemaphore(device_, acquire_semaphore_, + pAllocator); acquire_semaphore_ = VK_NULL_HANDLE; destroySemaphores(device_functions_, device_, pAllocator, blit_semaphores_); - destroySemaphores(device_functions_, device_, pAllocator, present_semaphores_); + destroySemaphores(device_functions_, device_, pAllocator, + present_semaphores_); device_functions_->vkDestroySwapchainKHR(device_, swapchain_, pAllocator); swapchain_ = VK_NULL_HANDLE; @@ -174,28 +172,32 @@ void BaseSwapchain::Destroy(const VkAllocationCallbacks *pAllocator) { command_buffers_.clear(); } -VkResult BaseSwapchain::PresentFrom(VkQueue queue, size_t index, VkImage image) { +VkResult BaseSwapchain::PresentFrom(VkQueue queue, size_t index, + VkImage image) { std::unique_lock guard(present_lock_); VkResult res; uint32_t base_index = 0; // TODO: the error return values here aren't necessarily valid return values // for VkQueueSubmit - if ((res = device_functions_->vkAcquireNextImageKHR(device_, swapchain_, 0, acquire_semaphore_, - VK_NULL_HANDLE, &base_index)) != VK_SUCCESS) { + if ((res = device_functions_->vkAcquireNextImageKHR( + device_, swapchain_, 0, acquire_semaphore_, VK_NULL_HANDLE, + &base_index)) != VK_SUCCESS) { return res; } VkCommandBuffer cmdbuf = command_buffers_[index]; - if ((res = device_functions_->vkResetCommandBuffer(cmdbuf, 0)) != VK_SUCCESS) { + if ((res = device_functions_->vkResetCommandBuffer(cmdbuf, 0)) != + VK_SUCCESS) { return res; } VkCommandBufferBeginInfo beginInfo = { - VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, // sType - 0, // pNext - VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, // flags - nullptr, // pInheritanceInfo + VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, // sType + 0, // pNext + VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, // flags + nullptr, // pInheritanceInfo }; - if ((res = device_functions_->vkBeginCommandBuffer(cmdbuf, &beginInfo)) != VK_SUCCESS) { + if ((res = device_functions_->vkBeginCommandBuffer(cmdbuf, &beginInfo)) != + VK_SUCCESS) { return res; } @@ -203,65 +205,70 @@ VkResult BaseSwapchain::PresentFrom(VkQueue queue, size_t index, VkImage image) // transition our image between VK_IMAGE_LAYOUT_TRANSFER_DST and // VK_IMAGE_LAYOUT_SHADER_PRESENT_KHR VkImageMemoryBarrier initialBarrier = { - VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType - nullptr, // pNext - 0, // srcAccessFlags - VK_ACCESS_TRANSFER_WRITE_BIT, // dstAccessFlags - VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, // oldLayout - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // newLayout - VK_QUEUE_FAMILY_IGNORED, // srcQueueFamilyIndex - VK_QUEUE_FAMILY_IGNORED, // dstQueueFamilyIndex - images_[base_index], // image - VkImageSubresourceRange { - VK_IMAGE_ASPECT_COLOR_BIT, // aspectMask - 0, // baseMipLevel - 1, // levelCount - 0, // baseArrayLayer - swapchain_info_.imageArrayLayers, // layerCount - }, // subresourceRange + VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType + nullptr, // pNext + 0, // srcAccessFlags + VK_ACCESS_TRANSFER_WRITE_BIT, // dstAccessFlags + VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, // oldLayout + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // newLayout + VK_QUEUE_FAMILY_IGNORED, // srcQueueFamilyIndex + VK_QUEUE_FAMILY_IGNORED, // dstQueueFamilyIndex + images_[base_index], // image + VkImageSubresourceRange{ + VK_IMAGE_ASPECT_COLOR_BIT, // aspectMask + 0, // baseMipLevel + 1, // levelCount + 0, // baseArrayLayer + swapchain_info_.imageArrayLayers, // layerCount + }, // subresourceRange }; device_functions_->vkCmdPipelineBarrier( cmdbuf, - 0, // srcStageMask - VK_PIPELINE_STAGE_TRANSFER_BIT, // dstStageMask - 0, // dependencyFlags - 0, // memoryBarrierCount - nullptr, // pMemoryBarriers - 0, // bufferMemoryBarrierCount - nullptr, // pBufferMemoryBarriers - 1, // imageMemoryBarrierCount - &initialBarrier // pImageMemoryBarriers + 0, // srcStageMask + VK_PIPELINE_STAGE_TRANSFER_BIT, // dstStageMask + 0, // dependencyFlags + 0, // memoryBarrierCount + nullptr, // pMemoryBarriers + 0, // bufferMemoryBarrierCount + nullptr, // pBufferMemoryBarriers + 1, // imageMemoryBarrierCount + &initialBarrier // pImageMemoryBarriers ); VkImageSubresourceLayers subresource = { - VK_IMAGE_ASPECT_COLOR_BIT, // aspectMask - 0, // mipLevel - 0, // baseArrayLayer - swapchain_info_.imageArrayLayers, // layerCount + VK_IMAGE_ASPECT_COLOR_BIT, // aspectMask + 0, // mipLevel + 0, // baseArrayLayer + swapchain_info_.imageArrayLayers, // layerCount }; VkOffset3D offsets[2] = { - { 0, 0, 0, }, - { (int32_t)swapchain_info_.imageExtent.width, - (int32_t)swapchain_info_.imageExtent.height, - 1, - }, + { + 0, + 0, + 0, + }, + { + (int32_t)swapchain_info_.imageExtent.width, + (int32_t)swapchain_info_.imageExtent.height, + 1, + }, }; VkImageBlit blit = { - subresource, - { offsets[0], offsets[1] }, - subresource, - { offsets[0], offsets[1] }, + subresource, + {offsets[0], offsets[1]}, + subresource, + {offsets[0], offsets[1]}, }; device_functions_->vkCmdBlitImage( cmdbuf, - image, // srcImage - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // srcImageLayout - images_[base_index], // dstImage - VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, // dstImageLayout - 1, // regionCount - &blit, // pRegions - VK_FILTER_NEAREST // filter + image, // srcImage + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // srcImageLayout + images_[base_index], // dstImage + VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, // dstImageLayout + 1, // regionCount + &blit, // pRegions + VK_FILTER_NEAREST // filter ); VkImageMemoryBarrier finalBarrier = initialBarrier; @@ -272,35 +279,34 @@ VkResult BaseSwapchain::PresentFrom(VkQueue queue, size_t index, VkImage image) device_functions_->vkCmdPipelineBarrier( cmdbuf, - VK_PIPELINE_STAGE_TRANSFER_BIT, // srcStageMask - 0, // dstStageMask - 0, // dependencyFlags - 0, // memoryBarrierCount - nullptr, // pMemoryBarriers - 0, // bufferMemoryBarrierCount - nullptr, // pBufferMemoryBarriers - 1, // imageMemoryBarrierCount - &finalBarrier // pImageMemoryBarriers + VK_PIPELINE_STAGE_TRANSFER_BIT, // srcStageMask + 0, // dstStageMask + 0, // dependencyFlags + 0, // memoryBarrierCount + nullptr, // pMemoryBarriers + 0, // bufferMemoryBarrierCount + nullptr, // pBufferMemoryBarriers + 1, // imageMemoryBarrierCount + &finalBarrier // pImageMemoryBarriers ); - if ((res = device_functions_->vkEndCommandBuffer(cmdbuf)) != - VK_SUCCESS) { + if ((res = device_functions_->vkEndCommandBuffer(cmdbuf)) != VK_SUCCESS) { return res; } VkSemaphore signal_semaphores[] = {blit_semaphores_[index], - present_semaphores_[index]}; + present_semaphores_[index]}; VkPipelineStageFlags waitStage = VK_PIPELINE_STAGE_TRANSFER_BIT; VkSubmitInfo submitInfo = { - VK_STRUCTURE_TYPE_SUBMIT_INFO, // sType - 0, // pNext - 1, // waitSemaphoreCount - &acquire_semaphore_, // pWaitSemaphores - &waitStage, // pWaitDstStageMask - 1, // commandBufferCount - &cmdbuf, // pCommandBuffers - 2, // signalSemaphoreCount - signal_semaphores, // pSignalSemaphores + VK_STRUCTURE_TYPE_SUBMIT_INFO, // sType + 0, // pNext + 1, // waitSemaphoreCount + &acquire_semaphore_, // pWaitSemaphores + &waitStage, // pWaitDstStageMask + 1, // commandBufferCount + &cmdbuf, // pCommandBuffers + 2, // signalSemaphoreCount + signal_semaphores, // pSignalSemaphores }; auto queue_functions = GetGlobalContext().GetQueueData(queue); if ((res = queue_functions->vkQueueSubmit(queue, 1, &submitInfo, @@ -310,14 +316,14 @@ VkResult BaseSwapchain::PresentFrom(VkQueue queue, size_t index, VkImage image) is_pending_[index] = true; VkPresentInfoKHR presentInfo = { - VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, // sType - 0, // pNext - 1, // waitSemaphoreCount - &present_semaphores_[index], // waitSemaphores - 1, // swapchainCount - &swapchain_, // pSwapchains, - &base_index, // pImageIndices - nullptr, // pResults + VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, // sType + 0, // pNext + 1, // waitSemaphoreCount + &present_semaphores_[index], // waitSemaphores + 1, // swapchainCount + &swapchain_, // pSwapchains, + &base_index, // pImageIndices + nullptr, // pResults }; if ((res = queue_functions->vkQueuePresentKHR(queue, &presentInfo)) != VK_SUCCESS) { @@ -333,4 +339,4 @@ VkSemaphore BaseSwapchain::BlitWaitSemaphore(size_t index) { is_pending_[index] = false; return blit_semaphores_[index]; } -} +} // namespace swapchain diff --git a/core/vulkan/vk_virtual_swapchain/cc/base_swapchain.h b/core/vulkan/vk_virtual_swapchain/cc/base_swapchain.h index 5c258db000..f187be8317 100644 --- a/core/vulkan/vk_virtual_swapchain/cc/base_swapchain.h +++ b/core/vulkan/vk_virtual_swapchain/cc/base_swapchain.h @@ -36,6 +36,7 @@ class BaseSwapchain { void Destroy(const VkAllocationCallbacks *pAllocator); VkResult PresentFrom(VkQueue queue, size_t index, VkImage image); VkSemaphore BlitWaitSemaphore(size_t index); + private: VkInstance instance_; VkDevice device_; @@ -66,6 +67,6 @@ class BaseSwapchain { std::vector command_buffers_; }; -} +} // namespace swapchain -#endif // VK_BASE_SWAPCHAIN_VIRTUAL_SWAPCHAIN_H_ +#endif // VK_BASE_SWAPCHAIN_VIRTUAL_SWAPCHAIN_H_ diff --git a/core/vulkan/vk_virtual_swapchain/cc/platform.cpp b/core/vulkan/vk_virtual_swapchain/cc/platform.cpp index 4a25044e36..2d233da40b 100644 --- a/core/vulkan/vk_virtual_swapchain/cc/platform.cpp +++ b/core/vulkan/vk_virtual_swapchain/cc/platform.cpp @@ -14,18 +14,21 @@ * limitations under the License. */ - #include "platform.h" namespace swapchain { -void CreateSurface(const InstanceData* functions, VkInstance instance, const void* data, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface) { +void CreateSurface(const InstanceData* functions, VkInstance instance, + const void* data, const VkAllocationCallbacks* pAllocator, + VkSurfaceKHR* pSurface) { #ifdef VK_USE_PLATFORM_ANDROID_KHR { auto pCreateInfo = static_cast(data); - if (pCreateInfo->sType == VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR) { + if (pCreateInfo->sType == + VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR) { // Attempt to create android surface - if (functions->vkCreateAndroidSurfaceKHR(instance, pCreateInfo, pAllocator, pSurface) != VK_SUCCESS) { + if (functions->vkCreateAndroidSurfaceKHR( + instance, pCreateInfo, pAllocator, pSurface) != VK_SUCCESS) { *pSurface = 0; } } @@ -35,4 +38,4 @@ void CreateSurface(const InstanceData* functions, VkInstance instance, const voi #endif } -} +} // namespace swapchain diff --git a/core/vulkan/vk_virtual_swapchain/cc/platform.h b/core/vulkan/vk_virtual_swapchain/cc/platform.h index 43be01611a..c513435ebb 100644 --- a/core/vulkan/vk_virtual_swapchain/cc/platform.h +++ b/core/vulkan/vk_virtual_swapchain/cc/platform.h @@ -23,8 +23,10 @@ namespace swapchain { -void CreateSurface(const InstanceData* functions, VkInstance instance, const void* data, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); +void CreateSurface(const InstanceData* functions, VkInstance instance, + const void* data, const VkAllocationCallbacks* pAllocator, + VkSurfaceKHR* pSurface); } -#endif // VK_VIRTUAL_SWAPCHAIN_PLATFORM_H_ +#endif // VK_VIRTUAL_SWAPCHAIN_PLATFORM_H_ diff --git a/core/vulkan/vk_virtual_swapchain/cc/swapchain.cpp b/core/vulkan/vk_virtual_swapchain/cc/swapchain.cpp index ddf6078c84..a32ab35e59 100644 --- a/core/vulkan/vk_virtual_swapchain/cc/swapchain.cpp +++ b/core/vulkan/vk_virtual_swapchain/cc/swapchain.cpp @@ -210,8 +210,8 @@ VKAPI_ATTR VkResult VKAPI_CALL vkCreateSwapchainKHR( if (pNext->sType == VIRTUAL_SWAPCHAIN_CREATE_PNEXT) { swp->SetAlwaysGetAcquiredImage(true); if (pNext->surfaceCreateInfo) { - swp->CreateBaseSwapchain(pdd.instance_, &inst_dat, - pAllocator, pNext->surfaceCreateInfo); + swp->CreateBaseSwapchain(pdd.instance_, &inst_dat, pAllocator, + pNext->surfaceCreateInfo); } break; } @@ -298,15 +298,16 @@ VKAPI_ATTR VkResult VKAPI_CALL vkAcquireNextImageKHR( VkPipelineStageFlags wait_stage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; bool has_wait_semaphore = wait_semaphore != VK_NULL_HANDLE; - VkSubmitInfo info{VK_STRUCTURE_TYPE_SUBMIT_INFO, // sType - nullptr, // pNext - (has_wait_semaphore ? 1u : 0u), // waitSemaphoreCount - (has_wait_semaphore ? &wait_semaphore : nullptr), // pWaitSemaphores - (has_wait_semaphore ? &wait_stage : nullptr), // pWaitDstStageMask - 0, // commandBufferCount - nullptr, // pCommandBuffers - (has_semaphore ? 1u : 0u), // semaphoreCount - (has_semaphore ? &semaphore : nullptr)}; // pSemaphores + VkSubmitInfo info{ + VK_STRUCTURE_TYPE_SUBMIT_INFO, // sType + nullptr, // pNext + (has_wait_semaphore ? 1u : 0u), // waitSemaphoreCount + (has_wait_semaphore ? &wait_semaphore : nullptr), // pWaitSemaphores + (has_wait_semaphore ? &wait_stage : nullptr), // pWaitDstStageMask + 0, // commandBufferCount + nullptr, // pCommandBuffers + (has_semaphore ? 1u : 0u), // semaphoreCount + (has_semaphore ? &semaphore : nullptr)}; // pSemaphores return swapchain::vkQueueSubmit(q, 1, &info, fence); } diff --git a/core/vulkan/vk_virtual_swapchain/cc/virtual_swapchain.cpp b/core/vulkan/vk_virtual_swapchain/cc/virtual_swapchain.cpp index 4a4c771b15..61cc0600cb 100644 --- a/core/vulkan/vk_virtual_swapchain/cc/virtual_swapchain.cpp +++ b/core/vulkan/vk_virtual_swapchain/cc/virtual_swapchain.cpp @@ -396,16 +396,11 @@ uint32_t VirtualSwapchain::ImageByteSize() const { return width_ * height_ * 4; } -void VirtualSwapchain::CreateBaseSwapchain(VkInstance instance, - const InstanceData *instance_functions, - const VkAllocationCallbacks *pAllocator, - const void *platform_info) { - base_swapchain_ = std::unique_ptr( - new BaseSwapchain(instance, device_, queue_, - command_pool_, num_images_, - instance_functions, functions_, - &swapchain_info_, - pAllocator, - platform_info)); +void VirtualSwapchain::CreateBaseSwapchain( + VkInstance instance, const InstanceData *instance_functions, + const VkAllocationCallbacks *pAllocator, const void *platform_info) { + base_swapchain_ = std::unique_ptr(new BaseSwapchain( + instance, device_, queue_, command_pool_, num_images_, instance_functions, + functions_, &swapchain_info_, pAllocator, platform_info)); } } // namespace swapchain From a7dac4a24d3d7eccf252788d1cb76aa3927728dc Mon Sep 17 00:00:00 2001 From: Sean Purcell Date: Tue, 31 Jul 2018 16:20:09 -0400 Subject: [PATCH 07/12] Fix clang-format with different clang-format version --- core/vulkan/vk_virtual_swapchain/cc/platform.h | 1 - 1 file changed, 1 deletion(-) diff --git a/core/vulkan/vk_virtual_swapchain/cc/platform.h b/core/vulkan/vk_virtual_swapchain/cc/platform.h index c513435ebb..34556e808d 100644 --- a/core/vulkan/vk_virtual_swapchain/cc/platform.h +++ b/core/vulkan/vk_virtual_swapchain/cc/platform.h @@ -26,7 +26,6 @@ namespace swapchain { void CreateSurface(const InstanceData* functions, VkInstance instance, const void* data, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); - } #endif // VK_VIRTUAL_SWAPCHAIN_PLATFORM_H_ From 66c9fb58e5f297de83a5c25f51b0dde6a9e0d246 Mon Sep 17 00:00:00 2001 From: Sean Purcell Date: Tue, 31 Jul 2018 17:31:05 -0400 Subject: [PATCH 08/12] Fix incorrect image blitting layout --- core/vulkan/vk_virtual_swapchain/cc/base_swapchain.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/vulkan/vk_virtual_swapchain/cc/base_swapchain.cpp b/core/vulkan/vk_virtual_swapchain/cc/base_swapchain.cpp index 04067080da..25f36b1bdc 100644 --- a/core/vulkan/vk_virtual_swapchain/cc/base_swapchain.cpp +++ b/core/vulkan/vk_virtual_swapchain/cc/base_swapchain.cpp @@ -201,9 +201,9 @@ VkResult BaseSwapchain::PresentFrom(VkQueue queue, size_t index, return res; } - // The source image is already in VK_IMAGE_LAYOUT_TRANSFER_SRC, we need to - // transition our image between VK_IMAGE_LAYOUT_TRANSFER_DST and - // VK_IMAGE_LAYOUT_SHADER_PRESENT_KHR + // The source image is already in VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, we + // need to transition our image between VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL + // and VK_IMAGE_LAYOUT_PRESENT_SRC_KHR VkImageMemoryBarrier initialBarrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType nullptr, // pNext @@ -265,7 +265,7 @@ VkResult BaseSwapchain::PresentFrom(VkQueue queue, size_t index, image, // srcImage VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // srcImageLayout images_[base_index], // dstImage - VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, // dstImageLayout + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // dstImageLayout 1, // regionCount &blit, // pRegions VK_FILTER_NEAREST // filter From ed40a5951ac609ef01d8de749250d0569cfd0170 Mon Sep 17 00:00:00 2001 From: Sean Purcell Date: Tue, 31 Jul 2018 18:11:59 -0400 Subject: [PATCH 09/12] Use #if defined instead of #ifdef It results in more consistent #if's when multiple platforms are supported. --- core/vulkan/vk_virtual_swapchain/cc/layer.cpp | 2 +- core/vulkan/vk_virtual_swapchain/cc/layer.h | 2 +- core/vulkan/vk_virtual_swapchain/cc/platform.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/vulkan/vk_virtual_swapchain/cc/layer.cpp b/core/vulkan/vk_virtual_swapchain/cc/layer.cpp index bfff858b0a..168789c088 100644 --- a/core/vulkan/vk_virtual_swapchain/cc/layer.cpp +++ b/core/vulkan/vk_virtual_swapchain/cc/layer.cpp @@ -135,7 +135,7 @@ VKAPI_ATTR VkResult VKAPI_CALL vkCreateInstance( GET_PROC(vkGetPhysicalDeviceProperties); GET_PROC(vkGetPhysicalDeviceMemoryProperties); -#ifdef VK_USE_PLATFORM_ANDROID_KHR +#if defined(VK_USE_PLATFORM_ANDROID_KHR) GET_PROC(vkCreateAndroidSurfaceKHR); #endif GET_PROC(vkDestroySurfaceKHR); diff --git a/core/vulkan/vk_virtual_swapchain/cc/layer.h b/core/vulkan/vk_virtual_swapchain/cc/layer.h index c5a329d3b7..bf1e89bab4 100644 --- a/core/vulkan/vk_virtual_swapchain/cc/layer.h +++ b/core/vulkan/vk_virtual_swapchain/cc/layer.h @@ -49,7 +49,7 @@ struct InstanceData { PFN_vkGetPhysicalDeviceProperties vkGetPhysicalDeviceProperties; PFN_vkGetPhysicalDeviceMemoryProperties vkGetPhysicalDeviceMemoryProperties; -#ifdef VK_USE_PLATFORM_ANDROID_KHR +#if defined(VK_USE_PLATFORM_ANDROID_KHR) PFN_vkCreateAndroidSurfaceKHR vkCreateAndroidSurfaceKHR; #endif PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR; diff --git a/core/vulkan/vk_virtual_swapchain/cc/platform.cpp b/core/vulkan/vk_virtual_swapchain/cc/platform.cpp index 2d233da40b..1d93127e1c 100644 --- a/core/vulkan/vk_virtual_swapchain/cc/platform.cpp +++ b/core/vulkan/vk_virtual_swapchain/cc/platform.cpp @@ -21,7 +21,7 @@ namespace swapchain { void CreateSurface(const InstanceData* functions, VkInstance instance, const void* data, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface) { -#ifdef VK_USE_PLATFORM_ANDROID_KHR +#if defined(VK_USE_PLATFORM_ANDROID_KHR) { auto pCreateInfo = static_cast(data); if (pCreateInfo->sType == From 102ff608472e131e74760efeb2e69fe547a1daed Mon Sep 17 00:00:00 2001 From: Sean Purcell Date: Wed, 1 Aug 2018 10:30:40 -0400 Subject: [PATCH 10/12] Remove displaytosurface from video since it chunks replay --- cmd/gapit/flags.go | 1 - cmd/gapit/sxs_video.go | 2 +- cmd/gapit/video.go | 5 ++--- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/cmd/gapit/flags.go b/cmd/gapit/flags.go index fcab0816b8..3ea2a4556d 100644 --- a/cmd/gapit/flags.go +++ b/cmd/gapit/flags.go @@ -124,7 +124,6 @@ type ( Minimum int `help:"_return error when less than this number of frames is found"` } NoOpt bool `help:"disables optimization of the replay stream"` - DisplayToSurface bool `help:"display the frames rendered in the replay back to the surface"` CommandFilterFlags } DumpShadersFlags struct { diff --git a/cmd/gapit/sxs_video.go b/cmd/gapit/sxs_video.go index 0e89bc8346..0bf0c70432 100644 --- a/cmd/gapit/sxs_video.go +++ b/cmd/gapit/sxs_video.go @@ -171,7 +171,7 @@ func (verb *videoVerb) sxsVideoSource( Stride: int(v.fbo.Width) * 4, Rect: image.Rect(0, 0, int(v.fbo.Width), int(v.fbo.Height)), } - if frame, err := getFrame(ctx, verb.Max.Width, verb.Max.Height, v.command, device, client, verb.NoOpt, verb.DisplayToSurface); err == nil { + if frame, err := getFrame(ctx, verb.Max.Width, verb.Max.Height, v.command, device, client, verb.NoOpt); err == nil { v.rendered = frame } else { v.renderError = err diff --git a/cmd/gapit/video.go b/cmd/gapit/video.go index d77557b158..9b2193d349 100644 --- a/cmd/gapit/video.go +++ b/cmd/gapit/video.go @@ -129,7 +129,7 @@ func (verb *videoVerb) regularVideoSource( for i, e := range eofEvents { i, e := i, e executor(ctx, func(ctx context.Context) error { - if frame, err := getFrame(ctx, verb.Max.Width, verb.Max.Height, e.Command, device, client, verb.NoOpt, verb.DisplayToSurface); err == nil { + if frame, err := getFrame(ctx, verb.Max.Width, verb.Max.Height, e.Command, device, client, verb.NoOpt); err == nil { rendered[i] = flipImg(frame) } else { errors[i] = err @@ -327,13 +327,12 @@ func (verb *videoVerb) encodeVideo(ctx context.Context, filepath string, vidFun return nil } -func getFrame(ctx context.Context, maxWidth, maxHeight int, cmd *path.Command, device *path.Device, client service.Service, noOpt bool, display bool) (*image.NRGBA, error) { +func getFrame(ctx context.Context, maxWidth, maxHeight int, cmd *path.Command, device *path.Device, client service.Service, noOpt bool) (*image.NRGBA, error) { ctx = log.V{"cmd": cmd.Indices}.Bind(ctx) settings := &service.RenderSettings{MaxWidth: uint32(maxWidth), MaxHeight: uint32(maxHeight)} iip, err := client.GetFramebufferAttachment(ctx, &service.ReplaySettings{ Device: device, DisableReplayOptimization: noOpt, - DisplayToSurface: display, }, cmd, api.FramebufferAttachment_Color0, settings, nil) if err != nil { return nil, log.Errf(ctx, err, "GetFramebufferAttachment failed at %v", cmd) From 2ff125d9280c4ebc9ffb2112bd7109a1d92eb29e Mon Sep 17 00:00:00 2001 From: Sean Purcell Date: Wed, 1 Aug 2018 12:48:34 -0400 Subject: [PATCH 11/12] Set timeout on base acquire image to UINT64_MAX We can't set acquire to 0 here, since the image hasn't necessarily done presenting. This is guaranteed to finish because the only way all base swapchain images could still be in use is if the present hasn't finished yet, but there's nothing blocking those presents. --- core/vulkan/vk_virtual_swapchain/cc/base_swapchain.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/vulkan/vk_virtual_swapchain/cc/base_swapchain.cpp b/core/vulkan/vk_virtual_swapchain/cc/base_swapchain.cpp index 25f36b1bdc..7f1913656f 100644 --- a/core/vulkan/vk_virtual_swapchain/cc/base_swapchain.cpp +++ b/core/vulkan/vk_virtual_swapchain/cc/base_swapchain.cpp @@ -180,7 +180,7 @@ VkResult BaseSwapchain::PresentFrom(VkQueue queue, size_t index, // TODO: the error return values here aren't necessarily valid return values // for VkQueueSubmit if ((res = device_functions_->vkAcquireNextImageKHR( - device_, swapchain_, 0, acquire_semaphore_, VK_NULL_HANDLE, + device_, swapchain_, UINT64_MAX, acquire_semaphore_, VK_NULL_HANDLE, &base_index)) != VK_SUCCESS) { return res; } From 8ecfec5c4e4f3e239dc66440b4ca1024af03089e Mon Sep 17 00:00:00 2001 From: Sean Purcell Date: Wed, 1 Aug 2018 12:53:56 -0400 Subject: [PATCH 12/12] Fix missing gofmt --- cmd/gapit/flags.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/gapit/flags.go b/cmd/gapit/flags.go index 3ea2a4556d..0ca4e28c87 100644 --- a/cmd/gapit/flags.go +++ b/cmd/gapit/flags.go @@ -123,7 +123,7 @@ type ( Count int `help:"number of frames after Start to capture: -1 for all frames"` Minimum int `help:"_return error when less than this number of frames is found"` } - NoOpt bool `help:"disables optimization of the replay stream"` + NoOpt bool `help:"disables optimization of the replay stream"` CommandFilterFlags } DumpShadersFlags struct {