• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2015 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "GrVkGpu.h"
9 
10 #include "GrBackendSemaphore.h"
11 #include "GrBackendSurface.h"
12 #include "GrContextOptions.h"
13 #include "GrGeometryProcessor.h"
14 #include "GrGpuResourceCacheAccess.h"
15 #include "GrMesh.h"
16 #include "GrPipeline.h"
17 #include "GrRenderTargetPriv.h"
18 #include "GrSurfacePriv.h"
19 #include "GrTexturePriv.h"
20 
21 #include "GrVkCommandBuffer.h"
22 #include "GrVkGpuCommandBuffer.h"
23 #include "GrVkImage.h"
24 #include "GrVkIndexBuffer.h"
25 #include "GrVkMemory.h"
26 #include "GrVkPipeline.h"
27 #include "GrVkPipelineState.h"
28 #include "GrVkRenderPass.h"
29 #include "GrVkResourceProvider.h"
30 #include "GrVkSemaphore.h"
31 #include "GrVkTexelBuffer.h"
32 #include "GrVkTexture.h"
33 #include "GrVkTextureRenderTarget.h"
34 #include "GrVkTransferBuffer.h"
35 #include "GrVkVertexBuffer.h"
36 
37 #include "SkConvertPixels.h"
38 #include "SkMipMap.h"
39 
40 #include "vk/GrVkInterface.h"
41 #include "vk/GrVkTypes.h"
42 
43 #include "SkSLCompiler.h"
44 
45 #if !defined(SK_BUILD_FOR_WIN)
46 #include <unistd.h>
47 #endif // !defined(SK_BUILD_FOR_WIN)
48 
49 #define VK_CALL(X) GR_VK_CALL(this->vkInterface(), X)
50 #define VK_CALL_RET(RET, X) GR_VK_CALL_RET(this->vkInterface(), RET, X)
51 #define VK_CALL_ERRCHECK(X) GR_VK_CALL_ERRCHECK(this->vkInterface(), X)
52 
53 #ifdef SK_ENABLE_VK_LAYERS
DebugReportCallback(VkDebugReportFlagsEXT flags,VkDebugReportObjectTypeEXT objectType,uint64_t object,size_t location,int32_t messageCode,const char * pLayerPrefix,const char * pMessage,void * pUserData)54 VKAPI_ATTR VkBool32 VKAPI_CALL DebugReportCallback(
55     VkDebugReportFlagsEXT       flags,
56     VkDebugReportObjectTypeEXT  objectType,
57     uint64_t                    object,
58     size_t                      location,
59     int32_t                     messageCode,
60     const char*                 pLayerPrefix,
61     const char*                 pMessage,
62     void*                       pUserData) {
63     if (flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) {
64         SkDebugf("Vulkan error [%s]: code: %d: %s\n", pLayerPrefix, messageCode, pMessage);
65         return VK_TRUE; // skip further layers
66     } else if (flags & VK_DEBUG_REPORT_WARNING_BIT_EXT) {
67         SkDebugf("Vulkan warning [%s]: code: %d: %s\n", pLayerPrefix, messageCode, pMessage);
68     } else if (flags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT) {
69         SkDebugf("Vulkan perf warning [%s]: code: %d: %s\n", pLayerPrefix, messageCode, pMessage);
70     } else {
71         SkDebugf("Vulkan info/debug [%s]: code: %d: %s\n", pLayerPrefix, messageCode, pMessage);
72     }
73     return VK_FALSE;
74 }
75 #endif
76 
Create(GrBackendContext backendContext,const GrContextOptions & options,GrContext * context)77 GrGpu* GrVkGpu::Create(GrBackendContext backendContext, const GrContextOptions& options,
78                        GrContext* context) {
79     const GrVkBackendContext* vkBackendContext =
80         reinterpret_cast<const GrVkBackendContext*>(backendContext);
81     if (!vkBackendContext) {
82         return nullptr;
83     } else {
84         vkBackendContext->ref();
85     }
86 
87     if (!vkBackendContext->fInterface->validate(vkBackendContext->fExtensions)) {
88         return nullptr;
89     }
90 
91     return new GrVkGpu(context, options, vkBackendContext);
92 }
93 
94 ////////////////////////////////////////////////////////////////////////////////
95 
GrVkGpu(GrContext * context,const GrContextOptions & options,const GrVkBackendContext * backendCtx)96 GrVkGpu::GrVkGpu(GrContext* context, const GrContextOptions& options,
97                  const GrVkBackendContext* backendCtx)
98     : INHERITED(context)
99     , fDevice(backendCtx->fDevice)
100     , fQueue(backendCtx->fQueue)
101     , fResourceProvider(this)
102     , fDisconnected(false) {
103     fBackendContext.reset(backendCtx);
104 
105 #ifdef SK_ENABLE_VK_LAYERS
106     fCallback = VK_NULL_HANDLE;
107     if (backendCtx->fExtensions & kEXT_debug_report_GrVkExtensionFlag) {
108         // Setup callback creation information
109         VkDebugReportCallbackCreateInfoEXT callbackCreateInfo;
110         callbackCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT;
111         callbackCreateInfo.pNext = nullptr;
112         callbackCreateInfo.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT |
113                                    VK_DEBUG_REPORT_WARNING_BIT_EXT |
114                                    //VK_DEBUG_REPORT_INFORMATION_BIT_EXT |
115                                    //VK_DEBUG_REPORT_DEBUG_BIT_EXT |
116                                    VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT;
117         callbackCreateInfo.pfnCallback = &DebugReportCallback;
118         callbackCreateInfo.pUserData = nullptr;
119 
120         // Register the callback
121         GR_VK_CALL_ERRCHECK(this->vkInterface(), CreateDebugReportCallbackEXT(
122                             backendCtx->fInstance, &callbackCreateInfo, nullptr, &fCallback));
123     }
124 #endif
125 
126     fCompiler = new SkSL::Compiler();
127 
128     fVkCaps.reset(new GrVkCaps(options, this->vkInterface(), backendCtx->fPhysicalDevice,
129                                backendCtx->fFeatures, backendCtx->fExtensions));
130     fCaps.reset(SkRef(fVkCaps.get()));
131 
132     VK_CALL(GetPhysicalDeviceMemoryProperties(backendCtx->fPhysicalDevice, &fPhysDevMemProps));
133 
134     const VkCommandPoolCreateInfo cmdPoolInfo = {
135         VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,      // sType
136         nullptr,                                         // pNext
137         VK_COMMAND_POOL_CREATE_TRANSIENT_BIT |
138         VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, // CmdPoolCreateFlags
139         backendCtx->fGraphicsQueueIndex,                 // queueFamilyIndex
140     };
141     GR_VK_CALL_ERRCHECK(this->vkInterface(), CreateCommandPool(fDevice, &cmdPoolInfo, nullptr,
142                                                                &fCmdPool));
143 
144     // must call this after creating the CommandPool
145     fResourceProvider.init();
146     fCurrentCmdBuffer = fResourceProvider.findOrCreatePrimaryCommandBuffer();
147     SkASSERT(fCurrentCmdBuffer);
148     fCurrentCmdBuffer->begin(this);
149 
150     // set up our heaps
151     fHeaps[kLinearImage_Heap].reset(new GrVkHeap(this, GrVkHeap::kSubAlloc_Strategy, 16*1024*1024));
152     fHeaps[kOptimalImage_Heap].reset(new GrVkHeap(this, GrVkHeap::kSubAlloc_Strategy, 64*1024*1024));
153     fHeaps[kSmallOptimalImage_Heap].reset(new GrVkHeap(this, GrVkHeap::kSubAlloc_Strategy, 2*1024*1024));
154     fHeaps[kVertexBuffer_Heap].reset(new GrVkHeap(this, GrVkHeap::kSingleAlloc_Strategy, 0));
155     fHeaps[kIndexBuffer_Heap].reset(new GrVkHeap(this, GrVkHeap::kSingleAlloc_Strategy, 0));
156     fHeaps[kUniformBuffer_Heap].reset(new GrVkHeap(this, GrVkHeap::kSubAlloc_Strategy, 256*1024));
157     fHeaps[kTexelBuffer_Heap].reset(new GrVkHeap(this, GrVkHeap::kSingleAlloc_Strategy, 0));
158     fHeaps[kCopyReadBuffer_Heap].reset(new GrVkHeap(this, GrVkHeap::kSingleAlloc_Strategy, 0));
159     fHeaps[kCopyWriteBuffer_Heap].reset(new GrVkHeap(this, GrVkHeap::kSubAlloc_Strategy, 16*1024*1024));
160 }
161 
destroyResources()162 void GrVkGpu::destroyResources() {
163     if (fCurrentCmdBuffer) {
164         fCurrentCmdBuffer->end(this);
165         fCurrentCmdBuffer->unref(this);
166     }
167 
168     // wait for all commands to finish
169     fResourceProvider.checkCommandBuffers();
170     VkResult res = VK_CALL(QueueWaitIdle(fQueue));
171 
172     // On windows, sometimes calls to QueueWaitIdle return before actually signalling the fences
173     // on the command buffers even though they have completed. This causes an assert to fire when
174     // destroying the command buffers. Currently this ony seems to happen on windows, so we add a
175     // sleep to make sure the fence signals.
176 #ifdef SK_DEBUG
177     if (this->vkCaps().mustSleepOnTearDown()) {
178 #if defined(SK_BUILD_FOR_WIN)
179         Sleep(10); // In milliseconds
180 #else
181         sleep(1);  // In seconds
182 #endif
183     }
184 #endif
185 
186 #ifdef SK_DEBUG
187     SkASSERT(VK_SUCCESS == res || VK_ERROR_DEVICE_LOST == res);
188 #endif
189 
190     for (int i = 0; i < fSemaphoresToWaitOn.count(); ++i) {
191         fSemaphoresToWaitOn[i]->unref(this);
192     }
193     fSemaphoresToWaitOn.reset();
194 
195     for (int i = 0; i < fSemaphoresToSignal.count(); ++i) {
196         fSemaphoresToSignal[i]->unref(this);
197     }
198     fSemaphoresToSignal.reset();
199 
200 
201     fCopyManager.destroyResources(this);
202 
203     // must call this just before we destroy the command pool and VkDevice
204     fResourceProvider.destroyResources(VK_ERROR_DEVICE_LOST == res);
205 
206     if (fCmdPool != VK_NULL_HANDLE) {
207         VK_CALL(DestroyCommandPool(fDevice, fCmdPool, nullptr));
208     }
209 
210 #ifdef SK_ENABLE_VK_LAYERS
211     if (fCallback) {
212         VK_CALL(DestroyDebugReportCallbackEXT(fBackendContext->fInstance, fCallback, nullptr));
213     }
214 #endif
215 
216 }
217 
~GrVkGpu()218 GrVkGpu::~GrVkGpu() {
219     if (!fDisconnected) {
220         this->destroyResources();
221     }
222     delete fCompiler;
223 }
224 
225 
disconnect(DisconnectType type)226 void GrVkGpu::disconnect(DisconnectType type) {
227     INHERITED::disconnect(type);
228     if (!fDisconnected) {
229         if (DisconnectType::kCleanup == type) {
230             this->destroyResources();
231         } else {
232             fCurrentCmdBuffer->unrefAndAbandon();
233             for (int i = 0; i < fSemaphoresToWaitOn.count(); ++i) {
234                 fSemaphoresToWaitOn[i]->unrefAndAbandon();
235             }
236             for (int i = 0; i < fSemaphoresToSignal.count(); ++i) {
237                 fSemaphoresToSignal[i]->unrefAndAbandon();
238             }
239             fCopyManager.abandonResources();
240 
241             // must call this just before we destroy the command pool and VkDevice
242             fResourceProvider.abandonResources();
243         }
244         fSemaphoresToWaitOn.reset();
245         fSemaphoresToSignal.reset();
246 #ifdef SK_ENABLE_VK_LAYERS
247         fCallback = VK_NULL_HANDLE;
248 #endif
249         fCurrentCmdBuffer = nullptr;
250         fCmdPool = VK_NULL_HANDLE;
251         fDisconnected = true;
252     }
253 }
254 
255 ///////////////////////////////////////////////////////////////////////////////
256 
createCommandBuffer(const GrGpuCommandBuffer::LoadAndStoreInfo & colorInfo,const GrGpuCommandBuffer::LoadAndStoreInfo & stencilInfo)257 GrGpuCommandBuffer* GrVkGpu::createCommandBuffer(
258             const GrGpuCommandBuffer::LoadAndStoreInfo& colorInfo,
259             const GrGpuCommandBuffer::LoadAndStoreInfo& stencilInfo) {
260     return new GrVkGpuCommandBuffer(this, colorInfo, stencilInfo);
261 }
262 
submitCommandBuffer(SyncQueue sync)263 void GrVkGpu::submitCommandBuffer(SyncQueue sync) {
264     SkASSERT(fCurrentCmdBuffer);
265     fCurrentCmdBuffer->end(this);
266 
267     fCurrentCmdBuffer->submitToQueue(this, fQueue, sync, fSemaphoresToSignal, fSemaphoresToWaitOn);
268 
269     for (int i = 0; i < fSemaphoresToWaitOn.count(); ++i) {
270         fSemaphoresToWaitOn[i]->unref(this);
271     }
272     fSemaphoresToWaitOn.reset();
273     for (int i = 0; i < fSemaphoresToSignal.count(); ++i) {
274         fSemaphoresToSignal[i]->unref(this);
275     }
276     fSemaphoresToSignal.reset();
277 
278     fResourceProvider.checkCommandBuffers();
279 
280     // Release old command buffer and create a new one
281     fCurrentCmdBuffer->unref(this);
282     fCurrentCmdBuffer = fResourceProvider.findOrCreatePrimaryCommandBuffer();
283     SkASSERT(fCurrentCmdBuffer);
284 
285     fCurrentCmdBuffer->begin(this);
286 }
287 
288 ///////////////////////////////////////////////////////////////////////////////
onCreateBuffer(size_t size,GrBufferType type,GrAccessPattern accessPattern,const void * data)289 GrBuffer* GrVkGpu::onCreateBuffer(size_t size, GrBufferType type, GrAccessPattern accessPattern,
290                                   const void* data) {
291     GrBuffer* buff;
292     switch (type) {
293         case kVertex_GrBufferType:
294             SkASSERT(kDynamic_GrAccessPattern == accessPattern ||
295                      kStatic_GrAccessPattern == accessPattern);
296             buff = GrVkVertexBuffer::Create(this, size, kDynamic_GrAccessPattern == accessPattern);
297             break;
298         case kIndex_GrBufferType:
299             SkASSERT(kDynamic_GrAccessPattern == accessPattern ||
300                      kStatic_GrAccessPattern == accessPattern);
301             buff = GrVkIndexBuffer::Create(this, size, kDynamic_GrAccessPattern == accessPattern);
302             break;
303         case kXferCpuToGpu_GrBufferType:
304             SkASSERT(kDynamic_GrAccessPattern == accessPattern ||
305                      kStream_GrAccessPattern == accessPattern);
306             buff = GrVkTransferBuffer::Create(this, size, GrVkBuffer::kCopyRead_Type);
307             break;
308         case kXferGpuToCpu_GrBufferType:
309             SkASSERT(kDynamic_GrAccessPattern == accessPattern ||
310                      kStream_GrAccessPattern == accessPattern);
311             buff = GrVkTransferBuffer::Create(this, size, GrVkBuffer::kCopyWrite_Type);
312             break;
313         case kTexel_GrBufferType:
314             SkASSERT(kDynamic_GrAccessPattern == accessPattern ||
315                      kStatic_GrAccessPattern == accessPattern);
316             buff = GrVkTexelBuffer::Create(this, size, kDynamic_GrAccessPattern == accessPattern);
317             break;
318         case kDrawIndirect_GrBufferType:
319             SkFAIL("DrawIndirect Buffers not supported  in vulkan backend.");
320             return nullptr;
321         default:
322             SkFAIL("Unknown buffer type.");
323             return nullptr;
324     }
325     if (data && buff) {
326         buff->updateData(data, size);
327     }
328     return buff;
329 }
330 
331 ////////////////////////////////////////////////////////////////////////////////
onGetWritePixelsInfo(GrSurface * dstSurface,int width,int height,GrPixelConfig srcConfig,DrawPreference * drawPreference,WritePixelTempDrawInfo * tempDrawInfo)332 bool GrVkGpu::onGetWritePixelsInfo(GrSurface* dstSurface, int width, int height,
333                                    GrPixelConfig srcConfig, DrawPreference* drawPreference,
334                                    WritePixelTempDrawInfo* tempDrawInfo) {
335     GrRenderTarget* renderTarget = dstSurface->asRenderTarget();
336 
337     // Start off assuming no swizzling
338     tempDrawInfo->fSwizzle = GrSwizzle::RGBA();
339     tempDrawInfo->fWriteConfig = srcConfig;
340 
341     // These settings we will always want if a temp draw is performed. Initially set the config
342     // to srcConfig, though that may be modified if we decide to do a R/B swap
343     tempDrawInfo->fTempSurfaceDesc.fFlags = kNone_GrSurfaceFlags;
344     tempDrawInfo->fTempSurfaceDesc.fConfig = srcConfig;
345     tempDrawInfo->fTempSurfaceDesc.fWidth = width;
346     tempDrawInfo->fTempSurfaceDesc.fHeight = height;
347     tempDrawInfo->fTempSurfaceDesc.fSampleCnt = 0;
348     tempDrawInfo->fTempSurfaceDesc.fOrigin = kTopLeft_GrSurfaceOrigin;
349 
350     if (dstSurface->config() == srcConfig) {
351         // We only support writing pixels to textures. Forcing a draw lets us write to pure RTs.
352         if (!dstSurface->asTexture()) {
353             ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
354         }
355         // If the dst is MSAA, we have to draw, or we'll just be writing to the resolve target.
356         if (renderTarget && renderTarget->numColorSamples() > 1) {
357             ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
358         }
359         return true;
360     }
361 
362     // Any config change requires a draw
363     ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
364 
365     bool configsAreRBSwaps = GrPixelConfigSwapRAndB(srcConfig) == dstSurface->config();
366 
367     if (!this->vkCaps().isConfigTexturable(srcConfig) && configsAreRBSwaps) {
368         tempDrawInfo->fTempSurfaceDesc.fConfig = dstSurface->config();
369         tempDrawInfo->fSwizzle = GrSwizzle::BGRA();
370         tempDrawInfo->fWriteConfig = dstSurface->config();
371     }
372     return true;
373 }
374 
onWritePixels(GrSurface * surface,int left,int top,int width,int height,GrPixelConfig config,const GrMipLevel texels[],int mipLevelCount)375 bool GrVkGpu::onWritePixels(GrSurface* surface,
376                             int left, int top, int width, int height,
377                             GrPixelConfig config,
378                             const GrMipLevel texels[], int mipLevelCount) {
379     GrVkTexture* vkTex = static_cast<GrVkTexture*>(surface->asTexture());
380     if (!vkTex) {
381         return false;
382     }
383 
384     // Make sure we have at least the base level
385     if (!mipLevelCount || !texels[0].fPixels) {
386         return false;
387     }
388 
389     // We assume Vulkan doesn't do sRGB <-> linear conversions when reading and writing pixels.
390     if (GrPixelConfigIsSRGB(surface->config()) != GrPixelConfigIsSRGB(config)) {
391         return false;
392     }
393 
394     bool success = false;
395     bool linearTiling = vkTex->isLinearTiled();
396     if (linearTiling) {
397         if (mipLevelCount > 1) {
398             SkDebugf("Can't upload mipmap data to linear tiled texture");
399             return false;
400         }
401         if (VK_IMAGE_LAYOUT_PREINITIALIZED != vkTex->currentLayout()) {
402             // Need to change the layout to general in order to perform a host write
403             vkTex->setImageLayout(this,
404                                   VK_IMAGE_LAYOUT_GENERAL,
405                                   VK_ACCESS_HOST_WRITE_BIT,
406                                   VK_PIPELINE_STAGE_HOST_BIT,
407                                   false);
408             this->submitCommandBuffer(kForce_SyncQueue);
409         }
410         success = this->uploadTexDataLinear(vkTex, left, top, width, height, config,
411                                             texels[0].fPixels, texels[0].fRowBytes);
412     } else {
413         int currentMipLevels = vkTex->texturePriv().maxMipMapLevel() + 1;
414         if (mipLevelCount > currentMipLevels) {
415             if (!vkTex->reallocForMipmap(this, mipLevelCount)) {
416                 return false;
417             }
418         }
419         success = this->uploadTexDataOptimal(vkTex, left, top, width, height, config,
420                                              texels, mipLevelCount);
421     }
422 
423     return success;
424 }
425 
onTransferPixels(GrTexture * texture,int left,int top,int width,int height,GrPixelConfig config,GrBuffer * transferBuffer,size_t bufferOffset,size_t rowBytes)426 bool GrVkGpu::onTransferPixels(GrTexture* texture,
427                                int left, int top, int width, int height,
428                                GrPixelConfig config, GrBuffer* transferBuffer,
429                                size_t bufferOffset, size_t rowBytes) {
430     // Vulkan only supports 4-byte aligned offsets
431     if (SkToBool(bufferOffset & 0x2)) {
432         return false;
433     }
434     GrVkTexture* vkTex = static_cast<GrVkTexture*>(texture);
435     if (!vkTex) {
436         return false;
437     }
438     GrVkTransferBuffer* vkBuffer = static_cast<GrVkTransferBuffer*>(transferBuffer);
439     if (!vkBuffer) {
440         return false;
441     }
442 
443     // We assume Vulkan doesn't do sRGB <-> linear conversions when reading and writing pixels.
444     if (GrPixelConfigIsSRGB(texture->config()) != GrPixelConfigIsSRGB(config)) {
445         return false;
446     }
447 
448     SkDEBUGCODE(
449         SkIRect subRect = SkIRect::MakeXYWH(left, top, width, height);
450         SkIRect bounds = SkIRect::MakeWH(texture->width(), texture->height());
451         SkASSERT(bounds.contains(subRect));
452     )
453     size_t bpp = GrBytesPerPixel(config);
454     if (rowBytes == 0) {
455         rowBytes = bpp*width;
456     }
457 
458     // Set up copy region
459     VkBufferImageCopy region;
460     memset(&region, 0, sizeof(VkBufferImageCopy));
461     region.bufferOffset = bufferOffset;
462     region.bufferRowLength = (uint32_t)(rowBytes/bpp);
463     region.bufferImageHeight = 0;
464     region.imageSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
465     region.imageOffset = { left, top, 0 };
466     region.imageExtent = { (uint32_t)width, (uint32_t)height, 1 };
467 
468     // Change layout of our target so it can be copied to
469     vkTex->setImageLayout(this,
470                           VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
471                           VK_ACCESS_TRANSFER_WRITE_BIT,
472                           VK_PIPELINE_STAGE_TRANSFER_BIT,
473                           false);
474 
475     // Copy the buffer to the image
476     fCurrentCmdBuffer->copyBufferToImage(this,
477                                          vkBuffer,
478                                          vkTex,
479                                          VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
480                                          1,
481                                          &region);
482 
483     vkTex->texturePriv().dirtyMipMaps(true);
484     return true;
485 }
486 
resolveImage(GrSurface * dst,GrVkRenderTarget * src,const SkIRect & srcRect,const SkIPoint & dstPoint)487 void GrVkGpu::resolveImage(GrSurface* dst, GrVkRenderTarget* src, const SkIRect& srcRect,
488                            const SkIPoint& dstPoint) {
489     SkASSERT(dst);
490     SkASSERT(src && src->numColorSamples() > 1 && src->msaaImage());
491 
492     if (this->vkCaps().mustSubmitCommandsBeforeCopyOp()) {
493         this->submitCommandBuffer(GrVkGpu::kSkip_SyncQueue);
494     }
495 
496     // Flip rect if necessary
497     SkIRect srcVkRect = srcRect;
498     int32_t dstY = dstPoint.fY;
499 
500     if (kBottomLeft_GrSurfaceOrigin == src->origin()) {
501         SkASSERT(kBottomLeft_GrSurfaceOrigin == dst->origin());
502         srcVkRect.fTop = src->height() - srcRect.fBottom;
503         srcVkRect.fBottom = src->height() - srcRect.fTop;
504         dstY = dst->height() - dstPoint.fY - srcVkRect.height();
505     }
506 
507     VkImageResolve resolveInfo;
508     resolveInfo.srcSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
509     resolveInfo.srcOffset = { srcVkRect.fLeft, srcVkRect.fTop, 0 };
510     resolveInfo.dstSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
511     resolveInfo.dstOffset = { dstPoint.fX, dstY, 0 };
512     resolveInfo.extent = { (uint32_t)srcVkRect.width(), (uint32_t)srcVkRect.height(), 1 };
513 
514     GrVkImage* dstImage;
515     GrRenderTarget* dstRT = dst->asRenderTarget();
516     if (dstRT) {
517         GrVkRenderTarget* vkRT = static_cast<GrVkRenderTarget*>(dstRT);
518         dstImage = vkRT;
519     } else {
520         SkASSERT(dst->asTexture());
521         dstImage = static_cast<GrVkTexture*>(dst->asTexture());
522     }
523     dstImage->setImageLayout(this,
524                              VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
525                              VK_ACCESS_TRANSFER_WRITE_BIT,
526                              VK_PIPELINE_STAGE_TRANSFER_BIT,
527                              false);
528 
529     src->msaaImage()->setImageLayout(this,
530                                      VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
531                                      VK_ACCESS_TRANSFER_READ_BIT,
532                                      VK_PIPELINE_STAGE_TRANSFER_BIT,
533                                      false);
534 
535     fCurrentCmdBuffer->resolveImage(this, *src->msaaImage(), *dstImage, 1, &resolveInfo);
536 }
537 
internalResolveRenderTarget(GrRenderTarget * target,bool requiresSubmit)538 void GrVkGpu::internalResolveRenderTarget(GrRenderTarget* target, bool requiresSubmit) {
539     if (target->needsResolve()) {
540         SkASSERT(target->numColorSamples() > 1);
541         GrVkRenderTarget* rt = static_cast<GrVkRenderTarget*>(target);
542         SkASSERT(rt->msaaImage());
543 
544         const SkIRect& srcRect = rt->getResolveRect();
545 
546         this->resolveImage(target, rt, srcRect, SkIPoint::Make(srcRect.fLeft, srcRect.fTop));
547 
548         rt->flagAsResolved();
549 
550         if (requiresSubmit) {
551             this->submitCommandBuffer(kSkip_SyncQueue);
552         }
553     }
554 }
555 
uploadTexDataLinear(GrVkTexture * tex,int left,int top,int width,int height,GrPixelConfig dataConfig,const void * data,size_t rowBytes)556 bool GrVkGpu::uploadTexDataLinear(GrVkTexture* tex,
557                                   int left, int top, int width, int height,
558                                   GrPixelConfig dataConfig,
559                                   const void* data,
560                                   size_t rowBytes) {
561     SkASSERT(data);
562     SkASSERT(tex->isLinearTiled());
563 
564     SkDEBUGCODE(
565         SkIRect subRect = SkIRect::MakeXYWH(left, top, width, height);
566         SkIRect bounds = SkIRect::MakeWH(tex->width(), tex->height());
567         SkASSERT(bounds.contains(subRect));
568     )
569     size_t bpp = GrBytesPerPixel(dataConfig);
570     size_t trimRowBytes = width * bpp;
571     if (!rowBytes) {
572         rowBytes = trimRowBytes;
573     }
574 
575     SkASSERT(VK_IMAGE_LAYOUT_PREINITIALIZED == tex->currentLayout() ||
576              VK_IMAGE_LAYOUT_GENERAL == tex->currentLayout());
577     const VkImageSubresource subres = {
578         VK_IMAGE_ASPECT_COLOR_BIT,
579         0,  // mipLevel
580         0,  // arraySlice
581     };
582     VkSubresourceLayout layout;
583     VkResult err;
584 
585     const GrVkInterface* interface = this->vkInterface();
586 
587     GR_VK_CALL(interface, GetImageSubresourceLayout(fDevice,
588                                                     tex->image(),
589                                                     &subres,
590                                                     &layout));
591 
592     int texTop = kBottomLeft_GrSurfaceOrigin == tex->origin() ? tex->height() - top - height : top;
593     const GrVkAlloc& alloc = tex->alloc();
594     VkDeviceSize offset = alloc.fOffset + texTop*layout.rowPitch + left*bpp;
595     VkDeviceSize size = height*layout.rowPitch;
596     void* mapPtr;
597     err = GR_VK_CALL(interface, MapMemory(fDevice, alloc.fMemory, offset, size, 0, &mapPtr));
598     if (err) {
599         return false;
600     }
601 
602     if (kBottomLeft_GrSurfaceOrigin == tex->origin()) {
603         // copy into buffer by rows
604         const char* srcRow = reinterpret_cast<const char*>(data);
605         char* dstRow = reinterpret_cast<char*>(mapPtr)+(height - 1)*layout.rowPitch;
606         for (int y = 0; y < height; y++) {
607             memcpy(dstRow, srcRow, trimRowBytes);
608             srcRow += rowBytes;
609             dstRow -= layout.rowPitch;
610         }
611     } else {
612         SkRectMemcpy(mapPtr, static_cast<size_t>(layout.rowPitch), data, rowBytes, trimRowBytes,
613                      height);
614     }
615 
616     GrVkMemory::FlushMappedAlloc(this, alloc);
617     GR_VK_CALL(interface, UnmapMemory(fDevice, alloc.fMemory));
618 
619     return true;
620 }
621 
uploadTexDataOptimal(GrVkTexture * tex,int left,int top,int width,int height,GrPixelConfig dataConfig,const GrMipLevel texels[],int mipLevelCount)622 bool GrVkGpu::uploadTexDataOptimal(GrVkTexture* tex,
623                                    int left, int top, int width, int height,
624                                    GrPixelConfig dataConfig,
625                                    const GrMipLevel texels[], int mipLevelCount) {
626     SkASSERT(!tex->isLinearTiled());
627     // The assumption is either that we have no mipmaps, or that our rect is the entire texture
628     SkASSERT(1 == mipLevelCount ||
629              (0 == left && 0 == top && width == tex->width() && height == tex->height()));
630 
631     // We assume that if the texture has mip levels, we either upload to all the levels or just the
632     // first.
633     SkASSERT(1 == mipLevelCount || mipLevelCount == (tex->texturePriv().maxMipMapLevel() + 1));
634 
635     if (width == 0 || height == 0) {
636         return false;
637     }
638 
639     SkASSERT(this->caps()->isConfigTexturable(tex->config()));
640     size_t bpp = GrBytesPerPixel(dataConfig);
641 
642     // texels is const.
643     // But we may need to adjust the fPixels ptr based on the copyRect, or fRowBytes.
644     // Because of this we need to make a non-const shallow copy of texels.
645     SkAutoTMalloc<GrMipLevel> texelsShallowCopy;
646 
647     if (mipLevelCount) {
648         texelsShallowCopy.reset(mipLevelCount);
649         memcpy(texelsShallowCopy.get(), texels, mipLevelCount*sizeof(GrMipLevel));
650     }
651 
652     for (int currentMipLevel = 0; currentMipLevel < mipLevelCount; ++currentMipLevel) {
653         SkASSERT(texelsShallowCopy[currentMipLevel].fPixels);
654     }
655 
656     // Determine whether we need to flip when we copy into the buffer
657     bool flipY = (kBottomLeft_GrSurfaceOrigin == tex->origin() && mipLevelCount);
658 
659     SkTArray<size_t> individualMipOffsets(mipLevelCount);
660     individualMipOffsets.push_back(0);
661     size_t combinedBufferSize = width * bpp * height;
662     int currentWidth = width;
663     int currentHeight = height;
664     // The alignment must be at least 4 bytes and a multiple of the bytes per pixel of the image
665     // config. This works with the assumption that the bytes in pixel config is always a power of 2.
666     SkASSERT((bpp & (bpp - 1)) == 0);
667     const size_t alignmentMask = 0x3 | (bpp - 1);
668     for (int currentMipLevel = 1; currentMipLevel < mipLevelCount; currentMipLevel++) {
669         currentWidth = SkTMax(1, currentWidth/2);
670         currentHeight = SkTMax(1, currentHeight/2);
671 
672         const size_t trimmedSize = currentWidth * bpp * currentHeight;
673         const size_t alignmentDiff = combinedBufferSize & alignmentMask;
674         if (alignmentDiff != 0) {
675            combinedBufferSize += alignmentMask - alignmentDiff + 1;
676         }
677         individualMipOffsets.push_back(combinedBufferSize);
678         combinedBufferSize += trimmedSize;
679     }
680 
681     // allocate buffer to hold our mip data
682     GrVkTransferBuffer* transferBuffer =
683                    GrVkTransferBuffer::Create(this, combinedBufferSize, GrVkBuffer::kCopyRead_Type);
684     if(!transferBuffer)
685         return false;
686 
687     char* buffer = (char*) transferBuffer->map();
688     SkTArray<VkBufferImageCopy> regions(mipLevelCount);
689 
690     currentWidth = width;
691     currentHeight = height;
692     int layerHeight = tex->height();
693     for (int currentMipLevel = 0; currentMipLevel < mipLevelCount; currentMipLevel++) {
694         SkASSERT(1 == mipLevelCount || currentHeight == layerHeight);
695         const size_t trimRowBytes = currentWidth * bpp;
696         const size_t rowBytes = texelsShallowCopy[currentMipLevel].fRowBytes ?
697                                 texelsShallowCopy[currentMipLevel].fRowBytes :
698                                 trimRowBytes;
699 
700         // copy data into the buffer, skipping the trailing bytes
701         char* dst = buffer + individualMipOffsets[currentMipLevel];
702         const char* src = (const char*)texelsShallowCopy[currentMipLevel].fPixels;
703         if (flipY) {
704             src += (currentHeight - 1) * rowBytes;
705             for (int y = 0; y < currentHeight; y++) {
706                 memcpy(dst, src, trimRowBytes);
707                 src -= rowBytes;
708                 dst += trimRowBytes;
709             }
710         } else {
711             SkRectMemcpy(dst, trimRowBytes, src, rowBytes, trimRowBytes, currentHeight);
712         }
713 
714         VkBufferImageCopy& region = regions.push_back();
715         memset(&region, 0, sizeof(VkBufferImageCopy));
716         region.bufferOffset = transferBuffer->offset() + individualMipOffsets[currentMipLevel];
717         region.bufferRowLength = currentWidth;
718         region.bufferImageHeight = currentHeight;
719         region.imageSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, SkToU32(currentMipLevel), 0, 1 };
720         region.imageOffset = { left, flipY ? layerHeight - top - currentHeight : top, 0 };
721         region.imageExtent = { (uint32_t)currentWidth, (uint32_t)currentHeight, 1 };
722 
723         currentWidth = SkTMax(1, currentWidth/2);
724         currentHeight = SkTMax(1, currentHeight/2);
725         layerHeight = currentHeight;
726     }
727 
728     // no need to flush non-coherent memory, unmap will do that for us
729     transferBuffer->unmap();
730 
731     // Change layout of our target so it can be copied to
732     tex->setImageLayout(this,
733                         VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
734                         VK_ACCESS_TRANSFER_WRITE_BIT,
735                         VK_PIPELINE_STAGE_TRANSFER_BIT,
736                         false);
737 
738     // Copy the buffer to the image
739     fCurrentCmdBuffer->copyBufferToImage(this,
740                                          transferBuffer,
741                                          tex,
742                                          VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
743                                          regions.count(),
744                                          regions.begin());
745     transferBuffer->unref();
746     if (1 == mipLevelCount) {
747        tex->texturePriv().dirtyMipMaps(true);
748     }
749 
750     return true;
751 }
752 
753 ////////////////////////////////////////////////////////////////////////////////
onCreateTexture(const GrSurfaceDesc & desc,SkBudgeted budgeted,const GrMipLevel texels[],int mipLevelCount)754 sk_sp<GrTexture> GrVkGpu::onCreateTexture(const GrSurfaceDesc& desc, SkBudgeted budgeted,
755                                           const GrMipLevel texels[], int mipLevelCount) {
756     bool renderTarget = SkToBool(desc.fFlags & kRenderTarget_GrSurfaceFlag);
757 
758     VkFormat pixelFormat;
759     if (!GrPixelConfigToVkFormat(desc.fConfig, &pixelFormat)) {
760         return nullptr;
761     }
762 
763     if (!fVkCaps->isConfigTexturable(desc.fConfig)) {
764         return nullptr;
765     }
766 
767     if (renderTarget && !fVkCaps->isConfigRenderable(desc.fConfig, false)) {
768         return nullptr;
769     }
770 
771     VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_SAMPLED_BIT;
772     if (renderTarget) {
773         usageFlags |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
774     }
775 
776     // For now we will set the VK_IMAGE_USAGE_TRANSFER_DESTINATION_BIT and
777     // VK_IMAGE_USAGE_TRANSFER_SOURCE_BIT on every texture since we do not know whether or not we
778     // will be using this texture in some copy or not. Also this assumes, as is the current case,
779     // that all render targets in vulkan are also textures. If we change this practice of setting
780     // both bits, we must make sure to set the destination bit if we are uploading srcData to the
781     // texture.
782     usageFlags |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
783 
784     // This ImageDesc refers to the texture that will be read by the client. Thus even if msaa is
785     // requested, this ImageDesc describes the resolved texture. Therefore we always have samples set
786     // to 1.
787     int mipLevels = !mipLevelCount ? 1 : mipLevelCount;
788     GrVkImage::ImageDesc imageDesc;
789     imageDesc.fImageType = VK_IMAGE_TYPE_2D;
790     imageDesc.fFormat = pixelFormat;
791     imageDesc.fWidth = desc.fWidth;
792     imageDesc.fHeight = desc.fHeight;
793     imageDesc.fLevels = mipLevels;
794     imageDesc.fSamples = 1;
795     imageDesc.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
796     imageDesc.fUsageFlags = usageFlags;
797     imageDesc.fMemProps = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
798 
799     sk_sp<GrVkTexture> tex;
800     if (renderTarget) {
801         tex = GrVkTextureRenderTarget::CreateNewTextureRenderTarget(this, budgeted, desc,
802                                                                     imageDesc);
803     } else {
804         tex = GrVkTexture::CreateNewTexture(this, budgeted, desc, imageDesc);
805     }
806 
807     if (!tex) {
808         return nullptr;
809     }
810 
811     if (mipLevelCount) {
812         SkASSERT(texels[0].fPixels);
813         if (!this->uploadTexDataOptimal(tex.get(), 0, 0, desc.fWidth, desc.fHeight, desc.fConfig,
814                                         texels, mipLevelCount)) {
815             tex->unref();
816             return nullptr;
817         }
818     }
819 
820     if (desc.fFlags & kPerformInitialClear_GrSurfaceFlag) {
821         VkClearColorValue zeroClearColor;
822         memset(&zeroClearColor, 0, sizeof(zeroClearColor));
823         VkImageSubresourceRange range;
824         range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
825         range.baseArrayLayer = 0;
826         range.baseMipLevel = 0;
827         range.layerCount = 1;
828         range.levelCount = 1;
829         tex->setImageLayout(this, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
830                             VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, false);
831         this->currentCommandBuffer()->clearColorImage(this, tex.get(), &zeroClearColor, 1, &range);
832     }
833     return tex;
834 }
835 
836 ////////////////////////////////////////////////////////////////////////////////
837 
updateBuffer(GrVkBuffer * buffer,const void * src,VkDeviceSize offset,VkDeviceSize size)838 bool GrVkGpu::updateBuffer(GrVkBuffer* buffer, const void* src,
839                            VkDeviceSize offset, VkDeviceSize size) {
840 
841     // Update the buffer
842     fCurrentCmdBuffer->updateBuffer(this, buffer, offset, size, src);
843 
844     return true;
845 }
846 
847 ////////////////////////////////////////////////////////////////////////////////
848 
resolve_origin(GrSurfaceOrigin origin)849 static GrSurfaceOrigin resolve_origin(GrSurfaceOrigin origin) {
850     // By default, all textures in Vk use TopLeft
851     if (kDefault_GrSurfaceOrigin == origin) {
852         return kTopLeft_GrSurfaceOrigin;
853     } else {
854         return origin;
855     }
856 }
857 
onWrapBackendTexture(const GrBackendTexture & backendTex,GrSurfaceOrigin origin,GrBackendTextureFlags flags,int sampleCnt,GrWrapOwnership ownership)858 sk_sp<GrTexture> GrVkGpu::onWrapBackendTexture(const GrBackendTexture& backendTex,
859                                                GrSurfaceOrigin origin,
860                                                GrBackendTextureFlags flags,
861                                                int sampleCnt,
862                                                GrWrapOwnership ownership) {
863     const GrVkImageInfo* info = backendTex.getVkImageInfo();
864     if (!info) {
865         return nullptr;
866     }
867 
868     int maxSize = this->caps()->maxTextureSize();
869     if (backendTex.width() > maxSize || backendTex.height() > maxSize) {
870         return nullptr;
871     }
872 
873     if (VK_NULL_HANDLE == info->fImage || VK_NULL_HANDLE == info->fAlloc.fMemory) {
874         return nullptr;
875     }
876 
877     SkASSERT(backendTex.config() == GrVkFormatToPixelConfig(info->fFormat));
878 
879     GrSurfaceDesc surfDesc;
880     // next line relies on GrBackendTextureFlags matching GrTexture's
881     surfDesc.fFlags = (GrSurfaceFlags)flags;
882     surfDesc.fWidth = backendTex.width();
883     surfDesc.fHeight = backendTex.height();
884     surfDesc.fConfig = backendTex.config();
885     surfDesc.fSampleCnt = this->caps()->getSampleCount(sampleCnt, backendTex.config());
886     bool renderTarget = SkToBool(flags & kRenderTarget_GrBackendTextureFlag);
887     // In GL, Chrome assumes all textures are BottomLeft
888     // In VK, we don't have this restriction
889     surfDesc.fOrigin = resolve_origin(origin);
890 
891     if (!renderTarget) {
892         return GrVkTexture::MakeWrappedTexture(this, surfDesc, ownership, info);
893     }
894     return GrVkTextureRenderTarget::MakeWrappedTextureRenderTarget(this, surfDesc, ownership, info);
895 }
896 
onWrapBackendRenderTarget(const GrBackendRenderTarget & backendRT,GrSurfaceOrigin origin)897 sk_sp<GrRenderTarget> GrVkGpu::onWrapBackendRenderTarget(const GrBackendRenderTarget& backendRT,
898                                                          GrSurfaceOrigin origin){
899     // Currently the Vulkan backend does not support wrapping of msaa render targets directly. In
900     // general this is not an issue since swapchain images in vulkan are never multisampled. Thus if
901     // you want a multisampled RT it is best to wrap the swapchain images and then let Skia handle
902     // creating and owning the MSAA images.
903     if (backendRT.sampleCnt()) {
904         return nullptr;
905     }
906 
907     const GrVkImageInfo* info = backendRT.getVkImageInfo();
908     if (!info) {
909         return nullptr;
910     }
911     if (VK_NULL_HANDLE == info->fImage) {
912         return nullptr;
913     }
914 
915     GrSurfaceDesc desc;
916     desc.fConfig = backendRT.config();
917     desc.fFlags = kRenderTarget_GrSurfaceFlag;
918     desc.fWidth = backendRT.width();
919     desc.fHeight = backendRT.height();
920     desc.fSampleCnt = 0;
921 
922     SkASSERT(kDefault_GrSurfaceOrigin != origin);
923     desc.fOrigin = origin;
924 
925     sk_sp<GrVkRenderTarget> tgt = GrVkRenderTarget::MakeWrappedRenderTarget(this, desc, info);
926     if (tgt && backendRT.stencilBits()) {
927         if (!createStencilAttachmentForRenderTarget(tgt.get(), desc.fWidth, desc.fHeight)) {
928             return nullptr;
929         }
930     }
931     return tgt;
932 }
933 
onWrapBackendTextureAsRenderTarget(const GrBackendTexture & tex,GrSurfaceOrigin origin,int sampleCnt)934 sk_sp<GrRenderTarget> GrVkGpu::onWrapBackendTextureAsRenderTarget(const GrBackendTexture& tex,
935                                                                   GrSurfaceOrigin origin,
936                                                                   int sampleCnt) {
937 
938     const GrVkImageInfo* info = tex.getVkImageInfo();
939     if (!info) {
940         return nullptr;
941     }
942     if (VK_NULL_HANDLE == info->fImage) {
943         return nullptr;
944     }
945 
946     GrSurfaceDesc desc;
947     desc.fFlags = kRenderTarget_GrSurfaceFlag;
948     desc.fConfig = tex.config();
949     desc.fWidth = tex.width();
950     desc.fHeight = tex.height();
951     desc.fSampleCnt = this->caps()->getSampleCount(sampleCnt, tex.config());
952 
953     desc.fOrigin = resolve_origin(origin);
954 
955     sk_sp<GrVkRenderTarget> tgt = GrVkRenderTarget::MakeWrappedRenderTarget(this, desc, info);
956     return tgt;
957 }
958 
generateMipmap(GrVkTexture * tex)959 void GrVkGpu::generateMipmap(GrVkTexture* tex) {
960     // don't do anything for linearly tiled textures (can't have mipmaps)
961     if (tex->isLinearTiled()) {
962         SkDebugf("Trying to create mipmap for linear tiled texture");
963         return;
964     }
965 
966     // determine if we can blit to and from this format
967     const GrVkCaps& caps = this->vkCaps();
968     if (!caps.configCanBeDstofBlit(tex->config(), false) ||
969         !caps.configCanBeSrcofBlit(tex->config(), false) ||
970         !caps.mipMapSupport()) {
971         return;
972     }
973 
974     if (this->vkCaps().mustSubmitCommandsBeforeCopyOp()) {
975         this->submitCommandBuffer(kSkip_SyncQueue);
976     }
977 
978     // We may need to resolve the texture first if it is also a render target
979     GrVkRenderTarget* texRT = static_cast<GrVkRenderTarget*>(tex->asRenderTarget());
980     if (texRT) {
981         this->internalResolveRenderTarget(texRT, false);
982     }
983 
984     int width = tex->width();
985     int height = tex->height();
986     VkImageBlit blitRegion;
987     memset(&blitRegion, 0, sizeof(VkImageBlit));
988 
989     // SkMipMap doesn't include the base level in the level count so we have to add 1
990     uint32_t levelCount = SkMipMap::ComputeLevelCount(tex->width(), tex->height()) + 1;
991     if (levelCount != tex->mipLevels()) {
992         const GrVkResource* oldResource = tex->resource();
993         oldResource->ref();
994         // grab handle to the original image resource
995         VkImage oldImage = tex->image();
996 
997         // change the original image's layout so we can copy from it
998         tex->setImageLayout(this, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
999                             VK_ACCESS_TRANSFER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, false);
1000 
1001         if (!tex->reallocForMipmap(this, levelCount)) {
1002             oldResource->unref(this);
1003             return;
1004         }
1005         // change the new image's layout so we can blit to it
1006         tex->setImageLayout(this, VK_IMAGE_LAYOUT_GENERAL,
1007                             VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, false);
1008 
1009         // Blit original image to top level of new image
1010         blitRegion.srcSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
1011         blitRegion.srcOffsets[0] = { 0, 0, 0 };
1012         blitRegion.srcOffsets[1] = { width, height, 1 };
1013         blitRegion.dstSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
1014         blitRegion.dstOffsets[0] = { 0, 0, 0 };
1015         blitRegion.dstOffsets[1] = { width, height, 1 };
1016 
1017         fCurrentCmdBuffer->blitImage(this,
1018                                      oldResource,
1019                                      oldImage,
1020                                      VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
1021                                      tex->resource(),
1022                                      tex->image(),
1023                                      VK_IMAGE_LAYOUT_GENERAL,
1024                                      1,
1025                                      &blitRegion,
1026                                      VK_FILTER_LINEAR);
1027 
1028         oldResource->unref(this);
1029     } else {
1030         // change layout of the layers so we can write to them.
1031         tex->setImageLayout(this, VK_IMAGE_LAYOUT_GENERAL,
1032                             VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, false);
1033     }
1034 
1035     // setup memory barrier
1036     SkASSERT(kUnknown_GrPixelConfig != GrVkFormatToPixelConfig(tex->imageFormat()));
1037     VkImageAspectFlags aspectFlags = VK_IMAGE_ASPECT_COLOR_BIT;
1038     VkImageMemoryBarrier imageMemoryBarrier = {
1039         VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,          // sType
1040         NULL,                                            // pNext
1041         VK_ACCESS_TRANSFER_WRITE_BIT,                    // srcAccessMask
1042         VK_ACCESS_TRANSFER_READ_BIT,                     // dstAccessMask
1043         VK_IMAGE_LAYOUT_GENERAL,                         // oldLayout
1044         VK_IMAGE_LAYOUT_GENERAL,                         // newLayout
1045         VK_QUEUE_FAMILY_IGNORED,                         // srcQueueFamilyIndex
1046         VK_QUEUE_FAMILY_IGNORED,                         // dstQueueFamilyIndex
1047         tex->image(),                                    // image
1048         { aspectFlags, 0, 1, 0, 1 }                      // subresourceRange
1049     };
1050 
1051     // Blit the miplevels
1052     uint32_t mipLevel = 1;
1053     while (mipLevel < levelCount) {
1054         int prevWidth = width;
1055         int prevHeight = height;
1056         width = SkTMax(1, width / 2);
1057         height = SkTMax(1, height / 2);
1058 
1059         imageMemoryBarrier.subresourceRange.baseMipLevel = mipLevel - 1;
1060         this->addImageMemoryBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
1061                                     false, &imageMemoryBarrier);
1062 
1063         blitRegion.srcSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, mipLevel - 1, 0, 1 };
1064         blitRegion.srcOffsets[0] = { 0, 0, 0 };
1065         blitRegion.srcOffsets[1] = { prevWidth, prevHeight, 1 };
1066         blitRegion.dstSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, mipLevel, 0, 1 };
1067         blitRegion.dstOffsets[0] = { 0, 0, 0 };
1068         blitRegion.dstOffsets[1] = { width, height, 1 };
1069         fCurrentCmdBuffer->blitImage(this,
1070                                      *tex,
1071                                      *tex,
1072                                      1,
1073                                      &blitRegion,
1074                                      VK_FILTER_LINEAR);
1075         ++mipLevel;
1076     }
1077 }
1078 
1079 ////////////////////////////////////////////////////////////////////////////////
1080 
createStencilAttachmentForRenderTarget(const GrRenderTarget * rt,int width,int height)1081 GrStencilAttachment* GrVkGpu::createStencilAttachmentForRenderTarget(const GrRenderTarget* rt,
1082                                                                      int width,
1083                                                                      int height) {
1084     SkASSERT(width >= rt->width());
1085     SkASSERT(height >= rt->height());
1086 
1087     int samples = rt->numStencilSamples();
1088 
1089     const GrVkCaps::StencilFormat& sFmt = this->vkCaps().preferedStencilFormat();
1090 
1091     GrVkStencilAttachment* stencil(GrVkStencilAttachment::Create(this,
1092                                                                  width,
1093                                                                  height,
1094                                                                  samples,
1095                                                                  sFmt));
1096     fStats.incStencilAttachmentCreates();
1097     return stencil;
1098 }
1099 
1100 ////////////////////////////////////////////////////////////////////////////////
1101 
copy_testing_data(GrVkGpu * gpu,void * srcData,const GrVkAlloc & alloc,size_t srcRowBytes,size_t dstRowBytes,int h)1102 bool copy_testing_data(GrVkGpu* gpu, void* srcData, const GrVkAlloc& alloc,
1103                        size_t srcRowBytes, size_t dstRowBytes, int h) {
1104     void* mapPtr;
1105     VkResult err = GR_VK_CALL(gpu->vkInterface(), MapMemory(gpu->device(),
1106                                                             alloc.fMemory,
1107                                                             alloc.fOffset,
1108                                                             dstRowBytes * h,
1109                                                             0,
1110                                                             &mapPtr));
1111     if (err) {
1112         return false;
1113     }
1114 
1115     if (srcData) {
1116         // If there is no padding on dst we can do a single memcopy.
1117         // This assumes the srcData comes in with no padding.
1118         SkRectMemcpy(mapPtr, static_cast<size_t>(dstRowBytes),
1119                      srcData, srcRowBytes, srcRowBytes, h);
1120     } else {
1121         // If there is no srcdata we always copy 0's into the textures so that it is initialized
1122         // with some data.
1123         if (srcRowBytes == static_cast<size_t>(dstRowBytes)) {
1124             memset(mapPtr, 0, srcRowBytes * h);
1125         } else {
1126             for (int i = 0; i < h; ++i) {
1127                 memset(mapPtr, 0, srcRowBytes);
1128                 mapPtr = SkTAddOffset<void>(mapPtr, static_cast<size_t>(dstRowBytes));
1129             }
1130         }
1131     }
1132     GrVkMemory::FlushMappedAlloc(gpu, alloc);
1133     GR_VK_CALL(gpu->vkInterface(), UnmapMemory(gpu->device(), alloc.fMemory));
1134     return true;
1135 }
1136 
createTestingOnlyBackendTexture(void * srcData,int w,int h,GrPixelConfig config,bool isRenderTarget)1137 GrBackendObject GrVkGpu::createTestingOnlyBackendTexture(void* srcData, int w, int h,
1138                                                          GrPixelConfig config,
1139                                                          bool isRenderTarget) {
1140 
1141     VkFormat pixelFormat;
1142     if (!GrPixelConfigToVkFormat(config, &pixelFormat)) {
1143         return 0;
1144     }
1145 
1146     bool linearTiling = false;
1147     if (!fVkCaps->isConfigTexturable(config)) {
1148         return 0;
1149     }
1150 
1151     if (isRenderTarget && !fVkCaps->isConfigRenderable(config, false)) {
1152         return 0;
1153     }
1154 
1155     if (fVkCaps->isConfigTexturableLinearly(config) &&
1156         (!isRenderTarget || fVkCaps->isConfigRenderableLinearly(config, false))) {
1157         linearTiling = true;
1158     }
1159 
1160     VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_SAMPLED_BIT;
1161     usageFlags |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
1162     usageFlags |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
1163     if (isRenderTarget) {
1164         usageFlags |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
1165     }
1166 
1167     VkImage image = VK_NULL_HANDLE;
1168     GrVkAlloc alloc = { VK_NULL_HANDLE, 0, 0, 0 };
1169 
1170     VkImageTiling imageTiling = linearTiling ? VK_IMAGE_TILING_LINEAR : VK_IMAGE_TILING_OPTIMAL;
1171     VkImageLayout initialLayout = (VK_IMAGE_TILING_LINEAR == imageTiling)
1172                                 ? VK_IMAGE_LAYOUT_PREINITIALIZED
1173                                 : VK_IMAGE_LAYOUT_UNDEFINED;
1174 
1175     // Create Image
1176     VkSampleCountFlagBits vkSamples;
1177     if (!GrSampleCountToVkSampleCount(1, &vkSamples)) {
1178         return 0;
1179     }
1180 
1181     const VkImageCreateInfo imageCreateInfo = {
1182         VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,         // sType
1183         NULL,                                        // pNext
1184         0,                                           // VkImageCreateFlags
1185         VK_IMAGE_TYPE_2D,                            // VkImageType
1186         pixelFormat,                                 // VkFormat
1187         { (uint32_t) w, (uint32_t) h, 1 },           // VkExtent3D
1188         1,                                           // mipLevels
1189         1,                                           // arrayLayers
1190         vkSamples,                                   // samples
1191         imageTiling,                                 // VkImageTiling
1192         usageFlags,                                  // VkImageUsageFlags
1193         VK_SHARING_MODE_EXCLUSIVE,                   // VkSharingMode
1194         0,                                           // queueFamilyCount
1195         0,                                           // pQueueFamilyIndices
1196         initialLayout                                // initialLayout
1197     };
1198 
1199     GR_VK_CALL_ERRCHECK(this->vkInterface(), CreateImage(this->device(), &imageCreateInfo, nullptr, &image));
1200 
1201     if (!GrVkMemory::AllocAndBindImageMemory(this, image, linearTiling, &alloc)) {
1202         VK_CALL(DestroyImage(this->device(), image, nullptr));
1203         return 0;
1204     }
1205 
1206     size_t bpp = GrBytesPerPixel(config);
1207     size_t rowCopyBytes = bpp * w;
1208     if (linearTiling) {
1209         const VkImageSubresource subres = {
1210             VK_IMAGE_ASPECT_COLOR_BIT,
1211             0,  // mipLevel
1212             0,  // arraySlice
1213         };
1214         VkSubresourceLayout layout;
1215 
1216         VK_CALL(GetImageSubresourceLayout(fDevice, image, &subres, &layout));
1217 
1218         if (!copy_testing_data(this, srcData, alloc, rowCopyBytes,
1219                                static_cast<size_t>(layout.rowPitch), h)) {
1220             GrVkMemory::FreeImageMemory(this, linearTiling, alloc);
1221             VK_CALL(DestroyImage(fDevice, image, nullptr));
1222             return 0;
1223         }
1224     } else {
1225         SkASSERT(w && h);
1226 
1227         VkBuffer buffer;
1228         VkBufferCreateInfo bufInfo;
1229         memset(&bufInfo, 0, sizeof(VkBufferCreateInfo));
1230         bufInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
1231         bufInfo.flags = 0;
1232         bufInfo.size = rowCopyBytes * h;
1233         bufInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
1234         bufInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
1235         bufInfo.queueFamilyIndexCount = 0;
1236         bufInfo.pQueueFamilyIndices = nullptr;
1237         VkResult err;
1238         err = VK_CALL(CreateBuffer(fDevice, &bufInfo, nullptr, &buffer));
1239 
1240         if (err) {
1241             GrVkMemory::FreeImageMemory(this, linearTiling, alloc);
1242             VK_CALL(DestroyImage(fDevice, image, nullptr));
1243             return 0;
1244         }
1245 
1246         GrVkAlloc bufferAlloc = { VK_NULL_HANDLE, 0, 0, 0 };
1247         if (!GrVkMemory::AllocAndBindBufferMemory(this, buffer, GrVkBuffer::kCopyRead_Type,
1248                                                   true, &bufferAlloc)) {
1249             GrVkMemory::FreeImageMemory(this, linearTiling, alloc);
1250             VK_CALL(DestroyImage(fDevice, image, nullptr));
1251             VK_CALL(DestroyBuffer(fDevice, buffer, nullptr));
1252             return 0;
1253         }
1254 
1255         if (!copy_testing_data(this, srcData, bufferAlloc, rowCopyBytes, rowCopyBytes, h)) {
1256             GrVkMemory::FreeImageMemory(this, linearTiling, alloc);
1257             VK_CALL(DestroyImage(fDevice, image, nullptr));
1258             GrVkMemory::FreeBufferMemory(this, GrVkBuffer::kCopyRead_Type, bufferAlloc);
1259             VK_CALL(DestroyBuffer(fDevice, buffer, nullptr));
1260             return 0;
1261         }
1262 
1263         const VkCommandBufferAllocateInfo cmdInfo = {
1264             VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,   // sType
1265             NULL,                                             // pNext
1266             fCmdPool,                                         // commandPool
1267             VK_COMMAND_BUFFER_LEVEL_PRIMARY,                  // level
1268             1                                                 // bufferCount
1269         };
1270 
1271         VkCommandBuffer cmdBuffer;
1272         err = VK_CALL(AllocateCommandBuffers(fDevice, &cmdInfo, &cmdBuffer));
1273         if (err) {
1274             GrVkMemory::FreeImageMemory(this, linearTiling, alloc);
1275             VK_CALL(DestroyImage(fDevice, image, nullptr));
1276             GrVkMemory::FreeBufferMemory(this, GrVkBuffer::kCopyRead_Type, bufferAlloc);
1277             VK_CALL(DestroyBuffer(fDevice, buffer, nullptr));
1278             return 0;
1279         }
1280 
1281         VkCommandBufferBeginInfo cmdBufferBeginInfo;
1282         memset(&cmdBufferBeginInfo, 0, sizeof(VkCommandBufferBeginInfo));
1283         cmdBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
1284         cmdBufferBeginInfo.pNext = nullptr;
1285         cmdBufferBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
1286         cmdBufferBeginInfo.pInheritanceInfo = nullptr;
1287 
1288         err = VK_CALL(BeginCommandBuffer(cmdBuffer, &cmdBufferBeginInfo));
1289         SkASSERT(!err);
1290 
1291         // Set image layout and add barrier
1292         VkImageMemoryBarrier barrier;
1293         memset(&barrier, 0, sizeof(VkImageMemoryBarrier));
1294         barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
1295         barrier.pNext = nullptr;
1296         barrier.srcAccessMask = GrVkMemory::LayoutToSrcAccessMask(initialLayout);
1297         barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
1298         barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
1299         barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
1300         barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
1301         barrier.image = image;
1302         barrier.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0 , 1};
1303 
1304         VK_CALL(CmdPipelineBarrier(cmdBuffer,
1305                                    GrVkMemory::LayoutToPipelineStageFlags(initialLayout),
1306                                    VK_PIPELINE_STAGE_TRANSFER_BIT,
1307                                    0,
1308                                    0, nullptr,
1309                                    0, nullptr,
1310                                    1, &barrier));
1311         initialLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
1312 
1313         // Submit copy command
1314         VkBufferImageCopy region;
1315         memset(&region, 0, sizeof(VkBufferImageCopy));
1316         region.bufferOffset = 0;
1317         region.bufferRowLength = w;
1318         region.bufferImageHeight = h;
1319         region.imageSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
1320         region.imageOffset = { 0, 0, 0 };
1321         region.imageExtent = { (uint32_t)w, (uint32_t)h, 1 };
1322 
1323         VK_CALL(CmdCopyBufferToImage(cmdBuffer, buffer, image, initialLayout, 1, &region));
1324 
1325         // End CommandBuffer
1326         err = VK_CALL(EndCommandBuffer(cmdBuffer));
1327         SkASSERT(!err);
1328 
1329         // Create Fence for queue
1330         VkFence fence;
1331         VkFenceCreateInfo fenceInfo;
1332         memset(&fenceInfo, 0, sizeof(VkFenceCreateInfo));
1333         fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
1334 
1335         err = VK_CALL(CreateFence(fDevice, &fenceInfo, nullptr, &fence));
1336         SkASSERT(!err);
1337 
1338         VkSubmitInfo submitInfo;
1339         memset(&submitInfo, 0, sizeof(VkSubmitInfo));
1340         submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
1341         submitInfo.pNext = nullptr;
1342         submitInfo.waitSemaphoreCount = 0;
1343         submitInfo.pWaitSemaphores = nullptr;
1344         submitInfo.pWaitDstStageMask = 0;
1345         submitInfo.commandBufferCount = 1;
1346         submitInfo.pCommandBuffers = &cmdBuffer;
1347         submitInfo.signalSemaphoreCount = 0;
1348         submitInfo.pSignalSemaphores = nullptr;
1349         err = VK_CALL(QueueSubmit(this->queue(), 1, &submitInfo, fence));
1350         SkASSERT(!err);
1351 
1352         err = VK_CALL(WaitForFences(fDevice, 1, &fence, true, UINT64_MAX));
1353         if (VK_TIMEOUT == err) {
1354             GrVkMemory::FreeImageMemory(this, linearTiling, alloc);
1355             VK_CALL(DestroyImage(fDevice, image, nullptr));
1356             GrVkMemory::FreeBufferMemory(this, GrVkBuffer::kCopyRead_Type, bufferAlloc);
1357             VK_CALL(DestroyBuffer(fDevice, buffer, nullptr));
1358             VK_CALL(FreeCommandBuffers(fDevice, fCmdPool, 1, &cmdBuffer));
1359             VK_CALL(DestroyFence(fDevice, fence, nullptr));
1360             SkDebugf("Fence failed to signal: %d\n", err);
1361             SkFAIL("failing");
1362         }
1363         SkASSERT(!err);
1364 
1365         // Clean up transfer resources
1366         GrVkMemory::FreeBufferMemory(this, GrVkBuffer::kCopyRead_Type, bufferAlloc);
1367         VK_CALL(DestroyBuffer(fDevice, buffer, nullptr));
1368         VK_CALL(FreeCommandBuffers(fDevice, fCmdPool, 1, &cmdBuffer));
1369         VK_CALL(DestroyFence(fDevice, fence, nullptr));
1370     }
1371 
1372     GrVkImageInfo* info = new GrVkImageInfo;
1373     info->fImage = image;
1374     info->fAlloc = alloc;
1375     info->fImageTiling = imageTiling;
1376     info->fImageLayout = initialLayout;
1377     info->fFormat = pixelFormat;
1378     info->fLevelCount = 1;
1379 
1380     return (GrBackendObject)info;
1381 }
1382 
isTestingOnlyBackendTexture(GrBackendObject id) const1383 bool GrVkGpu::isTestingOnlyBackendTexture(GrBackendObject id) const {
1384     const GrVkImageInfo* backend = reinterpret_cast<const GrVkImageInfo*>(id);
1385 
1386     if (backend && backend->fImage && backend->fAlloc.fMemory) {
1387         VkMemoryRequirements req;
1388         memset(&req, 0, sizeof(req));
1389         GR_VK_CALL(this->vkInterface(), GetImageMemoryRequirements(fDevice,
1390                                                                    backend->fImage,
1391                                                                    &req));
1392         // TODO: find a better check
1393         // This will probably fail with a different driver
1394         return (req.size > 0) && (req.size <= 8192 * 8192);
1395     }
1396 
1397     return false;
1398 }
1399 
deleteTestingOnlyBackendTexture(GrBackendObject id,bool abandon)1400 void GrVkGpu::deleteTestingOnlyBackendTexture(GrBackendObject id, bool abandon) {
1401     GrVkImageInfo* backend = reinterpret_cast<GrVkImageInfo*>(id);
1402     if (backend) {
1403         if (!abandon) {
1404             // something in the command buffer may still be using this, so force submit
1405             this->submitCommandBuffer(kForce_SyncQueue);
1406             GrVkImage::DestroyImageInfo(this, backend);
1407         }
1408         delete backend;
1409     }
1410 }
1411 
1412 ////////////////////////////////////////////////////////////////////////////////
1413 
addMemoryBarrier(VkPipelineStageFlags srcStageMask,VkPipelineStageFlags dstStageMask,bool byRegion,VkMemoryBarrier * barrier) const1414 void GrVkGpu::addMemoryBarrier(VkPipelineStageFlags srcStageMask,
1415                                VkPipelineStageFlags dstStageMask,
1416                                bool byRegion,
1417                                VkMemoryBarrier* barrier) const {
1418     SkASSERT(fCurrentCmdBuffer);
1419     fCurrentCmdBuffer->pipelineBarrier(this,
1420                                        srcStageMask,
1421                                        dstStageMask,
1422                                        byRegion,
1423                                        GrVkCommandBuffer::kMemory_BarrierType,
1424                                        barrier);
1425 }
1426 
addBufferMemoryBarrier(VkPipelineStageFlags srcStageMask,VkPipelineStageFlags dstStageMask,bool byRegion,VkBufferMemoryBarrier * barrier) const1427 void GrVkGpu::addBufferMemoryBarrier(VkPipelineStageFlags srcStageMask,
1428                                      VkPipelineStageFlags dstStageMask,
1429                                      bool byRegion,
1430                                      VkBufferMemoryBarrier* barrier) const {
1431     SkASSERT(fCurrentCmdBuffer);
1432     fCurrentCmdBuffer->pipelineBarrier(this,
1433                                        srcStageMask,
1434                                        dstStageMask,
1435                                        byRegion,
1436                                        GrVkCommandBuffer::kBufferMemory_BarrierType,
1437                                        barrier);
1438 }
1439 
addImageMemoryBarrier(VkPipelineStageFlags srcStageMask,VkPipelineStageFlags dstStageMask,bool byRegion,VkImageMemoryBarrier * barrier) const1440 void GrVkGpu::addImageMemoryBarrier(VkPipelineStageFlags srcStageMask,
1441                                     VkPipelineStageFlags dstStageMask,
1442                                     bool byRegion,
1443                                     VkImageMemoryBarrier* barrier) const {
1444     SkASSERT(fCurrentCmdBuffer);
1445     fCurrentCmdBuffer->pipelineBarrier(this,
1446                                        srcStageMask,
1447                                        dstStageMask,
1448                                        byRegion,
1449                                        GrVkCommandBuffer::kImageMemory_BarrierType,
1450                                        barrier);
1451 }
1452 
finishFlush()1453 void GrVkGpu::finishFlush() {
1454     // Submit the current command buffer to the Queue
1455     this->submitCommandBuffer(kSkip_SyncQueue);
1456 }
1457 
clearStencil(GrRenderTarget * target)1458 void GrVkGpu::clearStencil(GrRenderTarget* target) {
1459     if (nullptr == target) {
1460         return;
1461     }
1462     GrStencilAttachment* stencil = target->renderTargetPriv().getStencilAttachment();
1463     GrVkStencilAttachment* vkStencil = (GrVkStencilAttachment*)stencil;
1464 
1465 
1466     VkClearDepthStencilValue vkStencilColor;
1467     memset(&vkStencilColor, 0, sizeof(VkClearDepthStencilValue));
1468 
1469     vkStencil->setImageLayout(this,
1470                               VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1471                               VK_ACCESS_TRANSFER_WRITE_BIT,
1472                               VK_PIPELINE_STAGE_TRANSFER_BIT,
1473                               false);
1474 
1475     VkImageSubresourceRange subRange;
1476     memset(&subRange, 0, sizeof(VkImageSubresourceRange));
1477     subRange.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT;
1478     subRange.baseMipLevel = 0;
1479     subRange.levelCount = 1;
1480     subRange.baseArrayLayer = 0;
1481     subRange.layerCount = 1;
1482 
1483     // TODO: I imagine that most times we want to clear a stencil it will be at the beginning of a
1484     // draw. Thus we should look into using the load op functions on the render pass to clear out
1485     // the stencil there.
1486     fCurrentCmdBuffer->clearDepthStencilImage(this, vkStencil, &vkStencilColor, 1, &subRange);
1487 }
1488 
can_copy_image(const GrSurface * dst,const GrSurface * src,const GrVkGpu * gpu)1489 inline bool can_copy_image(const GrSurface* dst,
1490                            const GrSurface* src,
1491                            const GrVkGpu* gpu) {
1492     const GrRenderTarget* dstRT = dst->asRenderTarget();
1493     const GrRenderTarget* srcRT = src->asRenderTarget();
1494     if (dstRT && srcRT) {
1495         if (srcRT->numColorSamples() != dstRT->numColorSamples()) {
1496             return false;
1497         }
1498     } else if (dstRT) {
1499         if (dstRT->numColorSamples() > 1) {
1500             return false;
1501         }
1502     } else if (srcRT) {
1503         if (srcRT->numColorSamples() > 1) {
1504             return false;
1505         }
1506     }
1507 
1508     // We require that all vulkan GrSurfaces have been created with transfer_dst and transfer_src
1509     // as image usage flags.
1510     if (src->origin() == dst->origin() &&
1511         GrBytesPerPixel(src->config()) == GrBytesPerPixel(dst->config())) {
1512         return true;
1513     }
1514 
1515     return false;
1516 }
1517 
copySurfaceAsCopyImage(GrSurface * dst,GrSurface * src,GrVkImage * dstImage,GrVkImage * srcImage,const SkIRect & srcRect,const SkIPoint & dstPoint)1518 void GrVkGpu::copySurfaceAsCopyImage(GrSurface* dst,
1519                                      GrSurface* src,
1520                                      GrVkImage* dstImage,
1521                                      GrVkImage* srcImage,
1522                                      const SkIRect& srcRect,
1523                                      const SkIPoint& dstPoint) {
1524     SkASSERT(can_copy_image(dst, src, this));
1525 
1526     // These flags are for flushing/invalidating caches and for the dst image it doesn't matter if
1527     // the cache is flushed since it is only being written to.
1528     dstImage->setImageLayout(this,
1529                              VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1530                              VK_ACCESS_TRANSFER_WRITE_BIT,
1531                              VK_PIPELINE_STAGE_TRANSFER_BIT,
1532                              false);
1533 
1534     srcImage->setImageLayout(this,
1535                              VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
1536                              VK_ACCESS_TRANSFER_READ_BIT,
1537                              VK_PIPELINE_STAGE_TRANSFER_BIT,
1538                              false);
1539 
1540     // Flip rect if necessary
1541     SkIRect srcVkRect = srcRect;
1542     int32_t dstY = dstPoint.fY;
1543 
1544     if (kBottomLeft_GrSurfaceOrigin == src->origin()) {
1545         SkASSERT(kBottomLeft_GrSurfaceOrigin == dst->origin());
1546         srcVkRect.fTop = src->height() - srcRect.fBottom;
1547         srcVkRect.fBottom =  src->height() - srcRect.fTop;
1548         dstY = dst->height() - dstPoint.fY - srcVkRect.height();
1549     }
1550 
1551     VkImageCopy copyRegion;
1552     memset(&copyRegion, 0, sizeof(VkImageCopy));
1553     copyRegion.srcSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
1554     copyRegion.srcOffset = { srcVkRect.fLeft, srcVkRect.fTop, 0 };
1555     copyRegion.dstSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
1556     copyRegion.dstOffset = { dstPoint.fX, dstY, 0 };
1557     copyRegion.extent = { (uint32_t)srcVkRect.width(), (uint32_t)srcVkRect.height(), 1 };
1558 
1559     fCurrentCmdBuffer->copyImage(this,
1560                                  srcImage,
1561                                  VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
1562                                  dstImage,
1563                                  VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1564                                  1,
1565                                  &copyRegion);
1566 
1567     SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.fX, dstPoint.fY,
1568                                         srcRect.width(), srcRect.height());
1569     this->didWriteToSurface(dst, &dstRect);
1570 }
1571 
can_copy_as_blit(const GrSurface * dst,const GrSurface * src,const GrVkImage * dstImage,const GrVkImage * srcImage,const GrVkGpu * gpu)1572 inline bool can_copy_as_blit(const GrSurface* dst,
1573                              const GrSurface* src,
1574                              const GrVkImage* dstImage,
1575                              const GrVkImage* srcImage,
1576                              const GrVkGpu* gpu) {
1577     // We require that all vulkan GrSurfaces have been created with transfer_dst and transfer_src
1578     // as image usage flags.
1579     const GrVkCaps& caps = gpu->vkCaps();
1580     if (!caps.configCanBeDstofBlit(dst->config(), dstImage->isLinearTiled()) ||
1581         !caps.configCanBeSrcofBlit(src->config(), srcImage->isLinearTiled())) {
1582         return false;
1583     }
1584 
1585     // We cannot blit images that are multisampled. Will need to figure out if we can blit the
1586     // resolved msaa though.
1587     if ((dst->asRenderTarget() && dst->asRenderTarget()->numColorSamples() > 1) ||
1588         (src->asRenderTarget() && src->asRenderTarget()->numColorSamples() > 1)) {
1589         return false;
1590     }
1591 
1592     return true;
1593 }
1594 
copySurfaceAsBlit(GrSurface * dst,GrSurface * src,GrVkImage * dstImage,GrVkImage * srcImage,const SkIRect & srcRect,const SkIPoint & dstPoint)1595 void GrVkGpu::copySurfaceAsBlit(GrSurface* dst,
1596                                 GrSurface* src,
1597                                 GrVkImage* dstImage,
1598                                 GrVkImage* srcImage,
1599                                 const SkIRect& srcRect,
1600                                 const SkIPoint& dstPoint) {
1601     SkASSERT(can_copy_as_blit(dst, src, dstImage, srcImage, this));
1602 
1603     dstImage->setImageLayout(this,
1604                              VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1605                              VK_ACCESS_TRANSFER_WRITE_BIT,
1606                              VK_PIPELINE_STAGE_TRANSFER_BIT,
1607                              false);
1608 
1609     srcImage->setImageLayout(this,
1610                              VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
1611                              VK_ACCESS_TRANSFER_READ_BIT,
1612                              VK_PIPELINE_STAGE_TRANSFER_BIT,
1613                              false);
1614 
1615     // Flip rect if necessary
1616     SkIRect srcVkRect;
1617     srcVkRect.fLeft = srcRect.fLeft;
1618     srcVkRect.fRight = srcRect.fRight;
1619     SkIRect dstRect;
1620     dstRect.fLeft = dstPoint.fX;
1621     dstRect.fRight = dstPoint.fX + srcRect.width();
1622 
1623     if (kBottomLeft_GrSurfaceOrigin == src->origin()) {
1624         srcVkRect.fTop = src->height() - srcRect.fBottom;
1625         srcVkRect.fBottom = src->height() - srcRect.fTop;
1626     } else {
1627         srcVkRect.fTop = srcRect.fTop;
1628         srcVkRect.fBottom = srcRect.fBottom;
1629     }
1630 
1631     if (kBottomLeft_GrSurfaceOrigin == dst->origin()) {
1632         dstRect.fTop = dst->height() - dstPoint.fY - srcVkRect.height();
1633     } else {
1634         dstRect.fTop = dstPoint.fY;
1635     }
1636     dstRect.fBottom = dstRect.fTop + srcVkRect.height();
1637 
1638     // If we have different origins, we need to flip the top and bottom of the dst rect so that we
1639     // get the correct origintation of the copied data.
1640     if (src->origin() != dst->origin()) {
1641         SkTSwap(dstRect.fTop, dstRect.fBottom);
1642     }
1643 
1644     VkImageBlit blitRegion;
1645     memset(&blitRegion, 0, sizeof(VkImageBlit));
1646     blitRegion.srcSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
1647     blitRegion.srcOffsets[0] = { srcVkRect.fLeft, srcVkRect.fTop, 0 };
1648     blitRegion.srcOffsets[1] = { srcVkRect.fRight, srcVkRect.fBottom, 1 };
1649     blitRegion.dstSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
1650     blitRegion.dstOffsets[0] = { dstRect.fLeft, dstRect.fTop, 0 };
1651     blitRegion.dstOffsets[1] = { dstRect.fRight, dstRect.fBottom, 1 };
1652 
1653     fCurrentCmdBuffer->blitImage(this,
1654                                  *srcImage,
1655                                  *dstImage,
1656                                  1,
1657                                  &blitRegion,
1658                                  VK_FILTER_NEAREST); // We never scale so any filter works here
1659 
1660     this->didWriteToSurface(dst, &dstRect);
1661 }
1662 
can_copy_as_resolve(const GrSurface * dst,const GrSurface * src,const GrVkGpu * gpu)1663 inline bool can_copy_as_resolve(const GrSurface* dst,
1664                                 const GrSurface* src,
1665                                 const GrVkGpu* gpu) {
1666     // Our src must be a multisampled render target
1667     if (!src->asRenderTarget() || src->asRenderTarget()->numColorSamples() <= 1) {
1668         return false;
1669     }
1670 
1671     // The dst must not be a multisampled render target, expect in the case where the dst is the
1672     // resolve texture connected to the msaa src. We check for this in case we are copying a part of
1673     // a surface to a different region in the same surface.
1674     if (dst->asRenderTarget() && dst->asRenderTarget()->numColorSamples() > 1 && dst != src) {
1675         return false;
1676     }
1677 
1678     // Surfaces must have the same origin.
1679     if (src->origin() != dst->origin()) {
1680         return false;
1681     }
1682 
1683     return true;
1684 }
1685 
copySurfaceAsResolve(GrSurface * dst,GrSurface * src,const SkIRect & srcRect,const SkIPoint & dstPoint)1686 void GrVkGpu::copySurfaceAsResolve(GrSurface* dst,
1687                                    GrSurface* src,
1688                                    const SkIRect& srcRect,
1689                                    const SkIPoint& dstPoint) {
1690     GrVkRenderTarget* srcRT = static_cast<GrVkRenderTarget*>(src->asRenderTarget());
1691     this->resolveImage(dst, srcRT, srcRect, dstPoint);
1692 }
1693 
onCopySurface(GrSurface * dst,GrSurface * src,const SkIRect & srcRect,const SkIPoint & dstPoint)1694 bool GrVkGpu::onCopySurface(GrSurface* dst,
1695                             GrSurface* src,
1696                             const SkIRect& srcRect,
1697                             const SkIPoint& dstPoint) {
1698     if (can_copy_as_resolve(dst, src, this)) {
1699         this->copySurfaceAsResolve(dst, src, srcRect, dstPoint);
1700         return true;
1701     }
1702 
1703     if (this->vkCaps().mustSubmitCommandsBeforeCopyOp()) {
1704         this->submitCommandBuffer(GrVkGpu::kSkip_SyncQueue);
1705     }
1706 
1707     if (fCopyManager.copySurfaceAsDraw(this, dst, src, srcRect, dstPoint)) {
1708         return true;
1709     }
1710 
1711     GrVkImage* dstImage;
1712     GrVkImage* srcImage;
1713     GrRenderTarget* dstRT = dst->asRenderTarget();
1714     if (dstRT) {
1715         GrVkRenderTarget* vkRT = static_cast<GrVkRenderTarget*>(dstRT);
1716         dstImage = vkRT->numColorSamples() > 1 ? vkRT->msaaImage() : vkRT;
1717     } else {
1718         SkASSERT(dst->asTexture());
1719         dstImage = static_cast<GrVkTexture*>(dst->asTexture());
1720     }
1721     GrRenderTarget* srcRT = src->asRenderTarget();
1722     if (srcRT) {
1723         GrVkRenderTarget* vkRT = static_cast<GrVkRenderTarget*>(srcRT);
1724         srcImage = vkRT->numColorSamples() > 1 ? vkRT->msaaImage() : vkRT;
1725     } else {
1726         SkASSERT(src->asTexture());
1727         srcImage = static_cast<GrVkTexture*>(src->asTexture());
1728     }
1729 
1730     // For borrowed textures, we *only* want to copy using draws (to avoid layout changes)
1731     if (srcImage->isBorrowed()) {
1732         return false;
1733     }
1734 
1735     if (can_copy_image(dst, src, this)) {
1736         this->copySurfaceAsCopyImage(dst, src, dstImage, srcImage, srcRect, dstPoint);
1737         return true;
1738     }
1739 
1740     if (can_copy_as_blit(dst, src, dstImage, srcImage, this)) {
1741         this->copySurfaceAsBlit(dst, src, dstImage, srcImage, srcRect, dstPoint);
1742         return true;
1743     }
1744 
1745     return false;
1746 }
1747 
onQueryMultisampleSpecs(GrRenderTarget * rt,const GrStencilSettings &,int * effectiveSampleCnt,SamplePattern *)1748 void GrVkGpu::onQueryMultisampleSpecs(GrRenderTarget* rt, const GrStencilSettings&,
1749                                       int* effectiveSampleCnt, SamplePattern*) {
1750     // TODO: stub.
1751     SkASSERT(!this->caps()->sampleLocationsSupport());
1752     *effectiveSampleCnt = rt->numStencilSamples();
1753 }
1754 
onGetReadPixelsInfo(GrSurface * srcSurface,int width,int height,size_t rowBytes,GrPixelConfig readConfig,DrawPreference * drawPreference,ReadPixelTempDrawInfo * tempDrawInfo)1755 bool GrVkGpu::onGetReadPixelsInfo(GrSurface* srcSurface, int width, int height, size_t rowBytes,
1756                                   GrPixelConfig readConfig, DrawPreference* drawPreference,
1757                                   ReadPixelTempDrawInfo* tempDrawInfo) {
1758     // These settings we will always want if a temp draw is performed.
1759     tempDrawInfo->fTempSurfaceDesc.fFlags = kRenderTarget_GrSurfaceFlag;
1760     tempDrawInfo->fTempSurfaceDesc.fWidth = width;
1761     tempDrawInfo->fTempSurfaceDesc.fHeight = height;
1762     tempDrawInfo->fTempSurfaceDesc.fSampleCnt = 0;
1763     tempDrawInfo->fTempSurfaceDesc.fOrigin = kTopLeft_GrSurfaceOrigin; // no CPU y-flip for TL.
1764     tempDrawInfo->fTempSurfaceFit = SkBackingFit::kApprox;
1765 
1766     // For now assume no swizzling, we may change that below.
1767     tempDrawInfo->fSwizzle = GrSwizzle::RGBA();
1768 
1769     // Depends on why we need/want a temp draw. Start off assuming no change, the surface we read
1770     // from will be srcConfig and we will read readConfig pixels from it.
1771     // Note that if we require a draw and return a non-renderable format for the temp surface the
1772     // base class will fail for us.
1773     tempDrawInfo->fTempSurfaceDesc.fConfig = srcSurface->config();
1774     tempDrawInfo->fReadConfig = readConfig;
1775 
1776     if (srcSurface->config() == readConfig) {
1777         return true;
1778     }
1779 
1780     // Any config change requires a draw
1781     ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
1782     tempDrawInfo->fTempSurfaceDesc.fConfig = readConfig;
1783     tempDrawInfo->fReadConfig = readConfig;
1784 
1785     return true;
1786 }
1787 
onReadPixels(GrSurface * surface,int left,int top,int width,int height,GrPixelConfig config,void * buffer,size_t rowBytes)1788 bool GrVkGpu::onReadPixels(GrSurface* surface,
1789                            int left, int top, int width, int height,
1790                            GrPixelConfig config,
1791                            void* buffer,
1792                            size_t rowBytes) {
1793     VkFormat pixelFormat;
1794     if (!GrPixelConfigToVkFormat(config, &pixelFormat)) {
1795         return false;
1796     }
1797 
1798     GrVkImage* image = nullptr;
1799     GrVkRenderTarget* rt = static_cast<GrVkRenderTarget*>(surface->asRenderTarget());
1800     if (rt) {
1801         // resolve the render target if necessary
1802         switch (rt->getResolveType()) {
1803             case GrVkRenderTarget::kCantResolve_ResolveType:
1804                 return false;
1805             case GrVkRenderTarget::kAutoResolves_ResolveType:
1806                 break;
1807             case GrVkRenderTarget::kCanResolve_ResolveType:
1808                 this->internalResolveRenderTarget(rt, false);
1809                 break;
1810             default:
1811                 SkFAIL("Unknown resolve type");
1812         }
1813         image = rt;
1814     } else {
1815         image = static_cast<GrVkTexture*>(surface->asTexture());
1816     }
1817 
1818     if (!image) {
1819         return false;
1820     }
1821 
1822     // Change layout of our target so it can be used as copy
1823     image->setImageLayout(this,
1824                           VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
1825                           VK_ACCESS_TRANSFER_READ_BIT,
1826                           VK_PIPELINE_STAGE_TRANSFER_BIT,
1827                           false);
1828 
1829     size_t bpp = GrBytesPerPixel(config);
1830     size_t tightRowBytes = bpp * width;
1831     bool flipY = kBottomLeft_GrSurfaceOrigin == surface->origin();
1832 
1833     VkBufferImageCopy region;
1834     memset(&region, 0, sizeof(VkBufferImageCopy));
1835 
1836     bool copyFromOrigin = this->vkCaps().mustDoCopiesFromOrigin();
1837     if (copyFromOrigin) {
1838         region.imageOffset = { 0, 0, 0 };
1839         region.imageExtent = { (uint32_t)(left + width),
1840                                (uint32_t)(flipY ? surface->height() - top : top + height),
1841                                1
1842                              };
1843     } else {
1844         VkOffset3D offset = {
1845             left,
1846             flipY ? surface->height() - top - height : top,
1847             0
1848         };
1849         region.imageOffset = offset;
1850         region.imageExtent = { (uint32_t)width, (uint32_t)height, 1 };
1851     }
1852 
1853     size_t transBufferRowBytes = bpp * region.imageExtent.width;
1854     GrVkTransferBuffer* transferBuffer =
1855             static_cast<GrVkTransferBuffer*>(this->createBuffer(transBufferRowBytes * height,
1856                                                                 kXferGpuToCpu_GrBufferType,
1857                                                                 kStream_GrAccessPattern));
1858 
1859     // Copy the image to a buffer so we can map it to cpu memory
1860     region.bufferOffset = transferBuffer->offset();
1861     region.bufferRowLength = 0; // Forces RowLength to be width. We handle the rowBytes below.
1862     region.bufferImageHeight = 0; // Forces height to be tightly packed. Only useful for 3d images.
1863     region.imageSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
1864 
1865     fCurrentCmdBuffer->copyImageToBuffer(this,
1866                                          image,
1867                                          VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
1868                                          transferBuffer,
1869                                          1,
1870                                          &region);
1871 
1872     // make sure the copy to buffer has finished
1873     transferBuffer->addMemoryBarrier(this,
1874                                      VK_ACCESS_TRANSFER_WRITE_BIT,
1875                                      VK_ACCESS_HOST_READ_BIT,
1876                                      VK_PIPELINE_STAGE_TRANSFER_BIT,
1877                                      VK_PIPELINE_STAGE_HOST_BIT,
1878                                      false);
1879 
1880     // We need to submit the current command buffer to the Queue and make sure it finishes before
1881     // we can copy the data out of the buffer.
1882     this->submitCommandBuffer(kForce_SyncQueue);
1883     GrVkMemory::InvalidateMappedAlloc(this, transferBuffer->alloc());
1884     void* mappedMemory = transferBuffer->map();
1885 
1886     if (copyFromOrigin) {
1887         uint32_t skipRows = region.imageExtent.height - height;
1888         mappedMemory = (char*)mappedMemory + transBufferRowBytes * skipRows + bpp * left;
1889     }
1890 
1891     if (flipY) {
1892         const char* srcRow = reinterpret_cast<const char*>(mappedMemory);
1893         char* dstRow = reinterpret_cast<char*>(buffer)+(height - 1) * rowBytes;
1894         for (int y = 0; y < height; y++) {
1895             memcpy(dstRow, srcRow, tightRowBytes);
1896             srcRow += transBufferRowBytes;
1897             dstRow -= rowBytes;
1898         }
1899     } else {
1900         SkRectMemcpy(buffer, rowBytes, mappedMemory, transBufferRowBytes, tightRowBytes, height);
1901     }
1902 
1903     transferBuffer->unmap();
1904     transferBuffer->unref();
1905     return true;
1906 }
1907 
1908 // The RenderArea bounds we pass into BeginRenderPass must have a start x value that is a multiple
1909 // of the granularity. The width must also be a multiple of the granularity or eaqual to the width
1910 // 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)1911 void adjust_bounds_to_granularity(SkIRect* dstBounds, const SkIRect& srcBounds,
1912                                   const VkExtent2D& granularity, int maxWidth, int maxHeight) {
1913     // Adjust Width
1914     if ((0 != granularity.width && 1 != granularity.width)) {
1915         // Start with the right side of rect so we know if we end up going pass the maxWidth.
1916         int rightAdj = srcBounds.fRight % granularity.width;
1917         if (rightAdj != 0) {
1918             rightAdj = granularity.width - rightAdj;
1919         }
1920         dstBounds->fRight = srcBounds.fRight + rightAdj;
1921         if (dstBounds->fRight > maxWidth) {
1922             dstBounds->fRight = maxWidth;
1923             dstBounds->fLeft = 0;
1924         } else {
1925             dstBounds->fLeft = srcBounds.fLeft - srcBounds.fLeft % granularity.width;
1926         }
1927     } else {
1928         dstBounds->fLeft = srcBounds.fLeft;
1929         dstBounds->fRight = srcBounds.fRight;
1930     }
1931 
1932     // Adjust height
1933     if ((0 != granularity.height && 1 != granularity.height)) {
1934         // Start with the bottom side of rect so we know if we end up going pass the maxHeight.
1935         int bottomAdj = srcBounds.fBottom % granularity.height;
1936         if (bottomAdj != 0) {
1937             bottomAdj = granularity.height - bottomAdj;
1938         }
1939         dstBounds->fBottom = srcBounds.fBottom + bottomAdj;
1940         if (dstBounds->fBottom > maxHeight) {
1941             dstBounds->fBottom = maxHeight;
1942             dstBounds->fTop = 0;
1943         } else {
1944             dstBounds->fTop = srcBounds.fTop - srcBounds.fTop % granularity.height;
1945         }
1946     } else {
1947         dstBounds->fTop = srcBounds.fTop;
1948         dstBounds->fBottom = srcBounds.fBottom;
1949     }
1950 }
1951 
submitSecondaryCommandBuffer(const SkTArray<GrVkSecondaryCommandBuffer * > & buffers,const GrVkRenderPass * renderPass,const VkClearValue * colorClear,GrVkRenderTarget * target,const SkIRect & bounds)1952 void GrVkGpu::submitSecondaryCommandBuffer(const SkTArray<GrVkSecondaryCommandBuffer*>& buffers,
1953                                            const GrVkRenderPass* renderPass,
1954                                            const VkClearValue* colorClear,
1955                                            GrVkRenderTarget* target,
1956                                            const SkIRect& bounds) {
1957     const SkIRect* pBounds = &bounds;
1958     SkIRect flippedBounds;
1959     if (kBottomLeft_GrSurfaceOrigin == target->origin()) {
1960         flippedBounds = bounds;
1961         flippedBounds.fTop = target->height() - bounds.fBottom;
1962         flippedBounds.fBottom = target->height() - bounds.fTop;
1963         pBounds = &flippedBounds;
1964     }
1965 
1966     // The bounds we use for the render pass should be of the granularity supported
1967     // by the device.
1968     const VkExtent2D& granularity = renderPass->granularity();
1969     SkIRect adjustedBounds;
1970     if ((0 != granularity.width && 1 != granularity.width) ||
1971         (0 != granularity.height && 1 != granularity.height)) {
1972         adjust_bounds_to_granularity(&adjustedBounds, *pBounds, granularity,
1973                                      target->width(), target->height());
1974         pBounds = &adjustedBounds;
1975     }
1976 
1977     fCurrentCmdBuffer->beginRenderPass(this, renderPass, colorClear, *target, *pBounds, true);
1978     for (int i = 0; i < buffers.count(); ++i) {
1979         fCurrentCmdBuffer->executeCommands(this, buffers[i]);
1980     }
1981     fCurrentCmdBuffer->endRenderPass(this);
1982 
1983     this->didWriteToSurface(target, &bounds);
1984 }
1985 
insertFence()1986 GrFence SK_WARN_UNUSED_RESULT GrVkGpu::insertFence() {
1987     VkFenceCreateInfo createInfo;
1988     memset(&createInfo, 0, sizeof(VkFenceCreateInfo));
1989     createInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
1990     createInfo.pNext = nullptr;
1991     createInfo.flags = 0;
1992     VkFence fence = VK_NULL_HANDLE;
1993 
1994     VK_CALL_ERRCHECK(CreateFence(this->device(), &createInfo, nullptr, &fence));
1995     VK_CALL(QueueSubmit(this->queue(), 0, nullptr, fence));
1996 
1997     GR_STATIC_ASSERT(sizeof(GrFence) >= sizeof(VkFence));
1998     return (GrFence)fence;
1999 }
2000 
waitFence(GrFence fence,uint64_t timeout)2001 bool GrVkGpu::waitFence(GrFence fence, uint64_t timeout) {
2002     SkASSERT(VK_NULL_HANDLE != (VkFence)fence);
2003 
2004     VkResult result = VK_CALL(WaitForFences(this->device(), 1, (VkFence*)&fence, VK_TRUE, timeout));
2005     return (VK_SUCCESS == result);
2006 }
2007 
deleteFence(GrFence fence) const2008 void GrVkGpu::deleteFence(GrFence fence) const {
2009     VK_CALL(DestroyFence(this->device(), (VkFence)fence, nullptr));
2010 }
2011 
makeSemaphore(bool isOwned)2012 sk_sp<GrSemaphore> SK_WARN_UNUSED_RESULT GrVkGpu::makeSemaphore(bool isOwned) {
2013     return GrVkSemaphore::Make(this, isOwned);
2014 }
2015 
wrapBackendSemaphore(const GrBackendSemaphore & semaphore,GrWrapOwnership ownership)2016 sk_sp<GrSemaphore> GrVkGpu::wrapBackendSemaphore(const GrBackendSemaphore& semaphore,
2017                                                  GrWrapOwnership ownership) {
2018     return GrVkSemaphore::MakeWrapped(this, semaphore.vkSemaphore(), ownership);
2019 }
2020 
insertSemaphore(sk_sp<GrSemaphore> semaphore,bool flush)2021 void GrVkGpu::insertSemaphore(sk_sp<GrSemaphore> semaphore, bool flush) {
2022     GrVkSemaphore* vkSem = static_cast<GrVkSemaphore*>(semaphore.get());
2023 
2024     const GrVkSemaphore::Resource* resource = vkSem->getResource();
2025     resource->ref();
2026     fSemaphoresToSignal.push_back(resource);
2027 
2028     if (flush) {
2029         this->submitCommandBuffer(kSkip_SyncQueue);
2030     }
2031 }
2032 
waitSemaphore(sk_sp<GrSemaphore> semaphore)2033 void GrVkGpu::waitSemaphore(sk_sp<GrSemaphore> semaphore) {
2034     GrVkSemaphore* vkSem = static_cast<GrVkSemaphore*>(semaphore.get());
2035 
2036     const GrVkSemaphore::Resource* resource = vkSem->getResource();
2037     resource->ref();
2038     fSemaphoresToWaitOn.push_back(resource);
2039 }
2040 
prepareTextureForCrossContextUsage(GrTexture * texture)2041 sk_sp<GrSemaphore> GrVkGpu::prepareTextureForCrossContextUsage(GrTexture* texture) {
2042     SkASSERT(texture);
2043     GrVkTexture* vkTexture = static_cast<GrVkTexture*>(texture);
2044     vkTexture->setImageLayout(this,
2045                               VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
2046                               VK_ACCESS_SHADER_READ_BIT,
2047                               VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
2048                               false);
2049     this->submitCommandBuffer(kSkip_SyncQueue);
2050 
2051     // The image layout change serves as a barrier, so no semaphore is needed
2052     return nullptr;
2053 }
2054