Add support for RGB config to Vulkan.
This adds support for RGB, but from investigating, most desktops don't
support RGB at all, and on Android it is usually support as a linear
format and not necessarily an optimal one. So until we get better support
for linear formats this CL doesn't necessarily add more feature support to
our vulkan backend.
Bug: skia:8349
Change-Id: I1066ddafa660a1ef1d90dbf3e127e067d6132d45
Reviewed-on: https://skia-review.googlesource.com/156600
Commit-Queue: Greg Daniel <egdaniel@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
diff --git a/src/gpu/vk/GrVkCaps.cpp b/src/gpu/vk/GrVkCaps.cpp
index a1388a6..08a3e4d 100644
--- a/src/gpu/vk/GrVkCaps.cpp
+++ b/src/gpu/vk/GrVkCaps.cpp
@@ -712,8 +712,10 @@
}
break;
case kRGB_888x_SkColorType:
- // TODO: VK_FORMAT_R8G8B8_UNORM
- return false;
+ if (VK_FORMAT_R8G8B8_UNORM == format) {
+ *config = kRGB_888_GrPixelConfig;
+ }
+ break;
case kBGRA_8888_SkColorType:
if (VK_FORMAT_B8G8R8A8_UNORM == format) {
*config = kBGRA_8888_GrPixelConfig;
diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp
index 4505138..c415dd0 100644
--- a/src/gpu/vk/GrVkGpu.cpp
+++ b/src/gpu/vk/GrVkGpu.cpp
@@ -584,6 +584,24 @@
return false;
}
+ if (GrPixelConfigToColorType(tex->config()) != dataColorType) {
+ return false;
+ }
+
+ // For RGB_888x src data we are uploading it first to an RGBA texture and then copying it to the
+ // dst RGB texture. Thus we do not upload mip levels for that.
+ if (dataColorType == GrColorType::kRGB_888x) {
+ SkASSERT(tex->imageFormat() == VK_FORMAT_R8G8B8_UNORM &&
+ tex->config() == kRGB_888_GrPixelConfig);
+ // First check that we'll be able to do the copy to the to the R8G8B8 image in the end via a
+ // blit or draw.
+ if (!this->vkCaps().configCanBeDstofBlit(kRGB_888_GrPixelConfig, tex->isLinearTiled()) &&
+ !this->vkCaps().maxRenderTargetSampleCount(kRGB_888_GrPixelConfig)) {
+ return false;
+ }
+ mipLevelCount = 1;
+ }
+
SkASSERT(this->caps()->isConfigTexturable(tex->config()));
int bpp = GrColorTypeBytesPerPixel(dataColorType);
@@ -592,17 +610,15 @@
// Because of this we need to make a non-const shallow copy of texels.
SkAutoTMalloc<GrMipLevel> texelsShallowCopy;
- if (mipLevelCount) {
- texelsShallowCopy.reset(mipLevelCount);
- memcpy(texelsShallowCopy.get(), texels, mipLevelCount*sizeof(GrMipLevel));
- }
+ texelsShallowCopy.reset(mipLevelCount);
+ memcpy(texelsShallowCopy.get(), texels, mipLevelCount*sizeof(GrMipLevel));
SkTArray<size_t> individualMipOffsets(mipLevelCount);
individualMipOffsets.push_back(0);
size_t combinedBufferSize = width * bpp * height;
int currentWidth = width;
int currentHeight = height;
- if (mipLevelCount > 0 && !texelsShallowCopy[0].fPixels) {
+ if (!texelsShallowCopy[0].fPixels) {
combinedBufferSize = 0;
}
@@ -634,16 +650,55 @@
// allocate buffer to hold our mip data
GrVkTransferBuffer* transferBuffer =
GrVkTransferBuffer::Create(this, combinedBufferSize, GrVkBuffer::kCopyRead_Type);
- if(!transferBuffer) {
+ if (!transferBuffer) {
return false;
}
+ int uploadLeft = left;
+ int uploadTop = top;
+ GrVkTexture* uploadTexture = tex;
+ // For uploading RGB_888x data to an R8G8B8_UNORM texture we must first upload the data to an
+ // R8G8B8A8_UNORM image and then copy it.
+ sk_sp<GrVkTexture> copyTexture;
+ if (dataColorType == GrColorType::kRGB_888x) {
+ GrSurfaceDesc surfDesc;
+ surfDesc.fFlags = kRenderTarget_GrSurfaceFlag;
+ surfDesc.fWidth = width;
+ surfDesc.fHeight = height;
+ surfDesc.fConfig = kRGBA_8888_GrPixelConfig;
+ surfDesc.fSampleCnt = 1;
+
+ VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_SAMPLED_BIT |
+ VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
+ VK_IMAGE_USAGE_TRANSFER_DST_BIT;
+
+ GrVkImage::ImageDesc imageDesc;
+ imageDesc.fImageType = VK_IMAGE_TYPE_2D;
+ imageDesc.fFormat = VK_FORMAT_R8G8B8A8_UNORM;
+ imageDesc.fWidth = width;
+ imageDesc.fHeight = height;
+ imageDesc.fLevels = 1;
+ imageDesc.fSamples = 1;
+ imageDesc.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
+ imageDesc.fUsageFlags = usageFlags;
+ imageDesc.fMemProps = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
+
+ copyTexture = GrVkTexture::MakeNewTexture(this, SkBudgeted::kYes, surfDesc, imageDesc,
+ GrMipMapsStatus::kNotAllocated);
+ if (!copyTexture) {
+ return false;
+ }
+ uploadTexture = copyTexture.get();
+ uploadLeft = 0;
+ uploadTop = 0;
+ }
+
char* buffer = (char*) transferBuffer->map();
SkTArray<VkBufferImageCopy> regions(mipLevelCount);
currentWidth = width;
currentHeight = height;
- int layerHeight = tex->height();
+ int layerHeight = uploadTexture->height();
for (int currentMipLevel = 0; currentMipLevel < mipLevelCount; currentMipLevel++) {
if (texelsShallowCopy[currentMipLevel].fPixels) {
SkASSERT(1 == mipLevelCount || currentHeight == layerHeight);
@@ -663,7 +718,7 @@
region.bufferRowLength = currentWidth;
region.bufferImageHeight = currentHeight;
region.imageSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, SkToU32(currentMipLevel), 0, 1 };
- region.imageOffset = {left, top, 0};
+ region.imageOffset = {uploadLeft, uploadTop, 0};
region.imageExtent = { (uint32_t)currentWidth, (uint32_t)currentHeight, 1 };
}
currentWidth = SkTMax(1, currentWidth/2);
@@ -675,20 +730,30 @@
transferBuffer->unmap();
// Change layout of our target so it can be copied to
- tex->setImageLayout(this,
- VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
- VK_ACCESS_TRANSFER_WRITE_BIT,
- VK_PIPELINE_STAGE_TRANSFER_BIT,
- false);
+ uploadTexture->setImageLayout(this,
+ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+ VK_ACCESS_TRANSFER_WRITE_BIT,
+ VK_PIPELINE_STAGE_TRANSFER_BIT,
+ false);
// Copy the buffer to the image
fCurrentCmdBuffer->copyBufferToImage(this,
transferBuffer,
- tex,
+ uploadTexture,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
regions.count(),
regions.begin());
transferBuffer->unref();
+
+ // If we copied the data into a temporary image first, copy that image into our main texture
+ // now.
+ if (copyTexture.get()) {
+ SkASSERT(dataColorType == GrColorType::kRGB_888x);
+ static const GrSurfaceOrigin kOrigin = kTopLeft_GrSurfaceOrigin;
+ SkAssertResult(this->copySurface(tex, kOrigin, copyTexture.get(), kOrigin,
+ SkIRect::MakeWH(width, height), SkIPoint::Make(left, top),
+ false));
+ }
if (1 == mipLevelCount) {
tex->texturePriv().markMipMapsDirty();
}
@@ -745,12 +810,11 @@
sk_sp<GrVkTexture> tex;
if (renderTarget) {
- tex = GrVkTextureRenderTarget::CreateNewTextureRenderTarget(this, budgeted, desc,
- imageDesc,
- mipMapsStatus);
+ tex = GrVkTextureRenderTarget::MakeNewTextureRenderTarget(this, budgeted, desc,
+ imageDesc,
+ mipMapsStatus);
} else {
- tex = GrVkTexture::CreateNewTexture(this, budgeted, desc, imageDesc,
- mipMapsStatus);
+ tex = GrVkTexture::MakeNewTexture(this, budgeted, desc, imageDesc, mipMapsStatus);
}
if (!tex) {
@@ -1811,6 +1875,65 @@
return false;
}
+ // Skia's RGB_888x color type, which we map to the vulkan R8G8B8_UNORM, expects the data to be
+ // 32 bits, but the Vulkan format is only 24. So we first copy the surface into an R8G8B8A8
+ // image and then do the read pixels from that.
+ sk_sp<GrVkTextureRenderTarget> copySurface;
+ if (dstColorType == GrColorType::kRGB_888x) {
+ SkASSERT(image->imageFormat() == VK_FORMAT_R8G8B8_UNORM &&
+ surface->config() == kRGB_888_GrPixelConfig);
+
+ // Make a new surface that is RGBA to copy the RGB surface into.
+ GrSurfaceDesc surfDesc;
+ surfDesc.fFlags = kRenderTarget_GrSurfaceFlag;
+ surfDesc.fWidth = width;
+ surfDesc.fHeight = height;
+ surfDesc.fConfig = kRGBA_8888_GrPixelConfig;
+ surfDesc.fSampleCnt = 1;
+
+ VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
+ VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
+ VK_IMAGE_USAGE_TRANSFER_DST_BIT;
+
+ GrVkImage::ImageDesc imageDesc;
+ imageDesc.fImageType = VK_IMAGE_TYPE_2D;
+ imageDesc.fFormat = VK_FORMAT_R8G8B8A8_UNORM;
+ imageDesc.fWidth = width;
+ imageDesc.fHeight = height;
+ imageDesc.fLevels = 1;
+ imageDesc.fSamples = 1;
+ imageDesc.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
+ imageDesc.fUsageFlags = usageFlags;
+ imageDesc.fMemProps = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
+
+ copySurface = GrVkTextureRenderTarget::MakeNewTextureRenderTarget(
+ this, SkBudgeted::kYes, surfDesc, imageDesc, GrMipMapsStatus::kNotAllocated);
+ if (!copySurface) {
+ return false;
+ }
+
+ int srcSampleCount = 0;
+ if (rt) {
+ srcSampleCount = rt->numColorSamples();
+ }
+ static const GrSurfaceOrigin kOrigin = kTopLeft_GrSurfaceOrigin;
+ if (!this->vkCaps().canCopyAsBlit(copySurface->config(), 1, kOrigin,
+ surface->config(), srcSampleCount, kOrigin) ||
+ !this->vkCaps().canCopyAsDraw(copySurface->config(), false,
+ surface->config(), SkToBool(surface->asTexture()))) {
+ return false;
+ }
+ SkIRect srcRect = SkIRect::MakeXYWH(left, top, width, height);
+ if (!this->copySurface(copySurface.get(), kOrigin, surface, kOrigin,
+ srcRect, SkIPoint::Make(0,0))) {
+ return false;
+ }
+ top = 0;
+ left = 0;
+ dstColorType = GrColorType::kRGBA_8888;
+ image = copySurface.get();
+ }
+
// Change layout of our target so it can be used as copy
image->setImageLayout(this,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
diff --git a/src/gpu/vk/GrVkTexture.cpp b/src/gpu/vk/GrVkTexture.cpp
index 400d3d5..d072a88 100644
--- a/src/gpu/vk/GrVkTexture.cpp
+++ b/src/gpu/vk/GrVkTexture.cpp
@@ -64,10 +64,10 @@
SkASSERT((GrMipMapsStatus::kNotAllocated == mipMapsStatus) == (1 == info.fLevelCount));
}
-sk_sp<GrVkTexture> GrVkTexture::CreateNewTexture(GrVkGpu* gpu, SkBudgeted budgeted,
- const GrSurfaceDesc& desc,
- const GrVkImage::ImageDesc& imageDesc,
- GrMipMapsStatus mipMapsStatus) {
+sk_sp<GrVkTexture> GrVkTexture::MakeNewTexture(GrVkGpu* gpu, SkBudgeted budgeted,
+ const GrSurfaceDesc& desc,
+ const GrVkImage::ImageDesc& imageDesc,
+ GrMipMapsStatus mipMapsStatus) {
SkASSERT(imageDesc.fUsageFlags & VK_IMAGE_USAGE_SAMPLED_BIT);
GrVkImageInfo info;
diff --git a/src/gpu/vk/GrVkTexture.h b/src/gpu/vk/GrVkTexture.h
index c6f7c27..9c6b7b1 100644
--- a/src/gpu/vk/GrVkTexture.h
+++ b/src/gpu/vk/GrVkTexture.h
@@ -17,11 +17,11 @@
class GrVkTexture : public GrTexture, public virtual GrVkImage {
public:
- static sk_sp<GrVkTexture> CreateNewTexture(GrVkGpu*,
- SkBudgeted budgeted,
- const GrSurfaceDesc&,
- const GrVkImage::ImageDesc&,
- GrMipMapsStatus);
+ static sk_sp<GrVkTexture> MakeNewTexture(GrVkGpu*,
+ SkBudgeted budgeted,
+ const GrSurfaceDesc&,
+ const GrVkImage::ImageDesc&,
+ GrMipMapsStatus);
static sk_sp<GrVkTexture> MakeWrappedTexture(GrVkGpu*, const GrSurfaceDesc&,
GrWrapOwnership, const GrVkImageInfo&,
diff --git a/src/gpu/vk/GrVkTextureRenderTarget.cpp b/src/gpu/vk/GrVkTextureRenderTarget.cpp
index 0fde5f9..581dcc0 100644
--- a/src/gpu/vk/GrVkTextureRenderTarget.cpp
+++ b/src/gpu/vk/GrVkTextureRenderTarget.cpp
@@ -200,11 +200,11 @@
}
sk_sp<GrVkTextureRenderTarget>
-GrVkTextureRenderTarget::CreateNewTextureRenderTarget(GrVkGpu* gpu,
- SkBudgeted budgeted,
- const GrSurfaceDesc& desc,
- const GrVkImage::ImageDesc& imageDesc,
- GrMipMapsStatus mipMapsStatus) {
+GrVkTextureRenderTarget::MakeNewTextureRenderTarget(GrVkGpu* gpu,
+ SkBudgeted budgeted,
+ const GrSurfaceDesc& desc,
+ const GrVkImage::ImageDesc& imageDesc,
+ GrMipMapsStatus mipMapsStatus) {
SkASSERT(imageDesc.fUsageFlags & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
SkASSERT(imageDesc.fUsageFlags & VK_IMAGE_USAGE_SAMPLED_BIT);
diff --git a/src/gpu/vk/GrVkTextureRenderTarget.h b/src/gpu/vk/GrVkTextureRenderTarget.h
index 0a0ba4d..bd3973c 100644
--- a/src/gpu/vk/GrVkTextureRenderTarget.h
+++ b/src/gpu/vk/GrVkTextureRenderTarget.h
@@ -25,10 +25,10 @@
class GrVkTextureRenderTarget: public GrVkTexture, public GrVkRenderTarget {
public:
- static sk_sp<GrVkTextureRenderTarget> CreateNewTextureRenderTarget(GrVkGpu*, SkBudgeted,
- const GrSurfaceDesc&,
- const GrVkImage::ImageDesc&,
- GrMipMapsStatus);
+ static sk_sp<GrVkTextureRenderTarget> MakeNewTextureRenderTarget(GrVkGpu*, SkBudgeted,
+ const GrSurfaceDesc&,
+ const GrVkImage::ImageDesc&,
+ GrMipMapsStatus);
static sk_sp<GrVkTextureRenderTarget> MakeWrappedTextureRenderTarget(GrVkGpu*,
const GrSurfaceDesc&,
diff --git a/src/gpu/vk/GrVkUtil.cpp b/src/gpu/vk/GrVkUtil.cpp
index b0aa3d4..71279cd 100644
--- a/src/gpu/vk/GrVkUtil.cpp
+++ b/src/gpu/vk/GrVkUtil.cpp
@@ -23,8 +23,8 @@
*format = VK_FORMAT_R8G8B8A8_UNORM;
return true;
case kRGB_888_GrPixelConfig:
- // TODO: VK_FORMAT_R8G8B8_UNORM
- return false;
+ *format = VK_FORMAT_R8G8B8_UNORM;
+ return true;
case kBGRA_8888_GrPixelConfig:
*format = VK_FORMAT_B8G8R8A8_UNORM;
return true;
@@ -85,6 +85,8 @@
return kSRGBA_8888_GrPixelConfig == config;
case VK_FORMAT_B8G8R8A8_SRGB:
return kSBGRA_8888_GrPixelConfig == config;
+ case VK_FORMAT_R8G8B8_UNORM:
+ return kRGB_888_GrPixelConfig == config;
case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
return kRGBA_1010102_GrPixelConfig == config;
case VK_FORMAT_R5G6B5_UNORM_PACK16:
@@ -119,6 +121,7 @@
case VK_FORMAT_R8G8B8A8_SRGB:
case VK_FORMAT_B8G8R8A8_SRGB:
case VK_FORMAT_R8G8B8A8_SINT:
+ case VK_FORMAT_R8G8B8_UNORM:
case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
case VK_FORMAT_R5G6B5_UNORM_PACK16:
case VK_FORMAT_B4G4R4A4_UNORM_PACK16: