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