| OLD | NEW |
| (Empty) |
| 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& op
tions, | |
| 49 GrContext* context) { | |
| 50 // Below is Vulkan setup code that normal would be done by a client, but wil
l 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 arr
ay. | |
| 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*)queuePropsAl
loc.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, VkCom
mandPool 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::kCopyWrit
e_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* draw
Preference, | |
| 241 WritePixelTempDrawInfo* tempDrawInfo) { | |
| 242 if (kIndex_8_GrPixelConfig == srcConfig || GrPixelConfigIsCompressed(dstSurf
ace->config())) { | |
| 243 return false; | |
| 244 } | |
| 245 | |
| 246 // Currently we don't handle draws, so if the caller wants/needs to do a dra
w 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->currentLayo
ut()) { | |
| 287 // Need to change the layout to general in order to perform a host w
rite | |
| 288 VkImageLayout layout = vkTex->currentLayout(); | |
| 289 VkPipelineStageFlags srcStageMask = GrVkMemory::LayoutToPipelineStag
eFlags(layout); | |
| 290 VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_HOST_BIT; | |
| 291 VkAccessFlags srcAccessMask = GrVkMemory::LayoutToSrcAccessMask(layo
ut); | |
| 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 uploadCompress
edTexData | |
| 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(), off
set, 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.r
owPitch; | |
| 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.rowPi
tch) 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, trimRowByt
es, 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)*trimRowB
ytes; | |
| 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 m
emcpy | |
| 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::LayoutToPipelineStageFla
gs(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_OPTIMA
L, | |
| 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::Li
feCycle 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 pr
actice of setting | |
| 498 // both bits, we must make sure to set the destination bit if we are uploadi
ng 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_VISIB
LE_BIT : | |
| 503 VK_MEMORY_PROPERTY_DEVICE_LOC
AL_BIT; | |
| 504 | |
| 505 // This ImageDesc refers to the texture that will be read by the client. Thu
s even if msaa is | |
| 506 // requested, this ImageDesc describes the resolved texutre. Therefore we al
ways 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_TI
LING_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.fCon
fig, 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_GrBackendTextureFla
g); | |
| 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 life
Cycle, format, | |
| 598 imag
eRsrc); | |
| 599 } else { | |
| 600 texture = GrVkTexture::CreateWrappedTexture(this, surfDesc, lifeCycle, f
ormat, imageRsrc); | |
| 601 } | |
| 602 if (!texture) { | |
| 603 return nullptr; | |
| 604 } | |
| 605 | |
| 606 return texture; | |
| 607 } | |
| 608 | |
| 609 GrRenderTarget* GrVkGpu::onWrapBackendRenderTarget(const GrBackendRenderTargetDe
sc& 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, de
sc, | |
| 636 lifeCycl
e, imageRsrc); | |
| 637 if (tgt && wrapDesc.fStencilBits) { | |
| 638 if (!createStencilAttachmentForRenderTarget(tgt, desc.fWidth, desc.fHeig
ht)) { | |
| 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 GrRen
derTarget* 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, i
nt 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 ye
t 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_VISIB
LE_BIT : | |
| 741 VK_MEMORY_PROPERTY_DEVICE_LOC
AL_BIT; | |
| 742 | |
| 743 // This ImageDesc refers to the texture that will be read by the client. Thu
s even if msaa is | |
| 744 // requested, this ImageDesc describes the resolved texutre. Therefore we al
ways 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_TI
LING_OPTIMAL; | |
| 754 imageDesc.fUsageFlags = usageFlags; | |
| 755 imageDesc.fMemProps = memProps; | |
| 756 | |
| 757 const GrVkImage::Resource* imageRsrc = GrVkImage::CreateResource(this, image
Desc); | |
| 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 singl
e 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->fIma
ge, | |
| 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_BarrierT
ype, | |
| 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_BarrierTy
pe, | |
| 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(origDstL
ayout); | |
| 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(o
rigDstLayout); | |
| 935 VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT; | |
| 936 | |
| 937 VkAccessFlags srcAccessMask = GrVkMemory::LayoutToSrcAccessMask(origDstLayou
t);; | |
| 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 CmdClearColorAttac
hment. The more | |
| 959 // common use case will be clearing an attachment at the start of a render p
ass, 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 copy
ing 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 trans
fer_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(o
rigDstLayout); | |
| 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(origDstLayou
t);; | |
| 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.heigh
t(), 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* draw
Preference, | |
| 1086 ReadPixelTempDrawInfo* tempDrawInfo) { | |
| 1087 // Currently we don't handle draws, so if the caller wants/needs to do a dra
w 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(l
ayout); | |
| 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(rowByte
s * height, | |
| 1132 kGpuToC
pu_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 us
eful 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 i
t 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& vertice
s) { | |
| 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.primitiveT
ype(), | |
| 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 attachm
ent | |
| 1222 VkImageLayout layout = vkRT->currentLayout(); | |
| 1223 // Our color attachment is purely a destination and won't be read so don't n
eed to flush or | |
| 1224 // invalidate any caches | |
| 1225 VkPipelineStageFlags srcStageMask = GrVkMemory::LayoutToPipelineStageFlags(l
ayout); | |
| 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.startV
ertex(), 0); | |
| 1246 } | |
| 1247 | |
| 1248 fCurrentCmdBuffer->endRenderPass(this); | |
| 1249 | |
| 1250 // Technically we don't have to call this here (since there is a safety chec
k 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 | |
| OLD | NEW |