Add SkImage::MakeRasterFromCompressed and make MakeFromCompressed fall back to decompression for unsupported compression types (take 2)

This is intended to make using compressed textures easier since developers can just provided compressed data and it will be uploaded to the GPU in some way, shape or form.


TBR=reed@google.com
Change-Id: I8c672ccc7db5cd098f629c3469ae7cbdc7436392
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/266939
Reviewed-by: Robert Phillips <robertphillips@google.com>
Commit-Queue: Robert Phillips <robertphillips@google.com>
This commit is contained in:
Robert Phillips 2020-01-27 16:11:57 -05:00 committed by Skia Commit-Bot
parent 9f8c6ea7af
commit 99dead9830
21 changed files with 365 additions and 99 deletions

View File

@ -13,6 +13,12 @@ Milestone 81
makes SkBitmap match the behavior of raster SkSurfaces in rejecting
non-aligned rowBytes.
* Added an SkImage::MakeRasterFromCompressed entry point. Also updated
SkImage::MakeFromCompressed to decompress the compressed image data if
the GPU doesn't support the specified compression type (i.e., macOS Metal
doesn't support BC1_RGB8_UNORM so such compressed images will always be
decompressed on that platform).
* Added support for BC1 RGBA compressed textures
* Added CachingHint to SkImage::makeRasterImage

View File

