| 1 | // basisu_gpu_texture.h |
| 2 | // Copyright (C) 2019-2021 Binomial LLC. All Rights Reserved. |
| 3 | // |
| 4 | // Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | // you may not use this file except in compliance with the License. |
| 6 | // You may obtain a copy of the License at |
| 7 | // |
| 8 | // http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | // |
| 10 | // Unless required by applicable law or agreed to in writing, software |
| 11 | // distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | // See the License for the specific language governing permissions and |
| 14 | // limitations under the License. |
| 15 | #pragma once |
| 16 | #include "../transcoder/basisu.h" |
| 17 | #include "basisu_etc.h" |
| 18 | |
| 19 | namespace basisu |
| 20 | { |
| 21 | // GPU texture "image" |
| 22 | class gpu_image |
| 23 | { |
| 24 | public: |
| 25 | enum { cMaxBlockSize = 12 }; |
| 26 | |
| 27 | gpu_image() |
| 28 | { |
| 29 | clear(); |
| 30 | } |
| 31 | |
| 32 | gpu_image(texture_format fmt, uint32_t width, uint32_t height) |
| 33 | { |
| 34 | init(fmt, width, height); |
| 35 | } |
| 36 | |
| 37 | void clear() |
| 38 | { |
| 39 | m_fmt = texture_format::cInvalidTextureFormat; |
| 40 | m_width = 0; |
| 41 | m_height = 0; |
| 42 | m_block_width = 0; |
| 43 | m_block_height = 0; |
| 44 | m_blocks_x = 0; |
| 45 | m_blocks_y = 0; |
| 46 | m_qwords_per_block = 0; |
| 47 | m_blocks.clear(); |
| 48 | } |
| 49 | |
| 50 | inline texture_format get_format() const { return m_fmt; } |
| 51 | |
| 52 | // Width/height in pixels |
| 53 | inline uint32_t get_pixel_width() const { return m_width; } |
| 54 | inline uint32_t get_pixel_height() const { return m_height; } |
| 55 | |
| 56 | // Width/height in blocks, row pitch is assumed to be m_blocks_x. |
| 57 | inline uint32_t get_blocks_x() const { return m_blocks_x; } |
| 58 | inline uint32_t get_blocks_y() const { return m_blocks_y; } |
| 59 | |
| 60 | // Size of each block in pixels |
| 61 | inline uint32_t get_block_width() const { return m_block_width; } |
| 62 | inline uint32_t get_block_height() const { return m_block_height; } |
| 63 | |
| 64 | inline uint32_t get_qwords_per_block() const { return m_qwords_per_block; } |
| 65 | inline uint32_t get_total_blocks() const { return m_blocks_x * m_blocks_y; } |
| 66 | inline uint32_t get_bytes_per_block() const { return get_qwords_per_block() * sizeof(uint64_t); } |
| 67 | inline uint32_t get_row_pitch_in_bytes() const { return get_bytes_per_block() * get_blocks_x(); } |
| 68 | |
| 69 | inline const uint64_vec &get_blocks() const { return m_blocks; } |
| 70 | |
| 71 | inline const uint64_t *get_ptr() const { return &m_blocks[0]; } |
| 72 | inline uint64_t *get_ptr() { return &m_blocks[0]; } |
| 73 | |
| 74 | inline uint32_t get_size_in_bytes() const { return get_total_blocks() * get_qwords_per_block() * sizeof(uint64_t); } |
| 75 | |
| 76 | inline const void *get_block_ptr(uint32_t block_x, uint32_t block_y, uint32_t element_index = 0) const |
| 77 | { |
| 78 | assert(block_x < m_blocks_x && block_y < m_blocks_y); |
| 79 | return &m_blocks[(block_x + block_y * m_blocks_x) * m_qwords_per_block + element_index]; |
| 80 | } |
| 81 | |
| 82 | inline void *get_block_ptr(uint32_t block_x, uint32_t block_y, uint32_t element_index = 0) |
| 83 | { |
| 84 | assert(block_x < m_blocks_x && block_y < m_blocks_y && element_index < m_qwords_per_block); |
| 85 | return &m_blocks[(block_x + block_y * m_blocks_x) * m_qwords_per_block + element_index]; |
| 86 | } |
| 87 | |
| 88 | void init(texture_format fmt, uint32_t width, uint32_t height) |
| 89 | { |
| 90 | m_fmt = fmt; |
| 91 | m_width = width; |
| 92 | m_height = height; |
| 93 | m_block_width = basisu::get_block_width(m_fmt); |
| 94 | m_block_height = basisu::get_block_height(m_fmt); |
| 95 | m_blocks_x = (m_width + m_block_width - 1) / m_block_width; |
| 96 | m_blocks_y = (m_height + m_block_height - 1) / m_block_height; |
| 97 | m_qwords_per_block = basisu::get_qwords_per_block(m_fmt); |
| 98 | |
| 99 | m_blocks.resize(0); |
| 100 | m_blocks.resize(m_blocks_x * m_blocks_y * m_qwords_per_block); |
| 101 | } |
| 102 | |
| 103 | bool unpack(image& img) const; |
| 104 | |
| 105 | void override_dimensions(uint32_t w, uint32_t h) |
| 106 | { |
| 107 | m_width = w; |
| 108 | m_height = h; |
| 109 | } |
| 110 | |
| 111 | private: |
| 112 | texture_format m_fmt; |
| 113 | uint32_t m_width, m_height, m_blocks_x, m_blocks_y, m_block_width, m_block_height, m_qwords_per_block; |
| 114 | uint64_vec m_blocks; |
| 115 | }; |
| 116 | |
| 117 | typedef basisu::vector<gpu_image> gpu_image_vec; |
| 118 | |
| 119 | // KTX file writing |
| 120 | |
| 121 | bool create_ktx_texture_file(uint8_vec &ktx_data, const basisu::vector<gpu_image_vec>& gpu_images, bool cubemap_flag); |
| 122 | |
| 123 | bool write_compressed_texture_file(const char *pFilename, const basisu::vector<gpu_image_vec>& g, bool cubemap_flag); |
| 124 | |
| 125 | inline bool write_compressed_texture_file(const char *pFilename, const gpu_image_vec &g) |
| 126 | { |
| 127 | basisu::vector<gpu_image_vec> a; |
| 128 | a.push_back(g); |
| 129 | return write_compressed_texture_file(pFilename, a, false); |
| 130 | } |
| 131 | |
| 132 | bool write_compressed_texture_file(const char *pFilename, const gpu_image &g); |
| 133 | |
| 134 | bool write_3dfx_out_file(const char* pFilename, const gpu_image& gi); |
| 135 | |
| 136 | // GPU texture block unpacking |
| 137 | void unpack_etc2_eac(const void *pBlock_bits, color_rgba *pPixels); |
| 138 | bool unpack_bc1(const void *pBlock_bits, color_rgba *pPixels, bool set_alpha); |
| 139 | void unpack_bc4(const void *pBlock_bits, uint8_t *pPixels, uint32_t stride); |
| 140 | bool unpack_bc3(const void *pBlock_bits, color_rgba *pPixels); |
| 141 | void unpack_bc5(const void *pBlock_bits, color_rgba *pPixels); |
| 142 | bool unpack_bc7_mode6(const void *pBlock_bits, color_rgba *pPixels); |
| 143 | bool unpack_bc7(const void* pBlock_bits, color_rgba* pPixels); |
| 144 | void unpack_atc(const void* pBlock_bits, color_rgba* pPixels); |
| 145 | bool unpack_fxt1(const void* p, color_rgba* pPixels); |
| 146 | bool unpack_pvrtc2(const void* p, color_rgba* pPixels); |
| 147 | void unpack_etc2_eac_r(const void *p, color_rgba* pPixels, uint32_t c); |
| 148 | void unpack_etc2_eac_rg(const void* p, color_rgba* pPixels); |
| 149 | |
| 150 | // unpack_block() is primarily intended to unpack texture data created by the transcoder. |
| 151 | // For some texture formats (like ETC2 RGB, PVRTC2, FXT1) it's not a complete implementation. |
| 152 | bool unpack_block(texture_format fmt, const void *pBlock, color_rgba *pPixels); |
| 153 | |
| 154 | } // namespace basisu |
| 155 | |