Home | History | Annotate | Download | only in vk
      1 /*
      2  * Copyright 2016 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "VkTestContext.h"
      9 
     10 #ifdef SK_VULKAN
     11 
     12 #include "GrContext.h"
     13 #include "VkTestUtils.h"
     14 #include "vk/GrVkExtensions.h"
     15 
     16 namespace {
     17 
     18 #define ACQUIRE_VK_PROC(name, device)                                               \
     19     f##name = reinterpret_cast<PFN_vk##name>(getProc("vk" #name, nullptr, device)); \
     20     SkASSERT(f##name)
     21 
     22 /**
     23  * Implements sk_gpu_test::FenceSync for Vulkan. It creates a single command
     24  * buffer with USAGE_SIMULTANEOUS with no content . On every insertFence request
     25  * it submits the command buffer with a new fence.
     26  */
     27 class VkFenceSync : public sk_gpu_test::FenceSync {
     28 public:
     29     VkFenceSync(GrVkGetProc getProc, VkDevice device, VkQueue queue,
     30                 uint32_t queueFamilyIndex)
     31             : fDevice(device)
     32             , fQueue(queue) {
     33         ACQUIRE_VK_PROC(CreateCommandPool, device);
     34         ACQUIRE_VK_PROC(DestroyCommandPool, device);
     35         ACQUIRE_VK_PROC(AllocateCommandBuffers, device);
     36         ACQUIRE_VK_PROC(FreeCommandBuffers, device);
     37         ACQUIRE_VK_PROC(BeginCommandBuffer, device);
     38         ACQUIRE_VK_PROC(EndCommandBuffer, device);
     39         ACQUIRE_VK_PROC(CreateFence, device);
     40         ACQUIRE_VK_PROC(DestroyFence, device);
     41         ACQUIRE_VK_PROC(WaitForFences, device);
     42         ACQUIRE_VK_PROC(QueueSubmit, device);
     43 
     44         VkResult result;
     45         SkDEBUGCODE(fUnfinishedSyncs = 0;)
     46         VkCommandPoolCreateInfo createInfo;
     47         createInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
     48         createInfo.pNext = nullptr;
     49         createInfo.flags = 0;
     50         createInfo.queueFamilyIndex = queueFamilyIndex;
     51         result = fCreateCommandPool(fDevice, &createInfo, nullptr, &fCommandPool);
     52         SkASSERT(VK_SUCCESS == result);
     53 
     54         VkCommandBufferAllocateInfo allocateInfo;
     55         allocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
     56         allocateInfo.pNext = nullptr;
     57         allocateInfo.commandBufferCount = 1;
     58         allocateInfo.commandPool = fCommandPool;
     59         allocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
     60         result = fAllocateCommandBuffers(fDevice, &allocateInfo, &fCommandBuffer);
     61         SkASSERT(VK_SUCCESS == result);
     62 
     63         VkCommandBufferBeginInfo beginInfo;
     64         beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
     65         beginInfo.pNext = nullptr;
     66         beginInfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;
     67         beginInfo.pInheritanceInfo = nullptr;
     68         result = fBeginCommandBuffer(fCommandBuffer, &beginInfo);
     69         SkASSERT(VK_SUCCESS == result);
     70         result = fEndCommandBuffer(fCommandBuffer);
     71         SkASSERT(VK_SUCCESS == result);
     72 
     73     }
     74 
     75     ~VkFenceSync() override {
     76         SkASSERT(!fUnfinishedSyncs);
     77         // If the above assertion is true then the command buffer should not be in flight.
     78         fFreeCommandBuffers(fDevice, fCommandPool, 1, &fCommandBuffer);
     79         fDestroyCommandPool(fDevice, fCommandPool, nullptr);
     80     }
     81 
     82     sk_gpu_test::PlatformFence SK_WARN_UNUSED_RESULT insertFence() const override {
     83         VkResult result;
     84 
     85         VkFence fence;
     86         VkFenceCreateInfo info;
     87         info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
     88         info.pNext = nullptr;
     89         info.flags = 0;
     90         result = fCreateFence(fDevice, &info, nullptr, &fence);
     91         SkASSERT(VK_SUCCESS == result);
     92 
     93         VkSubmitInfo submitInfo;
     94         submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
     95         submitInfo.pNext = nullptr;
     96         submitInfo.waitSemaphoreCount = 0;
     97         submitInfo.pWaitSemaphores = nullptr;
     98         submitInfo.pWaitDstStageMask = nullptr;
     99         submitInfo.commandBufferCount = 1;
    100         submitInfo.pCommandBuffers = &fCommandBuffer;
    101         submitInfo.signalSemaphoreCount = 0;
    102         submitInfo.pSignalSemaphores = nullptr;
    103         result = fQueueSubmit(fQueue, 1, &submitInfo, fence);
    104         SkASSERT(VK_SUCCESS == result);
    105 
    106         SkDEBUGCODE(++fUnfinishedSyncs;)
    107         return (sk_gpu_test::PlatformFence)fence;
    108     }
    109 
    110     bool waitFence(sk_gpu_test::PlatformFence opaqueFence) const override {
    111         VkFence fence = (VkFence)opaqueFence;
    112         static constexpr uint64_t kForever = ~((uint64_t)0);
    113         auto result = fWaitForFences(fDevice, 1, &fence, true, kForever);
    114         return result != VK_TIMEOUT;
    115     }
    116 
    117     void deleteFence(sk_gpu_test::PlatformFence opaqueFence) const override {
    118         VkFence fence = (VkFence)opaqueFence;
    119         fDestroyFence(fDevice, fence, nullptr);
    120         SkDEBUGCODE(--fUnfinishedSyncs;)
    121     }
    122 
    123 private:
    124     VkDevice                    fDevice;
    125     VkQueue                     fQueue;
    126     VkCommandPool               fCommandPool;
    127     VkCommandBuffer             fCommandBuffer;
    128 
    129     PFN_vkCreateCommandPool fCreateCommandPool = nullptr;
    130     PFN_vkDestroyCommandPool fDestroyCommandPool = nullptr;
    131     PFN_vkAllocateCommandBuffers fAllocateCommandBuffers = nullptr;
    132     PFN_vkFreeCommandBuffers fFreeCommandBuffers = nullptr;
    133     PFN_vkBeginCommandBuffer fBeginCommandBuffer = nullptr;
    134     PFN_vkEndCommandBuffer fEndCommandBuffer = nullptr;
    135     PFN_vkCreateFence fCreateFence = nullptr;
    136     PFN_vkDestroyFence fDestroyFence = nullptr;
    137     PFN_vkWaitForFences fWaitForFences = nullptr;
    138     PFN_vkQueueSubmit fQueueSubmit = nullptr;
    139 
    140     SkDEBUGCODE(mutable int     fUnfinishedSyncs;)
    141     typedef sk_gpu_test::FenceSync INHERITED;
    142 };
    143 
    144 GR_STATIC_ASSERT(sizeof(VkFence) <= sizeof(sk_gpu_test::PlatformFence));
    145 
    146 // TODO: Implement swap buffers and finish
    147 class VkTestContextImpl : public sk_gpu_test::VkTestContext {
    148 public:
    149     static VkTestContext* Create(VkTestContext* sharedContext) {
    150         GrVkBackendContext backendContext;
    151         GrVkExtensions* extensions;
    152         VkPhysicalDeviceFeatures2* features;
    153         bool ownsContext = true;
    154         VkDebugReportCallbackEXT debugCallback = VK_NULL_HANDLE;
    155         PFN_vkDestroyDebugReportCallbackEXT destroyCallback = nullptr;
    156         if (sharedContext) {
    157             backendContext = sharedContext->getVkBackendContext();
    158             extensions = const_cast<GrVkExtensions*>(sharedContext->getVkExtensions());
    159             features = const_cast<VkPhysicalDeviceFeatures2*>(sharedContext->getVkFeatures());
    160             // We always delete the parent context last so make sure the child does not think they
    161             // own the vulkan context.
    162             ownsContext = false;
    163         } else {
    164             PFN_vkGetInstanceProcAddr instProc;
    165             PFN_vkGetDeviceProcAddr devProc;
    166             if (!sk_gpu_test::LoadVkLibraryAndGetProcAddrFuncs(&instProc, &devProc)) {
    167                 return nullptr;
    168             }
    169             auto getProc = [instProc, devProc](const char* proc_name,
    170                                                VkInstance instance, VkDevice device) {
    171                 if (device != VK_NULL_HANDLE) {
    172                     return devProc(device, proc_name);
    173                 }
    174                 return instProc(instance, proc_name);
    175             };
    176             extensions = new GrVkExtensions();
    177             features = new VkPhysicalDeviceFeatures2;
    178             memset(features, 0, sizeof(VkPhysicalDeviceFeatures2));
    179             if (!sk_gpu_test::CreateVkBackendContext(getProc, &backendContext, extensions,
    180                                                      features, &debugCallback)) {
    181                 sk_gpu_test::FreeVulkanFeaturesStructs(features);
    182                 delete features;
    183                 delete extensions;
    184                 return nullptr;
    185             }
    186             if (debugCallback != VK_NULL_HANDLE) {
    187                 destroyCallback = (PFN_vkDestroyDebugReportCallbackEXT) instProc(
    188                         backendContext.fInstance, "vkDestroyDebugReportCallbackEXT");
    189             }
    190         }
    191         return new VkTestContextImpl(backendContext, extensions, features, ownsContext,
    192                                      debugCallback, destroyCallback);
    193     }
    194 
    195     ~VkTestContextImpl() override { this->teardown(); }
    196 
    197     void testAbandon() override {}
    198 
    199     // There is really nothing to here since we don't own any unqueued command buffers here.
    200     void submit() override {}
    201 
    202     void finish() override {}
    203 
    204     sk_sp<GrContext> makeGrContext(const GrContextOptions& options) override {
    205         return GrContext::MakeVulkan(fVk, options);
    206     }
    207 
    208 protected:
    209 #define ACQUIRE_VK_PROC_LOCAL(name, inst)                                            \
    210     PFN_vk##name grVk##name =                                                        \
    211             reinterpret_cast<PFN_vk##name>(fVk.fGetProc("vk" #name, inst, nullptr)); \
    212     do {                                                                             \
    213         if (grVk##name == nullptr) {                                                 \
    214             SkDebugf("Function ptr for vk%s could not be acquired\n", #name);        \
    215             return;                                                                  \
    216         }                                                                            \
    217     } while (0)
    218 
    219     void teardown() override {
    220         INHERITED::teardown();
    221         fVk.fMemoryAllocator.reset();
    222         if (fOwnsContext) {
    223             ACQUIRE_VK_PROC_LOCAL(DeviceWaitIdle, fVk.fInstance);
    224             ACQUIRE_VK_PROC_LOCAL(DestroyDevice, fVk.fInstance);
    225             ACQUIRE_VK_PROC_LOCAL(DestroyInstance, fVk.fInstance);
    226             grVkDeviceWaitIdle(fVk.fDevice);
    227             grVkDestroyDevice(fVk.fDevice, nullptr);
    228 #ifdef SK_ENABLE_VK_LAYERS
    229             if (fDebugCallback != VK_NULL_HANDLE) {
    230                 fDestroyDebugReportCallbackEXT(fVk.fInstance, fDebugCallback, nullptr);
    231             }
    232 #endif
    233             grVkDestroyInstance(fVk.fInstance, nullptr);
    234             delete fExtensions;
    235 
    236             sk_gpu_test::FreeVulkanFeaturesStructs(fFeatures);
    237             delete fFeatures;
    238         }
    239     }
    240 
    241 private:
    242     VkTestContextImpl(const GrVkBackendContext& backendContext, const GrVkExtensions* extensions,
    243                       VkPhysicalDeviceFeatures2* features, bool ownsContext,
    244                       VkDebugReportCallbackEXT debugCallback,
    245                       PFN_vkDestroyDebugReportCallbackEXT destroyCallback)
    246             : VkTestContext(backendContext, extensions, features, ownsContext, debugCallback,
    247                             destroyCallback) {
    248         fFenceSync.reset(new VkFenceSync(fVk.fGetProc, fVk.fDevice, fVk.fQueue,
    249                                          fVk.fGraphicsQueueIndex));
    250     }
    251 
    252     void onPlatformMakeCurrent() const override {}
    253     std::function<void()> onPlatformGetAutoContextRestore() const override  { return nullptr; }
    254     void onPlatformSwapBuffers() const override {}
    255 
    256     typedef sk_gpu_test::VkTestContext INHERITED;
    257 };
    258 }  // anonymous namespace
    259 
    260 namespace sk_gpu_test {
    261 VkTestContext* CreatePlatformVkTestContext(VkTestContext* sharedContext) {
    262     return VkTestContextImpl::Create(sharedContext);
    263 }
    264 }  // namespace sk_gpu_test
    265 
    266 #endif
    267