File size: 5,938 Bytes
6b0231d | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 | /* -*- tab-width: 4; -*- */
/* vi: set sw=2 ts=4 expandtab: */
/*
* Copyright 2017-2020 Mark Callow.
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <ktx.h>
#if !defined(GL_COMPRESSED_SRGB_PVRTC_2BPPV1_EXT)
#define GL_COMPRESSED_SRGB_PVRTC_2BPPV1_EXT 0x8A54
#define GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG 0x8C01
#define GL_COMPRESSED_RGBA_PVRTC_2BPPV2_IMG 0x9137
#endif
#if !defined(GL_COMPRESSED_RG_RGTC2)
#define GL_COMPRESSED_RG_RGTC2 0x8DBD
#endif
#if !defined(GL_COMPRESSED_RGBA_BPTC_UNORM)
#define GL_COMPRESSED_RGBA_BPTC_UNORM 0x8E8C
#endif
#if !defined(GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT)
#define GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT 0x8E8E
#endif
class TextureTranscoder {
public:
TextureTranscoder() {
determineCompressedTexFeatures(deviceFeatures);
if (deviceFeatures.astc_ldr)
defaultTf = KTX_TTF_ASTC_4x4_RGBA;
else if (deviceFeatures.bc3)
defaultTf = KTX_TTF_BC1_OR_3;
else if (deviceFeatures.etc2)
defaultTf = KTX_TTF_ETC; // Let transcoder decide RGB or RGBA
else if (deviceFeatures.pvrtc1)
defaultTf = KTX_TTF_PVRTC1_4_RGBA;
else if (deviceFeatures.etc1)
defaultTf = KTX_TTF_ETC1_RGB;
else {
std::stringstream message;
message << "OpenGL implementation does not support any available transcode target.";
throw std::runtime_error(message.str());
}
}
void transcode(ktxTexture2* kTexture,
ktx_transcode_fmt_e otf = KTX_TTF_NOSELECTION) {
KTX_error_code ktxresult;
ktx_transcode_fmt_e tf;
if (otf != KTX_TTF_NOSELECTION) {
tf = otf;
} else {
khr_df_model_e colorModel = ktxTexture2_GetColorModel_e(kTexture);
if (colorModel == KHR_DF_MODEL_UASTC && deviceFeatures.astc_ldr) {
tf = KTX_TTF_ASTC_4x4_RGBA;
} else if (colorModel == KHR_DF_MODEL_ETC1S && deviceFeatures.etc2) {
tf = KTX_TTF_ETC;
} else {
tf = defaultTf;
}
}
ktxresult = ktxTexture2_TranscodeBasis(kTexture, tf, 0);
if (KTX_SUCCESS != ktxresult) {
std::stringstream message;
message << "Transcoding of ktxTexture2 to "
<< ktxTranscodeFormatString(tf) << " failed: "
<< ktxErrorString(ktxresult);
throw std::runtime_error(message.str());
}
}
protected:
ktx_transcode_fmt_e defaultTf;
struct compressedTexFeatures {
bool astc_ldr;
bool astc_hdr;
bool bc6h;
bool bc7;
bool etc1;
bool etc2;
bool bc3;
bool pvrtc1;
bool pvrtc_srgb;
bool pvrtc2;
bool rgtc;
} deviceFeatures;
void determineCompressedTexFeatures(compressedTexFeatures& features) {
ktx_int32_t numCompressedFormats;
memset(&features, false, sizeof(features));
glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &numCompressedFormats);
GLint* formats = new GLint[numCompressedFormats];
glGetIntegerv(GL_COMPRESSED_TEXTURE_FORMATS, formats);
for (ktx_int32_t i = 0; i < numCompressedFormats; i++) {
if (formats[i] == GL_COMPRESSED_RGBA8_ETC2_EAC)
features.etc2 = true;
if (formats[i] == GL_ETC1_RGB8_OES)
features.etc1 = true;
if (formats[i] == GL_COMPRESSED_RGBA_S3TC_DXT5_EXT)
features.bc3 = true;
if (formats[i] == GL_COMPRESSED_RG_RGTC2)
features.rgtc = true;
if (formats[i] == GL_COMPRESSED_SRGB_PVRTC_2BPPV1_EXT)
features.pvrtc_srgb = true;
if (formats[i] == GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG)
features.pvrtc1 = true;
if (formats[i] == GL_COMPRESSED_RGBA_PVRTC_2BPPV2_IMG)
features.pvrtc2 = true;
if (formats[i] == GL_COMPRESSED_RGBA_ASTC_4x4_KHR)
features.astc_ldr = true;
if (formats[i] == GL_COMPRESSED_RGBA_BPTC_UNORM)
features.bc7 = true;
if (formats[i] == GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT)
features.bc6h = true;
}
delete[] formats;
// Just in case COMPRESSED_TEXTURE_FORMATS didn't return anything.
// There is no ETC2 extension. It went into core in OpenGL ES 2.0.
// ARB_es_compatibility is not a good indicator. ETC2 could be supported
// by software decompression. Better to report unsupported.
if (!features.etc1 && SDL_GL_ExtensionSupported("GL_OES_compressed_ETC1_RGB8_texture"))
features.etc1 = true;;
if (!features.bc3 && SDL_GL_ExtensionSupported("GL_EXT_texture_compression_s3tc"))
features.bc3 = true;
if (!features.rgtc && SDL_GL_ExtensionSupported("GL_ARB_texture_compression_rgtc"))
features.rgtc = true;
if (!features.pvrtc1 && SDL_GL_ExtensionSupported("GL_IMG_texture_compression_pvrtc"))
features.pvrtc1 = true;
if (!features.pvrtc2 && SDL_GL_ExtensionSupported("GL_IMG_texture_compression_pvrtc2"))
features.pvrtc2 = true;
if (!features.pvrtc_srgb && SDL_GL_ExtensionSupported("GL_EXT_pvrtc_sRGB"))
features.pvrtc_srgb = true;
if (!(features.bc7 && features.bc6h) && SDL_GL_ExtensionSupported("GL_ARB_texture_compression_bptc"))
features.bc6h = features.bc7 = true;
if (!features.astc_ldr && SDL_GL_ExtensionSupported("GL_KHR_texture_compression_astc_ldr"))
features.astc_ldr = true;
// The only way to identify this support is the extension string.
// The format name is the same.
if (SDL_GL_ExtensionSupported("GL_KHR_texture_compression_astc_hdr"))
features.astc_hdr = true;
}
};
|