| // | |
| // Copyright 2022 The ANGLE Project Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| // | |
| // storeimage_paletted.cpp: Encodes GL_PALETTE_* textures. | |
| #include <unordered_map> | |
| #include "image_util/storeimage.h" | |
| #include <type_traits> | |
| #include "common/mathutil.h" | |
| #include "image_util/imageformats.h" | |
| namespace angle | |
| { | |
| namespace | |
| { | |
| template <typename T> | |
| inline T *OffsetDataPointer(uint8_t *data, size_t y, size_t z, size_t rowPitch, size_t depthPitch) | |
| { | |
| return reinterpret_cast<T *>(data + (y * rowPitch) + (z * depthPitch)); | |
| } | |
| template <typename T> | |
| inline const T *OffsetDataPointer(const uint8_t *data, | |
| size_t y, | |
| size_t z, | |
| size_t rowPitch, | |
| size_t depthPitch) | |
| { | |
| return reinterpret_cast<const T *>(data + (y * rowPitch) + (z * depthPitch)); | |
| } | |
| void EncodeColor(R8G8B8A8 rgba, | |
| uint32_t redBlueBits, | |
| uint32_t greenBits, | |
| uint32_t alphaBits, | |
| void *dst) | |
| { | |
| gl::ColorF color; | |
| R8G8B8A8::readColor(&color, &rgba); | |
| switch (redBlueBits) | |
| { | |
| case 8: | |
| ASSERT(greenBits == 8); | |
| switch (alphaBits) | |
| { | |
| case 0: | |
| return R8G8B8::writeColor(reinterpret_cast<R8G8B8 *>(dst), &color); | |
| case 8: | |
| return R8G8B8A8::writeColor(reinterpret_cast<R8G8B8A8 *>(dst), &color); | |
| default: | |
| UNREACHABLE(); | |
| break; | |
| } | |
| break; | |
| case 5: | |
| switch (greenBits) | |
| { | |
| case 6: | |
| ASSERT(alphaBits == 0); | |
| return R5G6B5::writeColor(reinterpret_cast<R5G6B5 *>(dst), &color); | |
| case 5: | |
| ASSERT(alphaBits == 1); | |
| return R5G5B5A1::writeColor(reinterpret_cast<R5G5B5A1 *>(dst), &color); | |
| default: | |
| UNREACHABLE(); | |
| break; | |
| } | |
| break; | |
| case 4: | |
| ASSERT(greenBits == 4 && alphaBits == 4); | |
| return R4G4B4A4::writeColor(reinterpret_cast<R4G4B4A4 *>(dst), &color); | |
| default: | |
| UNREACHABLE(); | |
| break; | |
| } | |
| } | |
| uint32_t R8G8B8A8Key(R8G8B8A8 rgba) | |
| { | |
| uint32_t key; | |
| static_assert(sizeof(key) == sizeof(rgba)); | |
| memcpy(&key, &rgba, sizeof(key)); | |
| return key; | |
| } | |
| } // namespace | |
| void StoreRGBA8ToPalettedImpl(size_t width, | |
| size_t height, | |
| size_t depth, | |
| uint32_t indexBits, | |
| uint32_t redBlueBits, | |
| uint32_t greenBits, | |
| uint32_t alphaBits, | |
| const uint8_t *input, | |
| size_t inputRowPitch, | |
| size_t inputDepthPitch, | |
| uint8_t *output, | |
| size_t outputRowPitch, | |
| size_t outputDepthPitch) | |
| { | |
| std::unordered_map<uint32_t, size_t> invPalette; | |
| ASSERT((redBlueBits + greenBits + redBlueBits + alphaBits) % 8 == 0); | |
| size_t colorBytes = (redBlueBits + greenBits + redBlueBits + alphaBits) / 8; | |
| size_t paletteSize = 1 << indexBits; | |
| size_t paletteBytes = paletteSize * colorBytes; | |
| uint8_t *palette = output; | |
| // We might not fill-out the entire palette. | |
| memset(palette, 0xab, paletteBytes); | |
| uint8_t *texels = output + paletteBytes; // + TODO(http://anglebug.com/7688): mip levels | |
| for (size_t z = 0; z < depth; z++) | |
| { | |
| for (size_t y = 0; y < height; y++) | |
| { | |
| const R8G8B8A8 *srcRow = | |
| OffsetDataPointer<R8G8B8A8>(input, y, z, inputRowPitch, inputDepthPitch); | |
| uint8_t *dstRow = | |
| OffsetDataPointer<uint8_t>(texels, y, z, outputRowPitch, outputDepthPitch); | |
| for (size_t x = 0; x < width; x++) | |
| { | |
| auto inversePaletteEntry = invPalette.insert( | |
| std::pair<uint32_t, size_t>(R8G8B8A8Key(srcRow[x]), invPalette.size())); | |
| size_t paletteIndex = inversePaletteEntry.first->second; | |
| ASSERT(paletteIndex < paletteSize); | |
| if (inversePaletteEntry.second) | |
| { | |
| EncodeColor(srcRow[x], redBlueBits, greenBits, alphaBits, | |
| palette + paletteIndex * colorBytes); | |
| } | |
| switch (indexBits) | |
| { | |
| case 4: | |
| // On even xses, initialize the location and store the high | |
| // bits, on odd (which always follows even) store the low | |
| // bits. | |
| if (x % 2 == 0) | |
| dstRow[x / 2] = static_cast<uint8_t>(paletteIndex) << 4; | |
| else | |
| dstRow[x / 2] |= static_cast<uint8_t>(paletteIndex); | |
| break; | |
| case 8: | |
| dstRow[x] = static_cast<uint8_t>(paletteIndex); | |
| break; | |
| default: | |
| UNREACHABLE(); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } // namespace angle |