blob: f6309ab3e91aaed6558c6124677304929f44cd53 [file] [log] [blame]
Greg Daniel164a9f02016-02-22 09:56:40 -05001/*
2 * Copyright 2015 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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "src/gpu/vk/GrVkGpu.h"
Greg Daniel164a9f02016-02-22 09:56:40 -05009
Mike Kleinc0bd9f92019-04-23 12:05:21 -050010#include "include/gpu/GrBackendSemaphore.h"
11#include "include/gpu/GrBackendSurface.h"
12#include "include/gpu/GrContextOptions.h"
13#include "include/private/SkTo.h"
14#include "src/core/SkConvertPixels.h"
15#include "src/core/SkMipMap.h"
16#include "src/gpu/GrContextPriv.h"
17#include "src/gpu/GrGeometryProcessor.h"
18#include "src/gpu/GrGpuResourceCacheAccess.h"
19#include "src/gpu/GrMesh.h"
20#include "src/gpu/GrPipeline.h"
Greg Daniel797efca2019-05-09 14:04:20 -040021#include "src/gpu/GrRenderTargetContext.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050022#include "src/gpu/GrRenderTargetPriv.h"
23#include "src/gpu/GrTexturePriv.h"
Greg Daniel797efca2019-05-09 14:04:20 -040024#include "src/gpu/SkGpuDevice.h"
Robert Phillips9dbcdcc2019-05-13 10:40:06 -040025#include "src/gpu/SkGr.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050026#include "src/gpu/vk/GrVkAMDMemoryAllocator.h"
27#include "src/gpu/vk/GrVkCommandBuffer.h"
28#include "src/gpu/vk/GrVkCommandPool.h"
29#include "src/gpu/vk/GrVkGpuCommandBuffer.h"
30#include "src/gpu/vk/GrVkImage.h"
31#include "src/gpu/vk/GrVkIndexBuffer.h"
32#include "src/gpu/vk/GrVkInterface.h"
33#include "src/gpu/vk/GrVkMemory.h"
34#include "src/gpu/vk/GrVkPipeline.h"
35#include "src/gpu/vk/GrVkPipelineState.h"
36#include "src/gpu/vk/GrVkRenderPass.h"
37#include "src/gpu/vk/GrVkResourceProvider.h"
38#include "src/gpu/vk/GrVkSemaphore.h"
39#include "src/gpu/vk/GrVkTexture.h"
40#include "src/gpu/vk/GrVkTextureRenderTarget.h"
41#include "src/gpu/vk/GrVkTransferBuffer.h"
42#include "src/gpu/vk/GrVkVertexBuffer.h"
Greg Daniel797efca2019-05-09 14:04:20 -040043#include "src/image/SkImage_Gpu.h"
44#include "src/image/SkSurface_Gpu.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050045#include "src/sksl/SkSLCompiler.h"
Greg Daniel98bffae2018-08-01 13:25:41 -040046
Mike Kleinc0bd9f92019-04-23 12:05:21 -050047#include "include/gpu/vk/GrVkExtensions.h"
48#include "include/gpu/vk/GrVkTypes.h"
Greg Daniel164a9f02016-02-22 09:56:40 -050049
Ben Wagnerf08d1d02018-06-18 15:11:00 -040050#include <utility>
51
Forrest Reiling44f85712017-03-27 23:22:20 -070052#if !defined(SK_BUILD_FOR_WIN)
53#include <unistd.h>
54#endif // !defined(SK_BUILD_FOR_WIN)
55
Greg Danieldef55462018-08-01 13:40:14 -040056#if defined(SK_BUILD_FOR_WIN) && defined(SK_DEBUG)
Mike Kleinc0bd9f92019-04-23 12:05:21 -050057#include "include/private/SkLeanWindows.h"
Greg Danieldef55462018-08-01 13:40:14 -040058#endif
59
Greg Daniel164a9f02016-02-22 09:56:40 -050060#define VK_CALL(X) GR_VK_CALL(this->vkInterface(), X)
61#define VK_CALL_RET(RET, X) GR_VK_CALL_RET(this->vkInterface(), RET, X)
62#define VK_CALL_ERRCHECK(X) GR_VK_CALL_ERRCHECK(this->vkInterface(), X)
63
Greg Danielf730c182018-07-02 20:15:37 +000064sk_sp<GrGpu> GrVkGpu::Make(const GrVkBackendContext& backendContext,
Brian Salomon384fab42017-12-07 12:33:05 -050065 const GrContextOptions& options, GrContext* context) {
Greg Danielf730c182018-07-02 20:15:37 +000066 if (backendContext.fInstance == VK_NULL_HANDLE ||
67 backendContext.fPhysicalDevice == VK_NULL_HANDLE ||
68 backendContext.fDevice == VK_NULL_HANDLE ||
69 backendContext.fQueue == VK_NULL_HANDLE) {
70 return nullptr;
71 }
Greg Danield3e65aa2018-08-01 09:19:45 -040072 if (!backendContext.fGetProc) {
73 return nullptr;
Greg Danielc8cd45a2018-07-12 10:02:37 -040074 }
Greg Danield3e65aa2018-08-01 09:19:45 -040075
Greg Daniel41f0e282019-01-28 13:15:05 -050076 PFN_vkEnumerateInstanceVersion localEnumerateInstanceVersion =
77 reinterpret_cast<PFN_vkEnumerateInstanceVersion>(
78 backendContext.fGetProc("vkEnumerateInstanceVersion",
79 VK_NULL_HANDLE, VK_NULL_HANDLE));
80 uint32_t instanceVersion = 0;
81 if (!localEnumerateInstanceVersion) {
82 instanceVersion = VK_MAKE_VERSION(1, 0, 0);
83 } else {
84 VkResult err = localEnumerateInstanceVersion(&instanceVersion);
85 if (err) {
86 SkDebugf("Failed to enumerate instance version. Err: %d\n", err);
87 return nullptr;
88 }
89 }
90
Greg Danielc0b03d82018-08-03 14:41:15 -040091 PFN_vkGetPhysicalDeviceProperties localGetPhysicalDeviceProperties =
92 reinterpret_cast<PFN_vkGetPhysicalDeviceProperties>(
93 backendContext.fGetProc("vkGetPhysicalDeviceProperties",
94 backendContext.fInstance,
95 VK_NULL_HANDLE));
96
97 if (!localGetPhysicalDeviceProperties) {
98 return nullptr;
99 }
100 VkPhysicalDeviceProperties physDeviceProperties;
101 localGetPhysicalDeviceProperties(backendContext.fPhysicalDevice, &physDeviceProperties);
102 uint32_t physDevVersion = physDeviceProperties.apiVersion;
103
Greg Daniel41f0e282019-01-28 13:15:05 -0500104 uint32_t apiVersion = backendContext.fMaxAPIVersion ? backendContext.fMaxAPIVersion
105 : instanceVersion;
106
107 instanceVersion = SkTMin(instanceVersion, apiVersion);
108 physDevVersion = SkTMin(physDevVersion, apiVersion);
109
Greg Daniel98bffae2018-08-01 13:25:41 -0400110 sk_sp<const GrVkInterface> interface;
Greg Danield3e65aa2018-08-01 09:19:45 -0400111
Greg Daniel98bffae2018-08-01 13:25:41 -0400112 if (backendContext.fVkExtensions) {
113 interface.reset(new GrVkInterface(backendContext.fGetProc,
114 backendContext.fInstance,
115 backendContext.fDevice,
Greg Daniel41f0e282019-01-28 13:15:05 -0500116 instanceVersion,
Greg Danielc0b03d82018-08-03 14:41:15 -0400117 physDevVersion,
Greg Daniel98bffae2018-08-01 13:25:41 -0400118 backendContext.fVkExtensions));
Greg Daniel41f0e282019-01-28 13:15:05 -0500119 if (!interface->validate(instanceVersion, physDevVersion, backendContext.fVkExtensions)) {
Greg Daniel98bffae2018-08-01 13:25:41 -0400120 return nullptr;
121 }
122 } else {
Greg Daniel98bffae2018-08-01 13:25:41 -0400123 GrVkExtensions extensions;
Greg Daniel88e8ddc2019-04-25 16:37:08 -0400124 // The only extension flag that may effect the vulkan backend is the swapchain extension. We
125 // need to know if this is enabled to know if we can transition to a present layout when
126 // flushing a surface.
127 if (backendContext.fExtensions & kKHR_swapchain_GrVkExtensionFlag) {
128 const char* swapChainExtName = VK_KHR_SWAPCHAIN_EXTENSION_NAME;
129 extensions.init(backendContext.fGetProc, backendContext.fInstance,
130 backendContext.fPhysicalDevice, 0, nullptr, 1, &swapChainExtName);
131 }
Greg Daniel98bffae2018-08-01 13:25:41 -0400132 interface.reset(new GrVkInterface(backendContext.fGetProc,
133 backendContext.fInstance,
134 backendContext.fDevice,
Greg Daniel41f0e282019-01-28 13:15:05 -0500135 instanceVersion,
Greg Danielc0b03d82018-08-03 14:41:15 -0400136 physDevVersion,
Greg Daniel98bffae2018-08-01 13:25:41 -0400137 &extensions));
Greg Daniel41f0e282019-01-28 13:15:05 -0500138 if (!interface->validate(instanceVersion, physDevVersion, &extensions)) {
Greg Daniel98bffae2018-08-01 13:25:41 -0400139 return nullptr;
140 }
Greg Daniel164a9f02016-02-22 09:56:40 -0500141 }
142
Greg Daniel41f0e282019-01-28 13:15:05 -0500143 return sk_sp<GrGpu>(new GrVkGpu(context, options, backendContext, interface, instanceVersion,
144 physDevVersion));
Greg Daniel164a9f02016-02-22 09:56:40 -0500145}
146
147////////////////////////////////////////////////////////////////////////////////
148
halcanary9d524f22016-03-29 09:03:52 -0700149GrVkGpu::GrVkGpu(GrContext* context, const GrContextOptions& options,
Greg Daniel41f0e282019-01-28 13:15:05 -0500150 const GrVkBackendContext& backendContext, sk_sp<const GrVkInterface> interface,
151 uint32_t instanceVersion, uint32_t physicalDeviceVersion)
Brian Salomon384fab42017-12-07 12:33:05 -0500152 : INHERITED(context)
Greg Danielc8cd45a2018-07-12 10:02:37 -0400153 , fInterface(std::move(interface))
Greg Danielf730c182018-07-02 20:15:37 +0000154 , fMemoryAllocator(backendContext.fMemoryAllocator)
155 , fInstance(backendContext.fInstance)
Greg Daniel637c06a2018-09-12 09:44:25 -0400156 , fPhysicalDevice(backendContext.fPhysicalDevice)
Greg Danielf730c182018-07-02 20:15:37 +0000157 , fDevice(backendContext.fDevice)
158 , fQueue(backendContext.fQueue)
Greg Danielecddbc02018-08-30 16:39:34 -0400159 , fQueueIndex(backendContext.fGraphicsQueueIndex)
Brian Salomon384fab42017-12-07 12:33:05 -0500160 , fResourceProvider(this)
161 , fDisconnected(false) {
Greg Danielf730c182018-07-02 20:15:37 +0000162 SkASSERT(!backendContext.fOwnsInstanceAndDevice);
jvanverth633b3562016-03-23 11:01:22 -0700163
Greg Daniel81df0412018-05-31 13:13:33 -0400164 if (!fMemoryAllocator) {
165 // We were not given a memory allocator at creation
Greg Danielf730c182018-07-02 20:15:37 +0000166 fMemoryAllocator.reset(new GrVkAMDMemoryAllocator(backendContext.fPhysicalDevice,
Greg Danielc8cd45a2018-07-12 10:02:37 -0400167 fDevice, fInterface));
Greg Daniel81df0412018-05-31 13:13:33 -0400168 }
169
ethannicholasb3058bd2016-07-01 08:22:01 -0700170 fCompiler = new SkSL::Compiler();
jvanverth633b3562016-03-23 11:01:22 -0700171
Greg Daniela0651ac2018-08-08 09:23:18 -0400172 if (backendContext.fDeviceFeatures2) {
Greg Daniel36443602018-08-02 12:51:52 -0400173 fVkCaps.reset(new GrVkCaps(options, this->vkInterface(), backendContext.fPhysicalDevice,
Greg Daniela0651ac2018-08-08 09:23:18 -0400174 *backendContext.fDeviceFeatures2, instanceVersion,
Greg Daniel41f0e282019-01-28 13:15:05 -0500175 physicalDeviceVersion,
Greg Danielc0b03d82018-08-03 14:41:15 -0400176 *backendContext.fVkExtensions));
Greg Daniela0651ac2018-08-08 09:23:18 -0400177 } else if (backendContext.fDeviceFeatures) {
178 VkPhysicalDeviceFeatures2 features2;
179 features2.pNext = nullptr;
180 features2.features = *backendContext.fDeviceFeatures;
181 fVkCaps.reset(new GrVkCaps(options, this->vkInterface(), backendContext.fPhysicalDevice,
Greg Daniel41f0e282019-01-28 13:15:05 -0500182 features2, instanceVersion, physicalDeviceVersion,
183 *backendContext.fVkExtensions));
Greg Daniel36443602018-08-02 12:51:52 -0400184 } else {
Greg Daniela0651ac2018-08-08 09:23:18 -0400185 VkPhysicalDeviceFeatures2 features;
186 memset(&features, 0, sizeof(VkPhysicalDeviceFeatures2));
187 features.pNext = nullptr;
Greg Daniel36443602018-08-02 12:51:52 -0400188 if (backendContext.fFeatures & kGeometryShader_GrVkFeatureFlag) {
Greg Daniela0651ac2018-08-08 09:23:18 -0400189 features.features.geometryShader = true;
Greg Daniel36443602018-08-02 12:51:52 -0400190 }
191 if (backendContext.fFeatures & kDualSrcBlend_GrVkFeatureFlag) {
Greg Daniela0651ac2018-08-08 09:23:18 -0400192 features.features.dualSrcBlend = true;
Greg Daniel36443602018-08-02 12:51:52 -0400193 }
194 if (backendContext.fFeatures & kSampleRateShading_GrVkFeatureFlag) {
Greg Daniela0651ac2018-08-08 09:23:18 -0400195 features.features.sampleRateShading = true;
Greg Daniel36443602018-08-02 12:51:52 -0400196 }
Greg Danielf808c5e2019-04-30 14:48:27 -0400197 GrVkExtensions extensions;
198 // The only extension flag that may effect the vulkan backend is the swapchain extension. We
199 // need to know if this is enabled to know if we can transition to a present layout when
200 // flushing a surface.
201 if (backendContext.fExtensions & kKHR_swapchain_GrVkExtensionFlag) {
202 const char* swapChainExtName = VK_KHR_SWAPCHAIN_EXTENSION_NAME;
203 extensions.init(backendContext.fGetProc, backendContext.fInstance,
204 backendContext.fPhysicalDevice, 0, nullptr, 1, &swapChainExtName);
205 }
Greg Daniel36443602018-08-02 12:51:52 -0400206 fVkCaps.reset(new GrVkCaps(options, this->vkInterface(), backendContext.fPhysicalDevice,
Greg Danielf808c5e2019-04-30 14:48:27 -0400207 features, instanceVersion, physicalDeviceVersion, extensions));
Greg Daniel36443602018-08-02 12:51:52 -0400208 }
jvanverth633b3562016-03-23 11:01:22 -0700209 fCaps.reset(SkRef(fVkCaps.get()));
210
Greg Danielf730c182018-07-02 20:15:37 +0000211 VK_CALL(GetPhysicalDeviceProperties(backendContext.fPhysicalDevice, &fPhysDevProps));
212 VK_CALL(GetPhysicalDeviceMemoryProperties(backendContext.fPhysicalDevice, &fPhysDevMemProps));
jvanverth633b3562016-03-23 11:01:22 -0700213
Greg Daniela870b462019-01-08 15:49:46 -0500214 fResourceProvider.init();
215
Ethan Nicholas8e265a72018-12-12 16:22:40 -0500216 fCmdPool = fResourceProvider.findOrCreateCommandPool();
217 fCurrentCmdBuffer = fCmdPool->getPrimaryCommandBuffer();
Ethan Nicholasbff4e072018-12-12 18:17:24 +0000218 SkASSERT(fCurrentCmdBuffer);
jvanverth633b3562016-03-23 11:01:22 -0700219 fCurrentCmdBuffer->begin(this);
Greg Daniel164a9f02016-02-22 09:56:40 -0500220}
221
Greg Daniel8606cf82017-05-08 16:17:53 -0400222void GrVkGpu::destroyResources() {
Ethan Nicholas8e265a72018-12-12 16:22:40 -0500223 if (fCmdPool) {
224 fCmdPool->getPrimaryCommandBuffer()->end(this);
225 fCmdPool->close();
Greg Daniel8606cf82017-05-08 16:17:53 -0400226 }
Greg Daniel164a9f02016-02-22 09:56:40 -0500227
228 // wait for all commands to finish
Jim Van Verth09557d72016-11-07 11:10:21 -0500229 VkResult res = VK_CALL(QueueWaitIdle(fQueue));
egdanielf8c2be32016-06-24 13:18:27 -0700230
231 // On windows, sometimes calls to QueueWaitIdle return before actually signalling the fences
232 // on the command buffers even though they have completed. This causes an assert to fire when
233 // destroying the command buffers. Currently this ony seems to happen on windows, so we add a
Jim Van Verth09557d72016-11-07 11:10:21 -0500234 // sleep to make sure the fence signals.
egdanielf8c2be32016-06-24 13:18:27 -0700235#ifdef SK_DEBUG
Greg Daniel80a08dd2017-01-20 10:45:49 -0500236 if (this->vkCaps().mustSleepOnTearDown()) {
egdanielf8c2be32016-06-24 13:18:27 -0700237#if defined(SK_BUILD_FOR_WIN)
Greg Daniel80a08dd2017-01-20 10:45:49 -0500238 Sleep(10); // In milliseconds
egdanielf8c2be32016-06-24 13:18:27 -0700239#else
Greg Daniel80a08dd2017-01-20 10:45:49 -0500240 sleep(1); // In seconds
egdanielf8c2be32016-06-24 13:18:27 -0700241#endif
Greg Daniel80a08dd2017-01-20 10:45:49 -0500242 }
egdanielf8c2be32016-06-24 13:18:27 -0700243#endif
244
egdanielbe9d8212016-09-20 08:54:23 -0700245#ifdef SK_DEBUG
Greg Daniel8a8668b2016-10-31 16:34:42 -0400246 SkASSERT(VK_SUCCESS == res || VK_ERROR_DEVICE_LOST == res);
egdanielbe9d8212016-09-20 08:54:23 -0700247#endif
halcanary9d524f22016-03-29 09:03:52 -0700248
Ethan Nicholas8e265a72018-12-12 16:22:40 -0500249 if (fCmdPool) {
250 fCmdPool->unref(this);
251 fCmdPool = nullptr;
252 }
253
Greg Daniel6be35232017-03-01 17:01:09 -0500254 for (int i = 0; i < fSemaphoresToWaitOn.count(); ++i) {
255 fSemaphoresToWaitOn[i]->unref(this);
256 }
257 fSemaphoresToWaitOn.reset();
258
Greg Daniela5cb7812017-06-16 09:45:32 -0400259 for (int i = 0; i < fSemaphoresToSignal.count(); ++i) {
260 fSemaphoresToSignal[i]->unref(this);
261 }
262 fSemaphoresToSignal.reset();
263
264
egdanielbc9b2962016-09-27 08:00:53 -0700265 fCopyManager.destroyResources(this);
266
Jim Van Verth09557d72016-11-07 11:10:21 -0500267 // must call this just before we destroy the command pool and VkDevice
268 fResourceProvider.destroyResources(VK_ERROR_DEVICE_LOST == res);
Greg Daniel164a9f02016-02-22 09:56:40 -0500269
Greg Danielf730c182018-07-02 20:15:37 +0000270 fMemoryAllocator.reset();
271
272 fQueue = VK_NULL_HANDLE;
273 fDevice = VK_NULL_HANDLE;
274 fInstance = VK_NULL_HANDLE;
Greg Daniel8606cf82017-05-08 16:17:53 -0400275}
276
277GrVkGpu::~GrVkGpu() {
278 if (!fDisconnected) {
279 this->destroyResources();
280 }
281 delete fCompiler;
282}
283
284
285void GrVkGpu::disconnect(DisconnectType type) {
286 INHERITED::disconnect(type);
287 if (!fDisconnected) {
288 if (DisconnectType::kCleanup == type) {
289 this->destroyResources();
290 } else {
Ethan Nicholas8e265a72018-12-12 16:22:40 -0500291 if (fCmdPool) {
292 fCmdPool->unrefAndAbandon();
293 fCmdPool = nullptr;
Greg Danieladb4bfe2018-08-23 16:15:05 -0400294 }
Greg Daniel8606cf82017-05-08 16:17:53 -0400295 for (int i = 0; i < fSemaphoresToWaitOn.count(); ++i) {
296 fSemaphoresToWaitOn[i]->unrefAndAbandon();
297 }
Greg Daniela5cb7812017-06-16 09:45:32 -0400298 for (int i = 0; i < fSemaphoresToSignal.count(); ++i) {
299 fSemaphoresToSignal[i]->unrefAndAbandon();
300 }
Greg Daniel8606cf82017-05-08 16:17:53 -0400301 fCopyManager.abandonResources();
302
303 // must call this just before we destroy the command pool and VkDevice
304 fResourceProvider.abandonResources();
Greg Danieladb4bfe2018-08-23 16:15:05 -0400305
306 fMemoryAllocator.reset();
Greg Daniel8606cf82017-05-08 16:17:53 -0400307 }
308 fSemaphoresToWaitOn.reset();
Greg Daniela5cb7812017-06-16 09:45:32 -0400309 fSemaphoresToSignal.reset();
Greg Daniel8606cf82017-05-08 16:17:53 -0400310 fCurrentCmdBuffer = nullptr;
Greg Daniel8606cf82017-05-08 16:17:53 -0400311 fDisconnected = true;
312 }
Greg Daniel164a9f02016-02-22 09:56:40 -0500313}
314
315///////////////////////////////////////////////////////////////////////////////
316
Robert Phillips5b5d84c2018-08-09 15:12:18 -0400317GrGpuRTCommandBuffer* GrVkGpu::getCommandBuffer(
Ethan Nicholas56d19a52018-10-15 11:26:20 -0400318 GrRenderTarget* rt, GrSurfaceOrigin origin, const SkRect& bounds,
Greg Daniel500d58b2017-08-24 15:59:33 -0400319 const GrGpuRTCommandBuffer::LoadAndStoreInfo& colorInfo,
320 const GrGpuRTCommandBuffer::StencilLoadAndStoreInfo& stencilInfo) {
Robert Phillips5b5d84c2018-08-09 15:12:18 -0400321 if (!fCachedRTCommandBuffer) {
322 fCachedRTCommandBuffer.reset(new GrVkGpuRTCommandBuffer(this));
323 }
324
Greg Daniela41a74a2018-10-09 12:59:23 +0000325 fCachedRTCommandBuffer->set(rt, origin, colorInfo, stencilInfo);
Robert Phillips5b5d84c2018-08-09 15:12:18 -0400326 return fCachedRTCommandBuffer.get();
Greg Daniel500d58b2017-08-24 15:59:33 -0400327}
328
Robert Phillips5b5d84c2018-08-09 15:12:18 -0400329GrGpuTextureCommandBuffer* GrVkGpu::getCommandBuffer(GrTexture* texture, GrSurfaceOrigin origin) {
330 if (!fCachedTexCommandBuffer) {
331 fCachedTexCommandBuffer.reset(new GrVkGpuTextureCommandBuffer(this));
332 }
333
334 fCachedTexCommandBuffer->set(texture, origin);
335 return fCachedTexCommandBuffer.get();
egdaniel066df7c2016-06-08 14:02:27 -0700336}
337
Greg Daniela3aa75a2019-04-12 14:24:55 -0400338void GrVkGpu::submitCommandBuffer(SyncQueue sync, GrGpuFinishedProc finishedProc,
339 GrGpuFinishedContext finishedContext) {
Greg Daniel164a9f02016-02-22 09:56:40 -0500340 SkASSERT(fCurrentCmdBuffer);
Robert Phillipsce0a2bf2019-04-02 13:37:34 -0400341
342 if (!fCurrentCmdBuffer->hasWork() && kForce_SyncQueue != sync &&
343 !fSemaphoresToSignal.count() && !fSemaphoresToWaitOn.count()) {
344 SkASSERT(fDrawables.empty());
Robert Phillips84614c32019-04-05 09:36:00 -0400345 fResourceProvider.checkCommandBuffers();
Greg Daniela3aa75a2019-04-12 14:24:55 -0400346 if (finishedProc) {
347 fResourceProvider.addFinishedProcToActiveCommandBuffers(finishedProc, finishedContext);
348 }
Robert Phillipsce0a2bf2019-04-02 13:37:34 -0400349 return;
350 }
351
Greg Daniel164a9f02016-02-22 09:56:40 -0500352 fCurrentCmdBuffer->end(this);
Ethan Nicholas8e265a72018-12-12 16:22:40 -0500353 fCmdPool->close();
Greg Daniela5cb7812017-06-16 09:45:32 -0400354 fCurrentCmdBuffer->submitToQueue(this, fQueue, sync, fSemaphoresToSignal, fSemaphoresToWaitOn);
Greg Daniel6be35232017-03-01 17:01:09 -0500355
Greg Daniela3aa75a2019-04-12 14:24:55 -0400356 if (finishedProc) {
357 // Make sure this is called after closing the current command pool
358 fResourceProvider.addFinishedProcToActiveCommandBuffers(finishedProc, finishedContext);
359 }
360
Greg Daniel64cc9aa2018-10-19 13:54:56 -0400361 // We must delete and drawables that have been waitint till submit for us to destroy.
362 fDrawables.reset();
363
Greg Daniel6be35232017-03-01 17:01:09 -0500364 for (int i = 0; i < fSemaphoresToWaitOn.count(); ++i) {
365 fSemaphoresToWaitOn[i]->unref(this);
366 }
367 fSemaphoresToWaitOn.reset();
Greg Daniela5cb7812017-06-16 09:45:32 -0400368 for (int i = 0; i < fSemaphoresToSignal.count(); ++i) {
369 fSemaphoresToSignal[i]->unref(this);
370 }
371 fSemaphoresToSignal.reset();
Greg Daniel6be35232017-03-01 17:01:09 -0500372
Ethan Nicholas8e265a72018-12-12 16:22:40 -0500373 // Release old command pool and create a new one
374 fCmdPool->unref(this);
Greg Daniel164a9f02016-02-22 09:56:40 -0500375 fResourceProvider.checkCommandBuffers();
Ethan Nicholas8e265a72018-12-12 16:22:40 -0500376 fCmdPool = fResourceProvider.findOrCreateCommandPool();
377 fCurrentCmdBuffer = fCmdPool->getPrimaryCommandBuffer();
Greg Daniel164a9f02016-02-22 09:56:40 -0500378 fCurrentCmdBuffer->begin(this);
379}
380
381///////////////////////////////////////////////////////////////////////////////
Brian Salomondbf70722019-02-07 11:31:24 -0500382sk_sp<GrGpuBuffer> GrVkGpu::onCreateBuffer(size_t size, GrGpuBufferType type,
383 GrAccessPattern accessPattern, const void* data) {
384 sk_sp<GrGpuBuffer> buff;
cdalton397536c2016-03-25 12:15:03 -0700385 switch (type) {
Brian Salomonae64c192019-02-05 09:41:37 -0500386 case GrGpuBufferType::kVertex:
cdalton397536c2016-03-25 12:15:03 -0700387 SkASSERT(kDynamic_GrAccessPattern == accessPattern ||
388 kStatic_GrAccessPattern == accessPattern);
Brian Salomon12d22642019-01-29 14:38:50 -0500389 buff = GrVkVertexBuffer::Make(this, size, kDynamic_GrAccessPattern == accessPattern);
egdaniele05bbbb2016-04-19 12:13:41 -0700390 break;
Brian Salomonae64c192019-02-05 09:41:37 -0500391 case GrGpuBufferType::kIndex:
cdalton397536c2016-03-25 12:15:03 -0700392 SkASSERT(kDynamic_GrAccessPattern == accessPattern ||
393 kStatic_GrAccessPattern == accessPattern);
Brian Salomon12d22642019-01-29 14:38:50 -0500394 buff = GrVkIndexBuffer::Make(this, size, kDynamic_GrAccessPattern == accessPattern);
egdaniele05bbbb2016-04-19 12:13:41 -0700395 break;
Brian Salomonae64c192019-02-05 09:41:37 -0500396 case GrGpuBufferType::kXferCpuToGpu:
Jim Van Verth2e5eaf02017-06-21 15:55:46 -0400397 SkASSERT(kDynamic_GrAccessPattern == accessPattern ||
398 kStream_GrAccessPattern == accessPattern);
Brian Salomon12d22642019-01-29 14:38:50 -0500399 buff = GrVkTransferBuffer::Make(this, size, GrVkBuffer::kCopyRead_Type);
egdaniele05bbbb2016-04-19 12:13:41 -0700400 break;
Brian Salomonae64c192019-02-05 09:41:37 -0500401 case GrGpuBufferType::kXferGpuToCpu:
Jim Van Verth2e5eaf02017-06-21 15:55:46 -0400402 SkASSERT(kDynamic_GrAccessPattern == accessPattern ||
403 kStream_GrAccessPattern == accessPattern);
Brian Salomon12d22642019-01-29 14:38:50 -0500404 buff = GrVkTransferBuffer::Make(this, size, GrVkBuffer::kCopyWrite_Type);
egdaniele05bbbb2016-04-19 12:13:41 -0700405 break;
cdalton397536c2016-03-25 12:15:03 -0700406 default:
Ben Wagnerb4aab9a2017-08-16 10:53:04 -0400407 SK_ABORT("Unknown buffer type.");
cdalton397536c2016-03-25 12:15:03 -0700408 return nullptr;
409 }
cdalton1bf3e712016-04-19 10:00:02 -0700410 if (data && buff) {
411 buff->updateData(data, size);
412 }
413 return buff;
Greg Daniel164a9f02016-02-22 09:56:40 -0500414}
415
Brian Salomona9b04b92018-06-01 15:04:28 -0400416bool GrVkGpu::onWritePixels(GrSurface* surface, int left, int top, int width, int height,
417 GrColorType srcColorType, const GrMipLevel texels[],
418 int mipLevelCount) {
Greg Daniel164a9f02016-02-22 09:56:40 -0500419 GrVkTexture* vkTex = static_cast<GrVkTexture*>(surface->asTexture());
420 if (!vkTex) {
421 return false;
422 }
423
jvanverth900bd4a2016-04-29 13:53:12 -0700424 // Make sure we have at least the base level
Robert Phillips590533f2017-07-11 14:22:35 -0400425 if (!mipLevelCount || !texels[0].fPixels) {
jvanverth03509ea2016-03-02 13:19:47 -0800426 return false;
427 }
bsalomona1e6b3b2016-03-02 10:58:23 -0800428
Jim Van Verth1676cb92019-01-15 13:24:45 -0500429 SkASSERT(!GrPixelConfigIsCompressed(vkTex->config()));
Greg Daniel164a9f02016-02-22 09:56:40 -0500430 bool success = false;
Robert Phillips92de6312017-05-23 07:43:48 -0400431 bool linearTiling = vkTex->isLinearTiled();
432 if (linearTiling) {
Robert Phillips590533f2017-07-11 14:22:35 -0400433 if (mipLevelCount > 1) {
Robert Phillips92de6312017-05-23 07:43:48 -0400434 SkDebugf("Can't upload mipmap data to linear tiled texture");
435 return false;
436 }
437 if (VK_IMAGE_LAYOUT_PREINITIALIZED != vkTex->currentLayout()) {
438 // Need to change the layout to general in order to perform a host write
439 vkTex->setImageLayout(this,
440 VK_IMAGE_LAYOUT_GENERAL,
441 VK_ACCESS_HOST_WRITE_BIT,
442 VK_PIPELINE_STAGE_HOST_BIT,
443 false);
444 this->submitCommandBuffer(kForce_SyncQueue);
445 }
Brian Salomona9b04b92018-06-01 15:04:28 -0400446 success = this->uploadTexDataLinear(vkTex, left, top, width, height, srcColorType,
Robert Phillips590533f2017-07-11 14:22:35 -0400447 texels[0].fPixels, texels[0].fRowBytes);
Greg Daniel164a9f02016-02-22 09:56:40 -0500448 } else {
Greg Danielda86e282018-06-13 09:41:19 -0400449 SkASSERT(mipLevelCount <= vkTex->texturePriv().maxMipMapLevel() + 1);
Brian Salomona9b04b92018-06-01 15:04:28 -0400450 success = this->uploadTexDataOptimal(vkTex, left, top, width, height, srcColorType, texels,
451 mipLevelCount);
Greg Daniel164a9f02016-02-22 09:56:40 -0500452 }
egdaniel4583ec52016-06-27 12:57:00 -0700453
jvanverth900bd4a2016-04-29 13:53:12 -0700454 return success;
Greg Daniel164a9f02016-02-22 09:56:40 -0500455}
456
Brian Salomone05ba5a2019-04-08 11:59:07 -0400457bool GrVkGpu::onTransferPixelsTo(GrTexture* texture, int left, int top, int width, int height,
458 GrColorType bufferColorType, GrGpuBuffer* transferBuffer,
459 size_t bufferOffset, size_t rowBytes) {
Jim Van Verth1676cb92019-01-15 13:24:45 -0500460 // Can't transfer compressed data
461 SkASSERT(!GrPixelConfigIsCompressed(texture->config()));
462
Jim Van Verth2e5eaf02017-06-21 15:55:46 -0400463 // Vulkan only supports 4-byte aligned offsets
464 if (SkToBool(bufferOffset & 0x2)) {
465 return false;
466 }
467 GrVkTexture* vkTex = static_cast<GrVkTexture*>(texture);
468 if (!vkTex) {
469 return false;
470 }
471 GrVkTransferBuffer* vkBuffer = static_cast<GrVkTransferBuffer*>(transferBuffer);
472 if (!vkBuffer) {
473 return false;
474 }
475
Greg Daniel660cc992017-06-26 14:55:05 -0400476 SkDEBUGCODE(
477 SkIRect subRect = SkIRect::MakeXYWH(left, top, width, height);
478 SkIRect bounds = SkIRect::MakeWH(texture->width(), texture->height());
479 SkASSERT(bounds.contains(subRect));
480 )
Brian Salomonc320b152018-02-20 14:05:36 -0500481 int bpp = GrColorTypeBytesPerPixel(bufferColorType);
Jim Van Verth2e5eaf02017-06-21 15:55:46 -0400482 if (rowBytes == 0) {
Brian Salomonc320b152018-02-20 14:05:36 -0500483 rowBytes = bpp * width;
Jim Van Verth2e5eaf02017-06-21 15:55:46 -0400484 }
485
486 // Set up copy region
487 VkBufferImageCopy region;
488 memset(&region, 0, sizeof(VkBufferImageCopy));
489 region.bufferOffset = bufferOffset;
490 region.bufferRowLength = (uint32_t)(rowBytes/bpp);
491 region.bufferImageHeight = 0;
492 region.imageSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
493 region.imageOffset = { left, top, 0 };
494 region.imageExtent = { (uint32_t)width, (uint32_t)height, 1 };
495
496 // Change layout of our target so it can be copied to
497 vkTex->setImageLayout(this,
498 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
499 VK_ACCESS_TRANSFER_WRITE_BIT,
500 VK_PIPELINE_STAGE_TRANSFER_BIT,
501 false);
502
503 // Copy the buffer to the image
504 fCurrentCmdBuffer->copyBufferToImage(this,
505 vkBuffer,
506 vkTex,
507 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
508 1,
509 &region);
510
Greg Daniel0fc4d2d2017-10-12 11:23:36 -0400511 vkTex->texturePriv().markMipMapsDirty();
Jim Van Verth2e5eaf02017-06-21 15:55:46 -0400512 return true;
513}
514
Brian Salomon26de56e2019-04-10 12:14:26 -0400515bool GrVkGpu::onTransferPixelsFrom(GrSurface* surface, int left, int top, int width, int height,
516 GrColorType bufferColorType, GrGpuBuffer* transferBuffer,
517 size_t offset) {
Brian Salomona585fe92019-04-09 14:57:00 -0400518 SkASSERT(surface);
519 SkASSERT(transferBuffer);
520
Brian Salomona585fe92019-04-09 14:57:00 -0400521 GrVkTransferBuffer* vkBuffer = static_cast<GrVkTransferBuffer*>(transferBuffer);
522
523 GrVkImage* srcImage;
524 if (GrVkRenderTarget* rt = static_cast<GrVkRenderTarget*>(surface->asRenderTarget())) {
525 // Reading from render targets that wrap a secondary command buffer is not allowed since
526 // it would require us to know the VkImage, which we don't have, as well as need us to
527 // stop and start the VkRenderPass which we don't have access to.
528 if (rt->wrapsSecondaryCommandBuffer()) {
529 return false;
530 }
531 // resolve the render target if necessary
532 switch (rt->getResolveType()) {
533 case GrVkRenderTarget::kCantResolve_ResolveType:
534 return false;
535 case GrVkRenderTarget::kAutoResolves_ResolveType:
536 break;
537 case GrVkRenderTarget::kCanResolve_ResolveType:
538 this->resolveRenderTargetNoFlush(rt);
539 break;
540 default:
541 SK_ABORT("Unknown resolve type");
542 }
543 srcImage = rt;
544 } else {
545 srcImage = static_cast<GrVkTexture*>(surface->asTexture());
546 }
547
548 // Set up copy region
549 VkBufferImageCopy region;
550 memset(&region, 0, sizeof(VkBufferImageCopy));
551 region.bufferOffset = offset;
Brian Salomon26de56e2019-04-10 12:14:26 -0400552 region.bufferRowLength = width;
Brian Salomona585fe92019-04-09 14:57:00 -0400553 region.bufferImageHeight = 0;
554 region.imageSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
555 region.imageOffset = { left, top, 0 };
556 region.imageExtent = { (uint32_t)width, (uint32_t)height, 1 };
557
558 srcImage->setImageLayout(this,
559 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
560 VK_ACCESS_TRANSFER_READ_BIT,
561 VK_PIPELINE_STAGE_TRANSFER_BIT,
562 false);
563
564 fCurrentCmdBuffer->copyImageToBuffer(this, srcImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
565 vkBuffer, 1, &region);
566
567 // Make sure the copy to buffer has finished.
568 vkBuffer->addMemoryBarrier(this,
569 VK_ACCESS_TRANSFER_WRITE_BIT,
570 VK_ACCESS_HOST_READ_BIT,
571 VK_PIPELINE_STAGE_TRANSFER_BIT,
572 VK_PIPELINE_STAGE_HOST_BIT,
573 false);
574
575 // The caller is responsible for syncing.
576 this->submitCommandBuffer(kSkip_SyncQueue);
577
Brian Salomon26de56e2019-04-10 12:14:26 -0400578 return true;
Brian Salomona585fe92019-04-09 14:57:00 -0400579}
580
Brian Salomon1fabd512018-02-09 09:54:25 -0500581void GrVkGpu::resolveImage(GrSurface* dst, GrVkRenderTarget* src, const SkIRect& srcRect,
582 const SkIPoint& dstPoint) {
egdaniel4bcd62e2016-08-31 07:37:31 -0700583 SkASSERT(dst);
584 SkASSERT(src && src->numColorSamples() > 1 && src->msaaImage());
585
egdaniel4bcd62e2016-08-31 07:37:31 -0700586 VkImageResolve resolveInfo;
Brian Salomon1fabd512018-02-09 09:54:25 -0500587 resolveInfo.srcSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1};
588 resolveInfo.srcOffset = {srcRect.fLeft, srcRect.fTop, 0};
589 resolveInfo.dstSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1};
590 resolveInfo.dstOffset = {dstPoint.fX, dstPoint.fY, 0};
591 resolveInfo.extent = {(uint32_t)srcRect.width(), (uint32_t)srcRect.height(), 1};
egdaniel4bcd62e2016-08-31 07:37:31 -0700592
Greg Danielbc26c392017-04-18 13:32:10 -0400593 GrVkImage* dstImage;
594 GrRenderTarget* dstRT = dst->asRenderTarget();
595 if (dstRT) {
596 GrVkRenderTarget* vkRT = static_cast<GrVkRenderTarget*>(dstRT);
Greg Danielbc26c392017-04-18 13:32:10 -0400597 dstImage = vkRT;
598 } else {
599 SkASSERT(dst->asTexture());
600 dstImage = static_cast<GrVkTexture*>(dst->asTexture());
601 }
602 dstImage->setImageLayout(this,
603 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
604 VK_ACCESS_TRANSFER_WRITE_BIT,
605 VK_PIPELINE_STAGE_TRANSFER_BIT,
606 false);
egdaniel4bcd62e2016-08-31 07:37:31 -0700607
608 src->msaaImage()->setImageLayout(this,
609 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
610 VK_ACCESS_TRANSFER_READ_BIT,
611 VK_PIPELINE_STAGE_TRANSFER_BIT,
612 false);
613
Greg Danielbc26c392017-04-18 13:32:10 -0400614 fCurrentCmdBuffer->resolveImage(this, *src->msaaImage(), *dstImage, 1, &resolveInfo);
egdaniel4bcd62e2016-08-31 07:37:31 -0700615}
616
Brian Salomon1fabd512018-02-09 09:54:25 -0500617void GrVkGpu::internalResolveRenderTarget(GrRenderTarget* target, bool requiresSubmit) {
egdaniel66933552016-08-24 07:22:19 -0700618 if (target->needsResolve()) {
619 SkASSERT(target->numColorSamples() > 1);
egdaniel52ad2512016-08-04 12:50:01 -0700620 GrVkRenderTarget* rt = static_cast<GrVkRenderTarget*>(target);
621 SkASSERT(rt->msaaImage());
Greg Daniel69d49922017-02-23 09:44:02 -0500622
egdaniel4bcd62e2016-08-31 07:37:31 -0700623 const SkIRect& srcRect = rt->getResolveRect();
egdaniel52ad2512016-08-04 12:50:01 -0700624
Brian Salomon1fabd512018-02-09 09:54:25 -0500625 this->resolveImage(target, rt, srcRect, SkIPoint::Make(srcRect.fLeft, srcRect.fTop));
egdaniel52ad2512016-08-04 12:50:01 -0700626
627 rt->flagAsResolved();
Greg Daniel69d49922017-02-23 09:44:02 -0500628
629 if (requiresSubmit) {
630 this->submitCommandBuffer(kSkip_SyncQueue);
631 }
egdaniel52ad2512016-08-04 12:50:01 -0700632 }
633}
634
Brian Salomona9b04b92018-06-01 15:04:28 -0400635bool GrVkGpu::uploadTexDataLinear(GrVkTexture* tex, int left, int top, int width, int height,
636 GrColorType dataColorType, const void* data, size_t rowBytes) {
Greg Daniel164a9f02016-02-22 09:56:40 -0500637 SkASSERT(data);
jvanverth900bd4a2016-04-29 13:53:12 -0700638 SkASSERT(tex->isLinearTiled());
Greg Daniel164a9f02016-02-22 09:56:40 -0500639
Jim Van Verth1676cb92019-01-15 13:24:45 -0500640 // If we're uploading compressed data then we should be using uploadCompressedTexData
641 SkASSERT(!GrPixelConfigIsCompressed(GrColorTypeToPixelConfig(dataColorType,
642 GrSRGBEncoded::kNo)));
643
Greg Daniel660cc992017-06-26 14:55:05 -0400644 SkDEBUGCODE(
645 SkIRect subRect = SkIRect::MakeXYWH(left, top, width, height);
646 SkIRect bounds = SkIRect::MakeWH(tex->width(), tex->height());
647 SkASSERT(bounds.contains(subRect));
648 )
Brian Salomonc320b152018-02-20 14:05:36 -0500649 int bpp = GrColorTypeBytesPerPixel(dataColorType);
Greg Daniel164a9f02016-02-22 09:56:40 -0500650 size_t trimRowBytes = width * bpp;
Greg Daniel660cc992017-06-26 14:55:05 -0400651 if (!rowBytes) {
652 rowBytes = trimRowBytes;
653 }
Greg Daniel164a9f02016-02-22 09:56:40 -0500654
jvanverth900bd4a2016-04-29 13:53:12 -0700655 SkASSERT(VK_IMAGE_LAYOUT_PREINITIALIZED == tex->currentLayout() ||
656 VK_IMAGE_LAYOUT_GENERAL == tex->currentLayout());
657 const VkImageSubresource subres = {
658 VK_IMAGE_ASPECT_COLOR_BIT,
659 0, // mipLevel
660 0, // arraySlice
661 };
662 VkSubresourceLayout layout;
Greg Daniel164a9f02016-02-22 09:56:40 -0500663
jvanverth900bd4a2016-04-29 13:53:12 -0700664 const GrVkInterface* interface = this->vkInterface();
Greg Daniel164a9f02016-02-22 09:56:40 -0500665
jvanverth900bd4a2016-04-29 13:53:12 -0700666 GR_VK_CALL(interface, GetImageSubresourceLayout(fDevice,
egdanielb2df0c22016-05-13 11:30:37 -0700667 tex->image(),
jvanverth900bd4a2016-04-29 13:53:12 -0700668 &subres,
669 &layout));
Greg Daniel164a9f02016-02-22 09:56:40 -0500670
jvanverth1e305ba2016-06-01 09:39:15 -0700671 const GrVkAlloc& alloc = tex->alloc();
Brian Salomona9b04b92018-06-01 15:04:28 -0400672 VkDeviceSize offset = top * layout.rowPitch + left * bpp;
jvanverth900bd4a2016-04-29 13:53:12 -0700673 VkDeviceSize size = height*layout.rowPitch;
Greg Daniel81df0412018-05-31 13:13:33 -0400674 SkASSERT(size + offset <= alloc.fSize);
675 void* mapPtr = GrVkMemory::MapAlloc(this, alloc);
676 if (!mapPtr) {
jvanverth900bd4a2016-04-29 13:53:12 -0700677 return false;
678 }
Greg Daniel81df0412018-05-31 13:13:33 -0400679 mapPtr = reinterpret_cast<char*>(mapPtr) + offset;
jvanverth900bd4a2016-04-29 13:53:12 -0700680
Brian Salomona9b04b92018-06-01 15:04:28 -0400681 SkRectMemcpy(mapPtr, static_cast<size_t>(layout.rowPitch), data, rowBytes, trimRowBytes,
682 height);
jvanverth900bd4a2016-04-29 13:53:12 -0700683
Greg Daniele35a99e2018-03-02 11:44:22 -0500684 GrVkMemory::FlushMappedAlloc(this, alloc, offset, size);
Greg Daniel81df0412018-05-31 13:13:33 -0400685 GrVkMemory::UnmapAlloc(this, alloc);
jvanverth900bd4a2016-04-29 13:53:12 -0700686
687 return true;
688}
689
Brian Salomona9b04b92018-06-01 15:04:28 -0400690bool GrVkGpu::uploadTexDataOptimal(GrVkTexture* tex, int left, int top, int width, int height,
691 GrColorType dataColorType, const GrMipLevel texels[],
692 int mipLevelCount) {
jvanverth900bd4a2016-04-29 13:53:12 -0700693 SkASSERT(!tex->isLinearTiled());
694 // The assumption is either that we have no mipmaps, or that our rect is the entire texture
Robert Phillips590533f2017-07-11 14:22:35 -0400695 SkASSERT(1 == mipLevelCount ||
jvanverth900bd4a2016-04-29 13:53:12 -0700696 (0 == left && 0 == top && width == tex->width() && height == tex->height()));
697
Greg Danieldd20e912017-04-07 14:42:23 -0400698 // We assume that if the texture has mip levels, we either upload to all the levels or just the
699 // first.
Robert Phillips590533f2017-07-11 14:22:35 -0400700 SkASSERT(1 == mipLevelCount || mipLevelCount == (tex->texturePriv().maxMipMapLevel() + 1));
Greg Danieldd20e912017-04-07 14:42:23 -0400701
Jim Van Verth1676cb92019-01-15 13:24:45 -0500702 // If we're uploading compressed data then we should be using uploadCompressedTexData
703 SkASSERT(!GrPixelConfigIsCompressed(GrColorTypeToPixelConfig(dataColorType,
704 GrSRGBEncoded::kNo)));
705
jvanverth900bd4a2016-04-29 13:53:12 -0700706 if (width == 0 || height == 0) {
707 return false;
708 }
709
Greg Daniel475eb702018-09-28 14:16:50 -0400710 if (GrPixelConfigToColorType(tex->config()) != dataColorType) {
711 return false;
712 }
713
714 // For RGB_888x src data we are uploading it first to an RGBA texture and then copying it to the
715 // dst RGB texture. Thus we do not upload mip levels for that.
Greg Danielf259b8b2019-02-14 09:03:43 -0500716 if (dataColorType == GrColorType::kRGB_888x && tex->imageFormat() == VK_FORMAT_R8G8B8_UNORM) {
717 SkASSERT(tex->config() == kRGB_888_GrPixelConfig);
Greg Daniel475eb702018-09-28 14:16:50 -0400718 // First check that we'll be able to do the copy to the to the R8G8B8 image in the end via a
719 // blit or draw.
Greg Danielcaa795f2019-05-14 11:54:25 -0400720 if (!this->vkCaps().formatCanBeDstofBlit(VK_FORMAT_R8G8B8_UNORM, tex->isLinearTiled()) &&
Greg Daniel475eb702018-09-28 14:16:50 -0400721 !this->vkCaps().maxRenderTargetSampleCount(kRGB_888_GrPixelConfig)) {
722 return false;
723 }
724 mipLevelCount = 1;
725 }
726
Brian Salomond1eaf492017-05-18 10:02:08 -0400727 SkASSERT(this->caps()->isConfigTexturable(tex->config()));
Brian Salomonc320b152018-02-20 14:05:36 -0500728 int bpp = GrColorTypeBytesPerPixel(dataColorType);
jvanverth900bd4a2016-04-29 13:53:12 -0700729
730 // texels is const.
jvanverthc578b0632016-05-02 10:58:12 -0700731 // But we may need to adjust the fPixels ptr based on the copyRect, or fRowBytes.
732 // Because of this we need to make a non-const shallow copy of texels.
Robert Phillips0f992772017-07-12 08:24:56 -0400733 SkAutoTMalloc<GrMipLevel> texelsShallowCopy;
734
Greg Daniel475eb702018-09-28 14:16:50 -0400735 texelsShallowCopy.reset(mipLevelCount);
736 memcpy(texelsShallowCopy.get(), texels, mipLevelCount*sizeof(GrMipLevel));
jvanverth900bd4a2016-04-29 13:53:12 -0700737
Robert Phillips590533f2017-07-11 14:22:35 -0400738 SkTArray<size_t> individualMipOffsets(mipLevelCount);
jvanverthc578b0632016-05-02 10:58:12 -0700739 individualMipOffsets.push_back(0);
740 size_t combinedBufferSize = width * bpp * height;
741 int currentWidth = width;
742 int currentHeight = height;
Greg Daniel475eb702018-09-28 14:16:50 -0400743 if (!texelsShallowCopy[0].fPixels) {
Greg Daniel55afd6d2017-09-29 09:32:44 -0400744 combinedBufferSize = 0;
745 }
746
Greg Daniel468fd632017-03-22 17:03:45 -0400747 // The alignment must be at least 4 bytes and a multiple of the bytes per pixel of the image
748 // config. This works with the assumption that the bytes in pixel config is always a power of 2.
749 SkASSERT((bpp & (bpp - 1)) == 0);
750 const size_t alignmentMask = 0x3 | (bpp - 1);
Robert Phillips590533f2017-07-11 14:22:35 -0400751 for (int currentMipLevel = 1; currentMipLevel < mipLevelCount; currentMipLevel++) {
jvanverthc578b0632016-05-02 10:58:12 -0700752 currentWidth = SkTMax(1, currentWidth/2);
753 currentHeight = SkTMax(1, currentHeight/2);
Greg Daniel660cc992017-06-26 14:55:05 -0400754
Greg Daniel55afd6d2017-09-29 09:32:44 -0400755 if (texelsShallowCopy[currentMipLevel].fPixels) {
756 const size_t trimmedSize = currentWidth * bpp * currentHeight;
757 const size_t alignmentDiff = combinedBufferSize & alignmentMask;
758 if (alignmentDiff != 0) {
759 combinedBufferSize += alignmentMask - alignmentDiff + 1;
760 }
761 individualMipOffsets.push_back(combinedBufferSize);
762 combinedBufferSize += trimmedSize;
763 } else {
764 individualMipOffsets.push_back(0);
Greg Daniel468fd632017-03-22 17:03:45 -0400765 }
Greg Daniel55afd6d2017-09-29 09:32:44 -0400766 }
767 if (0 == combinedBufferSize) {
768 // We don't actually have any data to upload so just return success
769 return true;
jvanverth900bd4a2016-04-29 13:53:12 -0700770 }
771
772 // allocate buffer to hold our mip data
Brian Salomon12d22642019-01-29 14:38:50 -0500773 sk_sp<GrVkTransferBuffer> transferBuffer =
774 GrVkTransferBuffer::Make(this, combinedBufferSize, GrVkBuffer::kCopyRead_Type);
Greg Daniel475eb702018-09-28 14:16:50 -0400775 if (!transferBuffer) {
Forrest Reilingc04f8452017-04-26 19:26:12 -0700776 return false;
Greg Daniel6888c0d2017-08-25 11:55:50 -0400777 }
jvanverth900bd4a2016-04-29 13:53:12 -0700778
Greg Daniel475eb702018-09-28 14:16:50 -0400779 int uploadLeft = left;
780 int uploadTop = top;
781 GrVkTexture* uploadTexture = tex;
782 // For uploading RGB_888x data to an R8G8B8_UNORM texture we must first upload the data to an
783 // R8G8B8A8_UNORM image and then copy it.
784 sk_sp<GrVkTexture> copyTexture;
Greg Danielf259b8b2019-02-14 09:03:43 -0500785 if (dataColorType == GrColorType::kRGB_888x && tex->imageFormat() == VK_FORMAT_R8G8B8_UNORM) {
Greg Daniel475eb702018-09-28 14:16:50 -0400786 GrSurfaceDesc surfDesc;
787 surfDesc.fFlags = kRenderTarget_GrSurfaceFlag;
788 surfDesc.fWidth = width;
789 surfDesc.fHeight = height;
790 surfDesc.fConfig = kRGBA_8888_GrPixelConfig;
791 surfDesc.fSampleCnt = 1;
792
793 VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_SAMPLED_BIT |
794 VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
795 VK_IMAGE_USAGE_TRANSFER_DST_BIT;
796
797 GrVkImage::ImageDesc imageDesc;
798 imageDesc.fImageType = VK_IMAGE_TYPE_2D;
799 imageDesc.fFormat = VK_FORMAT_R8G8B8A8_UNORM;
800 imageDesc.fWidth = width;
801 imageDesc.fHeight = height;
802 imageDesc.fLevels = 1;
803 imageDesc.fSamples = 1;
804 imageDesc.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
805 imageDesc.fUsageFlags = usageFlags;
806 imageDesc.fMemProps = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
807
808 copyTexture = GrVkTexture::MakeNewTexture(this, SkBudgeted::kYes, surfDesc, imageDesc,
809 GrMipMapsStatus::kNotAllocated);
810 if (!copyTexture) {
811 return false;
812 }
Greg Daniel5c7b5412019-05-10 11:39:55 -0400813
814 bool dstHasYcbcr = tex->ycbcrConversionInfo().isValid();
815 if (!this->vkCaps().canCopyAsBlit(tex->config(), 1, false, dstHasYcbcr,
816 copyTexture->config(), 1, false,
817 false) &&
818 !this->vkCaps().canCopyAsDraw(tex->config(), SkToBool(tex->asRenderTarget()),
819 dstHasYcbcr,
820 copyTexture->config(), true, false)) {
821 return false;
822 }
823
Greg Daniel475eb702018-09-28 14:16:50 -0400824 uploadTexture = copyTexture.get();
825 uploadLeft = 0;
826 uploadTop = 0;
827 }
828
jvanverth900bd4a2016-04-29 13:53:12 -0700829 char* buffer = (char*) transferBuffer->map();
Robert Phillips590533f2017-07-11 14:22:35 -0400830 SkTArray<VkBufferImageCopy> regions(mipLevelCount);
jvanverth900bd4a2016-04-29 13:53:12 -0700831
jvanverthc578b0632016-05-02 10:58:12 -0700832 currentWidth = width;
833 currentHeight = height;
Greg Daniel475eb702018-09-28 14:16:50 -0400834 int layerHeight = uploadTexture->height();
Robert Phillips590533f2017-07-11 14:22:35 -0400835 for (int currentMipLevel = 0; currentMipLevel < mipLevelCount; currentMipLevel++) {
Greg Daniel55afd6d2017-09-29 09:32:44 -0400836 if (texelsShallowCopy[currentMipLevel].fPixels) {
837 SkASSERT(1 == mipLevelCount || currentHeight == layerHeight);
838 const size_t trimRowBytes = currentWidth * bpp;
839 const size_t rowBytes = texelsShallowCopy[currentMipLevel].fRowBytes
840 ? texelsShallowCopy[currentMipLevel].fRowBytes
841 : trimRowBytes;
jvanverth900bd4a2016-04-29 13:53:12 -0700842
Greg Daniel55afd6d2017-09-29 09:32:44 -0400843 // copy data into the buffer, skipping the trailing bytes
844 char* dst = buffer + individualMipOffsets[currentMipLevel];
845 const char* src = (const char*)texelsShallowCopy[currentMipLevel].fPixels;
Brian Salomona9b04b92018-06-01 15:04:28 -0400846 SkRectMemcpy(dst, trimRowBytes, src, rowBytes, trimRowBytes, currentHeight);
Greg Daniel55afd6d2017-09-29 09:32:44 -0400847
848 VkBufferImageCopy& region = regions.push_back();
849 memset(&region, 0, sizeof(VkBufferImageCopy));
850 region.bufferOffset = transferBuffer->offset() + individualMipOffsets[currentMipLevel];
851 region.bufferRowLength = currentWidth;
852 region.bufferImageHeight = currentHeight;
853 region.imageSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, SkToU32(currentMipLevel), 0, 1 };
Greg Daniel475eb702018-09-28 14:16:50 -0400854 region.imageOffset = {uploadLeft, uploadTop, 0};
Greg Daniel55afd6d2017-09-29 09:32:44 -0400855 region.imageExtent = { (uint32_t)currentWidth, (uint32_t)currentHeight, 1 };
jvanverth900bd4a2016-04-29 13:53:12 -0700856 }
jvanverthc578b0632016-05-02 10:58:12 -0700857 currentWidth = SkTMax(1, currentWidth/2);
858 currentHeight = SkTMax(1, currentHeight/2);
Greg Daniela1b282b2017-03-28 14:56:46 -0400859 layerHeight = currentHeight;
jvanverth900bd4a2016-04-29 13:53:12 -0700860 }
861
jvanverth9d54afc2016-09-20 09:20:03 -0700862 // no need to flush non-coherent memory, unmap will do that for us
jvanverth900bd4a2016-04-29 13:53:12 -0700863 transferBuffer->unmap();
864
jvanverth900bd4a2016-04-29 13:53:12 -0700865 // Change layout of our target so it can be copied to
Greg Daniel475eb702018-09-28 14:16:50 -0400866 uploadTexture->setImageLayout(this,
867 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
868 VK_ACCESS_TRANSFER_WRITE_BIT,
869 VK_PIPELINE_STAGE_TRANSFER_BIT,
870 false);
jvanverth900bd4a2016-04-29 13:53:12 -0700871
872 // Copy the buffer to the image
873 fCurrentCmdBuffer->copyBufferToImage(this,
Brian Salomon12d22642019-01-29 14:38:50 -0500874 transferBuffer.get(),
Greg Daniel475eb702018-09-28 14:16:50 -0400875 uploadTexture,
jvanverth900bd4a2016-04-29 13:53:12 -0700876 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
877 regions.count(),
878 regions.begin());
Greg Daniel475eb702018-09-28 14:16:50 -0400879
880 // If we copied the data into a temporary image first, copy that image into our main texture
881 // now.
882 if (copyTexture.get()) {
883 SkASSERT(dataColorType == GrColorType::kRGB_888x);
884 static const GrSurfaceOrigin kOrigin = kTopLeft_GrSurfaceOrigin;
885 SkAssertResult(this->copySurface(tex, kOrigin, copyTexture.get(), kOrigin,
886 SkIRect::MakeWH(width, height), SkIPoint::Make(left, top),
887 false));
888 }
Robert Phillips590533f2017-07-11 14:22:35 -0400889 if (1 == mipLevelCount) {
Greg Daniel0fc4d2d2017-10-12 11:23:36 -0400890 tex->texturePriv().markMipMapsDirty();
Greg Danieldd20e912017-04-07 14:42:23 -0400891 }
jvanverth900bd4a2016-04-29 13:53:12 -0700892
Greg Daniel164a9f02016-02-22 09:56:40 -0500893 return true;
894}
895
Jim Van Verth1676cb92019-01-15 13:24:45 -0500896// It's probably possible to roll this into uploadTexDataOptimal,
897// but for now it's easier to maintain as a separate entity.
898bool GrVkGpu::uploadTexDataCompressed(GrVkTexture* tex, int left, int top, int width, int height,
899 GrColorType dataColorType, const GrMipLevel texels[],
900 int mipLevelCount) {
901 SkASSERT(!tex->isLinearTiled());
902 // For now the assumption is that our rect is the entire texture.
903 // Compressed textures are read-only so this should be a reasonable assumption.
904 SkASSERT(0 == left && 0 == top && width == tex->width() && height == tex->height());
905
906 // We assume that if the texture has mip levels, we either upload to all the levels or just the
907 // first.
908 SkASSERT(1 == mipLevelCount || mipLevelCount == (tex->texturePriv().maxMipMapLevel() + 1));
909
910 SkASSERT(GrPixelConfigIsCompressed(GrColorTypeToPixelConfig(dataColorType,
911 GrSRGBEncoded::kNo)));
912
913 if (width == 0 || height == 0) {
914 return false;
915 }
916
917 if (GrPixelConfigToColorType(tex->config()) != dataColorType) {
918 return false;
919 }
920
921 SkASSERT(this->caps()->isConfigTexturable(tex->config()));
922
923 SkTArray<size_t> individualMipOffsets(mipLevelCount);
924 individualMipOffsets.push_back(0);
925 size_t combinedBufferSize = GrCompressedFormatDataSize(tex->config(), width, height);
926 int currentWidth = width;
927 int currentHeight = height;
928 if (!texels[0].fPixels) {
929 return false;
930 }
931
932 // We assume that the alignment for any compressed format is at least 4 bytes and so we don't
933 // need to worry about alignment issues. For example, each block in ETC1 is 8 bytes.
934 for (int currentMipLevel = 1; currentMipLevel < mipLevelCount; currentMipLevel++) {
935 currentWidth = SkTMax(1, currentWidth / 2);
936 currentHeight = SkTMax(1, currentHeight / 2);
937
938 if (texels[currentMipLevel].fPixels) {
939 const size_t dataSize = GrCompressedFormatDataSize(tex->config(), currentWidth,
940 currentHeight);
941 individualMipOffsets.push_back(combinedBufferSize);
942 combinedBufferSize += dataSize;
943 } else {
944 return false;
945 }
946 }
947 if (0 == combinedBufferSize) {
948 // We don't have any data to upload so fail (compressed textures are read-only).
949 return false;
950 }
951
952 // allocate buffer to hold our mip data
Brian Salomon12d22642019-01-29 14:38:50 -0500953 sk_sp<GrVkTransferBuffer> transferBuffer =
954 GrVkTransferBuffer::Make(this, combinedBufferSize, GrVkBuffer::kCopyRead_Type);
Jim Van Verth1676cb92019-01-15 13:24:45 -0500955 if (!transferBuffer) {
956 return false;
957 }
958
959 int uploadLeft = left;
960 int uploadTop = top;
961 GrVkTexture* uploadTexture = tex;
962
963 char* buffer = (char*)transferBuffer->map();
964 SkTArray<VkBufferImageCopy> regions(mipLevelCount);
965
966 currentWidth = width;
967 currentHeight = height;
968 int layerHeight = uploadTexture->height();
969 for (int currentMipLevel = 0; currentMipLevel < mipLevelCount; currentMipLevel++) {
970 if (texels[currentMipLevel].fPixels) {
971 // Again, we're assuming that our rect is the entire texture
972 SkASSERT(currentHeight == layerHeight);
973 SkASSERT(0 == uploadLeft && 0 == uploadTop);
974
975 const size_t dataSize = GrCompressedFormatDataSize(tex->config(), currentWidth,
976 currentHeight);
977
978 // copy data into the buffer, skipping the trailing bytes
979 char* dst = buffer + individualMipOffsets[currentMipLevel];
980 const char* src = (const char*)texels[currentMipLevel].fPixels;
981 memcpy(dst, src, dataSize);
982
983 VkBufferImageCopy& region = regions.push_back();
984 memset(&region, 0, sizeof(VkBufferImageCopy));
985 region.bufferOffset = transferBuffer->offset() + individualMipOffsets[currentMipLevel];
986 region.bufferRowLength = currentWidth;
987 region.bufferImageHeight = currentHeight;
988 region.imageSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, SkToU32(currentMipLevel), 0, 1 };
989 region.imageOffset = { uploadLeft, uploadTop, 0 };
990 region.imageExtent = { (uint32_t)currentWidth, (uint32_t)currentHeight, 1 };
991 }
992 currentWidth = SkTMax(1, currentWidth / 2);
993 currentHeight = SkTMax(1, currentHeight / 2);
994 layerHeight = currentHeight;
995 }
996
997 // no need to flush non-coherent memory, unmap will do that for us
998 transferBuffer->unmap();
999
1000 // Change layout of our target so it can be copied to
1001 uploadTexture->setImageLayout(this,
1002 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1003 VK_ACCESS_TRANSFER_WRITE_BIT,
1004 VK_PIPELINE_STAGE_TRANSFER_BIT,
1005 false);
1006
1007 // Copy the buffer to the image
1008 fCurrentCmdBuffer->copyBufferToImage(this,
Brian Salomon12d22642019-01-29 14:38:50 -05001009 transferBuffer.get(),
Jim Van Verth1676cb92019-01-15 13:24:45 -05001010 uploadTexture,
1011 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1012 regions.count(),
1013 regions.begin());
Jim Van Verth1676cb92019-01-15 13:24:45 -05001014
1015 if (1 == mipLevelCount) {
1016 tex->texturePriv().markMipMapsDirty();
1017 }
1018
1019 return true;
1020}
1021
Greg Daniel164a9f02016-02-22 09:56:40 -05001022////////////////////////////////////////////////////////////////////////////////
Robert Phillips67d52cf2017-06-05 13:38:13 -04001023sk_sp<GrTexture> GrVkGpu::onCreateTexture(const GrSurfaceDesc& desc, SkBudgeted budgeted,
Brian Salomon58389b92018-03-07 13:01:25 -05001024 const GrMipLevel texels[], int mipLevelCount) {
Greg Daniel164a9f02016-02-22 09:56:40 -05001025 bool renderTarget = SkToBool(desc.fFlags & kRenderTarget_GrSurfaceFlag);
1026
1027 VkFormat pixelFormat;
Brian Salomonbdecacf2018-02-02 20:32:49 -05001028 SkAssertResult(GrPixelConfigToVkFormat(desc.fConfig, &pixelFormat));
egdaniel0a3a7f72016-06-24 09:22:31 -07001029
Greg Daniel164a9f02016-02-22 09:56:40 -05001030 VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_SAMPLED_BIT;
1031 if (renderTarget) {
1032 usageFlags |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
1033 }
1034
1035 // For now we will set the VK_IMAGE_USAGE_TRANSFER_DESTINATION_BIT and
1036 // VK_IMAGE_USAGE_TRANSFER_SOURCE_BIT on every texture since we do not know whether or not we
1037 // will be using this texture in some copy or not. Also this assumes, as is the current case,
jvanverth62340062016-04-26 08:01:44 -07001038 // that all render targets in vulkan are also textures. If we change this practice of setting
Greg Daniel164a9f02016-02-22 09:56:40 -05001039 // both bits, we must make sure to set the destination bit if we are uploading srcData to the
1040 // texture.
1041 usageFlags |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
1042
Greg Daniel164a9f02016-02-22 09:56:40 -05001043 // This ImageDesc refers to the texture that will be read by the client. Thus even if msaa is
jvanverth62340062016-04-26 08:01:44 -07001044 // requested, this ImageDesc describes the resolved texture. Therefore we always have samples set
Greg Daniel164a9f02016-02-22 09:56:40 -05001045 // to 1.
Robert Phillips590533f2017-07-11 14:22:35 -04001046 int mipLevels = !mipLevelCount ? 1 : mipLevelCount;
Greg Daniel164a9f02016-02-22 09:56:40 -05001047 GrVkImage::ImageDesc imageDesc;
1048 imageDesc.fImageType = VK_IMAGE_TYPE_2D;
1049 imageDesc.fFormat = pixelFormat;
1050 imageDesc.fWidth = desc.fWidth;
1051 imageDesc.fHeight = desc.fHeight;
Brian Salomon7128fdd2017-05-22 14:00:07 -04001052 imageDesc.fLevels = mipLevels;
Greg Daniel164a9f02016-02-22 09:56:40 -05001053 imageDesc.fSamples = 1;
Brian Salomon7128fdd2017-05-22 14:00:07 -04001054 imageDesc.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
Greg Daniel164a9f02016-02-22 09:56:40 -05001055 imageDesc.fUsageFlags = usageFlags;
Brian Salomon7128fdd2017-05-22 14:00:07 -04001056 imageDesc.fMemProps = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
Greg Daniel164a9f02016-02-22 09:56:40 -05001057
Greg Daniel0fc4d2d2017-10-12 11:23:36 -04001058 GrMipMapsStatus mipMapsStatus = GrMipMapsStatus::kNotAllocated;
1059 if (mipLevels > 1) {
1060 mipMapsStatus = GrMipMapsStatus::kValid;
1061 for (int i = 0; i < mipLevels; ++i) {
1062 if (!texels[i].fPixels) {
1063 mipMapsStatus = GrMipMapsStatus::kDirty;
1064 break;
1065 }
Greg Daniel834f1202017-10-09 15:06:20 -04001066 }
1067 }
1068
Robert Phillips67d52cf2017-06-05 13:38:13 -04001069 sk_sp<GrVkTexture> tex;
Greg Daniel164a9f02016-02-22 09:56:40 -05001070 if (renderTarget) {
Greg Daniel475eb702018-09-28 14:16:50 -04001071 tex = GrVkTextureRenderTarget::MakeNewTextureRenderTarget(this, budgeted, desc,
1072 imageDesc,
1073 mipMapsStatus);
Greg Daniel164a9f02016-02-22 09:56:40 -05001074 } else {
Greg Daniel475eb702018-09-28 14:16:50 -04001075 tex = GrVkTexture::MakeNewTexture(this, budgeted, desc, imageDesc, mipMapsStatus);
Greg Daniel164a9f02016-02-22 09:56:40 -05001076 }
1077
1078 if (!tex) {
1079 return nullptr;
1080 }
1081
Jim Van Verth1676cb92019-01-15 13:24:45 -05001082 bool isCompressed = GrPixelConfigIsCompressed(desc.fConfig);
Brian Salomonc320b152018-02-20 14:05:36 -05001083 auto colorType = GrPixelConfigToColorType(desc.fConfig);
Robert Phillips590533f2017-07-11 14:22:35 -04001084 if (mipLevelCount) {
Jim Van Verth1676cb92019-01-15 13:24:45 -05001085 bool success;
1086 if (isCompressed) {
1087 success = this->uploadTexDataCompressed(tex.get(), 0, 0, desc.fWidth, desc.fHeight,
1088 colorType, texels, mipLevelCount);
1089 } else {
1090 success = this->uploadTexDataOptimal(tex.get(), 0, 0, desc.fWidth, desc.fHeight,
1091 colorType, texels, mipLevelCount);
1092 }
1093 if (!success) {
Greg Daniel164a9f02016-02-22 09:56:40 -05001094 tex->unref();
1095 return nullptr;
1096 }
1097 }
1098
Jim Van Verth1676cb92019-01-15 13:24:45 -05001099 if (SkToBool(desc.fFlags & kPerformInitialClear_GrSurfaceFlag) && !isCompressed) {
Brian Salomond17b4a62017-05-23 16:53:47 -04001100 VkClearColorValue zeroClearColor;
1101 memset(&zeroClearColor, 0, sizeof(zeroClearColor));
1102 VkImageSubresourceRange range;
1103 range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1104 range.baseArrayLayer = 0;
1105 range.baseMipLevel = 0;
1106 range.layerCount = 1;
1107 range.levelCount = 1;
1108 tex->setImageLayout(this, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1109 VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, false);
Robert Phillips67d52cf2017-06-05 13:38:13 -04001110 this->currentCommandBuffer()->clearColorImage(this, tex.get(), &zeroClearColor, 1, &range);
Brian Salomond17b4a62017-05-23 16:53:47 -04001111 }
Ben Wagnerff134f22018-04-24 16:29:16 -04001112 return std::move(tex);
Greg Daniel164a9f02016-02-22 09:56:40 -05001113}
1114
1115////////////////////////////////////////////////////////////////////////////////
1116
Greg Daniel6888c0d2017-08-25 11:55:50 -04001117void GrVkGpu::copyBuffer(GrVkBuffer* srcBuffer, GrVkBuffer* dstBuffer, VkDeviceSize srcOffset,
1118 VkDeviceSize dstOffset, VkDeviceSize size) {
1119 VkBufferCopy copyRegion;
1120 copyRegion.srcOffset = srcOffset;
1121 copyRegion.dstOffset = dstOffset;
1122 copyRegion.size = size;
1123 fCurrentCmdBuffer->copyBuffer(this, srcBuffer, dstBuffer, 1, &copyRegion);
1124}
1125
jvanverthdb379092016-07-07 11:18:46 -07001126bool GrVkGpu::updateBuffer(GrVkBuffer* buffer, const void* src,
1127 VkDeviceSize offset, VkDeviceSize size) {
jvanvertha584de92016-06-30 09:10:52 -07001128 // Update the buffer
jvanverthdb379092016-07-07 11:18:46 -07001129 fCurrentCmdBuffer->updateBuffer(this, buffer, offset, size, src);
jvanvertha584de92016-06-30 09:10:52 -07001130
1131 return true;
1132}
1133
1134////////////////////////////////////////////////////////////////////////////////
1135
Greg Daniel7e000222018-12-03 10:08:21 -05001136static bool check_image_info(const GrVkCaps& caps,
1137 const GrVkImageInfo& info,
Greg Danielcb324152019-02-25 11:36:53 -05001138 GrPixelConfig config,
1139 bool isWrappedRT) {
1140 if (VK_NULL_HANDLE == info.fImage) {
1141 return false;
1142 }
1143
1144 if (VK_NULL_HANDLE == info.fAlloc.fMemory && !isWrappedRT) {
Brian Salomond17f6582017-07-19 18:28:58 -04001145 return false;
Greg Daniel164a9f02016-02-22 09:56:40 -05001146 }
1147
Greg Daniel7e000222018-12-03 10:08:21 -05001148 if (info.fYcbcrConversionInfo.isValid()) {
1149 if (!caps.supportsYcbcrConversion() || info.fFormat != VK_NULL_HANDLE) {
1150 return false;
1151 }
jvanverthfd359ca2016-03-18 11:57:24 -07001152 }
Greg Daniel7ef28f32017-04-20 16:41:55 +00001153
Greg Danielcb324152019-02-25 11:36:53 -05001154 if (info.fImageLayout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR && !caps.supportsSwapchain()) {
1155 return false;
1156 }
1157
Greg Daniel52e16d92018-04-10 09:34:07 -04001158 SkASSERT(GrVkFormatPixelConfigPairIsValid(info.fFormat, config));
Brian Salomond17f6582017-07-19 18:28:58 -04001159 return true;
1160}
1161
Greg Danielcaa795f2019-05-14 11:54:25 -04001162static bool check_tex_image_info(const GrVkCaps& caps, const GrVkImageInfo& info) {
1163 if (info.fImageTiling == VK_IMAGE_TILING_OPTIMAL) {
1164 if (!caps.isConfigTexturable(info.fFormat)) {
1165 return false;
1166 }
1167 } else {
1168 SkASSERT(info.fImageTiling == VK_IMAGE_TILING_LINEAR);
1169 if (!caps.isConfigTexturableLinearly(info.fFormat)) {
1170 return false;
1171 }
1172 }
1173 return true;
1174}
1175
1176static bool check_rt_image_info(const GrVkCaps& caps, const GrVkImageInfo& info) {
1177 if (!caps.maxRenderTargetSampleCount(info.fFormat)) {
1178 return false;
1179 }
1180 return true;
1181}
1182
Brian Salomond17f6582017-07-19 18:28:58 -04001183sk_sp<GrTexture> GrVkGpu::onWrapBackendTexture(const GrBackendTexture& backendTex,
Brian Salomonfa2ebea2019-01-24 15:58:58 -05001184 GrWrapOwnership ownership, GrWrapCacheable cacheable,
1185 GrIOType ioType) {
Greg Daniel7e000222018-12-03 10:08:21 -05001186 GrVkImageInfo imageInfo;
1187 if (!backendTex.getVkImageInfo(&imageInfo)) {
1188 return nullptr;
1189 }
1190
Greg Danielcb324152019-02-25 11:36:53 -05001191 if (!check_image_info(this->vkCaps(), imageInfo, backendTex.config(), false)) {
Brian Salomond17f6582017-07-19 18:28:58 -04001192 return nullptr;
1193 }
Greg Danielcaa795f2019-05-14 11:54:25 -04001194 if (!check_tex_image_info(this->vkCaps(), imageInfo)) {
1195 return nullptr;
1196 }
Greg Daniel164a9f02016-02-22 09:56:40 -05001197
Greg Daniel164a9f02016-02-22 09:56:40 -05001198 GrSurfaceDesc surfDesc;
Brian Salomond17f6582017-07-19 18:28:58 -04001199 surfDesc.fFlags = kNone_GrSurfaceFlags;
Greg Daniel7ef28f32017-04-20 16:41:55 +00001200 surfDesc.fWidth = backendTex.width();
1201 surfDesc.fHeight = backendTex.height();
1202 surfDesc.fConfig = backendTex.config();
Brian Salomonbdecacf2018-02-02 20:32:49 -05001203 surfDesc.fSampleCnt = 1;
Greg Daniel164a9f02016-02-22 09:56:40 -05001204
Greg Daniel52e16d92018-04-10 09:34:07 -04001205 sk_sp<GrVkImageLayout> layout = backendTex.getGrVkImageLayout();
1206 SkASSERT(layout);
Brian Salomonfa2ebea2019-01-24 15:58:58 -05001207 return GrVkTexture::MakeWrappedTexture(this, surfDesc, ownership, cacheable, ioType, imageInfo,
1208 std::move(layout));
Brian Salomond17f6582017-07-19 18:28:58 -04001209}
1210
1211sk_sp<GrTexture> GrVkGpu::onWrapRenderableBackendTexture(const GrBackendTexture& backendTex,
Brian Salomond17f6582017-07-19 18:28:58 -04001212 int sampleCnt,
Brian Salomonaa6ca0a2019-01-24 16:03:07 -05001213 GrWrapOwnership ownership,
1214 GrWrapCacheable cacheable) {
Greg Daniel7e000222018-12-03 10:08:21 -05001215 GrVkImageInfo imageInfo;
1216 if (!backendTex.getVkImageInfo(&imageInfo)) {
1217 return nullptr;
1218 }
1219
Greg Danielcb324152019-02-25 11:36:53 -05001220 if (!check_image_info(this->vkCaps(), imageInfo, backendTex.config(), false)) {
Brian Salomond17f6582017-07-19 18:28:58 -04001221 return nullptr;
Greg Daniel164a9f02016-02-22 09:56:40 -05001222 }
Greg Danielcaa795f2019-05-14 11:54:25 -04001223 if (!check_tex_image_info(this->vkCaps(), imageInfo)) {
1224 return nullptr;
1225 }
1226 if (!check_rt_image_info(this->vkCaps(), imageInfo)) {
1227 return nullptr;
1228 }
Brian Salomond17f6582017-07-19 18:28:58 -04001229
1230 GrSurfaceDesc surfDesc;
1231 surfDesc.fFlags = kRenderTarget_GrSurfaceFlag;
1232 surfDesc.fWidth = backendTex.width();
1233 surfDesc.fHeight = backendTex.height();
1234 surfDesc.fConfig = backendTex.config();
Brian Salomonbdecacf2018-02-02 20:32:49 -05001235 surfDesc.fSampleCnt = this->caps()->getRenderTargetSampleCount(sampleCnt, backendTex.config());
Brian Salomond17f6582017-07-19 18:28:58 -04001236
Greg Daniel52e16d92018-04-10 09:34:07 -04001237 sk_sp<GrVkImageLayout> layout = backendTex.getGrVkImageLayout();
1238 SkASSERT(layout);
1239
Brian Salomonaa6ca0a2019-01-24 16:03:07 -05001240 return GrVkTextureRenderTarget::MakeWrappedTextureRenderTarget(
1241 this, surfDesc, ownership, cacheable, imageInfo, std::move(layout));
Greg Daniel164a9f02016-02-22 09:56:40 -05001242}
1243
Robert Phillipsb0e93a22017-08-29 08:26:54 -04001244sk_sp<GrRenderTarget> GrVkGpu::onWrapBackendRenderTarget(const GrBackendRenderTarget& backendRT){
Greg Daniele79b4732017-04-20 14:07:46 -04001245 // Currently the Vulkan backend does not support wrapping of msaa render targets directly. In
1246 // general this is not an issue since swapchain images in vulkan are never multisampled. Thus if
1247 // you want a multisampled RT it is best to wrap the swapchain images and then let Skia handle
1248 // creating and owning the MSAA images.
Brian Salomonbdecacf2018-02-02 20:32:49 -05001249 if (backendRT.sampleCnt() > 1) {
Greg Daniele79b4732017-04-20 14:07:46 -04001250 return nullptr;
1251 }
halcanary9d524f22016-03-29 09:03:52 -07001252
Greg Daniel323fbcf2018-04-10 13:46:30 -04001253 GrVkImageInfo info;
1254 if (!backendRT.getVkImageInfo(&info)) {
Greg Danielbcf612b2017-05-01 13:50:58 +00001255 return nullptr;
1256 }
Greg Daniel323fbcf2018-04-10 13:46:30 -04001257
Greg Danielcb324152019-02-25 11:36:53 -05001258 if (!check_image_info(this->vkCaps(), info, backendRT.config(), true)) {
jvanverthfd359ca2016-03-18 11:57:24 -07001259 return nullptr;
1260 }
Greg Danielcaa795f2019-05-14 11:54:25 -04001261 if (!check_rt_image_info(this->vkCaps(), info)) {
1262 return nullptr;
1263 }
1264
Greg Daniel164a9f02016-02-22 09:56:40 -05001265
Greg Daniel164a9f02016-02-22 09:56:40 -05001266 GrSurfaceDesc desc;
Brian Salomon0ec981b2017-05-15 13:48:50 -04001267 desc.fFlags = kRenderTarget_GrSurfaceFlag;
Robert Phillips16d8ec62017-07-27 16:16:25 -04001268 desc.fWidth = backendRT.width();
1269 desc.fHeight = backendRT.height();
1270 desc.fConfig = backendRT.config();
Brian Salomonbdecacf2018-02-02 20:32:49 -05001271 desc.fSampleCnt = 1;
Greg Daniel164a9f02016-02-22 09:56:40 -05001272
Greg Daniel323fbcf2018-04-10 13:46:30 -04001273 sk_sp<GrVkImageLayout> layout = backendRT.getGrVkImageLayout();
Greg Daniel52e16d92018-04-10 09:34:07 -04001274
Greg Daniel323fbcf2018-04-10 13:46:30 -04001275 sk_sp<GrVkRenderTarget> tgt = GrVkRenderTarget::MakeWrappedRenderTarget(this, desc, info,
Greg Daniel52e16d92018-04-10 09:34:07 -04001276 std::move(layout));
Brian Salomonafdc6b12018-03-09 12:02:32 -05001277
1278 // We don't allow the client to supply a premade stencil buffer. We always create one if needed.
1279 SkASSERT(!backendRT.stencilBits());
1280 if (tgt) {
1281 SkASSERT(tgt->canAttemptStencilAttachment());
Greg Daniel164a9f02016-02-22 09:56:40 -05001282 }
Brian Salomonafdc6b12018-03-09 12:02:32 -05001283
Ben Wagnerff134f22018-04-24 16:29:16 -04001284 return std::move(tgt);
Greg Daniel164a9f02016-02-22 09:56:40 -05001285}
1286
Greg Daniel7ef28f32017-04-20 16:41:55 +00001287sk_sp<GrRenderTarget> GrVkGpu::onWrapBackendTextureAsRenderTarget(const GrBackendTexture& tex,
Greg Daniel7ef28f32017-04-20 16:41:55 +00001288 int sampleCnt) {
Brian Osman33910292017-04-18 14:38:53 -04001289
Greg Daniel52e16d92018-04-10 09:34:07 -04001290 GrVkImageInfo imageInfo;
1291 if (!tex.getVkImageInfo(&imageInfo)) {
Greg Danielbcf612b2017-05-01 13:50:58 +00001292 return nullptr;
1293 }
Greg Danielcb324152019-02-25 11:36:53 -05001294 if (!check_image_info(this->vkCaps(), imageInfo, tex.config(), false)) {
Brian Osman33910292017-04-18 14:38:53 -04001295 return nullptr;
1296 }
Greg Danielcaa795f2019-05-14 11:54:25 -04001297 if (!check_rt_image_info(this->vkCaps(), imageInfo)) {
1298 return nullptr;
1299 }
Greg Danielcb324152019-02-25 11:36:53 -05001300
Brian Osman33910292017-04-18 14:38:53 -04001301 GrSurfaceDesc desc;
Greg Daniel7ef28f32017-04-20 16:41:55 +00001302 desc.fFlags = kRenderTarget_GrSurfaceFlag;
Greg Daniel7ef28f32017-04-20 16:41:55 +00001303 desc.fWidth = tex.width();
1304 desc.fHeight = tex.height();
Robert Phillips16d8ec62017-07-27 16:16:25 -04001305 desc.fConfig = tex.config();
Brian Salomonbdecacf2018-02-02 20:32:49 -05001306 desc.fSampleCnt = this->caps()->getRenderTargetSampleCount(sampleCnt, tex.config());
1307 if (!desc.fSampleCnt) {
1308 return nullptr;
1309 }
Brian Osman33910292017-04-18 14:38:53 -04001310
Greg Daniel52e16d92018-04-10 09:34:07 -04001311 sk_sp<GrVkImageLayout> layout = tex.getGrVkImageLayout();
1312 SkASSERT(layout);
1313
Ben Wagnerff134f22018-04-24 16:29:16 -04001314 return GrVkRenderTarget::MakeWrappedRenderTarget(this, desc, imageInfo, std::move(layout));
Brian Osman33910292017-04-18 14:38:53 -04001315}
1316
Greg Danielb46add82019-01-02 14:51:29 -05001317sk_sp<GrRenderTarget> GrVkGpu::onWrapVulkanSecondaryCBAsRenderTarget(
1318 const SkImageInfo& imageInfo, const GrVkDrawableInfo& vkInfo) {
1319 int maxSize = this->caps()->maxTextureSize();
1320 if (imageInfo.width() > maxSize || imageInfo.height() > maxSize) {
1321 return nullptr;
1322 }
1323
1324 GrBackendFormat backendFormat = GrBackendFormat::MakeVk(vkInfo.fFormat);
1325 if (!backendFormat.isValid()) {
1326 return nullptr;
1327 }
1328 GrPixelConfig config = this->caps()->getConfigFromBackendFormat(backendFormat,
1329 imageInfo.colorType());
1330 if (config == kUnknown_GrPixelConfig) {
1331 return nullptr;
1332 }
1333
1334 GrSurfaceDesc desc;
1335 desc.fFlags = kRenderTarget_GrSurfaceFlag;
1336 desc.fWidth = imageInfo.width();
1337 desc.fHeight = imageInfo.height();
1338 desc.fConfig = config;
1339 desc.fSampleCnt = this->caps()->getRenderTargetSampleCount(1, config);
1340 if (!desc.fSampleCnt) {
1341 return nullptr;
1342 }
1343
1344 return GrVkRenderTarget::MakeSecondaryCBRenderTarget(this, desc, vkInfo);
1345}
1346
Brian Salomon930f9392018-06-20 16:25:26 -04001347bool GrVkGpu::onRegenerateMipMapLevels(GrTexture* tex) {
1348 auto* vkTex = static_cast<GrVkTexture*>(tex);
jvanverth900bd4a2016-04-29 13:53:12 -07001349 // don't do anything for linearly tiled textures (can't have mipmaps)
Brian Salomon930f9392018-06-20 16:25:26 -04001350 if (vkTex->isLinearTiled()) {
jvanverth900bd4a2016-04-29 13:53:12 -07001351 SkDebugf("Trying to create mipmap for linear tiled texture");
Brian Salomon930f9392018-06-20 16:25:26 -04001352 return false;
jvanverth62340062016-04-26 08:01:44 -07001353 }
1354
jvanverth62340062016-04-26 08:01:44 -07001355 // determine if we can blit to and from this format
1356 const GrVkCaps& caps = this->vkCaps();
Greg Danielcaa795f2019-05-14 11:54:25 -04001357 if (!caps.formatCanBeDstofBlit(vkTex->imageFormat(), false) ||
1358 !caps.formatCanBeSrcofBlit(vkTex->imageFormat(), false) ||
egdaniel2f5792a2016-07-06 08:51:23 -07001359 !caps.mipMapSupport()) {
Brian Salomon930f9392018-06-20 16:25:26 -04001360 return false;
jvanverth62340062016-04-26 08:01:44 -07001361 }
1362
egdaniel7ac5da82016-07-15 13:41:42 -07001363 int width = tex->width();
1364 int height = tex->height();
1365 VkImageBlit blitRegion;
1366 memset(&blitRegion, 0, sizeof(VkImageBlit));
jvanverth62340062016-04-26 08:01:44 -07001367
jvanverth82c05582016-05-03 11:19:01 -07001368 // SkMipMap doesn't include the base level in the level count so we have to add 1
1369 uint32_t levelCount = SkMipMap::ComputeLevelCount(tex->width(), tex->height()) + 1;
Brian Salomon930f9392018-06-20 16:25:26 -04001370 SkASSERT(levelCount == vkTex->mipLevels());
egdaniel7ac5da82016-07-15 13:41:42 -07001371
Greg Danielda86e282018-06-13 09:41:19 -04001372 // change layout of the layers so we can write to them.
Brian Salomon930f9392018-06-20 16:25:26 -04001373 vkTex->setImageLayout(this, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_ACCESS_TRANSFER_WRITE_BIT,
1374 VK_PIPELINE_STAGE_TRANSFER_BIT, false);
jvanverth62340062016-04-26 08:01:44 -07001375
jvanverth50c46c72016-05-06 12:31:28 -07001376 // setup memory barrier
Brian Salomon930f9392018-06-20 16:25:26 -04001377 SkASSERT(GrVkFormatIsSupported(vkTex->imageFormat()));
jvanverth50c46c72016-05-06 12:31:28 -07001378 VkImageAspectFlags aspectFlags = VK_IMAGE_ASPECT_COLOR_BIT;
1379 VkImageMemoryBarrier imageMemoryBarrier = {
Brian Salomon930f9392018-06-20 16:25:26 -04001380 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType
1381 nullptr, // pNext
1382 VK_ACCESS_TRANSFER_WRITE_BIT, // srcAccessMask
1383 VK_ACCESS_TRANSFER_READ_BIT, // dstAccessMask
1384 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // oldLayout
1385 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // newLayout
1386 VK_QUEUE_FAMILY_IGNORED, // srcQueueFamilyIndex
1387 VK_QUEUE_FAMILY_IGNORED, // dstQueueFamilyIndex
1388 vkTex->image(), // image
1389 {aspectFlags, 0, 1, 0, 1} // subresourceRange
jvanverth50c46c72016-05-06 12:31:28 -07001390 };
1391
jvanverth62340062016-04-26 08:01:44 -07001392 // Blit the miplevels
jvanverth82c05582016-05-03 11:19:01 -07001393 uint32_t mipLevel = 1;
1394 while (mipLevel < levelCount) {
1395 int prevWidth = width;
1396 int prevHeight = height;
1397 width = SkTMax(1, width / 2);
1398 height = SkTMax(1, height / 2);
jvanverth62340062016-04-26 08:01:44 -07001399
jvanverth50c46c72016-05-06 12:31:28 -07001400 imageMemoryBarrier.subresourceRange.baseMipLevel = mipLevel - 1;
Greg Daniel59dc1482019-02-22 10:46:38 -05001401 this->addImageMemoryBarrier(vkTex->resource(), VK_PIPELINE_STAGE_TRANSFER_BIT,
1402 VK_PIPELINE_STAGE_TRANSFER_BIT, false, &imageMemoryBarrier);
jvanverth50c46c72016-05-06 12:31:28 -07001403
1404 blitRegion.srcSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, mipLevel - 1, 0, 1 };
jvanverth82c05582016-05-03 11:19:01 -07001405 blitRegion.srcOffsets[0] = { 0, 0, 0 };
brianosmane9906e72016-06-08 12:44:27 -07001406 blitRegion.srcOffsets[1] = { prevWidth, prevHeight, 1 };
jvanverth82c05582016-05-03 11:19:01 -07001407 blitRegion.dstSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, mipLevel, 0, 1 };
1408 blitRegion.dstOffsets[0] = { 0, 0, 0 };
brianosmane9906e72016-06-08 12:44:27 -07001409 blitRegion.dstOffsets[1] = { width, height, 1 };
jvanverth62340062016-04-26 08:01:44 -07001410 fCurrentCmdBuffer->blitImage(this,
Brian Salomon930f9392018-06-20 16:25:26 -04001411 vkTex->resource(),
1412 vkTex->image(),
Greg Daniel31cc7312018-03-05 11:41:06 -05001413 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
Brian Salomon930f9392018-06-20 16:25:26 -04001414 vkTex->resource(),
1415 vkTex->image(),
Greg Daniel31cc7312018-03-05 11:41:06 -05001416 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
jvanverth62340062016-04-26 08:01:44 -07001417 1,
1418 &blitRegion,
1419 VK_FILTER_LINEAR);
jvanverth82c05582016-05-03 11:19:01 -07001420 ++mipLevel;
jvanverth62340062016-04-26 08:01:44 -07001421 }
Greg Danielee54f232019-04-03 14:58:40 -04001422 if (levelCount > 1) {
1423 // This barrier logically is not needed, but it changes the final level to the same layout
1424 // as all the others, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL. This makes tracking of the
1425 // layouts and future layout changes easier. The alternative here would be to track layout
1426 // and memory accesses per layer which doesn't seem work it.
1427 imageMemoryBarrier.subresourceRange.baseMipLevel = mipLevel - 1;
1428 this->addImageMemoryBarrier(vkTex->resource(), VK_PIPELINE_STAGE_TRANSFER_BIT,
1429 VK_PIPELINE_STAGE_TRANSFER_BIT, false, &imageMemoryBarrier);
1430 vkTex->updateImageLayout(VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
1431 }
Brian Salomon930f9392018-06-20 16:25:26 -04001432 return true;
jvanverth62340062016-04-26 08:01:44 -07001433}
1434
Greg Daniel164a9f02016-02-22 09:56:40 -05001435////////////////////////////////////////////////////////////////////////////////
1436
1437GrStencilAttachment* GrVkGpu::createStencilAttachmentForRenderTarget(const GrRenderTarget* rt,
1438 int width,
1439 int height) {
Greg Daniel164a9f02016-02-22 09:56:40 -05001440 SkASSERT(width >= rt->width());
1441 SkASSERT(height >= rt->height());
1442
1443 int samples = rt->numStencilSamples();
1444
Ethan Nicholasf610bae2018-09-20 16:55:21 -04001445 const GrVkCaps::StencilFormat& sFmt = this->vkCaps().preferredStencilFormat();
Greg Daniel164a9f02016-02-22 09:56:40 -05001446
1447 GrVkStencilAttachment* stencil(GrVkStencilAttachment::Create(this,
Greg Daniel164a9f02016-02-22 09:56:40 -05001448 width,
1449 height,
1450 samples,
1451 sFmt));
1452 fStats.incStencilAttachmentCreates();
1453 return stencil;
1454}
1455
1456////////////////////////////////////////////////////////////////////////////////
1457
Brian Salomon52e943a2018-03-13 09:32:39 -04001458bool copy_testing_data(GrVkGpu* gpu, const void* srcData, const GrVkAlloc& alloc,
Robert Phillips646f6372018-09-25 09:31:10 -04001459 size_t bufferOffset, size_t srcRowBytes, size_t dstRowBytes,
1460 size_t trimRowBytes, int h) {
Greg Daniel81df0412018-05-31 13:13:33 -04001461 VkDeviceSize size = dstRowBytes * h;
1462 VkDeviceSize offset = bufferOffset;
1463 SkASSERT(size + offset <= alloc.fSize);
1464 void* mapPtr = GrVkMemory::MapAlloc(gpu, alloc);
1465 if (!mapPtr) {
egdaniel3602d4f2016-08-12 11:58:53 -07001466 return false;
1467 }
Greg Daniel81df0412018-05-31 13:13:33 -04001468 mapPtr = reinterpret_cast<char*>(mapPtr) + offset;
egdaniel3602d4f2016-08-12 11:58:53 -07001469
Greg Daniel20ece3a2017-03-28 10:24:43 -04001470 if (srcData) {
1471 // If there is no padding on dst we can do a single memcopy.
1472 // This assumes the srcData comes in with no padding.
Robert Phillips646f6372018-09-25 09:31:10 -04001473 SkRectMemcpy(mapPtr, dstRowBytes, srcData, srcRowBytes, trimRowBytes, h);
Greg Daniel20ece3a2017-03-28 10:24:43 -04001474 } else {
1475 // If there is no srcdata we always copy 0's into the textures so that it is initialized
1476 // with some data.
Robert Phillips646f6372018-09-25 09:31:10 -04001477 memset(mapPtr, 0, dstRowBytes * h);
Greg Daniel20ece3a2017-03-28 10:24:43 -04001478 }
Greg Daniel81df0412018-05-31 13:13:33 -04001479 GrVkMemory::FlushMappedAlloc(gpu, alloc, offset, size);
1480 GrVkMemory::UnmapAlloc(gpu, alloc);
egdaniel3602d4f2016-08-12 11:58:53 -07001481 return true;
1482}
1483
Robert Phillips42dda082019-05-14 13:29:45 -04001484size_t VkBytesPerPixel(VkFormat vkFormat) {
1485 switch (vkFormat) {
1486 case VK_FORMAT_R8_UNORM:
1487 return 1;
1488
1489 case VK_FORMAT_R5G6B5_UNORM_PACK16:
1490 case VK_FORMAT_R4G4B4A4_UNORM_PACK16:
1491 case VK_FORMAT_B4G4R4A4_UNORM_PACK16:
1492 case VK_FORMAT_R8G8_UNORM:
1493 case VK_FORMAT_R16_SFLOAT:
1494 return 2;
1495
1496 case VK_FORMAT_R8G8B8_UNORM:
1497 return 3;
1498
1499 case VK_FORMAT_R8G8B8A8_UNORM:
1500 case VK_FORMAT_R8G8B8A8_SRGB:
1501 case VK_FORMAT_B8G8R8A8_UNORM:
1502 case VK_FORMAT_B8G8R8A8_SRGB:
1503 case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
1504 return 4;
1505
1506 case VK_FORMAT_R16G16B16A16_SFLOAT:
1507 case VK_FORMAT_R32G32_SFLOAT:
1508 return 8;
1509
1510 case VK_FORMAT_R32G32B32A32_SFLOAT:
1511 return 16;
1512
1513 case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
1514 return 8;
1515
1516 default:
1517 SK_ABORT("Invalid Vk format");
1518 return 0;
1519 }
1520
1521 SK_ABORT("Invalid Vk format");
1522 return 0;
1523}
1524
1525static size_t compute_combined_buffer_size(GrPixelConfig config, size_t bpp, int w, int h,
1526 SkTArray<size_t>* individualMipOffsets,
1527 uint32_t mipLevels) {
1528
1529 size_t combinedBufferSize = w * bpp * h;
1530 if (GrPixelConfigIsCompressed(config)) {
1531 combinedBufferSize = GrCompressedFormatDataSize(config, w, h);
1532 }
1533
1534 int currentWidth = w;
1535 int currentHeight = h;
1536
1537 // The Vulkan spec for copying a buffer to an image, requires that the alignment must be at
1538 // least 4 bytes and a multiple of the bytes per pixel of the image config.
1539 SkASSERT(bpp == 1 || bpp == 2 || bpp == 3 || bpp == 4 || bpp == 8 || bpp == 16);
1540 int desiredAlignment = (bpp == 3) ? 12 : (bpp > 4 ? bpp : 4);
1541
1542 for (uint32_t currentMipLevel = 1; currentMipLevel < mipLevels; currentMipLevel++) {
1543 currentWidth = SkTMax(1, currentWidth / 2);
1544 currentHeight = SkTMax(1, currentHeight / 2);
1545
1546 size_t trimmedSize;
1547 if (GrPixelConfigIsCompressed(config)) {
1548 trimmedSize = GrCompressedFormatDataSize(config, currentWidth, currentHeight);
1549 } else {
1550 trimmedSize = currentWidth * bpp * currentHeight;
1551 }
1552 const size_t alignmentDiff = combinedBufferSize % desiredAlignment;
1553 if (alignmentDiff != 0) {
1554 combinedBufferSize += desiredAlignment - alignmentDiff;
1555 }
1556 SkASSERT((0 == combinedBufferSize % 4) && (0 == combinedBufferSize % bpp));
1557
1558 individualMipOffsets->push_back(combinedBufferSize);
1559 combinedBufferSize += trimmedSize;
1560 }
1561
1562 return combinedBufferSize;
1563}
1564
Brian Salomonf865b052018-03-09 09:01:53 -05001565#if GR_TEST_UTILS
Brian Salomon52e943a2018-03-13 09:32:39 -04001566bool GrVkGpu::createTestingOnlyVkImage(GrPixelConfig config, int w, int h, bool texturable,
1567 bool renderable, GrMipMapped mipMapped, const void* srcData,
Robert Phillips646f6372018-09-25 09:31:10 -04001568 size_t srcRowBytes, GrVkImageInfo* info) {
Brian Salomon52e943a2018-03-13 09:32:39 -04001569 SkASSERT(texturable || renderable);
1570 if (!texturable) {
1571 SkASSERT(GrMipMapped::kNo == mipMapped);
1572 SkASSERT(!srcData);
1573 }
Robert Phillips42dda082019-05-14 13:29:45 -04001574 VkFormat vkFormat;
1575 if (!GrPixelConfigToVkFormat(config, &vkFormat)) {
Brian Salomon52e943a2018-03-13 09:32:39 -04001576 return false;
Robert Phillipsd21b2a52017-12-12 13:01:25 -05001577 }
1578
Brian Salomon52e943a2018-03-13 09:32:39 -04001579 if (texturable && !fVkCaps->isConfigTexturable(config)) {
1580 return false;
Robert Phillipsd21b2a52017-12-12 13:01:25 -05001581 }
1582
Brian Salomon52e943a2018-03-13 09:32:39 -04001583 if (renderable && !fVkCaps->isConfigRenderable(config)) {
1584 return false;
Robert Phillipsd21b2a52017-12-12 13:01:25 -05001585 }
1586
1587 // Currently we don't support uploading pixel data when mipped.
1588 if (srcData && GrMipMapped::kYes == mipMapped) {
Brian Salomon52e943a2018-03-13 09:32:39 -04001589 return false;
Robert Phillipsd21b2a52017-12-12 13:01:25 -05001590 }
1591
Brian Salomon52e943a2018-03-13 09:32:39 -04001592 VkImageUsageFlags usageFlags = 0;
Robert Phillipsd21b2a52017-12-12 13:01:25 -05001593 usageFlags |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
1594 usageFlags |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
Brian Salomon52e943a2018-03-13 09:32:39 -04001595 if (texturable) {
1596 usageFlags |= VK_IMAGE_USAGE_SAMPLED_BIT;
1597 }
1598 if (renderable) {
Robert Phillipsd21b2a52017-12-12 13:01:25 -05001599 usageFlags |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
1600 }
1601
1602 VkImage image = VK_NULL_HANDLE;
Greg Daniel8385a8a2018-02-26 13:29:37 -05001603 GrVkAlloc alloc;
Brian Salomonde9f5462018-03-07 14:23:58 -05001604 VkImageLayout initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
Robert Phillipsd21b2a52017-12-12 13:01:25 -05001605
1606 // Create Image
1607 VkSampleCountFlagBits vkSamples;
1608 if (!GrSampleCountToVkSampleCount(1, &vkSamples)) {
Brian Salomon52e943a2018-03-13 09:32:39 -04001609 return false;
Robert Phillipsd21b2a52017-12-12 13:01:25 -05001610 }
1611
1612 // Figure out the number of mip levels.
1613 uint32_t mipLevels = 1;
1614 if (GrMipMapped::kYes == mipMapped) {
1615 mipLevels = SkMipMap::ComputeLevelCount(w, h) + 1;
1616 }
1617
1618 const VkImageCreateInfo imageCreateInfo = {
Brian Salomonde9f5462018-03-07 14:23:58 -05001619 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // sType
1620 nullptr, // pNext
Brian Osman2b23c4b2018-06-01 12:25:08 -04001621 0, // VkImageCreateFlags
Brian Salomonde9f5462018-03-07 14:23:58 -05001622 VK_IMAGE_TYPE_2D, // VkImageType
Robert Phillips42dda082019-05-14 13:29:45 -04001623 vkFormat, // VkFormat
Brian Salomonde9f5462018-03-07 14:23:58 -05001624 {(uint32_t)w, (uint32_t)h, 1}, // VkExtent3D
1625 mipLevels, // mipLevels
1626 1, // arrayLayers
1627 vkSamples, // samples
1628 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling
1629 usageFlags, // VkImageUsageFlags
1630 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode
1631 0, // queueFamilyCount
1632 0, // pQueueFamilyIndices
1633 initialLayout // initialLayout
Robert Phillipsd21b2a52017-12-12 13:01:25 -05001634 };
1635
Brian Salomon52e943a2018-03-13 09:32:39 -04001636 GR_VK_CALL_ERRCHECK(this->vkInterface(),
1637 CreateImage(this->device(), &imageCreateInfo, nullptr, &image));
Robert Phillipsd21b2a52017-12-12 13:01:25 -05001638
Brian Salomonde9f5462018-03-07 14:23:58 -05001639 if (!GrVkMemory::AllocAndBindImageMemory(this, image, false, &alloc)) {
Robert Phillipsd21b2a52017-12-12 13:01:25 -05001640 VK_CALL(DestroyImage(this->device(), image, nullptr));
Brian Salomon52e943a2018-03-13 09:32:39 -04001641 return false;
Robert Phillipsd21b2a52017-12-12 13:01:25 -05001642 }
1643
1644 // We need to declare these early so that we can delete them at the end outside of the if block.
Greg Daniel8385a8a2018-02-26 13:29:37 -05001645 GrVkAlloc bufferAlloc;
Robert Phillipsd21b2a52017-12-12 13:01:25 -05001646 VkBuffer buffer = VK_NULL_HANDLE;
1647
1648 VkResult err;
1649 const VkCommandBufferAllocateInfo cmdInfo = {
1650 VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, // sType
1651 nullptr, // pNext
Ethan Nicholas8e265a72018-12-12 16:22:40 -05001652 fCmdPool->vkCommandPool(), // commandPool
Robert Phillipsd21b2a52017-12-12 13:01:25 -05001653 VK_COMMAND_BUFFER_LEVEL_PRIMARY, // level
1654 1 // bufferCount
1655 };
1656
1657 VkCommandBuffer cmdBuffer;
1658 err = VK_CALL(AllocateCommandBuffers(fDevice, &cmdInfo, &cmdBuffer));
1659 if (err) {
1660 GrVkMemory::FreeImageMemory(this, false, alloc);
1661 VK_CALL(DestroyImage(fDevice, image, nullptr));
Brian Salomon52e943a2018-03-13 09:32:39 -04001662 return false;
Robert Phillipsd21b2a52017-12-12 13:01:25 -05001663 }
1664
1665 VkCommandBufferBeginInfo cmdBufferBeginInfo;
1666 memset(&cmdBufferBeginInfo, 0, sizeof(VkCommandBufferBeginInfo));
1667 cmdBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
1668 cmdBufferBeginInfo.pNext = nullptr;
1669 cmdBufferBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
1670 cmdBufferBeginInfo.pInheritanceInfo = nullptr;
1671
1672 err = VK_CALL(BeginCommandBuffer(cmdBuffer, &cmdBufferBeginInfo));
1673 SkASSERT(!err);
1674
Robert Phillips42dda082019-05-14 13:29:45 -04001675 size_t bpp = VkBytesPerPixel(vkFormat);
Brian Salomonde9f5462018-03-07 14:23:58 -05001676 SkASSERT(w && h);
Robert Phillipsd21b2a52017-12-12 13:01:25 -05001677
Robert Phillips646f6372018-09-25 09:31:10 -04001678 const size_t trimRowBytes = w * bpp;
1679 if (!srcRowBytes) {
1680 srcRowBytes = trimRowBytes;
1681 }
1682
Brian Salomonde9f5462018-03-07 14:23:58 -05001683 SkTArray<size_t> individualMipOffsets(mipLevels);
1684 individualMipOffsets.push_back(0);
Robert Phillipsd21b2a52017-12-12 13:01:25 -05001685
Robert Phillips42dda082019-05-14 13:29:45 -04001686 size_t combinedBufferSize = compute_combined_buffer_size(config, bpp, w, h,
1687 &individualMipOffsets, mipLevels);
Robert Phillipsd21b2a52017-12-12 13:01:25 -05001688
Brian Salomonde9f5462018-03-07 14:23:58 -05001689 VkBufferCreateInfo bufInfo;
1690 memset(&bufInfo, 0, sizeof(VkBufferCreateInfo));
1691 bufInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
1692 bufInfo.flags = 0;
1693 bufInfo.size = combinedBufferSize;
1694 bufInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
1695 bufInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
1696 bufInfo.queueFamilyIndexCount = 0;
1697 bufInfo.pQueueFamilyIndices = nullptr;
1698 err = VK_CALL(CreateBuffer(fDevice, &bufInfo, nullptr, &buffer));
Robert Phillipsd21b2a52017-12-12 13:01:25 -05001699
Brian Salomonde9f5462018-03-07 14:23:58 -05001700 if (err) {
1701 GrVkMemory::FreeImageMemory(this, false, alloc);
1702 VK_CALL(DestroyImage(fDevice, image, nullptr));
1703 VK_CALL(EndCommandBuffer(cmdBuffer));
Ethan Nicholas8e265a72018-12-12 16:22:40 -05001704 VK_CALL(FreeCommandBuffers(fDevice, fCmdPool->vkCommandPool(), 1, &cmdBuffer));
Brian Salomon52e943a2018-03-13 09:32:39 -04001705 return false;
Brian Salomonde9f5462018-03-07 14:23:58 -05001706 }
Robert Phillipsd21b2a52017-12-12 13:01:25 -05001707
Brian Salomonde9f5462018-03-07 14:23:58 -05001708 if (!GrVkMemory::AllocAndBindBufferMemory(this, buffer, GrVkBuffer::kCopyRead_Type, true,
1709 &bufferAlloc)) {
1710 GrVkMemory::FreeImageMemory(this, false, alloc);
1711 VK_CALL(DestroyImage(fDevice, image, nullptr));
1712 VK_CALL(DestroyBuffer(fDevice, buffer, nullptr));
1713 VK_CALL(EndCommandBuffer(cmdBuffer));
Ethan Nicholas8e265a72018-12-12 16:22:40 -05001714 VK_CALL(FreeCommandBuffers(fDevice, fCmdPool->vkCommandPool(), 1, &cmdBuffer));
Brian Salomon52e943a2018-03-13 09:32:39 -04001715 return false;
Brian Salomonde9f5462018-03-07 14:23:58 -05001716 }
Robert Phillipsd21b2a52017-12-12 13:01:25 -05001717
Robert Phillips42dda082019-05-14 13:29:45 -04001718 int currentWidth = w;
1719 int currentHeight = h;
Brian Salomonde9f5462018-03-07 14:23:58 -05001720 for (uint32_t currentMipLevel = 0; currentMipLevel < mipLevels; currentMipLevel++) {
1721 SkASSERT(0 == currentMipLevel || !srcData);
Brian Salomonde9f5462018-03-07 14:23:58 -05001722 size_t bufferOffset = individualMipOffsets[currentMipLevel];
Jim Van Verth1676cb92019-01-15 13:24:45 -05001723 bool result;
1724 if (GrPixelConfigIsCompressed(config)) {
1725 size_t levelSize = GrCompressedFormatDataSize(config, currentWidth, currentHeight);
1726 size_t currentRowBytes = levelSize / currentHeight;
1727 result = copy_testing_data(this, srcData, bufferAlloc, bufferOffset, currentRowBytes,
1728 currentRowBytes, currentRowBytes, currentHeight);
1729 } else {
1730 size_t currentRowBytes = bpp * currentWidth;
1731 result = copy_testing_data(this, srcData, bufferAlloc, bufferOffset, srcRowBytes,
1732 currentRowBytes, trimRowBytes, currentHeight);
1733 }
1734 if (!result) {
Robert Phillipsd21b2a52017-12-12 13:01:25 -05001735 GrVkMemory::FreeImageMemory(this, false, alloc);
1736 VK_CALL(DestroyImage(fDevice, image, nullptr));
Brian Salomonde9f5462018-03-07 14:23:58 -05001737 GrVkMemory::FreeBufferMemory(this, GrVkBuffer::kCopyRead_Type, bufferAlloc);
Robert Phillipsd21b2a52017-12-12 13:01:25 -05001738 VK_CALL(DestroyBuffer(fDevice, buffer, nullptr));
1739 VK_CALL(EndCommandBuffer(cmdBuffer));
Ethan Nicholas8e265a72018-12-12 16:22:40 -05001740 VK_CALL(FreeCommandBuffers(fDevice, fCmdPool->vkCommandPool(), 1, &cmdBuffer));
Brian Salomon52e943a2018-03-13 09:32:39 -04001741 return false;
Robert Phillipsd21b2a52017-12-12 13:01:25 -05001742 }
Brian Salomonde9f5462018-03-07 14:23:58 -05001743 currentWidth = SkTMax(1, currentWidth / 2);
1744 currentHeight = SkTMax(1, currentHeight / 2);
Robert Phillipsd21b2a52017-12-12 13:01:25 -05001745 }
Brian Salomonde9f5462018-03-07 14:23:58 -05001746
1747 // Set image layout and add barrier
1748 VkImageMemoryBarrier barrier;
1749 memset(&barrier, 0, sizeof(VkImageMemoryBarrier));
1750 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
1751 barrier.pNext = nullptr;
Greg Daniel6ddbafc2018-05-24 12:34:29 -04001752 barrier.srcAccessMask = GrVkImage::LayoutToSrcAccessMask(initialLayout);
Brian Salomonde9f5462018-03-07 14:23:58 -05001753 barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
1754 barrier.oldLayout = initialLayout;
1755 barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
1756 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
1757 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
1758 barrier.image = image;
1759 barrier.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, mipLevels, 0, 1};
1760
Greg Danielf7828d02018-10-09 12:01:32 -04001761 VK_CALL(CmdPipelineBarrier(cmdBuffer, GrVkImage::LayoutToPipelineSrcStageFlags(initialLayout),
Brian Salomonde9f5462018-03-07 14:23:58 -05001762 VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1,
1763 &barrier));
1764 initialLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
1765
1766 SkTArray<VkBufferImageCopy> regions(mipLevels);
1767
1768 currentWidth = w;
1769 currentHeight = h;
1770 for (uint32_t currentMipLevel = 0; currentMipLevel < mipLevels; currentMipLevel++) {
1771 // Submit copy command
1772 VkBufferImageCopy& region = regions.push_back();
1773 memset(&region, 0, sizeof(VkBufferImageCopy));
1774 region.bufferOffset = individualMipOffsets[currentMipLevel];
1775 region.bufferRowLength = currentWidth;
1776 region.bufferImageHeight = currentHeight;
1777 region.imageSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1};
1778 region.imageOffset = {0, 0, 0};
1779 region.imageExtent = {(uint32_t)currentWidth, (uint32_t)currentHeight, 1};
1780 currentWidth = SkTMax(1, currentWidth / 2);
1781 currentHeight = SkTMax(1, currentHeight / 2);
1782 }
1783
1784 VK_CALL(CmdCopyBufferToImage(cmdBuffer, buffer, image, initialLayout, regions.count(),
1785 regions.begin()));
1786
Brian Salomon52e943a2018-03-13 09:32:39 -04001787 if (texturable) {
1788 // Change Image layout to shader read since if we use this texture as a borrowed textures
1789 // within Ganesh we require that its layout be set to that
1790 memset(&barrier, 0, sizeof(VkImageMemoryBarrier));
1791 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
1792 barrier.pNext = nullptr;
Greg Daniel6ddbafc2018-05-24 12:34:29 -04001793 barrier.srcAccessMask = GrVkImage::LayoutToSrcAccessMask(initialLayout);
Brian Salomon52e943a2018-03-13 09:32:39 -04001794 barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
1795 barrier.oldLayout = initialLayout;
1796 barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
1797 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
1798 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
1799 barrier.image = image;
1800 barrier.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, mipLevels, 0, 1};
Brian Salomon52e943a2018-03-13 09:32:39 -04001801 VK_CALL(CmdPipelineBarrier(cmdBuffer,
Greg Danielf7828d02018-10-09 12:01:32 -04001802 GrVkImage::LayoutToPipelineSrcStageFlags(initialLayout),
1803 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
Brian Salomon52e943a2018-03-13 09:32:39 -04001804 0,
1805 0, nullptr,
1806 0, nullptr,
1807 1, &barrier));
Greg Daniel4f4a53f2018-03-15 10:20:45 -04001808 initialLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
Brian Salomon52e943a2018-03-13 09:32:39 -04001809 }
Robert Phillipsd21b2a52017-12-12 13:01:25 -05001810
1811 // End CommandBuffer
1812 err = VK_CALL(EndCommandBuffer(cmdBuffer));
1813 SkASSERT(!err);
1814
1815 // Create Fence for queue
1816 VkFence fence;
1817 VkFenceCreateInfo fenceInfo;
1818 memset(&fenceInfo, 0, sizeof(VkFenceCreateInfo));
1819 fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
1820
1821 err = VK_CALL(CreateFence(fDevice, &fenceInfo, nullptr, &fence));
1822 SkASSERT(!err);
1823
1824 VkSubmitInfo submitInfo;
1825 memset(&submitInfo, 0, sizeof(VkSubmitInfo));
1826 submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
1827 submitInfo.pNext = nullptr;
1828 submitInfo.waitSemaphoreCount = 0;
1829 submitInfo.pWaitSemaphores = nullptr;
1830 submitInfo.pWaitDstStageMask = 0;
1831 submitInfo.commandBufferCount = 1;
1832 submitInfo.pCommandBuffers = &cmdBuffer;
1833 submitInfo.signalSemaphoreCount = 0;
1834 submitInfo.pSignalSemaphores = nullptr;
1835 err = VK_CALL(QueueSubmit(this->queue(), 1, &submitInfo, fence));
1836 SkASSERT(!err);
1837
1838 err = VK_CALL(WaitForFences(fDevice, 1, &fence, true, UINT64_MAX));
1839 if (VK_TIMEOUT == err) {
1840 GrVkMemory::FreeImageMemory(this, false, alloc);
1841 VK_CALL(DestroyImage(fDevice, image, nullptr));
1842 GrVkMemory::FreeBufferMemory(this, GrVkBuffer::kCopyRead_Type, bufferAlloc);
1843 VK_CALL(DestroyBuffer(fDevice, buffer, nullptr));
Ethan Nicholas8e265a72018-12-12 16:22:40 -05001844 VK_CALL(FreeCommandBuffers(fDevice, fCmdPool->vkCommandPool(), 1, &cmdBuffer));
Robert Phillipsd21b2a52017-12-12 13:01:25 -05001845 VK_CALL(DestroyFence(fDevice, fence, nullptr));
1846 SkDebugf("Fence failed to signal: %d\n", err);
1847 SK_ABORT("failing");
1848 }
1849 SkASSERT(!err);
1850
1851 // Clean up transfer resources
1852 if (buffer != VK_NULL_HANDLE) { // workaround for an older NVidia driver crash
1853 GrVkMemory::FreeBufferMemory(this, GrVkBuffer::kCopyRead_Type, bufferAlloc);
1854 VK_CALL(DestroyBuffer(fDevice, buffer, nullptr));
1855 }
Ethan Nicholas8e265a72018-12-12 16:22:40 -05001856 VK_CALL(FreeCommandBuffers(fDevice, fCmdPool->vkCommandPool(), 1, &cmdBuffer));
Robert Phillipsd21b2a52017-12-12 13:01:25 -05001857 VK_CALL(DestroyFence(fDevice, fence, nullptr));
1858
Brian Salomon52e943a2018-03-13 09:32:39 -04001859 info->fImage = image;
1860 info->fAlloc = alloc;
1861 info->fImageTiling = VK_IMAGE_TILING_OPTIMAL;
1862 info->fImageLayout = initialLayout;
Robert Phillips42dda082019-05-14 13:29:45 -04001863 info->fFormat = vkFormat;
Brian Salomon52e943a2018-03-13 09:32:39 -04001864 info->fLevelCount = mipLevels;
Robert Phillipsd21b2a52017-12-12 13:01:25 -05001865
Brian Salomon52e943a2018-03-13 09:32:39 -04001866 return true;
1867}
1868
Robert Phillips9dbcdcc2019-05-13 10:40:06 -04001869static bool vk_format_to_pixel_config(VkFormat format, GrPixelConfig* config) {
1870 GrPixelConfig dontCare;
1871 if (!config) {
1872 config = &dontCare;
1873 }
1874
1875 switch (format) {
1876 case VK_FORMAT_UNDEFINED:
1877 *config = kUnknown_GrPixelConfig;
1878 return false;
1879 case VK_FORMAT_R8G8B8A8_UNORM:
1880 *config = kRGBA_8888_GrPixelConfig;
1881 return true;
1882 case VK_FORMAT_R8G8B8_UNORM:
1883 *config = kRGB_888_GrPixelConfig;
1884 return true;
1885 case VK_FORMAT_R8G8_UNORM:
1886 *config = kRG_88_GrPixelConfig;
1887 return true;
1888 case VK_FORMAT_B8G8R8A8_UNORM:
1889 *config = kBGRA_8888_GrPixelConfig;
1890 return true;
1891 case VK_FORMAT_R8G8B8A8_SRGB:
1892 *config = kSRGBA_8888_GrPixelConfig;
1893 return true;
1894 case VK_FORMAT_B8G8R8A8_SRGB:
1895 *config = kSBGRA_8888_GrPixelConfig;
1896 return true;
1897 case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
1898 *config = kRGBA_1010102_GrPixelConfig;
1899 return true;
1900 case VK_FORMAT_R5G6B5_UNORM_PACK16:
1901 *config = kRGB_565_GrPixelConfig;
1902 return true;
1903 case VK_FORMAT_B4G4R4A4_UNORM_PACK16:
1904 *config = kRGBA_4444_GrPixelConfig; // we're swizzling in this case
1905 return true;
1906 case VK_FORMAT_R4G4B4A4_UNORM_PACK16:
1907 *config = kRGBA_4444_GrPixelConfig;
1908 return true;
1909 case VK_FORMAT_R8_UNORM:
1910 *config = kAlpha_8_GrPixelConfig;
1911 return true;
1912 case VK_FORMAT_R32G32B32A32_SFLOAT:
1913 *config = kRGBA_float_GrPixelConfig;
1914 return true;
1915 case VK_FORMAT_R32G32_SFLOAT:
1916 *config = kRG_float_GrPixelConfig;
1917 return true;
1918 case VK_FORMAT_R16G16B16A16_SFLOAT:
1919 *config = kRGBA_half_GrPixelConfig;
1920 return true;
1921 case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
1922 *config = kRGB_ETC1_GrPixelConfig;
1923 return true;
1924 case VK_FORMAT_R16_SFLOAT:
1925 *config = kAlpha_half_GrPixelConfig;
1926 return true;
1927 default:
1928 return false;
1929 }
1930 SK_ABORT("Unexpected config");
1931 return false;
1932}
1933
1934GrBackendTexture GrVkGpu::createTestingOnlyBackendTexture(int w, int h,
1935 const GrBackendFormat& format,
1936 GrMipMapped mipMapped,
1937 GrRenderable renderable,
1938 const void* srcData, size_t rowBytes) {
Brian Salomon8a375832018-03-14 10:21:40 -04001939 this->handleDirtyContext();
Robert Phillipsa479f962018-04-10 11:45:40 -04001940
Robert Phillips9dbcdcc2019-05-13 10:40:06 -04001941
Robert Phillipsa479f962018-04-10 11:45:40 -04001942 if (w > this->caps()->maxTextureSize() || h > this->caps()->maxTextureSize()) {
1943 return GrBackendTexture();
1944 }
1945
Robert Phillips9dbcdcc2019-05-13 10:40:06 -04001946 const VkFormat* vkFormat = format.getVkFormat();
1947 if (!vkFormat) {
1948 return GrBackendTexture();
1949 }
1950
1951 GrPixelConfig config;
1952
1953 if (!vk_format_to_pixel_config(*vkFormat, &config)) {
1954 return GrBackendTexture();
1955 }
Robert Phillips646f6372018-09-25 09:31:10 -04001956 if (!this->caps()->isConfigTexturable(config)) {
1957 return GrBackendTexture();
1958 }
1959
Robert Phillipsd21b2a52017-12-12 13:01:25 -05001960 GrVkImageInfo info;
Robert Phillips9dbcdcc2019-05-13 10:40:06 -04001961 if (!this->createTestingOnlyVkImage(config, w, h, true, GrRenderable::kYes == renderable,
1962 mipMapped, srcData, rowBytes, &info)) {
Brian Salomon52e943a2018-03-13 09:32:39 -04001963 return {};
1964 }
Greg Daniel108bb232018-07-03 16:18:29 -04001965 GrBackendTexture beTex = GrBackendTexture(w, h, info);
1966 // Lots of tests don't go through Skia's public interface which will set the config so for
1967 // testing we make sure we set a config here.
1968 beTex.setPixelConfig(config);
1969 return beTex;
Robert Phillipsd21b2a52017-12-12 13:01:25 -05001970}
1971
1972bool GrVkGpu::isTestingOnlyBackendTexture(const GrBackendTexture& tex) const {
Greg Danielbdf12ad2018-10-12 09:31:11 -04001973 SkASSERT(GrBackendApi::kVulkan == tex.fBackend);
Robert Phillipsd21b2a52017-12-12 13:01:25 -05001974
Greg Daniel52e16d92018-04-10 09:34:07 -04001975 GrVkImageInfo backend;
1976 if (!tex.getVkImageInfo(&backend)) {
1977 return false;
1978 }
Greg Daniel164a9f02016-02-22 09:56:40 -05001979
Greg Daniel52e16d92018-04-10 09:34:07 -04001980 if (backend.fImage && backend.fAlloc.fMemory) {
Greg Daniel164a9f02016-02-22 09:56:40 -05001981 VkMemoryRequirements req;
1982 memset(&req, 0, sizeof(req));
1983 GR_VK_CALL(this->vkInterface(), GetImageMemoryRequirements(fDevice,
Greg Daniel52e16d92018-04-10 09:34:07 -04001984 backend.fImage,
Greg Daniel164a9f02016-02-22 09:56:40 -05001985 &req));
1986 // TODO: find a better check
1987 // This will probably fail with a different driver
1988 return (req.size > 0) && (req.size <= 8192 * 8192);
1989 }
1990
1991 return false;
1992}
1993
Brian Salomon26102cb2018-03-09 09:33:19 -05001994void GrVkGpu::deleteTestingOnlyBackendTexture(const GrBackendTexture& tex) {
Greg Danielbdf12ad2018-10-12 09:31:11 -04001995 SkASSERT(GrBackendApi::kVulkan == tex.fBackend);
Robert Phillipsd21b2a52017-12-12 13:01:25 -05001996
Greg Daniel52e16d92018-04-10 09:34:07 -04001997 GrVkImageInfo info;
1998 if (tex.getVkImageInfo(&info)) {
Greg Daniel52e16d92018-04-10 09:34:07 -04001999 GrVkImage::DestroyImageInfo(this, const_cast<GrVkImageInfo*>(&info));
Greg Daniel164a9f02016-02-22 09:56:40 -05002000 }
2001}
2002
Brian Osman2d010b62018-08-09 10:55:09 -04002003GrBackendRenderTarget GrVkGpu::createTestingOnlyBackendRenderTarget(int w, int h, GrColorType ct) {
Greg Daniel92cbf3f2018-04-12 16:50:17 -04002004 if (w > this->caps()->maxRenderTargetSize() || h > this->caps()->maxRenderTargetSize()) {
2005 return GrBackendRenderTarget();
2006 }
2007
Brian Salomon8a375832018-03-14 10:21:40 -04002008 this->handleDirtyContext();
Brian Salomon52e943a2018-03-13 09:32:39 -04002009 GrVkImageInfo info;
Brian Osman2d010b62018-08-09 10:55:09 -04002010 auto config = GrColorTypeToPixelConfig(ct, GrSRGBEncoded::kNo);
Brian Salomon52e943a2018-03-13 09:32:39 -04002011 if (kUnknown_GrPixelConfig == config) {
2012 return {};
2013 }
Robert Phillips646f6372018-09-25 09:31:10 -04002014 if (!this->createTestingOnlyVkImage(config, w, h, false, true, GrMipMapped::kNo, nullptr, 0,
Brian Salomon52e943a2018-03-13 09:32:39 -04002015 &info)) {
2016 return {};
2017 }
Greg Daniel108bb232018-07-03 16:18:29 -04002018 GrBackendRenderTarget beRT = GrBackendRenderTarget(w, h, 1, 0, info);
2019 // Lots of tests don't go through Skia's public interface which will set the config so for
2020 // testing we make sure we set a config here.
2021 beRT.setPixelConfig(config);
2022 return beRT;
Brian Salomonf865b052018-03-09 09:01:53 -05002023}
2024
Brian Salomon52e943a2018-03-13 09:32:39 -04002025void GrVkGpu::deleteTestingOnlyBackendRenderTarget(const GrBackendRenderTarget& rt) {
Greg Danielbdf12ad2018-10-12 09:31:11 -04002026 SkASSERT(GrBackendApi::kVulkan == rt.fBackend);
Brian Salomonf865b052018-03-09 09:01:53 -05002027
Greg Daniel323fbcf2018-04-10 13:46:30 -04002028 GrVkImageInfo info;
2029 if (rt.getVkImageInfo(&info)) {
Brian Salomon52e943a2018-03-13 09:32:39 -04002030 // something in the command buffer may still be using this, so force submit
2031 this->submitCommandBuffer(kForce_SyncQueue);
Greg Daniel323fbcf2018-04-10 13:46:30 -04002032 GrVkImage::DestroyImageInfo(this, const_cast<GrVkImageInfo*>(&info));
Brian Salomon52e943a2018-03-13 09:32:39 -04002033 }
2034}
Brian Salomonf865b052018-03-09 09:01:53 -05002035
Greg Daniel26b50a42018-03-08 09:49:58 -05002036void GrVkGpu::testingOnly_flushGpuAndSync() {
2037 this->submitCommandBuffer(kForce_SyncQueue);
2038}
Brian Salomonf865b052018-03-09 09:01:53 -05002039#endif
Greg Daniel26b50a42018-03-08 09:49:58 -05002040
Greg Daniel164a9f02016-02-22 09:56:40 -05002041////////////////////////////////////////////////////////////////////////////////
2042
Greg Daniel59dc1482019-02-22 10:46:38 -05002043void GrVkGpu::addBufferMemoryBarrier(const GrVkResource* resource,
2044 VkPipelineStageFlags srcStageMask,
Greg Daniel164a9f02016-02-22 09:56:40 -05002045 VkPipelineStageFlags dstStageMask,
2046 bool byRegion,
2047 VkBufferMemoryBarrier* barrier) const {
2048 SkASSERT(fCurrentCmdBuffer);
Greg Daniel59dc1482019-02-22 10:46:38 -05002049 SkASSERT(resource);
Greg Daniel164a9f02016-02-22 09:56:40 -05002050 fCurrentCmdBuffer->pipelineBarrier(this,
Greg Daniel59dc1482019-02-22 10:46:38 -05002051 resource,
Greg Daniel164a9f02016-02-22 09:56:40 -05002052 srcStageMask,
2053 dstStageMask,
2054 byRegion,
2055 GrVkCommandBuffer::kBufferMemory_BarrierType,
2056 barrier);
2057}
2058
Greg Daniel59dc1482019-02-22 10:46:38 -05002059void GrVkGpu::addImageMemoryBarrier(const GrVkResource* resource,
2060 VkPipelineStageFlags srcStageMask,
Greg Daniel164a9f02016-02-22 09:56:40 -05002061 VkPipelineStageFlags dstStageMask,
2062 bool byRegion,
2063 VkImageMemoryBarrier* barrier) const {
2064 SkASSERT(fCurrentCmdBuffer);
Greg Daniel59dc1482019-02-22 10:46:38 -05002065 SkASSERT(resource);
Greg Daniel164a9f02016-02-22 09:56:40 -05002066 fCurrentCmdBuffer->pipelineBarrier(this,
Greg Daniel59dc1482019-02-22 10:46:38 -05002067 resource,
Greg Daniel164a9f02016-02-22 09:56:40 -05002068 srcStageMask,
2069 dstStageMask,
2070 byRegion,
2071 GrVkCommandBuffer::kImageMemory_BarrierType,
2072 barrier);
2073}
2074
Brian Salomonf9a1fdf2019-05-09 10:30:12 -04002075void GrVkGpu::onFinishFlush(GrSurfaceProxy* proxies[], int n,
Greg Daniel797efca2019-05-09 14:04:20 -04002076 SkSurface::BackendSurfaceAccess access, const GrFlushInfo& info,
2077 const GrPrepareForExternalIORequests& externalRequests) {
Brian Salomonf9a1fdf2019-05-09 10:30:12 -04002078 SkASSERT(n >= 0);
2079 SkASSERT(!n || proxies);
Greg Daniel51316782017-08-02 15:10:09 +00002080 // Submit the current command buffer to the Queue. Whether we inserted semaphores or not does
2081 // not effect what we do here.
Brian Salomonf9a1fdf2019-05-09 10:30:12 -04002082 if (n && access == SkSurface::BackendSurfaceAccess::kPresent) {
Greg Danielbae71212019-03-01 15:24:35 -05002083 GrVkImage* image;
Brian Salomonf9a1fdf2019-05-09 10:30:12 -04002084 for (int i = 0; i < n; ++i) {
2085 SkASSERT(proxies[i]->isInstantiated());
2086 if (GrTexture* tex = proxies[i]->peekTexture()) {
2087 image = static_cast<GrVkTexture*>(tex);
2088 } else {
2089 GrRenderTarget* rt = proxies[i]->peekRenderTarget();
2090 SkASSERT(rt);
2091 image = static_cast<GrVkRenderTarget*>(rt);
2092 }
2093 image->prepareForPresent(this);
Greg Danielbae71212019-03-01 15:24:35 -05002094 }
Greg Danielbae71212019-03-01 15:24:35 -05002095 }
Greg Daniel797efca2019-05-09 14:04:20 -04002096
2097 // Handle requests for preparing for external IO
2098 for (int i = 0; i < externalRequests.fNumImages; ++i) {
2099 SkImage* image = externalRequests.fImages[i];
2100 if (!image->isTextureBacked()) {
2101 continue;
2102 }
2103 SkImage_GpuBase* gpuImage = static_cast<SkImage_GpuBase*>(as_IB(image));
2104 sk_sp<GrTextureProxy> proxy = gpuImage->asTextureProxyRef(this->getContext());
2105 SkASSERT(proxy);
2106
2107 if (!proxy->isInstantiated()) {
2108 auto resourceProvider = this->getContext()->priv().resourceProvider();
2109 if (!proxy->instantiate(resourceProvider)) {
2110 continue;
2111 }
2112 }
2113
2114 GrTexture* tex = proxy->peekTexture();
2115 if (!tex) {
2116 continue;
2117 }
2118 GrVkTexture* vkTex = static_cast<GrVkTexture*>(tex);
2119 vkTex->prepareForExternal(this);
2120 }
2121 for (int i = 0; i < externalRequests.fNumSurfaces; ++i) {
2122 SkSurface* surface = externalRequests.fSurfaces[i];
2123 if (!surface->getCanvas()->getGrContext()) {
2124 continue;
2125 }
2126 SkSurface_Gpu* gpuSurface = static_cast<SkSurface_Gpu*>(surface);
2127 auto* rtc = gpuSurface->getDevice()->accessRenderTargetContext();
2128 sk_sp<GrRenderTargetProxy> proxy = rtc->asRenderTargetProxyRef();
2129 if (!proxy->isInstantiated()) {
2130 auto resourceProvider = this->getContext()->priv().resourceProvider();
2131 if (!proxy->instantiate(resourceProvider)) {
2132 continue;
2133 }
2134 }
2135
2136 GrRenderTarget* rt = proxy->peekRenderTarget();
2137 SkASSERT(rt);
2138 GrVkRenderTarget* vkRT = static_cast<GrVkRenderTarget*>(rt);
2139 if (externalRequests.fPrepareSurfaceForPresent &&
2140 externalRequests.fPrepareSurfaceForPresent[i]) {
2141 vkRT->prepareForPresent(this);
2142 } else {
2143 vkRT->prepareForExternal(this);
2144 }
2145 }
2146
Greg Daniele6bfb7d2019-04-17 15:26:11 -04002147 if (info.fFlags & kSyncCpu_GrFlushFlag) {
2148 this->submitCommandBuffer(kForce_SyncQueue, info.fFinishedProc, info.fFinishedContext);
Greg Danielbae71212019-03-01 15:24:35 -05002149 } else {
Greg Daniele6bfb7d2019-04-17 15:26:11 -04002150 this->submitCommandBuffer(kSkip_SyncQueue, info.fFinishedProc, info.fFinishedContext);
Greg Danielbae71212019-03-01 15:24:35 -05002151 }
Greg Daniel164a9f02016-02-22 09:56:40 -05002152}
2153
Greg Daniel25af6712018-04-25 10:44:38 -04002154static int get_surface_sample_cnt(GrSurface* surf) {
2155 if (const GrRenderTarget* rt = surf->asRenderTarget()) {
2156 return rt->numColorSamples();
egdaniel17b89252016-04-05 07:23:38 -07002157 }
Greg Daniel25af6712018-04-25 10:44:38 -04002158 return 0;
Greg Daniel164a9f02016-02-22 09:56:40 -05002159}
2160
Robert Phillipsb0e93a22017-08-29 08:26:54 -04002161void GrVkGpu::copySurfaceAsCopyImage(GrSurface* dst, GrSurfaceOrigin dstOrigin,
2162 GrSurface* src, GrSurfaceOrigin srcOrigin,
egdaniel17b89252016-04-05 07:23:38 -07002163 GrVkImage* dstImage,
2164 GrVkImage* srcImage,
Greg Daniel164a9f02016-02-22 09:56:40 -05002165 const SkIRect& srcRect,
2166 const SkIPoint& dstPoint) {
Greg Daniel25af6712018-04-25 10:44:38 -04002167#ifdef SK_DEBUG
2168 int dstSampleCnt = get_surface_sample_cnt(dst);
2169 int srcSampleCnt = get_surface_sample_cnt(src);
Greg Daniela51e93c2019-03-25 12:30:45 -04002170 bool dstHasYcbcr = dstImage->ycbcrConversionInfo().isValid();
2171 bool srcHasYcbcr = srcImage->ycbcrConversionInfo().isValid();
2172 SkASSERT(this->vkCaps().canCopyImage(dst->config(), dstSampleCnt, dstOrigin, dstHasYcbcr,
2173 src->config(), srcSampleCnt, srcOrigin, srcHasYcbcr));
Greg Daniel25af6712018-04-25 10:44:38 -04002174
2175#endif
Greg Daniel164a9f02016-02-22 09:56:40 -05002176
Greg Daniel164a9f02016-02-22 09:56:40 -05002177 // These flags are for flushing/invalidating caches and for the dst image it doesn't matter if
2178 // the cache is flushed since it is only being written to.
egdaniel17b89252016-04-05 07:23:38 -07002179 dstImage->setImageLayout(this,
jvanverth50c46c72016-05-06 12:31:28 -07002180 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
2181 VK_ACCESS_TRANSFER_WRITE_BIT,
2182 VK_PIPELINE_STAGE_TRANSFER_BIT,
2183 false);
Greg Daniel164a9f02016-02-22 09:56:40 -05002184
egdaniel17b89252016-04-05 07:23:38 -07002185 srcImage->setImageLayout(this,
2186 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
jvanverth50c46c72016-05-06 12:31:28 -07002187 VK_ACCESS_TRANSFER_READ_BIT,
2188 VK_PIPELINE_STAGE_TRANSFER_BIT,
egdaniel17b89252016-04-05 07:23:38 -07002189 false);
Greg Daniel164a9f02016-02-22 09:56:40 -05002190
2191 // Flip rect if necessary
2192 SkIRect srcVkRect = srcRect;
2193 int32_t dstY = dstPoint.fY;
2194
Robert Phillipsb0e93a22017-08-29 08:26:54 -04002195 if (kBottomLeft_GrSurfaceOrigin == srcOrigin) {
2196 SkASSERT(kBottomLeft_GrSurfaceOrigin == dstOrigin);
Greg Daniel164a9f02016-02-22 09:56:40 -05002197 srcVkRect.fTop = src->height() - srcRect.fBottom;
2198 srcVkRect.fBottom = src->height() - srcRect.fTop;
2199 dstY = dst->height() - dstPoint.fY - srcVkRect.height();
2200 }
2201
2202 VkImageCopy copyRegion;
2203 memset(&copyRegion, 0, sizeof(VkImageCopy));
2204 copyRegion.srcSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
2205 copyRegion.srcOffset = { srcVkRect.fLeft, srcVkRect.fTop, 0 };
2206 copyRegion.dstSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
2207 copyRegion.dstOffset = { dstPoint.fX, dstY, 0 };
egdanielc355bc82016-04-27 11:31:59 -07002208 copyRegion.extent = { (uint32_t)srcVkRect.width(), (uint32_t)srcVkRect.height(), 1 };
Greg Daniel164a9f02016-02-22 09:56:40 -05002209
2210 fCurrentCmdBuffer->copyImage(this,
egdaniel17b89252016-04-05 07:23:38 -07002211 srcImage,
Greg Daniel164a9f02016-02-22 09:56:40 -05002212 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
egdaniel17b89252016-04-05 07:23:38 -07002213 dstImage,
Greg Daniel164a9f02016-02-22 09:56:40 -05002214 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
2215 1,
2216 &copyRegion);
jvanverth900bd4a2016-04-29 13:53:12 -07002217
2218 SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.fX, dstPoint.fY,
2219 srcRect.width(), srcRect.height());
Brian Salomon1fabd512018-02-09 09:54:25 -05002220 this->didWriteToSurface(dst, dstOrigin, &dstRect);
Greg Daniel164a9f02016-02-22 09:56:40 -05002221}
2222
Robert Phillipsb0e93a22017-08-29 08:26:54 -04002223void GrVkGpu::copySurfaceAsBlit(GrSurface* dst, GrSurfaceOrigin dstOrigin,
2224 GrSurface* src, GrSurfaceOrigin srcOrigin,
egdaniel17b89252016-04-05 07:23:38 -07002225 GrVkImage* dstImage,
2226 GrVkImage* srcImage,
2227 const SkIRect& srcRect,
2228 const SkIPoint& dstPoint) {
Greg Daniel25af6712018-04-25 10:44:38 -04002229#ifdef SK_DEBUG
2230 int dstSampleCnt = get_surface_sample_cnt(dst);
2231 int srcSampleCnt = get_surface_sample_cnt(src);
Greg Daniela51e93c2019-03-25 12:30:45 -04002232 bool dstHasYcbcr = dstImage->ycbcrConversionInfo().isValid();
2233 bool srcHasYcbcr = srcImage->ycbcrConversionInfo().isValid();
Greg Daniel25af6712018-04-25 10:44:38 -04002234 SkASSERT(this->vkCaps().canCopyAsBlit(dst->config(), dstSampleCnt, dstImage->isLinearTiled(),
Greg Daniela51e93c2019-03-25 12:30:45 -04002235 dstHasYcbcr, src->config(), srcSampleCnt,
2236 srcImage->isLinearTiled(), srcHasYcbcr));
egdaniel17b89252016-04-05 07:23:38 -07002237
Greg Daniel25af6712018-04-25 10:44:38 -04002238#endif
egdaniel17b89252016-04-05 07:23:38 -07002239 dstImage->setImageLayout(this,
2240 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
jvanverth50c46c72016-05-06 12:31:28 -07002241 VK_ACCESS_TRANSFER_WRITE_BIT,
2242 VK_PIPELINE_STAGE_TRANSFER_BIT,
egdaniel17b89252016-04-05 07:23:38 -07002243 false);
2244
egdaniel17b89252016-04-05 07:23:38 -07002245 srcImage->setImageLayout(this,
2246 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
jvanverth50c46c72016-05-06 12:31:28 -07002247 VK_ACCESS_TRANSFER_READ_BIT,
2248 VK_PIPELINE_STAGE_TRANSFER_BIT,
egdaniel17b89252016-04-05 07:23:38 -07002249 false);
2250
2251 // Flip rect if necessary
2252 SkIRect srcVkRect;
egdaniel8af936d2016-04-07 10:17:47 -07002253 srcVkRect.fLeft = srcRect.fLeft;
2254 srcVkRect.fRight = srcRect.fRight;
egdaniel17b89252016-04-05 07:23:38 -07002255 SkIRect dstRect;
2256 dstRect.fLeft = dstPoint.fX;
egdaniel8af936d2016-04-07 10:17:47 -07002257 dstRect.fRight = dstPoint.fX + srcRect.width();
egdaniel17b89252016-04-05 07:23:38 -07002258
Robert Phillipsb0e93a22017-08-29 08:26:54 -04002259 if (kBottomLeft_GrSurfaceOrigin == srcOrigin) {
egdaniel17b89252016-04-05 07:23:38 -07002260 srcVkRect.fTop = src->height() - srcRect.fBottom;
2261 srcVkRect.fBottom = src->height() - srcRect.fTop;
2262 } else {
egdaniel8af936d2016-04-07 10:17:47 -07002263 srcVkRect.fTop = srcRect.fTop;
2264 srcVkRect.fBottom = srcRect.fBottom;
egdaniel17b89252016-04-05 07:23:38 -07002265 }
2266
Robert Phillipsb0e93a22017-08-29 08:26:54 -04002267 if (kBottomLeft_GrSurfaceOrigin == dstOrigin) {
egdaniel17b89252016-04-05 07:23:38 -07002268 dstRect.fTop = dst->height() - dstPoint.fY - srcVkRect.height();
2269 } else {
2270 dstRect.fTop = dstPoint.fY;
2271 }
2272 dstRect.fBottom = dstRect.fTop + srcVkRect.height();
2273
2274 // If we have different origins, we need to flip the top and bottom of the dst rect so that we
2275 // get the correct origintation of the copied data.
Robert Phillipsb0e93a22017-08-29 08:26:54 -04002276 if (srcOrigin != dstOrigin) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -04002277 using std::swap;
2278 swap(dstRect.fTop, dstRect.fBottom);
egdaniel17b89252016-04-05 07:23:38 -07002279 }
2280
2281 VkImageBlit blitRegion;
2282 memset(&blitRegion, 0, sizeof(VkImageBlit));
2283 blitRegion.srcSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
2284 blitRegion.srcOffsets[0] = { srcVkRect.fLeft, srcVkRect.fTop, 0 };
Greg Daniele76071c2016-11-02 11:57:06 -04002285 blitRegion.srcOffsets[1] = { srcVkRect.fRight, srcVkRect.fBottom, 1 };
egdaniel17b89252016-04-05 07:23:38 -07002286 blitRegion.dstSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
2287 blitRegion.dstOffsets[0] = { dstRect.fLeft, dstRect.fTop, 0 };
Greg Daniele76071c2016-11-02 11:57:06 -04002288 blitRegion.dstOffsets[1] = { dstRect.fRight, dstRect.fBottom, 1 };
egdaniel17b89252016-04-05 07:23:38 -07002289
2290 fCurrentCmdBuffer->blitImage(this,
egdanielb2df0c22016-05-13 11:30:37 -07002291 *srcImage,
2292 *dstImage,
egdaniel17b89252016-04-05 07:23:38 -07002293 1,
2294 &blitRegion,
2295 VK_FILTER_NEAREST); // We never scale so any filter works here
jvanverth900bd4a2016-04-29 13:53:12 -07002296
Greg Daniel1ba1bfc2018-06-21 13:55:19 -04002297 dstRect = SkIRect::MakeXYWH(dstPoint.fX, dstPoint.fY, srcRect.width(), srcRect.height());
Brian Salomon1fabd512018-02-09 09:54:25 -05002298 this->didWriteToSurface(dst, dstOrigin, &dstRect);
egdaniel17b89252016-04-05 07:23:38 -07002299}
2300
Brian Salomon1fabd512018-02-09 09:54:25 -05002301void GrVkGpu::copySurfaceAsResolve(GrSurface* dst, GrSurfaceOrigin dstOrigin, GrSurface* src,
2302 GrSurfaceOrigin srcOrigin, const SkIRect& origSrcRect,
2303 const SkIPoint& origDstPoint) {
egdaniel4bcd62e2016-08-31 07:37:31 -07002304 GrVkRenderTarget* srcRT = static_cast<GrVkRenderTarget*>(src->asRenderTarget());
Brian Salomon1fabd512018-02-09 09:54:25 -05002305 SkIRect srcRect = origSrcRect;
2306 SkIPoint dstPoint = origDstPoint;
2307 if (kBottomLeft_GrSurfaceOrigin == srcOrigin) {
2308 SkASSERT(kBottomLeft_GrSurfaceOrigin == dstOrigin);
2309 srcRect = {origSrcRect.fLeft, src->height() - origSrcRect.fBottom,
2310 origSrcRect.fRight, src->height() - origSrcRect.fTop};
2311 dstPoint.fY = dst->height() - dstPoint.fY - srcRect.height();
2312 }
2313 this->resolveImage(dst, srcRT, srcRect, dstPoint);
Greg Daniel1ba1bfc2018-06-21 13:55:19 -04002314 SkIRect dstRect = SkIRect::MakeXYWH(origDstPoint.fX, origDstPoint.fY,
2315 srcRect.width(), srcRect.height());
2316 this->didWriteToSurface(dst, dstOrigin, &dstRect);
egdaniel4bcd62e2016-08-31 07:37:31 -07002317}
2318
Robert Phillipsb0e93a22017-08-29 08:26:54 -04002319bool GrVkGpu::onCopySurface(GrSurface* dst, GrSurfaceOrigin dstOrigin,
2320 GrSurface* src, GrSurfaceOrigin srcOrigin,
Greg Daniel55fa6472018-03-16 16:13:10 -04002321 const SkIRect& srcRect, const SkIPoint& dstPoint,
2322 bool canDiscardOutsideDstRect) {
Greg Danielbe7fc462019-01-03 16:40:42 -05002323#ifdef SK_DEBUG
2324 if (GrVkRenderTarget* srcRT = static_cast<GrVkRenderTarget*>(src->asRenderTarget())) {
2325 SkASSERT(!srcRT->wrapsSecondaryCommandBuffer());
2326 }
2327 if (GrVkRenderTarget* dstRT = static_cast<GrVkRenderTarget*>(dst->asRenderTarget())) {
2328 SkASSERT(!dstRT->wrapsSecondaryCommandBuffer());
2329 }
2330#endif
2331
Greg Daniel25af6712018-04-25 10:44:38 -04002332 GrPixelConfig dstConfig = dst->config();
2333 GrPixelConfig srcConfig = src->config();
2334
2335 int dstSampleCnt = get_surface_sample_cnt(dst);
2336 int srcSampleCnt = get_surface_sample_cnt(src);
2337
egdaniel17b89252016-04-05 07:23:38 -07002338 GrVkImage* dstImage;
2339 GrVkImage* srcImage;
egdaniel4bcd62e2016-08-31 07:37:31 -07002340 GrRenderTarget* dstRT = dst->asRenderTarget();
2341 if (dstRT) {
2342 GrVkRenderTarget* vkRT = static_cast<GrVkRenderTarget*>(dstRT);
Greg Danielbe7fc462019-01-03 16:40:42 -05002343 if (vkRT->wrapsSecondaryCommandBuffer()) {
2344 return false;
2345 }
egdaniel4bcd62e2016-08-31 07:37:31 -07002346 dstImage = vkRT->numColorSamples() > 1 ? vkRT->msaaImage() : vkRT;
2347 } else {
2348 SkASSERT(dst->asTexture());
egdaniel17b89252016-04-05 07:23:38 -07002349 dstImage = static_cast<GrVkTexture*>(dst->asTexture());
egdaniel17b89252016-04-05 07:23:38 -07002350 }
egdaniel4bcd62e2016-08-31 07:37:31 -07002351 GrRenderTarget* srcRT = src->asRenderTarget();
2352 if (srcRT) {
2353 GrVkRenderTarget* vkRT = static_cast<GrVkRenderTarget*>(srcRT);
2354 srcImage = vkRT->numColorSamples() > 1 ? vkRT->msaaImage() : vkRT;
egdaniel17b89252016-04-05 07:23:38 -07002355 } else {
egdaniel4bcd62e2016-08-31 07:37:31 -07002356 SkASSERT(src->asTexture());
2357 srcImage = static_cast<GrVkTexture*>(src->asTexture());
egdaniel17b89252016-04-05 07:23:38 -07002358 }
2359
Greg Daniela51e93c2019-03-25 12:30:45 -04002360 bool dstHasYcbcr = dstImage->ycbcrConversionInfo().isValid();
2361 bool srcHasYcbcr = srcImage->ycbcrConversionInfo().isValid();
2362
2363 if (this->vkCaps().canCopyAsResolve(dstConfig, dstSampleCnt, dstOrigin, dstHasYcbcr,
2364 srcConfig, srcSampleCnt, srcOrigin, srcHasYcbcr)) {
2365 this->copySurfaceAsResolve(dst, dstOrigin, src, srcOrigin, srcRect, dstPoint);
2366 return true;
2367 }
2368
2369 if (this->vkCaps().canCopyAsDraw(dstConfig, SkToBool(dst->asRenderTarget()), dstHasYcbcr,
2370 srcConfig, SkToBool(src->asTexture()), srcHasYcbcr)) {
2371 SkAssertResult(fCopyManager.copySurfaceAsDraw(this, dst, dstOrigin, src, srcOrigin, srcRect,
2372 dstPoint, canDiscardOutsideDstRect));
2373 auto dstRect = srcRect.makeOffset(dstPoint.fX, dstPoint.fY);
2374 this->didWriteToSurface(dst, dstOrigin, &dstRect);
2375 return true;
2376 }
2377
2378 if (this->vkCaps().canCopyImage(dstConfig, dstSampleCnt, dstOrigin, dstHasYcbcr,
2379 srcConfig, srcSampleCnt, srcOrigin, srcHasYcbcr)) {
Robert Phillipsb0e93a22017-08-29 08:26:54 -04002380 this->copySurfaceAsCopyImage(dst, dstOrigin, src, srcOrigin, dstImage, srcImage,
2381 srcRect, dstPoint);
egdaniel17b89252016-04-05 07:23:38 -07002382 return true;
2383 }
2384
Greg Daniel25af6712018-04-25 10:44:38 -04002385 if (this->vkCaps().canCopyAsBlit(dstConfig, dstSampleCnt, dstImage->isLinearTiled(),
Greg Daniela51e93c2019-03-25 12:30:45 -04002386 dstHasYcbcr, srcConfig, srcSampleCnt,
2387 srcImage->isLinearTiled(), srcHasYcbcr)) {
Robert Phillipsb0e93a22017-08-29 08:26:54 -04002388 this->copySurfaceAsBlit(dst, dstOrigin, src, srcOrigin, dstImage, srcImage,
2389 srcRect, dstPoint);
Greg Daniel164a9f02016-02-22 09:56:40 -05002390 return true;
2391 }
2392
Greg Daniel164a9f02016-02-22 09:56:40 -05002393 return false;
2394}
2395
Brian Salomona6948702018-06-01 15:33:20 -04002396bool GrVkGpu::onReadPixels(GrSurface* surface, int left, int top, int width, int height,
2397 GrColorType dstColorType, void* buffer, size_t rowBytes) {
Brian Salomonc320b152018-02-20 14:05:36 -05002398 if (GrPixelConfigToColorType(surface->config()) != dstColorType) {
Greg Daniel164a9f02016-02-22 09:56:40 -05002399 return false;
2400 }
2401
egdaniel66933552016-08-24 07:22:19 -07002402 GrVkImage* image = nullptr;
2403 GrVkRenderTarget* rt = static_cast<GrVkRenderTarget*>(surface->asRenderTarget());
2404 if (rt) {
Greg Danielbe7fc462019-01-03 16:40:42 -05002405 // Reading from render targets that wrap a secondary command buffer is not allowed since
2406 // it would require us to know the VkImage, which we don't have, as well as need us to
2407 // stop and start the VkRenderPass which we don't have access to.
2408 if (rt->wrapsSecondaryCommandBuffer()) {
2409 return false;
2410 }
egdaniel66933552016-08-24 07:22:19 -07002411 // resolve the render target if necessary
2412 switch (rt->getResolveType()) {
2413 case GrVkRenderTarget::kCantResolve_ResolveType:
2414 return false;
2415 case GrVkRenderTarget::kAutoResolves_ResolveType:
2416 break;
2417 case GrVkRenderTarget::kCanResolve_ResolveType:
Greg Daniel0a77f432018-12-06 11:23:32 -05002418 this->resolveRenderTargetNoFlush(rt);
egdaniel66933552016-08-24 07:22:19 -07002419 break;
2420 default:
Ben Wagnerb4aab9a2017-08-16 10:53:04 -04002421 SK_ABORT("Unknown resolve type");
egdaniel66933552016-08-24 07:22:19 -07002422 }
2423 image = rt;
2424 } else {
2425 image = static_cast<GrVkTexture*>(surface->asTexture());
2426 }
2427
2428 if (!image) {
Greg Daniel164a9f02016-02-22 09:56:40 -05002429 return false;
2430 }
2431
Greg Daniel475eb702018-09-28 14:16:50 -04002432 // Skia's RGB_888x color type, which we map to the vulkan R8G8B8_UNORM, expects the data to be
2433 // 32 bits, but the Vulkan format is only 24. So we first copy the surface into an R8G8B8A8
2434 // image and then do the read pixels from that.
2435 sk_sp<GrVkTextureRenderTarget> copySurface;
Greg Danielf259b8b2019-02-14 09:03:43 -05002436 if (dstColorType == GrColorType::kRGB_888x && image->imageFormat() == VK_FORMAT_R8G8B8_UNORM) {
2437 SkASSERT(surface->config() == kRGB_888_GrPixelConfig);
Greg Daniel475eb702018-09-28 14:16:50 -04002438
2439 // Make a new surface that is RGBA to copy the RGB surface into.
2440 GrSurfaceDesc surfDesc;
2441 surfDesc.fFlags = kRenderTarget_GrSurfaceFlag;
2442 surfDesc.fWidth = width;
2443 surfDesc.fHeight = height;
2444 surfDesc.fConfig = kRGBA_8888_GrPixelConfig;
2445 surfDesc.fSampleCnt = 1;
2446
2447 VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
2448 VK_IMAGE_USAGE_SAMPLED_BIT |
2449 VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
2450 VK_IMAGE_USAGE_TRANSFER_DST_BIT;
2451
2452 GrVkImage::ImageDesc imageDesc;
2453 imageDesc.fImageType = VK_IMAGE_TYPE_2D;
2454 imageDesc.fFormat = VK_FORMAT_R8G8B8A8_UNORM;
2455 imageDesc.fWidth = width;
2456 imageDesc.fHeight = height;
2457 imageDesc.fLevels = 1;
2458 imageDesc.fSamples = 1;
2459 imageDesc.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
2460 imageDesc.fUsageFlags = usageFlags;
2461 imageDesc.fMemProps = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
2462
2463 copySurface = GrVkTextureRenderTarget::MakeNewTextureRenderTarget(
2464 this, SkBudgeted::kYes, surfDesc, imageDesc, GrMipMapsStatus::kNotAllocated);
2465 if (!copySurface) {
2466 return false;
2467 }
2468
2469 int srcSampleCount = 0;
2470 if (rt) {
2471 srcSampleCount = rt->numColorSamples();
2472 }
Greg Daniela51e93c2019-03-25 12:30:45 -04002473 bool srcHasYcbcr = image->ycbcrConversionInfo().isValid();
Greg Daniel5c7b5412019-05-10 11:39:55 -04002474 if (!this->vkCaps().canCopyAsBlit(copySurface->config(), 1, false, false,
2475 surface->config(), srcSampleCount, image->isLinearTiled(),
Greg Daniela51e93c2019-03-25 12:30:45 -04002476 srcHasYcbcr) &&
2477 !this->vkCaps().canCopyAsDraw(copySurface->config(), false, false,
2478 surface->config(), SkToBool(surface->asTexture()),
2479 srcHasYcbcr)) {
Greg Daniel475eb702018-09-28 14:16:50 -04002480 return false;
2481 }
2482 SkIRect srcRect = SkIRect::MakeXYWH(left, top, width, height);
Greg Daniel5c7b5412019-05-10 11:39:55 -04002483 static const GrSurfaceOrigin kOrigin = kTopLeft_GrSurfaceOrigin;
Greg Daniel475eb702018-09-28 14:16:50 -04002484 if (!this->copySurface(copySurface.get(), kOrigin, surface, kOrigin,
2485 srcRect, SkIPoint::Make(0,0))) {
2486 return false;
2487 }
2488 top = 0;
2489 left = 0;
2490 dstColorType = GrColorType::kRGBA_8888;
2491 image = copySurface.get();
2492 }
2493
Greg Daniel164a9f02016-02-22 09:56:40 -05002494 // Change layout of our target so it can be used as copy
egdaniel66933552016-08-24 07:22:19 -07002495 image->setImageLayout(this,
2496 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
2497 VK_ACCESS_TRANSFER_READ_BIT,
2498 VK_PIPELINE_STAGE_TRANSFER_BIT,
2499 false);
Greg Daniel164a9f02016-02-22 09:56:40 -05002500
Brian Salomonc320b152018-02-20 14:05:36 -05002501 int bpp = GrColorTypeBytesPerPixel(dstColorType);
egdaniel6fa0a912016-09-12 11:51:29 -07002502 size_t tightRowBytes = bpp * width;
Greg Daniel164a9f02016-02-22 09:56:40 -05002503
Greg Daniel164a9f02016-02-22 09:56:40 -05002504 VkBufferImageCopy region;
2505 memset(&region, 0, sizeof(VkBufferImageCopy));
egdaniel6fa0a912016-09-12 11:51:29 -07002506
2507 bool copyFromOrigin = this->vkCaps().mustDoCopiesFromOrigin();
2508 if (copyFromOrigin) {
2509 region.imageOffset = { 0, 0, 0 };
Brian Salomona6948702018-06-01 15:33:20 -04002510 region.imageExtent = { (uint32_t)(left + width), (uint32_t)(top + height), 1 };
egdaniel6fa0a912016-09-12 11:51:29 -07002511 } else {
Brian Salomona6948702018-06-01 15:33:20 -04002512 VkOffset3D offset = { left, top, 0 };
egdaniel6fa0a912016-09-12 11:51:29 -07002513 region.imageOffset = offset;
2514 region.imageExtent = { (uint32_t)width, (uint32_t)height, 1 };
2515 }
2516
2517 size_t transBufferRowBytes = bpp * region.imageExtent.width;
Greg Daniel386a9b62018-07-03 10:52:30 -04002518 size_t imageRows = region.imageExtent.height;
Brian Salomon12d22642019-01-29 14:38:50 -05002519 auto transferBuffer = sk_sp<GrVkTransferBuffer>(
Greg Daniel3cdfa092018-02-26 16:14:10 -05002520 static_cast<GrVkTransferBuffer*>(this->createBuffer(transBufferRowBytes * imageRows,
Brian Salomonae64c192019-02-05 09:41:37 -05002521 GrGpuBufferType::kXferGpuToCpu,
Brian Salomon12d22642019-01-29 14:38:50 -05002522 kStream_GrAccessPattern)
2523 .release()));
egdaniel6fa0a912016-09-12 11:51:29 -07002524
2525 // Copy the image to a buffer so we can map it to cpu memory
jvanverthdb379092016-07-07 11:18:46 -07002526 region.bufferOffset = transferBuffer->offset();
egdaniel88e8aef2016-06-27 14:34:55 -07002527 region.bufferRowLength = 0; // Forces RowLength to be width. We handle the rowBytes below.
Greg Daniel164a9f02016-02-22 09:56:40 -05002528 region.bufferImageHeight = 0; // Forces height to be tightly packed. Only useful for 3d images.
2529 region.imageSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
Greg Daniel164a9f02016-02-22 09:56:40 -05002530
2531 fCurrentCmdBuffer->copyImageToBuffer(this,
egdaniel66933552016-08-24 07:22:19 -07002532 image,
Greg Daniel164a9f02016-02-22 09:56:40 -05002533 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
Brian Salomon12d22642019-01-29 14:38:50 -05002534 transferBuffer.get(),
Greg Daniel164a9f02016-02-22 09:56:40 -05002535 1,
2536 &region);
2537
2538 // make sure the copy to buffer has finished
2539 transferBuffer->addMemoryBarrier(this,
2540 VK_ACCESS_TRANSFER_WRITE_BIT,
2541 VK_ACCESS_HOST_READ_BIT,
2542 VK_PIPELINE_STAGE_TRANSFER_BIT,
2543 VK_PIPELINE_STAGE_HOST_BIT,
2544 false);
2545
2546 // We need to submit the current command buffer to the Queue and make sure it finishes before
2547 // we can copy the data out of the buffer.
2548 this->submitCommandBuffer(kForce_SyncQueue);
Greg Daniel88fdee92018-02-24 22:41:50 +00002549 void* mappedMemory = transferBuffer->map();
Greg Daniele35a99e2018-03-02 11:44:22 -05002550 const GrVkAlloc& transAlloc = transferBuffer->alloc();
Greg Daniel81df0412018-05-31 13:13:33 -04002551 GrVkMemory::InvalidateMappedAlloc(this, transAlloc, 0, transAlloc.fSize);
Greg Daniel164a9f02016-02-22 09:56:40 -05002552
egdaniel6fa0a912016-09-12 11:51:29 -07002553 if (copyFromOrigin) {
2554 uint32_t skipRows = region.imageExtent.height - height;
2555 mappedMemory = (char*)mappedMemory + transBufferRowBytes * skipRows + bpp * left;
2556 }
2557
Brian Salomona6948702018-06-01 15:33:20 -04002558 SkRectMemcpy(buffer, rowBytes, mappedMemory, transBufferRowBytes, tightRowBytes, height);
Greg Daniel164a9f02016-02-22 09:56:40 -05002559
2560 transferBuffer->unmap();
Greg Daniel164a9f02016-02-22 09:56:40 -05002561 return true;
2562}
egdaniel066df7c2016-06-08 14:02:27 -07002563
egdaniel27bb2842016-07-07 11:58:35 -07002564// The RenderArea bounds we pass into BeginRenderPass must have a start x value that is a multiple
2565// of the granularity. The width must also be a multiple of the granularity or eaqual to the width
2566// the the entire attachment. Similar requirements for the y and height components.
2567void adjust_bounds_to_granularity(SkIRect* dstBounds, const SkIRect& srcBounds,
2568 const VkExtent2D& granularity, int maxWidth, int maxHeight) {
2569 // Adjust Width
egdanield5797b32016-09-20 12:57:45 -07002570 if ((0 != granularity.width && 1 != granularity.width)) {
2571 // Start with the right side of rect so we know if we end up going pass the maxWidth.
2572 int rightAdj = srcBounds.fRight % granularity.width;
2573 if (rightAdj != 0) {
2574 rightAdj = granularity.width - rightAdj;
2575 }
2576 dstBounds->fRight = srcBounds.fRight + rightAdj;
2577 if (dstBounds->fRight > maxWidth) {
2578 dstBounds->fRight = maxWidth;
2579 dstBounds->fLeft = 0;
2580 } else {
2581 dstBounds->fLeft = srcBounds.fLeft - srcBounds.fLeft % granularity.width;
2582 }
egdaniel27bb2842016-07-07 11:58:35 -07002583 } else {
egdanield5797b32016-09-20 12:57:45 -07002584 dstBounds->fLeft = srcBounds.fLeft;
2585 dstBounds->fRight = srcBounds.fRight;
egdaniel27bb2842016-07-07 11:58:35 -07002586 }
2587
2588 // Adjust height
egdanield5797b32016-09-20 12:57:45 -07002589 if ((0 != granularity.height && 1 != granularity.height)) {
2590 // Start with the bottom side of rect so we know if we end up going pass the maxHeight.
2591 int bottomAdj = srcBounds.fBottom % granularity.height;
2592 if (bottomAdj != 0) {
2593 bottomAdj = granularity.height - bottomAdj;
2594 }
2595 dstBounds->fBottom = srcBounds.fBottom + bottomAdj;
2596 if (dstBounds->fBottom > maxHeight) {
2597 dstBounds->fBottom = maxHeight;
2598 dstBounds->fTop = 0;
2599 } else {
2600 dstBounds->fTop = srcBounds.fTop - srcBounds.fTop % granularity.height;
2601 }
egdaniel27bb2842016-07-07 11:58:35 -07002602 } else {
egdanield5797b32016-09-20 12:57:45 -07002603 dstBounds->fTop = srcBounds.fTop;
2604 dstBounds->fBottom = srcBounds.fBottom;
egdaniel27bb2842016-07-07 11:58:35 -07002605 }
2606}
2607
Greg Daniel22bc8652017-03-22 15:45:43 -04002608void GrVkGpu::submitSecondaryCommandBuffer(const SkTArray<GrVkSecondaryCommandBuffer*>& buffers,
egdaniel9cb63402016-06-23 08:37:05 -07002609 const GrVkRenderPass* renderPass,
2610 const VkClearValue* colorClear,
Robert Phillipsb0e93a22017-08-29 08:26:54 -04002611 GrVkRenderTarget* target, GrSurfaceOrigin origin,
egdaniel9cb63402016-06-23 08:37:05 -07002612 const SkIRect& bounds) {
Greg Danielbe7fc462019-01-03 16:40:42 -05002613 SkASSERT (!target->wrapsSecondaryCommandBuffer());
egdaniele7d1b242016-07-01 08:06:45 -07002614 const SkIRect* pBounds = &bounds;
2615 SkIRect flippedBounds;
Robert Phillipsb0e93a22017-08-29 08:26:54 -04002616 if (kBottomLeft_GrSurfaceOrigin == origin) {
egdaniele7d1b242016-07-01 08:06:45 -07002617 flippedBounds = bounds;
2618 flippedBounds.fTop = target->height() - bounds.fBottom;
2619 flippedBounds.fBottom = target->height() - bounds.fTop;
2620 pBounds = &flippedBounds;
2621 }
2622
egdaniel27bb2842016-07-07 11:58:35 -07002623 // The bounds we use for the render pass should be of the granularity supported
2624 // by the device.
2625 const VkExtent2D& granularity = renderPass->granularity();
2626 SkIRect adjustedBounds;
2627 if ((0 != granularity.width && 1 != granularity.width) ||
2628 (0 != granularity.height && 1 != granularity.height)) {
2629 adjust_bounds_to_granularity(&adjustedBounds, *pBounds, granularity,
2630 target->width(), target->height());
2631 pBounds = &adjustedBounds;
2632 }
2633
Robert Phillips95214472017-08-08 18:00:03 -04002634#ifdef SK_DEBUG
2635 uint32_t index;
2636 bool result = renderPass->colorAttachmentIndex(&index);
2637 SkASSERT(result && 0 == index);
2638 result = renderPass->stencilAttachmentIndex(&index);
2639 if (result) {
2640 SkASSERT(1 == index);
2641 }
2642#endif
2643 VkClearValue clears[2];
2644 clears[0].color = colorClear->color;
Robert Phillips8c326e92017-08-10 13:50:17 -04002645 clears[1].depthStencil.depth = 0.0f;
2646 clears[1].depthStencil.stencil = 0;
Robert Phillips95214472017-08-08 18:00:03 -04002647
2648 fCurrentCmdBuffer->beginRenderPass(this, renderPass, clears, *target, *pBounds, true);
Greg Daniel22bc8652017-03-22 15:45:43 -04002649 for (int i = 0; i < buffers.count(); ++i) {
2650 fCurrentCmdBuffer->executeCommands(this, buffers[i]);
2651 }
Greg Daniel164a9f02016-02-22 09:56:40 -05002652 fCurrentCmdBuffer->endRenderPass(this);
egdaniel66933552016-08-24 07:22:19 -07002653
Brian Salomon1fabd512018-02-09 09:54:25 -05002654 this->didWriteToSurface(target, origin, &bounds);
Greg Daniel164a9f02016-02-22 09:56:40 -05002655}
egdaniel9cb63402016-06-23 08:37:05 -07002656
Robert Phillips5b5d84c2018-08-09 15:12:18 -04002657void GrVkGpu::submit(GrGpuCommandBuffer* buffer) {
2658 if (buffer->asRTCommandBuffer()) {
2659 SkASSERT(fCachedRTCommandBuffer.get() == buffer);
2660
2661 fCachedRTCommandBuffer->submit();
2662 fCachedRTCommandBuffer->reset();
2663 } else {
2664 SkASSERT(fCachedTexCommandBuffer.get() == buffer);
2665
2666 fCachedTexCommandBuffer->submit();
2667 fCachedTexCommandBuffer->reset();
2668 }
2669}
2670
Greg Daniel6be35232017-03-01 17:01:09 -05002671GrFence SK_WARN_UNUSED_RESULT GrVkGpu::insertFence() {
jvanverth84741b32016-09-30 08:39:02 -07002672 VkFenceCreateInfo createInfo;
2673 memset(&createInfo, 0, sizeof(VkFenceCreateInfo));
2674 createInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
2675 createInfo.pNext = nullptr;
2676 createInfo.flags = 0;
2677 VkFence fence = VK_NULL_HANDLE;
Greg Daniel6be35232017-03-01 17:01:09 -05002678
2679 VK_CALL_ERRCHECK(CreateFence(this->device(), &createInfo, nullptr, &fence));
2680 VK_CALL(QueueSubmit(this->queue(), 0, nullptr, fence));
2681
2682 GR_STATIC_ASSERT(sizeof(GrFence) >= sizeof(VkFence));
jvanverth84741b32016-09-30 08:39:02 -07002683 return (GrFence)fence;
2684}
2685
Greg Daniel6be35232017-03-01 17:01:09 -05002686bool GrVkGpu::waitFence(GrFence fence, uint64_t timeout) {
2687 SkASSERT(VK_NULL_HANDLE != (VkFence)fence);
2688
2689 VkResult result = VK_CALL(WaitForFences(this->device(), 1, (VkFence*)&fence, VK_TRUE, timeout));
jvanverth84741b32016-09-30 08:39:02 -07002690 return (VK_SUCCESS == result);
2691}
2692
2693void GrVkGpu::deleteFence(GrFence fence) const {
Greg Daniel6be35232017-03-01 17:01:09 -05002694 VK_CALL(DestroyFence(this->device(), (VkFence)fence, nullptr));
2695}
2696
Greg Daniela5cb7812017-06-16 09:45:32 -04002697sk_sp<GrSemaphore> SK_WARN_UNUSED_RESULT GrVkGpu::makeSemaphore(bool isOwned) {
2698 return GrVkSemaphore::Make(this, isOwned);
Greg Daniel6be35232017-03-01 17:01:09 -05002699}
2700
Greg Daniel48661b82018-01-22 16:11:35 -05002701sk_sp<GrSemaphore> GrVkGpu::wrapBackendSemaphore(const GrBackendSemaphore& semaphore,
2702 GrResourceProvider::SemaphoreWrapType wrapType,
2703 GrWrapOwnership ownership) {
2704 return GrVkSemaphore::MakeWrapped(this, semaphore.vkSemaphore(), wrapType, ownership);
Greg Daniela5cb7812017-06-16 09:45:32 -04002705}
2706
Greg Daniel858e12c2018-12-06 11:11:37 -05002707void GrVkGpu::insertSemaphore(sk_sp<GrSemaphore> semaphore) {
Greg Daniel6be35232017-03-01 17:01:09 -05002708 GrVkSemaphore* vkSem = static_cast<GrVkSemaphore*>(semaphore.get());
2709
Greg Daniel48661b82018-01-22 16:11:35 -05002710 GrVkSemaphore::Resource* resource = vkSem->getResource();
2711 if (resource->shouldSignal()) {
Greg Daniel17b7c052018-01-09 13:55:33 -05002712 resource->ref();
2713 fSemaphoresToSignal.push_back(resource);
2714 }
Greg Daniel6be35232017-03-01 17:01:09 -05002715}
2716
Greg Daniel48661b82018-01-22 16:11:35 -05002717void GrVkGpu::waitSemaphore(sk_sp<GrSemaphore> semaphore) {
Greg Daniel6be35232017-03-01 17:01:09 -05002718 GrVkSemaphore* vkSem = static_cast<GrVkSemaphore*>(semaphore.get());
2719
Greg Daniel48661b82018-01-22 16:11:35 -05002720 GrVkSemaphore::Resource* resource = vkSem->getResource();
2721 if (resource->shouldWait()) {
2722 resource->ref();
2723 fSemaphoresToWaitOn.push_back(resource);
2724 }
jvanverth84741b32016-09-30 08:39:02 -07002725}
Brian Osman13dddce2017-05-09 13:19:50 -04002726
2727sk_sp<GrSemaphore> GrVkGpu::prepareTextureForCrossContextUsage(GrTexture* texture) {
2728 SkASSERT(texture);
2729 GrVkTexture* vkTexture = static_cast<GrVkTexture*>(texture);
2730 vkTexture->setImageLayout(this,
2731 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
2732 VK_ACCESS_SHADER_READ_BIT,
Greg Danielf7828d02018-10-09 12:01:32 -04002733 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
Brian Osman13dddce2017-05-09 13:19:50 -04002734 false);
2735 this->submitCommandBuffer(kSkip_SyncQueue);
2736
Greg Danielb3f66542019-05-10 17:11:19 -04002737 // The image layout change serves as a barrier, so no semaphore is needed.
2738 // If we ever decide we need to return a semaphore here, we need to make sure GrVkSemaphore is
2739 // thread safe so that only the first thread that tries to use the semaphore actually submits
2740 // it. This additionally would also require thread safety in command buffer submissions to
2741 // queues in general.
Brian Osman13dddce2017-05-09 13:19:50 -04002742 return nullptr;
2743}
Greg Danielf5d87582017-12-18 14:48:15 -05002744
Greg Daniel64cc9aa2018-10-19 13:54:56 -04002745void GrVkGpu::addDrawable(std::unique_ptr<SkDrawable::GpuDrawHandler> drawable) {
2746 fDrawables.emplace_back(std::move(drawable));
2747}
2748
Greg Daniel7a82edf2018-12-04 10:54:34 -05002749uint32_t GrVkGpu::getExtraSamplerKeyForProgram(const GrSamplerState& samplerState,
2750 const GrBackendFormat& format) {
2751 const GrVkYcbcrConversionInfo* ycbcrInfo = format.getVkYcbcrConversionInfo();
2752 SkASSERT(ycbcrInfo);
2753 if (!ycbcrInfo->isValid()) {
2754 return 0;
2755 }
2756
2757 const GrVkSampler* sampler = this->resourceProvider().findOrCreateCompatibleSampler(
2758 samplerState, *ycbcrInfo);
2759
2760 return sampler->uniqueID();
2761}
2762
Greg Daniela870b462019-01-08 15:49:46 -05002763void GrVkGpu::storeVkPipelineCacheData() {
Robert Phillips9da87e02019-02-04 13:26:26 -05002764 if (this->getContext()->priv().getPersistentCache()) {
Greg Daniela870b462019-01-08 15:49:46 -05002765 this->resourceProvider().storePipelineCacheData();
2766 }
2767}