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:
parent
9f8c6ea7af
commit
99dead9830
@ -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
|
||||
|
@ -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());
|
||||
|
@ -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",
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
149
src/core/SkCompressedDataUtils.cpp
Normal file
149
src/core/SkCompressedDataUtils.cpp
Normal 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);
|
||||
}
|
48
src/core/SkCompressedDataUtils.h
Normal file
48
src/core/SkCompressedDataUtils.h
Normal 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
|
@ -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]);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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>(
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 };
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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));
|
||||
|
@ -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;
|
||||
|
@ -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()) {
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user