1d5b598c4e
We'd really like to converge on SkRGBA4f everywhere. This CL continues to store GrColor4f in the GPU backend, but changes the constantColor optimization logic to use SkPMColor4f. GrColor[4f] have "unknown" alpha type, but in this context, they are nearly always premul, so let's take advantage of our SkRGBA4f type safety. We lose some of the semantic benefits and helpers that are present in GrColor4f (OpaqueWhite, TransparentBlack). The biggest thing that would probably help is a direct path to/from bytes (GrColor). Bug: skia: Change-Id: Ic0838ad3f95d207163b3af51e5f5cf6f499c2047 Reviewed-on: https://skia-review.googlesource.com/157840 Reviewed-by: Mike Klein <mtklein@google.com> Commit-Queue: Brian Osman <brianosman@google.com>
248 lines
7.4 KiB
C++
248 lines
7.4 KiB
C++
|
|
/*
|
|
* Copyright 2010 Google Inc.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
* found in the LICENSE file.
|
|
*/
|
|
|
|
|
|
|
|
#ifndef GrColor_DEFINED
|
|
#define GrColor_DEFINED
|
|
|
|
#include "GrTypes.h"
|
|
#include "SkColor.h"
|
|
#include "SkColorPriv.h"
|
|
#include "SkUnPreMultiply.h"
|
|
|
|
/**
|
|
* GrColor is 4 bytes for R, G, B, A, in a specific order defined below. Whether the color is
|
|
* premultiplied or not depends on the context in which it is being used.
|
|
*/
|
|
typedef uint32_t GrColor;
|
|
|
|
// shift amount to assign a component to a GrColor int
|
|
// These shift values are chosen for compatibility with GL attrib arrays
|
|
// ES doesn't allow BGRA vertex attrib order so if they were not in this order
|
|
// we'd have to swizzle in shaders.
|
|
#ifdef SK_CPU_BENDIAN
|
|
#define GrColor_SHIFT_R 24
|
|
#define GrColor_SHIFT_G 16
|
|
#define GrColor_SHIFT_B 8
|
|
#define GrColor_SHIFT_A 0
|
|
#else
|
|
#define GrColor_SHIFT_R 0
|
|
#define GrColor_SHIFT_G 8
|
|
#define GrColor_SHIFT_B 16
|
|
#define GrColor_SHIFT_A 24
|
|
#endif
|
|
|
|
/**
|
|
* Pack 4 components (RGBA) into a GrColor int
|
|
*/
|
|
static inline GrColor GrColorPackRGBA(unsigned r, unsigned g, unsigned b, unsigned a) {
|
|
SkASSERT((uint8_t)r == r);
|
|
SkASSERT((uint8_t)g == g);
|
|
SkASSERT((uint8_t)b == b);
|
|
SkASSERT((uint8_t)a == a);
|
|
return (r << GrColor_SHIFT_R) |
|
|
(g << GrColor_SHIFT_G) |
|
|
(b << GrColor_SHIFT_B) |
|
|
(a << GrColor_SHIFT_A);
|
|
}
|
|
|
|
/**
|
|
* Packs a color with an alpha channel replicated across all four channels.
|
|
*/
|
|
static inline GrColor GrColorPackA4(unsigned a) {
|
|
SkASSERT((uint8_t)a == a);
|
|
return (a << GrColor_SHIFT_R) |
|
|
(a << GrColor_SHIFT_G) |
|
|
(a << GrColor_SHIFT_B) |
|
|
(a << GrColor_SHIFT_A);
|
|
}
|
|
|
|
// extract a component (byte) from a GrColor int
|
|
|
|
#define GrColorUnpackR(color) (((color) >> GrColor_SHIFT_R) & 0xFF)
|
|
#define GrColorUnpackG(color) (((color) >> GrColor_SHIFT_G) & 0xFF)
|
|
#define GrColorUnpackB(color) (((color) >> GrColor_SHIFT_B) & 0xFF)
|
|
#define GrColorUnpackA(color) (((color) >> GrColor_SHIFT_A) & 0xFF)
|
|
|
|
/**
|
|
* Since premultiplied means that alpha >= color, we construct a color with
|
|
* each component==255 and alpha == 0 to be "illegal"
|
|
*/
|
|
#define GrColor_ILLEGAL (~(0xFF << GrColor_SHIFT_A))
|
|
|
|
#define GrColor_WHITE 0xFFFFFFFF
|
|
#define GrColor_TRANSPARENT_BLACK 0x0
|
|
|
|
/**
|
|
* Assert in debug builds that a GrColor is premultiplied.
|
|
*/
|
|
static inline void GrColorIsPMAssert(GrColor SkDEBUGCODE(c)) {
|
|
#ifdef SK_DEBUG
|
|
unsigned a = GrColorUnpackA(c);
|
|
unsigned r = GrColorUnpackR(c);
|
|
unsigned g = GrColorUnpackG(c);
|
|
unsigned b = GrColorUnpackB(c);
|
|
|
|
SkASSERT(r <= a);
|
|
SkASSERT(g <= a);
|
|
SkASSERT(b <= a);
|
|
#endif
|
|
}
|
|
|
|
static inline GrColor GrColorMul(GrColor c0, GrColor c1) {
|
|
U8CPU r = SkMulDiv255Round(GrColorUnpackR(c0), GrColorUnpackR(c1));
|
|
U8CPU g = SkMulDiv255Round(GrColorUnpackG(c0), GrColorUnpackG(c1));
|
|
U8CPU b = SkMulDiv255Round(GrColorUnpackB(c0), GrColorUnpackB(c1));
|
|
U8CPU a = SkMulDiv255Round(GrColorUnpackA(c0), GrColorUnpackA(c1));
|
|
return GrColorPackRGBA(r, g, b, a);
|
|
}
|
|
|
|
/** Converts a GrColor to an rgba array of GrGLfloat */
|
|
static inline void GrColorToRGBAFloat(GrColor color, float rgba[4]) {
|
|
static const float ONE_OVER_255 = 1.f / 255.f;
|
|
rgba[0] = GrColorUnpackR(color) * ONE_OVER_255;
|
|
rgba[1] = GrColorUnpackG(color) * ONE_OVER_255;
|
|
rgba[2] = GrColorUnpackB(color) * ONE_OVER_255;
|
|
rgba[3] = GrColorUnpackA(color) * ONE_OVER_255;
|
|
}
|
|
|
|
/** Normalizes and coverts an uint8_t to a float. [0, 255] -> [0.0, 1.0] */
|
|
static inline float GrNormalizeByteToFloat(uint8_t value) {
|
|
static const float ONE_OVER_255 = 1.f / 255.f;
|
|
return value * ONE_OVER_255;
|
|
}
|
|
|
|
/** Determines whether the color is opaque or not. */
|
|
static inline bool GrColorIsOpaque(GrColor color) {
|
|
return (color & (0xFFU << GrColor_SHIFT_A)) == (0xFFU << GrColor_SHIFT_A);
|
|
}
|
|
|
|
static inline GrColor GrPremulColor(GrColor color) {
|
|
unsigned r = GrColorUnpackR(color);
|
|
unsigned g = GrColorUnpackG(color);
|
|
unsigned b = GrColorUnpackB(color);
|
|
unsigned a = GrColorUnpackA(color);
|
|
return GrColorPackRGBA(SkMulDiv255Round(r, a),
|
|
SkMulDiv255Round(g, a),
|
|
SkMulDiv255Round(b, a),
|
|
a);
|
|
}
|
|
|
|
/** Returns an unpremuled version of the GrColor. */
|
|
static inline GrColor GrUnpremulColor(GrColor color) {
|
|
GrColorIsPMAssert(color);
|
|
unsigned r = GrColorUnpackR(color);
|
|
unsigned g = GrColorUnpackG(color);
|
|
unsigned b = GrColorUnpackB(color);
|
|
unsigned a = GrColorUnpackA(color);
|
|
SkPMColor colorPM = SkPackARGB32(a, r, g, b);
|
|
SkColor colorUPM = SkUnPreMultiply::PMColorToColor(colorPM);
|
|
|
|
r = SkColorGetR(colorUPM);
|
|
g = SkColorGetG(colorUPM);
|
|
b = SkColorGetB(colorUPM);
|
|
a = SkColorGetA(colorUPM);
|
|
|
|
return GrColorPackRGBA(r, g, b, a);
|
|
}
|
|
|
|
|
|
/**
|
|
* Similarly, GrColor4f is 4 floats for R, G, B, A, in that order. And like GrColor, whether
|
|
* the color is premultiplied or not depends on the context.
|
|
*/
|
|
struct GrColor4f {
|
|
float fRGBA[4];
|
|
|
|
GrColor4f() {}
|
|
GrColor4f(float r, float g, float b, float a) {
|
|
fRGBA[0] = r;
|
|
fRGBA[1] = g;
|
|
fRGBA[2] = b;
|
|
fRGBA[3] = a;
|
|
}
|
|
|
|
enum Illegal_Constructor {
|
|
kIllegalConstructor
|
|
};
|
|
GrColor4f(Illegal_Constructor) {
|
|
fRGBA[0] = SK_FloatNaN;
|
|
fRGBA[1] = SK_FloatNaN;
|
|
fRGBA[2] = SK_FloatNaN;
|
|
fRGBA[3] = SK_FloatNaN;
|
|
}
|
|
|
|
static GrColor4f OpaqueWhite() {
|
|
return GrColor4f(1.0f, 1.0f, 1.0f, 1.0f);
|
|
}
|
|
|
|
static GrColor4f TransparentBlack() {
|
|
return GrColor4f(0.0f, 0.0f, 0.0f, 0.0f);
|
|
}
|
|
|
|
static GrColor4f FromGrColor(GrColor color) {
|
|
GrColor4f result;
|
|
GrColorToRGBAFloat(color, result.fRGBA);
|
|
return result;
|
|
}
|
|
|
|
template <SkAlphaType kAT>
|
|
static GrColor4f FromRGBA4f(const SkRGBA4f<kAT>& color) {
|
|
return GrColor4f(color.fR, color.fG, color.fB, color.fA);
|
|
}
|
|
|
|
bool operator==(const GrColor4f& other) const {
|
|
return
|
|
fRGBA[0] == other.fRGBA[0] &&
|
|
fRGBA[1] == other.fRGBA[1] &&
|
|
fRGBA[2] == other.fRGBA[2] &&
|
|
fRGBA[3] == other.fRGBA[3];
|
|
}
|
|
bool operator!=(const GrColor4f& other) const {
|
|
return !(*this == other);
|
|
}
|
|
|
|
GrColor toGrColor() const {
|
|
return GrColorPackRGBA(
|
|
static_cast<unsigned>(SkTPin(fRGBA[0], 0.0f,1.0f) * 255 + 0.5f),
|
|
static_cast<unsigned>(SkTPin(fRGBA[1], 0.0f,1.0f) * 255 + 0.5f),
|
|
static_cast<unsigned>(SkTPin(fRGBA[2], 0.0f,1.0f) * 255 + 0.5f),
|
|
static_cast<unsigned>(SkTPin(fRGBA[3], 0.0f,1.0f) * 255 + 0.5f));
|
|
}
|
|
|
|
template <SkAlphaType kAT>
|
|
SkRGBA4f<kAT> asRGBA4f() const {
|
|
return SkRGBA4f<kAT> { fRGBA[0], fRGBA[1], fRGBA[2], fRGBA[3] };
|
|
}
|
|
|
|
GrColor4f opaque() const {
|
|
return GrColor4f(fRGBA[0], fRGBA[1], fRGBA[2], 1.0f);
|
|
}
|
|
|
|
bool isOpaque() const {
|
|
return fRGBA[3] >= 1.f; // just in case precision causes a superopaque value.
|
|
}
|
|
|
|
GrColor4f premul() const {
|
|
float a = fRGBA[3];
|
|
return GrColor4f(fRGBA[0] * a, fRGBA[1] * a, fRGBA[2] * a, a);
|
|
}
|
|
|
|
GrColor4f unpremul() const {
|
|
float a = fRGBA[3];
|
|
if (a <= 0.0f) {
|
|
return GrColor4f(0.0f, 0.0f, 0.0f, 0.0f);
|
|
}
|
|
float invAlpha = 1.0f / a;
|
|
return GrColor4f(fRGBA[0] * invAlpha, fRGBA[1] * invAlpha, fRGBA[2] * invAlpha, a);
|
|
}
|
|
};
|
|
|
|
#endif
|