Use vkCmdClearColorImage to clear backend textures

Also don't use GrPixelConfig to create the VkImage.


Bug: skia:7959
Bug: skia:6718

Change-Id: Ia13c5ed2fbe0542c060b725694eff9d566c491f0
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/226078
Reviewed-by: Greg Daniel <egdaniel@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
This commit is contained in:
Brian Salomon 2019-07-09 09:36:51 -04:00 committed by Skia Commit-Bot
parent 21ba586f32
commit b450f3be4f
8 changed files with 180 additions and 146 deletions

View File

@ -520,6 +520,7 @@
"~^TextureStripAtlasManagerColorFilterTest$",
"~^WritePixelsNonTextureMSAA_Gpu$",
"~^AsyncReadPixels$",
"~^VkBackendAllocationTest$",
"--nonativeFonts",
"--verbose"
],

View File

@ -738,6 +738,7 @@ def dm_flags(api, bot):
match.append('~^TextureStripAtlasManagerColorFilterTest$')
match.append('~^WritePixelsNonTextureMSAA_Gpu$')
match.append('~^AsyncReadPixels$')
match.append('~^VkBackendAllocationTest$')
if 'ANGLE' in bot:
# skia:7835

View File

@ -481,14 +481,15 @@ GrBackendTexture GrContext::createBackendTexture(int width, int height,
return GrBackendTexture();
}
GrBackendFormat format =
this->caps()->getBackendFormatFromColorType(SkColorTypeToGrColorType(colorType));
GrColorType ct = SkColorTypeToGrColorType(colorType);
GrBackendFormat format = this->caps()->getBackendFormatFromColorType(ct);
if (!format.isValid()) {
return GrBackendTexture();
}
SkColor4f swizzledColor = this->caps()->getOutputSwizzle(format, ct).applyTo(color);
return this->createBackendTexture(width, height, format, color,
mipMapped, renderable, isProtected);
return this->createBackendTexture(width, height, format, swizzledColor, mipMapped, renderable,
isProtected);
}
void GrContext::deleteBackendTexture(GrBackendTexture backendTex) {

View File

@ -42,7 +42,8 @@ public:
}
/** Applies this swizzle to the input color and returns the swizzled color. */
constexpr SkPMColor4f applyTo(const SkPMColor4f& color) const;
template <SkAlphaType AlphaType>
constexpr SkRGBA4f<AlphaType> applyTo(const SkRGBA4f<AlphaType>& color) const;
void apply(SkRasterPipeline*) const;
@ -54,7 +55,8 @@ public:
static constexpr GrSwizzle RGB1() { return GrSwizzle("rgb1"); }
private:
static constexpr float ComponentIndexToFloat(const SkPMColor4f& color, int idx);
template <SkAlphaType AlphaType>
static constexpr float ComponentIndexToFloat(const SkRGBA4f<AlphaType>& color, int idx);
static constexpr int CToI(char c);
static constexpr char IToC(int idx);
@ -80,7 +82,8 @@ constexpr GrSwizzle& GrSwizzle::operator=(const GrSwizzle& that) {
return *this;
}
constexpr SkPMColor4f GrSwizzle::applyTo(const SkPMColor4f& color) const {
template <SkAlphaType AlphaType>
constexpr SkRGBA4f<AlphaType> GrSwizzle::applyTo(const SkRGBA4f<AlphaType>& color) const {
uint32_t key = fKey;
// Index of the input color that should be mapped to output r.
int idx = (key & 15);
@ -107,7 +110,8 @@ constexpr void GrSwizzle::setFromKey(uint16_t key) {
SkASSERT(fSwiz[4] == '\0');
}
constexpr float GrSwizzle::ComponentIndexToFloat(const SkPMColor4f& color, int idx) {
template <SkAlphaType AlphaType>
constexpr float GrSwizzle::ComponentIndexToFloat(const SkRGBA4f<AlphaType>& color, int idx) {
if (idx <= 3) {
return color[idx];
}

View File

@ -1494,28 +1494,6 @@ bool copy_compressed_src_data(GrVkGpu* gpu, const GrVkAlloc& alloc,
GrVkMemory::UnmapAlloc(gpu, alloc);
return true;
}
bool fill_in_with_color(GrVkGpu* gpu, const GrVkAlloc& alloc, VkFormat vkFormat,
int baseWidth, int baseHeight,
const SkTArray<size_t>& individualMipOffsets,
GrPixelConfig config, const SkColor4f& color) {
void* mapPtr = GrVkMemory::MapAlloc(gpu, alloc);
if (!mapPtr) {
return false;
}
SkImage::CompressionType compressionType;
if (GrVkFormatToCompressionType(vkFormat, &compressionType)) {
GrFillInCompressedData(compressionType, baseWidth, baseHeight, (char*)mapPtr, color);
} else {
// TODO: pass in alloc.fSize and assert we never write past it
GrFillInData(config, baseWidth, baseHeight, individualMipOffsets, (char*)mapPtr, color);
}
GrVkMemory::FlushMappedAlloc(gpu, alloc, 0, alloc.fSize);
GrVkMemory::UnmapAlloc(gpu, alloc);
return true;
}
static void set_image_layout(const GrVkInterface* vkInterface, VkCommandBuffer cmdBuffer,
GrVkImageInfo* info, VkImageLayout newLayout, uint32_t mipLevels,
@ -1547,10 +1525,11 @@ static void set_image_layout(const GrVkInterface* vkInterface, VkCommandBuffer c
info->fImageLayout = newLayout;
}
bool GrVkGpu::createTestingOnlyVkImage(GrPixelConfig config, int w, int h, bool texturable,
bool renderable, GrMipMapped mipMapped, const void* srcData,
size_t srcRowBytes, const SkColor4f* color,
GrVkImageInfo* info, GrProtected isProtected) {
bool GrVkGpu::createVkImageForBackendSurface(VkFormat vkFormat, int w, int h, bool texturable,
bool renderable, GrMipMapped mipMapped,
const void* srcData, size_t srcRowBytes,
const SkColor4f* color, GrVkImageInfo* info,
GrProtected isProtected) {
SkASSERT(texturable || renderable);
if (!texturable) {
SkASSERT(GrMipMapped::kNo == mipMapped);
@ -1561,11 +1540,6 @@ bool GrVkGpu::createTestingOnlyVkImage(GrPixelConfig config, int w, int h, bool
return false;
}
VkFormat vkFormat;
if (!GrPixelConfigToVkFormat(config, &vkFormat)) {
return false;
}
if (texturable && !fVkCaps->isVkFormatTexturable(vkFormat)) {
return false;
}
@ -1647,103 +1621,126 @@ bool GrVkGpu::createTestingOnlyVkImage(GrPixelConfig config, int w, int h, bool
err = VK_CALL(BeginCommandBuffer(cmdBuffer, &cmdBufferBeginInfo));
SkASSERT(!err);
size_t bytesPerPixel = GrVkBytesPerFormat(vkFormat);
SkASSERT(w && h);
SkTArray<size_t> individualMipOffsets(mipLevels);
// Set image layout and add barrier
set_image_layout(this->vkInterface(), cmdBuffer, info, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
mipLevels, VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
// TODO: Lift this to GrContext level.
SkImage::CompressionType compressionType;
bool isCompressed = GrVkFormatToCompressionType(vkFormat, &compressionType);
std::unique_ptr<char[]> tempData;
if (isCompressed && !srcData) {
SkASSERT(color);
size_t size = GrCompressedDataSize(compressionType, w, h);
tempData.reset(new char[size]);
GrFillInCompressedData(compressionType, w, h, tempData.get(), *color);
srcData = tempData.get();
}
size_t combinedBufferSize;
if (isCompressed) {
// Compressed textures currently must be non-MIP mapped and have initial data.
if (mipMapped == GrMipMapped::kYes) {
if (srcData) {
size_t bytesPerPixel = GrVkBytesPerFormat(vkFormat);
SkASSERT(w && h);
SkTArray<size_t> individualMipOffsets(mipLevels);
SkImage::CompressionType compressionType;
bool isCompressed = GrVkFormatToCompressionType(vkFormat, &compressionType);
size_t combinedBufferSize;
if (isCompressed) {
// Compressed textures currently must be non-MIP mapped.
if (mipMapped == GrMipMapped::kYes) {
return false;
}
combinedBufferSize = GrCompressedDataSize(compressionType, w, h);
individualMipOffsets.push_back(0);
} else {
combinedBufferSize = GrComputeTightCombinedBufferSize(bytesPerPixel, w, h,
&individualMipOffsets, mipLevels);
}
VkBufferCreateInfo bufInfo;
memset(&bufInfo, 0, sizeof(VkBufferCreateInfo));
bufInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
bufInfo.flags = fProtectedContext == GrProtected::kYes ? VK_BUFFER_CREATE_PROTECTED_BIT : 0;
bufInfo.size = combinedBufferSize;
bufInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
bufInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
bufInfo.queueFamilyIndexCount = 0;
bufInfo.pQueueFamilyIndices = nullptr;
err = VK_CALL(CreateBuffer(fDevice, &bufInfo, nullptr, &buffer));
if (err) {
GrVkImage::DestroyImageInfo(this, info);
VK_CALL(EndCommandBuffer(cmdBuffer));
VK_CALL(FreeCommandBuffers(fDevice, fCmdPool->vkCommandPool(), 1, &cmdBuffer));
return false;
}
if (!srcData && !color) {
if (!GrVkMemory::AllocAndBindBufferMemory(this, buffer, GrVkBuffer::kCopyRead_Type, true,
&bufferAlloc)) {
GrVkImage::DestroyImageInfo(this, info);
VK_CALL(DestroyBuffer(fDevice, buffer, nullptr));
VK_CALL(EndCommandBuffer(cmdBuffer));
VK_CALL(FreeCommandBuffers(fDevice, fCmdPool->vkCommandPool(), 1, &cmdBuffer));
return false;
}
combinedBufferSize = GrCompressedDataSize(compressionType, w, h);
individualMipOffsets.push_back(0);
bool result;
if (isCompressed) {
result = copy_compressed_src_data(this, bufferAlloc, compressionType, w, h, srcData);
} else {
SkASSERT(1 == mipLevels);
result = copy_src_data(this, bufferAlloc, vkFormat, w, h, srcData, srcRowBytes);
}
if (!result) {
GrVkImage::DestroyImageInfo(this, info);
GrVkMemory::FreeBufferMemory(this, GrVkBuffer::kCopyRead_Type, bufferAlloc);
VK_CALL(DestroyBuffer(fDevice, buffer, nullptr));
VK_CALL(EndCommandBuffer(cmdBuffer));
VK_CALL(FreeCommandBuffers(fDevice, fCmdPool->vkCommandPool(), 1, &cmdBuffer));
return false;
}
SkTArray<VkBufferImageCopy> regions(mipLevels);
int currentWidth = w;
int 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, currentMipLevel, 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, info->fImage, info->fImageLayout,
regions.count(), regions.begin()));
} else {
combinedBufferSize = GrComputeTightCombinedBufferSize(bytesPerPixel, w, h,
&individualMipOffsets, mipLevels);
SkASSERT(color);
VkClearColorValue vkColor;
// If we ever support SINT or UINT formats this needs to be updated to use the int32 and
// uint32 union members in those cases.
vkColor.float32[0] = color->fR;
vkColor.float32[1] = color->fG;
vkColor.float32[2] = color->fB;
vkColor.float32[3] = color->fA;
VkImageSubresourceRange range;
range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
range.baseArrayLayer = 0;
range.baseMipLevel = 0;
range.layerCount = 1;
range.levelCount = mipLevels;
VK_CALL(CmdClearColorImage(cmdBuffer, info->fImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
&vkColor, 1, &range));
}
VkBufferCreateInfo bufInfo;
memset(&bufInfo, 0, sizeof(VkBufferCreateInfo));
bufInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
bufInfo.flags = fProtectedContext == GrProtected::kYes ? VK_BUFFER_CREATE_PROTECTED_BIT : 0;
bufInfo.size = combinedBufferSize;
bufInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
bufInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
bufInfo.queueFamilyIndexCount = 0;
bufInfo.pQueueFamilyIndices = nullptr;
err = VK_CALL(CreateBuffer(fDevice, &bufInfo, nullptr, &buffer));
if (err) {
GrVkImage::DestroyImageInfo(this, info);
VK_CALL(EndCommandBuffer(cmdBuffer));
VK_CALL(FreeCommandBuffers(fDevice, fCmdPool->vkCommandPool(), 1, &cmdBuffer));
return false;
}
if (!GrVkMemory::AllocAndBindBufferMemory(this, buffer, GrVkBuffer::kCopyRead_Type, true,
&bufferAlloc)) {
GrVkImage::DestroyImageInfo(this, info);
VK_CALL(DestroyBuffer(fDevice, buffer, nullptr));
VK_CALL(EndCommandBuffer(cmdBuffer));
VK_CALL(FreeCommandBuffers(fDevice, fCmdPool->vkCommandPool(), 1, &cmdBuffer));
return false;
}
bool result;
if (!srcData) {
result = fill_in_with_color(this, bufferAlloc, vkFormat, w, h, individualMipOffsets,
config, *color);
} else if (isCompressed) {
result = copy_compressed_src_data(this, bufferAlloc, compressionType, w, h, srcData);
} else {
SkASSERT(1 == mipLevels);
result = copy_src_data(this, bufferAlloc, vkFormat, w, h, srcData, srcRowBytes);
}
if (!result) {
GrVkImage::DestroyImageInfo(this, info);
GrVkMemory::FreeBufferMemory(this, GrVkBuffer::kCopyRead_Type, bufferAlloc);
VK_CALL(DestroyBuffer(fDevice, buffer, nullptr));
VK_CALL(EndCommandBuffer(cmdBuffer));
VK_CALL(FreeCommandBuffers(fDevice, fCmdPool->vkCommandPool(), 1, &cmdBuffer));
return false;
}
// Set image layout and add barrier
set_image_layout(this->vkInterface(), cmdBuffer, info,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, mipLevels,
VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
SkTArray<VkBufferImageCopy> regions(mipLevels);
int currentWidth = w;
int 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, currentMipLevel, 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, info->fImage, info->fImageLayout,
regions.count(), regions.begin()));
if (!srcData && renderable) {
SkASSERT(color);
@ -1927,15 +1924,10 @@ GrBackendTexture GrVkGpu::createBackendTexture(int w, int h,
return GrBackendTexture();
}
GrPixelConfig config;
if (!vk_format_to_pixel_config(*vkFormat, &config)) {
SkDebugf("Could net get vkformat\n");
return GrBackendTexture();
}
GrVkImageInfo info;
if (!this->createTestingOnlyVkImage(config, w, h, true, GrRenderable::kYes == renderable,
mipMapped, srcData, rowBytes, color, &info, isProtected)) {
if (!this->createVkImageForBackendSurface(*vkFormat, w, h, true,
GrRenderable::kYes == renderable, mipMapped, srcData,
rowBytes, color, &info, isProtected)) {
SkDebugf("Failed to create testing only image\n");
return GrBackendTexture();
}
@ -1943,6 +1935,10 @@ GrBackendTexture GrVkGpu::createBackendTexture(int w, int h,
#if GR_TEST_UTILS
// Lots of tests don't go through Skia's public interface which will set the config so for
// testing we make sure we set a config here.
GrPixelConfig config = kUnknown_GrPixelConfig;
if (!vk_format_to_pixel_config(*vkFormat, &config)) {
SkDebugf("Could net get vkformat\n");
}
beTex.setPixelConfig(config);
#endif
return beTex;
@ -1991,10 +1987,15 @@ GrBackendRenderTarget GrVkGpu::createTestingOnlyBackendRenderTarget(int w, int h
if (kUnknown_GrPixelConfig == config) {
return {};
}
VkFormat vkFormat;
if (!GrPixelConfigToVkFormat(config, &vkFormat)) {
return {};
}
GrVkImageInfo info;
if (!this->createTestingOnlyVkImage(config, w, h, false, true, GrMipMapped::kNo, nullptr, 0,
&SkColors::kTransparent, &info, GrProtected::kNo)) {
if (!this->createVkImageForBackendSurface(vkFormat, w, h, false, true, GrMipMapped::kNo,
nullptr, 0, &SkColors::kTransparent, &info,
GrProtected::kNo)) {
return {};
}
GrBackendRenderTarget beRT = GrBackendRenderTarget(w, h, 1, 0, info);

View File

@ -261,10 +261,10 @@ private:
void resolveImage(GrSurface* dst, GrVkRenderTarget* src, const SkIRect& srcRect,
const SkIPoint& dstPoint);
bool createTestingOnlyVkImage(GrPixelConfig config, int w, int h, bool texturable,
bool renderable, GrMipMapped mipMapped, const void* srcData,
size_t srcRowBytes, const SkColor4f* color, GrVkImageInfo* info,
GrProtected isProtected);
bool createVkImageForBackendSurface(VkFormat vkFormat, int w, int h, bool texturable,
bool renderable, GrMipMapped mipMapped, const void* srcData,
size_t srcRowBytes, const SkColor4f* color,
GrVkImageInfo* info, GrProtected isProtected);
sk_sp<const GrVkInterface> fInterface;
sk_sp<GrVkMemoryAllocator> fMemoryAllocator;

View File

@ -121,6 +121,8 @@ bool GrVkFormatPixelConfigPairIsValid(VkFormat format, GrPixelConfig config) {
// R4G4B4A4 is not required to be supported so we actually
// store RGBA_4444 data as B4G4R4A4.
return kRGBA_4444_GrPixelConfig == config;
case VK_FORMAT_R4G4B4A4_UNORM_PACK16:
return kRGBA_4444_GrPixelConfig == config;
case VK_FORMAT_R8_UNORM:
return kAlpha_8_GrPixelConfig == config ||
kAlpha_8_as_Red_GrPixelConfig == config ||

View File

@ -696,7 +696,7 @@ DEF_GPUTEST_FOR_VULKAN_CONTEXT(VkBackendAllocationTest, reporter, ctxInfo) {
{ kRGBA_1010102_SkColorType, VK_FORMAT_A2B10G10R10_UNORM_PACK32, { 0.5f, 0, 0, 1.0f } },
{ kRGB_565_SkColorType, VK_FORMAT_R5G6B5_UNORM_PACK16, SkColors::kRed },
{ kARGB_4444_SkColorType, VK_FORMAT_R4G4B4A4_UNORM_PACK16, SkColors::kGreen },
{ kARGB_4444_SkColorType, VK_FORMAT_R4G4B4A4_UNORM_PACK16, SkColors::kCyan },
{ kARGB_4444_SkColorType, VK_FORMAT_B4G4R4A4_UNORM_PACK16, SkColors::kYellow },
{ kAlpha_8_SkColorType, VK_FORMAT_R8_UNORM, kTransCol },
@ -765,12 +765,37 @@ DEF_GPUTEST_FOR_VULKAN_CONTEXT(VkBackendAllocationTest, reporter, ctxInfo) {
}
{
auto createWithColorMtd = [format](GrContext* context,
const SkColor4f& color,
GrMipMapped mipMapped,
GrRenderable renderable) {
// We're creating backend textures without specifying a color type "view" of
// them at the public API level. Therefore, Ganesh will not apply any swizzles
// before writing the color to the texture. However, our validation code does
// rely on interpreting the texture contents via a SkColorType and therefore
// swizzles may be applied during the read step.
// Ideally we'd update our validation code to use a "raw" read that doesn't
// impose a color type but for now we just munge the data we upload to match the
// expectation.
GrSwizzle swizzle;
switch (combo.fColorType) {
case kAlpha_8_SkColorType:
SkASSERT(combo.fFormat == VK_FORMAT_R8_UNORM);
swizzle = GrSwizzle("aaaa");
break;
case kARGB_4444_SkColorType:
if (combo.fFormat == VK_FORMAT_B4G4R4A4_UNORM_PACK16) {
swizzle = GrSwizzle("bgra");
}
break;
default:
swizzle = GrSwizzle("rgba");
break;
}
auto createWithColorMtd = [format, swizzle](GrContext* context,
const SkColor4f& color,
GrMipMapped mipMapped,
GrRenderable renderable) {
auto swizzledColor = swizzle.applyTo(color);
GrBackendTexture beTex = context->createBackendTexture(32, 32, format,
color, mipMapped,
swizzledColor,
mipMapped,
renderable,
GrProtected::kNo);
check_vk_layout(beTex, GrRenderable::kYes == renderable
@ -778,7 +803,6 @@ DEF_GPUTEST_FOR_VULKAN_CONTEXT(VkBackendAllocationTest, reporter, ctxInfo) {
: VkLayout::kReadOnlyOptimal);
return beTex;
};
test_color_init(context, reporter, createWithColorMtd,
combo.fColorType, combo.fColor, mipMapped, renderable);
}