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;
    }

};