Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 314524e

Browse files
rphilliSkia Commit-Bot
authored andcommitted
Add compressed backend textures to Metal (take 2)
Bug: skia:9680 Change-Id: I88035added2fd1721ef98048bd3344ab90e3da5c Reviewed-on: https://skia-review.googlesource.com/c/skia/+/266199 Reviewed-by: Greg Daniel <[email protected]> Commit-Queue: Robert Phillips <[email protected]>
1 parent 7ad393e commit 314524e

File tree

3 files changed

+141
-53
lines changed

3 files changed

+141
-53
lines changed

src/gpu/mtl/GrMtlCaps.mm

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
#include "include/core/SkRect.h"
1111
#include "include/gpu/GrBackendSurface.h"
12+
#include "src/core/SkCompressedDataUtils.h"
1213
#include "src/gpu/GrProcessor.h"
1314
#include "src/gpu/GrProgramDesc.h"
1415
#include "src/gpu/GrProgramInfo.h"
@@ -873,6 +874,13 @@ static bool format_is_srgb(MTLPixelFormat format) {
873874
bool GrMtlCaps::onAreColorTypeAndFormatCompatible(GrColorType ct,
874875
const GrBackendFormat& format) const {
875876
MTLPixelFormat mtlFormat = GrBackendFormatAsMTLPixelFormat(format);
877+
878+
SkImage::CompressionType compression = GrMtlFormatToCompressionType(mtlFormat);
879+
if (compression != SkImage::CompressionType::kNone) {
880+
return ct == (SkCompressionTypeIsOpaque(compression) ? GrColorType::kRGB_888x
881+
: GrColorType::kRGBA_8888);
882+
}
883+
876884
const auto& info = this->getFormatInfo(mtlFormat);
877885
for (int i = 0; i < info.fColorTypeInfoCount; ++i) {
878886
if (info.fColorTypeInfos[i].fColorType == ct) {
@@ -992,6 +1000,17 @@ static bool format_is_srgb(MTLPixelFormat format) {
9921000
GrColorType dstColorType) const {
9931001
MTLPixelFormat mtlFormat = GrBackendFormatAsMTLPixelFormat(srcBackendFormat);
9941002

1003+
SkImage::CompressionType compression = GrMtlFormatToCompressionType(mtlFormat);
1004+
if (compression != SkImage::CompressionType::kNone) {
1005+
#ifdef SK_BUILD_FOR_IOS
1006+
// Reading back to kRGB_888x doesn't work on Metal/iOS (skbug.com/9839)
1007+
return { GrColorType::kUnknown, 0 };
1008+
#else
1009+
return { SkCompressionTypeIsOpaque(compression) ? GrColorType::kRGB_888x
1010+
: GrColorType::kRGBA_8888, 0 };
1011+
#endif
1012+
}
1013+
9951014
// Metal requires the destination offset for copyFromTexture to be a multiple of the textures
9961015
// pixels size.
9971016
size_t offsetAlignment = GrColorTypeBytesPerPixel(srcColorType);

src/gpu/mtl/GrMtlGpu.mm

Lines changed: 115 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
#include "src/gpu/mtl/GrMtlGpu.h"
99

10+
#include "include/private/GrTypesPriv.h"
1011
#include "src/core/SkCompressedDataUtils.h"
1112
#include "src/core/SkConvertPixels.h"
1213
#include "src/core/SkMipMap.h"
@@ -594,7 +595,7 @@ static bool check_max_blit_width(int widthInPixels) {
594595

595596
// TODO: can this all be done in one go?
596597
[blitCmdEncoder copyFromBuffer: transferBuffer
597-
sourceOffset: individualMipOffsets[currentMipLevel]
598+
sourceOffset: bufferOffset + individualMipOffsets[currentMipLevel]
598599
sourceBytesPerRow: levelRowBytes
599600
sourceBytesPerImage: levelSize
600601
sourceSize: MTLSizeMake(levelDimensions.width(),
@@ -644,7 +645,8 @@ static inline void init_surface_desc(GrSurfaceDesc* surfaceDesc, id<MTLTexture>
644645
sk_sp<GrTexture> GrMtlGpu::onWrapBackendTexture(const GrBackendTexture& backendTex,
645646
GrColorType grColorType,
646647
GrWrapOwnership,
647-
GrWrapCacheable cacheable, GrIOType ioType) {
648+
GrWrapCacheable cacheable,
649+
GrIOType ioType) {
648650
id<MTLTexture> mtlTexture = get_texture_from_backend(backendTex);
649651
if (!mtlTexture) {
650652
return nullptr;
@@ -657,9 +659,17 @@ static inline void init_surface_desc(GrSurfaceDesc* surfaceDesc, id<MTLTexture>
657659
}
658660

659661
sk_sp<GrTexture> GrMtlGpu::onWrapCompressedBackendTexture(const GrBackendTexture& backendTex,
660-
GrWrapOwnership ownership,
662+
GrWrapOwnership,
661663
GrWrapCacheable cacheable) {
662-
return nullptr;
664+
id<MTLTexture> mtlTexture = get_texture_from_backend(backendTex);
665+
if (!mtlTexture) {
666+
return nullptr;
667+
}
668+
669+
GrSurfaceDesc surfDesc;
670+
init_surface_desc(&surfDesc, mtlTexture, GrRenderable::kNo);
671+
672+
return GrMtlTexture::MakeWrappedTexture(this, surfDesc, mtlTexture, cacheable, kRead_GrIOType);
663673
}
664674

665675
sk_sp<GrTexture> GrMtlGpu::onWrapRenderableBackendTexture(const GrBackendTexture& backendTex,
@@ -788,7 +798,7 @@ void copy_src_data(char* dst, size_t bytesPerPixel, const SkTArray<size_t>& indi
788798
}
789799
}
790800

791-
bool GrMtlGpu::createMtlTextureForBackendSurface(MTLPixelFormat format,
801+
bool GrMtlGpu::createMtlTextureForBackendSurface(MTLPixelFormat mtlFormat,
792802
SkISize dimensions,
793803
GrTexturable texturable,
794804
GrRenderable renderable,
@@ -800,15 +810,10 @@ void copy_src_data(char* dst, size_t bytesPerPixel, const SkTArray<size_t>& indi
800810
SkASSERT(!data && mipMapped == GrMipMapped::kNo);
801811
}
802812

803-
#ifdef SK_BUILD_FOR_IOS
804-
// Compressed formats go through onCreateCompressedBackendTexture
805-
SkASSERT(!GrMtlFormatIsCompressed(format));
806-
#endif
807-
808-
if (texturable == GrTexturable::kYes && !fMtlCaps->isFormatTexturable(format)) {
813+
if (texturable == GrTexturable::kYes && !fMtlCaps->isFormatTexturable(mtlFormat)) {
809814
return false;
810815
}
811-
if (renderable == GrRenderable::kYes && !fMtlCaps->isFormatRenderable(format, 1)) {
816+
if (renderable == GrRenderable::kYes && !fMtlCaps->isFormatRenderable(mtlFormat, 1)) {
812817
return false;
813818
}
814819

@@ -817,7 +822,7 @@ void copy_src_data(char* dst, size_t bytesPerPixel, const SkTArray<size_t>& indi
817822
}
818823

819824
MTLTextureDescriptor* desc =
820-
[MTLTextureDescriptor texture2DDescriptorWithPixelFormat: format
825+
[MTLTextureDescriptor texture2DDescriptorWithPixelFormat: mtlFormat
821826
width: dimensions.width()
822827
height: dimensions.height()
823828
mipmapped: mipMapped == GrMipMapped::kYes];
@@ -835,8 +840,6 @@ void copy_src_data(char* dst, size_t bytesPerPixel, const SkTArray<size_t>& indi
835840
}
836841

837842
// Create the transfer buffer
838-
size_t bytesPerPixel = fMtlCaps->bytesPerPixel(format);
839-
840843
NSUInteger options = 0; // TODO: consider other options here
841844
if (@available(macOS 10.11, iOS 9.0, *)) {
842845
#ifdef SK_BUILD_FOR_MAC
@@ -851,69 +854,121 @@ void copy_src_data(char* dst, size_t bytesPerPixel, const SkTArray<size_t>& indi
851854
numMipLevels = SkMipMap::ComputeLevelCount(dimensions.width(), dimensions.height()) + 1;
852855
}
853856

857+
SkImage::CompressionType compression = GrMtlFormatToCompressionType(mtlFormat);
858+
854859
// Create a transfer buffer and fill with data.
855860
SkSTArray<16, size_t> individualMipOffsets;
856861
id<MTLBuffer> transferBuffer;
857862
size_t transferBufferSize;
858863

859-
SkASSERT(data->type() != BackendTextureData::Type::kCompressed);
860-
if (data->type() == BackendTextureData::Type::kPixmaps) {
861-
transferBufferSize = GrComputeTightCombinedBufferSize(bytesPerPixel, dimensions,
862-
&individualMipOffsets, numMipLevels);
864+
if (data->type() == BackendTextureData::Type::kCompressed ||
865+
data->type() == BackendTextureData::Type::kPixmaps) {
866+
867+
if (compression == SkImage::CompressionType::kNone) {
868+
size_t bytesPerPixel = fMtlCaps->bytesPerPixel(mtlFormat);
869+
870+
transferBufferSize = GrComputeTightCombinedBufferSize(bytesPerPixel, dimensions,
871+
&individualMipOffsets,
872+
numMipLevels);
873+
874+
} else {
875+
transferBufferSize = SkCompressedDataSize(compression, dimensions,
876+
&individualMipOffsets,
877+
mipMapped == GrMipMapped::kYes);
878+
}
879+
SkASSERT(individualMipOffsets.count() == numMipLevels);
880+
863881
transferBuffer = [fDevice newBufferWithLength: transferBufferSize
864882
options: options];
865883
if (nil == transferBuffer) {
866884
return false;
867885
}
868886
char* buffer = (char*)transferBuffer.contents;
869-
copy_src_data(buffer, bytesPerPixel, individualMipOffsets, data->pixmaps(), numMipLevels,
870-
transferBufferSize);
887+
888+
if (data->type() == BackendTextureData::Type::kPixmaps) {
889+
size_t bytesPerPixel = fMtlCaps->bytesPerPixel(mtlFormat);
890+
891+
copy_src_data(buffer, bytesPerPixel, individualMipOffsets, data->pixmaps(),
892+
numMipLevels, transferBufferSize);
893+
} else {
894+
SkASSERT(data->type() == BackendTextureData::Type::kCompressed);
895+
896+
memcpy(buffer, data->compressedData(), data->compressedSize());
897+
}
871898
} else {
872899
SkASSERT(data->type() == BackendTextureData::Type::kColor);
873-
auto colorType = mtl_format_to_backend_tex_clear_colortype(format);
874-
if (colorType == GrColorType::kUnknown) {
875-
return false;
876-
}
877-
GrImageInfo ii(colorType, kUnpremul_SkAlphaType, nullptr, dimensions);
878-
auto rb = ii.minRowBytes();
879-
transferBufferSize = rb*dimensions.height();
880-
transferBuffer = [fDevice newBufferWithLength: transferBufferSize
881-
options: options];
882-
if (nil == transferBuffer) {
883-
return false;
884-
}
885-
if (!GrClearImage(ii, transferBuffer.contents, rb, data->color())) {
886-
return false;
900+
901+
if (compression == SkImage::CompressionType::kNone) {
902+
auto colorType = mtl_format_to_backend_tex_clear_colortype(mtlFormat);
903+
if (colorType == GrColorType::kUnknown) {
904+
return false;
905+
}
906+
GrImageInfo ii(colorType, kUnpremul_SkAlphaType, nullptr, dimensions);
907+
auto rb = ii.minRowBytes();
908+
transferBufferSize = rb*dimensions.height();
909+
transferBuffer = [fDevice newBufferWithLength: transferBufferSize
910+
options: options];
911+
if (nil == transferBuffer) {
912+
return false;
913+
}
914+
if (!GrClearImage(ii, transferBuffer.contents, rb, data->color())) {
915+
return false;
916+
}
917+
// Reuse the same buffer for all levels. Should be ok since we made the row bytes tight.
918+
individualMipOffsets.push_back_n(numMipLevels, (size_t)0);
919+
} else {
920+
transferBufferSize = SkCompressedDataSize(compression, dimensions,
921+
&individualMipOffsets,
922+
mipMapped == GrMipMapped::kYes);
923+
SkASSERT(individualMipOffsets.count() == numMipLevels);
924+
925+
transferBuffer = [fDevice newBufferWithLength: transferBufferSize
926+
options: options];
927+
if (nil == transferBuffer) {
928+
return false;
929+
}
930+
931+
char* buffer = (char*)transferBuffer.contents;
932+
GrFillInCompressedData(compression, dimensions, mipMapped, buffer, data->color());
887933
}
888-
// Reuse the same buffer for all levels. Should be ok since we made the row bytes tight.
889-
individualMipOffsets.push_back_n(numMipLevels, (size_t)0);
890934
}
891935

892936
// Transfer buffer contents to texture
893-
int currentWidth = dimensions.width();
894-
int currentHeight = dimensions.height();
895937
MTLOrigin origin = MTLOriginMake(0, 0, 0);
896938

897939
id<MTLCommandBuffer> cmdBuffer = [fQueue commandBuffer];
898940
id<MTLBlitCommandEncoder> blitCmdEncoder = [cmdBuffer blitCommandEncoder];
899941

942+
SkISize levelDimensions(dimensions);
900943
for (int currentMipLevel = 0; currentMipLevel < numMipLevels; currentMipLevel++) {
901-
size_t trimRowBytes = currentWidth * bytesPerPixel;
902-
size_t levelSize = trimRowBytes*currentHeight;
944+
size_t levelRowBytes;
945+
size_t levelSize;
946+
947+
if (compression == SkImage::CompressionType::kNone) {
948+
size_t bytesPerPixel = fMtlCaps->bytesPerPixel(mtlFormat);
949+
950+
levelRowBytes = levelDimensions.width() * bytesPerPixel;
951+
levelSize = levelRowBytes * levelDimensions.height();
952+
} else {
953+
levelRowBytes = GrCompressedRowBytes(compression, levelDimensions.width());
954+
levelSize = SkCompressedDataSize(compression, levelDimensions, nullptr,
955+
false);
956+
}
903957

904958
// TODO: can this all be done in one go?
905959
[blitCmdEncoder copyFromBuffer: transferBuffer
906960
sourceOffset: individualMipOffsets[currentMipLevel]
907-
sourceBytesPerRow: trimRowBytes
961+
sourceBytesPerRow: levelRowBytes
908962
sourceBytesPerImage: levelSize
909-
sourceSize: MTLSizeMake(currentWidth, currentHeight, 1)
963+
sourceSize: MTLSizeMake(levelDimensions.width(),
964+
levelDimensions.height(), 1)
910965
toTexture: testTexture
911966
destinationSlice: 0
912967
destinationLevel: currentMipLevel
913968
destinationOrigin: origin];
914969

915-
currentWidth = SkTMax(1, currentWidth/2);
916-
currentHeight = SkTMax(1, currentHeight/2);
970+
levelDimensions = { SkTMax(1, levelDimensions.width() / 2),
971+
SkTMax(1, levelDimensions.height() / 2) };
917972
}
918973
#ifdef SK_BUILD_FOR_MAC
919974
[transferBuffer didModifyRange: NSMakeRange(0, transferBufferSize)];
@@ -925,7 +980,6 @@ void copy_src_data(char* dst, size_t bytesPerPixel, const SkTArray<size_t>& indi
925980
transferBuffer = nil;
926981

927982
info->fTexture.reset(GrRetainPtrFromId(testTexture));
928-
929983
return true;
930984
}
931985

@@ -935,8 +989,8 @@ void copy_src_data(char* dst, size_t bytesPerPixel, const SkTArray<size_t>& indi
935989
GrMipMapped mipMapped,
936990
GrProtected isProtected,
937991
const BackendTextureData* data) {
938-
// GrGpu::createBackendTexture should've ensured these conditions
939992
const MTLPixelFormat mtlFormat = GrBackendFormatAsMTLPixelFormat(format);
993+
940994
GrMtlTextureInfo info;
941995
if (!this->createMtlTextureForBackendSurface(mtlFormat, dimensions, GrTexturable::kYes,
942996
renderable, mipMapped, &info, data)) {
@@ -948,11 +1002,20 @@ void copy_src_data(char* dst, size_t bytesPerPixel, const SkTArray<size_t>& indi
9481002
}
9491003

9501004
GrBackendTexture GrMtlGpu::onCreateCompressedBackendTexture(SkISize dimensions,
951-
const GrBackendFormat&,
952-
GrMipMapped,
953-
GrProtected,
954-
const BackendTextureData*) {
955-
return {};
1005+
const GrBackendFormat& format,
1006+
GrMipMapped mipMapped,
1007+
GrProtected isProtected,
1008+
const BackendTextureData* data) {
1009+
const MTLPixelFormat mtlFormat = GrBackendFormatAsMTLPixelFormat(format);
1010+
1011+
GrMtlTextureInfo info;
1012+
if (!this->createMtlTextureForBackendSurface(mtlFormat, dimensions, GrTexturable::kYes,
1013+
GrRenderable::kNo, mipMapped, &info, data)) {
1014+
return {};
1015+
}
1016+
1017+
GrBackendTexture backendTex(dimensions.width(), dimensions.height(), mipMapped, info);
1018+
return backendTex;
9561019
}
9571020

9581021
void GrMtlGpu::deleteBackendTexture(const GrBackendTexture& tex) {

tests/CompressedBackendAllocationTest.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,13 @@ static void check_readback(GrContext* context, sk_sp<SkImage> img,
110110
SkImage::CompressionType compressionType,
111111
const SkColor4f& expectedColor,
112112
skiatest::Reporter* reporter, const char* label) {
113+
#ifdef SK_BUILD_FOR_IOS
114+
// reading back ETC2 is broken on Metal/iOS (skbug.com/9839)
115+
if (context->backend() == GrBackendApi::kMetal) {
116+
return;
117+
}
118+
#endif
119+
113120
SkAutoPixmapStorage actual;
114121

115122
SkImageInfo readBackII = SkImageInfo::Make(img->width(), img->height(),
@@ -137,7 +144,6 @@ static void test_compressed_color_init(GrContext* context,
137144
GrMipMapped mipMapped) {
138145
GrBackendTexture backendTex = create(context, color, mipMapped);
139146
if (!backendTex.isValid()) {
140-
// errors here should be reported by the test_wrapping test
141147
return;
142148
}
143149

0 commit comments

Comments
 (0)