Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright 2015 Google Inc. | 2 * Copyright 2015 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 #include "GrVkGpu.h" | 8 #include "GrVkGpu.h" |
| 9 | 9 |
| 10 #include "GrContextOptions.h" | 10 #include "GrContextOptions.h" |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 23 #include "GrVkPipeline.h" | 23 #include "GrVkPipeline.h" |
| 24 #include "GrVkPipelineState.h" | 24 #include "GrVkPipelineState.h" |
| 25 #include "GrVkRenderPass.h" | 25 #include "GrVkRenderPass.h" |
| 26 #include "GrVkResourceProvider.h" | 26 #include "GrVkResourceProvider.h" |
| 27 #include "GrVkTexture.h" | 27 #include "GrVkTexture.h" |
| 28 #include "GrVkTextureRenderTarget.h" | 28 #include "GrVkTextureRenderTarget.h" |
| 29 #include "GrVkTransferBuffer.h" | 29 #include "GrVkTransferBuffer.h" |
| 30 #include "GrVkVertexBuffer.h" | 30 #include "GrVkVertexBuffer.h" |
| 31 | 31 |
| 32 #include "SkConfig8888.h" | 32 #include "SkConfig8888.h" |
| 33 #include "SkMipMap.h" | |
| 33 | 34 |
| 34 #include "vk/GrVkInterface.h" | 35 #include "vk/GrVkInterface.h" |
| 35 #include "vk/GrVkTypes.h" | 36 #include "vk/GrVkTypes.h" |
| 36 | 37 |
| 37 #define VK_CALL(X) GR_VK_CALL(this->vkInterface(), X) | 38 #define VK_CALL(X) GR_VK_CALL(this->vkInterface(), X) |
| 38 #define VK_CALL_RET(RET, X) GR_VK_CALL_RET(this->vkInterface(), RET, X) | 39 #define VK_CALL_RET(RET, X) GR_VK_CALL_RET(this->vkInterface(), RET, X) |
| 39 #define VK_CALL_ERRCHECK(X) GR_VK_CALL_ERRCHECK(this->vkInterface(), X) | 40 #define VK_CALL_ERRCHECK(X) GR_VK_CALL_ERRCHECK(this->vkInterface(), X) |
| 40 | 41 |
| 41 #ifdef ENABLE_VK_LAYERS | 42 #ifdef ENABLE_VK_LAYERS |
| 42 VKAPI_ATTR VkBool32 VKAPI_CALL DebugReportCallback( | 43 VKAPI_ATTR VkBool32 VKAPI_CALL DebugReportCallback( |
| (...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 228 | 229 |
| 229 bool GrVkGpu::onWritePixels(GrSurface* surface, | 230 bool GrVkGpu::onWritePixels(GrSurface* surface, |
| 230 int left, int top, int width, int height, | 231 int left, int top, int width, int height, |
| 231 GrPixelConfig config, | 232 GrPixelConfig config, |
| 232 const SkTArray<GrMipLevel>& texels) { | 233 const SkTArray<GrMipLevel>& texels) { |
| 233 GrVkTexture* vkTex = static_cast<GrVkTexture*>(surface->asTexture()); | 234 GrVkTexture* vkTex = static_cast<GrVkTexture*>(surface->asTexture()); |
| 234 if (!vkTex) { | 235 if (!vkTex) { |
| 235 return false; | 236 return false; |
| 236 } | 237 } |
| 237 | 238 |
| 238 // TODO: We're ignoring MIP levels here. | 239 // Make sure we have at least the base level |
| 239 if (texels.empty() || !texels.begin()->fPixels) { | 240 if (texels.empty() || !texels.begin()->fPixels) { |
| 240 return false; | 241 return false; |
| 241 } | 242 } |
| 242 | 243 |
| 243 // We assume Vulkan doesn't do sRGB <-> linear conversions when reading and writing pixels. | 244 // We assume Vulkan doesn't do sRGB <-> linear conversions when reading and writing pixels. |
| 244 if (GrPixelConfigIsSRGB(surface->config()) != GrPixelConfigIsSRGB(config)) { | 245 if (GrPixelConfigIsSRGB(surface->config()) != GrPixelConfigIsSRGB(config)) { |
| 245 return false; | 246 return false; |
| 246 } | 247 } |
| 247 | 248 |
| 248 bool success = false; | 249 bool success = false; |
| 249 if (GrPixelConfigIsCompressed(vkTex->desc().fConfig)) { | 250 if (GrPixelConfigIsCompressed(vkTex->desc().fConfig)) { |
| 250 // We check that config == desc.fConfig in GrGpu::getWritePixelsInfo() | 251 // We check that config == desc.fConfig in GrGpu::getWritePixelsInfo() |
| 251 SkASSERT(config == vkTex->desc().fConfig); | 252 SkASSERT(config == vkTex->desc().fConfig); |
| 252 // TODO: add compressed texture support | 253 // TODO: add compressed texture support |
| 253 // delete the following two lines and uncomment the two after that when ready | 254 // delete the following two lines and uncomment the two after that when ready |
| 254 vkTex->unref(); | 255 vkTex->unref(); |
| 255 return false; | 256 return false; |
| 256 //success = this->uploadCompressedTexData(vkTex->desc(), buffer, false, left, top, width, | 257 //success = this->uploadCompressedTexData(vkTex->desc(), buffer, false, left, top, width, |
| 257 // height); | 258 // height); |
| 258 } else { | 259 } else { |
| 259 bool linearTiling = vkTex->isLinearTiled(); | 260 bool linearTiling = vkTex->isLinearTiled(); |
| 260 if (linearTiling && VK_IMAGE_LAYOUT_PREINITIALIZED != vkTex->currentLayo ut()) { | 261 if (linearTiling) { |
| 261 // Need to change the layout to general in order to perform a host w rite | 262 if (texels.count() > 1) { |
| 262 VkImageLayout layout = vkTex->currentLayout(); | 263 SkDebugf("Can't upload mipmap data to linear tiled texture"); |
| 263 VkPipelineStageFlags srcStageMask = GrVkMemory::LayoutToPipelineStag eFlags(layout); | 264 return false; |
| 264 VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_HOST_BIT; | 265 } |
| 265 VkAccessFlags srcAccessMask = GrVkMemory::LayoutToSrcAccessMask(layo ut); | 266 if (VK_IMAGE_LAYOUT_PREINITIALIZED != vkTex->currentLayout()) { |
| 266 VkAccessFlags dstAccessMask = VK_ACCESS_HOST_WRITE_BIT; | 267 // Need to change the layout to general in order to perform a ho st write |
| 267 vkTex->setImageLayout(this, | 268 VkImageLayout layout = vkTex->currentLayout(); |
| 268 VK_IMAGE_LAYOUT_GENERAL, | 269 VkPipelineStageFlags srcStageMask = GrVkMemory::LayoutToPipeline StageFlags(layout); |
| 269 srcAccessMask, | 270 VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_HOST_BIT; |
| 270 dstAccessMask, | 271 VkAccessFlags srcAccessMask = GrVkMemory::LayoutToSrcAccessMask( layout); |
| 271 srcStageMask, | 272 VkAccessFlags dstAccessMask = VK_ACCESS_HOST_WRITE_BIT; |
| 272 dstStageMask, | 273 vkTex->setImageLayout(this, |
| 273 false); | 274 VK_IMAGE_LAYOUT_GENERAL, |
| 275 srcAccessMask, | |
| 276 dstAccessMask, | |
| 277 srcStageMask, | |
| 278 dstStageMask, | |
| 279 false); | |
| 280 } | |
| 281 success = this->uploadTexDataLinear(vkTex, left, top, width, height, config, | |
| 282 texels.begin()->fPixels, texels. begin()->fRowBytes); | |
| 283 } else { | |
| 284 uint32_t mipLevels = texels.count(); | |
| 285 if (vkTex->texturePriv().maxMipMapLevel() != mipLevels) { | |
| 286 if (!vkTex->reallocForMipmap(this, mipLevels)) { | |
| 287 return false; | |
| 288 } | |
| 289 } | |
| 290 success = this->uploadTexDataOptimal(vkTex, left, top, width, height , config, texels); | |
| 274 } | 291 } |
| 275 success = this->uploadTexData(vkTex, left, top, width, height, config, | |
| 276 texels.begin()->fPixels, texels.begin()->f RowBytes); | |
| 277 } | 292 } |
| 278 | 293 |
| 279 if (success) { | 294 return success; |
| 280 vkTex->texturePriv().dirtyMipMaps(true); | |
| 281 return true; | |
| 282 } | |
| 283 | |
| 284 return false; | |
| 285 } | 295 } |
| 286 | 296 |
| 287 bool GrVkGpu::uploadTexData(GrVkTexture* tex, | 297 bool GrVkGpu::uploadTexDataLinear(GrVkTexture* tex, |
| 288 int left, int top, int width, int height, | 298 int left, int top, int width, int height, |
| 289 GrPixelConfig dataConfig, | 299 GrPixelConfig dataConfig, |
| 290 const void* data, | 300 const void* data, |
| 291 size_t rowBytes) { | 301 size_t rowBytes) { |
| 292 SkASSERT(data); | 302 SkASSERT(data); |
| 303 SkASSERT(tex->isLinearTiled()); | |
| 293 | 304 |
| 294 // If we're uploading compressed data then we should be using uploadCompress edTexData | 305 // If we're uploading compressed data then we should be using uploadCompress edTexData |
| 295 SkASSERT(!GrPixelConfigIsCompressed(dataConfig)); | 306 SkASSERT(!GrPixelConfigIsCompressed(dataConfig)); |
| 296 | 307 |
| 297 bool linearTiling = tex->isLinearTiled(); | |
| 298 | |
| 299 size_t bpp = GrBytesPerPixel(dataConfig); | 308 size_t bpp = GrBytesPerPixel(dataConfig); |
| 300 | 309 |
| 301 const GrSurfaceDesc& desc = tex->desc(); | 310 const GrSurfaceDesc& desc = tex->desc(); |
| 302 | 311 |
| 303 if (!GrSurfacePriv::AdjustWritePixelParams(desc.fWidth, desc.fHeight, bpp, & left, &top, | 312 if (!GrSurfacePriv::AdjustWritePixelParams(desc.fWidth, desc.fHeight, bpp, & left, &top, |
| 304 &width, &height, &data, &rowBytes )) { | 313 &width, &height, &data, &rowBytes )) { |
| 305 return false; | 314 return false; |
| 306 } | 315 } |
| 307 size_t trimRowBytes = width * bpp; | 316 size_t trimRowBytes = width * bpp; |
| 308 | 317 |
| 309 if (linearTiling) { | 318 SkASSERT(VK_IMAGE_LAYOUT_PREINITIALIZED == tex->currentLayout() || |
| 310 SkASSERT(VK_IMAGE_LAYOUT_PREINITIALIZED == tex->currentLayout() || | 319 VK_IMAGE_LAYOUT_GENERAL == tex->currentLayout()); |
| 311 VK_IMAGE_LAYOUT_GENERAL == tex->currentLayout()); | 320 const VkImageSubresource subres = { |
| 312 const VkImageSubresource subres = { | 321 VK_IMAGE_ASPECT_COLOR_BIT, |
| 313 VK_IMAGE_ASPECT_COLOR_BIT, | 322 0, // mipLevel |
| 314 0, // mipLevel | 323 0, // arraySlice |
| 315 0, // arraySlice | 324 }; |
| 316 }; | 325 VkSubresourceLayout layout; |
| 317 VkSubresourceLayout layout; | 326 VkResult err; |
| 318 VkResult err; | |
| 319 | 327 |
| 320 const GrVkInterface* interface = this->vkInterface(); | 328 const GrVkInterface* interface = this->vkInterface(); |
| 321 | 329 |
| 322 GR_VK_CALL(interface, GetImageSubresourceLayout(fDevice, | 330 GR_VK_CALL(interface, GetImageSubresourceLayout(fDevice, |
| 323 tex->textureImage(), | 331 tex->textureImage(), |
| 324 &subres, | 332 &subres, |
| 325 &layout)); | 333 &layout)); |
| 326 | 334 |
| 327 int texTop = kBottomLeft_GrSurfaceOrigin == desc.fOrigin ? tex->height() - top - height | 335 int texTop = kBottomLeft_GrSurfaceOrigin == desc.fOrigin ? tex->height() - t op - height : top; |
| 328 : top; | 336 VkDeviceSize offset = texTop*layout.rowPitch + left*bpp; |
| 329 VkDeviceSize offset = texTop*layout.rowPitch + left*bpp; | 337 VkDeviceSize size = height*layout.rowPitch; |
| 330 VkDeviceSize size = height*layout.rowPitch; | 338 void* mapPtr; |
| 331 void* mapPtr; | 339 err = GR_VK_CALL(interface, MapMemory(fDevice, tex->textureMemory(), offset, size, 0, |
| 332 err = GR_VK_CALL(interface, MapMemory(fDevice, tex->textureMemory(), off set, size, 0, | 340 &mapPtr)); |
| 333 &mapPtr)); | 341 if (err) { |
| 334 if (err) { | 342 return false; |
| 343 } | |
| 344 | |
| 345 if (kBottomLeft_GrSurfaceOrigin == desc.fOrigin) { | |
| 346 // copy into buffer by rows | |
| 347 const char* srcRow = reinterpret_cast<const char*>(data); | |
| 348 char* dstRow = reinterpret_cast<char*>(mapPtr)+(height - 1)*layout.rowPi tch; | |
| 349 for (int y = 0; y < height; y++) { | |
| 350 memcpy(dstRow, srcRow, trimRowBytes); | |
| 351 srcRow += rowBytes; | |
| 352 dstRow -= layout.rowPitch; | |
| 353 } | |
| 354 } else { | |
| 355 // If there is no padding on the src (rowBytes) or dst (layout.rowPitch) we can memcpy | |
| 356 if (trimRowBytes == rowBytes && trimRowBytes == layout.rowPitch) { | |
| 357 memcpy(mapPtr, data, trimRowBytes * height); | |
| 358 } else { | |
| 359 SkRectMemcpy(mapPtr, static_cast<size_t>(layout.rowPitch), data, row Bytes, | |
| 360 trimRowBytes, height); | |
| 361 } | |
| 362 } | |
| 363 | |
| 364 GR_VK_CALL(interface, UnmapMemory(fDevice, tex->textureMemory())); | |
| 365 | |
| 366 return true; | |
| 367 } | |
| 368 | |
| 369 bool GrVkGpu::uploadTexDataOptimal(GrVkTexture* tex, | |
| 370 int left, int top, int width, int height, | |
| 371 GrPixelConfig dataConfig, | |
| 372 const SkTArray<GrMipLevel>& texels) { | |
| 373 SkASSERT(!tex->isLinearTiled()); | |
| 374 // The assumption is either that we have no mipmaps, or that our rect is the entire texture | |
| 375 SkASSERT(1 == texels.count() || | |
| 376 (0 == left && 0 == top && width == tex->width() && height == tex->h eight())); | |
| 377 | |
| 378 // If we're uploading compressed data then we should be using uploadCompress edTexData | |
| 379 SkASSERT(!GrPixelConfigIsCompressed(dataConfig)); | |
| 380 | |
| 381 if (width == 0 || height == 0) { | |
| 382 return false; | |
| 383 } | |
| 384 | |
| 385 const GrSurfaceDesc& desc = tex->desc(); | |
| 386 SkASSERT(this->caps()->isConfigTexturable(desc.fConfig)); | |
| 387 size_t bpp = GrBytesPerPixel(dataConfig); | |
| 388 | |
| 389 // texels is const. | |
| 390 // But we may need to adjust the fPixels ptr based on the copyRect. | |
| 391 // In this case we need to make a non-const shallow copy of texels. | |
| 392 const SkTArray<GrMipLevel>* texelsPtr = &texels; | |
| 393 SkTArray<GrMipLevel> texelsCopy; | |
| 394 if (0 != left || 0 != top || width != tex->width() || height != tex->height( )) { | |
| 395 texelsCopy = texels; | |
| 396 | |
| 397 SkASSERT(1 == texels.count()); | |
| 398 SkASSERT(texelsCopy[0].fPixels); | |
| 399 | |
| 400 if (!GrSurfacePriv::AdjustWritePixelParams(desc.fWidth, desc.fHeight, bp p, &left, &top, | |
| 401 &width, &height, &texelsCopy[ 0].fPixels, | |
| 402 &texelsCopy[0].fRowBytes)) { | |
| 335 return false; | 403 return false; |
| 336 } | 404 } |
| 337 | 405 |
| 338 if (kBottomLeft_GrSurfaceOrigin == desc.fOrigin) { | 406 texelsPtr = &texelsCopy; |
| 339 // copy into buffer by rows | 407 } |
| 340 const char* srcRow = reinterpret_cast<const char*>(data); | 408 |
| 341 char* dstRow = reinterpret_cast<char*>(mapPtr)+(height - 1)*layout.r owPitch; | 409 // Determine whether we need to flip when we copy into the buffer |
| 342 for (int y = 0; y < height; y++) { | 410 bool flipY = (kBottomLeft_GrSurfaceOrigin == desc.fOrigin && !texelsPtr->emp ty()); |
| 343 memcpy(dstRow, srcRow, trimRowBytes); | 411 |
| 344 srcRow += rowBytes; | 412 // find the combined size of all the mip levels and the relative offset of |
| 345 dstRow -= layout.rowPitch; | 413 // each into the collective buffer |
| 414 size_t combinedBufferSize = 0; | |
| 415 SkTArray<size_t> individualMipOffsets(texelsPtr->count()); | |
| 416 for (int currentMipLevel = 0; currentMipLevel < texelsPtr->count(); currentM ipLevel++) { | |
| 417 int twoToTheMipLevel = 1 << currentMipLevel; | |
| 418 int currentWidth = SkTMax(1, width / twoToTheMipLevel); | |
| 419 int currentHeight = SkTMax(1, height / twoToTheMipLevel); | |
| 420 const size_t trimmedSize = currentWidth * bpp * currentHeight; | |
| 421 individualMipOffsets.push_back(combinedBufferSize); | |
| 422 combinedBufferSize += trimmedSize; | |
| 423 } | |
| 424 | |
| 425 // allocate buffer to hold our mip data | |
| 426 GrVkTransferBuffer* transferBuffer = | |
| 427 GrVkTransferBuffer::Create(this, combinedBufferSize, GrVkBuff er::kCopyRead_Type); | |
| 428 | |
| 429 char* buffer = (char*) transferBuffer->map(); | |
| 430 SkTArray<VkBufferImageCopy> regions(texelsPtr->count()); | |
| 431 | |
| 432 for (int currentMipLevel = 0; currentMipLevel < texelsPtr->count(); currentM ipLevel++) { | |
| 433 int twoToTheMipLevel = 1 << currentMipLevel; | |
| 434 int currentWidth = SkTMax(1, width / twoToTheMipLevel); | |
| 435 int currentHeight = SkTMax(1, height / twoToTheMipLevel); | |
| 436 const size_t trimRowBytes = currentWidth * bpp; | |
| 437 const size_t rowBytes = (*texelsPtr)[currentMipLevel].fRowBytes; | |
| 438 | |
| 439 // copy data into the buffer, skipping the trailing bytes | |
| 440 char* dst = buffer + individualMipOffsets[currentMipLevel]; | |
| 441 const char* src = (const char*)(*texelsPtr)[currentMipLevel].fPixels; | |
| 442 if (flipY) { | |
| 443 src += (currentHeight - 1) * rowBytes; | |
| 444 for (int y = 0; y < currentHeight; y++) { | |
| 445 memcpy(dst, src, trimRowBytes); | |
| 446 src -= rowBytes; | |
| 447 dst += trimRowBytes; | |
| 346 } | 448 } |
| 449 } else if (trimRowBytes == rowBytes) { | |
| 450 memcpy(dst, src, trimRowBytes * currentHeight); | |
| 347 } else { | 451 } else { |
| 348 // If there is no padding on the src (rowBytes) or dst (layout.rowPi tch) we can memcpy | 452 SkRectMemcpy(dst, trimRowBytes, src, rowBytes, trimRowBytes, current Height); |
| 349 if (trimRowBytes == rowBytes && trimRowBytes == layout.rowPitch) { | |
| 350 memcpy(mapPtr, data, trimRowBytes * height); | |
| 351 } else { | |
| 352 SkRectMemcpy(mapPtr, static_cast<size_t>(layout.rowPitch), data, rowBytes, | |
| 353 trimRowBytes, height); | |
| 354 } | |
| 355 } | 453 } |
| 356 | 454 |
| 357 GR_VK_CALL(interface, UnmapMemory(fDevice, tex->textureMemory())); | 455 VkBufferImageCopy& region = regions.push_back(); |
| 358 } else { | 456 memset(®ion, 0, sizeof(VkBufferImageCopy)); |
| 359 GrVkTransferBuffer* transferBuffer = | 457 region.bufferOffset = individualMipOffsets[currentMipLevel]; |
| 360 GrVkTransferBuffer::Create(this, trimRowBytes * height, GrVkBuffer:: kCopyRead_Type); | 458 region.bufferRowLength = currentWidth; |
| 459 region.bufferImageHeight = currentHeight; | |
| 460 region.imageSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, currentMipLevel, 0, 1 }; | |
| 461 region.imageOffset = { left, top, 0 }; | |
| 462 region.imageExtent = { (uint32_t)currentWidth, (uint32_t)currentHeight, 1 }; | |
| 463 } | |
| 361 | 464 |
| 362 void* mapPtr = transferBuffer->map(); | 465 transferBuffer->unmap(); |
| 363 | 466 |
| 364 if (kBottomLeft_GrSurfaceOrigin == desc.fOrigin) { | 467 // make sure the unmap has finished |
| 365 // copy into buffer by rows | 468 transferBuffer->addMemoryBarrier(this, |
| 366 const char* srcRow = reinterpret_cast<const char*>(data); | 469 VK_ACCESS_HOST_WRITE_BIT, |
| 367 char* dstRow = reinterpret_cast<char*>(mapPtr)+(height - 1)*trimRowB ytes; | 470 VK_ACCESS_TRANSFER_READ_BIT, |
| 368 for (int y = 0; y < height; y++) { | 471 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, |
| 369 memcpy(dstRow, srcRow, trimRowBytes); | 472 VK_PIPELINE_STAGE_TRANSFER_BIT, |
| 370 srcRow += rowBytes; | 473 false); |
| 371 dstRow -= trimRowBytes; | |
| 372 } | |
| 373 } else { | |
| 374 // If there is no padding on the src data rows, we can do a single m emcpy | |
| 375 if (trimRowBytes == rowBytes) { | |
| 376 memcpy(mapPtr, data, trimRowBytes * height); | |
| 377 } else { | |
| 378 SkRectMemcpy(mapPtr, trimRowBytes, data, rowBytes, trimRowBytes, height); | |
| 379 } | |
| 380 } | |
| 381 | 474 |
| 382 transferBuffer->unmap(); | 475 // Change layout of our target so it can be copied to |
| 476 VkImageLayout layout = tex->currentLayout(); | |
| 477 VkPipelineStageFlags srcStageMask = GrVkMemory::LayoutToPipelineStageFlags(l ayout); | |
| 478 VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT; | |
| 479 VkAccessFlags srcAccessMask = GrVkMemory::LayoutToSrcAccessMask(layout); | |
| 480 VkAccessFlags dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; | |
| 481 // TODO: change layout of all the subresources | |
| 482 tex->setImageLayout(this, | |
| 483 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, | |
| 484 srcAccessMask, | |
| 485 dstAccessMask, | |
| 486 srcStageMask, | |
| 487 dstStageMask, | |
| 488 false); | |
| 383 | 489 |
| 384 // make sure the unmap has finished | 490 // Copy the buffer to the image |
| 385 transferBuffer->addMemoryBarrier(this, | 491 fCurrentCmdBuffer->copyBufferToImage(this, |
| 386 VK_ACCESS_HOST_WRITE_BIT, | 492 transferBuffer, |
| 387 VK_ACCESS_TRANSFER_READ_BIT, | 493 tex, |
| 388 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, | 494 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, |
| 389 VK_PIPELINE_STAGE_TRANSFER_BIT, | 495 regions.count(), |
| 390 false); | 496 regions.begin()); |
| 391 | 497 |
| 392 // Set up copy region | 498 // Submit the current command buffer to the Queue |
| 393 bool flipY = kBottomLeft_GrSurfaceOrigin == tex->origin(); | 499 this->submitCommandBuffer(kSkip_SyncQueue); |
| 394 VkOffset3D offset = { | |
| 395 left, | |
| 396 flipY ? tex->height() - top - height : top, | |
| 397 0 | |
| 398 }; | |
| 399 | 500 |
| 400 VkBufferImageCopy region; | 501 transferBuffer->unref(); |
| 401 memset(®ion, 0, sizeof(VkBufferImageCopy)); | |
| 402 region.bufferOffset = 0; | |
| 403 region.bufferRowLength = width; | |
| 404 region.bufferImageHeight = height; | |
| 405 region.imageSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 }; | |
| 406 region.imageOffset = offset; | |
| 407 region.imageExtent = { (uint32_t)width, (uint32_t)height, 1 }; | |
| 408 | |
| 409 // Change layout of our target so it can be copied to | |
| 410 VkImageLayout layout = tex->currentLayout(); | |
| 411 VkPipelineStageFlags srcStageMask = GrVkMemory::LayoutToPipelineStageFla gs(layout); | |
| 412 VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT; | |
| 413 VkAccessFlags srcAccessMask = GrVkMemory::LayoutToSrcAccessMask(layout); | |
| 414 VkAccessFlags dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; | |
| 415 tex->setImageLayout(this, | |
| 416 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, | |
| 417 srcAccessMask, | |
| 418 dstAccessMask, | |
| 419 srcStageMask, | |
| 420 dstStageMask, | |
| 421 false); | |
| 422 | |
| 423 // Copy the buffer to the image | |
| 424 fCurrentCmdBuffer->copyBufferToImage(this, | |
| 425 transferBuffer, | |
| 426 tex, | |
| 427 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMA L, | |
| 428 1, | |
| 429 ®ion); | |
| 430 | |
| 431 // Submit the current command buffer to the Queue | |
| 432 this->submitCommandBuffer(kSkip_SyncQueue); | |
| 433 | |
| 434 transferBuffer->unref(); | |
| 435 } | |
| 436 | 502 |
| 437 return true; | 503 return true; |
| 438 } | 504 } |
| 439 | 505 |
| 440 //////////////////////////////////////////////////////////////////////////////// | 506 //////////////////////////////////////////////////////////////////////////////// |
| 441 GrTexture* GrVkGpu::onCreateTexture(const GrSurfaceDesc& desc, SkBudgeted budget ed, | 507 GrTexture* GrVkGpu::onCreateTexture(const GrSurfaceDesc& desc, SkBudgeted budget ed, |
| 442 const SkTArray<GrMipLevel>& texels) { | 508 const SkTArray<GrMipLevel>& texels) { |
| 443 bool renderTarget = SkToBool(desc.fFlags & kRenderTarget_GrSurfaceFlag); | 509 bool renderTarget = SkToBool(desc.fFlags & kRenderTarget_GrSurfaceFlag); |
| 444 | 510 |
| 445 VkFormat pixelFormat; | 511 VkFormat pixelFormat; |
| 446 if (!GrPixelConfigToVkFormat(desc.fConfig, &pixelFormat)) { | 512 if (!GrPixelConfigToVkFormat(desc.fConfig, &pixelFormat)) { |
| 447 return nullptr; | 513 return nullptr; |
| 448 } | 514 } |
| 449 | 515 |
| 450 if (!fVkCaps->isConfigTexturable(desc.fConfig)) { | 516 if (!fVkCaps->isConfigTexturable(desc.fConfig)) { |
| 451 return nullptr; | 517 return nullptr; |
| 452 } | 518 } |
| 453 | 519 |
| 454 bool linearTiling = false; | 520 bool linearTiling = false; |
| 455 if (SkToBool(desc.fFlags & kZeroCopy_GrSurfaceFlag)) { | 521 if (SkToBool(desc.fFlags & kZeroCopy_GrSurfaceFlag)) { |
| 522 // we can't have a linear texture with a mipmap | |
| 523 if (texels.count() > 1) { | |
| 524 SkDebugf("Trying to create linear tiled texture with mipmap"); | |
| 525 return nullptr; | |
| 526 } | |
| 456 if (fVkCaps->isConfigTexurableLinearly(desc.fConfig) && | 527 if (fVkCaps->isConfigTexurableLinearly(desc.fConfig) && |
| 457 (!renderTarget || fVkCaps->isConfigRenderableLinearly(desc.fConfig, false))) { | 528 (!renderTarget || fVkCaps->isConfigRenderableLinearly(desc.fConfig, false))) { |
| 458 linearTiling = true; | 529 linearTiling = true; |
| 459 } else { | 530 } else { |
| 460 return nullptr; | 531 return nullptr; |
| 461 } | 532 } |
| 462 } | 533 } |
| 463 | 534 |
| 464 VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_SAMPLED_BIT; | 535 VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_SAMPLED_BIT; |
| 465 if (renderTarget) { | 536 if (renderTarget) { |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 478 VK_MEMORY_PROPERTY_DE VICE_LOCAL_BIT; | 549 VK_MEMORY_PROPERTY_DE VICE_LOCAL_BIT; |
| 479 | 550 |
| 480 // This ImageDesc refers to the texture that will be read by the client. Thu s even if msaa is | 551 // This ImageDesc refers to the texture that will be read by the client. Thu s even if msaa is |
| 481 // requested, this ImageDesc describes the resolved texture. Therefore we al ways have samples set | 552 // requested, this ImageDesc describes the resolved texture. Therefore we al ways have samples set |
| 482 // to 1. | 553 // to 1. |
| 483 GrVkImage::ImageDesc imageDesc; | 554 GrVkImage::ImageDesc imageDesc; |
| 484 imageDesc.fImageType = VK_IMAGE_TYPE_2D; | 555 imageDesc.fImageType = VK_IMAGE_TYPE_2D; |
| 485 imageDesc.fFormat = pixelFormat; | 556 imageDesc.fFormat = pixelFormat; |
| 486 imageDesc.fWidth = desc.fWidth; | 557 imageDesc.fWidth = desc.fWidth; |
| 487 imageDesc.fHeight = desc.fHeight; | 558 imageDesc.fHeight = desc.fHeight; |
| 488 imageDesc.fLevels = 1; // TODO: support miplevels for optimal tiling | 559 imageDesc.fLevels = linearTiling ? 1 : texels.count(); |
| 489 imageDesc.fSamples = 1; | 560 imageDesc.fSamples = 1; |
| 490 imageDesc.fImageTiling = linearTiling ? VK_IMAGE_TILING_LINEAR : VK_IMAGE_TI LING_OPTIMAL; | 561 imageDesc.fImageTiling = linearTiling ? VK_IMAGE_TILING_LINEAR : VK_IMAGE_TI LING_OPTIMAL; |
| 491 imageDesc.fUsageFlags = usageFlags; | 562 imageDesc.fUsageFlags = usageFlags; |
| 492 imageDesc.fMemProps = memProps; | 563 imageDesc.fMemProps = memProps; |
| 493 | 564 |
| 494 GrVkTexture* tex; | 565 GrVkTexture* tex; |
| 495 if (renderTarget) { | 566 if (renderTarget) { |
| 496 tex = GrVkTextureRenderTarget::CreateNewTextureRenderTarget(this, budget ed, desc, | 567 tex = GrVkTextureRenderTarget::CreateNewTextureRenderTarget(this, budget ed, desc, |
| 497 imageDesc); | 568 imageDesc); |
| 498 } else { | 569 } else { |
| 499 tex = GrVkTexture::CreateNewTexture(this, budgeted, desc, imageDesc); | 570 tex = GrVkTexture::CreateNewTexture(this, budgeted, desc, imageDesc); |
| 500 } | 571 } |
| 501 | 572 |
| 502 if (!tex) { | 573 if (!tex) { |
| 503 return nullptr; | 574 return nullptr; |
| 504 } | 575 } |
| 505 | 576 |
| 506 // TODO: We're ignoring MIP levels here. | |
| 507 if (!texels.empty()) { | 577 if (!texels.empty()) { |
| 508 SkASSERT(texels.begin()->fPixels); | 578 SkASSERT(texels.begin()->fPixels); |
| 509 if (!this->uploadTexData(tex, 0, 0, desc.fWidth, desc.fHeight, desc.fCon fig, | 579 bool success; |
| 510 texels.begin()->fPixels, texels.begin()->fRowBy tes)) { | 580 if (linearTiling) { |
| 581 success = this->uploadTexDataLinear(tex, 0, 0, desc.fWidth, desc.fHe ight, desc.fConfig, | |
| 582 texels.begin()->fPixels, texels. begin()->fRowBytes); | |
| 583 } else { | |
| 584 success = this->uploadTexDataOptimal(tex, 0, 0, desc.fWidth, desc.fH eight, desc.fConfig, | |
| 585 texels); | |
| 586 } | |
| 587 if (!success) { | |
| 511 tex->unref(); | 588 tex->unref(); |
| 512 return nullptr; | 589 return nullptr; |
| 513 } | 590 } |
| 514 } | 591 } |
| 515 | 592 |
| 516 return tex; | 593 return tex; |
| 517 } | 594 } |
| 518 | 595 |
| 519 //////////////////////////////////////////////////////////////////////////////// | 596 //////////////////////////////////////////////////////////////////////////////// |
| 520 | 597 |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 600 if (tgt && wrapDesc.fStencilBits) { | 677 if (tgt && wrapDesc.fStencilBits) { |
| 601 if (!createStencilAttachmentForRenderTarget(tgt, desc.fWidth, desc.fHeig ht)) { | 678 if (!createStencilAttachmentForRenderTarget(tgt, desc.fWidth, desc.fHeig ht)) { |
| 602 tgt->unref(); | 679 tgt->unref(); |
| 603 return nullptr; | 680 return nullptr; |
| 604 } | 681 } |
| 605 } | 682 } |
| 606 return tgt; | 683 return tgt; |
| 607 } | 684 } |
| 608 | 685 |
| 609 void GrVkGpu::generateMipmap(GrVkTexture* tex) const { | 686 void GrVkGpu::generateMipmap(GrVkTexture* tex) const { |
| 610 // don't need to do anything for linearly tiled textures (can't have mipmaps ) | 687 // don't do anything for linearly tiled textures (can't have mipmaps) |
| 611 if (tex->isLinearTiled()) { | 688 if (tex->isLinearTiled()) { |
| 689 SkDebugf("Trying to create mipmap for linear tiled texture"); | |
| 612 return; | 690 return; |
| 613 } | 691 } |
| 614 | 692 |
| 615 // We cannot generate mipmaps for images that are multisampled. | 693 // We cannot generate mipmaps for images that are multisampled. |
| 616 // TODO: does it even make sense for rendertargets in general? | 694 // TODO: does it even make sense for rendertargets in general? |
| 617 if (tex->asRenderTarget() && tex->asRenderTarget()->numColorSamples() > 1) { | 695 if (tex->asRenderTarget() && tex->asRenderTarget()->numColorSamples() > 1) { |
| 618 return; | 696 return; |
| 619 } | 697 } |
| 620 | 698 |
| 621 // determine if we can blit to and from this format | 699 // determine if we can blit to and from this format |
| 622 const GrVkCaps& caps = this->vkCaps(); | 700 const GrVkCaps& caps = this->vkCaps(); |
| 623 if (!caps.configCanBeDstofBlit(tex->config(), false) || | 701 if (!caps.configCanBeDstofBlit(tex->config(), false) || |
| 624 !caps.configCanBeSrcofBlit(tex->config(), false)) { | 702 !caps.configCanBeSrcofBlit(tex->config(), false)) { |
| 625 return; | 703 return; |
| 626 } | 704 } |
| 627 | 705 |
| 628 // change the original image's layout | 706 // change the original image's layout |
| 629 VkImageLayout origSrcLayout = tex->currentLayout(); | 707 VkImageLayout origSrcLayout = tex->currentLayout(); |
| 630 VkPipelineStageFlags srcStageMask = GrVkMemory::LayoutToPipelineStageFlags(o rigSrcLayout); | 708 VkPipelineStageFlags srcStageMask = GrVkMemory::LayoutToPipelineStageFlags(o rigSrcLayout); |
| 631 VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT; | 709 VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT; |
| 632 | 710 |
| 633 VkAccessFlags srcAccessMask = GrVkMemory::LayoutToSrcAccessMask(origSrcLayou t); | 711 VkAccessFlags srcAccessMask = GrVkMemory::LayoutToSrcAccessMask(origSrcLayou t); |
| 634 VkAccessFlags dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; | 712 VkAccessFlags dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; |
| 635 | 713 |
| 714 // TODO: change layout of all the subresources | |
| 636 tex->setImageLayout(this, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, | 715 tex->setImageLayout(this, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, |
| 637 srcAccessMask, dstAccessMask, srcStageMask, dstStageMask , false); | 716 srcAccessMask, dstAccessMask, srcStageMask, dstStageMask , false); |
| 638 | 717 |
| 639 // grab handle to the original image resource | 718 // grab handle to the original image resource |
| 640 const GrVkImage::Resource* oldResource = tex->resource(); | 719 const GrVkImage::Resource* oldResource = tex->resource(); |
| 641 oldResource->ref(); | 720 oldResource->ref(); |
| 642 | 721 |
| 643 if (!tex->reallocForMipmap(this)) { | 722 uint32_t mipLevels = SkMipMap::ComputeLevelCount(tex->width(), tex->height() ); |
| 723 if (!tex->reallocForMipmap(this, mipLevels)) { | |
| 644 oldResource->unref(this); | 724 oldResource->unref(this); |
| 645 return; | 725 return; |
| 646 } | 726 } |
| 647 | 727 |
| 648 // change the new image's layout | 728 // change the new image's layout |
| 649 VkImageLayout origDstLayout = tex->currentLayout(); | 729 VkImageLayout origDstLayout = tex->currentLayout(); |
| 650 | 730 |
| 651 srcStageMask = GrVkMemory::LayoutToPipelineStageFlags(origDstLayout); | 731 srcStageMask = GrVkMemory::LayoutToPipelineStageFlags(origDstLayout); |
| 652 dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT; | 732 dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT; |
| 653 | 733 |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 686 VK_FILTER_LINEAR); | 766 VK_FILTER_LINEAR); |
| 687 // Blit the miplevels | 767 // Blit the miplevels |
| 688 while (width/2 > 0 && height/2 > 0) { | 768 while (width/2 > 0 && height/2 > 0) { |
| 689 blitRegion.srcSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, mipLevel, 0, 1 }; | 769 blitRegion.srcSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, mipLevel, 0, 1 }; |
| 690 blitRegion.srcOffsets[0] = { 0, 0, 0 }; | 770 blitRegion.srcOffsets[0] = { 0, 0, 0 }; |
| 691 blitRegion.srcOffsets[1] = { width, height, 0 }; | 771 blitRegion.srcOffsets[1] = { width, height, 0 }; |
| 692 blitRegion.dstSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, mipLevel+1, 0, 1 }; | 772 blitRegion.dstSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, mipLevel+1, 0, 1 }; |
| 693 blitRegion.dstOffsets[0] = { 0, 0, 0 }; | 773 blitRegion.dstOffsets[0] = { 0, 0, 0 }; |
| 694 blitRegion.dstOffsets[1] = { width/2, height/2, 0 }; | 774 blitRegion.dstOffsets[1] = { width/2, height/2, 0 }; |
| 695 | 775 |
| 776 // TODO: insert image barrier to wait on previous blit | |
| 777 | |
| 696 fCurrentCmdBuffer->blitImage(this, | 778 fCurrentCmdBuffer->blitImage(this, |
| 697 tex->resource(), | 779 tex->resource(), |
| 698 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, | 780 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, |
| 699 tex->resource(), | 781 tex->resource(), |
| 700 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, | 782 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, |
| 701 1, | 783 1, |
| 702 &blitRegion, | 784 &blitRegion, |
| 703 VK_FILTER_LINEAR); | 785 VK_FILTER_LINEAR); |
| 704 | 786 |
| 705 width /= 2; | 787 width /= 2; |
| (...skipping 561 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1267 // depth value be 1. | 1349 // depth value be 1. |
| 1268 copyRegion.extent = { (uint32_t)srcVkRect.width(), (uint32_t)srcVkRect.heigh t(), 1 }; | 1350 copyRegion.extent = { (uint32_t)srcVkRect.width(), (uint32_t)srcVkRect.heigh t(), 1 }; |
| 1269 | 1351 |
| 1270 fCurrentCmdBuffer->copyImage(this, | 1352 fCurrentCmdBuffer->copyImage(this, |
| 1271 srcImage, | 1353 srcImage, |
| 1272 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, | 1354 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, |
| 1273 dstImage, | 1355 dstImage, |
| 1274 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, | 1356 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, |
| 1275 1, | 1357 1, |
| 1276 ©Region); | 1358 ©Region); |
| 1359 | |
| 1360 SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.fX, dstPoint.fY, | |
| 1361 srcRect.width(), srcRect.height()); | |
| 1362 this->didWriteToSurface(dst, &dstRect); | |
|
egdaniel
2016/04/29 18:10:28
is this something that GL does as well when we do
jvanverth1
2016/04/29 18:16:10
Yup, and in flushRenderTarget(). I don't think we
| |
| 1277 } | 1363 } |
| 1278 | 1364 |
| 1279 inline bool can_copy_as_blit(const GrSurface* dst, | 1365 inline bool can_copy_as_blit(const GrSurface* dst, |
| 1280 const GrSurface* src, | 1366 const GrSurface* src, |
| 1281 const GrVkImage* dstImage, | 1367 const GrVkImage* dstImage, |
| 1282 const GrVkImage* srcImage, | 1368 const GrVkImage* srcImage, |
| 1283 const GrVkGpu* gpu) { | 1369 const GrVkGpu* gpu) { |
| 1284 // We require that all vulkan GrSurfaces have been created with transfer_dst and transfer_src | 1370 // We require that all vulkan GrSurfaces have been created with transfer_dst and transfer_src |
| 1285 // as image usage flags. | 1371 // as image usage flags. |
| 1286 const GrVkCaps& caps = gpu->vkCaps(); | 1372 const GrVkCaps& caps = gpu->vkCaps(); |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1377 blitRegion.dstOffsets[1] = { dstRect.fRight, dstRect.fBottom, 0 }; | 1463 blitRegion.dstOffsets[1] = { dstRect.fRight, dstRect.fBottom, 0 }; |
| 1378 | 1464 |
| 1379 fCurrentCmdBuffer->blitImage(this, | 1465 fCurrentCmdBuffer->blitImage(this, |
| 1380 srcImage->resource(), | 1466 srcImage->resource(), |
| 1381 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, | 1467 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, |
| 1382 dstImage->resource(), | 1468 dstImage->resource(), |
| 1383 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, | 1469 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, |
| 1384 1, | 1470 1, |
| 1385 &blitRegion, | 1471 &blitRegion, |
| 1386 VK_FILTER_NEAREST); // We never scale so any fi lter works here | 1472 VK_FILTER_NEAREST); // We never scale so any fi lter works here |
| 1473 | |
| 1474 this->didWriteToSurface(dst, &dstRect); | |
| 1387 } | 1475 } |
| 1388 | 1476 |
| 1389 inline bool can_copy_as_draw(const GrSurface* dst, | 1477 inline bool can_copy_as_draw(const GrSurface* dst, |
| 1390 const GrSurface* src, | 1478 const GrSurface* src, |
| 1391 const GrVkGpu* gpu) { | 1479 const GrVkGpu* gpu) { |
| 1392 return false; | 1480 return false; |
| 1393 } | 1481 } |
| 1394 | 1482 |
| 1395 void GrVkGpu::copySurfaceAsDraw(GrSurface* dst, | 1483 void GrVkGpu::copySurfaceAsDraw(GrSurface* dst, |
| 1396 GrSurface* src, | 1484 GrSurface* src, |
| (...skipping 307 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1704 aglSwapBuffers(aglGetCurrentContext()); | 1792 aglSwapBuffers(aglGetCurrentContext()); |
| 1705 int set_a_break_pt_here = 9; | 1793 int set_a_break_pt_here = 9; |
| 1706 aglSwapBuffers(aglGetCurrentContext()); | 1794 aglSwapBuffers(aglGetCurrentContext()); |
| 1707 #elif defined(SK_BUILD_FOR_WIN32) | 1795 #elif defined(SK_BUILD_FOR_WIN32) |
| 1708 SwapBuf(); | 1796 SwapBuf(); |
| 1709 int set_a_break_pt_here = 9; | 1797 int set_a_break_pt_here = 9; |
| 1710 SwapBuf(); | 1798 SwapBuf(); |
| 1711 #endif | 1799 #endif |
| 1712 #endif | 1800 #endif |
| 1713 } | 1801 } |
| OLD | NEW |