xref: /aosp_15_r20/external/angle/src/image_util/storeimage_paletted.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1 //
2 // Copyright 2022 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 
7 // storeimage_paletted.cpp: Encodes GL_PALETTE_* textures.
8 
9 #include <unordered_map>
10 
11 #include "image_util/storeimage.h"
12 
13 #include <type_traits>
14 #include "common/mathutil.h"
15 
16 #include "image_util/imageformats.h"
17 
18 namespace angle
19 {
20 
21 namespace
22 {
23 
24 template <typename T>
OffsetDataPointer(uint8_t * data,size_t y,size_t z,size_t rowPitch,size_t depthPitch)25 inline T *OffsetDataPointer(uint8_t *data, size_t y, size_t z, size_t rowPitch, size_t depthPitch)
26 {
27     return reinterpret_cast<T *>(data + (y * rowPitch) + (z * depthPitch));
28 }
29 
30 template <typename T>
OffsetDataPointer(const uint8_t * data,size_t y,size_t z,size_t rowPitch,size_t depthPitch)31 inline const T *OffsetDataPointer(const uint8_t *data,
32                                   size_t y,
33                                   size_t z,
34                                   size_t rowPitch,
35                                   size_t depthPitch)
36 {
37     return reinterpret_cast<const T *>(data + (y * rowPitch) + (z * depthPitch));
38 }
39 
EncodeColor(R8G8B8A8 rgba,uint32_t redBlueBits,uint32_t greenBits,uint32_t alphaBits,void * dst)40 void EncodeColor(R8G8B8A8 rgba,
41                  uint32_t redBlueBits,
42                  uint32_t greenBits,
43                  uint32_t alphaBits,
44                  void *dst)
45 {
46     gl::ColorF color;
47     R8G8B8A8::readColor(&color, &rgba);
48 
49     switch (redBlueBits)
50     {
51         case 8:
52             ASSERT(greenBits == 8);
53             switch (alphaBits)
54             {
55                 case 0:
56                     return R8G8B8::writeColor(reinterpret_cast<R8G8B8 *>(dst), &color);
57                 case 8:
58                     return R8G8B8A8::writeColor(reinterpret_cast<R8G8B8A8 *>(dst), &color);
59                 default:
60                     UNREACHABLE();
61                     break;
62             }
63             break;
64 
65         case 5:
66             switch (greenBits)
67             {
68                 case 6:
69                     ASSERT(alphaBits == 0);
70                     return R5G6B5::writeColor(reinterpret_cast<R5G6B5 *>(dst), &color);
71                 case 5:
72                     ASSERT(alphaBits == 1);
73                     return R5G5B5A1::writeColor(reinterpret_cast<R5G5B5A1 *>(dst), &color);
74                 default:
75                     UNREACHABLE();
76                     break;
77             }
78             break;
79 
80         case 4:
81             ASSERT(greenBits == 4 && alphaBits == 4);
82             return R4G4B4A4::writeColor(reinterpret_cast<R4G4B4A4 *>(dst), &color);
83 
84         default:
85             UNREACHABLE();
86             break;
87     }
88 }
89 
R8G8B8A8Key(R8G8B8A8 rgba)90 uint32_t R8G8B8A8Key(R8G8B8A8 rgba)
91 {
92     uint32_t key;
93     static_assert(sizeof(key) == sizeof(rgba));
94     memcpy(&key, &rgba, sizeof(key));
95     return key;
96 }
97 
98 }  // namespace
99 
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)100 void StoreRGBA8ToPalettedImpl(size_t width,
101                               size_t height,
102                               size_t depth,
103                               uint32_t indexBits,
104                               uint32_t redBlueBits,
105                               uint32_t greenBits,
106                               uint32_t alphaBits,
107                               const uint8_t *input,
108                               size_t inputRowPitch,
109                               size_t inputDepthPitch,
110                               uint8_t *output,
111                               size_t outputRowPitch,
112                               size_t outputDepthPitch)
113 {
114     std::unordered_map<uint32_t, size_t> invPalette;
115 
116     ASSERT((redBlueBits + greenBits + redBlueBits + alphaBits) % 8 == 0);
117 
118     size_t colorBytes   = (redBlueBits + greenBits + redBlueBits + alphaBits) / 8;
119     size_t paletteSize  = 1 << indexBits;
120     size_t paletteBytes = paletteSize * colorBytes;
121 
122     uint8_t *palette = output;
123 
124     // We might not fill-out the entire palette.
125     memset(palette, 0xab, paletteBytes);
126 
127     uint8_t *texels = output + paletteBytes;  // + TODO(http://anglebug.com/42266155): mip levels
128 
129     for (size_t z = 0; z < depth; z++)
130     {
131         for (size_t y = 0; y < height; y++)
132         {
133             const R8G8B8A8 *srcRow =
134                 OffsetDataPointer<R8G8B8A8>(input, y, z, inputRowPitch, inputDepthPitch);
135             uint8_t *dstRow =
136                 OffsetDataPointer<uint8_t>(texels, y, z, outputRowPitch, outputDepthPitch);
137 
138             for (size_t x = 0; x < width; x++)
139             {
140                 auto inversePaletteEntry = invPalette.insert(
141                     std::pair<uint32_t, size_t>(R8G8B8A8Key(srcRow[x]), invPalette.size()));
142                 size_t paletteIndex = inversePaletteEntry.first->second;
143                 ASSERT(paletteIndex < paletteSize);
144                 if (inversePaletteEntry.second)
145                 {
146                     EncodeColor(srcRow[x], redBlueBits, greenBits, alphaBits,
147                                 palette + paletteIndex * colorBytes);
148                 }
149 
150                 switch (indexBits)
151                 {
152                     case 4:
153                         // On even xses, initialize the location and store the high
154                         // bits, on odd (which always follows even) store the low
155                         // bits.
156                         if (x % 2 == 0)
157                             dstRow[x / 2] = static_cast<uint8_t>(paletteIndex) << 4;
158                         else
159                             dstRow[x / 2] |= static_cast<uint8_t>(paletteIndex);
160                         break;
161 
162                     case 8:
163                         dstRow[x] = static_cast<uint8_t>(paletteIndex);
164                         break;
165 
166                     default:
167                         UNREACHABLE();
168                 }
169             }
170         }
171     }
172 }
173 
174 }  // namespace angle
175