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