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