1// 2// Copyright 2014 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#include "common/mathutil.h" 8 9#include <string.h> 10 11namespace angle 12{ 13 14namespace priv 15{ 16 17template <typename T> 18inline T *OffsetDataPointer(uint8_t *data, size_t y, size_t z, size_t rowPitch, size_t depthPitch) 19{ 20 return reinterpret_cast<T*>(data + (y * rowPitch) + (z * depthPitch)); 21} 22 23template <typename T> 24inline const T *OffsetDataPointer(const uint8_t *data, size_t y, size_t z, size_t rowPitch, size_t depthPitch) 25{ 26 return reinterpret_cast<const T*>(data + (y * rowPitch) + (z * depthPitch)); 27} 28 29} // namespace priv 30 31template <typename type, size_t componentCount> 32inline void LoadToNative(const ImageLoadContext &context, size_t width, size_t height, size_t depth, 33 const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, 34 uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) 35{ 36 const size_t rowSize = width * sizeof(type) * componentCount; 37 const size_t layerSize = rowSize * height; 38 const size_t imageSize = layerSize * depth; 39 40 if (layerSize == inputDepthPitch && layerSize == outputDepthPitch) 41 { 42 ASSERT(rowSize == inputRowPitch && rowSize == outputRowPitch); 43 memcpy(output, input, imageSize); 44 } 45 else if (rowSize == inputRowPitch && rowSize == outputRowPitch) 46 { 47 for (size_t z = 0; z < depth; z++) 48 { 49 const type *source = priv::OffsetDataPointer<type>(input, 0, z, inputRowPitch, inputDepthPitch); 50 type *dest = priv::OffsetDataPointer<type>(output, 0, z, outputRowPitch, outputDepthPitch); 51 52 memcpy(dest, source, layerSize); 53 } 54 } 55 else 56 { 57 for (size_t z = 0; z < depth; z++) 58 { 59 for (size_t y = 0; y < height; y++) 60 { 61 const type *source = priv::OffsetDataPointer<type>(input, y, z, inputRowPitch, inputDepthPitch); 62 type *dest = priv::OffsetDataPointer<type>(output, y, z, outputRowPitch, outputDepthPitch); 63 memcpy(dest, source, width * sizeof(type) * componentCount); 64 } 65 } 66 } 67} 68 69template <typename type, uint32_t fourthComponentBits> 70inline void LoadToNative3To4(const ImageLoadContext &context, size_t width, size_t height, 71 size_t depth, const uint8_t *input, size_t inputRowPitch, 72 size_t inputDepthPitch, uint8_t *output, size_t outputRowPitch, 73 size_t outputDepthPitch) 74{ 75 const type fourthValue = gl::bitCast<type>(fourthComponentBits); 76 77 for (size_t z = 0; z < depth; z++) 78 { 79 for (size_t y = 0; y < height; y++) 80 { 81 const type *source = priv::OffsetDataPointer<type>(input, y, z, inputRowPitch, inputDepthPitch); 82 type *dest = priv::OffsetDataPointer<type>(output, y, z, outputRowPitch, outputDepthPitch); 83 for (size_t x = 0; x < width; x++) 84 { 85 memcpy(&dest[x * 4], &source[x * 3], sizeof(type) * 3); 86 dest[x * 4 + 3] = fourthValue; 87 } 88 } 89 } 90} 91 92template <size_t componentCount> 93inline void Load32FTo16F(const ImageLoadContext &context, size_t width, size_t height, size_t depth, 94 const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, 95 uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) 96{ 97 const size_t elementWidth = componentCount * width; 98 99 for (size_t z = 0; z < depth; z++) 100 { 101 for (size_t y = 0; y < height; y++) 102 { 103 const float *source = priv::OffsetDataPointer<float>(input, y, z, inputRowPitch, inputDepthPitch); 104 uint16_t *dest = priv::OffsetDataPointer<uint16_t>(output, y, z, outputRowPitch, outputDepthPitch); 105 106 for (size_t x = 0; x < elementWidth; x++) 107 { 108 dest[x] = gl::float32ToFloat16(source[x]); 109 } 110 } 111 } 112} 113 114template <typename type, 115 size_t inputComponentCount, 116 size_t outputComponentCount, 117 bool normalized> 118inline void LoadToFloat(const ImageLoadContext &context, size_t width, size_t height, size_t depth, 119 const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, 120 uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) { 121 typedef std::numeric_limits<type> NL; 122 123 for (size_t z = 0; z < depth; z++) 124 { 125 for (size_t y = 0; y < height; y++) 126 { 127 const type *source_line = priv::OffsetDataPointer<type>(input, y, z, inputRowPitch, inputDepthPitch); 128 float *dest_line = priv::OffsetDataPointer<float>(output, y, z, outputRowPitch, outputDepthPitch); 129 130 for (size_t x = 0; x < width; x++) 131 { 132 const type *source_pixel = source_line + x * inputComponentCount; 133 float *dest_pixel = dest_line + x * outputComponentCount; 134 135 for (size_t i = 0; i < inputComponentCount; i++) 136 { 137 float result = 0; 138 if (normalized) 139 { 140 if (NL::is_signed) 141 { 142 result = static_cast<float>(source_pixel[i]) / static_cast<float>(NL::max()); 143 result = result >= -1.0f ? result : -1.0f; 144 } 145 else 146 { 147 result = static_cast<float>(source_pixel[i]) / static_cast<float>(NL::max()); 148 } 149 } 150 else 151 { 152 result = static_cast<float>(source_pixel[i]); 153 } 154 dest_pixel[i] = result; 155 } 156 157 for (size_t j = inputComponentCount; j < outputComponentCount; j++) 158 { 159 dest_pixel[j] = j == 3 ? 1.0f : 0.0f; 160 } 161 } 162 } 163 } 164} 165 166template <size_t blockWidth, size_t blockHeight, size_t blockDepth, size_t blockSize> 167inline void LoadCompressedToNative(const ImageLoadContext &context, size_t width, size_t height, 168 size_t depth, const uint8_t *input, size_t inputRowPitch, 169 size_t inputDepthPitch, uint8_t *output, size_t outputRowPitch, 170 size_t outputDepthPitch) 171{ 172 const size_t columns = (width + (blockWidth - 1)) / blockWidth; 173 const size_t rows = (height + (blockHeight - 1)) / blockHeight; 174 const size_t layers = (depth + (blockDepth - 1)) / blockDepth; 175 176 for (size_t z = 0; z < layers; ++z) 177 { 178 for (size_t y = 0; y < rows; ++y) 179 { 180 const uint8_t *source = priv::OffsetDataPointer<uint8_t>(input, y, z, inputRowPitch, inputDepthPitch); 181 uint8_t *dest = priv::OffsetDataPointer<uint8_t>(output, y, z, outputRowPitch, outputDepthPitch); 182 memcpy(dest, source, columns * blockSize); 183 } 184 } 185} 186 187template <typename type, uint32_t firstBits, uint32_t secondBits, uint32_t thirdBits, uint32_t fourthBits> 188inline void Initialize4ComponentData(size_t width, size_t height, size_t depth, 189 uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) 190{ 191 type writeValues[4] = 192 { 193 gl::bitCast<type>(firstBits), 194 gl::bitCast<type>(secondBits), 195 gl::bitCast<type>(thirdBits), 196 gl::bitCast<type>(fourthBits), 197 }; 198 199 for (size_t z = 0; z < depth; z++) 200 { 201 for (size_t y = 0; y < height; y++) 202 { 203 type *destRow = priv::OffsetDataPointer<type>(output, y, z, outputRowPitch, outputDepthPitch); 204 for (size_t x = 0; x < width; x++) 205 { 206 type* destPixel = destRow + x * 4; 207 208 // This could potentially be optimized by generating an entire row of initialization 209 // data and copying row by row instead of pixel by pixel. 210 memcpy(destPixel, writeValues, sizeof(type) * 4); 211 } 212 } 213 } 214} 215 216template <size_t blockWidth, size_t blockHeight> 217inline void LoadASTCToRGBA8(const ImageLoadContext &context, 218 size_t width, 219 size_t height, 220 size_t depth, 221 const uint8_t *input, 222 size_t inputRowPitch, 223 size_t inputDepthPitch, 224 uint8_t *output, 225 size_t outputRowPitch, 226 size_t outputDepthPitch) 227{ 228 LoadASTCToRGBA8Inner(context, width, height, depth, blockWidth, blockHeight, input, inputRowPitch, 229 inputDepthPitch, output, outputRowPitch, outputDepthPitch); 230} 231 232template <uint32_t indexBits, uint32_t redBlueBits, uint32_t greenBits, uint32_t alphaBits> 233inline void LoadPalettedToRGBA8(const ImageLoadContext &context, 234 size_t width, 235 size_t height, 236 size_t depth, 237 const uint8_t *input, 238 size_t inputRowPitch, 239 size_t inputDepthPitch, 240 uint8_t *output, 241 size_t outputRowPitch, 242 size_t outputDepthPitch) 243{ 244 static_assert(indexBits == 4 || indexBits == 8); 245 static_assert(redBlueBits == 4 || redBlueBits == 5 || redBlueBits == 8); 246 static_assert(greenBits == 4 || greenBits == 5 || greenBits == 6 || greenBits == 8); 247 static_assert(alphaBits == 0 || alphaBits == 1 || alphaBits == 4 || alphaBits == 8); 248 constexpr uint32_t colorBits = 2 * redBlueBits + greenBits + alphaBits; 249 static_assert(colorBits == 16 || colorBits == 24 || colorBits == 32); 250 251 LoadPalettedToRGBA8Impl(context, width, height, depth, 252 indexBits, redBlueBits, greenBits, alphaBits, 253 input, inputRowPitch, inputDepthPitch, 254 output, outputRowPitch, outputDepthPitch); 255} 256 257// Temporary overload functions; need to have no-context overloads of the following functions used 258// by Chromium. A Chromium change will switch to the with-context overloads, and then these can be 259// removed. 260inline void LoadEACR11ToR8(size_t width, 261 size_t height, 262 size_t depth, 263 const uint8_t *input, 264 size_t inputRowPitch, 265 size_t inputDepthPitch, 266 uint8_t *output, 267 size_t outputRowPitch, 268 size_t outputDepthPitch) 269{ 270 LoadEACR11ToR8({}, width, height, depth, input, inputRowPitch, inputDepthPitch, output, 271 outputRowPitch, outputDepthPitch); 272} 273 274inline void LoadEACR11SToR8(size_t width, 275 size_t height, 276 size_t depth, 277 const uint8_t *input, 278 size_t inputRowPitch, 279 size_t inputDepthPitch, 280 uint8_t *output, 281 size_t outputRowPitch, 282 size_t outputDepthPitch) 283{ 284 LoadEACR11SToR8({}, width, height, depth, input, inputRowPitch, inputDepthPitch, output, 285 outputRowPitch, outputDepthPitch); 286} 287 288inline void LoadEACRG11ToRG8(size_t width, 289 size_t height, 290 size_t depth, 291 const uint8_t *input, 292 size_t inputRowPitch, 293 size_t inputDepthPitch, 294 uint8_t *output, 295 size_t outputRowPitch, 296 size_t outputDepthPitch) 297{ 298 LoadEACRG11ToRG8({}, width, height, depth, input, inputRowPitch, inputDepthPitch, output, 299 outputRowPitch, outputDepthPitch); 300} 301 302inline void LoadEACRG11SToRG8(size_t width, 303 size_t height, 304 size_t depth, 305 const uint8_t *input, 306 size_t inputRowPitch, 307 size_t inputDepthPitch, 308 uint8_t *output, 309 size_t outputRowPitch, 310 size_t outputDepthPitch) 311{ 312 LoadEACRG11SToRG8({}, width, height, depth, input, inputRowPitch, inputDepthPitch, output, 313 outputRowPitch, outputDepthPitch); 314} 315 316inline void LoadETC2RGB8ToRGBA8(size_t width, 317 size_t height, 318 size_t depth, 319 const uint8_t *input, 320 size_t inputRowPitch, 321 size_t inputDepthPitch, 322 uint8_t *output, 323 size_t outputRowPitch, 324 size_t outputDepthPitch) 325{ 326 LoadETC2RGB8ToRGBA8({}, width, height, depth, input, inputRowPitch, inputDepthPitch, output, 327 outputRowPitch, outputDepthPitch); 328} 329 330inline void LoadETC2SRGB8ToRGBA8(size_t width, 331 size_t height, 332 size_t depth, 333 const uint8_t *input, 334 size_t inputRowPitch, 335 size_t inputDepthPitch, 336 uint8_t *output, 337 size_t outputRowPitch, 338 size_t outputDepthPitch) 339{ 340 LoadETC2SRGB8ToRGBA8({}, width, height, depth, input, inputRowPitch, inputDepthPitch, output, 341 outputRowPitch, outputDepthPitch); 342} 343 344inline void LoadETC2RGBA8ToRGBA8(size_t width, 345 size_t height, 346 size_t depth, 347 const uint8_t *input, 348 size_t inputRowPitch, 349 size_t inputDepthPitch, 350 uint8_t *output, 351 size_t outputRowPitch, 352 size_t outputDepthPitch) 353{ 354 LoadETC2RGBA8ToRGBA8({}, width, height, depth, input, inputRowPitch, inputDepthPitch, output, 355 outputRowPitch, outputDepthPitch); 356} 357 358inline void LoadETC2RGB8A1ToRGBA8(size_t width, 359 size_t height, 360 size_t depth, 361 const uint8_t *input, 362 size_t inputRowPitch, 363 size_t inputDepthPitch, 364 uint8_t *output, 365 size_t outputRowPitch, 366 size_t outputDepthPitch) 367{ 368 LoadETC2RGB8A1ToRGBA8({}, width, height, depth, input, inputRowPitch, inputDepthPitch, output, 369 outputRowPitch, outputDepthPitch); 370} 371 372inline void LoadETC2SRGBA8ToSRGBA8(size_t width, 373 size_t height, 374 size_t depth, 375 const uint8_t *input, 376 size_t inputRowPitch, 377 size_t inputDepthPitch, 378 uint8_t *output, 379 size_t outputRowPitch, 380 size_t outputDepthPitch) 381{ 382 LoadETC2SRGBA8ToSRGBA8({}, width, height, depth, input, inputRowPitch, inputDepthPitch, output, 383 outputRowPitch, outputDepthPitch); 384} 385 386inline void LoadETC2SRGB8A1ToRGBA8(size_t width, 387 size_t height, 388 size_t depth, 389 const uint8_t *input, 390 size_t inputRowPitch, 391 size_t inputDepthPitch, 392 uint8_t *output, 393 size_t outputRowPitch, 394 size_t outputDepthPitch) 395{ 396 LoadETC2SRGB8A1ToRGBA8({}, width, height, depth, input, inputRowPitch, inputDepthPitch, output, 397 outputRowPitch, outputDepthPitch); 398} 399 400} // namespace angle 401