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