Generate GrVkInterface when we make the GrVkGpu.

Also add a GetProc function to the GrVkBackendContext which will be used
to create the GrVkInterface.

This change (and updating clients to use it), will allow us to move GrVkInterface
out of public which is needed to fix vulkan header issues.

Bug: skia:
Change-Id: Id8067943ae27cec8cad29fd31b05f0b8387412d4
Reviewed-on: https://skia-review.googlesource.com/140783
Commit-Queue: Greg Daniel <egdaniel@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
This commit is contained in:
Greg Daniel 2018-07-12 10:02:37 -04:00 committed by Skia Commit-Bot
parent 77c138f2cd
commit c8cd45aaf4
9 changed files with 121 additions and 70 deletions

View File

@ -30,6 +30,12 @@ enum GrVkFeatureFlags {
kSampleRateShading_GrVkFeatureFlag = 0x0004,
};
using GrVkGetProc = std::function<PFN_vkVoidFunction(
const char*, // function name
VkInstance, // instance or VK_NULL_HANDLE
VkDevice // device or VK_NULL_HANDLE
)>;
// The BackendContext contains all of the base Vulkan objects needed by the GrVkGpu. The assumption
// is that the client will set these up and pass them to the GrVkGpu constructor. The VkDevice
// created must support at least one graphics queue, which is passed in as well.
@ -49,6 +55,7 @@ struct SK_API GrVkBackendContext {
uint32_t fFeatures;
sk_sp<const GrVkInterface> fInterface;
sk_sp<GrVkMemoryAllocator> fMemoryAllocator;
GrVkGetProc fGetProc = nullptr;
// This is deprecated and should be set to false. The client is responsible for managing the
// lifetime of the VkInstance and VkDevice objects.

View File

@ -35,6 +35,8 @@ private:
typedef SkRefCnt INHERITED;
public:
// TODO: This matches the definition of GrVkGetProc in GrVkTypes. Once we switch clients to
// using that and make GrVkInterface private, we can remove this GetProc.
using GetProc = std::function<PFN_vkVoidFunction(
const char*, // function name
VkInstance, // instance or VK_NULL_HANDLE

View File

@ -57,20 +57,32 @@ sk_sp<GrGpu> GrVkGpu::Make(const GrVkBackendContext& backendContext,
backendContext.fQueue == VK_NULL_HANDLE) {
return nullptr;
}
if (!backendContext.fInterface ||
!backendContext.fInterface->validate(backendContext.fExtensions)) {
sk_sp<const GrVkInterface> interface;
if (backendContext.fGetProc) {
interface.reset(new GrVkInterface(backendContext.fGetProc,
backendContext.fInstance,
backendContext.fDevice,
backendContext.fExtensions));
} else {
if (!backendContext.fInterface) {
return nullptr;
}
interface = backendContext.fInterface;
}
SkASSERT(interface);
if (!interface->validate(backendContext.fExtensions)) {
return nullptr;
}
return sk_sp<GrGpu>(new GrVkGpu(context, options, backendContext));
return sk_sp<GrGpu>(new GrVkGpu(context, options, backendContext, interface));
}
////////////////////////////////////////////////////////////////////////////////
GrVkGpu::GrVkGpu(GrContext* context, const GrContextOptions& options,
const GrVkBackendContext& backendContext)
const GrVkBackendContext& backendContext, sk_sp<const GrVkInterface> interface)
: INHERITED(context)
, fInterface(std::move(backendContext.fInterface))
, fInterface(std::move(interface))
, fMemoryAllocator(backendContext.fMemoryAllocator)
, fInstance(backendContext.fInstance)
, fDevice(backendContext.fDevice)
@ -82,7 +94,7 @@ GrVkGpu::GrVkGpu(GrContext* context, const GrContextOptions& options,
if (!fMemoryAllocator) {
// We were not given a memory allocator at creation
fMemoryAllocator.reset(new GrVkAMDMemoryAllocator(backendContext.fPhysicalDevice,
fDevice, backendContext.fInterface));
fDevice, fInterface));
}
fCompiler = new SkSL::Compiler();

View File

