Compute inverse gamma table at compile time.

This introduces skstd::index_sequence and skstd::make_index_sequence so
that these can be used in C++11. These are mostly equivalent to their
std:: counterparts. This also introduces SkMakeArray<N, C>
which is constexpr and creates a std::array with N elements with each
element being initialized with the value of C(i) where i is the index of
the element.

These are then used to create inverse gamma table at compile time. This
avoids threading issues.

BUG=skia:7187

Change-Id: I61fb10a778898652e546d54c104a08d6e6bf88d3
Reviewed-on: https://skia-review.googlesource.com/61380
Commit-Queue: Ben Wagner <bungeman@google.com>
Reviewed-by: Mike Klein <mtklein@chromium.org>
This commit is contained in:
Ben Wagner 2017-10-18 11:30:56 -04:00 committed by Skia Commit-Bot
parent 62cbb67a02
commit 7a0248f738
3 changed files with 38 additions and 17 deletions

View File

@ -14,6 +14,7 @@
#ifndef SkTLogic_DEFINED
#define SkTLogic_DEFINED
#include <array>
#include <stddef.h>
#include <stdint.h>
#include <type_traits>
@ -39,6 +40,8 @@ template <typename T> using add_cv_t = typename std::add_cv<T>::type;
template <typename T> using add_pointer_t = typename std::add_pointer<T>::type;
template <typename T> using add_lvalue_reference_t = typename std::add_lvalue_reference<T>::type;
template <typename T> using result_of_t = typename std::result_of<T>::type;
template <typename... T> using common_type_t = typename std::common_type<T...>::type;
// Chromium currently requires gcc 4.8.2 or a recent clang compiler, but uses libstdc++4.6.4.
@ -64,6 +67,25 @@ template <typename T> using is_trivially_destructible = std::is_trivially_destru
#endif
template <typename T> using underlying_type_t = typename skstd::underlying_type<T>::type;
template <std::size_t... Ints> struct index_sequence {
using type = index_sequence;
using value_type = size_t;
static constexpr std::size_t size() noexcept { return sizeof...(Ints); }
};
template <typename S1, typename S2> struct make_index_sequence_combine;
template <size_t... I1, size_t... I2>
struct make_index_sequence_combine<skstd::index_sequence<I1...>, skstd::index_sequence<I2...>>
: skstd::index_sequence<I1..., (sizeof...(I1)+I2)...>
{ };
template <size_t N> struct make_index_sequence
: make_index_sequence_combine<typename skstd::make_index_sequence< N/2>::type,
typename skstd::make_index_sequence<N - N/2>::type>{};
template<> struct make_index_sequence<0> : skstd::index_sequence< >{};
template<> struct make_index_sequence<1> : skstd::index_sequence<0>{};
} // namespace skstd
// The sknonstd namespace contains things we would like to be proposed and feel std-ish.

View File

@ -483,4 +483,15 @@ private:
using SkAutoFree = std::unique_ptr<void, SkFunctionWrapper<void, void, sk_free>>;
template<typename C, std::size_t... Is>
constexpr auto SkMakeArrayFromIndexSequence(C c, skstd::index_sequence<Is...>)
-> std::array<skstd::result_of_t<C(std::size_t)>, sizeof...(Is)> {
return {{ c(Is)... }};
}
template<size_t N, typename C> constexpr auto SkMakeArray(C c)
-> std::array<skstd::result_of_t<C(std::size_t)>, N> {
return SkMakeArrayFromIndexSequence(c, skstd::make_index_sequence<N>{});
}
#endif

View File

@ -1056,12 +1056,8 @@ void SkScalerContext_Mac::generateMetrics(SkGlyph* glyph) {
#include "SkColorData.h"
static void build_power_table(uint8_t table[]) {
for (int i = 0; i < 256; i++) {
float x = i / 255.f;
int xx = SkScalarRoundToInt(x * x * 255);
table[i] = SkToU8(xx);
}
static constexpr uint8_t sk_pow2_table(size_t i) {
return SkToU8(((i * i + 128) / 255));
}
/**
@ -1071,15 +1067,7 @@ static void build_power_table(uint8_t table[]) {
* CoreGraphics obscurely defaults to 2.0 as the smoothing gamma value.
* The color space used does not appear to affect this choice.
*/
static const uint8_t* getInverseGammaTableCoreGraphicSmoothing() {
static bool gInited;
static uint8_t gTableCoreGraphicsSmoothing[256];
if (!gInited) {
build_power_table(gTableCoreGraphicsSmoothing);
gInited = true;
}
return gTableCoreGraphicsSmoothing;
}
static constexpr auto gLinearCoverageFromCGLCDValue = SkMakeArray<256>(sk_pow2_table);
static void cgpixels_to_bits(uint8_t dst[], const CGRGBPixel src[], int count) {
while (count > 0) {
@ -1179,7 +1167,7 @@ void SkScalerContext_Mac::generateImage(const SkGlyph& glyph) {
if ((glyph.fMaskFormat == SkMask::kLCD16_Format) ||
(glyph.fMaskFormat == SkMask::kA8_Format && supports_LCD() && generateA8FromLCD))
{
const uint8_t* table = getInverseGammaTableCoreGraphicSmoothing();
const uint8_t* linear = gLinearCoverageFromCGLCDValue.data();
//Note that the following cannot really be integrated into the
//pre-blend, since we may not be applying the pre-blend; when we aren't
@ -1192,7 +1180,7 @@ void SkScalerContext_Mac::generateImage(const SkGlyph& glyph) {
int r = (addr[x] >> 16) & 0xFF;
int g = (addr[x] >> 8) & 0xFF;
int b = (addr[x] >> 0) & 0xFF;
addr[x] = (table[r] << 16) | (table[g] << 8) | table[b];
addr[x] = (linear[r] << 16) | (linear[g] << 8) | linear[b];
}
addr = SkTAddOffset<CGRGBPixel>(addr, cgRowBytes);
}