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