@ -144,7 +144,8 @@ public:
bool updateBuffer(GrVkBuffer* buffer, const void* src, VkDeviceSize offset, VkDeviceSize size);
private:
GrVkGpu(GrContext*, const GrContextOptions&, const GrVkBackendContext& backendContext);
GrVkGpu(GrContext*, const GrContextOptions&, const GrVkBackendContext& backendContext,
sk_sp<const GrVkInterface>);
void onResetContext(uint32_t resetBits) override {}

View File

@ -15,6 +15,11 @@
#include "vk/GrVkUtil.h"
namespace {
#define ACQUIRE_VK_PROC(name, device) \
f##name = reinterpret_cast<PFN_vk##name>(getProc("vk" #name, nullptr, device)); \
SkASSERT(f##name);
/**
* Implements sk_gpu_test::FenceSync for Vulkan. It creates a single command
* buffer with USAGE_SIMULTANEOUS with no content . On every insertFence request
@ -22,18 +27,30 @@ namespace {
*/
class VkFenceSync : public sk_gpu_test::FenceSync {
public:
VkFenceSync(sk_sp<const GrVkInterface> vk, VkDevice device, VkQueue queue,
VkFenceSync(GrVkGetProc getProc, VkDevice device, VkQueue queue,
uint32_t queueFamilyIndex)
: fVk(std::move(vk))
, fDevice(device)
: fDevice(device)
, fQueue(queue) {
ACQUIRE_VK_PROC(CreateCommandPool, device);
ACQUIRE_VK_PROC(DestroyCommandPool, device);
ACQUIRE_VK_PROC(AllocateCommandBuffers, device);
ACQUIRE_VK_PROC(FreeCommandBuffers, device);
ACQUIRE_VK_PROC(BeginCommandBuffer, device);
ACQUIRE_VK_PROC(EndCommandBuffer, device);
ACQUIRE_VK_PROC(CreateFence, device);
ACQUIRE_VK_PROC(DestroyFence, device);
ACQUIRE_VK_PROC(WaitForFences, device);
ACQUIRE_VK_PROC(QueueSubmit, device);
VkResult result;
SkDEBUGCODE(fUnfinishedSyncs = 0;)
VkCommandPoolCreateInfo createInfo;
createInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
createInfo.pNext = nullptr;
createInfo.flags = 0;
createInfo.queueFamilyIndex = queueFamilyIndex;
GR_VK_CALL_ERRCHECK(fVk, CreateCommandPool(fDevice, &createInfo, nullptr, &fCommandPool));
result = fCreateCommandPool(fDevice, &createInfo, nullptr, &fCommandPool);
SkASSERT(VK_SUCCESS == result);
VkCommandBufferAllocateInfo allocateInfo;
allocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
@ -41,31 +58,39 @@ public:
allocateInfo.commandBufferCount = 1;
allocateInfo.commandPool = fCommandPool;
allocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
GR_VK_CALL_ERRCHECK(fVk, AllocateCommandBuffers(fDevice, &allocateInfo, &fCommandBuffer));
result = fAllocateCommandBuffers(fDevice, &allocateInfo, &fCommandBuffer);
SkASSERT(VK_SUCCESS == result);
VkCommandBufferBeginInfo beginInfo;
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
beginInfo.pNext = nullptr;
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;
beginInfo.pInheritanceInfo = nullptr;
GR_VK_CALL_ERRCHECK(fVk, BeginCommandBuffer(fCommandBuffer, &beginInfo));
GR_VK_CALL_ERRCHECK(fVk, EndCommandBuffer(fCommandBuffer));
result = fBeginCommandBuffer(fCommandBuffer, &beginInfo);
SkASSERT(VK_SUCCESS == result);
result = fEndCommandBuffer(fCommandBuffer);
SkASSERT(VK_SUCCESS == result);
}
~VkFenceSync() override {
SkASSERT(!fUnfinishedSyncs);
// If the above assertion is true then the command buffer should not be in flight.
GR_VK_CALL(fVk, FreeCommandBuffers(fDevice, fCommandPool, 1, &fCommandBuffer));
GR_VK_CALL(fVk, DestroyCommandPool(fDevice, fCommandPool, nullptr));
fFreeCommandBuffers(fDevice, fCommandPool, 1, &fCommandBuffer);
fDestroyCommandPool(fDevice, fCommandPool, nullptr);
}
sk_gpu_test::PlatformFence SK_WARN_UNUSED_RESULT insertFence() const override {
VkResult result;
VkFence fence;
VkFenceCreateInfo info;
info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
info.pNext = nullptr;
info.flags = 0;
GR_VK_CALL_ERRCHECK(fVk, CreateFence(fDevice, &info, nullptr, &fence));
result = fCreateFence(fDevice, &info, nullptr, &fence);
SkASSERT(VK_SUCCESS == result);
VkSubmitInfo submitInfo;
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfo.pNext = nullptr;
@ -76,7 +101,9 @@ public:
submitInfo.pCommandBuffers = &fCommandBuffer;
submitInfo.signalSemaphoreCount = 0;
submitInfo.pSignalSemaphores = nullptr;
GR_VK_CALL_ERRCHECK(fVk, QueueSubmit(fQueue, 1, &submitInfo, fence));
result = fQueueSubmit(fQueue, 1, &submitInfo, fence);
SkASSERT(VK_SUCCESS == result);
SkDEBUGCODE(++fUnfinishedSyncs;)
return (sk_gpu_test::PlatformFence)fence;
}
@ -84,22 +111,33 @@ public:
bool waitFence(sk_gpu_test::PlatformFence opaqueFence) const override {
VkFence fence = (VkFence)opaqueFence;
static constexpr uint64_t kForever = ~((uint64_t)0);
auto result = GR_VK_CALL(fVk, WaitForFences(fDevice, 1, &fence, true, kForever));
auto result = fWaitForFences(fDevice, 1, &fence, true, kForever);
return result != VK_TIMEOUT;
}
void deleteFence(sk_gpu_test::PlatformFence opaqueFence) const override {
VkFence fence = (VkFence)opaqueFence;
GR_VK_CALL(fVk, DestroyFence(fDevice, fence, nullptr));
fDestroyFence(fDevice, fence, nullptr);
SkDEBUGCODE(--fUnfinishedSyncs;)
}
private:
sk_sp<const GrVkInterface> fVk;
VkDevice fDevice;
VkQueue fQueue;
VkCommandPool fCommandPool;
VkCommandBuffer fCommandBuffer;
PFN_vkCreateCommandPool fCreateCommandPool = nullptr;
PFN_vkDestroyCommandPool fDestroyCommandPool = nullptr;
PFN_vkAllocateCommandBuffers fAllocateCommandBuffers = nullptr;
PFN_vkFreeCommandBuffers fFreeCommandBuffers = nullptr;
PFN_vkBeginCommandBuffer fBeginCommandBuffer = nullptr;
PFN_vkEndCommandBuffer fEndCommandBuffer = nullptr;
PFN_vkCreateFence fCreateFence = nullptr;
PFN_vkDestroyFence fDestroyFence = nullptr;
PFN_vkWaitForFences fWaitForFences = nullptr;
PFN_vkQueueSubmit fQueueSubmit = nullptr;
SkDEBUGCODE(mutable int fUnfinishedSyncs;)
typedef sk_gpu_test::FenceSync INHERITED;
};
@ -146,19 +184,30 @@ public:
}
protected:
#define ACQUIRE_VK_PROC_LOCAL(name, inst) \
PFN_vk##name grVk##name = \
reinterpret_cast<PFN_vk##name>(fVk.fGetProc("vk" #name, inst, nullptr)); \
if (grVk##name == nullptr) { \
SkDebugf("Function ptr for vk%s could not be acquired\n", #name); \
return; \
}
void teardown() override {
INHERITED::teardown();
fVk.fMemoryAllocator.reset();
if (fOwnsContext) {
GR_VK_CALL(this->vk(), DeviceWaitIdle(fVk.fDevice));
GR_VK_CALL(this->vk(), DestroyDevice(fVk.fDevice, nullptr));
ACQUIRE_VK_PROC_LOCAL(DeviceWaitIdle, fVk.fInstance);
ACQUIRE_VK_PROC_LOCAL(DestroyDevice, fVk.fInstance);
ACQUIRE_VK_PROC_LOCAL(DestroyInstance, fVk.fInstance);
grVkDeviceWaitIdle(fVk.fDevice);
grVkDestroyDevice(fVk.fDevice, nullptr);
#ifdef SK_ENABLE_VK_LAYERS
if (fDebugCallback != VK_NULL_HANDLE) {
GR_VK_CALL(this->vk(), DestroyDebugReportCallbackEXT(fVk.fInstance, fDebugCallback,
nullptr));
ACQUIRE_VK_PROC_LOCAL(DestroyDebugReportCallbackEXT, fVk.fInstance);
grVkDestroyDebugReportCallbackEXT(fVk.fInstance, fDebugCallback, nullptr);
}
#endif
GR_VK_CALL(this->vk(), DestroyInstance(fVk.fInstance, nullptr));
grVkDestroyInstance(fVk.fInstance, nullptr);
}
}
@ -166,7 +215,7 @@ private:
VkTestContextImpl(const GrVkBackendContext& backendContext, bool ownsContext,
VkDebugReportCallbackEXT debugCallback)
: VkTestContext(backendContext, ownsContext, debugCallback) {
fFenceSync.reset(new VkFenceSync(fVk.fInterface, fVk.fDevice, fVk.fQueue,
fFenceSync.reset(new VkFenceSync(fVk.fGetProc, fVk.fDevice, fVk.fQueue,
fVk.fGraphicsQueueIndex));
}

View File

@ -23,8 +23,6 @@ public:
return fVk;
}
const GrVkInterface* vk() const { return fVk.fInterface.get(); }
protected:
VkTestContext(const GrVkBackendContext& vk, bool ownsContext,
VkDebugReportCallbackEXT debugCallback)

View File

@ -138,8 +138,8 @@ bool CreateVkBackendContext(const GrVkInterface::GetInstanceProc& getInstancePro
VkDebugReportCallbackEXT* debugCallback,
uint32_t* presentQueueIndexPtr,
CanPresentFn canPresent) {
auto getProc = [&getInstanceProc, &getDeviceProc](const char* proc_name,
VkInstance instance, VkDevice device) {
auto getProc = [getInstanceProc, getDeviceProc](const char* proc_name,
VkInstance instance, VkDevice device) {
if (device != VK_NULL_HANDLE) {
return getDeviceProc(device, proc_name);
}
@ -406,16 +406,6 @@ bool CreateVkBackendContext(const GrVkInterface::GetInstanceProc& getInstancePro
return false;
}
auto interface =
sk_make_sp<GrVkInterface>(getProc, inst, device, extensionFlags);
if (!interface->validate(extensionFlags)) {
SkDebugf("Vulkan interface validation failed\n");
grVkDeviceWaitIdle(device);
grVkDestroyDevice(device, nullptr);
destroy_instance(getProc, inst, debugCallback, hasDebugExtension);
return false;
}
VkQueue queue;
grVkGetDeviceQueue(device, graphicsQueueIndex, 0, &queue);
@ -427,7 +417,8 @@ bool CreateVkBackendContext(const GrVkInterface::GetInstanceProc& getInstancePro
ctx->fMinAPIVersion = kGrVkMinimumVersion;
ctx->fExtensions = extensionFlags;
ctx->fFeatures = featureFlags;
ctx->fInterface.reset(interface.release());
ctx->fInterface = nullptr;
ctx->fGetProc = getProc;
ctx->fOwnsInstanceAndDevice = false;
return true;

View File

@ -66,7 +66,8 @@ void VulkanWindowContext::initializeContext() {
fDevice = backendContext.fDevice;
fGraphicsQueueIndex = backendContext.fGraphicsQueueIndex;
fGraphicsQueue = backendContext.fQueue;
fInterface = backendContext.fInterface;
fInterface.reset(new GrVkInterface(backendContext.fGetProc, fInstance, fDevice,
backendContext.fExtensions));
GET_PROC(DestroyInstance);
GET_PROC(DestroySurfaceKHR);

View File

@ -70,42 +70,32 @@ private:
VkDevice fDevice = VK_NULL_HANDLE;
VkDebugReportCallbackEXT fDebugCallback = VK_NULL_HANDLE;
// simple wrapper class that exists only to initialize a pointer to NULL
template <typename FNPTR_TYPE> class VkPtr {
public:
VkPtr() : fPtr(NULL) {}
VkPtr operator=(FNPTR_TYPE ptr) { fPtr = ptr; return *this; }
operator FNPTR_TYPE() const { return fPtr; }
private:
FNPTR_TYPE fPtr;
};
// Create functions
CreateVkSurfaceFn fCreateVkSurfaceFn;
CanPresentFn fCanPresentFn;
// Vulkan GetProcAddr functions
VkPtr<PFN_vkGetInstanceProcAddr> fGetInstanceProcAddr;
VkPtr<PFN_vkGetDeviceProcAddr> fGetDeviceProcAddr;
PFN_vkGetInstanceProcAddr fGetInstanceProcAddr = nullptr;
PFN_vkGetDeviceProcAddr fGetDeviceProcAddr = nullptr;
// WSI interface functions
VkPtr<PFN_vkDestroySurfaceKHR> fDestroySurfaceKHR;
VkPtr<PFN_vkGetPhysicalDeviceSurfaceSupportKHR> fGetPhysicalDeviceSurfaceSupportKHR;
VkPtr<PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR> fGetPhysicalDeviceSurfaceCapabilitiesKHR;
VkPtr<PFN_vkGetPhysicalDeviceSurfaceFormatsKHR> fGetPhysicalDeviceSurfaceFormatsKHR;
VkPtr<PFN_vkGetPhysicalDeviceSurfacePresentModesKHR> fGetPhysicalDeviceSurfacePresentModesKHR;
PFN_vkDestroySurfaceKHR fDestroySurfaceKHR = nullptr;
PFN_vkGetPhysicalDeviceSurfaceSupportKHR fGetPhysicalDeviceSurfaceSupportKHR = nullptr;
PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR fGetPhysicalDeviceSurfaceCapabilitiesKHR =nullptr;
PFN_vkGetPhysicalDeviceSurfaceFormatsKHR fGetPhysicalDeviceSurfaceFormatsKHR = nullptr;
PFN_vkGetPhysicalDeviceSurfacePresentModesKHR fGetPhysicalDeviceSurfacePresentModesKHR =nullptr;
VkPtr<PFN_vkCreateSwapchainKHR> fCreateSwapchainKHR;
VkPtr<PFN_vkDestroySwapchainKHR> fDestroySwapchainKHR;
VkPtr<PFN_vkGetSwapchainImagesKHR> fGetSwapchainImagesKHR;
VkPtr<PFN_vkAcquireNextImageKHR> fAcquireNextImageKHR;
VkPtr<PFN_vkQueuePresentKHR> fQueuePresentKHR;
PFN_vkCreateSwapchainKHR fCreateSwapchainKHR = nullptr;
PFN_vkDestroySwapchainKHR fDestroySwapchainKHR = nullptr;
PFN_vkGetSwapchainImagesKHR fGetSwapchainImagesKHR = nullptr;
PFN_vkAcquireNextImageKHR fAcquireNextImageKHR = nullptr;
PFN_vkQueuePresentKHR fQueuePresentKHR = nullptr;
VkPtr<PFN_vkDestroyInstance> fDestroyInstance;
VkPtr<PFN_vkDeviceWaitIdle> fDeviceWaitIdle;
VkPtr<PFN_vkQueueWaitIdle> fQueueWaitIdle;
VkPtr<PFN_vkDestroyDevice> fDestroyDevice;
VkPtr<PFN_vkGetDeviceQueue> fGetDeviceQueue;
PFN_vkDestroyInstance fDestroyInstance = nullptr;
PFN_vkDeviceWaitIdle fDeviceWaitIdle = nullptr;
PFN_vkQueueWaitIdle fQueueWaitIdle = nullptr;
PFN_vkDestroyDevice fDestroyDevice = nullptr;
PFN_vkGetDeviceQueue fGetDeviceQueue = nullptr;
sk_sp<const GrVkInterface> fInterface;