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.
48GrGpu* 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
168GrVkGpu::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
190GrVkGpu::~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
208void 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///////////////////////////////////////////////////////////////////////////////
224GrVertexBuffer* GrVkGpu::onCreateVertexBuffer(size_t size, bool dynamic) {
225    return GrVkVertexBuffer::Create(this, size, dynamic);
226}
227
228GrIndexBuffer* GrVkGpu::onCreateIndexBuffer(size_t size, bool dynamic) {
229    return GrVkIndexBuffer::Create(this, size, dynamic);
230}
231
232GrTransferBuffer* 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////////////////////////////////////////////////////////////////////////////////
239bool 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
260bool 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
313bool 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////////////////////////////////////////////////////////////////////////////////
466GrTexture* 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
544static 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
553GrTexture* 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
609GrRenderTarget* 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
648void 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
680void 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
690GrStencilAttachment* 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
714GrBackendObject 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
810bool 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
827void 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
841void 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
854void 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
867void 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
880void GrVkGpu::finishDrawTarget() {
881    // Submit the current command buffer to the Queue
882    this->submitCommandBuffer(kSkip_SyncQueue);
883}
884
885void 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
967inline 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
983void 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
1054inline bool can_copy_as_draw(const GrSurface* dst,
1055                             const GrSurface* src,
1056                             const GrVkGpu* gpu) {
1057    return false;
1058}
1059
1060void GrVkGpu::copySurfaceAsDraw(GrSurface* dst,
1061                                GrSurface* src,
1062                                const SkIRect& srcRect,
1063                                const SkIPoint& dstPoint) {
1064    SkASSERT(false);
1065}
1066
1067bool 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
1084bool 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
1101bool 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
1198void 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