@ -7,7 +7,7 @@
#include "include/core/SkTypes.h" // IWYU pragma: keep
#if !defined(SK_BUILD_FOR_GOOGLE3)
#if !defined(SK_BUILD_FOR_GOOGLE3) // Google3 doesn't have etc1.h
#include "gm/gm.h"
#include "include/core/SkBitmap.h"
@ -21,13 +21,27 @@
#include "include/core/SkRefCnt.h"
#include "include/core/SkSize.h"
#include "include/core/SkString.h"
#include "src/core/SkCompressedDataUtils.h"
#include "src/core/SkMipMap.h"
#include "src/gpu/GrContextPriv.h"
#include "src/gpu/GrDataUtils.h"
#include "src/image/SkImage_Base.h"
#include "third_party/etc1/etc1.h"
class GrContext;
class GrRenderTargetContext;
static sk_sp<SkColorFilter> make_color_filter() {
// rotate R, G and B
float colorMatrix[20] = {
0, 1, 0, 0, 0,
0, 0, 1, 0, 0,
1, 0, 0, 0, 0,
0, 0, 0, 1, 0
};
return SkColorFilters::Matrix(colorMatrix);
}
static SkPoint gen_pt(float angle, const SkVector& scale) {
SkScalar s = SkScalarSin(angle);
SkScalar c = SkScalarCos(angle);
@ -97,7 +111,7 @@ static sk_sp<SkData> make_compressed_data(SkISize dimensions,
SkColorType colorType,
bool opaque,
SkImage::CompressionType compression) {
size_t totalSize = GrCompressedDataSize(compression, dimensions, nullptr, GrMipMapped::kYes);
size_t totalSize = SkCompressedDataSize(compression, dimensions, nullptr, true);
sk_sp<SkData> tmp = SkData::MakeUninitialized(totalSize);
char* pixels = (char*) tmp->writable_data();
@ -118,7 +132,7 @@ static sk_sp<SkData> make_compressed_data(SkISize dimensions,
};
for (int i = 0; i < numMipLevels; ++i) {
size_t levelSize = GrCompressedDataSize(compression, dimensions, nullptr, GrMipMapped::kNo);
size_t levelSize = SkCompressedDataSize(compression, dimensions, nullptr, false);
SkBitmap bm = render_level(dimensions, kColors[i%7], colorType, opaque);
if (compression == SkImage::CompressionType::kETC2_RGB8_UNORM) {
@ -150,7 +164,7 @@ static sk_sp<SkData> make_compressed_data(SkISize dimensions,
// RGBA8 | | kBC1_RGBA8_UNORM |
// --------------------------------------
//
class CompressedTexturesGM : public skiagm::GpuGM {
class CompressedTexturesGM : public skiagm::GM {
public:
CompressedTexturesGM() {
this->setBGColor(0xFFCCCCCC);
@ -179,7 +193,9 @@ protected:
SkImage::CompressionType::kBC1_RGBA8_UNORM);
}
void onDraw(GrContext* context, GrRenderTargetContext*, SkCanvas* canvas) override {
void onDraw(SkCanvas* canvas) override {
GrContext* context = canvas->getGrContext();
this->drawCell(context, canvas, fOpaqueETC2Data,
SkImage::CompressionType::kETC2_RGB8_UNORM, { kPad, kPad });
@ -195,9 +211,18 @@ private:
void drawCell(GrContext* context, SkCanvas* canvas, sk_sp<SkData> data,
SkImage::CompressionType compression, SkIVector offset) {
sk_sp<SkImage> image = SkImage::MakeFromCompressed(context, data,
kTexWidth, kTexHeight,
compression, GrMipMapped::kYes);
sk_sp<SkImage> image;
if (context) {
image = SkImage::MakeFromCompressed(context, std::move(data), kTexWidth, kTexHeight,
compression, GrMipMapped::kYes);
} else {
image = SkImage::MakeRasterFromCompressed(std::move(data), kTexWidth, kTexHeight,
compression);
}
if (!image) {
return;
}
SkISize dimensions{ kTexWidth, kTexHeight };
int numMipLevels = SkMipMap::ComputeLevelCount(dimensions.width(), dimensions.height()) + 1;
@ -205,6 +230,19 @@ private:
SkPaint paint;
paint.setFilterQuality(kHigh_SkFilterQuality); // to force mipmapping
bool isCompressed = false;
if (image->isTextureBacked()) {
const GrCaps* caps = context->priv().caps();
GrTextureProxy* proxy = as_IB(image)->peekProxy();
isCompressed = caps->isFormatCompressed(proxy->backendFormat());
}
if (!isCompressed) {
// Make it obvious which drawImages used decompressed images
paint.setColorFilter(make_color_filter());
}
for (int i = 0; i < numMipLevels; ++i) {
SkRect r = SkRect::MakeXYWH(offset.fX, offset.fY,
dimensions.width(), dimensions.height());

View File

@ -151,6 +151,8 @@ skia_core_sources = [
"$_src/core/SkColorFilter_Matrix.h",
"$_src/core/SkColorSpace.cpp",
"$_src/core/SkColorSpaceXformSteps.cpp",
"$_src/core/SkCompressedDataUtils.h",
"$_src/core/SkCompressedDataUtils.cpp",
"$_src/core/SkContourMeasure.cpp",
"$_src/core/SkConvertPixels.cpp",
"$_src/core/SkConvertPixels.h",

View File

@ -257,8 +257,12 @@ public:
/** Creates a GPU-backed SkImage from compressed data.
SkImage is returned if format of the compressed data is supported.
Supported formats vary by platform.
This method will return an SkImage representing the compressed data.
If the GPU doesn't support the specified compression method, the data
will be decompressed and then wrapped in a GPU-backed image.
Note: one can query the supported compression formats via
GrContext::compressedBackendFormat.
@param context GPU context
@param data compressed data to store in SkImage
@ -269,11 +273,28 @@ public:
@param isProtected do the contents of 'data' require DRM protection (on Vulkan)?
@return created SkImage, or nullptr
*/
static sk_sp<SkImage> MakeFromCompressed(GrContext* context, sk_sp<SkData> data,
int width, int height, CompressionType type,
static sk_sp<SkImage> MakeFromCompressed(GrContext* context,
sk_sp<SkData> data,
int width, int height,
CompressionType type,
GrMipMapped mipMapped = GrMipMapped::kNo,
GrProtected isProtected = GrProtected::kNo);
/** Creates a CPU-backed SkImage from compressed data.
This method will decompress the compressed data and create an image wrapping
it. Any mipmap levels present in the compressed data are discarded.
@param data compressed data to store in SkImage
@param width width of full SkImage
@param height height of full SkImage
@param type type of compression used
@return created SkImage, or nullptr
*/
static sk_sp<SkImage> MakeRasterFromCompressed(sk_sp<SkData> data,
int width, int height,
CompressionType type);
/** User function called when supplied texture may be deleted.
*/
typedef void (*TextureReleaseProc)(ReleaseContext releaseContext);

View File

@ -776,12 +776,6 @@ enum class GrMipMapsStatus {
GR_MAKE_BITFIELD_CLASS_OPS(GpuPathRenderers)
/**
* Returns the data size for the given SkImage::CompressionType
*/
size_t GrCompressedFormatDataSize(SkImage::CompressionType, SkISize dimensions,
GrMipMapped = GrMipMapped::kNo);
/**
* Like SkColorType this describes a layout of pixel data in CPU memory. It specifies the channels,
* their type, and width. This exists so that the GPU backend can have private types that have no
@ -1144,17 +1138,6 @@ static constexpr size_t GrColorTypeBytesPerPixel(GrColorType ct) {
SkUNREACHABLE;
}
static constexpr bool GrCompressionTypeIsOpaque(SkImage::CompressionType compression) {
switch (compression) {
case SkImage::CompressionType::kNone: return true;
case SkImage::CompressionType::kETC2_RGB8_UNORM: return true;
case SkImage::CompressionType::kBC1_RGB8_UNORM: return true;
case SkImage::CompressionType::kBC1_RGBA8_UNORM: return false;
}
SkUNREACHABLE;
}
// In general we try to not mix CompressionType and ColorType, but currently SkImage still requires
// an SkColorType even for CompressedTypes so we need some conversion.
static constexpr SkColorType GrCompressionTypeToSkColorType(SkImage::CompressionType compression) {

View File

@ -0,0 +1,149 @@
/*
* Copyright 2020 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "src/core/SkCompressedDataUtils.h"
#include "include/core/SkColorPriv.h"
#include "include/core/SkData.h"
#include "include/private/SkColorData.h"
#include "src/core/SkMipMap.h"
struct ETC1Block {
uint32_t fHigh;
uint32_t fLow;
};
struct BC1Block {
uint16_t fColor0;
uint16_t fColor1;
uint32_t fIndices;
};
static SkPMColor from565(uint16_t rgb565) {
uint8_t r8 = SkR16ToR32((rgb565 >> 11) & 0x1F);
uint8_t g8 = SkG16ToG32((rgb565 >> 5) & 0x3F);
uint8_t b8 = SkB16ToB32(rgb565 & 0x1F);
return SkPackARGB32(0xFF, r8, g8, b8);
}
static int num_4x4_blocks(int size) {
return ((size + 3) & ~3) >> 2;
}
// return t*col0 + (1-t)*col1
static SkPMColor lerp(float t, SkPMColor col0, SkPMColor col1) {
SkASSERT(SkGetPackedA32(col0) == 0xFF && SkGetPackedA32(col1) == 0xFF);
// TODO: given 't' is only either 1/3 or 2/3 this could be done faster
uint8_t r8 = SkScalarRoundToInt(t * SkGetPackedR32(col0) + (1.0f - t) * SkGetPackedR32(col1));
uint8_t g8 = SkScalarRoundToInt(t * SkGetPackedG32(col0) + (1.0f - t) * SkGetPackedG32(col1));
uint8_t b8 = SkScalarRoundToInt(t * SkGetPackedB32(col0) + (1.0f - t) * SkGetPackedB32(col1));
return SkPackARGB32(0xFF, r8, g8, b8);
}
static bool decompress_bc1(SkISize dimensions, const uint8_t* srcData,
bool isOpaque, SkBitmap* dst) {
const BC1Block* srcBlocks = reinterpret_cast<const BC1Block*>(srcData);
int numXBlocks = num_4x4_blocks(dimensions.width());
int numYBlocks = num_4x4_blocks(dimensions.height());
SkPMColor colors[4];
for (int y = 0; y < numYBlocks; ++y) {
for (int x = 0; x < numXBlocks; ++x) {
const BC1Block* curBlock = &srcBlocks[y * numXBlocks + x];
colors[0] = from565(curBlock->fColor0);
colors[1] = from565(curBlock->fColor1);
if (isOpaque) {
colors[2] = lerp(2.0f/3.0f, colors[0], colors[1]);
colors[3] = lerp(1.0f/3.0f, colors[0], colors[1]);
} else {
colors[2] = SkPackARGB32(
0xFF,
(SkGetPackedR32(colors[0]) + SkGetPackedR32(colors[1])) >> 1,
(SkGetPackedG32(colors[0]) + SkGetPackedG32(colors[1])) >> 1,
(SkGetPackedB32(colors[0]) + SkGetPackedB32(colors[1])) >> 1);
colors[3] = SkPackARGB32(0, 0, 0, 0);
}
int shift = 0;
int offsetX = 4 * x, offsetY = 4 * y;
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
int index = (curBlock->fIndices >> shift) & 0x3;
*dst->getAddr32(offsetX + j, offsetY + i) = colors[index];
shift += 2;
}
}
}
}
return true;
}
// TODO: add decompression of ETC1
bool SkDecompress(sk_sp<SkData> data,
SkISize dimensions,
SkImage::CompressionType compressionType,
SkBitmap* dst) {
using Type = SkImage::CompressionType;
const uint8_t* bytes = data->bytes();
switch (compressionType) {
case Type::kNone: return false;
case Type::kETC2_RGB8_UNORM: return false;
case Type::kBC1_RGB8_UNORM: return decompress_bc1(dimensions, bytes, true, dst);
case Type::kBC1_RGBA8_UNORM: return decompress_bc1(dimensions, bytes, false, dst);
}
SkUNREACHABLE;
return false;
}
size_t SkCompressedDataSize(SkImage::CompressionType type, SkISize dimensions,
SkTArray<size_t>* individualMipOffsets, bool mipMapped) {
SkASSERT(!individualMipOffsets || !individualMipOffsets->count());
int numMipLevels = 1;
if (mipMapped) {
numMipLevels = SkMipMap::ComputeLevelCount(dimensions.width(), dimensions.height()) + 1;
}
size_t totalSize = 0;
switch (type) {
case SkImage::CompressionType::kNone:
break;
case SkImage::CompressionType::kETC2_RGB8_UNORM:
case SkImage::CompressionType::kBC1_RGB8_UNORM:
case SkImage::CompressionType::kBC1_RGBA8_UNORM: {
for (int i = 0; i < numMipLevels; ++i) {
int numBlocks = num_4x4_blocks(dimensions.width()) *
num_4x4_blocks(dimensions.height());
if (individualMipOffsets) {
individualMipOffsets->push_back(totalSize);
}
static_assert(sizeof(ETC1Block) == sizeof(BC1Block));
totalSize += numBlocks * sizeof(ETC1Block);
dimensions = {SkTMax(1, dimensions.width()/2), SkTMax(1, dimensions.height()/2)};
}
break;
}
}
return totalSize;
}
size_t SkCompressedFormatDataSize(SkImage::CompressionType compressionType,
SkISize dimensions, bool mipMapped) {
return SkCompressedDataSize(compressionType, dimensions, nullptr, mipMapped);
}

View File

@ -0,0 +1,48 @@
/*
* Copyright 2020 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkCompressedDataUtils_DEFINED
#define SkCompressedDataUtils_DEFINED
#include "include/core/SkImage.h"
#include "include/core/SkRefCnt.h"
#include "include/core/SkSize.h"
#include "include/private/SkTArray.h"
class SkBitmap;
class SkData;
static constexpr bool SkCompressionTypeIsOpaque(SkImage::CompressionType compression) {
switch (compression) {
case SkImage::CompressionType::kNone: return true;
case SkImage::CompressionType::kETC2_RGB8_UNORM: return true;
case SkImage::CompressionType::kBC1_RGB8_UNORM: return true;
case SkImage::CompressionType::kBC1_RGBA8_UNORM: return false;
}
SkUNREACHABLE;
}
size_t SkCompressedDataSize(SkImage::CompressionType, SkISize baseDimensions,
SkTArray<size_t>* individualMipOffsets, bool mipMapped);
/**
* Returns the data size for the given SkImage::CompressionType
*/
size_t SkCompressedFormatDataSize(SkImage::CompressionType compressionType,
SkISize dimensions, bool mipMapped);
/*
* This method will decompress the bottommost level in 'data' into 'dst'.
*/
bool SkDecompress(sk_sp<SkData> data,
SkISize dimensions,
SkImage::CompressionType compressionType,
SkBitmap* dst);
#endif

View File

@ -8,6 +8,7 @@
#include "src/gpu/GrDataUtils.h"
#include "src/core/SkColorSpaceXformSteps.h"
#include "src/core/SkCompressedDataUtils.h"
#include "src/core/SkConvertPixels.h"
#include "src/core/SkMipMap.h"
#include "src/core/SkTLazy.h"
@ -157,46 +158,6 @@ static void create_BC1_block(SkColor col0, SkColor col1, BC1Block* block) {
}
}
size_t GrCompressedDataSize(SkImage::CompressionType type, SkISize dimensions,
SkTArray<size_t>* individualMipOffsets, GrMipMapped mipMapped) {
SkASSERT(!individualMipOffsets || !individualMipOffsets->count());
int numMipLevels = 1;
if (mipMapped == GrMipMapped::kYes) {
numMipLevels = SkMipMap::ComputeLevelCount(dimensions.width(), dimensions.height()) + 1;
}
size_t totalSize = 0;
switch (type) {
case SkImage::CompressionType::kNone:
break;
case SkImage::CompressionType::kETC2_RGB8_UNORM:
case SkImage::CompressionType::kBC1_RGB8_UNORM:
case SkImage::CompressionType::kBC1_RGBA8_UNORM: {
for (int i = 0; i < numMipLevels; ++i) {
int numBlocks = num_ETC1_blocks(dimensions.width(), dimensions.height());
if (individualMipOffsets) {
individualMipOffsets->push_back(totalSize);
}
static_assert(sizeof(ETC1Block) == sizeof(BC1Block));
totalSize += numBlocks * sizeof(ETC1Block);
dimensions = {SkTMax(1, dimensions.width()/2), SkTMax(1, dimensions.height()/2)};
}
break;
}
}
return totalSize;
}
size_t GrCompressedFormatDataSize(SkImage::CompressionType compressionType,
SkISize dimensions, GrMipMapped mipMapped) {
return GrCompressedDataSize(compressionType, dimensions, nullptr, mipMapped);
}
size_t GrCompressedRowBytes(SkImage::CompressionType type, int width) {
switch (type) {
case SkImage::CompressionType::kNone:
@ -230,7 +191,6 @@ SkISize GrCompressedDimensions(SkImage::CompressionType type, SkISize baseDimens
SkUNREACHABLE;
}
// Fill in 'dest' with ETC1 blocks derived from 'colorf'
static void fillin_ETC1_with_color(SkISize dimensions, const SkColor4f& colorf, char* dest) {
SkColor color = colorf.toSkColor();
@ -263,7 +223,7 @@ static void fillin_BC1_with_color(SkISize dimensions, const SkColor4f& colorf, c
// Fill in 'dstPixels' with BC1 blocks derived from the 'pixmap'.
void GrTwoColorBC1Compress(const SkPixmap& pixmap, SkColor otherColor, char* dstPixels) {
BC1Block* dstBlocks = (BC1Block*) dstPixels;
BC1Block* dstBlocks = reinterpret_cast<BC1Block*>(dstPixels);
SkASSERT(pixmap.colorType() == SkColorType::kRGBA_8888_SkColorType);
BC1Block block;
@ -349,7 +309,7 @@ void GrFillInCompressedData(SkImage::CompressionType type, SkISize dimensions,
size_t offset = 0;
for (int i = 0; i < numMipLevels; ++i) {
size_t levelSize = GrCompressedDataSize(type, dimensions, nullptr, GrMipMapped::kNo);
size_t levelSize = SkCompressedDataSize(type, dimensions, nullptr, false);
if (SkImage::CompressionType::kETC2_RGB8_UNORM == type) {
fillin_ETC1_with_color(dimensions, colorf, &dstPixels[offset]);

View File

@ -15,9 +15,6 @@
class GrImageInfo;
size_t GrCompressedDataSize(SkImage::CompressionType, SkISize baseDimensions,
SkTArray<size_t>* individualMipOffsets, GrMipMapped);
// Returns a value that can be used to set rowBytes for a transfer function.
size_t GrCompressedRowBytes(SkImage::CompressionType, int w);

View File

@ -11,6 +11,7 @@
#include "include/gpu/GrBackendSemaphore.h"
#include "include/gpu/GrBackendSurface.h"
#include "include/gpu/GrContext.h"
#include "src/core/SkCompressedDataUtils.h"
#include "src/core/SkMathPriv.h"
#include "src/core/SkMipMap.h"
#include "src/gpu/GrAuditTrail.h"
@ -293,7 +294,8 @@ sk_sp<GrTexture> GrGpu::createCompressedTexture(SkISize dimensions,
// TODO: expand CompressedDataIsCorrect to work here too
SkImage::CompressionType compressionType = this->caps()->compressionType(format);
if (dataSize < GrCompressedDataSize(compressionType, dimensions, nullptr, mipMapped)) {
if (dataSize < SkCompressedDataSize(compressionType, dimensions, nullptr,
mipMapped == GrMipMapped::kYes)) {
return nullptr;
}
return this->onCreateCompressedTexture(dimensions, format, budgeted, mipMapped, isProtected,
@ -809,8 +811,8 @@ bool GrGpu::CompressedDataIsCorrect(SkISize dimensions, SkImage::CompressionType
SkASSERT(data->type() == BackendTextureData::Type::kCompressed);
size_t computedSize = GrCompressedDataSize(compressionType, dimensions,
nullptr, mipMapped);
size_t computedSize = SkCompressedDataSize(compressionType, dimensions,
nullptr, mipMapped == GrMipMapped::kYes);
return computedSize == data->compressedSize();
}

View File

@ -16,6 +16,7 @@
#include "include/private/GrSingleOwner.h"
#include "include/private/SkImageInfoPriv.h"
#include "src/core/SkAutoPixmapStorage.h"
#include "src/core/SkCompressedDataUtils.h"
#include "src/core/SkImagePriv.h"
#include "src/core/SkMipMap.h"
#include "src/core/SkTraceEvent.h"
@ -601,7 +602,7 @@ sk_sp<GrTextureProxy> GrProxyProvider::wrapCompressedBackendTexture(const GrBack
SkImage::CompressionType compressionType = caps->compressionType(beTex.getBackendFormat());
GrSwizzle texSwizzle = GrCompressionTypeIsOpaque(compressionType) ? GrSwizzle::RGB1()
GrSwizzle texSwizzle = SkCompressionTypeIsOpaque(compressionType) ? GrSwizzle::RGB1()
: GrSwizzle::RGBA();
return sk_sp<GrTextureProxy>(

View File

@ -8,6 +8,7 @@
#include "include/gpu/GrContext.h"
#include "include/gpu/GrSurface.h"
#include "include/gpu/GrTexture.h"
#include "src/core/SkCompressedDataUtils.h"
#include "src/gpu/GrRenderTarget.h"
#include "src/gpu/GrResourceProvider.h"
#include "src/gpu/GrSurfacePriv.h"
@ -35,7 +36,8 @@ size_t GrSurface::ComputeSize(const GrCaps& caps,
SkImage::CompressionType compressionType = caps.compressionType(format);
if (compressionType != SkImage::CompressionType::kNone) {
colorSize = GrCompressedFormatDataSize(compressionType, dimensions, mipMapped);
colorSize = SkCompressedFormatDataSize(compressionType, dimensions,
mipMapped == GrMipMapped::kYes);
} else {
colorSize = (size_t)dimensions.width() * dimensions.height() * caps.bytesPerPixel(format);
}

View File

@ -8,6 +8,7 @@
#include "src/gpu/gl/GrGLCaps.h"
#include "include/gpu/GrContextOptions.h"
#include "src/core/SkCompressedDataUtils.h"
#include "src/core/SkTSearch.h"
#include "src/core/SkTSort.h"
#include "src/gpu/GrProgramDesc.h"
@ -3984,7 +3985,7 @@ GrCaps::SupportedRead GrGLCaps::onSupportedReadPixelsColorType(
SkImage::CompressionType compression = this->compressionType(srcBackendFormat);
if (compression != SkImage::CompressionType::kNone) {
return { GrCompressionTypeIsOpaque(compression) ? GrColorType::kRGB_888x
return { SkCompressionTypeIsOpaque(compression) ? GrColorType::kRGB_888x
: GrColorType::kRGBA_8888,
offset_alignment_for_transfer_buffer(GR_GL_UNSIGNED_BYTE) };
}
@ -4224,7 +4225,7 @@ bool GrGLCaps::onAreColorTypeAndFormatCompatible(GrColorType ct,
SkImage::CompressionType compression = GrGLFormatToCompressionType(glFormat);
if (compression != SkImage::CompressionType::kNone) {
return ct == (GrCompressionTypeIsOpaque(compression) ? GrColorType::kRGB_888x
return ct == (SkCompressionTypeIsOpaque(compression) ? GrColorType::kRGB_888x
: GrColorType::kRGBA_8888);
}

View File

@ -15,6 +15,7 @@
#include "include/private/SkTemplates.h"
#include "include/private/SkTo.h"
#include "src/core/SkAutoMalloc.h"
#include "src/core/SkCompressedDataUtils.h"
#include "src/core/SkConvertPixels.h"
#include "src/core/SkMipMap.h"
#include "src/core/SkTraceEvent.h"
@ -1101,8 +1102,8 @@ bool GrGLGpu::uploadCompressedTexData(GrGLFormat format,
size_t offset = 0;
for (int level = 0; level < numMipLevels; ++level) {
size_t levelDataSize = GrCompressedDataSize(compressionType, dimensions,
nullptr, GrMipMapped::kNo);
size_t levelDataSize = SkCompressedDataSize(compressionType, dimensions,
nullptr, false);
GL_CALL(CompressedTexSubImage2D(target,
level,
@ -1126,8 +1127,8 @@ bool GrGLGpu::uploadCompressedTexData(GrGLFormat format,
size_t offset = 0;
for (int level = 0; level < numMipLevels; ++level) {
size_t levelDataSize = GrCompressedDataSize(compressionType, dimensions,
nullptr, GrMipMapped::kNo);
size_t levelDataSize = SkCompressedDataSize(compressionType, dimensions,
nullptr, false);
const char* rawLevelData = &((char*)data)[offset];
GL_ALLOC_CALL(this->glInterface(), CompressedTexImage2D(target,
@ -1464,7 +1465,8 @@ GrBackendTexture GrGLGpu::onCreateCompressedBackendTexture(SkISize dimensions,
SkImage::CompressionType compression = GrGLFormatToCompressionType(glFormat);
SkASSERT(compression != SkImage::CompressionType::kNone);
rawDataSize = GrCompressedDataSize(compression, dimensions, nullptr, mipMapped);
rawDataSize = SkCompressedDataSize(compression, dimensions, nullptr,
mipMapped == GrMipMapped::kYes);
am.reset(rawDataSize);

View File

@ -7,6 +7,7 @@
#include "src/gpu/mtl/GrMtlGpu.h"
#include "src/core/SkCompressedDataUtils.h"
#include "src/core/SkConvertPixels.h"
#include "src/core/SkMipMap.h"
#include "src/gpu/GrDataUtils.h"
@ -565,8 +566,9 @@ sk_sp<GrTexture> GrMtlGpu::onCreateCompressedTexture(SkISize dimensions,
SkASSERT(compressionType != SkImage::CompressionType::kNone);
SkTArray<size_t> individualMipOffsets(numMipLevels);
SkDEBUGCODE(size_t combinedBufferSize =) GrCompressedDataSize(compressionType, dimensions,
&individualMipOffsets, mipMapped);
SkDEBUGCODE(size_t combinedBufferSize =) SkCompressedDataSize(compressionType, dimensions,
&individualMipOffsets,
mipMapped == GrMipMapped::kYes);
SkASSERT(individualMipOffsets.count() == numMipLevels);
SkASSERT(dataSize == combinedBufferSize);
@ -588,8 +590,7 @@ sk_sp<GrTexture> GrMtlGpu::onCreateCompressedTexture(SkISize dimensions,
SkISize levelDimensions = dimensions;
for (int currentMipLevel = 0; currentMipLevel < numMipLevels; currentMipLevel++) {
const size_t levelRowBytes = GrCompressedRowBytes(compressionType, levelDimensions.width());
size_t levelSize = GrCompressedDataSize(compressionType, levelDimensions, nullptr,
GrMipMapped::kNo);
size_t levelSize = SkCompressedDataSize(compressionType, levelDimensions, nullptr, false);
// TODO: can this all be done in one go?
[blitCmdEncoder copyFromBuffer: transferBuffer

View File

@ -8,6 +8,7 @@
#include "include/gpu/GrBackendSurface.h"
#include "include/gpu/vk/GrVkBackendContext.h"
#include "include/gpu/vk/GrVkExtensions.h"
#include "src/core/SkCompressedDataUtils.h"
#include "src/gpu/GrProgramDesc.h"
#include "src/gpu/GrRenderTarget.h"
#include "src/gpu/GrRenderTargetProxy.h"
@ -1515,7 +1516,7 @@ bool GrVkCaps::onAreColorTypeAndFormatCompatible(GrColorType ct,
SkImage::CompressionType compression = GrVkFormatToCompressionType(vkFormat);
if (compression != SkImage::CompressionType::kNone) {
return ct == (GrCompressionTypeIsOpaque(compression) ? GrColorType::kRGB_888x
return ct == (SkCompressionTypeIsOpaque(compression) ? GrColorType::kRGB_888x
: GrColorType::kRGBA_8888);
}
@ -1643,7 +1644,7 @@ GrCaps::SupportedRead GrVkCaps::onSupportedReadPixelsColorType(
SkImage::CompressionType compression = GrVkFormatToCompressionType(vkFormat);
if (compression != SkImage::CompressionType::kNone) {
return { GrCompressionTypeIsOpaque(compression) ? GrColorType::kRGB_888x
return { SkCompressionTypeIsOpaque(compression) ? GrColorType::kRGB_888x
: GrColorType::kRGBA_8888, 0 };
}

View File

@ -11,6 +11,7 @@
#include "include/gpu/GrBackendSurface.h"
#include "include/gpu/GrContextOptions.h"
#include "include/private/SkTo.h"
#include "src/core/SkCompressedDataUtils.h"
#include "src/core/SkConvertPixels.h"
#include "src/core/SkMipMap.h"
#include "src/gpu/GrContextPriv.h"
@ -717,8 +718,8 @@ static size_t fill_in_regions(GrVkCaps* vkCaps, SkTArray<VkBufferImageCopy>* reg
individualMipOffsets,
numMipLevels);
} else {
combinedBufferSize = GrCompressedDataSize(compression, dimensions,
individualMipOffsets, mipMapped);
combinedBufferSize = SkCompressedDataSize(compression, dimensions, individualMipOffsets,
mipMapped == GrMipMapped::kYes);
}
SkASSERT(individualMipOffsets->count() == numMipLevels);

View File

@ -229,6 +229,19 @@ sk_sp<SkImage> SkImage::MakeFromAdoptedTexture(GrContext* ctx,
sk_sp<SkImage> SkImage::MakeFromCompressed(GrContext* context, sk_sp<SkData> data,
int width, int height, CompressionType type,
GrMipMapped mipMapped, GrProtected isProtected) {
if (!context || !data) {
return nullptr;
}
GrBackendFormat beFormat = context->compressedBackendFormat(type);
if (!beFormat.isValid()) {
sk_sp<SkImage> tmp = MakeRasterFromCompressed(std::move(data), width, height, type);
if (!tmp) {
return nullptr;
}
return tmp->makeTextureImage(context, mipMapped);
}
GrProxyProvider* proxyProvider = context->priv().proxyProvider();
sk_sp<GrTextureProxy> proxy = proxyProvider->createCompressedTextureProxy(
{width, height}, SkBudgeted::kYes, mipMapped, isProtected, type, std::move(data));

View File

@ -12,6 +12,7 @@
#include "include/core/SkSurface.h"
#include "include/private/SkImageInfoPriv.h"
#include "src/codec/SkColorTable.h"
#include "src/core/SkCompressedDataUtils.h"
#include "src/core/SkConvertPixels.h"
#include "src/core/SkImagePriv.h"
#include "src/core/SkTLazy.h"
@ -282,6 +283,39 @@ sk_sp<SkImage> SkImage::MakeRasterData(const SkImageInfo& info, sk_sp<SkData> da
return sk_make_sp<SkImage_Raster>(info, std::move(data), rowBytes);
}
// TODO: this could be improved to decode and make use of the mipmap
// levels potentially present in the compressed data. For now, any
// mipmap levels are discarded.
sk_sp<SkImage> SkImage::MakeRasterFromCompressed(sk_sp<SkData> data,
int width, int height,
CompressionType type) {
size_t expectedSize = SkCompressedFormatDataSize(type, { width, height }, false);
if (!data || data->size() < expectedSize) {
return nullptr;
}
SkAlphaType at = SkCompressionTypeIsOpaque(type) ? kOpaque_SkAlphaType
: kPremul_SkAlphaType;
SkImageInfo ii = SkImageInfo::Make({ width, height }, kRGBA_8888_SkColorType, at);
if (!SkImage_Raster::ValidArgs(ii, ii.minRowBytes(), nullptr)) {
return nullptr;
}
SkBitmap bitmap;
if (!bitmap.tryAllocPixels(ii)) {
return nullptr;
}
if (!SkDecompress(std::move(data), { width, height }, type, &bitmap)) {
return nullptr;
}
bitmap.setImmutable();
return MakeFromBitmap(bitmap);
}
sk_sp<SkImage> SkImage::MakeFromRaster(const SkPixmap& pmap, RasterReleaseProc proc,
ReleaseContext ctx) {
size_t size;

View File

@ -7,6 +7,7 @@
#include "include/gpu/GrContext.h"
#include "src/core/SkAutoPixmapStorage.h"
#include "src/core/SkCompressedDataUtils.h"
#include "src/core/SkMipMap.h"
#include "src/gpu/GrContextPriv.h"
#include "src/image/SkImage_Base.h"
@ -37,7 +38,7 @@ sk_sp<SkImage> create_image(GrContext* context, const GrBackendTexture& backendT
SkImage::CompressionType compression = caps->compressionType(backendTex.getBackendFormat());
SkAlphaType at = GrCompressionTypeIsOpaque(compression) ? kOpaque_SkAlphaType
SkAlphaType at = SkCompressionTypeIsOpaque(compression) ? kOpaque_SkAlphaType
: kPremul_SkAlphaType;
return SkImage::MakeFromCompressedTexture(context,
@ -168,7 +169,8 @@ static std::unique_ptr<const char[]> make_compressed_data(SkImage::CompressionTy
SkTArray<size_t> mipMapOffsets(numMipLevels);
size_t dataSize = GrCompressedDataSize(compression, dimensions, &mipMapOffsets, mipMapped);
size_t dataSize = SkCompressedDataSize(compression, dimensions, &mipMapOffsets,
mipMapped == GrMipMapped::kYes);
char* data = new char[dataSize];
for (int level = 0; level < numMipLevels; ++level) {
@ -205,7 +207,8 @@ static void test_compressed_data_init(GrContext* context,
std::unique_ptr<const char[]> data(make_compressed_data(compression, expectedColors,
mipMapped));
size_t dataSize = GrCompressedDataSize(compression, { 32, 32 }, nullptr, mipMapped);
size_t dataSize = SkCompressedDataSize(compression, { 32, 32 }, nullptr,
mipMapped == GrMipMapped::kYes);
GrBackendTexture backendTex = create(context, data.get(), dataSize, mipMapped);
if (!backendTex.isValid()) {

View File

@ -10,6 +10,7 @@
#include "include/gpu/GrContext.h"
#include "include/gpu/GrTexture.h"
#include "src/core/SkAutoPixmapStorage.h"
#include "src/core/SkCompressedDataUtils.h"
#include "src/gpu/GrClip.h"
#include "src/gpu/GrContextPriv.h"
#include "src/gpu/GrGpu.h"
@ -89,7 +90,7 @@ DEF_GPUTEST_FOR_ALL_CONTEXTS(GrSurfaceRenderability, reporter, ctxInfo) {
if (renderable == GrRenderable::kYes) {
return nullptr;
}
auto size = GrCompressedDataSize(compression, dimensions, nullptr, GrMipMapped::kNo);
auto size = SkCompressedDataSize(compression, dimensions, nullptr, false);
auto data = SkData::MakeUninitialized(size);
SkColor4f color = {0, 0, 0, 0};
GrFillInCompressedData(compression, dimensions, GrMipMapped::kNo,