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