Add ETC2 support to Metal backend.
Fills out onCreateCompressedTexture and sets iOS caps to support ETC2. Skia supports no compressed texture formats on MacOS as yet. Bug: skia:8243 Change-Id: I2ce20f601c035a8822e658c88b815fdd8587aa98 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/240692 Commit-Queue: Jim Van Verth <jvanverth@google.com> Reviewed-by: Brian Salomon <bsalomon@google.com>
This commit is contained in:
parent
d46cb9729b
commit
c25802db30
@ -50,7 +50,7 @@ GrGLTexture::GrGLTexture(GrGLGpu* gpu, SkBudgeted budgeted, const Desc& desc,
|
||||
, fParameters(sk_make_sp<GrGLTextureParameters>()) {
|
||||
this->init(desc);
|
||||
this->registerWithCache(budgeted);
|
||||
if (GrPixelConfigIsCompressed(desc.fConfig)) {
|
||||
if (GrGLFormatIsCompressed(desc.fFormat)) {
|
||||
this->setReadOnly();
|
||||
}
|
||||
}
|
||||
|
@ -745,8 +745,7 @@ void GrMtlCaps::initFormatTable() {
|
||||
#ifdef SK_BUILD_FOR_IOS
|
||||
// ETC2_RGB8
|
||||
info = &fFormatTable[GetFormatIndex(MTLPixelFormatETC2_RGB8)];
|
||||
// GrMtlGpu::onCreateCompressedTexture() not implemented.
|
||||
info->fFlags = 0;
|
||||
info->fFlags = FormatInfo::kTexturable_Flag;
|
||||
// NO supported colorTypes
|
||||
#endif
|
||||
|
||||
|
@ -143,9 +143,7 @@ private:
|
||||
uint32_t levelClearMask) override;
|
||||
sk_sp<GrTexture> onCreateCompressedTexture(int width, int height, const GrBackendFormat&,
|
||||
SkImage::CompressionType, SkBudgeted,
|
||||
const void* data) override {
|
||||
return nullptr;
|
||||
}
|
||||
const void* data) override;
|
||||
|
||||
sk_sp<GrTexture> onWrapBackendTexture(const GrBackendTexture&, GrColorType,
|
||||
GrWrapOwnership, GrWrapCacheable, GrIOType) override;
|
||||
|
@ -455,6 +455,92 @@ sk_sp<GrTexture> GrMtlGpu::onCreateTexture(const GrSurfaceDesc& desc,
|
||||
return tex;
|
||||
}
|
||||
|
||||
sk_sp<GrTexture> GrMtlGpu::onCreateCompressedTexture(int width, int height,
|
||||
const GrBackendFormat& format,
|
||||
SkImage::CompressionType compressionType,
|
||||
SkBudgeted budgeted, const void* data) {
|
||||
SkASSERT(this->caps()->isFormatTexturable(format));
|
||||
SkASSERT(data);
|
||||
|
||||
if (!check_max_blit_width(width)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MTLPixelFormat mtlPixelFormat = GrBackendFormatAsMTLPixelFormat(format);
|
||||
|
||||
// This TexDesc refers to the texture that will be read by the client. Thus even if msaa is
|
||||
// requested, this TexDesc describes the resolved texture. Therefore we always have samples
|
||||
// set to 1.
|
||||
// Compressed textures with MIP levels or multiple samples are not supported as of now.
|
||||
MTLTextureDescriptor* texDesc = [[MTLTextureDescriptor alloc] init];
|
||||
texDesc.textureType = MTLTextureType2D;
|
||||
texDesc.pixelFormat = mtlPixelFormat;
|
||||
texDesc.width = width;
|
||||
texDesc.height = height;
|
||||
texDesc.depth = 1;
|
||||
texDesc.mipmapLevelCount = 1;
|
||||
texDesc.sampleCount = 1;
|
||||
texDesc.arrayLength = 1;
|
||||
// Make all textures have private gpu only access. We can use transfer buffers or textures
|
||||
// to copy to them.
|
||||
texDesc.storageMode = MTLStorageModePrivate;
|
||||
texDesc.usage = MTLTextureUsageShaderRead;
|
||||
|
||||
GrSurfaceDesc desc;
|
||||
desc.fConfig = GrCompressionTypePixelConfig(compressionType);
|
||||
desc.fWidth = width;
|
||||
desc.fHeight = height;
|
||||
auto tex = GrMtlTexture::MakeNewTexture(this, budgeted, desc, texDesc,
|
||||
GrMipMapsStatus::kNotAllocated);
|
||||
if (!tex) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Upload to texture
|
||||
id<MTLTexture> mtlTexture = tex->mtlTexture();
|
||||
SkASSERT(mtlTexture);
|
||||
|
||||
SkImage::CompressionType textureCompressionType;
|
||||
if (!GrMtlFormatToCompressionType(mtlTexture.pixelFormat, &textureCompressionType) ||
|
||||
textureCompressionType != compressionType) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
size_t dataSize = GrCompressedDataSize(compressionType, width, height);
|
||||
SkASSERT(dataSize);
|
||||
|
||||
size_t bufferOffset;
|
||||
id<MTLBuffer> transferBuffer = this->resourceProvider().getDynamicBuffer(dataSize,
|
||||
&bufferOffset);
|
||||
if (!transferBuffer) {
|
||||
return nullptr;
|
||||
}
|
||||
char* buffer = (char*) transferBuffer.contents + bufferOffset;
|
||||
|
||||
MTLOrigin origin = MTLOriginMake(0, 0, 0);
|
||||
|
||||
id<MTLBlitCommandEncoder> blitCmdEncoder = this->commandBuffer()->getBlitCommandEncoder();
|
||||
// sourceBytesPerRow: must be at least 32
|
||||
const size_t rowBytes = SkTMax(dataSize/height, (size_t)32);
|
||||
|
||||
// copy data into the buffer, skipping any trailing bytes
|
||||
memcpy(buffer, data, dataSize);
|
||||
[blitCmdEncoder copyFromBuffer: transferBuffer
|
||||
sourceOffset: bufferOffset
|
||||
sourceBytesPerRow: rowBytes
|
||||
sourceBytesPerImage: dataSize
|
||||
sourceSize: MTLSizeMake(width, height, 1)
|
||||
toTexture: mtlTexture
|
||||
destinationSlice: 0
|
||||
destinationLevel: 0
|
||||
destinationOrigin: origin];
|
||||
#ifdef SK_BUILD_FOR_MAC
|
||||
[transferBuffer didModifyRange: NSMakeRange(bufferOffset, dataSize)];
|
||||
#endif
|
||||
|
||||
return tex;
|
||||
}
|
||||
|
||||
static id<MTLTexture> get_texture_from_backend(const GrBackendTexture& backendTex) {
|
||||
GrMtlTextureInfo textureInfo;
|
||||
if (!backendTex.getMtlTextureInfo(&textureInfo)) {
|
||||
|
@ -26,6 +26,9 @@ GrMtlTexture::GrMtlTexture(GrMtlGpu* gpu,
|
||||
, fTexture(texture) {
|
||||
SkASSERT((GrMipMapsStatus::kNotAllocated == mipMapsStatus) == (1 == texture.mipmapLevelCount));
|
||||
this->registerWithCache(budgeted);
|
||||
if (GrMtlFormatIsCompressed(texture.pixelFormat)) {
|
||||
this->setReadOnly();
|
||||
}
|
||||
}
|
||||
|
||||
GrMtlTexture::GrMtlTexture(GrMtlGpu* gpu,
|
||||
|
@ -116,4 +116,14 @@ static inline MTLPixelFormat GrBackendFormatAsMTLPixelFormat(const GrBackendForm
|
||||
return static_cast<MTLPixelFormat>(format.asMtlFormat());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the format is compressed.
|
||||
*/
|
||||
bool GrMtlFormatIsCompressed(MTLPixelFormat mtlFormat);
|
||||
|
||||
/**
|
||||
* Maps a MTLPixelFormat into the CompressionType enum if applicable.
|
||||
*/
|
||||
bool GrMtlFormatToCompressionType(MTLPixelFormat mtlFormat,
|
||||
SkImage::CompressionType* compressionType);
|
||||
#endif
|
||||
|
@ -330,6 +330,30 @@ size_t GrMtlBytesPerFormat(MTLPixelFormat format) {
|
||||
SK_ABORT("Invalid Mtl format");
|
||||
}
|
||||
|
||||
bool GrMtlFormatIsCompressed(MTLPixelFormat mtlFormat) {
|
||||
switch (mtlFormat) {
|
||||
#ifdef SK_BUILD_FOR_IOS
|
||||
case MTLPixelFormatETC2_RGB8:
|
||||
return true;
|
||||
#endif
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool GrMtlFormatToCompressionType(MTLPixelFormat mtlFormat,
|
||||
SkImage::CompressionType* compressionType) {
|
||||
switch (mtlFormat) {
|
||||
#ifdef SK_BUILD_FOR_IOS
|
||||
case MTLPixelFormatETC2_RGB8:
|
||||
*compressionType = SkImage::kETC1_CompressionType;
|
||||
return true;
|
||||
#endif
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#if GR_TEST_UTILS
|
||||
const char* GrMtlFormatToStr(GrMTLPixelFormat mtlFormat) {
|
||||
switch (mtlFormat) {
|
||||
|
@ -32,7 +32,7 @@ GrVkTexture::GrVkTexture(GrVkGpu* gpu,
|
||||
, fTextureView(view) {
|
||||
SkASSERT((GrMipMapsStatus::kNotAllocated == mipMapsStatus) == (1 == info.fLevelCount));
|
||||
this->registerWithCache(budgeted);
|
||||
if (GrPixelConfigIsCompressed(desc.fConfig)) {
|
||||
if (GrVkFormatIsCompressed(info.fFormat)) {
|
||||
this->setReadOnly();
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user