Make Vulkan testing-only backend textures have optimal layout

Change-Id: I984a6a657417565c36687d32e41b5f7d9bbc39f8
Reviewed-on: https://skia-review.googlesource.com/112800
Reviewed-by: Greg Daniel <egdaniel@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
This commit is contained in:
Brian Salomon 2018-03-07 14:23:58 -05:00 committed by Skia Commit-Bot
parent 7578f3ecdd
commit de9f546a04

View File

@ -1191,7 +1191,6 @@ GrBackendTexture GrVkGpu::createTestingOnlyBackendTexture(void* srcData, int w,
return GrBackendTexture(); // invalid return GrBackendTexture(); // invalid
} }
bool linearTiling = false;
if (!fVkCaps->isConfigTexturable(config)) { if (!fVkCaps->isConfigTexturable(config)) {
return GrBackendTexture(); // invalid return GrBackendTexture(); // invalid
} }
@ -1205,12 +1204,6 @@ GrBackendTexture GrVkGpu::createTestingOnlyBackendTexture(void* srcData, int w,
return GrBackendTexture(); // invalid return GrBackendTexture(); // invalid
} }
if (fVkCaps->isConfigTexturableLinearly(config) &&
(!isRenderTarget || fVkCaps->isConfigRenderableLinearly(config, false)) &&
GrMipMapped::kNo == mipMapped) {
linearTiling = true;
}
VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_SAMPLED_BIT; VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_SAMPLED_BIT;
usageFlags |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT; usageFlags |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
usageFlags |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; usageFlags |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
@ -1220,11 +1213,7 @@ GrBackendTexture GrVkGpu::createTestingOnlyBackendTexture(void* srcData, int w,
VkImage image = VK_NULL_HANDLE; VkImage image = VK_NULL_HANDLE;
GrVkAlloc alloc; GrVkAlloc alloc;
VkImageLayout initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
VkImageTiling imageTiling = linearTiling ? VK_IMAGE_TILING_LINEAR : VK_IMAGE_TILING_OPTIMAL;
VkImageLayout initialLayout = (VK_IMAGE_TILING_LINEAR == imageTiling)
? VK_IMAGE_LAYOUT_PREINITIALIZED
: VK_IMAGE_LAYOUT_UNDEFINED;
// Create Image // Create Image
VkSampleCountFlagBits vkSamples; VkSampleCountFlagBits vkSamples;
@ -1239,26 +1228,26 @@ GrBackendTexture GrVkGpu::createTestingOnlyBackendTexture(void* srcData, int w,
} }
const VkImageCreateInfo imageCreateInfo = { const VkImageCreateInfo imageCreateInfo = {
VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // sType VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // sType
nullptr, // pNext nullptr, // pNext
0, // VkImageCreateFlags 0, // VkImageCreateFlags
VK_IMAGE_TYPE_2D, // VkImageType VK_IMAGE_TYPE_2D, // VkImageType
pixelFormat, // VkFormat pixelFormat, // VkFormat
{ (uint32_t) w, (uint32_t) h, 1 }, // VkExtent3D {(uint32_t)w, (uint32_t)h, 1}, // VkExtent3D
mipLevels, // mipLevels mipLevels, // mipLevels
1, // arrayLayers 1, // arrayLayers
vkSamples, // samples vkSamples, // samples
imageTiling, // VkImageTiling VK_IMAGE_TILING_OPTIMAL, // VkImageTiling
usageFlags, // VkImageUsageFlags usageFlags, // VkImageUsageFlags
VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode
0, // queueFamilyCount 0, // queueFamilyCount
0, // pQueueFamilyIndices 0, // pQueueFamilyIndices
initialLayout // initialLayout initialLayout // initialLayout
}; };
GR_VK_CALL_ERRCHECK(this->vkInterface(), CreateImage(this->device(), &imageCreateInfo, nullptr, &image)); GR_VK_CALL_ERRCHECK(this->vkInterface(), CreateImage(this->device(), &imageCreateInfo, nullptr, &image));
if (!GrVkMemory::AllocAndBindImageMemory(this, image, linearTiling, &alloc)) { if (!GrVkMemory::AllocAndBindImageMemory(this, image, false, &alloc)) {
VK_CALL(DestroyImage(this->device(), image, nullptr)); VK_CALL(DestroyImage(this->device(), image, nullptr));
return GrBackendTexture(); // invalid return GrBackendTexture(); // invalid
} }
@ -1295,147 +1284,122 @@ GrBackendTexture GrVkGpu::createTestingOnlyBackendTexture(void* srcData, int w,
SkASSERT(!err); SkASSERT(!err);
size_t bpp = GrBytesPerPixel(config); size_t bpp = GrBytesPerPixel(config);
size_t rowCopyBytes = bpp * w; SkASSERT(w && h);
if (linearTiling) {
const VkImageSubresource subres = {
VK_IMAGE_ASPECT_COLOR_BIT,
0, // mipLevel
0, // arraySlice
};
VkSubresourceLayout layout;
VK_CALL(GetImageSubresourceLayout(fDevice, image, &subres, &layout)); SkTArray<size_t> individualMipOffsets(mipLevels);
individualMipOffsets.push_back(0);
size_t combinedBufferSize = w * bpp * h;
int currentWidth = w;
int currentHeight = h;
// The alignment must be at least 4 bytes and a multiple of the bytes per pixel of the image
// config. This works with the assumption that the bytes in pixel config is always a power
// of 2.
SkASSERT((bpp & (bpp - 1)) == 0);
const size_t alignmentMask = 0x3 | (bpp - 1);
for (uint32_t currentMipLevel = 1; currentMipLevel < mipLevels; currentMipLevel++) {
currentWidth = SkTMax(1, currentWidth / 2);
currentHeight = SkTMax(1, currentHeight / 2);
if (!copy_testing_data(this, srcData, alloc, 0, rowCopyBytes, const size_t trimmedSize = currentWidth * bpp * currentHeight;
static_cast<size_t>(layout.rowPitch), h)) { const size_t alignmentDiff = combinedBufferSize & alignmentMask;
GrVkMemory::FreeImageMemory(this, true, alloc); if (alignmentDiff != 0) {
VK_CALL(DestroyImage(fDevice, image, nullptr)); combinedBufferSize += alignmentMask - alignmentDiff + 1;
VK_CALL(EndCommandBuffer(cmdBuffer));
VK_CALL(FreeCommandBuffers(fDevice, fCmdPool, 1, &cmdBuffer));
return GrBackendTexture(); // invalid
} }
} else { individualMipOffsets.push_back(combinedBufferSize);
SkASSERT(w && h); combinedBufferSize += trimmedSize;
}
SkTArray<size_t> individualMipOffsets(mipLevels); VkBufferCreateInfo bufInfo;
individualMipOffsets.push_back(0); memset(&bufInfo, 0, sizeof(VkBufferCreateInfo));
size_t combinedBufferSize = w * bpp * h; bufInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
int currentWidth = w; bufInfo.flags = 0;
int currentHeight = h; bufInfo.size = combinedBufferSize;
// The alignment must be at least 4 bytes and a multiple of the bytes per pixel of the image bufInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
// config. This works with the assumption that the bytes in pixel config is always a power bufInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
// of 2. bufInfo.queueFamilyIndexCount = 0;
SkASSERT((bpp & (bpp - 1)) == 0); bufInfo.pQueueFamilyIndices = nullptr;
const size_t alignmentMask = 0x3 | (bpp - 1); err = VK_CALL(CreateBuffer(fDevice, &bufInfo, nullptr, &buffer));
for (uint32_t currentMipLevel = 1; currentMipLevel < mipLevels; currentMipLevel++) {
currentWidth = SkTMax(1, currentWidth/2);
currentHeight = SkTMax(1, currentHeight/2);
const size_t trimmedSize = currentWidth * bpp * currentHeight; if (err) {
const size_t alignmentDiff = combinedBufferSize & alignmentMask; GrVkMemory::FreeImageMemory(this, false, alloc);
if (alignmentDiff != 0) { VK_CALL(DestroyImage(fDevice, image, nullptr));
combinedBufferSize += alignmentMask - alignmentDiff + 1; VK_CALL(EndCommandBuffer(cmdBuffer));
} VK_CALL(FreeCommandBuffers(fDevice, fCmdPool, 1, &cmdBuffer));
individualMipOffsets.push_back(combinedBufferSize); return GrBackendTexture(); // invalid
combinedBufferSize += trimmedSize; }
}
VkBufferCreateInfo bufInfo; if (!GrVkMemory::AllocAndBindBufferMemory(this, buffer, GrVkBuffer::kCopyRead_Type, true,
memset(&bufInfo, 0, sizeof(VkBufferCreateInfo)); &bufferAlloc)) {
bufInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; GrVkMemory::FreeImageMemory(this, false, alloc);
bufInfo.flags = 0; VK_CALL(DestroyImage(fDevice, image, nullptr));
bufInfo.size = combinedBufferSize; VK_CALL(DestroyBuffer(fDevice, buffer, nullptr));
bufInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; VK_CALL(EndCommandBuffer(cmdBuffer));
bufInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; VK_CALL(FreeCommandBuffers(fDevice, fCmdPool, 1, &cmdBuffer));
bufInfo.queueFamilyIndexCount = 0; return GrBackendTexture(); // invalid
bufInfo.pQueueFamilyIndices = nullptr; }
err = VK_CALL(CreateBuffer(fDevice, &bufInfo, nullptr, &buffer));
if (err) { currentWidth = w;
GrVkMemory::FreeImageMemory(this, false, alloc); currentHeight = h;
VK_CALL(DestroyImage(fDevice, image, nullptr)); for (uint32_t currentMipLevel = 0; currentMipLevel < mipLevels; currentMipLevel++) {
VK_CALL(EndCommandBuffer(cmdBuffer)); SkASSERT(0 == currentMipLevel || !srcData);
VK_CALL(FreeCommandBuffers(fDevice, fCmdPool, 1, &cmdBuffer)); size_t currentRowBytes = bpp * currentWidth;
return GrBackendTexture(); // invalid size_t bufferOffset = individualMipOffsets[currentMipLevel];
} if (!copy_testing_data(this, srcData, bufferAlloc, bufferOffset, currentRowBytes,
currentRowBytes, currentHeight)) {
if (!GrVkMemory::AllocAndBindBufferMemory(this, buffer, GrVkBuffer::kCopyRead_Type,
true, &bufferAlloc)) {
GrVkMemory::FreeImageMemory(this, false, alloc); GrVkMemory::FreeImageMemory(this, false, alloc);
VK_CALL(DestroyImage(fDevice, image, nullptr)); VK_CALL(DestroyImage(fDevice, image, nullptr));
GrVkMemory::FreeBufferMemory(this, GrVkBuffer::kCopyRead_Type, bufferAlloc);
VK_CALL(DestroyBuffer(fDevice, buffer, nullptr)); VK_CALL(DestroyBuffer(fDevice, buffer, nullptr));
VK_CALL(EndCommandBuffer(cmdBuffer)); VK_CALL(EndCommandBuffer(cmdBuffer));
VK_CALL(FreeCommandBuffers(fDevice, fCmdPool, 1, &cmdBuffer)); VK_CALL(FreeCommandBuffers(fDevice, fCmdPool, 1, &cmdBuffer));
return GrBackendTexture(); // invalid return GrBackendTexture(); // invalid
} }
currentWidth = SkTMax(1, currentWidth / 2);
currentWidth = w; currentHeight = SkTMax(1, currentHeight / 2);
currentHeight = h;
for (uint32_t currentMipLevel = 0; currentMipLevel < mipLevels; currentMipLevel++) {
SkASSERT(0 == currentMipLevel || !srcData);
size_t currentRowBytes = bpp * currentWidth;
size_t bufferOffset = individualMipOffsets[currentMipLevel];
if (!copy_testing_data(this, srcData, bufferAlloc, bufferOffset,
currentRowBytes, currentRowBytes, currentHeight)) {
GrVkMemory::FreeImageMemory(this, false, alloc);
VK_CALL(DestroyImage(fDevice, image, nullptr));
GrVkMemory::FreeBufferMemory(this, GrVkBuffer::kCopyRead_Type, bufferAlloc);
VK_CALL(DestroyBuffer(fDevice, buffer, nullptr));
VK_CALL(EndCommandBuffer(cmdBuffer));
VK_CALL(FreeCommandBuffers(fDevice, fCmdPool, 1, &cmdBuffer));
return GrBackendTexture(); // invalid
}
currentWidth = SkTMax(1, currentWidth/2);
currentHeight = SkTMax(1, currentHeight/2);
}
// Set image layout and add barrier
VkImageMemoryBarrier barrier;
memset(&barrier, 0, sizeof(VkImageMemoryBarrier));
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier.pNext = nullptr;
barrier.srcAccessMask = GrVkMemory::LayoutToSrcAccessMask(initialLayout);
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
barrier.oldLayout = initialLayout;
barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.image = image;
barrier.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, mipLevels, 0 , 1};
VK_CALL(CmdPipelineBarrier(cmdBuffer,
GrVkMemory::LayoutToPipelineStageFlags(initialLayout),
VK_PIPELINE_STAGE_TRANSFER_BIT,
0,
0, nullptr,
0, nullptr,
1, &barrier));
initialLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
SkTArray<VkBufferImageCopy> regions(mipLevels);
currentWidth = w;
currentHeight = h;
for (uint32_t currentMipLevel = 0; currentMipLevel < mipLevels; currentMipLevel++) {
// Submit copy command
VkBufferImageCopy& region = regions.push_back();
memset(&region, 0, sizeof(VkBufferImageCopy));
region.bufferOffset = individualMipOffsets[currentMipLevel];
region.bufferRowLength = currentWidth;
region.bufferImageHeight = currentHeight;
region.imageSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
region.imageOffset = { 0, 0, 0 };
region.imageExtent = { (uint32_t)currentWidth, (uint32_t)currentHeight, 1 };
currentWidth = SkTMax(1, currentWidth/2);
currentHeight = SkTMax(1, currentHeight/2);
}
VK_CALL(CmdCopyBufferToImage(cmdBuffer, buffer, image, initialLayout, regions.count(),
regions.begin()));
} }
// Set image layout and add barrier
VkImageMemoryBarrier barrier;
memset(&barrier, 0, sizeof(VkImageMemoryBarrier));
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier.pNext = nullptr;
barrier.srcAccessMask = GrVkMemory::LayoutToSrcAccessMask(initialLayout);
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
barrier.oldLayout = initialLayout;
barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.image = image;
barrier.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, mipLevels, 0, 1};
VK_CALL(CmdPipelineBarrier(cmdBuffer, GrVkMemory::LayoutToPipelineStageFlags(initialLayout),
VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1,
&barrier));
initialLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
SkTArray<VkBufferImageCopy> regions(mipLevels);
currentWidth = w;
currentHeight = h;
for (uint32_t currentMipLevel = 0; currentMipLevel < mipLevels; currentMipLevel++) {
// Submit copy command
VkBufferImageCopy& region = regions.push_back();
memset(&region, 0, sizeof(VkBufferImageCopy));
region.bufferOffset = individualMipOffsets[currentMipLevel];
region.bufferRowLength = currentWidth;
region.bufferImageHeight = currentHeight;
region.imageSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1};
region.imageOffset = {0, 0, 0};
region.imageExtent = {(uint32_t)currentWidth, (uint32_t)currentHeight, 1};
currentWidth = SkTMax(1, currentWidth / 2);
currentHeight = SkTMax(1, currentHeight / 2);
}
VK_CALL(CmdCopyBufferToImage(cmdBuffer, buffer, image, initialLayout, regions.count(),
regions.begin()));
// Change Image layout to shader read since if we use this texture as a borrowed textures within // Change Image layout to shader read since if we use this texture as a borrowed textures within
// Ganesh we require that its layout be set to that // Ganesh we require that its layout be set to that
VkImageMemoryBarrier barrier;
memset(&barrier, 0, sizeof(VkImageMemoryBarrier)); memset(&barrier, 0, sizeof(VkImageMemoryBarrier));
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier.pNext = nullptr; barrier.pNext = nullptr;
@ -1508,7 +1472,7 @@ GrBackendTexture GrVkGpu::createTestingOnlyBackendTexture(void* srcData, int w,
GrVkImageInfo info; GrVkImageInfo info;
info.fImage = image; info.fImage = image;
info.fAlloc = alloc; info.fAlloc = alloc;
info.fImageTiling = imageTiling; info.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
info.fImageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; info.fImageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
info.fFormat = pixelFormat; info.fFormat = pixelFormat;
info.fLevelCount = mipLevels; info.fLevelCount = mipLevels;