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