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 "GrPipeline.h"
14 #include "GrRenderTargetPriv.h"
15 #include "GrSurfacePriv.h"
16 #include "GrTexturePriv.h"
17 #include "GrVertices.h"
18 
19 #include "GrVkCommandBuffer.h"
20 #include "GrVkImage.h"
21 #include "GrVkIndexBuffer.h"
22 #include "GrVkMemory.h"
23 #include "GrVkPipeline.h"
24 #include "GrVkProgram.h"
25 #include "GrVkProgramBuilder.h"
26 #include "GrVkProgramDesc.h"
27 #include "GrVkRenderPass.h"
28 #include "GrVkResourceProvider.h"
29 #include "GrVkTexture.h"
30 #include "GrVkTextureRenderTarget.h"
31 #include "GrVkTransferBuffer.h"
32 #include "GrVkVertexBuffer.h"
33 
34 #include "SkConfig8888.h"
35 
36 #include "vk/GrVkInterface.h"
37 
38 #define VK_CALL(X) GR_VK_CALL(this->vkInterface(), X)
39 #define VK_CALL_RET(RET, X) GR_VK_CALL_RET(this->vkInterface(), RET, X)
40 #define VK_CALL_ERRCHECK(X) GR_VK_CALL_ERRCHECK(this->vkInterface(), X)
41 
42 ////////////////////////////////////////////////////////////////////////////////
43 // Stuff used to set up a GrVkGpu secrectly for now.
44 
45 // For now the VkGpuCreate is using the same signature as GL. This is mostly for ease of
46 // hiding this code from offical skia. In the end the VkGpuCreate will not take a GrBackendContext
47 // and mostly likely would take an optional device and queues to use.
vk_gpu_create(GrBackendContext backendContext,const GrContextOptions & options,GrContext * context)48 GrGpu* vk_gpu_create(GrBackendContext backendContext, const GrContextOptions& options,
49                      GrContext* context) {
50     // Below is Vulkan setup code that normal would be done by a client, but will do here for now
51     // for testing purposes.
52     VkPhysicalDevice physDev;
53     VkDevice device;
54     VkInstance inst;
55     VkResult err;
56 
57     const VkApplicationInfo app_info = {
58         VK_STRUCTURE_TYPE_APPLICATION_INFO, // sType
59         nullptr,                            // pNext
60         "vktest",                           // pApplicationName
61         0,                                  // applicationVersion
62         "vktest",                           // pEngineName
63         0,                                  // engineVerison
64         VK_API_VERSION,                     // apiVersion
65     };
66     const VkInstanceCreateInfo instance_create = {
67         VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, // sType
68         nullptr,                                // pNext
69         0,                                      // flags
70         &app_info,                              // pApplicationInfo
71         0,                                      // enabledLayerNameCount
72         nullptr,                                // ppEnabledLayerNames
73         0,                                      // enabledExtensionNameCount
74         nullptr,                                // ppEnabledExtensionNames
75     };
76     err = vkCreateInstance(&instance_create, nullptr, &inst);
77     if (err < 0) {
78         SkDebugf("vkCreateInstanced failed: %d\n", err);
79         SkFAIL("failing");
80     }
81 
82     uint32_t gpuCount;
83     err = vkEnumeratePhysicalDevices(inst, &gpuCount, nullptr);
84     if (err) {
85         SkDebugf("vkEnumeratePhysicalDevices failed: %d\n", err);
86         SkFAIL("failing");
87     }
88     SkASSERT(gpuCount > 0);
89     // Just returning the first physical device instead of getting the whole array.
90     gpuCount = 1;
91     err = vkEnumeratePhysicalDevices(inst, &gpuCount, &physDev);
92     if (err) {
93         SkDebugf("vkEnumeratePhysicalDevices failed: %d\n", err);
94         SkFAIL("failing");
95     }
96 
97     // query to get the initial queue props size
98     uint32_t queueCount;
99     vkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueCount, nullptr);
100     SkASSERT(queueCount >= 1);
101 
102     SkAutoMalloc queuePropsAlloc(queueCount * sizeof(VkQueueFamilyProperties));
103     // now get the actual queue props
104     VkQueueFamilyProperties* queueProps = (VkQueueFamilyProperties*)queuePropsAlloc.get();
105 
106     vkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueCount, queueProps);
107 
108     // iterate to find the graphics queue
109     uint32_t graphicsQueueIndex = -1;
110     for (uint32_t i = 0; i < queueCount; i++) {
111         if (queueProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
112             graphicsQueueIndex = i;
113             break;
114         }
115     }
116     SkASSERT(graphicsQueueIndex < queueCount);
117 
118     float queuePriorities[1] = { 0.0 };
119     const VkDeviceQueueCreateInfo queueInfo = {
120         VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // sType
121         nullptr,                                    // pNext
122         0,                                          // VkDeviceQueueCreateFlags
123         0,                                          // queueFamilyIndex
124         1,                                          // queueCount
125         queuePriorities,                            // pQueuePriorities
126     };
127     const VkDeviceCreateInfo deviceInfo = {
128         VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,  // sType
129         nullptr,                               // pNext
130         0,                                     // VkDeviceCreateFlags
131         1,                                     // queueCreateInfoCount
132         &queueInfo,                            // pQueueCreateInfos
133         0,                                     // layerCount
134         nullptr,                               // ppEnabledLayerNames
135         0,                                     // extensionCount
136         nullptr,                               // ppEnabledExtensionNames
137         nullptr                                // ppEnabledFeatures
138     };
139 
140     err = vkCreateDevice(physDev, &deviceInfo, nullptr, &device);
141     if (err) {
142         SkDebugf("CreateDevice failed: %d\n", err);
143         SkFAIL("failing");
144     }
145 
146     VkQueue queue;
147     vkGetDeviceQueue(device, graphicsQueueIndex, 0, &queue);
148 
149     const VkCommandPoolCreateInfo cmdPoolInfo = {
150         VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, // sType
151         nullptr,                                    // pNext
152         0,                                          // CmdPoolCreateFlags
153         graphicsQueueIndex,                         // queueFamilyIndex
154     };
155 
156     VkCommandPool cmdPool;
157     err = vkCreateCommandPool(device, &cmdPoolInfo, nullptr, &cmdPool);
158     if (err) {
159         SkDebugf("CreateCommandPool failed: %d\n", err);
160         SkFAIL("failing");
161     }
162 
163     return new GrVkGpu(context, options, physDev, device, queue, cmdPool, inst);
164 }
165 
166 ////////////////////////////////////////////////////////////////////////////////
167 
GrVkGpu(GrContext * context,const GrContextOptions & options,VkPhysicalDevice physDev,VkDevice device,VkQueue queue,VkCommandPool cmdPool,VkInstance inst)168 GrVkGpu::GrVkGpu(GrContext* context, const GrContextOptions& options,
169                  VkPhysicalDevice physDev, VkDevice device, VkQueue queue, VkCommandPool cmdPool,
170                  VkInstance inst)
171     : INHERITED(context)
172     , fDevice(device)
173     , fQueue(queue)
174     , fCmdPool(cmdPool)
175     , fResourceProvider(this)
176     , fVkInstance(inst) {
177     fInterface.reset(GrVkCreateInterface(fVkInstance));
178     fCompiler = shaderc_compiler_initialize();
179 
180     fVkCaps.reset(new GrVkCaps(options, fInterface, physDev));
181     fCaps.reset(SkRef(fVkCaps.get()));
182 
183     fCurrentCmdBuffer = fResourceProvider.createCommandBuffer();
184     SkASSERT(fCurrentCmdBuffer);
185     fCurrentCmdBuffer->begin(this);
186     VK_CALL(GetPhysicalDeviceMemoryProperties(physDev, &fPhysDevMemProps));
187 
188 }
189 
~GrVkGpu()190 GrVkGpu::~GrVkGpu() {
191     shaderc_compiler_release(fCompiler);
192     fCurrentCmdBuffer->end(this);
193     fCurrentCmdBuffer->unref(this);
194 
195     // wait for all commands to finish
196     VK_CALL(QueueWaitIdle(fQueue));
197 
198     // must call this just before we destroy the VkDevice
199     fResourceProvider.destroyResources();
200 
201     VK_CALL(DestroyCommandPool(fDevice, fCmdPool, nullptr));
202     VK_CALL(DestroyDevice(fDevice, nullptr));
203     VK_CALL(DestroyInstance(fVkInstance, nullptr));
204 }
205 
206 ///////////////////////////////////////////////////////////////////////////////
207 
submitCommandBuffer(SyncQueue sync)208 void GrVkGpu::submitCommandBuffer(SyncQueue sync) {
209     SkASSERT(fCurrentCmdBuffer);
210     fCurrentCmdBuffer->end(this);
211 
212     fCurrentCmdBuffer->submitToQueue(this, fQueue, sync);
213     fResourceProvider.checkCommandBuffers();
214 
215     // Release old command buffer and create a new one
216     fCurrentCmdBuffer->unref(this);
217     fCurrentCmdBuffer = fResourceProvider.createCommandBuffer();
218     SkASSERT(fCurrentCmdBuffer);
219 
220     fCurrentCmdBuffer->begin(this);
221 }
222 
223 ///////////////////////////////////////////////////////////////////////////////
onCreateVertexBuffer(size_t size,bool dynamic)224 GrVertexBuffer* GrVkGpu::onCreateVertexBuffer(size_t size, bool dynamic) {
225     return GrVkVertexBuffer::Create(this, size, dynamic);
226 }
227 
onCreateIndexBuffer(size_t size,bool dynamic)228 GrIndexBuffer* GrVkGpu::onCreateIndexBuffer(size_t size, bool dynamic) {
229     return GrVkIndexBuffer::Create(this, size, dynamic);
230 }
231 
onCreateTransferBuffer(size_t size,TransferType type)232 GrTransferBuffer* GrVkGpu::onCreateTransferBuffer(size_t size, TransferType type) {
233     GrVkBuffer::Type bufferType = kCpuToGpu_TransferType ? GrVkBuffer::kCopyRead_Type
234                                                          : GrVkBuffer::kCopyWrite_Type;
235     return GrVkTransferBuffer::Create(this, size, bufferType);
236 }
237 
238 ////////////////////////////////////////////////////////////////////////////////
onGetWritePixelsInfo(GrSurface * dstSurface,int width,int height,GrPixelConfig srcConfig,DrawPreference * drawPreference,WritePixelTempDrawInfo * tempDrawInfo)239 bool GrVkGpu::onGetWritePixelsInfo(GrSurface* dstSurface, int width, int height,
240                                    GrPixelConfig srcConfig, DrawPreference* drawPreference,
241                                    WritePixelTempDrawInfo* tempDrawInfo) {
242     if (kIndex_8_GrPixelConfig == srcConfig || GrPixelConfigIsCompressed(dstSurface->config())) {
243         return false;
244     }
245 
246     // Currently we don't handle draws, so if the caller wants/needs to do a draw we need to fail
247     if (kNoDraw_DrawPreference != *drawPreference) {
248         return false;
249     }
250 
251     if (dstSurface->config() != srcConfig) {
252         // TODO: This should fall back to drawing or copying to change config of dstSurface to
253         // match that of srcConfig.
254         return false;
255     }
256 
257     return true;
258 }
259 
onWritePixels(GrSurface * surface,int left,int top,int width,int height,GrPixelConfig config,const void * buffer,size_t rowBytes)260 bool GrVkGpu::onWritePixels(GrSurface* surface,
261                             int left, int top, int width, int height,
262                             GrPixelConfig config, const void* buffer,
263                             size_t rowBytes) {
264     GrVkTexture* vkTex = static_cast<GrVkTexture*>(surface->asTexture());
265     if (!vkTex) {
266         return false;
267     }
268 
269     // We assume Vulkan doesn't do sRGB <-> linear conversions when reading and writing pixels.
270     if (GrPixelConfigIsSRGB(surface->config()) != GrPixelConfigIsSRGB(config)) {
271         return false;
272     }
273 
274     bool success = false;
275     if (GrPixelConfigIsCompressed(vkTex->desc().fConfig)) {
276         // We check that config == desc.fConfig in GrGpu::getWritePixelsInfo()
277         SkASSERT(config == vkTex->desc().fConfig);
278         // TODO: add compressed texture support
279         // delete the following two lines and uncomment the two after that when ready
280         vkTex->unref();
281         return false;
282         //success = this->uploadCompressedTexData(vkTex->desc(), buffer, false, left, top, width,
283         //                                       height);
284     } else {
285         bool linearTiling = vkTex->isLinearTiled();
286         if (linearTiling && VK_IMAGE_LAYOUT_PREINITIALIZED != vkTex->currentLayout()) {
287             // Need to change the layout to general in order to perform a host write
288             VkImageLayout layout = vkTex->currentLayout();
289             VkPipelineStageFlags srcStageMask = GrVkMemory::LayoutToPipelineStageFlags(layout);
290             VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_HOST_BIT;
291             VkAccessFlags srcAccessMask = GrVkMemory::LayoutToSrcAccessMask(layout);
292             VkAccessFlags dstAccessMask = VK_ACCESS_HOST_WRITE_BIT;
293             vkTex->setImageLayout(this,
294                                   VK_IMAGE_LAYOUT_GENERAL,
295                                   srcAccessMask,
296                                   dstAccessMask,
297                                   srcStageMask,
298                                   dstStageMask,
299                                   false);
300         }
301         success = this->uploadTexData(vkTex, left, top, width, height, config,
302                                       buffer, rowBytes);
303     }
304 
305     if (success) {
306         vkTex->texturePriv().dirtyMipMaps(true);
307         return true;
308     }
309 
310     return false;
311 }
312 
uploadTexData(GrVkTexture * tex,int left,int top,int width,int height,GrPixelConfig dataConfig,const void * data,size_t rowBytes)313 bool GrVkGpu::uploadTexData(GrVkTexture* tex,
314                             int left, int top, int width, int height,
315                             GrPixelConfig dataConfig,
316                             const void* data,
317                             size_t rowBytes) {
318     SkASSERT(data);
319 
320     // If we're uploading compressed data then we should be using uploadCompressedTexData
321     SkASSERT(!GrPixelConfigIsCompressed(dataConfig));
322 
323     bool linearTiling = tex->isLinearTiled();
324 
325     size_t bpp = GrBytesPerPixel(dataConfig);
326 
327     const GrSurfaceDesc& desc = tex->desc();
328 
329     if (!GrSurfacePriv::AdjustWritePixelParams(desc.fWidth, desc.fHeight, bpp, &left, &top,
330                                                &width, &height, &data, &rowBytes)) {
331         return false;
332     }
333     size_t trimRowBytes = width * bpp;
334 
335     if (linearTiling) {
336         SkASSERT(VK_IMAGE_LAYOUT_PREINITIALIZED == tex->currentLayout() ||
337                  VK_IMAGE_LAYOUT_GENERAL == tex->currentLayout());
338         const VkImageSubresource subres = {
339             VK_IMAGE_ASPECT_COLOR_BIT,
340             0,  // mipLevel
341             0,  // arraySlice
342         };
343         VkSubresourceLayout layout;
344         VkResult err;
345 
346         const GrVkInterface* interface = this->vkInterface();
347 
348         GR_VK_CALL(interface, GetImageSubresourceLayout(fDevice,
349                                                         tex->textureImage(),
350                                                         &subres,
351                                                         &layout));
352 
353         int texTop = kBottomLeft_GrSurfaceOrigin == desc.fOrigin ? tex->height() - top - height
354                                                                     : top;
355         VkDeviceSize offset = texTop*layout.rowPitch + left*bpp;
356         VkDeviceSize size = height*layout.rowPitch;
357         void* mapPtr;
358         err = GR_VK_CALL(interface, MapMemory(fDevice, tex->textureMemory(), offset, size, 0,
359                                                 &mapPtr));
360         if (err) {
361             return false;
362         }
363 
364         if (kBottomLeft_GrSurfaceOrigin == desc.fOrigin) {
365             // copy into buffer by rows
366             const char* srcRow = reinterpret_cast<const char*>(data);
367             char* dstRow = reinterpret_cast<char*>(mapPtr)+(height - 1)*layout.rowPitch;
368             for (int y = 0; y < height; y++) {
369                 memcpy(dstRow, srcRow, trimRowBytes);
370                 srcRow += rowBytes;
371                 dstRow -= layout.rowPitch;
372             }
373         } else {
374             // If there is no padding on the src (rowBytes) or dst (layout.rowPitch) we can memcpy
375             if (trimRowBytes == rowBytes && trimRowBytes == layout.rowPitch) {
376                 memcpy(mapPtr, data, trimRowBytes * height);
377             } else {
378                 SkRectMemcpy(mapPtr, layout.rowPitch, data, rowBytes, trimRowBytes, height);
379             }
380         }
381 
382         GR_VK_CALL(interface, UnmapMemory(fDevice, tex->textureMemory()));
383     } else {
384         GrVkTransferBuffer* transferBuffer =
385             GrVkTransferBuffer::Create(this, trimRowBytes * height, GrVkBuffer::kCopyRead_Type);
386 
387         void* mapPtr = transferBuffer->map();
388 
389         if (kBottomLeft_GrSurfaceOrigin == desc.fOrigin) {
390             // copy into buffer by rows
391             const char* srcRow = reinterpret_cast<const char*>(data);
392             char* dstRow = reinterpret_cast<char*>(mapPtr)+(height - 1)*trimRowBytes;
393             for (int y = 0; y < height; y++) {
394                 memcpy(dstRow, srcRow, trimRowBytes);
395                 srcRow += rowBytes;
396                 dstRow -= trimRowBytes;
397             }
398         } else {
399             // If there is no padding on the src data rows, we can do a single memcpy
400             if (trimRowBytes == rowBytes) {
401                 memcpy(mapPtr, data, trimRowBytes * height);
402             } else {
403                 SkRectMemcpy(mapPtr, trimRowBytes, data, rowBytes, trimRowBytes, height);
404             }
405         }
406 
407         transferBuffer->unmap();
408 
409         // make sure the unmap has finished
410         transferBuffer->addMemoryBarrier(this,
411                                          VK_ACCESS_HOST_WRITE_BIT,
412                                          VK_ACCESS_TRANSFER_READ_BIT,
413                                          VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
414                                          VK_PIPELINE_STAGE_TRANSFER_BIT,
415                                          false);
416 
417         // Set up copy region
418         bool flipY = kBottomLeft_GrSurfaceOrigin == tex->origin();
419         VkOffset3D offset = {
420             left,
421             flipY ? tex->height() - top - height : top,
422             0
423         };
424 
425         VkBufferImageCopy region;
426         memset(&region, 0, sizeof(VkBufferImageCopy));
427         region.bufferOffset = 0;
428         region.bufferRowLength = width;
429         region.bufferImageHeight = height;
430         region.imageSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
431         region.imageOffset = offset;
432         region.imageExtent = { (uint32_t)width, (uint32_t)height, 1 };
433 
434         // Change layout of our target so it can be copied to
435         VkImageLayout layout = tex->currentLayout();
436         VkPipelineStageFlags srcStageMask = GrVkMemory::LayoutToPipelineStageFlags(layout);
437         VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
438         VkAccessFlags srcAccessMask = GrVkMemory::LayoutToSrcAccessMask(layout);
439         VkAccessFlags dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
440         tex->setImageLayout(this,
441                             VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
442                             srcAccessMask,
443                             dstAccessMask,
444                             srcStageMask,
445                             dstStageMask,
446                             false);
447 
448         // Copy the buffer to the image
449         fCurrentCmdBuffer->copyBufferToImage(this,
450                                              transferBuffer,
451                                              tex,
452                                              VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
453                                              1,
454                                              &region);
455 
456         // Submit the current command buffer to the Queue
457         this->submitCommandBuffer(kSkip_SyncQueue);
458 
459         transferBuffer->unref();
460     }
461 
462     return true;
463 }
464 
465 ////////////////////////////////////////////////////////////////////////////////
onCreateTexture(const GrSurfaceDesc & desc,GrGpuResource::LifeCycle lifeCycle,const void * srcData,size_t rowBytes)466 GrTexture* GrVkGpu::onCreateTexture(const GrSurfaceDesc& desc, GrGpuResource::LifeCycle lifeCycle,
467                                     const void* srcData, size_t rowBytes) {
468     bool renderTarget = SkToBool(desc.fFlags & kRenderTarget_GrSurfaceFlag);
469 
470     VkFormat pixelFormat;
471     if (!GrPixelConfigToVkFormat(desc.fConfig, &pixelFormat)) {
472         return nullptr;
473     }
474 
475     if (!fVkCaps->isConfigTexturable(desc.fConfig)) {
476         return nullptr;
477     }
478 
479     bool linearTiling = false;
480     if (SkToBool(desc.fFlags & kZeroCopy_GrSurfaceFlag)) {
481         if (fVkCaps->isConfigTexurableLinearly(desc.fConfig) &&
482             (!renderTarget || fVkCaps->isConfigRenderableLinearly(desc.fConfig, false))) {
483             linearTiling = true;
484         } else {
485             return nullptr;
486         }
487     }
488 
489     VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_SAMPLED_BIT;
490     if (renderTarget) {
491         usageFlags |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
492     }
493 
494     // For now we will set the VK_IMAGE_USAGE_TRANSFER_DESTINATION_BIT and
495     // VK_IMAGE_USAGE_TRANSFER_SOURCE_BIT on every texture since we do not know whether or not we
496     // will be using this texture in some copy or not. Also this assumes, as is the current case,
497     // that all render targets in vulkan are also texutres. If we change this practice of setting
498     // both bits, we must make sure to set the destination bit if we are uploading srcData to the
499     // texture.
500     usageFlags |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
501 
502     VkFlags memProps = (srcData && linearTiling) ? VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT :
503                                                    VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
504 
505     // This ImageDesc refers to the texture that will be read by the client. Thus even if msaa is
506     // requested, this ImageDesc describes the resolved texutre. Therefore we always have samples set
507     // to 1.
508     GrVkImage::ImageDesc imageDesc;
509     imageDesc.fImageType = VK_IMAGE_TYPE_2D;
510     imageDesc.fFormat = pixelFormat;
511     imageDesc.fWidth = desc.fWidth;
512     imageDesc.fHeight = desc.fHeight;
513     imageDesc.fLevels = 1;
514     imageDesc.fSamples = 1;
515     imageDesc.fImageTiling = linearTiling ? VK_IMAGE_TILING_LINEAR : VK_IMAGE_TILING_OPTIMAL;
516     imageDesc.fUsageFlags = usageFlags;
517     imageDesc.fMemProps = memProps;
518 
519     GrVkTexture* tex;
520     if (renderTarget) {
521         tex = GrVkTextureRenderTarget::CreateNewTextureRenderTarget(this, desc, lifeCycle,
522                                                                     imageDesc);
523     } else {
524         tex = GrVkTexture::CreateNewTexture(this, desc, lifeCycle, imageDesc);
525     }
526 
527     if (!tex) {
528         return nullptr;
529     }
530 
531     if (srcData) {
532         if (!this->uploadTexData(tex, 0, 0, desc.fWidth, desc.fHeight, desc.fConfig, srcData,
533                                  rowBytes)) {
534             tex->unref();
535             return nullptr;
536         }
537     }
538 
539     return tex;
540 }
541 
542 ////////////////////////////////////////////////////////////////////////////////
543 
resolve_origin(GrSurfaceOrigin origin)544 static GrSurfaceOrigin resolve_origin(GrSurfaceOrigin origin) {
545     // By default, all textures in Vk use TopLeft
546     if (kDefault_GrSurfaceOrigin == origin) {
547         return kTopLeft_GrSurfaceOrigin;
548     } else {
549         return origin;
550     }
551 }
552 
onWrapBackendTexture(const GrBackendTextureDesc & desc,GrWrapOwnership ownership)553 GrTexture* GrVkGpu::onWrapBackendTexture(const GrBackendTextureDesc& desc,
554                                          GrWrapOwnership ownership) {
555     VkFormat format;
556     if (!GrPixelConfigToVkFormat(desc.fConfig, &format)) {
557         return nullptr;
558     }
559 
560     if (0 == desc.fTextureHandle) {
561         return nullptr;
562     }
563 
564     int maxSize = this->caps()->maxTextureSize();
565     if (desc.fWidth > maxSize || desc.fHeight > maxSize) {
566         return nullptr;
567     }
568 
569     // TODO: determine what format Chrome will actually send us and turn it into a Resource
570     GrVkImage::Resource* imageRsrc = reinterpret_cast<GrVkImage::Resource*>(desc.fTextureHandle);
571 
572     GrGpuResource::LifeCycle lifeCycle;
573     switch (ownership) {
574         case kAdopt_GrWrapOwnership:
575             lifeCycle = GrGpuResource::kAdopted_LifeCycle;
576             break;
577         case kBorrow_GrWrapOwnership:
578             lifeCycle = GrGpuResource::kBorrowed_LifeCycle;
579             break;
580     }
581 
582     GrSurfaceDesc surfDesc;
583     // next line relies on GrBackendTextureDesc's flags matching GrTexture's
584     surfDesc.fFlags = (GrSurfaceFlags)desc.fFlags;
585     surfDesc.fWidth = desc.fWidth;
586     surfDesc.fHeight = desc.fHeight;
587     surfDesc.fConfig = desc.fConfig;
588     surfDesc.fSampleCnt = SkTMin(desc.fSampleCnt, this->caps()->maxSampleCount());
589     bool renderTarget = SkToBool(desc.fFlags & kRenderTarget_GrBackendTextureFlag);
590     // In GL, Chrome assumes all textures are BottomLeft
591     // In VK, we don't have this restriction
592     surfDesc.fOrigin = resolve_origin(desc.fOrigin);
593 
594     GrVkTexture* texture = nullptr;
595     if (renderTarget) {
596         texture = GrVkTextureRenderTarget::CreateWrappedTextureRenderTarget(this, surfDesc,
597                                                                             lifeCycle, format,
598                                                                             imageRsrc);
599     } else {
600         texture = GrVkTexture::CreateWrappedTexture(this, surfDesc, lifeCycle, format, imageRsrc);
601     }
602     if (!texture) {
603         return nullptr;
604     }
605 
606     return texture;
607 }
608 
onWrapBackendRenderTarget(const GrBackendRenderTargetDesc & wrapDesc,GrWrapOwnership ownership)609 GrRenderTarget* GrVkGpu::onWrapBackendRenderTarget(const GrBackendRenderTargetDesc& wrapDesc,
610                                                    GrWrapOwnership ownership) {
611 
612     // TODO: determine what format Chrome will actually send us and turn it into a Resource
613     GrVkImage::Resource* imageRsrc =
614         reinterpret_cast<GrVkImage::Resource*>(wrapDesc.fRenderTargetHandle);
615 
616     GrGpuResource::LifeCycle lifeCycle;
617     switch (ownership) {
618         case kAdopt_GrWrapOwnership:
619             lifeCycle = GrGpuResource::kAdopted_LifeCycle;
620             break;
621         case kBorrow_GrWrapOwnership:
622             lifeCycle = GrGpuResource::kBorrowed_LifeCycle;
623             break;
624     }
625 
626     GrSurfaceDesc desc;
627     desc.fConfig = wrapDesc.fConfig;
628     desc.fFlags = kCheckAllocation_GrSurfaceFlag;
629     desc.fWidth = wrapDesc.fWidth;
630     desc.fHeight = wrapDesc.fHeight;
631     desc.fSampleCnt = SkTMin(wrapDesc.fSampleCnt, this->caps()->maxSampleCount());
632 
633     desc.fOrigin = resolve_origin(wrapDesc.fOrigin);
634 
635     GrVkRenderTarget* tgt = GrVkRenderTarget::CreateWrappedRenderTarget(this, desc,
636                                                                         lifeCycle, imageRsrc);
637     if (tgt && wrapDesc.fStencilBits) {
638         if (!createStencilAttachmentForRenderTarget(tgt, desc.fWidth, desc.fHeight)) {
639             tgt->unref();
640             return nullptr;
641         }
642     }
643     return tgt;
644 }
645 
646 ////////////////////////////////////////////////////////////////////////////////
647 
bindGeometry(const GrPrimitiveProcessor & primProc,const GrNonInstancedVertices & vertices)648 void GrVkGpu::bindGeometry(const GrPrimitiveProcessor& primProc,
649                            const GrNonInstancedVertices& vertices) {
650     GrVkVertexBuffer* vbuf;
651     vbuf = (GrVkVertexBuffer*)vertices.vertexBuffer();
652     SkASSERT(vbuf);
653     SkASSERT(!vbuf->isMapped());
654 
655     vbuf->addMemoryBarrier(this,
656                            VK_ACCESS_HOST_WRITE_BIT,
657                            VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT,
658                            VK_PIPELINE_STAGE_HOST_BIT,
659                            VK_PIPELINE_STAGE_VERTEX_INPUT_BIT,
660                            false);
661 
662     fCurrentCmdBuffer->bindVertexBuffer(this, vbuf);
663 
664     if (vertices.isIndexed()) {
665         GrVkIndexBuffer* ibuf = (GrVkIndexBuffer*)vertices.indexBuffer();
666         SkASSERT(ibuf);
667         SkASSERT(!ibuf->isMapped());
668 
669         ibuf->addMemoryBarrier(this,
670                                VK_ACCESS_HOST_WRITE_BIT,
671                                VK_ACCESS_INDEX_READ_BIT,
672                                VK_PIPELINE_STAGE_HOST_BIT,
673                                VK_PIPELINE_STAGE_VERTEX_INPUT_BIT,
674                                false);
675 
676         fCurrentCmdBuffer->bindIndexBuffer(this, ibuf);
677     }
678 }
679 
buildProgramDesc(GrProgramDesc * desc,const GrPrimitiveProcessor & primProc,const GrPipeline & pipeline) const680 void GrVkGpu::buildProgramDesc(GrProgramDesc* desc,
681                                const GrPrimitiveProcessor& primProc,
682                                const GrPipeline& pipeline) const {
683     if (!GrVkProgramDescBuilder::Build(desc, primProc, pipeline, *this->vkCaps().glslCaps())) {
684         SkDEBUGFAIL("Failed to generate GL program descriptor");
685     }
686 }
687 
688 ////////////////////////////////////////////////////////////////////////////////
689 
createStencilAttachmentForRenderTarget(const GrRenderTarget * rt,int width,int height)690 GrStencilAttachment* GrVkGpu::createStencilAttachmentForRenderTarget(const GrRenderTarget* rt,
691                                                                      int width,
692                                                                      int height) {
693     SkASSERT(rt->asTexture());
694     SkASSERT(width >= rt->width());
695     SkASSERT(height >= rt->height());
696 
697     int samples = rt->numStencilSamples();
698 
699     SkASSERT(this->vkCaps().stencilFormats().count());
700     const GrVkCaps::StencilFormat& sFmt = this->vkCaps().stencilFormats()[0];
701 
702     GrVkStencilAttachment* stencil(GrVkStencilAttachment::Create(this,
703                                                                  GrGpuResource::kCached_LifeCycle,
704                                                                  width,
705                                                                  height,
706                                                                  samples,
707                                                                  sFmt));
708     fStats.incStencilAttachmentCreates();
709     return stencil;
710 }
711 
712 ////////////////////////////////////////////////////////////////////////////////
713 
createTestingOnlyBackendTexture(void * srcData,int w,int h,GrPixelConfig config)714 GrBackendObject GrVkGpu::createTestingOnlyBackendTexture(void* srcData, int w, int h,
715                                                          GrPixelConfig config) {
716 
717     VkFormat pixelFormat;
718     if (!GrPixelConfigToVkFormat(config, &pixelFormat)) {
719         return 0;
720     }
721 
722     bool linearTiling = false;
723     if (!fVkCaps->isConfigTexturable(config)) {
724         return 0;
725     }
726 
727     if (fVkCaps->isConfigTexurableLinearly(config)) {
728         linearTiling = true;
729     }
730 
731     // Currently this is not supported since it requires a copy which has not yet been implemented.
732     if (srcData && !linearTiling) {
733         return 0;
734     }
735 
736     VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_SAMPLED_BIT;
737     usageFlags |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
738     usageFlags |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
739 
740     VkFlags memProps = (srcData && linearTiling) ? VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT :
741                                                    VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
742 
743     // This ImageDesc refers to the texture that will be read by the client. Thus even if msaa is
744     // requested, this ImageDesc describes the resolved texutre. Therefore we always have samples set
745     // to 1.
746     GrVkImage::ImageDesc imageDesc;
747     imageDesc.fImageType = VK_IMAGE_TYPE_2D;
748     imageDesc.fFormat = pixelFormat;
749     imageDesc.fWidth = w;
750     imageDesc.fHeight = h;
751     imageDesc.fLevels = 1;
752     imageDesc.fSamples = 1;
753     imageDesc.fImageTiling = linearTiling ? VK_IMAGE_TILING_LINEAR : VK_IMAGE_TILING_OPTIMAL;
754     imageDesc.fUsageFlags = usageFlags;
755     imageDesc.fMemProps = memProps;
756 
757     const GrVkImage::Resource* imageRsrc = GrVkImage::CreateResource(this, imageDesc);
758     if (!imageRsrc) {
759         return 0;
760     }
761 
762     if (srcData) {
763         if (linearTiling) {
764             const VkImageSubresource subres = {
765                 VK_IMAGE_ASPECT_COLOR_BIT,
766                 0,  // mipLevel
767                 0,  // arraySlice
768             };
769             VkSubresourceLayout layout;
770             VkResult err;
771 
772             const GrVkInterface* interface = this->vkInterface();
773 
774             GR_VK_CALL(interface, GetImageSubresourceLayout(fDevice,
775                                                             imageRsrc->fImage,
776                                                             &subres,
777                                                             &layout));
778 
779             void* mapPtr;
780             err = GR_VK_CALL(interface, MapMemory(fDevice,
781                                                   imageRsrc->fAlloc,
782                                                   0,
783                                                   layout.rowPitch * h,
784                                                   0,
785                                                   &mapPtr));
786             if (err) {
787                 imageRsrc->unref(this);
788                 return 0;
789             }
790 
791             size_t bpp = GrBytesPerPixel(config);
792             size_t rowCopyBytes = bpp * w;
793             // If there is no padding on dst (layout.rowPitch) we can do a single memcopy.
794             // This assumes the srcData comes in with no padding.
795             if (rowCopyBytes == layout.rowPitch) {
796                 memcpy(mapPtr, srcData, rowCopyBytes * h);
797             } else {
798                 SkRectMemcpy(mapPtr, layout.rowPitch, srcData, w, rowCopyBytes, h);
799             }
800             GR_VK_CALL(interface, UnmapMemory(fDevice, imageRsrc->fAlloc));
801         } else {
802             // TODO: Add support for copying to optimal tiling
803             SkASSERT(false);
804         }
805     }
806 
807     return (GrBackendObject)imageRsrc;
808 }
809 
isTestingOnlyBackendTexture(GrBackendObject id) const810 bool GrVkGpu::isTestingOnlyBackendTexture(GrBackendObject id) const {
811     GrVkImage::Resource* backend = reinterpret_cast<GrVkImage::Resource*>(id);
812 
813     if (backend && backend->fImage && backend->fAlloc) {
814         VkMemoryRequirements req;
815         memset(&req, 0, sizeof(req));
816         GR_VK_CALL(this->vkInterface(), GetImageMemoryRequirements(fDevice,
817                                                                    backend->fImage,
818                                                                    &req));
819         // TODO: find a better check
820         // This will probably fail with a different driver
821         return (req.size > 0) && (req.size <= 8192 * 8192);
822     }
823 
824     return false;
825 }
826 
deleteTestingOnlyBackendTexture(GrBackendObject id,bool abandon)827 void GrVkGpu::deleteTestingOnlyBackendTexture(GrBackendObject id, bool abandon) {
828     GrVkImage::Resource* backend = reinterpret_cast<GrVkImage::Resource*>(id);
829 
830     if (backend) {
831         if (!abandon) {
832             backend->unref(this);
833         } else {
834             backend->unrefAndAbandon();
835         }
836     }
837 }
838 
839 ////////////////////////////////////////////////////////////////////////////////
840 
addMemoryBarrier(VkPipelineStageFlags srcStageMask,VkPipelineStageFlags dstStageMask,bool byRegion,VkMemoryBarrier * barrier) const841 void GrVkGpu::addMemoryBarrier(VkPipelineStageFlags srcStageMask,
842                                VkPipelineStageFlags dstStageMask,
843                                bool byRegion,
844                                VkMemoryBarrier* barrier) const {
845     SkASSERT(fCurrentCmdBuffer);
846     fCurrentCmdBuffer->pipelineBarrier(this,
847                                        srcStageMask,
848                                        dstStageMask,
849                                        byRegion,
850                                        GrVkCommandBuffer::kMemory_BarrierType,
851                                        barrier);
852 }
853 
addBufferMemoryBarrier(VkPipelineStageFlags srcStageMask,VkPipelineStageFlags dstStageMask,bool byRegion,VkBufferMemoryBarrier * barrier) const854 void GrVkGpu::addBufferMemoryBarrier(VkPipelineStageFlags srcStageMask,
855                                      VkPipelineStageFlags dstStageMask,
856                                      bool byRegion,
857                                      VkBufferMemoryBarrier* barrier) const {
858     SkASSERT(fCurrentCmdBuffer);
859     fCurrentCmdBuffer->pipelineBarrier(this,
860                                        srcStageMask,
861                                        dstStageMask,
862                                        byRegion,
863                                        GrVkCommandBuffer::kBufferMemory_BarrierType,
864                                        barrier);
865 }
866 
addImageMemoryBarrier(VkPipelineStageFlags srcStageMask,VkPipelineStageFlags dstStageMask,bool byRegion,VkImageMemoryBarrier * barrier) const867 void GrVkGpu::addImageMemoryBarrier(VkPipelineStageFlags srcStageMask,
868                                     VkPipelineStageFlags dstStageMask,
869                                     bool byRegion,
870                                     VkImageMemoryBarrier* barrier) const {
871     SkASSERT(fCurrentCmdBuffer);
872     fCurrentCmdBuffer->pipelineBarrier(this,
873                                        srcStageMask,
874                                        dstStageMask,
875                                        byRegion,
876                                        GrVkCommandBuffer::kImageMemory_BarrierType,
877                                        barrier);
878 }
879 
finishDrawTarget()880 void GrVkGpu::finishDrawTarget() {
881     // Submit the current command buffer to the Queue
882     this->submitCommandBuffer(kSkip_SyncQueue);
883 }
884 
onClear(GrRenderTarget * target,const SkIRect & rect,GrColor color)885 void GrVkGpu::onClear(GrRenderTarget* target, const SkIRect& rect, GrColor color) {
886     // parent class should never let us get here with no RT
887     SkASSERT(target);
888 
889     VkClearColorValue vkColor;
890     GrColorToRGBAFloat(color, vkColor.float32);
891 
892     GrVkRenderTarget* vkRT = static_cast<GrVkRenderTarget*>(target);
893     VkImageLayout origDstLayout = vkRT->currentLayout();
894 
895     if (rect.width() != target->width() || rect.height() != target->height()) {
896         VkAccessFlags srcAccessMask = GrVkMemory::LayoutToSrcAccessMask(origDstLayout);
897         VkAccessFlags dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
898         VkPipelineStageFlags srcStageMask =
899             GrVkMemory::LayoutToPipelineStageFlags(vkRT->currentLayout());
900         VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
901         vkRT->setImageLayout(this,
902                              VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
903                              srcAccessMask,
904                              dstAccessMask,
905                              srcStageMask,
906                              dstStageMask,
907                              false);
908 
909         VkClearRect clearRect;
910         clearRect.rect.offset = { rect.fLeft, rect.fTop };
911         clearRect.rect.extent = { (uint32_t)rect.width(), (uint32_t)rect.height() };
912         clearRect.baseArrayLayer = 0;
913         clearRect.layerCount = 1;
914 
915 
916 
917         const GrVkRenderPass* renderPass = vkRT->simpleRenderPass();
918         SkASSERT(renderPass);
919         fCurrentCmdBuffer->beginRenderPass(this, renderPass, *vkRT);
920 
921         uint32_t colorIndex;
922         SkAssertResult(renderPass->colorAttachmentIndex(&colorIndex));
923 
924         VkClearAttachment attachment;
925         attachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
926         attachment.colorAttachment = colorIndex;
927         attachment.clearValue.color = vkColor;
928 
929         fCurrentCmdBuffer->clearAttachments(this, 1, &attachment, 1, &clearRect);
930         fCurrentCmdBuffer->endRenderPass(this);
931         return;
932     }
933 
934     VkPipelineStageFlags srcStageMask = GrVkMemory::LayoutToPipelineStageFlags(origDstLayout);
935     VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
936 
937     VkAccessFlags srcAccessMask = GrVkMemory::LayoutToSrcAccessMask(origDstLayout);;
938     VkAccessFlags dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
939 
940     vkRT->setImageLayout(this,
941                          VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
942                          srcAccessMask,
943                          dstAccessMask,
944                          srcStageMask,
945                          dstStageMask,
946                          false);
947 
948 
949     VkImageSubresourceRange subRange;
950     memset(&subRange, 0, sizeof(VkImageSubresourceRange));
951     subRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
952     subRange.baseMipLevel = 0;
953     subRange.levelCount = 1;
954     subRange.baseArrayLayer = 0;
955     subRange.layerCount = 1;
956 
957     // In the future we may not actually be doing this type of clear at all. If we are inside a
958     // render pass or doing a non full clear then we will use CmdClearColorAttachment. The more
959     // common use case will be clearing an attachment at the start of a render pass, in which case
960     // we will use the clear load ops.
961     fCurrentCmdBuffer->clearColorImage(this,
962                                        vkRT,
963                                        &vkColor,
964                                        1, &subRange);
965 }
966 
can_copy_image(const GrSurface * dst,const GrSurface * src,const GrVkGpu * gpu)967 inline bool can_copy_image(const GrSurface* dst,
968                            const GrSurface* src,
969                            const GrVkGpu* gpu) {
970     if (src->asTexture() &&
971         dst->asTexture() &&
972         src->origin() == dst->origin() &&
973         src->config() == dst->config()) {
974         return true;
975     }
976 
977     // How does msaa play into this? If a VkTexture is multisampled, are we copying the multisampled
978     // or the resolved image here?
979 
980     return false;
981 }
982 
copySurfaceAsCopyImage(GrSurface * dst,GrSurface * src,const SkIRect & srcRect,const SkIPoint & dstPoint)983 void GrVkGpu::copySurfaceAsCopyImage(GrSurface* dst,
984                                      GrSurface* src,
985                                      const SkIRect& srcRect,
986                                      const SkIPoint& dstPoint) {
987     SkASSERT(can_copy_image(dst, src, this));
988 
989     // Insert memory barriers to switch src and dst to transfer_source and transfer_dst layouts
990     GrVkTexture* dstTex = static_cast<GrVkTexture*>(dst->asTexture());
991     GrVkTexture* srcTex = static_cast<GrVkTexture*>(src->asTexture());
992 
993     VkImageLayout origDstLayout = dstTex->currentLayout();
994     VkImageLayout origSrcLayout = srcTex->currentLayout();
995 
996     VkPipelineStageFlags srcStageMask = GrVkMemory::LayoutToPipelineStageFlags(origDstLayout);
997     VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
998 
999     // These flags are for flushing/invalidating caches and for the dst image it doesn't matter if
1000     // the cache is flushed since it is only being written to.
1001     VkAccessFlags srcAccessMask = GrVkMemory::LayoutToSrcAccessMask(origDstLayout);;
1002     VkAccessFlags dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
1003 
1004     dstTex->setImageLayout(this,
1005                            VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1006                            srcAccessMask,
1007                            dstAccessMask,
1008                            srcStageMask,
1009                            dstStageMask,
1010                            false);
1011 
1012     srcStageMask = GrVkMemory::LayoutToPipelineStageFlags(origSrcLayout);
1013     dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
1014 
1015     srcAccessMask = GrVkMemory::LayoutToSrcAccessMask(origSrcLayout);
1016     dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
1017 
1018     srcTex->setImageLayout(this,
1019                            VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
1020                            srcAccessMask,
1021                            dstAccessMask,
1022                            srcStageMask,
1023                            dstStageMask,
1024                            false);
1025 
1026     // Flip rect if necessary
1027     SkIRect srcVkRect = srcRect;
1028     int32_t dstY = dstPoint.fY;
1029 
1030     if (kBottomLeft_GrSurfaceOrigin == src->origin()) {
1031         SkASSERT(kBottomLeft_GrSurfaceOrigin == dst->origin());
1032         srcVkRect.fTop = src->height() - srcRect.fBottom;
1033         srcVkRect.fBottom =  src->height() - srcRect.fTop;
1034         dstY = dst->height() - dstPoint.fY - srcVkRect.height();
1035     }
1036 
1037     VkImageCopy copyRegion;
1038     memset(&copyRegion, 0, sizeof(VkImageCopy));
1039     copyRegion.srcSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
1040     copyRegion.srcOffset = { srcVkRect.fLeft, srcVkRect.fTop, 0 };
1041     copyRegion.dstSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
1042     copyRegion.dstOffset = { dstPoint.fX, dstY, 0 };
1043     copyRegion.extent = { (uint32_t)srcVkRect.width(), (uint32_t)srcVkRect.height(), 0 };
1044 
1045     fCurrentCmdBuffer->copyImage(this,
1046                                  srcTex,
1047                                  VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
1048                                  dstTex,
1049                                  VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1050                                  1,
1051                                  &copyRegion);
1052 }
1053 
can_copy_as_draw(const GrSurface * dst,const GrSurface * src,const GrVkGpu * gpu)1054 inline bool can_copy_as_draw(const GrSurface* dst,
1055                              const GrSurface* src,
1056                              const GrVkGpu* gpu) {
1057     return false;
1058 }
1059 
copySurfaceAsDraw(GrSurface * dst,GrSurface * src,const SkIRect & srcRect,const SkIPoint & dstPoint)1060 void GrVkGpu::copySurfaceAsDraw(GrSurface* dst,
1061                                 GrSurface* src,
1062                                 const SkIRect& srcRect,
1063                                 const SkIPoint& dstPoint) {
1064     SkASSERT(false);
1065 }
1066 
onCopySurface(GrSurface * dst,GrSurface * src,const SkIRect & srcRect,const SkIPoint & dstPoint)1067 bool GrVkGpu::onCopySurface(GrSurface* dst,
1068                             GrSurface* src,
1069                             const SkIRect& srcRect,
1070                             const SkIPoint& dstPoint) {
1071     if (can_copy_image(dst, src, this)) {
1072         this->copySurfaceAsCopyImage(dst, src, srcRect, dstPoint);
1073         return true;
1074     }
1075 
1076     if (can_copy_as_draw(dst, src, this)) {
1077         this->copySurfaceAsDraw(dst, src, srcRect, dstPoint);
1078         return true;
1079     }
1080 
1081     return false;
1082 }
1083 
onGetReadPixelsInfo(GrSurface * srcSurface,int width,int height,size_t rowBytes,GrPixelConfig readConfig,DrawPreference * drawPreference,ReadPixelTempDrawInfo * tempDrawInfo)1084 bool GrVkGpu::onGetReadPixelsInfo(GrSurface* srcSurface, int width, int height, size_t rowBytes,
1085                                   GrPixelConfig readConfig, DrawPreference* drawPreference,
1086                                   ReadPixelTempDrawInfo* tempDrawInfo) {
1087     // Currently we don't handle draws, so if the caller wants/needs to do a draw we need to fail
1088     if (kNoDraw_DrawPreference != *drawPreference) {
1089         return false;
1090     }
1091 
1092     if (srcSurface->config() != readConfig) {
1093         // TODO: This should fall back to drawing or copying to change config of srcSurface to match
1094         // that of readConfig.
1095         return false;
1096     }
1097 
1098     return true;
1099 }
1100 
onReadPixels(GrSurface * surface,int left,int top,int width,int height,GrPixelConfig config,void * buffer,size_t rowBytes)1101 bool GrVkGpu::onReadPixels(GrSurface* surface,
1102                            int left, int top, int width, int height,
1103                            GrPixelConfig config,
1104                            void* buffer,
1105                            size_t rowBytes) {
1106     VkFormat pixelFormat;
1107     if (!GrPixelConfigToVkFormat(config, &pixelFormat)) {
1108         return false;
1109     }
1110 
1111     GrVkTexture* tgt = static_cast<GrVkTexture*>(surface->asTexture());
1112     if (!tgt) {
1113         return false;
1114     }
1115 
1116     // Change layout of our target so it can be used as copy
1117     VkImageLayout layout = tgt->currentLayout();
1118     VkPipelineStageFlags srcStageMask = GrVkMemory::LayoutToPipelineStageFlags(layout);
1119     VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
1120     VkAccessFlags srcAccessMask = GrVkMemory::LayoutToSrcAccessMask(layout);
1121     VkAccessFlags dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
1122     tgt->setImageLayout(this,
1123                         VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
1124                         srcAccessMask,
1125                         dstAccessMask,
1126                         srcStageMask,
1127                         dstStageMask,
1128                         false);
1129 
1130     GrVkTransferBuffer* transferBuffer =
1131         reinterpret_cast<GrVkTransferBuffer*>(this->createTransferBuffer(rowBytes * height,
1132                                                                          kGpuToCpu_TransferType));
1133 
1134     bool flipY = kBottomLeft_GrSurfaceOrigin == surface->origin();
1135     VkOffset3D offset = {
1136         left,
1137         flipY ? surface->height() - top - height : top,
1138         0
1139     };
1140 
1141     // Copy the image to a buffer so we can map it to cpu memory
1142     VkBufferImageCopy region;
1143     memset(&region, 0, sizeof(VkBufferImageCopy));
1144     region.bufferOffset = 0;
1145     region.bufferRowLength = 0; // Forces RowLength to be imageExtent.width
1146     region.bufferImageHeight = 0; // Forces height to be tightly packed. Only useful for 3d images.
1147     region.imageSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
1148     region.imageOffset = offset;
1149     region.imageExtent = { (uint32_t)width, (uint32_t)height, 1 };
1150 
1151     fCurrentCmdBuffer->copyImageToBuffer(this,
1152                                          tgt,
1153                                          VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
1154                                          transferBuffer,
1155                                          1,
1156                                          &region);
1157 
1158     // make sure the copy to buffer has finished
1159     transferBuffer->addMemoryBarrier(this,
1160                                      VK_ACCESS_TRANSFER_WRITE_BIT,
1161                                      VK_ACCESS_HOST_READ_BIT,
1162                                      VK_PIPELINE_STAGE_TRANSFER_BIT,
1163                                      VK_PIPELINE_STAGE_HOST_BIT,
1164                                      false);
1165 
1166     // We need to submit the current command buffer to the Queue and make sure it finishes before
1167     // we can copy the data out of the buffer.
1168     this->submitCommandBuffer(kForce_SyncQueue);
1169 
1170     void* mappedMemory = transferBuffer->map();
1171 
1172     memcpy(buffer, mappedMemory, rowBytes*height);
1173 
1174     transferBuffer->unmap();
1175     transferBuffer->unref();
1176 
1177     if (flipY) {
1178         SkAutoSMalloc<32 * sizeof(GrColor)> scratch;
1179         size_t tightRowBytes = GrBytesPerPixel(config) * width;
1180         scratch.reset(tightRowBytes);
1181         void* tmpRow = scratch.get();
1182         // flip y in-place by rows
1183         const int halfY = height >> 1;
1184         char* top = reinterpret_cast<char*>(buffer);
1185         char* bottom = top + (height - 1) * rowBytes;
1186         for (int y = 0; y < halfY; y++) {
1187             memcpy(tmpRow, top, tightRowBytes);
1188             memcpy(top, bottom, tightRowBytes);
1189             memcpy(bottom, tmpRow, tightRowBytes);
1190             top += rowBytes;
1191             bottom -= rowBytes;
1192         }
1193     }
1194 
1195     return true;
1196 }
1197 
onDraw(const DrawArgs & args,const GrNonInstancedVertices & vertices)1198 void GrVkGpu::onDraw(const DrawArgs& args, const GrNonInstancedVertices& vertices) {
1199     GrRenderTarget* rt = args.fPipeline->getRenderTarget();
1200     GrVkRenderTarget* vkRT = static_cast<GrVkRenderTarget*>(rt);
1201     const GrVkRenderPass* renderPass = vkRT->simpleRenderPass();
1202     SkASSERT(renderPass);
1203 
1204 
1205     GrVkProgram* program = GrVkProgramBuilder::CreateProgram(this, args,
1206                                                              vertices.primitiveType(),
1207                                                              *renderPass);
1208 
1209     if (!program) {
1210         return;
1211     }
1212 
1213     program->setData(this, *args.fPrimitiveProcessor, *args.fPipeline);
1214 
1215     fCurrentCmdBuffer->beginRenderPass(this, renderPass, *vkRT);
1216 
1217     program->bind(this, fCurrentCmdBuffer);
1218 
1219     this->bindGeometry(*args.fPrimitiveProcessor, vertices);
1220 
1221     // Change layout of our render target so it can be used as the color attachment
1222     VkImageLayout layout = vkRT->currentLayout();
1223     // Our color attachment is purely a destination and won't be read so don't need to flush or
1224     // invalidate any caches
1225     VkPipelineStageFlags srcStageMask = GrVkMemory::LayoutToPipelineStageFlags(layout);
1226     VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
1227     VkAccessFlags srcAccessMask = GrVkMemory::LayoutToSrcAccessMask(layout);
1228     VkAccessFlags dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
1229     vkRT->setImageLayout(this,
1230                          VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
1231                          srcAccessMask,
1232                          dstAccessMask,
1233                          srcStageMask,
1234                          dstStageMask,
1235                          false);
1236 
1237     if (vertices.isIndexed()) {
1238         fCurrentCmdBuffer->drawIndexed(this,
1239                                        vertices.indexCount(),
1240                                        1,
1241                                        vertices.startIndex(),
1242                                        vertices.startVertex(),
1243                                        0);
1244     } else {
1245         fCurrentCmdBuffer->draw(this, vertices.vertexCount(), 1, vertices.startVertex(),  0);
1246     }
1247 
1248     fCurrentCmdBuffer->endRenderPass(this);
1249 
1250     // Technically we don't have to call this here (since there is a safety check in program:setData
1251     // but this will allow for quicker freeing of resources if the program sits in a cache for a
1252     // while.
1253     program->freeTempResources(this);
1254     // This free will go away once we setup a program cache, and then the cache will be responsible
1255     // for call freeGpuResources.
1256     program->freeGPUResources(this);
1257     program->unref();
1258 
1259 #if SWAP_PER_DRAW
1260     glFlush();
1261 #if defined(SK_BUILD_FOR_MAC)
1262     aglSwapBuffers(aglGetCurrentContext());
1263     int set_a_break_pt_here = 9;
1264     aglSwapBuffers(aglGetCurrentContext());
1265 #elif defined(SK_BUILD_FOR_WIN32)
1266     SwapBuf();
1267     int set_a_break_pt_here = 9;
1268     SwapBuf();
1269 #endif
1270 #endif
1271 }
1272 
1273