• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
8 #include "src/gpu/vk/GrVkGpu.h"
9 
10 #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/GrDataUtils.h"
18 #include "src/gpu/GrGeometryProcessor.h"
19 #include "src/gpu/GrGpuResourceCacheAccess.h"
20 #include "src/gpu/GrMesh.h"
21 #include "src/gpu/GrPipeline.h"
22 #include "src/gpu/GrRenderTargetContext.h"
23 #include "src/gpu/GrRenderTargetPriv.h"
24 #include "src/gpu/GrTexturePriv.h"
25 #include "src/gpu/SkGpuDevice.h"
26 #include "src/gpu/SkGr.h"
27 #include "src/gpu/vk/GrVkAMDMemoryAllocator.h"
28 #include "src/gpu/vk/GrVkCommandBuffer.h"
29 #include "src/gpu/vk/GrVkCommandPool.h"
30 #include "src/gpu/vk/GrVkGpuCommandBuffer.h"
31 #include "src/gpu/vk/GrVkImage.h"
32 #include "src/gpu/vk/GrVkIndexBuffer.h"
33 #include "src/gpu/vk/GrVkInterface.h"
34 #include "src/gpu/vk/GrVkMemory.h"
35 #include "src/gpu/vk/GrVkPipeline.h"
36 #include "src/gpu/vk/GrVkPipelineState.h"
37 #include "src/gpu/vk/GrVkRenderPass.h"
38 #include "src/gpu/vk/GrVkResourceProvider.h"
39 #include "src/gpu/vk/GrVkSemaphore.h"
40 #include "src/gpu/vk/GrVkTexture.h"
41 #include "src/gpu/vk/GrVkTextureRenderTarget.h"
42 #include "src/gpu/vk/GrVkTransferBuffer.h"
43 #include "src/gpu/vk/GrVkVertexBuffer.h"
44 #include "src/image/SkImage_Gpu.h"
45 #include "src/image/SkSurface_Gpu.h"
46 #include "src/sksl/SkSLCompiler.h"
47 
48 #include "include/gpu/vk/GrVkExtensions.h"
49 #include "include/gpu/vk/GrVkTypes.h"
50 
51 #include <utility>
52 
53 #if !defined(SK_BUILD_FOR_WIN)
54 #include <unistd.h>
55 #endif // !defined(SK_BUILD_FOR_WIN)
56 
57 #if defined(SK_BUILD_FOR_WIN) && defined(SK_DEBUG)
58 #include "src/core/SkLeanWindows.h"
59 #endif
60 
61 #define VK_CALL(X) GR_VK_CALL(this->vkInterface(), X)
62 #define VK_CALL_RET(RET, X) GR_VK_CALL_RET(this->vkInterface(), RET, X)
63 #define VK_CALL_ERRCHECK(X) GR_VK_CALL_ERRCHECK(this->vkInterface(), X)
64 
Make(const GrVkBackendContext & backendContext,const GrContextOptions & options,GrContext * context)65 sk_sp<GrGpu> GrVkGpu::Make(const GrVkBackendContext& backendContext,
66                            const GrContextOptions& options, GrContext* context) {
67     if (backendContext.fInstance == VK_NULL_HANDLE ||
68         backendContext.fPhysicalDevice == VK_NULL_HANDLE ||
69         backendContext.fDevice == VK_NULL_HANDLE ||
70         backendContext.fQueue == VK_NULL_HANDLE) {
71         return nullptr;
72     }
73     if (!backendContext.fGetProc) {
74         return nullptr;
75     }
76 
77     PFN_vkEnumerateInstanceVersion localEnumerateInstanceVersion =
78             reinterpret_cast<PFN_vkEnumerateInstanceVersion>(
79                     backendContext.fGetProc("vkEnumerateInstanceVersion",
80                                             VK_NULL_HANDLE, VK_NULL_HANDLE));
81     uint32_t instanceVersion = 0;
82     if (!localEnumerateInstanceVersion) {
83         instanceVersion = VK_MAKE_VERSION(1, 0, 0);
84     } else {
85         VkResult err = localEnumerateInstanceVersion(&instanceVersion);
86         if (err) {
87             SkDebugf("Failed to enumerate instance version. Err: %d\n", err);
88             return nullptr;
89         }
90     }
91 
92     PFN_vkGetPhysicalDeviceProperties localGetPhysicalDeviceProperties =
93             reinterpret_cast<PFN_vkGetPhysicalDeviceProperties>(
94                     backendContext.fGetProc("vkGetPhysicalDeviceProperties",
95                                             backendContext.fInstance,
96                                             VK_NULL_HANDLE));
97 
98     if (!localGetPhysicalDeviceProperties) {
99         return nullptr;
100     }
101     VkPhysicalDeviceProperties physDeviceProperties;
102     localGetPhysicalDeviceProperties(backendContext.fPhysicalDevice, &physDeviceProperties);
103     uint32_t physDevVersion = physDeviceProperties.apiVersion;
104 
105     uint32_t apiVersion = backendContext.fMaxAPIVersion ? backendContext.fMaxAPIVersion
106                                                         : instanceVersion;
107 
108     instanceVersion = SkTMin(instanceVersion, apiVersion);
109     physDevVersion = SkTMin(physDevVersion, apiVersion);
110 
111     sk_sp<const GrVkInterface> interface;
112 
113     if (backendContext.fVkExtensions) {
114         interface.reset(new GrVkInterface(backendContext.fGetProc,
115                                           backendContext.fInstance,
116                                           backendContext.fDevice,
117                                           instanceVersion,
118                                           physDevVersion,
119                                           backendContext.fVkExtensions));
120         if (!interface->validate(instanceVersion, physDevVersion, backendContext.fVkExtensions)) {
121             return nullptr;
122         }
123     } else {
124         GrVkExtensions extensions;
125         // The only extension flag that may effect the vulkan backend is the swapchain extension. We
126         // need to know if this is enabled to know if we can transition to a present layout when
127         // flushing a surface.
128         if (backendContext.fExtensions & kKHR_swapchain_GrVkExtensionFlag) {
129             const char* swapChainExtName = VK_KHR_SWAPCHAIN_EXTENSION_NAME;
130             extensions.init(backendContext.fGetProc, backendContext.fInstance,
131                             backendContext.fPhysicalDevice, 0, nullptr, 1, &swapChainExtName);
132         }
133         interface.reset(new GrVkInterface(backendContext.fGetProc,
134                                           backendContext.fInstance,
135                                           backendContext.fDevice,
136                                           instanceVersion,
137                                           physDevVersion,
138                                           &extensions));
139         if (!interface->validate(instanceVersion, physDevVersion, &extensions)) {
140             return nullptr;
141         }
142     }
143 
144      sk_sp<GrVkGpu> vkGpu(new GrVkGpu(context, options, backendContext, interface,
145                                        instanceVersion, physDevVersion));
146      if (backendContext.fProtectedContext == GrProtected::kYes &&
147          !vkGpu->vkCaps().supportsProtectedMemory()) {
148          return nullptr;
149      }
150      return vkGpu;
151 }
152 
153 ////////////////////////////////////////////////////////////////////////////////
154 
GrVkGpu(GrContext * context,const GrContextOptions & options,const GrVkBackendContext & backendContext,sk_sp<const GrVkInterface> interface,uint32_t instanceVersion,uint32_t physicalDeviceVersion)155 GrVkGpu::GrVkGpu(GrContext* context, const GrContextOptions& options,
156                  const GrVkBackendContext& backendContext, sk_sp<const GrVkInterface> interface,
157                  uint32_t instanceVersion, uint32_t physicalDeviceVersion)
158         : INHERITED(context)
159         , fInterface(std::move(interface))
160         , fMemoryAllocator(backendContext.fMemoryAllocator)
161         , fInstance(backendContext.fInstance)
162         , fPhysicalDevice(backendContext.fPhysicalDevice)
163         , fDevice(backendContext.fDevice)
164         , fQueue(backendContext.fQueue)
165         , fQueueIndex(backendContext.fGraphicsQueueIndex)
166         , fResourceProvider(this)
167         , fDisconnected(false)
168         , fProtectedContext(backendContext.fProtectedContext) {
169     SkASSERT(!backendContext.fOwnsInstanceAndDevice);
170 
171     if (!fMemoryAllocator) {
172         // We were not given a memory allocator at creation
173         fMemoryAllocator.reset(new GrVkAMDMemoryAllocator(backendContext.fPhysicalDevice,
174                                                           fDevice, fInterface));
175     }
176 
177     fCompiler = new SkSL::Compiler();
178 
179     if (backendContext.fDeviceFeatures2) {
180         fVkCaps.reset(new GrVkCaps(options, this->vkInterface(), backendContext.fPhysicalDevice,
181                                    *backendContext.fDeviceFeatures2, instanceVersion,
182                                    physicalDeviceVersion,
183                                    *backendContext.fVkExtensions, fProtectedContext));
184     } else if (backendContext.fDeviceFeatures) {
185         VkPhysicalDeviceFeatures2 features2;
186         features2.pNext = nullptr;
187         features2.features = *backendContext.fDeviceFeatures;
188         fVkCaps.reset(new GrVkCaps(options, this->vkInterface(), backendContext.fPhysicalDevice,
189                                    features2, instanceVersion, physicalDeviceVersion,
190                                    *backendContext.fVkExtensions, fProtectedContext));
191     } else {
192         VkPhysicalDeviceFeatures2 features;
193         memset(&features, 0, sizeof(VkPhysicalDeviceFeatures2));
194         features.pNext = nullptr;
195         if (backendContext.fFeatures & kGeometryShader_GrVkFeatureFlag) {
196             features.features.geometryShader = true;
197         }
198         if (backendContext.fFeatures & kDualSrcBlend_GrVkFeatureFlag) {
199             features.features.dualSrcBlend = true;
200         }
201         if (backendContext.fFeatures & kSampleRateShading_GrVkFeatureFlag) {
202             features.features.sampleRateShading = true;
203         }
204         GrVkExtensions extensions;
205         // The only extension flag that may effect the vulkan backend is the swapchain extension. We
206         // need to know if this is enabled to know if we can transition to a present layout when
207         // flushing a surface.
208         if (backendContext.fExtensions & kKHR_swapchain_GrVkExtensionFlag) {
209             const char* swapChainExtName = VK_KHR_SWAPCHAIN_EXTENSION_NAME;
210             extensions.init(backendContext.fGetProc, backendContext.fInstance,
211                             backendContext.fPhysicalDevice, 0, nullptr, 1, &swapChainExtName);
212         }
213         fVkCaps.reset(new GrVkCaps(options, this->vkInterface(), backendContext.fPhysicalDevice,
214                                    features, instanceVersion, physicalDeviceVersion, extensions,
215                                    fProtectedContext));
216     }
217     fCaps.reset(SkRef(fVkCaps.get()));
218 
219     VK_CALL(GetPhysicalDeviceProperties(backendContext.fPhysicalDevice, &fPhysDevProps));
220     VK_CALL(GetPhysicalDeviceMemoryProperties(backendContext.fPhysicalDevice, &fPhysDevMemProps));
221 
222     fResourceProvider.init();
223 
224     fCmdPool = fResourceProvider.findOrCreateCommandPool();
225     fCurrentCmdBuffer = fCmdPool->getPrimaryCommandBuffer();
226     SkASSERT(fCurrentCmdBuffer);
227     fCurrentCmdBuffer->begin(this);
228 }
229 
destroyResources()230 void GrVkGpu::destroyResources() {
231     if (fCmdPool) {
232         fCmdPool->getPrimaryCommandBuffer()->end(this);
233         fCmdPool->close();
234     }
235 
236     // wait for all commands to finish
237     VkResult res = VK_CALL(QueueWaitIdle(fQueue));
238 
239     // On windows, sometimes calls to QueueWaitIdle return before actually signalling the fences
240     // on the command buffers even though they have completed. This causes an assert to fire when
241     // destroying the command buffers. Currently this ony seems to happen on windows, so we add a
242     // sleep to make sure the fence signals.
243 #ifdef SK_DEBUG
244     if (this->vkCaps().mustSleepOnTearDown()) {
245 #if defined(SK_BUILD_FOR_WIN)
246         Sleep(10); // In milliseconds
247 #else
248         sleep(1);  // In seconds
249 #endif
250     }
251 #endif
252 
253 #ifdef SK_DEBUG
254     SkASSERT(VK_SUCCESS == res || VK_ERROR_DEVICE_LOST == res);
255 #endif
256 
257     if (fCmdPool) {
258         fCmdPool->unref(this);
259         fCmdPool = nullptr;
260     }
261 
262     for (int i = 0; i < fSemaphoresToWaitOn.count(); ++i) {
263         fSemaphoresToWaitOn[i]->unref(this);
264     }
265     fSemaphoresToWaitOn.reset();
266 
267     for (int i = 0; i < fSemaphoresToSignal.count(); ++i) {
268         fSemaphoresToSignal[i]->unref(this);
269     }
270     fSemaphoresToSignal.reset();
271 
272     // must call this just before we destroy the command pool and VkDevice
273     fResourceProvider.destroyResources(VK_ERROR_DEVICE_LOST == res);
274 
275     fMemoryAllocator.reset();
276 
277     fQueue = VK_NULL_HANDLE;
278     fDevice = VK_NULL_HANDLE;
279     fInstance = VK_NULL_HANDLE;
280 }
281 
~GrVkGpu()282 GrVkGpu::~GrVkGpu() {
283     if (!fDisconnected) {
284         this->destroyResources();
285     }
286     delete fCompiler;
287 }
288 
289 
disconnect(DisconnectType type)290 void GrVkGpu::disconnect(DisconnectType type) {
291     INHERITED::disconnect(type);
292     if (!fDisconnected) {
293         if (DisconnectType::kCleanup == type) {
294             this->destroyResources();
295         } else {
296             if (fCmdPool) {
297                 fCmdPool->unrefAndAbandon();
298                 fCmdPool = nullptr;
299             }
300             for (int i = 0; i < fSemaphoresToWaitOn.count(); ++i) {
301                 fSemaphoresToWaitOn[i]->unrefAndAbandon();
302             }
303             for (int i = 0; i < fSemaphoresToSignal.count(); ++i) {
304                 fSemaphoresToSignal[i]->unrefAndAbandon();
305             }
306 
307             // must call this just before we destroy the command pool and VkDevice
308             fResourceProvider.abandonResources();
309 
310             fMemoryAllocator.reset();
311         }
312         fSemaphoresToWaitOn.reset();
313         fSemaphoresToSignal.reset();
314         fCurrentCmdBuffer = nullptr;
315         fDisconnected = true;
316     }
317 }
318 
319 ///////////////////////////////////////////////////////////////////////////////
320 
getCommandBuffer(GrRenderTarget * rt,GrSurfaceOrigin origin,const SkRect & bounds,const GrGpuRTCommandBuffer::LoadAndStoreInfo & colorInfo,const GrGpuRTCommandBuffer::StencilLoadAndStoreInfo & stencilInfo)321 GrGpuRTCommandBuffer* GrVkGpu::getCommandBuffer(
322             GrRenderTarget* rt, GrSurfaceOrigin origin, const SkRect& bounds,
323             const GrGpuRTCommandBuffer::LoadAndStoreInfo& colorInfo,
324             const GrGpuRTCommandBuffer::StencilLoadAndStoreInfo& stencilInfo) {
325     if (!fCachedRTCommandBuffer) {
326         fCachedRTCommandBuffer.reset(new GrVkGpuRTCommandBuffer(this));
327     }
328 
329     fCachedRTCommandBuffer->set(rt, origin, colorInfo, stencilInfo);
330     return fCachedRTCommandBuffer.get();
331 }
332 
getCommandBuffer(GrTexture * texture,GrSurfaceOrigin origin)333 GrGpuTextureCommandBuffer* GrVkGpu::getCommandBuffer(GrTexture* texture, GrSurfaceOrigin origin) {
334     if (!fCachedTexCommandBuffer) {
335         fCachedTexCommandBuffer.reset(new GrVkGpuTextureCommandBuffer(this));
336     }
337 
338     fCachedTexCommandBuffer->set(texture, origin);
339     return fCachedTexCommandBuffer.get();
340 }
341 
submitCommandBuffer(SyncQueue sync,GrGpuFinishedProc finishedProc,GrGpuFinishedContext finishedContext)342 void GrVkGpu::submitCommandBuffer(SyncQueue sync, GrGpuFinishedProc finishedProc,
343                                   GrGpuFinishedContext finishedContext) {
344     TRACE_EVENT0("skia.gpu", TRACE_FUNC);
345     SkASSERT(fCurrentCmdBuffer);
346     SkASSERT(!fCachedRTCommandBuffer || !fCachedRTCommandBuffer->isActive());
347     SkASSERT(!fCachedTexCommandBuffer || !fCachedTexCommandBuffer->isActive());
348 
349     if (!fCurrentCmdBuffer->hasWork() && kForce_SyncQueue != sync &&
350         !fSemaphoresToSignal.count() && !fSemaphoresToWaitOn.count()) {
351         SkASSERT(fDrawables.empty());
352         fResourceProvider.checkCommandBuffers();
353         if (finishedProc) {
354             fResourceProvider.addFinishedProcToActiveCommandBuffers(finishedProc, finishedContext);
355         }
356         return;
357     }
358 
359     fCurrentCmdBuffer->end(this);
360     fCmdPool->close();
361     fCurrentCmdBuffer->submitToQueue(this, fQueue, sync, fSemaphoresToSignal, fSemaphoresToWaitOn);
362 
363     if (finishedProc) {
364         // Make sure this is called after closing the current command pool
365         fResourceProvider.addFinishedProcToActiveCommandBuffers(finishedProc, finishedContext);
366     }
367 
368     // We must delete and drawables that have been waitint till submit for us to destroy.
369     fDrawables.reset();
370 
371     for (int i = 0; i < fSemaphoresToWaitOn.count(); ++i) {
372         fSemaphoresToWaitOn[i]->unref(this);
373     }
374     fSemaphoresToWaitOn.reset();
375     for (int i = 0; i < fSemaphoresToSignal.count(); ++i) {
376         fSemaphoresToSignal[i]->unref(this);
377     }
378     fSemaphoresToSignal.reset();
379 
380     // Release old command pool and create a new one
381     fCmdPool->unref(this);
382     fResourceProvider.checkCommandBuffers();
383     fCmdPool = fResourceProvider.findOrCreateCommandPool();
384     fCurrentCmdBuffer = fCmdPool->getPrimaryCommandBuffer();
385     fCurrentCmdBuffer->begin(this);
386 }
387 
388 ///////////////////////////////////////////////////////////////////////////////
onCreateBuffer(size_t size,GrGpuBufferType type,GrAccessPattern accessPattern,const void * data)389 sk_sp<GrGpuBuffer> GrVkGpu::onCreateBuffer(size_t size, GrGpuBufferType type,
390                                            GrAccessPattern accessPattern, const void* data) {
391     sk_sp<GrGpuBuffer> buff;
392     switch (type) {
393         case GrGpuBufferType::kVertex:
394             SkASSERT(kDynamic_GrAccessPattern == accessPattern ||
395                      kStatic_GrAccessPattern == accessPattern);
396             buff = GrVkVertexBuffer::Make(this, size, kDynamic_GrAccessPattern == accessPattern);
397             break;
398         case GrGpuBufferType::kIndex:
399             SkASSERT(kDynamic_GrAccessPattern == accessPattern ||
400                      kStatic_GrAccessPattern == accessPattern);
401             buff = GrVkIndexBuffer::Make(this, size, kDynamic_GrAccessPattern == accessPattern);
402             break;
403         case GrGpuBufferType::kXferCpuToGpu:
404             SkASSERT(kDynamic_GrAccessPattern == accessPattern ||
405                      kStream_GrAccessPattern == accessPattern);
406             buff = GrVkTransferBuffer::Make(this, size, GrVkBuffer::kCopyRead_Type);
407             break;
408         case GrGpuBufferType::kXferGpuToCpu:
409             SkASSERT(kDynamic_GrAccessPattern == accessPattern ||
410                      kStream_GrAccessPattern == accessPattern);
411             buff = GrVkTransferBuffer::Make(this, size, GrVkBuffer::kCopyWrite_Type);
412             break;
413         default:
414             SK_ABORT("Unknown buffer type.");
415     }
416     if (data && buff) {
417         buff->updateData(data, size);
418     }
419     return buff;
420 }
421 
onWritePixels(GrSurface * surface,int left,int top,int width,int height,GrColorType surfaceColorType,GrColorType srcColorType,const GrMipLevel texels[],int mipLevelCount)422 bool GrVkGpu::onWritePixels(GrSurface* surface, int left, int top, int width, int height,
423                             GrColorType surfaceColorType, GrColorType srcColorType,
424                             const GrMipLevel texels[], int mipLevelCount) {
425     GrVkTexture* vkTex = static_cast<GrVkTexture*>(surface->asTexture());
426     if (!vkTex) {
427         return false;
428     }
429 
430     // Make sure we have at least the base level
431     if (!mipLevelCount || !texels[0].fPixels) {
432         return false;
433     }
434 
435     SkASSERT(!GrVkFormatIsCompressed(vkTex->imageFormat()));
436     bool success = false;
437     bool linearTiling = vkTex->isLinearTiled();
438     if (linearTiling) {
439         if (mipLevelCount > 1) {
440             SkDebugf("Can't upload mipmap data to linear tiled texture");
441             return false;
442         }
443         if (VK_IMAGE_LAYOUT_PREINITIALIZED != vkTex->currentLayout()) {
444             // Need to change the layout to general in order to perform a host write
445             vkTex->setImageLayout(this,
446                                   VK_IMAGE_LAYOUT_GENERAL,
447                                   VK_ACCESS_HOST_WRITE_BIT,
448                                   VK_PIPELINE_STAGE_HOST_BIT,
449                                   false);
450             this->submitCommandBuffer(kForce_SyncQueue);
451         }
452         success = this->uploadTexDataLinear(vkTex, left, top, width, height, srcColorType,
453                                             texels[0].fPixels, texels[0].fRowBytes);
454     } else {
455         SkASSERT(mipLevelCount <= vkTex->texturePriv().maxMipMapLevel() + 1);
456         success = this->uploadTexDataOptimal(vkTex, left, top, width, height, srcColorType, texels,
457                                              mipLevelCount);
458     }
459 
460     return success;
461 }
462 
onTransferPixelsTo(GrTexture * texture,int left,int top,int width,int height,GrColorType surfaceColorType,GrColorType bufferColorType,GrGpuBuffer * transferBuffer,size_t bufferOffset,size_t rowBytes)463 bool GrVkGpu::onTransferPixelsTo(GrTexture* texture, int left, int top, int width, int height,
464                                  GrColorType surfaceColorType, GrColorType bufferColorType,
465                                  GrGpuBuffer* transferBuffer, size_t bufferOffset,
466                                  size_t rowBytes) {
467     // Vulkan only supports offsets that are both 4-byte aligned and aligned to a pixel.
468     if ((bufferOffset & 0x3) || (bufferOffset % GrColorTypeBytesPerPixel(bufferColorType))) {
469         return false;
470     }
471     GrVkTexture* vkTex = static_cast<GrVkTexture*>(texture);
472     if (!vkTex) {
473         return false;
474     }
475 
476     // Can't transfer compressed data
477     SkASSERT(!GrVkFormatIsCompressed(vkTex->imageFormat()));
478 
479     GrVkTransferBuffer* vkBuffer = static_cast<GrVkTransferBuffer*>(transferBuffer);
480     if (!vkBuffer) {
481         return false;
482     }
483 
484     SkDEBUGCODE(
485         SkIRect subRect = SkIRect::MakeXYWH(left, top, width, height);
486         SkIRect bounds = SkIRect::MakeWH(texture->width(), texture->height());
487         SkASSERT(bounds.contains(subRect));
488     )
489     size_t bpp = GrColorTypeBytesPerPixel(bufferColorType);
490 
491     // Set up copy region
492     VkBufferImageCopy region;
493     memset(&region, 0, sizeof(VkBufferImageCopy));
494     region.bufferOffset = bufferOffset;
495     region.bufferRowLength = (uint32_t)(rowBytes/bpp);
496     region.bufferImageHeight = 0;
497     region.imageSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
498     region.imageOffset = { left, top, 0 };
499     region.imageExtent = { (uint32_t)width, (uint32_t)height, 1 };
500 
501     // Change layout of our target so it can be copied to
502     vkTex->setImageLayout(this,
503                           VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
504                           VK_ACCESS_TRANSFER_WRITE_BIT,
505                           VK_PIPELINE_STAGE_TRANSFER_BIT,
506                           false);
507 
508     // Copy the buffer to the image
509     fCurrentCmdBuffer->copyBufferToImage(this,
510                                          vkBuffer,
511                                          vkTex,
512                                          VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
513                                          1,
514                                          &region);
515 
516     vkTex->texturePriv().markMipMapsDirty();
517     return true;
518 }
519 
onTransferPixelsFrom(GrSurface * surface,int left,int top,int width,int height,GrColorType surfaceColorType,GrColorType bufferColorType,GrGpuBuffer * transferBuffer,size_t offset)520 bool GrVkGpu::onTransferPixelsFrom(GrSurface* surface, int left, int top, int width, int height,
521                                    GrColorType surfaceColorType, GrColorType bufferColorType,
522                                    GrGpuBuffer* transferBuffer, size_t offset) {
523     SkASSERT(surface);
524     SkASSERT(transferBuffer);
525     if (fProtectedContext == GrProtected::kYes) {
526         return false;
527     }
528 
529     GrVkTransferBuffer* vkBuffer = static_cast<GrVkTransferBuffer*>(transferBuffer);
530 
531     GrVkImage* srcImage;
532     if (GrVkRenderTarget* rt = static_cast<GrVkRenderTarget*>(surface->asRenderTarget())) {
533         // Reading from render targets that wrap a secondary command buffer is not allowed since
534         // it would require us to know the VkImage, which we don't have, as well as need us to
535         // stop and start the VkRenderPass which we don't have access to.
536         if (rt->wrapsSecondaryCommandBuffer()) {
537             return false;
538         }
539         // resolve the render target if necessary
540         switch (rt->getResolveType()) {
541             case GrVkRenderTarget::kCantResolve_ResolveType:
542                 return false;
543             case GrVkRenderTarget::kAutoResolves_ResolveType:
544                 break;
545             case GrVkRenderTarget::kCanResolve_ResolveType:
546                 this->resolveRenderTargetNoFlush(rt);
547                 break;
548             default:
549                 SK_ABORT("Unknown resolve type");
550         }
551         srcImage = rt;
552     } else {
553         srcImage = static_cast<GrVkTexture*>(surface->asTexture());
554     }
555 
556     // Set up copy region
557     VkBufferImageCopy region;
558     memset(&region, 0, sizeof(VkBufferImageCopy));
559     region.bufferOffset = offset;
560     region.bufferRowLength = width;
561     region.bufferImageHeight = 0;
562     region.imageSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
563     region.imageOffset = { left, top, 0 };
564     region.imageExtent = { (uint32_t)width, (uint32_t)height, 1 };
565 
566     srcImage->setImageLayout(this,
567                              VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
568                              VK_ACCESS_TRANSFER_READ_BIT,
569                              VK_PIPELINE_STAGE_TRANSFER_BIT,
570                              false);
571 
572     fCurrentCmdBuffer->copyImageToBuffer(this, srcImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
573                                          vkBuffer, 1, &region);
574 
575     // Make sure the copy to buffer has finished.
576     vkBuffer->addMemoryBarrier(this,
577                                VK_ACCESS_TRANSFER_WRITE_BIT,
578                                VK_ACCESS_HOST_READ_BIT,
579                                VK_PIPELINE_STAGE_TRANSFER_BIT,
580                                VK_PIPELINE_STAGE_HOST_BIT,
581                                false);
582     return true;
583 }
584 
resolveImage(GrSurface * dst,GrVkRenderTarget * src,const SkIRect & srcRect,const SkIPoint & dstPoint)585 void GrVkGpu::resolveImage(GrSurface* dst, GrVkRenderTarget* src, const SkIRect& srcRect,
586                            const SkIPoint& dstPoint) {
587     SkASSERT(dst);
588     SkASSERT(src && src->numSamples() > 1 && src->msaaImage());
589 
590     VkImageResolve resolveInfo;
591     resolveInfo.srcSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1};
592     resolveInfo.srcOffset = {srcRect.fLeft, srcRect.fTop, 0};
593     resolveInfo.dstSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1};
594     resolveInfo.dstOffset = {dstPoint.fX, dstPoint.fY, 0};
595     resolveInfo.extent = {(uint32_t)srcRect.width(), (uint32_t)srcRect.height(), 1};
596 
597     GrVkImage* dstImage;
598     GrRenderTarget* dstRT = dst->asRenderTarget();
599     if (dstRT) {
600         GrVkRenderTarget* vkRT = static_cast<GrVkRenderTarget*>(dstRT);
601         dstImage = vkRT;
602     } else {
603         SkASSERT(dst->asTexture());
604         dstImage = static_cast<GrVkTexture*>(dst->asTexture());
605     }
606     dstImage->setImageLayout(this,
607                              VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
608                              VK_ACCESS_TRANSFER_WRITE_BIT,
609                              VK_PIPELINE_STAGE_TRANSFER_BIT,
610                              false);
611 
612     src->msaaImage()->setImageLayout(this,
613                                      VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
614                                      VK_ACCESS_TRANSFER_READ_BIT,
615                                      VK_PIPELINE_STAGE_TRANSFER_BIT,
616                                      false);
617 
618     fCurrentCmdBuffer->resolveImage(this, *src->msaaImage(), *dstImage, 1, &resolveInfo);
619 }
620 
internalResolveRenderTarget(GrRenderTarget * target,bool requiresSubmit)621 void GrVkGpu::internalResolveRenderTarget(GrRenderTarget* target, bool requiresSubmit) {
622     if (target->needsResolve()) {
623         SkASSERT(target->numSamples() > 1);
624         GrVkRenderTarget* rt = static_cast<GrVkRenderTarget*>(target);
625         SkASSERT(rt->msaaImage());
626 
627         const SkIRect& srcRect = rt->getResolveRect();
628 
629         this->resolveImage(target, rt, srcRect, SkIPoint::Make(srcRect.fLeft, srcRect.fTop));
630 
631         rt->flagAsResolved();
632 
633         if (requiresSubmit) {
634             this->submitCommandBuffer(kSkip_SyncQueue);
635         }
636     }
637 }
638 
uploadTexDataLinear(GrVkTexture * tex,int left,int top,int width,int height,GrColorType dataColorType,const void * data,size_t rowBytes)639 bool GrVkGpu::uploadTexDataLinear(GrVkTexture* tex, int left, int top, int width, int height,
640                                   GrColorType dataColorType, const void* data, size_t rowBytes) {
641     SkASSERT(data);
642     SkASSERT(tex->isLinearTiled());
643 
644     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     )
649     size_t bpp = GrColorTypeBytesPerPixel(dataColorType);
650     size_t trimRowBytes = width * bpp;
651 
652     SkASSERT(VK_IMAGE_LAYOUT_PREINITIALIZED == tex->currentLayout() ||
653              VK_IMAGE_LAYOUT_GENERAL == tex->currentLayout());
654     const VkImageSubresource subres = {
655         VK_IMAGE_ASPECT_COLOR_BIT,
656         0,  // mipLevel
657         0,  // arraySlice
658     };
659     VkSubresourceLayout layout;
660 
661     const GrVkInterface* interface = this->vkInterface();
662 
663     GR_VK_CALL(interface, GetImageSubresourceLayout(fDevice,
664                                                     tex->image(),
665                                                     &subres,
666                                                     &layout));
667 
668     const GrVkAlloc& alloc = tex->alloc();
669     if (VK_NULL_HANDLE == alloc.fMemory) {
670         return false;
671     }
672     VkDeviceSize offset = top * layout.rowPitch + left * bpp;
673     VkDeviceSize size = height*layout.rowPitch;
674     SkASSERT(size + offset <= alloc.fSize);
675     void* mapPtr = GrVkMemory::MapAlloc(this, alloc);
676     if (!mapPtr) {
677         return false;
678     }
679     mapPtr = reinterpret_cast<char*>(mapPtr) + offset;
680 
681     SkRectMemcpy(mapPtr, static_cast<size_t>(layout.rowPitch), data, rowBytes, trimRowBytes,
682                  height);
683 
684     GrVkMemory::FlushMappedAlloc(this, alloc, offset, size);
685     GrVkMemory::UnmapAlloc(this, alloc);
686 
687     return true;
688 }
689 
uploadTexDataOptimal(GrVkTexture * tex,int left,int top,int width,int height,GrColorType dataColorType,const GrMipLevel texels[],int mipLevelCount)690 bool GrVkGpu::uploadTexDataOptimal(GrVkTexture* tex, int left, int top, int width, int height,
691                                    GrColorType dataColorType, const GrMipLevel texels[],
692                                    int mipLevelCount) {
693     SkASSERT(!tex->isLinearTiled());
694     // The assumption is either that we have no mipmaps, or that our rect is the entire texture
695     SkASSERT(1 == mipLevelCount ||
696              (0 == left && 0 == top && width == tex->width() && height == tex->height()));
697 
698     // We assume that if the texture has mip levels, we either upload to all the levels or just the
699     // first.
700     SkASSERT(1 == mipLevelCount || mipLevelCount == (tex->texturePriv().maxMipMapLevel() + 1));
701 
702     if (width == 0 || height == 0) {
703         return false;
704     }
705 
706     if (GrPixelConfigToColorType(tex->config()) != dataColorType) {
707         return false;
708     }
709 
710     // For RGB_888x src data we are uploading it first to an RGBA texture and then copying it to the
711     // dst RGB texture. Thus we do not upload mip levels for that.
712     if (dataColorType == GrColorType::kRGB_888x && tex->imageFormat() == VK_FORMAT_R8G8B8_UNORM) {
713         SkASSERT(tex->config() == kRGB_888_GrPixelConfig);
714         // First check that we'll be able to do the copy to the to the R8G8B8 image in the end via a
715         // blit or draw.
716         if (!this->vkCaps().formatCanBeDstofBlit(VK_FORMAT_R8G8B8_UNORM, tex->isLinearTiled()) &&
717             !this->vkCaps().isFormatRenderable(VK_FORMAT_R8G8B8_UNORM, 1)) {
718             return false;
719         }
720         mipLevelCount = 1;
721     }
722 
723     SkASSERT(this->vkCaps().isVkFormatTexturable(tex->imageFormat()));
724     size_t bpp = GrColorTypeBytesPerPixel(dataColorType);
725 
726     // texels is const.
727     // But we may need to adjust the fPixels ptr based on the copyRect, or fRowBytes.
728     // Because of this we need to make a non-const shallow copy of texels.
729     SkAutoTMalloc<GrMipLevel> texelsShallowCopy;
730 
731     texelsShallowCopy.reset(mipLevelCount);
732     memcpy(texelsShallowCopy.get(), texels, mipLevelCount*sizeof(GrMipLevel));
733 
734     SkTArray<size_t> individualMipOffsets(mipLevelCount);
735     individualMipOffsets.push_back(0);
736     size_t combinedBufferSize = width * bpp * height;
737     int currentWidth = width;
738     int currentHeight = height;
739     if (!texelsShallowCopy[0].fPixels) {
740         combinedBufferSize = 0;
741     }
742 
743     // The alignment must be at least 4 bytes and a multiple of the bytes per pixel of the image
744     // config. This works with the assumption that the bytes in pixel config is always a power of 2.
745     SkASSERT((bpp & (bpp - 1)) == 0);
746     const size_t alignmentMask = 0x3 | (bpp - 1);
747     for (int currentMipLevel = 1; currentMipLevel < mipLevelCount; currentMipLevel++) {
748         currentWidth = SkTMax(1, currentWidth/2);
749         currentHeight = SkTMax(1, currentHeight/2);
750 
751         if (texelsShallowCopy[currentMipLevel].fPixels) {
752             const size_t trimmedSize = currentWidth * bpp * currentHeight;
753             const size_t alignmentDiff = combinedBufferSize & alignmentMask;
754             if (alignmentDiff != 0) {
755                 combinedBufferSize += alignmentMask - alignmentDiff + 1;
756             }
757             individualMipOffsets.push_back(combinedBufferSize);
758             combinedBufferSize += trimmedSize;
759         } else {
760             individualMipOffsets.push_back(0);
761         }
762     }
763     if (0 == combinedBufferSize) {
764         // We don't actually have any data to upload so just return success
765         return true;
766     }
767 
768     // allocate buffer to hold our mip data
769     sk_sp<GrVkTransferBuffer> transferBuffer =
770             GrVkTransferBuffer::Make(this, combinedBufferSize, GrVkBuffer::kCopyRead_Type);
771     if (!transferBuffer) {
772         return false;
773     }
774 
775     int uploadLeft = left;
776     int uploadTop = top;
777     GrVkTexture* uploadTexture = tex;
778     // For uploading RGB_888x data to an R8G8B8_UNORM texture we must first upload the data to an
779     // R8G8B8A8_UNORM image and then copy it.
780     sk_sp<GrVkTexture> copyTexture;
781     if (dataColorType == GrColorType::kRGB_888x && tex->imageFormat() == VK_FORMAT_R8G8B8_UNORM) {
782         bool dstHasYcbcr = tex->ycbcrConversionInfo().isValid();
783         if (!this->vkCaps().canCopyAsBlit(tex->imageFormat(), 1, false, dstHasYcbcr,
784                                           VK_FORMAT_R8G8B8A8_UNORM, 1, false, false)) {
785             return false;
786         }
787         GrSurfaceDesc surfDesc;
788         surfDesc.fWidth = width;
789         surfDesc.fHeight = height;
790         surfDesc.fConfig = kRGBA_8888_GrPixelConfig;
791 
792         VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_SAMPLED_BIT |
793                                        VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
794                                        VK_IMAGE_USAGE_TRANSFER_DST_BIT;
795 
796         GrVkImage::ImageDesc imageDesc;
797         imageDesc.fImageType = VK_IMAGE_TYPE_2D;
798         imageDesc.fFormat = VK_FORMAT_R8G8B8A8_UNORM;
799         imageDesc.fWidth = width;
800         imageDesc.fHeight = height;
801         imageDesc.fLevels = 1;
802         imageDesc.fSamples = 1;
803         imageDesc.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
804         imageDesc.fUsageFlags = usageFlags;
805         imageDesc.fMemProps = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
806 
807         copyTexture = GrVkTexture::MakeNewTexture(this, SkBudgeted::kYes, surfDesc, imageDesc,
808                                                   GrMipMapsStatus::kNotAllocated);
809         if (!copyTexture) {
810             return false;
811         }
812 
813         uploadTexture = copyTexture.get();
814         uploadLeft = 0;
815         uploadTop = 0;
816     }
817 
818     char* buffer = (char*) transferBuffer->map();
819     SkTArray<VkBufferImageCopy> regions(mipLevelCount);
820 
821     currentWidth = width;
822     currentHeight = height;
823     int layerHeight = uploadTexture->height();
824     for (int currentMipLevel = 0; currentMipLevel < mipLevelCount; currentMipLevel++) {
825         if (texelsShallowCopy[currentMipLevel].fPixels) {
826             SkASSERT(1 == mipLevelCount || currentHeight == layerHeight);
827             const size_t trimRowBytes = currentWidth * bpp;
828             const size_t rowBytes = texelsShallowCopy[currentMipLevel].fRowBytes;
829 
830             // copy data into the buffer, skipping the trailing bytes
831             char* dst = buffer + individualMipOffsets[currentMipLevel];
832             const char* src = (const char*)texelsShallowCopy[currentMipLevel].fPixels;
833             SkRectMemcpy(dst, trimRowBytes, src, rowBytes, trimRowBytes, currentHeight);
834 
835             VkBufferImageCopy& region = regions.push_back();
836             memset(&region, 0, sizeof(VkBufferImageCopy));
837             region.bufferOffset = transferBuffer->offset() + individualMipOffsets[currentMipLevel];
838             region.bufferRowLength = currentWidth;
839             region.bufferImageHeight = currentHeight;
840             region.imageSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, SkToU32(currentMipLevel), 0, 1 };
841             region.imageOffset = {uploadLeft, uploadTop, 0};
842             region.imageExtent = { (uint32_t)currentWidth, (uint32_t)currentHeight, 1 };
843         }
844         currentWidth = SkTMax(1, currentWidth/2);
845         currentHeight = SkTMax(1, currentHeight/2);
846         layerHeight = currentHeight;
847     }
848 
849     // no need to flush non-coherent memory, unmap will do that for us
850     transferBuffer->unmap();
851 
852     // Change layout of our target so it can be copied to
853     uploadTexture->setImageLayout(this,
854                                   VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
855                                   VK_ACCESS_TRANSFER_WRITE_BIT,
856                                   VK_PIPELINE_STAGE_TRANSFER_BIT,
857                                   false);
858 
859     // Copy the buffer to the image
860     fCurrentCmdBuffer->copyBufferToImage(this,
861                                          transferBuffer.get(),
862                                          uploadTexture,
863                                          VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
864                                          regions.count(),
865                                          regions.begin());
866 
867     // If we copied the data into a temporary image first, copy that image into our main texture
868     // now.
869     if (copyTexture.get()) {
870         SkASSERT(dataColorType == GrColorType::kRGB_888x);
871         SkAssertResult(this->copySurface(tex, copyTexture.get(), SkIRect::MakeWH(width, height),
872                                          SkIPoint::Make(left, top), false));
873     }
874     if (1 == mipLevelCount) {
875         tex->texturePriv().markMipMapsDirty();
876     }
877 
878     return true;
879 }
880 
881 // It's probably possible to roll this into uploadTexDataOptimal,
882 // but for now it's easier to maintain as a separate entity.
uploadTexDataCompressed(GrVkTexture * tex,int left,int top,int width,int height,SkImage::CompressionType compressionType,const void * data)883 bool GrVkGpu::uploadTexDataCompressed(GrVkTexture* tex, int left, int top, int width, int height,
884                                       SkImage::CompressionType compressionType, const void* data) {
885     SkASSERT(data);
886     SkASSERT(!tex->isLinearTiled());
887     // For now the assumption is that our rect is the entire texture.
888     // Compressed textures are read-only so this should be a reasonable assumption.
889     SkASSERT(0 == left && 0 == top && width == tex->width() && height == tex->height());
890 
891     if (width == 0 || height == 0) {
892         return false;
893     }
894 
895     SkImage::CompressionType textureCompressionType;
896     if (!GrVkFormatToCompressionType(tex->imageFormat(), &textureCompressionType) ||
897         textureCompressionType != compressionType) {
898         return false;
899     }
900 
901     SkASSERT(this->vkCaps().isVkFormatTexturable(tex->imageFormat()));
902 
903     size_t dataSize = GrCompressedDataSize(compressionType, width, height);
904 
905     // allocate buffer to hold our mip data
906     sk_sp<GrVkTransferBuffer> transferBuffer =
907             GrVkTransferBuffer::Make(this, dataSize, GrVkBuffer::kCopyRead_Type);
908     if (!transferBuffer) {
909         return false;
910     }
911 
912     int uploadLeft = left;
913     int uploadTop = top;
914     GrVkTexture* uploadTexture = tex;
915 
916     char* buffer = (char*)transferBuffer->map();
917 
918     memcpy(buffer, data, dataSize);
919 
920     VkBufferImageCopy region;
921     memset(&region, 0, sizeof(VkBufferImageCopy));
922     region.bufferOffset = transferBuffer->offset();
923     region.bufferRowLength = width;
924     region.bufferImageHeight = height;
925     region.imageSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
926     region.imageOffset = { uploadLeft, uploadTop, 0 };
927     region.imageExtent = { SkToU32(width), SkToU32(height), 1 };
928 
929     // no need to flush non-coherent memory, unmap will do that for us
930     transferBuffer->unmap();
931 
932     // Change layout of our target so it can be copied to
933     uploadTexture->setImageLayout(this,
934                                   VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
935                                   VK_ACCESS_TRANSFER_WRITE_BIT,
936                                   VK_PIPELINE_STAGE_TRANSFER_BIT,
937                                   false);
938 
939     // Copy the buffer to the image
940     fCurrentCmdBuffer->copyBufferToImage(this,
941                                          transferBuffer.get(),
942                                          uploadTexture,
943                                          VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
944                                          1,
945                                          &region);
946 
947     return true;
948 }
949 
950 ////////////////////////////////////////////////////////////////////////////////
onCreateTexture(const GrSurfaceDesc & desc,const GrBackendFormat & format,GrRenderable renderable,int renderTargetSampleCnt,SkBudgeted budgeted,GrProtected isProtected,const GrMipLevel texels[],int mipLevelCount)951 sk_sp<GrTexture> GrVkGpu::onCreateTexture(const GrSurfaceDesc& desc,
952                                           const GrBackendFormat& format,
953                                           GrRenderable renderable,
954                                           int renderTargetSampleCnt,
955                                           SkBudgeted budgeted,
956                                           GrProtected isProtected,
957                                           const GrMipLevel texels[],
958                                           int mipLevelCount) {
959     VkFormat pixelFormat;
960     SkAssertResult(format.asVkFormat(&pixelFormat));
961     SkASSERT(!GrVkFormatIsCompressed(pixelFormat));
962 
963     VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_SAMPLED_BIT;
964     if (renderable == GrRenderable::kYes) {
965         usageFlags |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
966     }
967 
968     // For now we will set the VK_IMAGE_USAGE_TRANSFER_DESTINATION_BIT and
969     // VK_IMAGE_USAGE_TRANSFER_SOURCE_BIT on every texture since we do not know whether or not we
970     // will be using this texture in some copy or not. Also this assumes, as is the current case,
971     // that all render targets in vulkan are also textures. If we change this practice of setting
972     // both bits, we must make sure to set the destination bit if we are uploading srcData to the
973     // texture.
974     usageFlags |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
975 
976     // This ImageDesc refers to the texture that will be read by the client. Thus even if msaa is
977     // requested, this ImageDesc describes the resolved texture. Therefore we always have samples set
978     // to 1.
979     int mipLevels = !mipLevelCount ? 1 : mipLevelCount;
980     GrVkImage::ImageDesc imageDesc;
981     imageDesc.fImageType = VK_IMAGE_TYPE_2D;
982     imageDesc.fFormat = pixelFormat;
983     imageDesc.fWidth = desc.fWidth;
984     imageDesc.fHeight = desc.fHeight;
985     imageDesc.fLevels = mipLevels;
986     imageDesc.fSamples = 1;
987     imageDesc.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
988     imageDesc.fUsageFlags = usageFlags;
989     imageDesc.fIsProtected = isProtected;
990 
991     GrMipMapsStatus mipMapsStatus = GrMipMapsStatus::kNotAllocated;
992     if (mipLevels > 1) {
993         mipMapsStatus = GrMipMapsStatus::kValid;
994         for (int i = 0; i < mipLevels; ++i) {
995             if (!texels[i].fPixels) {
996                 mipMapsStatus = GrMipMapsStatus::kDirty;
997                 break;
998             }
999         }
1000     }
1001 
1002     sk_sp<GrVkTexture> tex;
1003     if (renderable == GrRenderable::kYes) {
1004         tex = GrVkTextureRenderTarget::MakeNewTextureRenderTarget(
1005                 this, budgeted, desc, renderTargetSampleCnt, imageDesc, mipMapsStatus);
1006     } else {
1007         tex = GrVkTexture::MakeNewTexture(this, budgeted, desc, imageDesc, mipMapsStatus);
1008     }
1009 
1010     if (!tex) {
1011         return nullptr;
1012     }
1013 
1014     auto colorType = GrPixelConfigToColorType(desc.fConfig);
1015     if (mipLevelCount) {
1016         if (!this->uploadTexDataOptimal(tex.get(), 0, 0, desc.fWidth, desc.fHeight, colorType,
1017                                         texels, mipLevelCount)) {
1018             tex->unref();
1019             return nullptr;
1020         }
1021     }
1022 
1023     if (this->caps()->shouldInitializeTextures()) {
1024         SkSTArray<1, VkImageSubresourceRange> ranges;
1025         bool inRange = false;
1026         for (uint32_t i = 0; i < tex->mipLevels(); ++i) {
1027             if (i >= static_cast<uint32_t>(mipLevelCount) || !texels[i].fPixels) {
1028                 if (inRange) {
1029                     ranges.back().levelCount++;
1030                 } else {
1031                     auto& range = ranges.push_back();
1032                     range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1033                     range.baseArrayLayer = 0;
1034                     range.baseMipLevel = i;
1035                     range.layerCount = 1;
1036                     range.levelCount = 1;
1037                     inRange = true;
1038                 }
1039             } else if (inRange) {
1040                 inRange = false;
1041             }
1042         }
1043 
1044         if (!ranges.empty()) {
1045             static constexpr VkClearColorValue kZeroClearColor = {};
1046             tex->setImageLayout(this, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1047                                 VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
1048                                 false);
1049             this->currentCommandBuffer()->clearColorImage(this, tex.get(), &kZeroClearColor,
1050                                                           ranges.count(), ranges.begin());
1051         }
1052     }
1053     return tex;
1054 }
1055 
onCreateCompressedTexture(int width,int height,const GrBackendFormat & format,SkImage::CompressionType compressionType,SkBudgeted budgeted,const void * data)1056 sk_sp<GrTexture> GrVkGpu::onCreateCompressedTexture(int width, int height,
1057                                                     const GrBackendFormat& format,
1058                                                     SkImage::CompressionType compressionType,
1059                                                     SkBudgeted budgeted, const void* data) {
1060     VkFormat pixelFormat;
1061     if (!format.asVkFormat(&pixelFormat)) {
1062         return nullptr;
1063     }
1064 
1065     VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_SAMPLED_BIT;
1066 
1067     // For now we will set the VK_IMAGE_USAGE_TRANSFER_DESTINATION_BIT and
1068     // VK_IMAGE_USAGE_TRANSFER_SOURCE_BIT on every texture since we do not know whether or not we
1069     // will be using this texture in some copy or not. Also this assumes, as is the current case,
1070     // that all render targets in vulkan are also textures. If we change this practice of setting
1071     // both bits, we must make sure to set the destination bit if we are uploading srcData to the
1072     // texture.
1073     usageFlags |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
1074 
1075     // Compressed textures with MIP levels or multiple samples are not supported as of now.
1076     GrVkImage::ImageDesc imageDesc;
1077     imageDesc.fImageType = VK_IMAGE_TYPE_2D;
1078     imageDesc.fFormat = pixelFormat;
1079     imageDesc.fWidth = width;
1080     imageDesc.fHeight = height;
1081     imageDesc.fLevels = 1;
1082     imageDesc.fSamples = 1;
1083     imageDesc.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
1084     imageDesc.fUsageFlags = usageFlags;
1085     imageDesc.fIsProtected = GrProtected::kNo;
1086 
1087     GrSurfaceDesc desc;
1088     desc.fConfig = GrCompressionTypePixelConfig(compressionType);
1089     desc.fWidth = width;
1090     desc.fHeight = height;
1091     auto tex = GrVkTexture::MakeNewTexture(this, budgeted, desc, imageDesc,
1092                                            GrMipMapsStatus::kNotAllocated);
1093     if (!tex) {
1094         return nullptr;
1095     }
1096 
1097     if (!this->uploadTexDataCompressed(tex.get(), 0, 0, desc.fWidth, desc.fHeight, compressionType,
1098                                        data)) {
1099         return nullptr;
1100     }
1101 
1102     return tex;
1103 }
1104 
1105 ////////////////////////////////////////////////////////////////////////////////
1106 
copyBuffer(GrVkBuffer * srcBuffer,GrVkBuffer * dstBuffer,VkDeviceSize srcOffset,VkDeviceSize dstOffset,VkDeviceSize size)1107 void GrVkGpu::copyBuffer(GrVkBuffer* srcBuffer, GrVkBuffer* dstBuffer, VkDeviceSize srcOffset,
1108                          VkDeviceSize dstOffset, VkDeviceSize size) {
1109     VkBufferCopy copyRegion;
1110     copyRegion.srcOffset = srcOffset;
1111     copyRegion.dstOffset = dstOffset;
1112     copyRegion.size = size;
1113     fCurrentCmdBuffer->copyBuffer(this, srcBuffer, dstBuffer, 1, &copyRegion);
1114 }
1115 
updateBuffer(GrVkBuffer * buffer,const void * src,VkDeviceSize offset,VkDeviceSize size)1116 bool GrVkGpu::updateBuffer(GrVkBuffer* buffer, const void* src,
1117                            VkDeviceSize offset, VkDeviceSize size) {
1118     // Update the buffer
1119     fCurrentCmdBuffer->updateBuffer(this, buffer, offset, size, src);
1120 
1121     return true;
1122 }
1123 
1124 ////////////////////////////////////////////////////////////////////////////////
1125 
check_image_info(const GrVkCaps & caps,const GrVkImageInfo & info,GrColorType colorType,bool needsAllocation)1126 static bool check_image_info(const GrVkCaps& caps,
1127                              const GrVkImageInfo& info,
1128                              GrColorType colorType,
1129                              bool needsAllocation) {
1130     if (VK_NULL_HANDLE == info.fImage) {
1131         return false;
1132     }
1133 
1134     if (VK_NULL_HANDLE == info.fAlloc.fMemory && needsAllocation) {
1135         return false;
1136     }
1137 
1138     if (info.fYcbcrConversionInfo.isValid()) {
1139         if (!caps.supportsYcbcrConversion()) {
1140             return false;
1141         }
1142     }
1143 
1144     if (info.fImageLayout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR && !caps.supportsSwapchain()) {
1145         return false;
1146     }
1147 
1148     SkASSERT(GrVkFormatColorTypePairIsValid(info.fFormat, colorType));
1149     return true;
1150 }
1151 
check_tex_image_info(const GrVkCaps & caps,const GrVkImageInfo & info)1152 static bool check_tex_image_info(const GrVkCaps& caps, const GrVkImageInfo& info) {
1153     if (info.fImageTiling == VK_IMAGE_TILING_OPTIMAL) {
1154         if (!caps.isVkFormatTexturable(info.fFormat)) {
1155             return false;
1156         }
1157     } else {
1158         SkASSERT(info.fImageTiling == VK_IMAGE_TILING_LINEAR);
1159         if (!caps.isVkFormatTexturableLinearly(info.fFormat)) {
1160             return false;
1161         }
1162     }
1163     return true;
1164 }
1165 
check_rt_image_info(const GrVkCaps & caps,const GrVkImageInfo & info,int sampleCnt)1166 static bool check_rt_image_info(const GrVkCaps& caps, const GrVkImageInfo& info, int sampleCnt) {
1167     if (!caps.isFormatRenderable(info.fFormat, sampleCnt)) {
1168         return false;
1169     }
1170     return true;
1171 }
1172 
onWrapBackendTexture(const GrBackendTexture & backendTex,GrColorType colorType,GrWrapOwnership ownership,GrWrapCacheable cacheable,GrIOType ioType)1173 sk_sp<GrTexture> GrVkGpu::onWrapBackendTexture(const GrBackendTexture& backendTex,
1174                                                GrColorType colorType, GrWrapOwnership ownership,
1175                                                GrWrapCacheable cacheable, GrIOType ioType) {
1176     GrVkImageInfo imageInfo;
1177     if (!backendTex.getVkImageInfo(&imageInfo)) {
1178         return nullptr;
1179     }
1180 
1181     if (!check_image_info(this->vkCaps(), imageInfo, colorType,
1182                           kAdopt_GrWrapOwnership == ownership)) {
1183         return nullptr;
1184     }
1185     if (!check_tex_image_info(this->vkCaps(), imageInfo)) {
1186         return nullptr;
1187     }
1188 
1189     if (backendTex.isProtected() && (fProtectedContext == GrProtected::kNo)) {
1190         return nullptr;
1191     }
1192 
1193     GrPixelConfig config = this->caps()->getConfigFromBackendFormat(backendTex.getBackendFormat(),
1194                                                                     colorType);
1195     SkASSERT(kUnknown_GrPixelConfig != config);
1196 
1197     GrSurfaceDesc surfDesc;
1198     surfDesc.fWidth = backendTex.width();
1199     surfDesc.fHeight = backendTex.height();
1200     surfDesc.fConfig = config;
1201 
1202     sk_sp<GrVkImageLayout> layout = backendTex.getGrVkImageLayout();
1203     SkASSERT(layout);
1204     return GrVkTexture::MakeWrappedTexture(this, surfDesc, ownership, cacheable, ioType, imageInfo,
1205                                            std::move(layout));
1206 }
1207 
onWrapRenderableBackendTexture(const GrBackendTexture & backendTex,int sampleCnt,GrColorType colorType,GrWrapOwnership ownership,GrWrapCacheable cacheable)1208 sk_sp<GrTexture> GrVkGpu::onWrapRenderableBackendTexture(const GrBackendTexture& backendTex,
1209                                                          int sampleCnt,
1210                                                          GrColorType colorType,
1211                                                          GrWrapOwnership ownership,
1212                                                          GrWrapCacheable cacheable) {
1213     GrVkImageInfo imageInfo;
1214     if (!backendTex.getVkImageInfo(&imageInfo)) {
1215         return nullptr;
1216     }
1217 
1218     if (!check_image_info(this->vkCaps(), imageInfo, colorType,
1219                           kAdopt_GrWrapOwnership == ownership)) {
1220         return nullptr;
1221     }
1222     if (!check_tex_image_info(this->vkCaps(), imageInfo)) {
1223         return nullptr;
1224     }
1225     if (!check_rt_image_info(this->vkCaps(), imageInfo, sampleCnt)) {
1226         return nullptr;
1227     }
1228 
1229     if (backendTex.isProtected() && (fProtectedContext == GrProtected::kNo)) {
1230         return nullptr;
1231     }
1232 
1233 
1234     GrPixelConfig config = this->caps()->getConfigFromBackendFormat(backendTex.getBackendFormat(),
1235                                                                     colorType);
1236     SkASSERT(kUnknown_GrPixelConfig != config);
1237 
1238     GrSurfaceDesc surfDesc;
1239     surfDesc.fWidth = backendTex.width();
1240     surfDesc.fHeight = backendTex.height();
1241     surfDesc.fConfig = config;
1242     sampleCnt = this->vkCaps().getRenderTargetSampleCount(sampleCnt, imageInfo.fFormat);
1243 
1244     sk_sp<GrVkImageLayout> layout = backendTex.getGrVkImageLayout();
1245     SkASSERT(layout);
1246 
1247     return GrVkTextureRenderTarget::MakeWrappedTextureRenderTarget(
1248             this, surfDesc, sampleCnt, ownership, cacheable, imageInfo, std::move(layout));
1249 }
1250 
onWrapBackendRenderTarget(const GrBackendRenderTarget & backendRT,GrColorType colorType)1251 sk_sp<GrRenderTarget> GrVkGpu::onWrapBackendRenderTarget(const GrBackendRenderTarget& backendRT,
1252                                                          GrColorType colorType) {
1253     // Currently the Vulkan backend does not support wrapping of msaa render targets directly. In
1254     // general this is not an issue since swapchain images in vulkan are never multisampled. Thus if
1255     // you want a multisampled RT it is best to wrap the swapchain images and then let Skia handle
1256     // creating and owning the MSAA images.
1257     if (backendRT.sampleCnt() > 1) {
1258         return nullptr;
1259     }
1260 
1261     GrVkImageInfo info;
1262     if (!backendRT.getVkImageInfo(&info)) {
1263         return nullptr;
1264     }
1265 
1266     GrPixelConfig config = this->caps()->getConfigFromBackendFormat(backendRT.getBackendFormat(),
1267                                                                     colorType);
1268     SkASSERT(kUnknown_GrPixelConfig != config);
1269 
1270     if (!check_image_info(this->vkCaps(), info, colorType, false)) {
1271         return nullptr;
1272     }
1273     if (!check_rt_image_info(this->vkCaps(), info, backendRT.sampleCnt())) {
1274         return nullptr;
1275     }
1276 
1277     if (backendRT.isProtected() && (fProtectedContext == GrProtected::kNo)) {
1278         return nullptr;
1279     }
1280 
1281     GrSurfaceDesc desc;
1282     desc.fWidth = backendRT.width();
1283     desc.fHeight = backendRT.height();
1284     desc.fConfig = config;
1285 
1286     sk_sp<GrVkImageLayout> layout = backendRT.getGrVkImageLayout();
1287 
1288     sk_sp<GrVkRenderTarget> tgt =
1289             GrVkRenderTarget::MakeWrappedRenderTarget(this, desc, 1, info, std::move(layout));
1290 
1291     // We don't allow the client to supply a premade stencil buffer. We always create one if needed.
1292     SkASSERT(!backendRT.stencilBits());
1293     if (tgt) {
1294         SkASSERT(tgt->canAttemptStencilAttachment());
1295     }
1296 
1297     return tgt;
1298 }
1299 
onWrapBackendTextureAsRenderTarget(const GrBackendTexture & tex,int sampleCnt,GrColorType grColorType)1300 sk_sp<GrRenderTarget> GrVkGpu::onWrapBackendTextureAsRenderTarget(const GrBackendTexture& tex,
1301                                                                   int sampleCnt,
1302                                                                   GrColorType grColorType) {
1303 
1304     GrVkImageInfo imageInfo;
1305     if (!tex.getVkImageInfo(&imageInfo)) {
1306         return nullptr;
1307     }
1308     if (!check_image_info(this->vkCaps(), imageInfo, grColorType, false)) {
1309         return nullptr;
1310     }
1311     if (!check_rt_image_info(this->vkCaps(), imageInfo, sampleCnt)) {
1312         return nullptr;
1313     }
1314 
1315     if (tex.isProtected() && (fProtectedContext == GrProtected::kNo)) {
1316         return nullptr;
1317     }
1318 
1319     GrPixelConfig config = this->caps()->getConfigFromBackendFormat(tex.getBackendFormat(),
1320                                                                     grColorType);
1321     SkASSERT(kUnknown_GrPixelConfig != config);
1322 
1323     GrSurfaceDesc desc;
1324     desc.fWidth = tex.width();
1325     desc.fHeight = tex.height();
1326     desc.fConfig = config;
1327 
1328     sampleCnt = this->vkCaps().getRenderTargetSampleCount(sampleCnt, imageInfo.fFormat);
1329     if (!sampleCnt) {
1330         return nullptr;
1331     }
1332 
1333     sk_sp<GrVkImageLayout> layout = tex.getGrVkImageLayout();
1334     SkASSERT(layout);
1335 
1336     return GrVkRenderTarget::MakeWrappedRenderTarget(this, desc, sampleCnt, imageInfo,
1337                                                      std::move(layout));
1338 }
1339 
onWrapVulkanSecondaryCBAsRenderTarget(const SkImageInfo & imageInfo,const GrVkDrawableInfo & vkInfo)1340 sk_sp<GrRenderTarget> GrVkGpu::onWrapVulkanSecondaryCBAsRenderTarget(
1341         const SkImageInfo& imageInfo, const GrVkDrawableInfo& vkInfo) {
1342     int maxSize = this->caps()->maxTextureSize();
1343     if (imageInfo.width() > maxSize || imageInfo.height() > maxSize) {
1344         return nullptr;
1345     }
1346 
1347     GrBackendFormat backendFormat = GrBackendFormat::MakeVk(vkInfo.fFormat);
1348     if (!backendFormat.isValid()) {
1349         return nullptr;
1350     }
1351     int sampleCnt = this->vkCaps().getRenderTargetSampleCount(1, vkInfo.fFormat);
1352     if (!sampleCnt) {
1353         return nullptr;
1354     }
1355 
1356     GrColorType grColorType = SkColorTypeToGrColorType(imageInfo.colorType());
1357     GrPixelConfig config = this->caps()->getConfigFromBackendFormat(backendFormat, grColorType);
1358     if (config == kUnknown_GrPixelConfig) {
1359         return nullptr;
1360     }
1361 
1362     GrSurfaceDesc desc;
1363     desc.fWidth = imageInfo.width();
1364     desc.fHeight = imageInfo.height();
1365     desc.fConfig = config;
1366 
1367     return GrVkRenderTarget::MakeSecondaryCBRenderTarget(this, desc, vkInfo);
1368 }
1369 
onRegenerateMipMapLevels(GrTexture * tex)1370 bool GrVkGpu::onRegenerateMipMapLevels(GrTexture* tex) {
1371     auto* vkTex = static_cast<GrVkTexture*>(tex);
1372     // don't do anything for linearly tiled textures (can't have mipmaps)
1373     if (vkTex->isLinearTiled()) {
1374         SkDebugf("Trying to create mipmap for linear tiled texture");
1375         return false;
1376     }
1377 
1378     // determine if we can blit to and from this format
1379     const GrVkCaps& caps = this->vkCaps();
1380     if (!caps.formatCanBeDstofBlit(vkTex->imageFormat(), false) ||
1381         !caps.formatCanBeSrcofBlit(vkTex->imageFormat(), false) ||
1382         !caps.mipMapSupport()) {
1383         return false;
1384     }
1385 
1386     int width = tex->width();
1387     int height = tex->height();
1388     VkImageBlit blitRegion;
1389     memset(&blitRegion, 0, sizeof(VkImageBlit));
1390 
1391     // SkMipMap doesn't include the base level in the level count so we have to add 1
1392     uint32_t levelCount = SkMipMap::ComputeLevelCount(tex->width(), tex->height()) + 1;
1393     SkASSERT(levelCount == vkTex->mipLevels());
1394 
1395     // change layout of the layers so we can write to them.
1396     vkTex->setImageLayout(this, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_ACCESS_TRANSFER_WRITE_BIT,
1397                           VK_PIPELINE_STAGE_TRANSFER_BIT, false);
1398 
1399     // setup memory barrier
1400     SkASSERT(GrVkFormatIsSupported(vkTex->imageFormat()));
1401     VkImageMemoryBarrier imageMemoryBarrier = {
1402             VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,  // sType
1403             nullptr,                                 // pNext
1404             VK_ACCESS_TRANSFER_WRITE_BIT,            // srcAccessMask
1405             VK_ACCESS_TRANSFER_READ_BIT,             // dstAccessMask
1406             VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,    // oldLayout
1407             VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,    // newLayout
1408             VK_QUEUE_FAMILY_IGNORED,                 // srcQueueFamilyIndex
1409             VK_QUEUE_FAMILY_IGNORED,                 // dstQueueFamilyIndex
1410             vkTex->image(),                          // image
1411             {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}  // subresourceRange
1412     };
1413 
1414     // Blit the miplevels
1415     uint32_t mipLevel = 1;
1416     while (mipLevel < levelCount) {
1417         int prevWidth = width;
1418         int prevHeight = height;
1419         width = SkTMax(1, width / 2);
1420         height = SkTMax(1, height / 2);
1421 
1422         imageMemoryBarrier.subresourceRange.baseMipLevel = mipLevel - 1;
1423         this->addImageMemoryBarrier(vkTex->resource(), VK_PIPELINE_STAGE_TRANSFER_BIT,
1424                                     VK_PIPELINE_STAGE_TRANSFER_BIT, false, &imageMemoryBarrier);
1425 
1426         blitRegion.srcSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, mipLevel - 1, 0, 1 };
1427         blitRegion.srcOffsets[0] = { 0, 0, 0 };
1428         blitRegion.srcOffsets[1] = { prevWidth, prevHeight, 1 };
1429         blitRegion.dstSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, mipLevel, 0, 1 };
1430         blitRegion.dstOffsets[0] = { 0, 0, 0 };
1431         blitRegion.dstOffsets[1] = { width, height, 1 };
1432         fCurrentCmdBuffer->blitImage(this,
1433                                      vkTex->resource(),
1434                                      vkTex->image(),
1435                                      VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
1436                                      vkTex->resource(),
1437                                      vkTex->image(),
1438                                      VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1439                                      1,
1440                                      &blitRegion,
1441                                      VK_FILTER_LINEAR);
1442         ++mipLevel;
1443     }
1444     if (levelCount > 1) {
1445         // This barrier logically is not needed, but it changes the final level to the same layout
1446         // as all the others, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL. This makes tracking of the
1447         // layouts and future layout changes easier. The alternative here would be to track layout
1448         // and memory accesses per layer which doesn't seem work it.
1449         imageMemoryBarrier.subresourceRange.baseMipLevel = mipLevel - 1;
1450         this->addImageMemoryBarrier(vkTex->resource(), VK_PIPELINE_STAGE_TRANSFER_BIT,
1451                                     VK_PIPELINE_STAGE_TRANSFER_BIT, false, &imageMemoryBarrier);
1452         vkTex->updateImageLayout(VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
1453     }
1454     return true;
1455 }
1456 
1457 ////////////////////////////////////////////////////////////////////////////////
1458 
createStencilAttachmentForRenderTarget(const GrRenderTarget * rt,int width,int height,int numStencilSamples)1459 GrStencilAttachment* GrVkGpu::createStencilAttachmentForRenderTarget(
1460         const GrRenderTarget* rt, int width, int height, int numStencilSamples) {
1461     SkASSERT(numStencilSamples == rt->numSamples());
1462     SkASSERT(width >= rt->width());
1463     SkASSERT(height >= rt->height());
1464 
1465     int samples = rt->numSamples();
1466 
1467     const GrVkCaps::StencilFormat& sFmt = this->vkCaps().preferredStencilFormat();
1468 
1469     GrVkStencilAttachment* stencil(GrVkStencilAttachment::Create(this,
1470                                                                  width,
1471                                                                  height,
1472                                                                  samples,
1473                                                                  sFmt));
1474     fStats.incStencilAttachmentCreates();
1475     return stencil;
1476 }
1477 
1478 ////////////////////////////////////////////////////////////////////////////////
1479 
copy_src_data(GrVkGpu * gpu,const GrVkAlloc & alloc,VkFormat vkFormat,int width,int height,const void * srcData,size_t srcRowBytes)1480 bool copy_src_data(GrVkGpu* gpu, const GrVkAlloc& alloc, VkFormat vkFormat,
1481                    int width, int height,
1482                    const void* srcData, size_t srcRowBytes) {
1483     SkASSERT(srcData);
1484     SkASSERT(!GrVkFormatIsCompressed(vkFormat));
1485 
1486     void* mapPtr = GrVkMemory::MapAlloc(gpu, alloc);
1487     if (!mapPtr) {
1488         return false;
1489     }
1490     size_t bytesPerPixel = GrVkBytesPerFormat(vkFormat);
1491     const size_t trimRowBytes = width * bytesPerPixel;
1492     if (!srcRowBytes) {
1493         srcRowBytes = trimRowBytes;
1494     }
1495     SkASSERT(trimRowBytes * height <= alloc.fSize);
1496 
1497     SkRectMemcpy(mapPtr, trimRowBytes, srcData, srcRowBytes, trimRowBytes, height);
1498 
1499     GrVkMemory::FlushMappedAlloc(gpu, alloc, 0, alloc.fSize);
1500     GrVkMemory::UnmapAlloc(gpu, alloc);
1501     return true;
1502 }
1503 
copy_compressed_src_data(GrVkGpu * gpu,const GrVkAlloc & alloc,SkImage::CompressionType compressionType,int width,int height,const void * data)1504 bool copy_compressed_src_data(GrVkGpu* gpu, const GrVkAlloc& alloc,
1505                               SkImage::CompressionType compressionType, int width, int height,
1506                               const void* data) {
1507     SkASSERT(data);
1508 
1509     void* mapPtr = GrVkMemory::MapAlloc(gpu, alloc);
1510     if (!mapPtr) {
1511         return false;
1512     }
1513     mapPtr = reinterpret_cast<char*>(mapPtr);
1514 
1515     size_t dataSize = GrCompressedDataSize(compressionType, width, height);
1516     SkASSERT(dataSize <= alloc.fSize);
1517     memcpy(mapPtr, data, dataSize);
1518     GrVkMemory::FlushMappedAlloc(gpu, alloc, 0, alloc.fSize);
1519     GrVkMemory::UnmapAlloc(gpu, alloc);
1520     return true;
1521 }
1522 
set_image_layout(const GrVkInterface * vkInterface,VkCommandBuffer cmdBuffer,GrVkImageInfo * info,VkImageLayout newLayout,uint32_t mipLevels,VkAccessFlags dstAccessMask,VkPipelineStageFlagBits dstStageMask)1523 static void set_image_layout(const GrVkInterface* vkInterface, VkCommandBuffer cmdBuffer,
1524                              GrVkImageInfo* info, VkImageLayout newLayout, uint32_t mipLevels,
1525                              VkAccessFlags dstAccessMask, VkPipelineStageFlagBits dstStageMask) {
1526     VkAccessFlags srcAccessMask = GrVkImage::LayoutToSrcAccessMask(info->fImageLayout);
1527     VkPipelineStageFlags srcStageMask = GrVkImage::LayoutToPipelineSrcStageFlags(
1528                                                                               info->fImageLayout);
1529 
1530     VkImageMemoryBarrier barrier;
1531     memset(&barrier, 0, sizeof(VkImageMemoryBarrier));
1532     barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
1533     barrier.pNext = nullptr;
1534     barrier.srcAccessMask = srcAccessMask;
1535     barrier.dstAccessMask = dstAccessMask;
1536     barrier.oldLayout = info->fImageLayout;
1537     barrier.newLayout = newLayout;
1538     barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
1539     barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
1540     barrier.image = info->fImage;
1541     barrier.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, mipLevels, 0, 1};
1542     GR_VK_CALL(vkInterface, CmdPipelineBarrier(
1543                                cmdBuffer,
1544                                srcStageMask,
1545                                dstStageMask,
1546                                0,
1547                                0, nullptr,
1548                                0, nullptr,
1549                                1, &barrier));
1550     info->fImageLayout = newLayout;
1551 }
1552 
createVkImageForBackendSurface(VkFormat vkFormat,int w,int h,bool texturable,bool renderable,GrMipMapped mipMapped,const void * srcData,size_t srcRowBytes,const SkColor4f * color,GrVkImageInfo * info,GrProtected isProtected)1553 bool GrVkGpu::createVkImageForBackendSurface(VkFormat vkFormat, int w, int h, bool texturable,
1554                                              bool renderable, GrMipMapped mipMapped,
1555                                              const void* srcData, size_t srcRowBytes,
1556                                              const SkColor4f* color, GrVkImageInfo* info,
1557                                              GrProtected isProtected) {
1558     SkASSERT(texturable || renderable);
1559     if (!texturable) {
1560         SkASSERT(GrMipMapped::kNo == mipMapped);
1561         SkASSERT(!srcData);
1562     }
1563 
1564     if (fProtectedContext != isProtected) {
1565         return false;
1566     }
1567 
1568     if (texturable && !fVkCaps->isVkFormatTexturable(vkFormat)) {
1569         return false;
1570     }
1571 
1572     if (renderable && !fVkCaps->isFormatRenderable(vkFormat, 1)) {
1573         return false;
1574     }
1575 
1576     // Currently we don't support uploading pixel data when mipped.
1577     if (srcData && GrMipMapped::kYes == mipMapped) {
1578         return false;
1579     }
1580 
1581     VkImageUsageFlags usageFlags = 0;
1582     usageFlags |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
1583     usageFlags |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
1584     if (texturable) {
1585         usageFlags |= VK_IMAGE_USAGE_SAMPLED_BIT;
1586     }
1587     if (renderable) {
1588         usageFlags |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
1589     }
1590 
1591     // Figure out the number of mip levels.
1592     uint32_t mipLevels = 1;
1593     if (GrMipMapped::kYes == mipMapped) {
1594         mipLevels = SkMipMap::ComputeLevelCount(w, h) + 1;
1595     }
1596 
1597     GrVkImage::ImageDesc imageDesc;
1598     imageDesc.fImageType = VK_IMAGE_TYPE_2D;
1599     imageDesc.fFormat = vkFormat;
1600     imageDesc.fWidth = w;
1601     imageDesc.fHeight = h;
1602     imageDesc.fLevels = mipLevels;
1603     imageDesc.fSamples = 1;
1604     imageDesc.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
1605     imageDesc.fUsageFlags = usageFlags;
1606     imageDesc.fMemProps = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
1607     imageDesc.fIsProtected = fProtectedContext;
1608 
1609     if (!GrVkImage::InitImageInfo(this, imageDesc, info)) {
1610         SkDebugf("Failed to init image info\n");
1611         return false;
1612     }
1613 
1614     if (!srcData && !color) {
1615         return true;
1616     }
1617 
1618     // We need to declare these early so that we can delete them at the end outside of
1619     // the if block.
1620     GrVkAlloc bufferAlloc;
1621     VkBuffer buffer = VK_NULL_HANDLE;
1622 
1623     VkResult err;
1624     const VkCommandBufferAllocateInfo cmdInfo = {
1625         VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,   // sType
1626         nullptr,                                          // pNext
1627         fCmdPool->vkCommandPool(),                        // commandPool
1628         VK_COMMAND_BUFFER_LEVEL_PRIMARY,                  // level
1629         1                                                 // bufferCount
1630     };
1631 
1632     VkCommandBuffer cmdBuffer;
1633     err = VK_CALL(AllocateCommandBuffers(fDevice, &cmdInfo, &cmdBuffer));
1634     if (err) {
1635         GrVkImage::DestroyImageInfo(this, info);
1636         return false;
1637     }
1638 
1639     VkCommandBufferBeginInfo cmdBufferBeginInfo;
1640     memset(&cmdBufferBeginInfo, 0, sizeof(VkCommandBufferBeginInfo));
1641     cmdBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
1642     cmdBufferBeginInfo.pNext = nullptr;
1643     cmdBufferBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
1644     cmdBufferBeginInfo.pInheritanceInfo = nullptr;
1645 
1646     err = VK_CALL(BeginCommandBuffer(cmdBuffer, &cmdBufferBeginInfo));
1647     SkASSERT(!err);
1648 
1649     // Set image layout and add barrier
1650     set_image_layout(this->vkInterface(), cmdBuffer, info, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1651                      mipLevels, VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
1652 
1653     // TODO: Lift this to GrContext level.
1654     SkImage::CompressionType compressionType;
1655     bool isCompressed = GrVkFormatToCompressionType(vkFormat, &compressionType);
1656     std::unique_ptr<char[]> tempData;
1657     if (isCompressed && !srcData) {
1658         SkASSERT(color);
1659         size_t size = GrCompressedDataSize(compressionType, w, h);
1660         tempData.reset(new char[size]);
1661         GrFillInCompressedData(compressionType, w, h, tempData.get(), *color);
1662         srcData = tempData.get();
1663     }
1664 
1665     if (srcData) {
1666         size_t bytesPerPixel = GrVkBytesPerFormat(vkFormat);
1667         SkASSERT(w && h);
1668 
1669         SkTArray<size_t> individualMipOffsets(mipLevels);
1670 
1671         SkImage::CompressionType compressionType;
1672         bool isCompressed = GrVkFormatToCompressionType(vkFormat, &compressionType);
1673 
1674         size_t combinedBufferSize;
1675         if (isCompressed) {
1676             // Compressed textures currently must be non-MIP mapped.
1677             if (mipMapped == GrMipMapped::kYes) {
1678                 return false;
1679             }
1680             combinedBufferSize = GrCompressedDataSize(compressionType, w, h);
1681             individualMipOffsets.push_back(0);
1682         } else {
1683             combinedBufferSize = GrComputeTightCombinedBufferSize(bytesPerPixel, w, h,
1684                                                                   &individualMipOffsets, mipLevels);
1685         }
1686 
1687         VkBufferCreateInfo bufInfo;
1688         memset(&bufInfo, 0, sizeof(VkBufferCreateInfo));
1689         bufInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
1690         bufInfo.flags = fProtectedContext == GrProtected::kYes ? VK_BUFFER_CREATE_PROTECTED_BIT : 0;
1691         bufInfo.size = combinedBufferSize;
1692         bufInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
1693         bufInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
1694         bufInfo.queueFamilyIndexCount = 0;
1695         bufInfo.pQueueFamilyIndices = nullptr;
1696         err = VK_CALL(CreateBuffer(fDevice, &bufInfo, nullptr, &buffer));
1697 
1698         if (err) {
1699             GrVkImage::DestroyImageInfo(this, info);
1700             VK_CALL(EndCommandBuffer(cmdBuffer));
1701             VK_CALL(FreeCommandBuffers(fDevice, fCmdPool->vkCommandPool(), 1, &cmdBuffer));
1702             return false;
1703         }
1704 
1705         if (!GrVkMemory::AllocAndBindBufferMemory(this, buffer, GrVkBuffer::kCopyRead_Type, true,
1706                                                   &bufferAlloc)) {
1707             GrVkImage::DestroyImageInfo(this, info);
1708             VK_CALL(DestroyBuffer(fDevice, buffer, nullptr));
1709             VK_CALL(EndCommandBuffer(cmdBuffer));
1710             VK_CALL(FreeCommandBuffers(fDevice, fCmdPool->vkCommandPool(), 1, &cmdBuffer));
1711             return false;
1712         }
1713 
1714         bool result;
1715         if (isCompressed) {
1716             result = copy_compressed_src_data(this, bufferAlloc, compressionType, w, h, srcData);
1717         } else {
1718             SkASSERT(1 == mipLevels);
1719             result = copy_src_data(this, bufferAlloc, vkFormat, w, h, srcData, srcRowBytes);
1720         }
1721         if (!result) {
1722             GrVkImage::DestroyImageInfo(this, info);
1723             GrVkMemory::FreeBufferMemory(this, GrVkBuffer::kCopyRead_Type, bufferAlloc);
1724             VK_CALL(DestroyBuffer(fDevice, buffer, nullptr));
1725             VK_CALL(EndCommandBuffer(cmdBuffer));
1726             VK_CALL(FreeCommandBuffers(fDevice, fCmdPool->vkCommandPool(), 1, &cmdBuffer));
1727             return false;
1728         }
1729 
1730         SkTArray<VkBufferImageCopy> regions(mipLevels);
1731 
1732         int currentWidth = w;
1733         int currentHeight = h;
1734         for (uint32_t currentMipLevel = 0; currentMipLevel < mipLevels; currentMipLevel++) {
1735             // Submit copy command
1736             VkBufferImageCopy& region = regions.push_back();
1737             memset(&region, 0, sizeof(VkBufferImageCopy));
1738             region.bufferOffset = individualMipOffsets[currentMipLevel];
1739             region.bufferRowLength = currentWidth;
1740             region.bufferImageHeight = currentHeight;
1741             region.imageSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, currentMipLevel, 0, 1};
1742             region.imageOffset = {0, 0, 0};
1743             region.imageExtent = {(uint32_t)currentWidth, (uint32_t)currentHeight, 1};
1744             currentWidth = SkTMax(1, currentWidth / 2);
1745             currentHeight = SkTMax(1, currentHeight / 2);
1746         }
1747 
1748         VK_CALL(CmdCopyBufferToImage(cmdBuffer, buffer, info->fImage, info->fImageLayout,
1749                                      regions.count(), regions.begin()));
1750     } else {
1751         SkASSERT(color);
1752         VkClearColorValue vkColor;
1753         // If we ever support SINT or UINT formats this needs to be updated to use the int32 and
1754         // uint32 union members in those cases.
1755         vkColor.float32[0] = color->fR;
1756         vkColor.float32[1] = color->fG;
1757         vkColor.float32[2] = color->fB;
1758         vkColor.float32[3] = color->fA;
1759         VkImageSubresourceRange range;
1760         range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1761         range.baseArrayLayer = 0;
1762         range.baseMipLevel = 0;
1763         range.layerCount = 1;
1764         range.levelCount = mipLevels;
1765         VK_CALL(CmdClearColorImage(cmdBuffer, info->fImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1766                                    &vkColor, 1, &range));
1767     }
1768 
1769     if (!srcData && renderable) {
1770         SkASSERT(color);
1771 
1772         // Change image layout to color-attachment-optimal since if we use this texture as a
1773         // borrowed texture within Ganesh we are probably going to render to it
1774         set_image_layout(this->vkInterface(), cmdBuffer, info,
1775                          VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, mipLevels,
1776                          VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
1777                          VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
1778                          VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
1779     } else if (texturable) {
1780         // Change image layout to shader read since if we use this texture as a borrowed
1781         // texture within Ganesh we require that its layout be set to that
1782         set_image_layout(this->vkInterface(), cmdBuffer, info,
1783                          VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, mipLevels,
1784                          VK_ACCESS_SHADER_READ_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
1785     }
1786 
1787     // End CommandBuffer
1788     err = VK_CALL(EndCommandBuffer(cmdBuffer));
1789     SkASSERT(!err);
1790 
1791     // Create Fence for queue
1792     VkFenceCreateInfo fenceInfo;
1793     memset(&fenceInfo, 0, sizeof(VkFenceCreateInfo));
1794     fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
1795     fenceInfo.pNext = nullptr;
1796     fenceInfo.flags = 0;
1797     VkFence fence = VK_NULL_HANDLE;
1798 
1799     err = VK_CALL(CreateFence(fDevice, &fenceInfo, nullptr, &fence));
1800     SkASSERT(!err);
1801 
1802     VkProtectedSubmitInfo protectedSubmitInfo;
1803     if (fProtectedContext == GrProtected::kYes) {
1804         memset(&protectedSubmitInfo, 0, sizeof(VkProtectedSubmitInfo));
1805         protectedSubmitInfo.sType = VK_STRUCTURE_TYPE_PROTECTED_SUBMIT_INFO;
1806         protectedSubmitInfo.pNext = nullptr;
1807         protectedSubmitInfo.protectedSubmit = VK_TRUE;
1808     }
1809 
1810     VkSubmitInfo submitInfo;
1811     memset(&submitInfo, 0, sizeof(VkSubmitInfo));
1812     submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
1813     submitInfo.pNext = fProtectedContext == GrProtected::kYes ? &protectedSubmitInfo : nullptr;
1814     submitInfo.waitSemaphoreCount = 0;
1815     submitInfo.pWaitSemaphores = nullptr;
1816     submitInfo.pWaitDstStageMask = 0;
1817     submitInfo.commandBufferCount = 1;
1818     submitInfo.pCommandBuffers = &cmdBuffer;
1819     submitInfo.signalSemaphoreCount = 0;
1820     submitInfo.pSignalSemaphores = nullptr;
1821     err = VK_CALL(QueueSubmit(this->queue(), 1, &submitInfo, fence));
1822     SkASSERT(!err);
1823 
1824     err = VK_CALL(WaitForFences(this->device(), 1, &fence, VK_TRUE, UINT64_MAX));
1825     if (VK_TIMEOUT == err) {
1826         GrVkImage::DestroyImageInfo(this, info);
1827         if (buffer != VK_NULL_HANDLE) { // workaround for an older NVidia driver crash
1828             GrVkMemory::FreeBufferMemory(this, GrVkBuffer::kCopyRead_Type, bufferAlloc);
1829             VK_CALL(DestroyBuffer(fDevice, buffer, nullptr));
1830         }
1831         VK_CALL(FreeCommandBuffers(fDevice, fCmdPool->vkCommandPool(), 1, &cmdBuffer));
1832         VK_CALL(DestroyFence(this->device(), fence, nullptr));
1833         SkDebugf("Fence failed to signal: %d\n", err);
1834         SK_ABORT("failing");
1835     }
1836     SkASSERT(!err);
1837 
1838     // Clean up transfer resources
1839     if (buffer != VK_NULL_HANDLE) { // workaround for an older NVidia driver crash
1840         GrVkMemory::FreeBufferMemory(this, GrVkBuffer::kCopyRead_Type, bufferAlloc);
1841         VK_CALL(DestroyBuffer(fDevice, buffer, nullptr));
1842     }
1843     VK_CALL(FreeCommandBuffers(fDevice, fCmdPool->vkCommandPool(), 1, &cmdBuffer));
1844     VK_CALL(DestroyFence(this->device(), fence, nullptr));
1845 
1846     return true;
1847 }
1848 
createBackendTexture(int w,int h,const GrBackendFormat & format,GrMipMapped mipMapped,GrRenderable renderable,const void * srcData,size_t rowBytes,const SkColor4f * color,GrProtected isProtected)1849 GrBackendTexture GrVkGpu::createBackendTexture(int w, int h,
1850                                                const GrBackendFormat& format,
1851                                                GrMipMapped mipMapped,
1852                                                GrRenderable renderable,
1853                                                const void* srcData, size_t rowBytes,
1854                                                const SkColor4f* color, GrProtected isProtected) {
1855     const GrVkCaps& caps = this->vkCaps();
1856     this->handleDirtyContext();
1857 
1858     if (fProtectedContext != isProtected) {
1859         return GrBackendTexture();
1860     }
1861 
1862     if (w > caps.maxTextureSize() || h > caps.maxTextureSize()) {
1863         return GrBackendTexture();
1864     }
1865 
1866     VkFormat vkFormat;
1867     if (!format.asVkFormat(&vkFormat)) {
1868         SkDebugf("Could net get vkformat\n");
1869         return GrBackendTexture();
1870     }
1871 
1872     if (!caps.isVkFormatTexturable(vkFormat)) {
1873         SkDebugf("Config is not texturable\n");
1874         return GrBackendTexture();
1875     }
1876 
1877     if (GrVkFormatNeedsYcbcrSampler(vkFormat)) {
1878         SkDebugf("Can't create BackendTexture that requires Ycbcb sampler.\n");
1879         return GrBackendTexture();
1880     }
1881 
1882     GrVkImageInfo info;
1883     if (!this->createVkImageForBackendSurface(vkFormat, w, h, true,
1884                                               GrRenderable::kYes == renderable, mipMapped, srcData,
1885                                               rowBytes, color, &info, isProtected)) {
1886         SkDebugf("Failed to create testing only image\n");
1887         return GrBackendTexture();
1888     }
1889 
1890     return GrBackendTexture(w, h, info);
1891 }
1892 
deleteBackendTexture(const GrBackendTexture & tex)1893 void GrVkGpu::deleteBackendTexture(const GrBackendTexture& tex) {
1894     SkASSERT(GrBackendApi::kVulkan == tex.fBackend);
1895 
1896     GrVkImageInfo info;
1897     if (tex.getVkImageInfo(&info)) {
1898         GrVkImage::DestroyImageInfo(this, const_cast<GrVkImageInfo*>(&info));
1899     }
1900 }
1901 
1902 #if GR_TEST_UTILS
isTestingOnlyBackendTexture(const GrBackendTexture & tex) const1903 bool GrVkGpu::isTestingOnlyBackendTexture(const GrBackendTexture& tex) const {
1904     SkASSERT(GrBackendApi::kVulkan == tex.fBackend);
1905 
1906     GrVkImageInfo backend;
1907     if (!tex.getVkImageInfo(&backend)) {
1908         return false;
1909     }
1910 
1911     if (backend.fImage && backend.fAlloc.fMemory) {
1912         VkMemoryRequirements req;
1913         memset(&req, 0, sizeof(req));
1914         GR_VK_CALL(this->vkInterface(), GetImageMemoryRequirements(fDevice,
1915                                                                    backend.fImage,
1916                                                                    &req));
1917         // TODO: find a better check
1918         // This will probably fail with a different driver
1919         return (req.size > 0) && (req.size <= 8192 * 8192);
1920     }
1921 
1922     return false;
1923 }
1924 
createTestingOnlyBackendRenderTarget(int w,int h,GrColorType ct)1925 GrBackendRenderTarget GrVkGpu::createTestingOnlyBackendRenderTarget(int w, int h, GrColorType ct) {
1926     this->handleDirtyContext();
1927 
1928     if (w > this->caps()->maxRenderTargetSize() || h > this->caps()->maxRenderTargetSize()) {
1929         return GrBackendRenderTarget();
1930     }
1931 
1932     VkFormat vkFormat = this->vkCaps().getFormatFromColorType(ct);
1933 
1934     GrVkImageInfo info;
1935     if (!this->createVkImageForBackendSurface(vkFormat, w, h, false, true, GrMipMapped::kNo,
1936                                               nullptr, 0, &SkColors::kTransparent, &info,
1937                                               GrProtected::kNo)) {
1938         return {};
1939     }
1940 
1941     return GrBackendRenderTarget(w, h, 1, 0, info);
1942 }
1943 
deleteTestingOnlyBackendRenderTarget(const GrBackendRenderTarget & rt)1944 void GrVkGpu::deleteTestingOnlyBackendRenderTarget(const GrBackendRenderTarget& rt) {
1945     SkASSERT(GrBackendApi::kVulkan == rt.fBackend);
1946 
1947     GrVkImageInfo info;
1948     if (rt.getVkImageInfo(&info)) {
1949         // something in the command buffer may still be using this, so force submit
1950         this->submitCommandBuffer(kForce_SyncQueue);
1951         GrVkImage::DestroyImageInfo(this, const_cast<GrVkImageInfo*>(&info));
1952     }
1953 }
1954 
testingOnly_flushGpuAndSync()1955 void GrVkGpu::testingOnly_flushGpuAndSync() {
1956     this->submitCommandBuffer(kForce_SyncQueue);
1957 }
1958 #endif
1959 
1960 ////////////////////////////////////////////////////////////////////////////////
1961 
addBufferMemoryBarrier(const GrVkResource * resource,VkPipelineStageFlags srcStageMask,VkPipelineStageFlags dstStageMask,bool byRegion,VkBufferMemoryBarrier * barrier) const1962 void GrVkGpu::addBufferMemoryBarrier(const GrVkResource* resource,
1963                                      VkPipelineStageFlags srcStageMask,
1964                                      VkPipelineStageFlags dstStageMask,
1965                                      bool byRegion,
1966                                      VkBufferMemoryBarrier* barrier) const {
1967     SkASSERT(fCurrentCmdBuffer);
1968     SkASSERT(resource);
1969     fCurrentCmdBuffer->pipelineBarrier(this,
1970                                        resource,
1971                                        srcStageMask,
1972                                        dstStageMask,
1973                                        byRegion,
1974                                        GrVkCommandBuffer::kBufferMemory_BarrierType,
1975                                        barrier);
1976 }
1977 
addImageMemoryBarrier(const GrVkResource * resource,VkPipelineStageFlags srcStageMask,VkPipelineStageFlags dstStageMask,bool byRegion,VkImageMemoryBarrier * barrier) const1978 void GrVkGpu::addImageMemoryBarrier(const GrVkResource* resource,
1979                                     VkPipelineStageFlags srcStageMask,
1980                                     VkPipelineStageFlags dstStageMask,
1981                                     bool byRegion,
1982                                     VkImageMemoryBarrier* barrier) const {
1983     SkASSERT(fCurrentCmdBuffer);
1984     SkASSERT(resource);
1985     fCurrentCmdBuffer->pipelineBarrier(this,
1986                                        resource,
1987                                        srcStageMask,
1988                                        dstStageMask,
1989                                        byRegion,
1990                                        GrVkCommandBuffer::kImageMemory_BarrierType,
1991                                        barrier);
1992 }
1993 
onFinishFlush(GrSurfaceProxy * proxies[],int n,SkSurface::BackendSurfaceAccess access,const GrFlushInfo & info,const GrPrepareForExternalIORequests & externalRequests)1994 void GrVkGpu::onFinishFlush(GrSurfaceProxy* proxies[], int n,
1995                             SkSurface::BackendSurfaceAccess access, const GrFlushInfo& info,
1996                             const GrPrepareForExternalIORequests& externalRequests) {
1997     SkASSERT(n >= 0);
1998     SkASSERT(!n || proxies);
1999     // Submit the current command buffer to the Queue. Whether we inserted semaphores or not does
2000     // not effect what we do here.
2001     if (n && access == SkSurface::BackendSurfaceAccess::kPresent) {
2002         GrVkImage* image;
2003         for (int i = 0; i < n; ++i) {
2004             SkASSERT(proxies[i]->isInstantiated());
2005             if (GrTexture* tex = proxies[i]->peekTexture()) {
2006                 image = static_cast<GrVkTexture*>(tex);
2007             } else {
2008                 GrRenderTarget* rt = proxies[i]->peekRenderTarget();
2009                 SkASSERT(rt);
2010                 image = static_cast<GrVkRenderTarget*>(rt);
2011             }
2012             image->prepareForPresent(this);
2013         }
2014     }
2015 
2016     // Handle requests for preparing for external IO
2017     for (int i = 0; i < externalRequests.fNumImages; ++i) {
2018         SkImage* image = externalRequests.fImages[i];
2019         if (!image->isTextureBacked()) {
2020             continue;
2021         }
2022         SkImage_GpuBase* gpuImage = static_cast<SkImage_GpuBase*>(as_IB(image));
2023         sk_sp<GrTextureProxy> proxy = gpuImage->asTextureProxyRef(this->getContext());
2024         SkASSERT(proxy);
2025 
2026         if (!proxy->isInstantiated()) {
2027             auto resourceProvider = this->getContext()->priv().resourceProvider();
2028             if (!proxy->instantiate(resourceProvider)) {
2029                 continue;
2030             }
2031         }
2032 
2033         GrTexture* tex = proxy->peekTexture();
2034         if (!tex) {
2035             continue;
2036         }
2037         GrVkTexture* vkTex = static_cast<GrVkTexture*>(tex);
2038         vkTex->prepareForExternal(this);
2039     }
2040     for (int i = 0; i < externalRequests.fNumSurfaces; ++i) {
2041         SkSurface* surface = externalRequests.fSurfaces[i];
2042         if (!surface->getCanvas()->getGrContext()) {
2043             continue;
2044         }
2045         SkSurface_Gpu* gpuSurface = static_cast<SkSurface_Gpu*>(surface);
2046         auto* rtc = gpuSurface->getDevice()->accessRenderTargetContext();
2047         sk_sp<GrRenderTargetProxy> proxy = rtc->asRenderTargetProxyRef();
2048         if (!proxy->isInstantiated()) {
2049             auto resourceProvider = this->getContext()->priv().resourceProvider();
2050             if (!proxy->instantiate(resourceProvider)) {
2051                 continue;
2052             }
2053         }
2054 
2055         GrRenderTarget* rt = proxy->peekRenderTarget();
2056         SkASSERT(rt);
2057         GrVkRenderTarget* vkRT = static_cast<GrVkRenderTarget*>(rt);
2058         if (externalRequests.fPrepareSurfaceForPresent &&
2059             externalRequests.fPrepareSurfaceForPresent[i]) {
2060             vkRT->prepareForPresent(this);
2061         } else {
2062             vkRT->prepareForExternal(this);
2063         }
2064     }
2065 
2066     if (info.fFlags & kSyncCpu_GrFlushFlag) {
2067         this->submitCommandBuffer(kForce_SyncQueue, info.fFinishedProc, info.fFinishedContext);
2068     } else {
2069         this->submitCommandBuffer(kSkip_SyncQueue, info.fFinishedProc, info.fFinishedContext);
2070     }
2071 }
2072 
get_surface_sample_cnt(GrSurface * surf)2073 static int get_surface_sample_cnt(GrSurface* surf) {
2074     if (const GrRenderTarget* rt = surf->asRenderTarget()) {
2075         return rt->numSamples();
2076     }
2077     return 0;
2078 }
2079 
copySurfaceAsCopyImage(GrSurface * dst,GrSurface * src,GrVkImage * dstImage,GrVkImage * srcImage,const SkIRect & srcRect,const SkIPoint & dstPoint)2080 void GrVkGpu::copySurfaceAsCopyImage(GrSurface* dst, GrSurface* src, GrVkImage* dstImage,
2081                                      GrVkImage* srcImage, const SkIRect& srcRect,
2082                                      const SkIPoint& dstPoint) {
2083 #ifdef SK_DEBUG
2084     int dstSampleCnt = get_surface_sample_cnt(dst);
2085     int srcSampleCnt = get_surface_sample_cnt(src);
2086     bool dstHasYcbcr = dstImage->ycbcrConversionInfo().isValid();
2087     bool srcHasYcbcr = srcImage->ycbcrConversionInfo().isValid();
2088     VkFormat dstFormat = dstImage->imageFormat();
2089     VkFormat srcFormat;
2090     SkAssertResult(dst->backendFormat().asVkFormat(&srcFormat));
2091     SkASSERT(this->vkCaps().canCopyImage(dstFormat, dstSampleCnt, dstHasYcbcr,
2092                                          srcFormat, srcSampleCnt, srcHasYcbcr));
2093 #endif
2094     if (src->isProtected() && !dst->isProtected()) {
2095         SkDebugf("Can't copy from protected memory to non-protected");
2096         return;
2097     }
2098 
2099     // These flags are for flushing/invalidating caches and for the dst image it doesn't matter if
2100     // the cache is flushed since it is only being written to.
2101     dstImage->setImageLayout(this,
2102                              VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
2103                              VK_ACCESS_TRANSFER_WRITE_BIT,
2104                              VK_PIPELINE_STAGE_TRANSFER_BIT,
2105                              false);
2106 
2107     srcImage->setImageLayout(this,
2108                              VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
2109                              VK_ACCESS_TRANSFER_READ_BIT,
2110                              VK_PIPELINE_STAGE_TRANSFER_BIT,
2111                              false);
2112 
2113     VkImageCopy copyRegion;
2114     memset(&copyRegion, 0, sizeof(VkImageCopy));
2115     copyRegion.srcSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
2116     copyRegion.srcOffset = { srcRect.fLeft, srcRect.fTop, 0 };
2117     copyRegion.dstSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
2118     copyRegion.dstOffset = { dstPoint.fX, dstPoint.fY, 0 };
2119     copyRegion.extent = { (uint32_t)srcRect.width(), (uint32_t)srcRect.height(), 1 };
2120 
2121     fCurrentCmdBuffer->copyImage(this,
2122                                  srcImage,
2123                                  VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
2124                                  dstImage,
2125                                  VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
2126                                  1,
2127                                  &copyRegion);
2128 
2129     SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.fX, dstPoint.fY,
2130                                         srcRect.width(), srcRect.height());
2131     // The rect is already in device space so we pass in kTopLeft so no flip is done.
2132     this->didWriteToSurface(dst, kTopLeft_GrSurfaceOrigin, &dstRect);
2133 }
2134 
copySurfaceAsBlit(GrSurface * dst,GrSurface * src,GrVkImage * dstImage,GrVkImage * srcImage,const SkIRect & srcRect,const SkIPoint & dstPoint)2135 void GrVkGpu::copySurfaceAsBlit(GrSurface* dst, GrSurface* src, GrVkImage* dstImage,
2136                                 GrVkImage* srcImage, const SkIRect& srcRect,
2137                                 const SkIPoint& dstPoint) {
2138 #ifdef SK_DEBUG
2139     int dstSampleCnt = get_surface_sample_cnt(dst);
2140     int srcSampleCnt = get_surface_sample_cnt(src);
2141     bool dstHasYcbcr = dstImage->ycbcrConversionInfo().isValid();
2142     bool srcHasYcbcr = srcImage->ycbcrConversionInfo().isValid();
2143     VkFormat dstFormat = dstImage->imageFormat();
2144     VkFormat srcFormat;
2145     SkAssertResult(dst->backendFormat().asVkFormat(&srcFormat));
2146     SkASSERT(this->vkCaps().canCopyAsBlit(dstFormat, dstSampleCnt, dstImage->isLinearTiled(),
2147                                           dstHasYcbcr, srcFormat, srcSampleCnt,
2148                                           srcImage->isLinearTiled(), srcHasYcbcr));
2149 
2150 #endif
2151     if (src->isProtected() && !dst->isProtected()) {
2152         SkDebugf("Can't copy from protected memory to non-protected");
2153         return;
2154     }
2155 
2156     dstImage->setImageLayout(this,
2157                              VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
2158                              VK_ACCESS_TRANSFER_WRITE_BIT,
2159                              VK_PIPELINE_STAGE_TRANSFER_BIT,
2160                              false);
2161 
2162     srcImage->setImageLayout(this,
2163                              VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
2164                              VK_ACCESS_TRANSFER_READ_BIT,
2165                              VK_PIPELINE_STAGE_TRANSFER_BIT,
2166                              false);
2167 
2168     // Flip rect if necessary
2169     SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.fX, dstPoint.fY, srcRect.width(),
2170                                         srcRect.height());
2171 
2172     VkImageBlit blitRegion;
2173     memset(&blitRegion, 0, sizeof(VkImageBlit));
2174     blitRegion.srcSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
2175     blitRegion.srcOffsets[0] = { srcRect.fLeft, srcRect.fTop, 0 };
2176     blitRegion.srcOffsets[1] = { srcRect.fRight, srcRect.fBottom, 1 };
2177     blitRegion.dstSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
2178     blitRegion.dstOffsets[0] = { dstRect.fLeft, dstRect.fTop, 0 };
2179     blitRegion.dstOffsets[1] = { dstRect.fRight, dstRect.fBottom, 1 };
2180 
2181     fCurrentCmdBuffer->blitImage(this,
2182                                  *srcImage,
2183                                  *dstImage,
2184                                  1,
2185                                  &blitRegion,
2186                                  VK_FILTER_NEAREST); // We never scale so any filter works here
2187 
2188     // The rect is already in device space so we pass in kTopLeft so no flip is done.
2189     this->didWriteToSurface(dst, kTopLeft_GrSurfaceOrigin, &dstRect);
2190 }
2191 
copySurfaceAsResolve(GrSurface * dst,GrSurface * src,const SkIRect & srcRect,const SkIPoint & dstPoint)2192 void GrVkGpu::copySurfaceAsResolve(GrSurface* dst, GrSurface* src, const SkIRect& srcRect,
2193                                    const SkIPoint& dstPoint) {
2194     if (src->isProtected() && !dst->isProtected()) {
2195         SkDebugf("Can't copy from protected memory to non-protected");
2196         return;
2197     }
2198     GrVkRenderTarget* srcRT = static_cast<GrVkRenderTarget*>(src->asRenderTarget());
2199     this->resolveImage(dst, srcRT, srcRect, dstPoint);
2200     SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.fX, dstPoint.fY,
2201                                         srcRect.width(), srcRect.height());
2202     // The rect is already in device space so we pass in kTopLeft so no flip is done.
2203     this->didWriteToSurface(dst, kTopLeft_GrSurfaceOrigin, &dstRect);
2204 }
2205 
onCopySurface(GrSurface * dst,GrSurface * src,const SkIRect & srcRect,const SkIPoint & dstPoint,bool canDiscardOutsideDstRect)2206 bool GrVkGpu::onCopySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcRect,
2207                             const SkIPoint& dstPoint, bool canDiscardOutsideDstRect) {
2208 #ifdef SK_DEBUG
2209     if (GrVkRenderTarget* srcRT = static_cast<GrVkRenderTarget*>(src->asRenderTarget())) {
2210         SkASSERT(!srcRT->wrapsSecondaryCommandBuffer());
2211     }
2212     if (GrVkRenderTarget* dstRT = static_cast<GrVkRenderTarget*>(dst->asRenderTarget())) {
2213         SkASSERT(!dstRT->wrapsSecondaryCommandBuffer());
2214     }
2215 #endif
2216     if (src->isProtected() && !dst->isProtected()) {
2217         SkDebugf("Can't copy from protected memory to non-protected");
2218         return false;
2219     }
2220 
2221     int dstSampleCnt = get_surface_sample_cnt(dst);
2222     int srcSampleCnt = get_surface_sample_cnt(src);
2223 
2224     GrVkImage* dstImage;
2225     GrVkImage* srcImage;
2226     GrRenderTarget* dstRT = dst->asRenderTarget();
2227     if (dstRT) {
2228         GrVkRenderTarget* vkRT = static_cast<GrVkRenderTarget*>(dstRT);
2229         if (vkRT->wrapsSecondaryCommandBuffer()) {
2230             return false;
2231         }
2232         dstImage = vkRT->numSamples() > 1 ? vkRT->msaaImage() : vkRT;
2233     } else {
2234         SkASSERT(dst->asTexture());
2235         dstImage = static_cast<GrVkTexture*>(dst->asTexture());
2236     }
2237     GrRenderTarget* srcRT = src->asRenderTarget();
2238     if (srcRT) {
2239         GrVkRenderTarget* vkRT = static_cast<GrVkRenderTarget*>(srcRT);
2240         srcImage = vkRT->numSamples() > 1 ? vkRT->msaaImage() : vkRT;
2241     } else {
2242         SkASSERT(src->asTexture());
2243         srcImage = static_cast<GrVkTexture*>(src->asTexture());
2244     }
2245 
2246     VkFormat dstFormat = dstImage->imageFormat();
2247     VkFormat srcFormat = srcImage->imageFormat();
2248 
2249     bool dstHasYcbcr = dstImage->ycbcrConversionInfo().isValid();
2250     bool srcHasYcbcr = srcImage->ycbcrConversionInfo().isValid();
2251 
2252     if (this->vkCaps().canCopyAsResolve(dstFormat, dstSampleCnt, dstHasYcbcr,
2253                                         srcFormat, srcSampleCnt, srcHasYcbcr)) {
2254         this->copySurfaceAsResolve(dst, src, srcRect, dstPoint);
2255         return true;
2256     }
2257 
2258     if (this->vkCaps().canCopyImage(dstFormat, dstSampleCnt, dstHasYcbcr,
2259                                     srcFormat, srcSampleCnt, srcHasYcbcr)) {
2260         this->copySurfaceAsCopyImage(dst, src, dstImage, srcImage, srcRect, dstPoint);
2261         return true;
2262     }
2263 
2264     if (this->vkCaps().canCopyAsBlit(dstFormat, dstSampleCnt, dstImage->isLinearTiled(),
2265                                      dstHasYcbcr, srcFormat, srcSampleCnt,
2266                                      srcImage->isLinearTiled(), srcHasYcbcr)) {
2267         this->copySurfaceAsBlit(dst, src, dstImage, srcImage, srcRect, dstPoint);
2268         return true;
2269     }
2270 
2271     return false;
2272 }
2273 
onReadPixels(GrSurface * surface,int left,int top,int width,int height,GrColorType surfaceColorType,GrColorType dstColorType,void * buffer,size_t rowBytes)2274 bool GrVkGpu::onReadPixels(GrSurface* surface, int left, int top, int width, int height,
2275                            GrColorType surfaceColorType, GrColorType dstColorType, void* buffer,
2276                            size_t rowBytes) {
2277     if (surface->isProtected()) {
2278         return false;
2279     }
2280 
2281     if (surfaceColorType != dstColorType) {
2282         return false;
2283     }
2284 
2285     GrVkImage* image = nullptr;
2286     GrVkRenderTarget* rt = static_cast<GrVkRenderTarget*>(surface->asRenderTarget());
2287     if (rt) {
2288         // Reading from render targets that wrap a secondary command buffer is not allowed since
2289         // it would require us to know the VkImage, which we don't have, as well as need us to
2290         // stop and start the VkRenderPass which we don't have access to.
2291         if (rt->wrapsSecondaryCommandBuffer()) {
2292             return false;
2293         }
2294         // resolve the render target if necessary
2295         switch (rt->getResolveType()) {
2296             case GrVkRenderTarget::kCantResolve_ResolveType:
2297                 return false;
2298             case GrVkRenderTarget::kAutoResolves_ResolveType:
2299                 break;
2300             case GrVkRenderTarget::kCanResolve_ResolveType:
2301                 this->resolveRenderTargetNoFlush(rt);
2302                 break;
2303             default:
2304                 SK_ABORT("Unknown resolve type");
2305         }
2306         image = rt;
2307     } else {
2308         image = static_cast<GrVkTexture*>(surface->asTexture());
2309     }
2310 
2311     if (!image) {
2312         return false;
2313     }
2314 
2315     // Skia's RGB_888x color type, which we map to the vulkan R8G8B8_UNORM, expects the data to be
2316     // 32 bits, but the Vulkan format is only 24. So we first copy the surface into an R8G8B8A8
2317     // image and then do the read pixels from that.
2318     sk_sp<GrVkTextureRenderTarget> copySurface;
2319     if (dstColorType == GrColorType::kRGB_888x && image->imageFormat() == VK_FORMAT_R8G8B8_UNORM) {
2320         int srcSampleCount = 0;
2321         if (rt) {
2322             srcSampleCount = rt->numSamples();
2323         }
2324         bool srcHasYcbcr = image->ycbcrConversionInfo().isValid();
2325         if (!this->vkCaps().canCopyAsBlit(VK_FORMAT_R8G8B8A8_UNORM, 1, false, false,
2326                                           image->imageFormat(), srcSampleCount,
2327                                           image->isLinearTiled(), srcHasYcbcr)) {
2328             return false;
2329         }
2330 
2331         // Make a new surface that is RGBA to copy the RGB surface into.
2332         GrSurfaceDesc surfDesc;
2333         surfDesc.fWidth = width;
2334         surfDesc.fHeight = height;
2335         surfDesc.fConfig = kRGBA_8888_GrPixelConfig;
2336 
2337         VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
2338                                        VK_IMAGE_USAGE_SAMPLED_BIT |
2339                                        VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
2340                                        VK_IMAGE_USAGE_TRANSFER_DST_BIT;
2341 
2342         GrVkImage::ImageDesc imageDesc;
2343         imageDesc.fImageType = VK_IMAGE_TYPE_2D;
2344         imageDesc.fFormat = VK_FORMAT_R8G8B8A8_UNORM;
2345         imageDesc.fWidth = width;
2346         imageDesc.fHeight = height;
2347         imageDesc.fLevels = 1;
2348         imageDesc.fSamples = 1;
2349         imageDesc.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
2350         imageDesc.fUsageFlags = usageFlags;
2351         imageDesc.fMemProps = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
2352 
2353         copySurface = GrVkTextureRenderTarget::MakeNewTextureRenderTarget(
2354                 this, SkBudgeted::kYes, surfDesc, 1, imageDesc, GrMipMapsStatus::kNotAllocated);
2355         if (!copySurface) {
2356             return false;
2357         }
2358 
2359         SkIRect srcRect = SkIRect::MakeXYWH(left, top, width, height);
2360         SkAssertResult(this->copySurface(copySurface.get(), surface, srcRect, SkIPoint::Make(0,0)));
2361 
2362         top = 0;
2363         left = 0;
2364         dstColorType = GrColorType::kRGBA_8888;
2365         image = copySurface.get();
2366     }
2367 
2368     // Change layout of our target so it can be used as copy
2369     image->setImageLayout(this,
2370                           VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
2371                           VK_ACCESS_TRANSFER_READ_BIT,
2372                           VK_PIPELINE_STAGE_TRANSFER_BIT,
2373                           false);
2374 
2375     size_t bpp = GrColorTypeBytesPerPixel(dstColorType);
2376     size_t tightRowBytes = bpp * width;
2377 
2378     VkBufferImageCopy region;
2379     memset(&region, 0, sizeof(VkBufferImageCopy));
2380 
2381     bool copyFromOrigin = this->vkCaps().mustDoCopiesFromOrigin();
2382     if (copyFromOrigin) {
2383         region.imageOffset = { 0, 0, 0 };
2384         region.imageExtent = { (uint32_t)(left + width), (uint32_t)(top + height), 1 };
2385     } else {
2386         VkOffset3D offset = { left, top, 0 };
2387         region.imageOffset = offset;
2388         region.imageExtent = { (uint32_t)width, (uint32_t)height, 1 };
2389     }
2390 
2391     size_t transBufferRowBytes = bpp * region.imageExtent.width;
2392     size_t imageRows = region.imageExtent.height;
2393     auto transferBuffer = sk_sp<GrVkTransferBuffer>(
2394             static_cast<GrVkTransferBuffer*>(this->createBuffer(transBufferRowBytes * imageRows,
2395                                                                 GrGpuBufferType::kXferGpuToCpu,
2396                                                                 kStream_GrAccessPattern)
2397                                                      .release()));
2398 
2399     // Copy the image to a buffer so we can map it to cpu memory
2400     region.bufferOffset = transferBuffer->offset();
2401     region.bufferRowLength = 0; // Forces RowLength to be width. We handle the rowBytes below.
2402     region.bufferImageHeight = 0; // Forces height to be tightly packed. Only useful for 3d images.
2403     region.imageSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
2404 
2405     fCurrentCmdBuffer->copyImageToBuffer(this,
2406                                          image,
2407                                          VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
2408                                          transferBuffer.get(),
2409                                          1,
2410                                          &region);
2411 
2412     // make sure the copy to buffer has finished
2413     transferBuffer->addMemoryBarrier(this,
2414                                      VK_ACCESS_TRANSFER_WRITE_BIT,
2415                                      VK_ACCESS_HOST_READ_BIT,
2416                                      VK_PIPELINE_STAGE_TRANSFER_BIT,
2417                                      VK_PIPELINE_STAGE_HOST_BIT,
2418                                      false);
2419 
2420     // We need to submit the current command buffer to the Queue and make sure it finishes before
2421     // we can copy the data out of the buffer.
2422     this->submitCommandBuffer(kForce_SyncQueue);
2423     void* mappedMemory = transferBuffer->map();
2424     const GrVkAlloc& transAlloc = transferBuffer->alloc();
2425     GrVkMemory::InvalidateMappedAlloc(this, transAlloc, 0, transAlloc.fSize);
2426 
2427     if (copyFromOrigin) {
2428         uint32_t skipRows = region.imageExtent.height - height;
2429         mappedMemory = (char*)mappedMemory + transBufferRowBytes * skipRows + bpp * left;
2430     }
2431 
2432     SkRectMemcpy(buffer, rowBytes, mappedMemory, transBufferRowBytes, tightRowBytes, height);
2433 
2434     transferBuffer->unmap();
2435     return true;
2436 }
2437 
2438 // The RenderArea bounds we pass into BeginRenderPass must have a start x value that is a multiple
2439 // of the granularity. The width must also be a multiple of the granularity or eaqual to the width
2440 // the the entire attachment. Similar requirements for the y and height components.
adjust_bounds_to_granularity(SkIRect * dstBounds,const SkIRect & srcBounds,const VkExtent2D & granularity,int maxWidth,int maxHeight)2441 void adjust_bounds_to_granularity(SkIRect* dstBounds, const SkIRect& srcBounds,
2442                                   const VkExtent2D& granularity, int maxWidth, int maxHeight) {
2443     // Adjust Width
2444     if ((0 != granularity.width && 1 != granularity.width)) {
2445         // Start with the right side of rect so we know if we end up going pass the maxWidth.
2446         int rightAdj = srcBounds.fRight % granularity.width;
2447         if (rightAdj != 0) {
2448             rightAdj = granularity.width - rightAdj;
2449         }
2450         dstBounds->fRight = srcBounds.fRight + rightAdj;
2451         if (dstBounds->fRight > maxWidth) {
2452             dstBounds->fRight = maxWidth;
2453             dstBounds->fLeft = 0;
2454         } else {
2455             dstBounds->fLeft = srcBounds.fLeft - srcBounds.fLeft % granularity.width;
2456         }
2457     } else {
2458         dstBounds->fLeft = srcBounds.fLeft;
2459         dstBounds->fRight = srcBounds.fRight;
2460     }
2461 
2462     // Adjust height
2463     if ((0 != granularity.height && 1 != granularity.height)) {
2464         // Start with the bottom side of rect so we know if we end up going pass the maxHeight.
2465         int bottomAdj = srcBounds.fBottom % granularity.height;
2466         if (bottomAdj != 0) {
2467             bottomAdj = granularity.height - bottomAdj;
2468         }
2469         dstBounds->fBottom = srcBounds.fBottom + bottomAdj;
2470         if (dstBounds->fBottom > maxHeight) {
2471             dstBounds->fBottom = maxHeight;
2472             dstBounds->fTop = 0;
2473         } else {
2474             dstBounds->fTop = srcBounds.fTop - srcBounds.fTop % granularity.height;
2475         }
2476     } else {
2477         dstBounds->fTop = srcBounds.fTop;
2478         dstBounds->fBottom = srcBounds.fBottom;
2479     }
2480 }
2481 
submitSecondaryCommandBuffer(std::unique_ptr<GrVkSecondaryCommandBuffer> buffer,const GrVkRenderPass * renderPass,const VkClearValue * colorClear,GrVkRenderTarget * target,GrSurfaceOrigin origin,const SkIRect & bounds)2482 void GrVkGpu::submitSecondaryCommandBuffer(
2483         std::unique_ptr<GrVkSecondaryCommandBuffer> buffer,
2484         const GrVkRenderPass* renderPass,
2485         const VkClearValue* colorClear,
2486         GrVkRenderTarget* target, GrSurfaceOrigin origin,
2487         const SkIRect& bounds) {
2488 
2489     SkASSERT (!target->wrapsSecondaryCommandBuffer());
2490     const SkIRect* pBounds = &bounds;
2491     SkIRect flippedBounds;
2492     if (kBottomLeft_GrSurfaceOrigin == origin) {
2493         flippedBounds = bounds;
2494         flippedBounds.fTop = target->height() - bounds.fBottom;
2495         flippedBounds.fBottom = target->height() - bounds.fTop;
2496         pBounds = &flippedBounds;
2497     }
2498 
2499     // The bounds we use for the render pass should be of the granularity supported
2500     // by the device.
2501     const VkExtent2D& granularity = renderPass->granularity();
2502     SkIRect adjustedBounds;
2503     if ((0 != granularity.width && 1 != granularity.width) ||
2504         (0 != granularity.height && 1 != granularity.height)) {
2505         adjust_bounds_to_granularity(&adjustedBounds, *pBounds, granularity,
2506                                      target->width(), target->height());
2507         pBounds = &adjustedBounds;
2508     }
2509 
2510 #ifdef SK_DEBUG
2511     uint32_t index;
2512     bool result = renderPass->colorAttachmentIndex(&index);
2513     SkASSERT(result && 0 == index);
2514     result = renderPass->stencilAttachmentIndex(&index);
2515     if (result) {
2516         SkASSERT(1 == index);
2517     }
2518 #endif
2519     VkClearValue clears[2];
2520     clears[0].color = colorClear->color;
2521     clears[1].depthStencil.depth = 0.0f;
2522     clears[1].depthStencil.stencil = 0;
2523 
2524     fCurrentCmdBuffer->beginRenderPass(this, renderPass, clears, *target, *pBounds, true);
2525     fCurrentCmdBuffer->executeCommands(this, std::move(buffer));
2526     fCurrentCmdBuffer->endRenderPass(this);
2527 
2528     this->didWriteToSurface(target, origin, &bounds);
2529 }
2530 
submit(GrGpuCommandBuffer * buffer)2531 void GrVkGpu::submit(GrGpuCommandBuffer* buffer) {
2532     if (buffer->asRTCommandBuffer()) {
2533         SkASSERT(fCachedRTCommandBuffer.get() == buffer);
2534 
2535         fCachedRTCommandBuffer->submit();
2536         fCachedRTCommandBuffer->reset();
2537     } else {
2538         SkASSERT(fCachedTexCommandBuffer.get() == buffer);
2539 
2540         fCachedTexCommandBuffer->submit();
2541         fCachedTexCommandBuffer->reset();
2542     }
2543 }
2544 
insertFence()2545 GrFence SK_WARN_UNUSED_RESULT GrVkGpu::insertFence() {
2546     VkFenceCreateInfo createInfo;
2547     memset(&createInfo, 0, sizeof(VkFenceCreateInfo));
2548     createInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
2549     createInfo.pNext = nullptr;
2550     createInfo.flags = 0;
2551     VkFence fence = VK_NULL_HANDLE;
2552 
2553     VK_CALL_ERRCHECK(CreateFence(this->device(), &createInfo, nullptr, &fence));
2554     VK_CALL(QueueSubmit(this->queue(), 0, nullptr, fence));
2555 
2556     GR_STATIC_ASSERT(sizeof(GrFence) >= sizeof(VkFence));
2557     return (GrFence)fence;
2558 }
2559 
waitFence(GrFence fence,uint64_t timeout)2560 bool GrVkGpu::waitFence(GrFence fence, uint64_t timeout) {
2561     SkASSERT(VK_NULL_HANDLE != (VkFence)fence);
2562 
2563     VkResult result = VK_CALL(WaitForFences(this->device(), 1, (VkFence*)&fence, VK_TRUE, timeout));
2564     return (VK_SUCCESS == result);
2565 }
2566 
deleteFence(GrFence fence) const2567 void GrVkGpu::deleteFence(GrFence fence) const {
2568     VK_CALL(DestroyFence(this->device(), (VkFence)fence, nullptr));
2569 }
2570 
makeSemaphore(bool isOwned)2571 sk_sp<GrSemaphore> SK_WARN_UNUSED_RESULT GrVkGpu::makeSemaphore(bool isOwned) {
2572     return GrVkSemaphore::Make(this, isOwned);
2573 }
2574 
wrapBackendSemaphore(const GrBackendSemaphore & semaphore,GrResourceProvider::SemaphoreWrapType wrapType,GrWrapOwnership ownership)2575 sk_sp<GrSemaphore> GrVkGpu::wrapBackendSemaphore(const GrBackendSemaphore& semaphore,
2576                                                  GrResourceProvider::SemaphoreWrapType wrapType,
2577                                                  GrWrapOwnership ownership) {
2578     return GrVkSemaphore::MakeWrapped(this, semaphore.vkSemaphore(), wrapType, ownership);
2579 }
2580 
insertSemaphore(sk_sp<GrSemaphore> semaphore)2581 void GrVkGpu::insertSemaphore(sk_sp<GrSemaphore> semaphore) {
2582     GrVkSemaphore* vkSem = static_cast<GrVkSemaphore*>(semaphore.get());
2583 
2584     GrVkSemaphore::Resource* resource = vkSem->getResource();
2585     if (resource->shouldSignal()) {
2586         resource->ref();
2587         fSemaphoresToSignal.push_back(resource);
2588     }
2589 }
2590 
waitSemaphore(sk_sp<GrSemaphore> semaphore)2591 void GrVkGpu::waitSemaphore(sk_sp<GrSemaphore> semaphore) {
2592     GrVkSemaphore* vkSem = static_cast<GrVkSemaphore*>(semaphore.get());
2593 
2594     GrVkSemaphore::Resource* resource = vkSem->getResource();
2595     if (resource->shouldWait()) {
2596         resource->ref();
2597         fSemaphoresToWaitOn.push_back(resource);
2598     }
2599 }
2600 
prepareTextureForCrossContextUsage(GrTexture * texture)2601 sk_sp<GrSemaphore> GrVkGpu::prepareTextureForCrossContextUsage(GrTexture* texture) {
2602     SkASSERT(texture);
2603     GrVkTexture* vkTexture = static_cast<GrVkTexture*>(texture);
2604     vkTexture->setImageLayout(this,
2605                               VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
2606                               VK_ACCESS_SHADER_READ_BIT,
2607                               VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
2608                               false);
2609     this->submitCommandBuffer(kSkip_SyncQueue);
2610 
2611     // The image layout change serves as a barrier, so no semaphore is needed.
2612     // If we ever decide we need to return a semaphore here, we need to make sure GrVkSemaphore is
2613     // thread safe so that only the first thread that tries to use the semaphore actually submits
2614     // it. This additionally would also require thread safety in command buffer submissions to
2615     // queues in general.
2616     return nullptr;
2617 }
2618 
addDrawable(std::unique_ptr<SkDrawable::GpuDrawHandler> drawable)2619 void GrVkGpu::addDrawable(std::unique_ptr<SkDrawable::GpuDrawHandler> drawable) {
2620     fDrawables.emplace_back(std::move(drawable));
2621 }
2622 
getExtraSamplerKeyForProgram(const GrSamplerState & samplerState,const GrBackendFormat & format)2623 uint32_t GrVkGpu::getExtraSamplerKeyForProgram(const GrSamplerState& samplerState,
2624                                                const GrBackendFormat& format) {
2625     const GrVkYcbcrConversionInfo* ycbcrInfo = format.getVkYcbcrConversionInfo();
2626     SkASSERT(ycbcrInfo);
2627     if (!ycbcrInfo->isValid()) {
2628         return 0;
2629     }
2630 
2631     const GrVkSampler* sampler = this->resourceProvider().findOrCreateCompatibleSampler(
2632             samplerState, *ycbcrInfo);
2633 
2634     uint32_t result = sampler->uniqueID();
2635 
2636     sampler->unref(this);
2637 
2638     return result;
2639 }
2640 
storeVkPipelineCacheData()2641 void GrVkGpu::storeVkPipelineCacheData() {
2642     if (this->getContext()->priv().getPersistentCache()) {
2643         this->resourceProvider().storePipelineCacheData();
2644     }
2645 }
2646