diff options
-rw-r--r-- | external/skia/README | 6 | ||||
-rw-r--r-- | external/skia/UnpackedTarball_skia.mk | 8 | ||||
-rw-r--r-- | external/skia/share-grcontext.patch.1 | 499 | ||||
-rw-r--r-- | vcl/Library_vcl.mk | 3 | ||||
-rw-r--r-- | vcl/inc/skia/gdiimpl.hxx | 4 | ||||
-rw-r--r-- | vcl/inc/skia/vulkan.hxx | 29 | ||||
-rw-r--r-- | vcl/skia/README | 16 | ||||
-rw-r--r-- | vcl/skia/gdiimpl.cxx | 59 | ||||
-rw-r--r-- | vcl/skia/vulkan.cxx | 39 | ||||
-rw-r--r-- | vcl/skia/win/gdiimpl.cxx | 22 | ||||
-rw-r--r-- | vcl/skia/x11/gdiimpl.cxx | 32 |
11 files changed, 601 insertions, 116 deletions
diff --git a/external/skia/README b/external/skia/README index 767f12e91936..95be1561d4fb 100644 --- a/external/skia/README +++ b/external/skia/README @@ -17,3 +17,9 @@ tar cvJf skia-mXX-$id.tar.xz skia (where XX refers to the branch version) And review differences for BUILD.gn and relevant files in gn/ . + + +GrContext sharing +================= + +For details about the share-grcontext patch, see vcl/skia/README. diff --git a/external/skia/UnpackedTarball_skia.mk b/external/skia/UnpackedTarball_skia.mk index e9905f5abfa7..c3988042a012 100644 --- a/external/skia/UnpackedTarball_skia.mk +++ b/external/skia/UnpackedTarball_skia.mk @@ -12,7 +12,13 @@ $(eval $(call gb_UnpackedTarball_UnpackedTarball,skia)) $(eval $(call gb_UnpackedTarball_set_tarball,skia,$(SKIA_TARBALL))) # TODO -skia_patches := lerp.patch fix-pch.patch fix-ddi.patch make-api-visible.patch.1 fix-shader-locale.patch.1 +skia_patches := \ + lerp.patch \ + fix-pch.patch \ + fix-ddi.patch \ + make-api-visible.patch.1 \ + fix-shader-locale.patch.1 \ + share-grcontext.patch.1 $(eval $(call gb_UnpackedTarball_set_patchlevel,skia,1)) diff --git a/external/skia/share-grcontext.patch.1 b/external/skia/share-grcontext.patch.1 new file mode 100644 index 000000000000..0492bd948240 --- /dev/null +++ b/external/skia/share-grcontext.patch.1 @@ -0,0 +1,499 @@ +diff --git a/tools/sk_app/VulkanWindowContext.cpp b/tools/sk_app/VulkanWindowContext.cpp +index 793c88c158..21164cac67 100644 +--- a/tools/sk_app/VulkanWindowContext.cpp ++++ b/tools/sk_app/VulkanWindowContext.cpp +@@ -1,4 +1,3 @@ +- + /* + * Copyright 2015 Google Inc. + * +@@ -24,8 +23,10 @@ + #undef CreateSemaphore + #endif + +-#define GET_PROC(F) f ## F = (PFN_vk ## F) fGetInstanceProcAddr(fInstance, "vk" #F) +-#define GET_DEV_PROC(F) f ## F = (PFN_vk ## F) fGetDeviceProcAddr(fDevice, "vk" #F) ++#define GET_PROC(F) f ## F = (PFN_vk ## F) fGetInstanceProcAddr(fShared->fInstance, "vk" #F) ++#define GET_DEV_PROC(F) f ## F = (PFN_vk ## F) fGetDeviceProcAddr(fShared->fDevice, "vk" #F) ++#define GET_PROC_GLOBAL(F) fGlobalShared->f ## F = (PFN_vk ## F) fGetInstanceProcAddr(fGlobalShared->fInstance, "vk" #F) ++#define GET_DEV_PROC_GLOBAL(F) fGlobalShared->f ## F = (PFN_vk ## F) fGetDeviceProcAddr(fGlobalShared->fDevice, "vk" #F) + + namespace sk_app { + +@@ -49,6 +50,14 @@ VulkanWindowContext::VulkanWindowContext(const DisplayParams& params, + } + + void VulkanWindowContext::initializeContext() { ++ fShared = fGlobalShared; ++ if( !fShared ) ++ { ++ // TODO do we need a mutex? ++ ++ fGlobalShared = sk_make_sp<Shared>(); ++ Shared* d = fGlobalShared.get(); // shorter variable name ++ + // any config code here (particularly for msaa)? + + PFN_vkGetInstanceProcAddr getInstanceProc = fGetInstanceProcAddr; +@@ -62,24 +71,25 @@ void VulkanWindowContext::initializeContext() { + }; + GrVkBackendContext backendContext; + GrVkExtensions extensions; +- VkPhysicalDeviceFeatures2 features; +- if (!sk_gpu_test::CreateVkBackendContext(getProc, &backendContext, &extensions, &features, +- &fDebugCallback, &fPresentQueueIndex, fCanPresentFn)) { +- sk_gpu_test::FreeVulkanFeaturesStructs(&features); ++ if (!sk_gpu_test::CreateVkBackendContext(getProc, &backendContext, &extensions, &d->features, ++ &d->fDebugCallback, &d->fPresentQueueIndex, fCanPresentFn)) { ++ sk_gpu_test::FreeVulkanFeaturesStructs(&d->features); ++ fGlobalShared.reset(); + return; + } + + if (!extensions.hasExtension(VK_KHR_SURFACE_EXTENSION_NAME, 25) || + !extensions.hasExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME, 68)) { +- sk_gpu_test::FreeVulkanFeaturesStructs(&features); ++ sk_gpu_test::FreeVulkanFeaturesStructs(&d->features); ++ fGlobalShared.reset(); + return; + } + +- fInstance = backendContext.fInstance; +- fPhysicalDevice = backendContext.fPhysicalDevice; +- fDevice = backendContext.fDevice; +- fGraphicsQueueIndex = backendContext.fGraphicsQueueIndex; +- fGraphicsQueue = backendContext.fQueue; ++ d->fInstance = backendContext.fInstance; ++ d->fPhysicalDevice = backendContext.fPhysicalDevice; ++ d->fDevice = backendContext.fDevice; ++ d->fGraphicsQueueIndex = backendContext.fGraphicsQueueIndex; ++ d->fGraphicsQueue = backendContext.fQueue; + + PFN_vkGetPhysicalDeviceProperties localGetPhysicalDeviceProperties = + reinterpret_cast<PFN_vkGetPhysicalDeviceProperties>( +@@ -87,21 +97,31 @@ void VulkanWindowContext::initializeContext() { + backendContext.fInstance, + VK_NULL_HANDLE)); + if (!localGetPhysicalDeviceProperties) { +- sk_gpu_test::FreeVulkanFeaturesStructs(&features); ++ sk_gpu_test::FreeVulkanFeaturesStructs(&d->features); ++ fGlobalShared.reset(); + return; + } + VkPhysicalDeviceProperties physDeviceProperties; + localGetPhysicalDeviceProperties(backendContext.fPhysicalDevice, &physDeviceProperties); + uint32_t physDevVersion = physDeviceProperties.apiVersion; + +- fInterface.reset(new GrVkInterface(backendContext.fGetProc, fInstance, fDevice, ++ d->fInterface.reset(new GrVkInterface(backendContext.fGetProc, d->fInstance, d->fDevice, + backendContext.fInstanceVersion, physDevVersion, + &extensions)); + +- GET_PROC(DestroyInstance); +- if (fDebugCallback != VK_NULL_HANDLE) { +- GET_PROC(DestroyDebugReportCallbackEXT); ++ d->fContext = GrContext::MakeVulkan(backendContext, fDisplayParams.fGrContextOptions); ++ ++ GET_PROC_GLOBAL(DestroyInstance); ++ GET_DEV_PROC_GLOBAL(DestroyDevice); ++ if (fGlobalShared->fDebugCallback != VK_NULL_HANDLE) { ++ GET_PROC_GLOBAL(DestroyDebugReportCallbackEXT); + } ++ ++ fShared = fGlobalShared; ++ } // if( !fShared ) ++ ++ fContext = fShared->fContext; ++ + GET_PROC(DestroySurfaceKHR); + GET_PROC(GetPhysicalDeviceSurfaceSupportKHR); + GET_PROC(GetPhysicalDeviceSurfaceCapabilitiesKHR); +@@ -109,7 +129,6 @@ void VulkanWindowContext::initializeContext() { + GET_PROC(GetPhysicalDeviceSurfacePresentModesKHR); + GET_DEV_PROC(DeviceWaitIdle); + GET_DEV_PROC(QueueWaitIdle); +- GET_DEV_PROC(DestroyDevice); + GET_DEV_PROC(CreateSwapchainKHR); + GET_DEV_PROC(DestroySwapchainKHR); + GET_DEV_PROC(GetSwapchainImagesKHR); +@@ -117,46 +136,40 @@ void VulkanWindowContext::initializeContext() { + GET_DEV_PROC(QueuePresentKHR); + GET_DEV_PROC(GetDeviceQueue); + +- fContext = GrContext::MakeVulkan(backendContext, fDisplayParams.fGrContextOptions); +- +- fSurface = fCreateVkSurfaceFn(fInstance); ++ fSurface = fCreateVkSurfaceFn(fShared->fInstance); + if (VK_NULL_HANDLE == fSurface) { + this->destroyContext(); +- sk_gpu_test::FreeVulkanFeaturesStructs(&features); + return; + } + + VkBool32 supported; +- VkResult res = fGetPhysicalDeviceSurfaceSupportKHR(fPhysicalDevice, fPresentQueueIndex, ++ VkResult res = fGetPhysicalDeviceSurfaceSupportKHR(fShared->fPhysicalDevice, fShared->fPresentQueueIndex, + fSurface, &supported); + if (VK_SUCCESS != res) { + this->destroyContext(); +- sk_gpu_test::FreeVulkanFeaturesStructs(&features); + return; + } + + if (!this->createSwapchain(-1, -1, fDisplayParams)) { + this->destroyContext(); +- sk_gpu_test::FreeVulkanFeaturesStructs(&features); + return; + } + + // create presentQueue +- fGetDeviceQueue(fDevice, fPresentQueueIndex, 0, &fPresentQueue); +- sk_gpu_test::FreeVulkanFeaturesStructs(&features); ++ fGetDeviceQueue(fShared->fDevice, fShared->fPresentQueueIndex, 0, &fPresentQueue); + } + + bool VulkanWindowContext::createSwapchain(int width, int height, + const DisplayParams& params) { + // check for capabilities + VkSurfaceCapabilitiesKHR caps; +- VkResult res = fGetPhysicalDeviceSurfaceCapabilitiesKHR(fPhysicalDevice, fSurface, &caps); ++ VkResult res = fGetPhysicalDeviceSurfaceCapabilitiesKHR(fShared->fPhysicalDevice, fSurface, &caps); + if (VK_SUCCESS != res) { + return false; + } + + uint32_t surfaceFormatCount; +- res = fGetPhysicalDeviceSurfaceFormatsKHR(fPhysicalDevice, fSurface, &surfaceFormatCount, ++ res = fGetPhysicalDeviceSurfaceFormatsKHR(fShared->fPhysicalDevice, fSurface, &surfaceFormatCount, + nullptr); + if (VK_SUCCESS != res) { + return false; +@@ -164,14 +177,14 @@ bool VulkanWindowContext::createSwapchain(int width, int height, + + SkAutoMalloc surfaceFormatAlloc(surfaceFormatCount * sizeof(VkSurfaceFormatKHR)); + VkSurfaceFormatKHR* surfaceFormats = (VkSurfaceFormatKHR*)surfaceFormatAlloc.get(); +- res = fGetPhysicalDeviceSurfaceFormatsKHR(fPhysicalDevice, fSurface, &surfaceFormatCount, ++ res = fGetPhysicalDeviceSurfaceFormatsKHR(fShared->fPhysicalDevice, fSurface, &surfaceFormatCount, + surfaceFormats); + if (VK_SUCCESS != res) { + return false; + } + + uint32_t presentModeCount; +- res = fGetPhysicalDeviceSurfacePresentModesKHR(fPhysicalDevice, fSurface, &presentModeCount, ++ res = fGetPhysicalDeviceSurfacePresentModesKHR(fShared->fPhysicalDevice, fSurface, &presentModeCount, + nullptr); + if (VK_SUCCESS != res) { + return false; +@@ -179,7 +192,7 @@ bool VulkanWindowContext::createSwapchain(int width, int height, + + SkAutoMalloc presentModeAlloc(presentModeCount * sizeof(VkPresentModeKHR)); + VkPresentModeKHR* presentModes = (VkPresentModeKHR*)presentModeAlloc.get(); +- res = fGetPhysicalDeviceSurfacePresentModesKHR(fPhysicalDevice, fSurface, &presentModeCount, ++ res = fGetPhysicalDeviceSurfacePresentModesKHR(fShared->fPhysicalDevice, fSurface, &presentModeCount, + presentModes); + if (VK_SUCCESS != res) { + return false; +@@ -286,8 +299,8 @@ bool VulkanWindowContext::createSwapchain(int width, int height, + swapchainCreateInfo.imageArrayLayers = 1; + swapchainCreateInfo.imageUsage = usageFlags; + +- uint32_t queueFamilies[] = { fGraphicsQueueIndex, fPresentQueueIndex }; +- if (fGraphicsQueueIndex != fPresentQueueIndex) { ++ uint32_t queueFamilies[] = { fShared->fGraphicsQueueIndex, fShared->fPresentQueueIndex }; ++ if (fShared->fGraphicsQueueIndex != fShared->fPresentQueueIndex) { + swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT; + swapchainCreateInfo.queueFamilyIndexCount = 2; + swapchainCreateInfo.pQueueFamilyIndices = queueFamilies; +@@ -303,18 +316,18 @@ bool VulkanWindowContext::createSwapchain(int width, int height, + swapchainCreateInfo.clipped = true; + swapchainCreateInfo.oldSwapchain = fSwapchain; + +- res = fCreateSwapchainKHR(fDevice, &swapchainCreateInfo, nullptr, &fSwapchain); ++ res = fCreateSwapchainKHR(fShared->fDevice, &swapchainCreateInfo, nullptr, &fSwapchain); + if (VK_SUCCESS != res) { + return false; + } + + // destroy the old swapchain + if (swapchainCreateInfo.oldSwapchain != VK_NULL_HANDLE) { +- fDeviceWaitIdle(fDevice); ++ fDeviceWaitIdle(fShared->fDevice); + + this->destroyBuffers(); + +- fDestroySwapchainKHR(fDevice, swapchainCreateInfo.oldSwapchain, nullptr); ++ fDestroySwapchainKHR(fShared->fDevice, swapchainCreateInfo.oldSwapchain, nullptr); + } + + this->createBuffers(swapchainCreateInfo.imageFormat, colorType); +@@ -323,10 +336,10 @@ bool VulkanWindowContext::createSwapchain(int width, int height, + } + + void VulkanWindowContext::createBuffers(VkFormat format, SkColorType colorType) { +- fGetSwapchainImagesKHR(fDevice, fSwapchain, &fImageCount, nullptr); ++ fGetSwapchainImagesKHR(fShared->fDevice, fSwapchain, &fImageCount, nullptr); + SkASSERT(fImageCount); + fImages = new VkImage[fImageCount]; +- fGetSwapchainImagesKHR(fDevice, fSwapchain, &fImageCount, fImages); ++ fGetSwapchainImagesKHR(fShared->fDevice, fSwapchain, &fImageCount, fImages); + + // set up initial image layouts and create surfaces + fImageLayouts = new VkImageLayout[fImageCount]; +@@ -341,7 +354,7 @@ void VulkanWindowContext::createBuffers(VkFormat format, SkColorType colorType) + info.fImageTiling = VK_IMAGE_TILING_OPTIMAL; + info.fFormat = format; + info.fLevelCount = 1; +- info.fCurrentQueueFamily = fPresentQueueIndex; ++ info.fCurrentQueueFamily = fShared->fPresentQueueIndex; + + if (fSampleCount == 1) { + GrBackendRenderTarget backendRT(fWidth, fHeight, fSampleCount, info); +@@ -372,8 +385,8 @@ void VulkanWindowContext::createBuffers(VkFormat format, SkColorType colorType) + fBackbuffers = new BackbufferInfo[fImageCount + 1]; + for (uint32_t i = 0; i < fImageCount + 1; ++i) { + fBackbuffers[i].fImageIndex = -1; +- GR_VK_CALL_ERRCHECK(fInterface, +- CreateSemaphore(fDevice, &semaphoreInfo, ++ GR_VK_CALL_ERRCHECK(fShared->fInterface, ++ CreateSemaphore(fShared->fDevice, &semaphoreInfo, + nullptr, &fBackbuffers[i].fRenderSemaphore)); + } + fCurrentBackbufferIndex = fImageCount; +@@ -384,8 +397,8 @@ void VulkanWindowContext::destroyBuffers() { + if (fBackbuffers) { + for (uint32_t i = 0; i < fImageCount + 1; ++i) { + fBackbuffers[i].fImageIndex = -1; +- GR_VK_CALL(fInterface, +- DestroySemaphore(fDevice, ++ GR_VK_CALL(fShared->fInterface, ++ DestroySemaphore(fShared->fDevice, + fBackbuffers[i].fRenderSemaphore, + nullptr)); + } +@@ -410,41 +423,55 @@ VulkanWindowContext::~VulkanWindowContext() { + void VulkanWindowContext::destroyContext() { + if (this->isValid()) { + fQueueWaitIdle(fPresentQueue); +- fDeviceWaitIdle(fDevice); ++ fDeviceWaitIdle(fShared->fDevice); + + this->destroyBuffers(); + + if (VK_NULL_HANDLE != fSwapchain) { +- fDestroySwapchainKHR(fDevice, fSwapchain, nullptr); ++ fDestroySwapchainKHR(fShared->fDevice, fSwapchain, nullptr); + fSwapchain = VK_NULL_HANDLE; + } + + if (VK_NULL_HANDLE != fSurface) { +- fDestroySurfaceKHR(fInstance, fSurface, nullptr); ++ fDestroySurfaceKHR(fShared->fInstance, fSurface, nullptr); + fSurface = VK_NULL_HANDLE; + } + } + + fContext.reset(); +- fInterface.reset(); ++ fShared.reset(); ++ ++ checkDestroyShared(); ++} + +- if (VK_NULL_HANDLE != fDevice) { +- fDestroyDevice(fDevice, nullptr); +- fDevice = VK_NULL_HANDLE; ++void VulkanWindowContext::checkDestroyShared() ++{ ++ if(!fGlobalShared || !fGlobalShared->unique()) // TODO mutex? ++ return; ++ SkASSERT(fGlobalShared->fContext->unique()); ++ fGlobalShared->fContext.reset(); ++ fGlobalShared->fInterface.reset(); ++ ++ if (VK_NULL_HANDLE != fGlobalShared->fDevice) { ++ fGlobalShared->fDestroyDevice(fGlobalShared->fDevice, nullptr); ++ fGlobalShared->fDevice = VK_NULL_HANDLE; + } + + #ifdef SK_ENABLE_VK_LAYERS +- if (fDebugCallback != VK_NULL_HANDLE) { +- fDestroyDebugReportCallbackEXT(fInstance, fDebugCallback, nullptr); ++ if (fGlobalShared->fDebugCallback != VK_NULL_HANDLE) { ++ fGlobalShared->fDestroyDebugReportCallbackEXT(fGlobalShared->fInstance, fDebugCallback, nullptr); + } + #endif + +- fPhysicalDevice = VK_NULL_HANDLE; ++ fGlobalShared->fPhysicalDevice = VK_NULL_HANDLE; + +- if (VK_NULL_HANDLE != fInstance) { +- fDestroyInstance(fInstance, nullptr); +- fInstance = VK_NULL_HANDLE; ++ if (VK_NULL_HANDLE != fGlobalShared->fInstance) { ++ fGlobalShared->fDestroyInstance(fGlobalShared->fInstance, nullptr); ++ fGlobalShared->fInstance = VK_NULL_HANDLE; + } ++ ++ sk_gpu_test::FreeVulkanFeaturesStructs(&fGlobalShared->features); ++ fGlobalShared.reset(); + } + + VulkanWindowContext::BackbufferInfo* VulkanWindowContext::getAvailableBackbuffer() { +@@ -470,34 +497,34 @@ sk_sp<SkSurface> VulkanWindowContext::getBackbufferSurface() { + semaphoreInfo.pNext = nullptr; + semaphoreInfo.flags = 0; + VkSemaphore semaphore; +- GR_VK_CALL_ERRCHECK(fInterface, CreateSemaphore(fDevice, &semaphoreInfo, ++ GR_VK_CALL_ERRCHECK(fShared->fInterface, CreateSemaphore(fShared->fDevice, &semaphoreInfo, + nullptr, &semaphore)); + + // acquire the image +- VkResult res = fAcquireNextImageKHR(fDevice, fSwapchain, UINT64_MAX, ++ VkResult res = fAcquireNextImageKHR(fShared->fDevice, fSwapchain, UINT64_MAX, + semaphore, VK_NULL_HANDLE, + &backbuffer->fImageIndex); + if (VK_ERROR_SURFACE_LOST_KHR == res) { + // need to figure out how to create a new vkSurface without the platformData* + // maybe use attach somehow? but need a Window +- GR_VK_CALL(fInterface, DestroySemaphore(fDevice, semaphore, nullptr)); ++ GR_VK_CALL(fShared->fInterface, DestroySemaphore(fShared->fDevice, semaphore, nullptr)); + return nullptr; + } + if (VK_ERROR_OUT_OF_DATE_KHR == res) { + // tear swapchain down and try again + if (!this->createSwapchain(-1, -1, fDisplayParams)) { +- GR_VK_CALL(fInterface, DestroySemaphore(fDevice, semaphore, nullptr)); ++ GR_VK_CALL(fShared->fInterface, DestroySemaphore(fShared->fDevice, semaphore, nullptr)); + return nullptr; + } + backbuffer = this->getAvailableBackbuffer(); + + // acquire the image +- res = fAcquireNextImageKHR(fDevice, fSwapchain, UINT64_MAX, ++ res = fAcquireNextImageKHR(fShared->fDevice, fSwapchain, UINT64_MAX, + semaphore, VK_NULL_HANDLE, + &backbuffer->fImageIndex); + + if (VK_SUCCESS != res) { +- GR_VK_CALL(fInterface, DestroySemaphore(fDevice, semaphore, nullptr)); ++ GR_VK_CALL(fShared->fInterface, DestroySemaphore(fShared->fDevice, semaphore, nullptr)); + return nullptr; + } + } +@@ -541,4 +568,6 @@ void VulkanWindowContext::swapBuffers() { + fQueuePresentKHR(fPresentQueue, &presentInfo); + } + ++SK_API sk_sp<VulkanWindowContext::Shared> VulkanWindowContext::fGlobalShared; ++ + } //namespace sk_app +diff --git a/tools/sk_app/VulkanWindowContext.h b/tools/sk_app/VulkanWindowContext.h +index 2db9e79ae6..7950dc159b 100644 +--- a/tools/sk_app/VulkanWindowContext.h ++++ b/tools/sk_app/VulkanWindowContext.h +@@ -1,4 +1,3 @@ +- + /* + * Copyright 2016 Google Inc. + * +@@ -23,14 +22,30 @@ class GrRenderTarget; + + namespace sk_app { + +-class VulkanWindowContext : public WindowContext { ++class SK_API VulkanWindowContext : public WindowContext { ++ struct Shared; + public: + ~VulkanWindowContext() override; + ++ class SharedGrContext { ++ public: ++ SharedGrContext() {} ++ GrContext* getGrContext() { return shared ? shared->fContext.get() : nullptr; } ++ ~SharedGrContext() { shared.reset(); checkDestroyShared(); } ++ bool operator!() const { return !shared; } ++ void reset() { shared.reset(); } ++ private: ++ friend class VulkanWindowContext; ++ SharedGrContext(sk_sp<Shared>& sh ) : shared( sh ) {} ++ sk_sp<Shared> shared; ++ }; ++ ++ static SharedGrContext getSharedGrContext() { return SharedGrContext( fGlobalShared ); } ++ + sk_sp<SkSurface> getBackbufferSurface() override; + void swapBuffers() override; + +- bool isValid() override { return fDevice != VK_NULL_HANDLE; } ++ bool isValid() override { return fShared->fDevice != VK_NULL_HANDLE; } + + void resize(int w, int h) override { + this->createSwapchain(w, h, fDisplayParams); +@@ -53,6 +68,7 @@ public: + private: + void initializeContext(); + void destroyContext(); ++ static void checkDestroyShared(); + + struct BackbufferInfo { + uint32_t fImageIndex; // image this is associated with +@@ -64,11 +80,6 @@ private: + void createBuffers(VkFormat format, SkColorType colorType); + void destroyBuffers(); + +- VkInstance fInstance = VK_NULL_HANDLE; +- VkPhysicalDevice fPhysicalDevice = VK_NULL_HANDLE; +- VkDevice fDevice = VK_NULL_HANDLE; +- VkDebugReportCallbackEXT fDebugCallback = VK_NULL_HANDLE; +- + // Create functions + CreateVkSurfaceFn fCreateVkSurfaceFn; + CanPresentFn fCanPresentFn; +@@ -90,20 +101,41 @@ private: + PFN_vkAcquireNextImageKHR fAcquireNextImageKHR = nullptr; + PFN_vkQueuePresentKHR fQueuePresentKHR = nullptr; + +- PFN_vkDestroyInstance fDestroyInstance = nullptr; + PFN_vkDeviceWaitIdle fDeviceWaitIdle = nullptr; +- PFN_vkDestroyDebugReportCallbackEXT fDestroyDebugReportCallbackEXT = nullptr; + PFN_vkQueueWaitIdle fQueueWaitIdle = nullptr; +- PFN_vkDestroyDevice fDestroyDevice = nullptr; + PFN_vkGetDeviceQueue fGetDeviceQueue = nullptr; + ++ // We need to use just one GrContext, so share all the relevant data. ++ struct Shared : public SkRefCnt ++ { ++ PFN_vkDestroyInstance fDestroyInstance = nullptr; ++ PFN_vkDestroyDevice fDestroyDevice = nullptr; ++ PFN_vkDestroyDebugReportCallbackEXT fDestroyDebugReportCallbackEXT = nullptr; ++ ++ VkInstance fInstance = VK_NULL_HANDLE; ++ VkPhysicalDevice fPhysicalDevice = VK_NULL_HANDLE; ++ VkDevice fDevice = VK_NULL_HANDLE; ++ VkDebugReportCallbackEXT fDebugCallback = VK_NULL_HANDLE; ++ + sk_sp<const GrVkInterface> fInterface; + +- VkSurfaceKHR fSurface; +- VkSwapchainKHR fSwapchain; ++ // Original code had this as a function-local variable, but that seems wrong. ++ // It should exist as long as the context exists. ++ VkPhysicalDeviceFeatures2 features; ++ + uint32_t fGraphicsQueueIndex; + VkQueue fGraphicsQueue; + uint32_t fPresentQueueIndex; ++ ++ sk_sp<GrContext> fContext; ++ }; ++ ++ sk_sp<Shared> fShared; ++ ++ static sk_sp<Shared> fGlobalShared; ++ ++ VkSurfaceKHR fSurface; ++ VkSwapchainKHR fSwapchain; + VkQueue fPresentQueue; + + uint32_t fImageCount; diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk index 1f05f7aa9dd2..c054a2767a3c 100644 --- a/vcl/Library_vcl.mk +++ b/vcl/Library_vcl.mk @@ -586,8 +586,7 @@ $(eval $(call gb_Library_add_exception_objects,vcl,\ vcl/skia/SkiaHelper \ $(if $(filter SKIA,$(BUILD_TYPE)), \ vcl/skia/salbmp \ - vcl/skia/gdiimpl \ - vcl/skia/vulkan) \ + vcl/skia/gdiimpl) \ )) # runtime dependency diff --git a/vcl/inc/skia/gdiimpl.hxx b/vcl/inc/skia/gdiimpl.hxx index 04f96cb7bd11..195b5d877eed 100644 --- a/vcl/inc/skia/gdiimpl.hxx +++ b/vcl/inc/skia/gdiimpl.hxx @@ -26,6 +26,7 @@ #include <salgeom.hxx> #include <SkSurface.h> +#include <tools/sk_app/VulkanWindowContext.h> class SkiaFlushIdle; @@ -210,6 +211,7 @@ protected: void destroySurface(); // Reimplemented for X11. virtual bool avoidRecreateByResize() const { return false; } + void createOffscreenSurface(); void privateDrawAlphaRect(long nX, long nY, long nWidth, long nHeight, double nTransparency, bool blockAA = false); @@ -265,6 +267,8 @@ protected: // The Skia surface that is target of all the rendering. sk_sp<SkSurface> mSurface; bool mIsGPU; // whether the surface is GPU-backed + // Keep reference to shared GrContext. + sk_app::VulkanWindowContext::SharedGrContext mOffscreenGrContext; vcl::Region mClipRegion; Color mLineColor; Color mFillColor; diff --git a/vcl/inc/skia/vulkan.hxx b/vcl/inc/skia/vulkan.hxx deleted file mode 100644 index 6c8e3c7bfa44..000000000000 --- a/vcl/inc/skia/vulkan.hxx +++ /dev/null @@ -1,29 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ - -#ifndef INCLUDED_VCL_INC_SKIA_VULKAN_HXX -#define INCLUDED_VCL_INC_SKIA_VULKAN_HXX - -#include <GrContext.h> - -#include <vcl/dllapi.h> - -// Create and handle GrContext for Vulkan drawing to offscreen surfaces. -// Skia already provides WindowContext class that does this for surfaces -// used for drawing to windows, but it does not seem to provide a simple -// way to get GrContext without a window. -class VCL_PLUGIN_PUBLIC SkiaVulkanGrContext -{ -public: - static GrContext* getGrContext(); -}; - -#endif // INCLUDED_VCL_INC_SKIA_VULKAN_HXX - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/skia/README b/vcl/skia/README index 793c16e8dd39..f1248d90c3ea 100644 --- a/vcl/skia/README +++ b/vcl/skia/README @@ -17,3 +17,19 @@ Skia supports several methods to draw: - Vulkan - Vulkan-based GPU drawing, this is the default There are more (OpenGL, Metal on Mac, etc.), but (as of now) they are not supported by VCL. + +GrContext sharing: +================== + +We use Skia's sk_app::WindowContext class for creating surfaces for windows, that class +takes care of the internals. But of offscreen drawing, we need an instance of class +GrContext. There is sk_app::WindowContext::getGrContext(), but each instance creates +its own GrContext, and apparently it does not work to mix them. Which means that +for offscreen drawing we would need to know which window (and only that window) +the contents will be eventually painted to, which is not possible (it may not even +be known at the time). + +To solve this problem we patch sk_app::WindowContext to create just one GrContext object +and share it between instances. Additionally, using sk_app::WindowContext::SharedGrContext +it is possible to share it also for offscreen drawing, including keeping proper reference +count. diff --git a/vcl/skia/gdiimpl.cxx b/vcl/skia/gdiimpl.cxx index 776e44216c45..ac47d254cc03 100644 --- a/vcl/skia/gdiimpl.cxx +++ b/vcl/skia/gdiimpl.cxx @@ -23,12 +23,14 @@ #include <skia/salbmp.hxx> #include <vcl/idle.hxx> #include <vcl/svapp.hxx> +#include <vcl/lazydelete.hxx> #include <SkCanvas.h> #include <SkPath.h> #include <SkRegion.h> #include <SkDashPathEffect.h> #include <GrBackendSurface.h> +#include <GrContextFactory.h> #include <basegfx/polygon/b2dpolygontools.hxx> @@ -190,7 +192,11 @@ SkiaSalGraphicsImpl::SkiaSalGraphicsImpl(SalGraphics& rParent, SalGeometryProvid { } -SkiaSalGraphicsImpl::~SkiaSalGraphicsImpl() {} +SkiaSalGraphicsImpl::~SkiaSalGraphicsImpl() +{ + assert(!mSurface); + assert(!mOffscreenGrContext); +} void SkiaSalGraphicsImpl::Init() {} @@ -208,8 +214,7 @@ void SkiaSalGraphicsImpl::recreateSurface() void SkiaSalGraphicsImpl::createSurface() { - // Create surface for offscreen graphics. Subclasses will create GPU-backed - // surfaces as appropriate. + // Create raster surface. Subclasses will create GPU-backed surfaces as appropriate. mSurface = SkSurface::MakeRasterN32Premul(GetWidth(), GetHeight()); mIsGPU = false; #ifdef DBG_UTIL @@ -217,6 +222,53 @@ void SkiaSalGraphicsImpl::createSurface() #endif } +void SkiaSalGraphicsImpl::createOffscreenSurface() +{ + assert(isOffscreen()); + destroySurface(); + switch (renderMethodToUse()) + { + case RenderVulkan: + { + mOffscreenGrContext = sk_app::VulkanWindowContext::getSharedGrContext(); + GrContext* grContext = mOffscreenGrContext.getGrContext(); + // We may not get a GrContext if called before any onscreen window is created, + // but that happens very early, so this should be rare and insignificant. + // Unittests are an exception, they usually do not create any windows, + // so in that case do create GrContext that has no window associated. + if (!grContext) + { + static bool isUnitTest = (getenv("LO_TESTNAME") != nullptr); + if (isUnitTest) + { + static vcl::DeleteOnDeinit<sk_gpu_test::GrContextFactory> factory( + new sk_gpu_test::GrContextFactory); + // The factory owns the context. + grContext + = factory.get()->get(sk_gpu_test::GrContextFactory::kVulkan_ContextType); + } + } + if (grContext) + { + mSurface = SkSurface::MakeRenderTarget( + grContext, SkBudgeted::kNo, + SkImageInfo::MakeN32Premul(GetWidth(), GetHeight())); + mIsGPU = true; + assert(mSurface.get()); +#ifdef DBG_UTIL + prefillSurface(); +#endif + return; + } + SAL_WARN("vcl.skia", "cannot create Vulkan GPU offscreen surface"); + break; + } + default: + break; + } + return SkiaSalGraphicsImpl::createSurface(); // create a raster one +} + void SkiaSalGraphicsImpl::destroySurface() { if (mSurface) @@ -237,6 +289,7 @@ void SkiaSalGraphicsImpl::destroySurface() mSurface->flush(); mSurface.reset(); mIsGPU = false; + mOffscreenGrContext.reset(); } void SkiaSalGraphicsImpl::DeInit() { destroySurface(); } diff --git a/vcl/skia/vulkan.cxx b/vcl/skia/vulkan.cxx deleted file mode 100644 index c5c9093739fc..000000000000 --- a/vcl/skia/vulkan.cxx +++ /dev/null @@ -1,39 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Some of this code is based on Skia source code, covered by the following - * license notice (see readlicense_oo for the full license): - * - * Copyright 2016 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - * - */ - -#include <skia/vulkan.hxx> - -#include <GrContextFactory.h> - -#include <vcl/lazydelete.hxx> - -static GrContext* createGrContext() -{ - static vcl::DeleteOnDeinit<sk_gpu_test::GrContextFactory> factory( - new sk_gpu_test::GrContextFactory); - // The factory owns the context. - return factory.get()->get(sk_gpu_test::GrContextFactory::kVulkan_ContextType); -} - -GrContext* SkiaVulkanGrContext::getGrContext() -{ - static GrContext* context = createGrContext(); - return context; -} - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/skia/win/gdiimpl.cxx b/vcl/skia/win/gdiimpl.cxx index e9db555c25c0..8f30c3486dac 100644 --- a/vcl/skia/win/gdiimpl.cxx +++ b/vcl/skia/win/gdiimpl.cxx @@ -12,7 +12,6 @@ #include <tools/sk_app/win/WindowContextFactory_win.h> #include <tools/sk_app/WindowContext.h> #include <win/saldata.hxx> -#include <skia/vulkan.hxx> #include <SkColorFilter.h> #include <SkPixelRef.h> @@ -45,26 +44,9 @@ void WinSkiaSalGraphicsImpl::Init() void WinSkiaSalGraphicsImpl::createSurface() { - destroySurface(); if (isOffscreen()) - { - switch (renderMethodToUse()) - { - case RenderVulkan: - mSurface = SkSurface::MakeRenderTarget( - SkiaVulkanGrContext::getGrContext(), SkBudgeted::kNo, - SkImageInfo::MakeN32Premul(GetWidth(), GetHeight())); - mIsGPU = true; - assert(mSurface.get()); -#ifdef DBG_UTIL - prefillSurface(); -#endif - return; - default: - break; - } - return SkiaSalGraphicsImpl::createSurface(); - } + return createOffscreenSurface(); + destroySurface(); // When created, Init() gets called with size (0,0), which is invalid size // for Skia. Creating the actual surface is delayed, so the size should be always // valid here, but better check. diff --git a/vcl/skia/x11/gdiimpl.cxx b/vcl/skia/x11/gdiimpl.cxx index e349074e70e1..ef381c5e56d3 100644 --- a/vcl/skia/x11/gdiimpl.cxx +++ b/vcl/skia/x11/gdiimpl.cxx @@ -21,8 +21,6 @@ #include <tools/sk_app/unix/WindowContextFactory_unix.h> #include <tools/sk_app/WindowContext.h> -#include <skia/vulkan.hxx> - X11SkiaSalGraphicsImpl::X11SkiaSalGraphicsImpl(X11SalGraphics& rParent) : SkiaSalGraphicsImpl(rParent, rParent.GetGeometryProvider()) , mX11Parent(rParent) @@ -40,29 +38,12 @@ void X11SkiaSalGraphicsImpl::Init() void X11SkiaSalGraphicsImpl::createSurface() { - destroySurface(); if (isOffscreen()) - { - switch (renderMethodToUse()) - { - case RenderVulkan: - mSurface = SkSurface::MakeRenderTarget( - SkiaVulkanGrContext::getGrContext(), SkBudgeted::kNo, - SkImageInfo::MakeN32Premul(GetWidth(), GetHeight())); - mIsGPU = true; - assert(mSurface.get()); -#ifdef DBG_UTIL - prefillSurface(); -#endif - return; - default: - break; - } - return SkiaSalGraphicsImpl::createSurface(); - } + return createOffscreenSurface(); + destroySurface(); sk_app::DisplayParams displayParams; - // TODO The Skia Xlib code actually requires the non-native color type to work properly. // Use a macro to hide an unreachable code warning. + // TODO The Skia Xlib code actually requires the non-native color type to work properly. #define GET_FORMAT \ kN32_SkColorType == kBGRA_8888_SkColorType ? kRGBA_8888_SkColorType : kBGRA_8888_SkColorType displayParams.fColorType = GET_FORMAT; @@ -73,6 +54,13 @@ void X11SkiaSalGraphicsImpl::createSurface() assert(winInfo.fDisplay && winInfo.fWindow != None); winInfo.fFBConfig = nullptr; // not used winInfo.fVisualInfo = const_cast<SalVisual*>(&mX11Parent.GetVisual()); +#ifdef DBG_UTIL + // Our patched Skia has VulkanWindowContext that shares GrContext, which requires + // that the X11 visual is always the same. Ensure it is so. + static VisualID checkVisualID = -1U; + assert(checkVisualID == -1U || winInfo.fVisualInfo->visualid == checkVisualID); + checkVisualID = winInfo.fVisualInfo->visualid; +#endif winInfo.fWidth = GetWidth(); winInfo.fHeight = GetHeight(); switch (renderMethodToUse()) |