| /* | |
| * Copyright 2023 Google LLC | |
| * | |
| * Use of this source code is governed by a BSD-style license that can be | |
| * found in the LICENSE file. | |
| */ | |
| #include "src/gpu/DitherUtils.h" | |
| #ifndef SK_IGNORE_GPU_DITHER | |
| #include "include/core/SkBitmap.h" | |
| #include "include/core/SkColorType.h" | |
| #include "include/core/SkImageInfo.h" | |
| #include <cstdint> | |
| namespace skgpu { | |
| float DitherRangeForConfig(SkColorType dstColorType) { | |
| SkASSERT(dstColorType != kUnknown_SkColorType); | |
| // We use 1 / (2^bitdepth-1) as the range since each channel can hold 2^bitdepth values | |
| switch (dstColorType) { | |
| // 4 bit | |
| case kARGB_4444_SkColorType: | |
| return 1 / 15.f; | |
| // 6 bit | |
| case kRGB_565_SkColorType: | |
| return 1 / 63.f; | |
| // 8 bit | |
| case kAlpha_8_SkColorType: | |
| case kGray_8_SkColorType: | |
| case kR8_unorm_SkColorType: | |
| case kR8G8_unorm_SkColorType: | |
| case kRGB_888x_SkColorType: | |
| case kRGBA_8888_SkColorType: | |
| case kSRGBA_8888_SkColorType: | |
| case kBGRA_8888_SkColorType: | |
| return 1 / 255.f; | |
| // 10 bit | |
| case kRGBA_1010102_SkColorType: | |
| case kBGRA_1010102_SkColorType: | |
| case kRGB_101010x_SkColorType: | |
| case kBGR_101010x_SkColorType: | |
| case kBGR_101010x_XR_SkColorType: | |
| case kBGRA_10101010_XR_SkColorType: | |
| case kRGBA_10x6_SkColorType: | |
| return 1 / 1023.f; | |
| // 16 bit | |
| case kA16_unorm_SkColorType: | |
| case kR16_unorm_SkColorType: | |
| case kR16G16_unorm_SkColorType: | |
| case kR16G16B16A16_unorm_SkColorType: | |
| return 1 / 32767.f; | |
| // Unknown | |
| case kUnknown_SkColorType: | |
| // Half | |
| case kA16_float_SkColorType: | |
| case kR16_float_SkColorType: | |
| case kR16G16_float_SkColorType: | |
| case kRGBA_F16_SkColorType: | |
| case kRGB_F16F16F16x_SkColorType: | |
| case kRGBA_F16Norm_SkColorType: | |
| // Float | |
| case kRGBA_F32_SkColorType: | |
| return 0.f; // no dithering | |
| } | |
| SkUNREACHABLE; | |
| } | |
| SkBitmap MakeDitherLUT() { | |
| static constexpr struct DitherTable { | |
| constexpr DitherTable() : data() { | |
| constexpr int kImgSize = 8; // if changed, also change value in sk_dither_shader | |
| for (int x = 0; x < kImgSize; ++x) { | |
| for (int y = 0; y < kImgSize; ++y) { | |
| // The computation of 'm' and 'value' is lifted from CPU backend. | |
| unsigned int m = (y & 1) << 5 | (x & 1) << 4 | | |
| (y & 2) << 2 | (x & 2) << 1 | | |
| (y & 4) >> 1 | (x & 4) >> 2; | |
| float value = static_cast<float>(m) * (1.0f / 64.0f) - (63.0f / 128.0f); | |
| // Bias by 0.5 to be in 0..1, mul by 255 and round to nearest int to make byte. | |
| data[y * 8 + x] = (uint8_t)((value + 0.5f) * 255.f + 0.5f); | |
| } | |
| } | |
| } | |
| uint8_t data[64]; | |
| } gTable; | |
| SkBitmap bmp; | |
| bmp.installPixels(SkImageInfo::MakeA8(8, 8), const_cast<uint8_t*>(gTable.data), 8); | |
| bmp.setImmutable(); | |
| return bmp; | |
| } | |
| } // namespace skgpu | |
| #endif // SK_IGNORE_GPU_DITHER |