2015-07-30 22:34:56 +00:00
|
|
|
/*
|
|
|
|
* Copyright 2015 Google Inc.
|
|
|
|
*
|
|
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
|
|
* found in the LICENSE file.
|
|
|
|
*/
|
|
|
|
|
2019-04-23 17:05:21 +00:00
|
|
|
#include "include/core/SkCanvas.h"
|
|
|
|
#include "include/core/SkSurface.h"
|
|
|
|
#include "include/gpu/GrContext.h"
|
2020-07-06 14:56:46 +00:00
|
|
|
#include "include/gpu/GrDirectContext.h"
|
2019-04-23 17:05:21 +00:00
|
|
|
#include "src/gpu/GrCaps.h"
|
|
|
|
#include "src/gpu/GrContextPriv.h"
|
2019-09-30 16:15:30 +00:00
|
|
|
#include "src/gpu/GrImageInfo.h"
|
2019-07-16 19:36:11 +00:00
|
|
|
#include "src/gpu/GrRenderTargetContext.h"
|
2019-04-23 17:05:21 +00:00
|
|
|
#include "src/gpu/GrSurfaceContext.h"
|
|
|
|
#include "src/gpu/SkGr.h"
|
|
|
|
#include "tests/Test.h"
|
2015-07-30 22:34:56 +00:00
|
|
|
|
|
|
|
// using anonymous namespace because these functions are used as template params.
|
|
|
|
namespace {
|
|
|
|
/** convert 0..1 srgb value to 0..1 linear */
|
|
|
|
float srgb_to_linear(float srgb) {
|
|
|
|
if (srgb <= 0.04045f) {
|
|
|
|
return srgb / 12.92f;
|
|
|
|
} else {
|
|
|
|
return powf((srgb + 0.055f) / 1.055f, 2.4f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/** convert 0..1 linear value to 0..1 srgb */
|
|
|
|
float linear_to_srgb(float linear) {
|
|
|
|
if (linear <= 0.0031308) {
|
|
|
|
return linear * 12.92f;
|
|
|
|
} else {
|
|
|
|
return 1.055f * powf(linear, 1.f / 2.4f) - 0.055f;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/** tests a conversion with an error tolerance */
|
|
|
|
template <float (*CONVERT)(float)> static bool check_conversion(uint32_t input, uint32_t output,
|
|
|
|
float error) {
|
|
|
|
// alpha should always be exactly preserved.
|
|
|
|
if ((input & 0xff000000) != (output & 0xff000000)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int c = 0; c < 3; ++c) {
|
|
|
|
uint8_t inputComponent = (uint8_t) ((input & (0xff << (c*8))) >> (c*8));
|
2020-02-07 15:36:46 +00:00
|
|
|
float lower = std::max(0.f, (float) inputComponent - error);
|
|
|
|
float upper = std::min(255.f, (float) inputComponent + error);
|
2015-07-30 22:34:56 +00:00
|
|
|
lower = CONVERT(lower / 255.f);
|
|
|
|
upper = CONVERT(upper / 255.f);
|
|
|
|
SkASSERT(lower >= 0.f && lower <= 255.f);
|
|
|
|
SkASSERT(upper >= 0.f && upper <= 255.f);
|
|
|
|
uint8_t outputComponent = (output & (0xff << (c*8))) >> (c*8);
|
|
|
|
if (outputComponent < SkScalarFloorToInt(lower * 255.f) ||
|
|
|
|
outputComponent > SkScalarCeilToInt(upper * 255.f)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** tests a forward and backward conversion with an error tolerance */
|
|
|
|
template <float (*FORWARD)(float), float (*BACKWARD)(float)>
|
|
|
|
static bool check_double_conversion(uint32_t input, uint32_t output, float error) {
|
|
|
|
// alpha should always be exactly preserved.
|
|
|
|
if ((input & 0xff000000) != (output & 0xff000000)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int c = 0; c < 3; ++c) {
|
|
|
|
uint8_t inputComponent = (uint8_t) ((input & (0xff << (c*8))) >> (c*8));
|
2020-02-07 15:36:46 +00:00
|
|
|
float lower = std::max(0.f, (float) inputComponent - error);
|
|
|
|
float upper = std::min(255.f, (float) inputComponent + error);
|
2015-07-30 22:34:56 +00:00
|
|
|
lower = FORWARD(lower / 255.f);
|
|
|
|
upper = FORWARD(upper / 255.f);
|
|
|
|
SkASSERT(lower >= 0.f && lower <= 255.f);
|
|
|
|
SkASSERT(upper >= 0.f && upper <= 255.f);
|
|
|
|
uint8_t upperComponent = SkScalarCeilToInt(upper * 255.f);
|
|
|
|
uint8_t lowerComponent = SkScalarFloorToInt(lower * 255.f);
|
2020-02-07 15:36:46 +00:00
|
|
|
lower = std::max(0.f, (float) lowerComponent - error);
|
|
|
|
upper = std::min(255.f, (float) upperComponent + error);
|
2015-07-30 22:34:56 +00:00
|
|
|
lower = BACKWARD(lowerComponent / 255.f);
|
|
|
|
upper = BACKWARD(upperComponent / 255.f);
|
|
|
|
SkASSERT(lower >= 0.f && lower <= 255.f);
|
|
|
|
SkASSERT(upper >= 0.f && upper <= 255.f);
|
|
|
|
upperComponent = SkScalarCeilToInt(upper * 255.f);
|
|
|
|
lowerComponent = SkScalarFloorToInt(lower * 255.f);
|
|
|
|
|
|
|
|
uint8_t outputComponent = (output & (0xff << (c*8))) >> (c*8);
|
|
|
|
if (outputComponent < lowerComponent || outputComponent > upperComponent) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool check_srgb_to_linear_conversion(uint32_t srgb, uint32_t linear, float error) {
|
|
|
|
return check_conversion<srgb_to_linear>(srgb, linear, error);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool check_linear_to_srgb_conversion(uint32_t linear, uint32_t srgb, float error) {
|
|
|
|
return check_conversion<linear_to_srgb>(linear, srgb, error);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool check_linear_to_srgb_to_linear_conversion(uint32_t input, uint32_t output, float error) {
|
|
|
|
return check_double_conversion<linear_to_srgb, srgb_to_linear>(input, output, error);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool check_srgb_to_linear_to_srgb_conversion(uint32_t input, uint32_t output, float error) {
|
|
|
|
return check_double_conversion<srgb_to_linear, linear_to_srgb>(input, output, error);
|
|
|
|
}
|
|
|
|
|
2018-02-13 22:13:31 +00:00
|
|
|
static bool check_no_conversion(uint32_t input, uint32_t output, float error) {
|
|
|
|
// This is a bit of a hack to check identity transformations that may lose precision.
|
|
|
|
return check_srgb_to_linear_to_srgb_conversion(input, output, error);
|
|
|
|
}
|
|
|
|
|
2015-07-30 22:34:56 +00:00
|
|
|
typedef bool (*CheckFn) (uint32_t orig, uint32_t actual, float error);
|
|
|
|
|
2017-03-29 16:08:49 +00:00
|
|
|
void read_and_check_pixels(skiatest::Reporter* reporter, GrSurfaceContext* context,
|
|
|
|
uint32_t* origData,
|
|
|
|
const SkImageInfo& dstInfo, CheckFn checker, float error,
|
2015-07-30 22:34:56 +00:00
|
|
|
const char* subtestName) {
|
2017-03-29 16:08:49 +00:00
|
|
|
int w = dstInfo.width();
|
|
|
|
int h = dstInfo.height();
|
2015-07-30 22:34:56 +00:00
|
|
|
SkAutoTMalloc<uint32_t> readData(w * h);
|
|
|
|
memset(readData.get(), 0, sizeof(uint32_t) * w * h);
|
2017-03-29 16:08:49 +00:00
|
|
|
|
2019-07-01 17:05:28 +00:00
|
|
|
if (!context->readPixels(dstInfo, readData.get(), 0, {0, 0})) {
|
2015-07-30 22:34:56 +00:00
|
|
|
ERRORF(reporter, "Could not read pixels for %s.", subtestName);
|
|
|
|
return;
|
|
|
|
}
|
2017-03-29 16:08:49 +00:00
|
|
|
|
2015-07-30 22:34:56 +00:00
|
|
|
for (int j = 0; j < h; ++j) {
|
|
|
|
for (int i = 0; i < w; ++i) {
|
|
|
|
uint32_t orig = origData[j * w + i];
|
|
|
|
uint32_t read = readData[j * w + i];
|
|
|
|
|
|
|
|
if (!checker(orig, read, error)) {
|
2018-03-19 20:06:44 +00:00
|
|
|
ERRORF(reporter, "Original 0x%08x, read back as 0x%08x in %s at %d, %d).", orig,
|
|
|
|
read, subtestName, i, j);
|
2015-07-30 22:34:56 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-13 22:13:31 +00:00
|
|
|
namespace {
|
|
|
|
enum class Encoding {
|
|
|
|
kUntagged,
|
|
|
|
kLinear,
|
|
|
|
kSRGB,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
static sk_sp<SkColorSpace> encoding_as_color_space(Encoding encoding) {
|
|
|
|
switch (encoding) {
|
|
|
|
case Encoding::kUntagged: return nullptr;
|
|
|
|
case Encoding::kLinear: return SkColorSpace::MakeSRGBLinear();
|
|
|
|
case Encoding::kSRGB: return SkColorSpace::MakeSRGB();
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char* encoding_as_str(Encoding encoding) {
|
|
|
|
switch (encoding) {
|
|
|
|
case Encoding::kUntagged: return "untagged";
|
|
|
|
case Encoding::kLinear: return "linear";
|
|
|
|
case Encoding::kSRGB: return "sRGB";
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2018-02-26 19:32:39 +00:00
|
|
|
static constexpr int kW = 255;
|
|
|
|
static constexpr int kH = 255;
|
|
|
|
|
|
|
|
static std::unique_ptr<uint32_t[]> make_data() {
|
|
|
|
std::unique_ptr<uint32_t[]> data(new uint32_t[kW * kH]);
|
2015-07-30 22:34:56 +00:00
|
|
|
for (int j = 0; j < kH; ++j) {
|
|
|
|
for (int i = 0; i < kW; ++i) {
|
2018-07-12 14:47:01 +00:00
|
|
|
data[j * kW + i] = (0xFF << 24) | (i << 16) | (i << 8) | i;
|
2015-07-30 22:34:56 +00:00
|
|
|
}
|
|
|
|
}
|
2018-02-26 19:32:39 +00:00
|
|
|
return data;
|
|
|
|
}
|
2015-07-30 22:34:56 +00:00
|
|
|
|
2019-08-21 13:38:10 +00:00
|
|
|
static std::unique_ptr<GrSurfaceContext> make_surface_context(Encoding contextEncoding,
|
|
|
|
GrContext* context,
|
|
|
|
skiatest::Reporter* reporter) {
|
2020-01-08 16:52:34 +00:00
|
|
|
auto surfaceContext = GrRenderTargetContext::Make(
|
|
|
|
context, GrColorType::kRGBA_8888, encoding_as_color_space(contextEncoding),
|
|
|
|
SkBackingFit::kExact, {kW, kH}, 1, GrMipMapped::kNo, GrProtected::kNo,
|
|
|
|
kBottomLeft_GrSurfaceOrigin, SkBudgeted::kNo);
|
2018-02-13 22:13:31 +00:00
|
|
|
if (!surfaceContext) {
|
|
|
|
ERRORF(reporter, "Could not create %s surface context.", encoding_as_str(contextEncoding));
|
2018-02-26 19:32:39 +00:00
|
|
|
}
|
turn on -Wreturn-std-move-in-c++11
This CL has a complicated back story, but it's concrete change is
simple, just turning the warning on and converting a bunch of
return foo;
to
return std::move(foo);
These changes are exclusively in places where RVO and NRVO do not apply,
so it should not conflict with warnings like -Wpessimizing-move.
Since C++11, when you return a named local and its type doesn't match
the declared return type exactly, there's an implicit std::move()
wrapped around the value (what I'm making explicit here) so the move
constructor gets an opportunity to take precedence over the copy
constructor. You can read about this implicit move here under the
section "automatic move from local variables and parameters":
https://en.cppreference.com/w/cpp/language/return#Notes.
This situation comes up for us with smart pointers: a function declares
its return type as std::unique_ptr<Base> or sk_sp<Base>, and we return a
std::unique_ptr<Impl> or sk_sp<Impl>. Those types don't match exactly,
so RVO and NRVO don't come into play. They've always been going through
move constructors, and that's not changed here, just made explicit.
There was apparently once a bug in the C++11 standard and compilers
implementing that which made these copy instead of move, and then this
sort of code would do a little unnecessary ref/unref dance for sk_sp,
and would entirely fail to compile for uncopyable std::unique_ptr.
These explicit moves ostensibly will make our code more compatible with
those older compilers.
That compatibility alone is, I think, a terrible reason to land this CL.
Like, actively bad. But... to balance that out, I think the explicit
std::move()s here actually help remind us that RVO/NRVO are not in play,
and remind us we're going to call the move constructor. So that C++11
standard bug becomes kind of useful for us, in that Clang added this
warning to catch it, and its fix improves readability.
So really read this all as, "warn about implicit std::move() on return".
In the end I think it's just about readability. I don't really hold any
hope out that we'll become compatible with those older compilers.
Bug: skia:9909
Change-Id: Id596e9261188b6f10e759906af6c95fe303f6ffe
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/271601
Reviewed-by: Brian Salomon <bsalomon@google.com>
Reviewed-by: Ben Wagner <bungeman@google.com>
Commit-Queue: Mike Klein <mtklein@google.com>
2020-02-18 19:33:23 +00:00
|
|
|
return std::move(surfaceContext);
|
2018-02-26 19:32:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_write_read(Encoding contextEncoding, Encoding writeEncoding, Encoding readEncoding,
|
|
|
|
float error, CheckFn check, GrContext* context,
|
|
|
|
skiatest::Reporter* reporter) {
|
|
|
|
auto surfaceContext = make_surface_context(contextEncoding, context, reporter);
|
|
|
|
if (!surfaceContext) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
auto writeII = SkImageInfo::Make(kW, kH, kRGBA_8888_SkColorType, kPremul_SkAlphaType,
|
|
|
|
encoding_as_color_space(writeEncoding));
|
|
|
|
auto data = make_data();
|
2019-07-01 17:05:28 +00:00
|
|
|
if (!surfaceContext->writePixels(writeII, data.get(), 0, {0, 0})) {
|
2018-02-13 22:13:31 +00:00
|
|
|
ERRORF(reporter, "Could not write %s to %s surface context.",
|
|
|
|
encoding_as_str(writeEncoding), encoding_as_str(contextEncoding));
|
|
|
|
return;
|
|
|
|
}
|
2018-02-13 20:51:26 +00:00
|
|
|
|
2018-02-13 22:13:31 +00:00
|
|
|
auto readII = SkImageInfo::Make(kW, kH, kRGBA_8888_SkColorType, kPremul_SkAlphaType,
|
|
|
|
encoding_as_color_space(readEncoding));
|
|
|
|
SkString testName;
|
|
|
|
testName.printf("write %s data to a %s context and read as %s.", encoding_as_str(writeEncoding),
|
|
|
|
encoding_as_str(contextEncoding), encoding_as_str(readEncoding));
|
2018-02-26 19:32:39 +00:00
|
|
|
read_and_check_pixels(reporter, surfaceContext.get(), data.get(), readII, check, error,
|
2018-02-13 22:13:31 +00:00
|
|
|
testName.c_str());
|
|
|
|
}
|
2018-02-13 20:51:26 +00:00
|
|
|
|
2018-02-13 22:13:31 +00:00
|
|
|
// Test all combinations of writePixels/readPixels where the surface context/write source/read dst
|
|
|
|
// are sRGB, linear, or untagged RGBA_8888.
|
|
|
|
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SRGBReadWritePixels, reporter, ctxInfo) {
|
2020-07-06 14:56:46 +00:00
|
|
|
auto context = ctxInfo.directContext();
|
2019-08-01 17:08:33 +00:00
|
|
|
if (!context->priv().caps()->getDefaultBackendFormat(GrColorType::kRGBA_8888_SRGB,
|
|
|
|
GrRenderable::kNo).isValid()) {
|
2018-02-13 22:13:31 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
// We allow more error on GPUs with lower precision shader variables.
|
2019-02-04 18:26:26 +00:00
|
|
|
float error = context->priv().caps()->shaderCaps()->halfIs32Bits() ? 0.5f : 1.2f;
|
2018-02-13 22:13:31 +00:00
|
|
|
// For the all-sRGB case, we allow a small error only for devices that have
|
|
|
|
// precision variation because the sRGB data gets converted to linear and back in
|
|
|
|
// the shader.
|
2019-02-04 18:26:26 +00:00
|
|
|
float smallError = context->priv().caps()->shaderCaps()->halfIs32Bits() ? 0.0f : 1.f;
|
2018-02-13 20:51:26 +00:00
|
|
|
|
2018-02-13 22:13:31 +00:00
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Write sRGB data to a sRGB context - no conversion on the write.
|
|
|
|
|
2018-03-19 20:06:44 +00:00
|
|
|
// back to sRGB - no conversion.
|
2018-02-26 19:32:39 +00:00
|
|
|
test_write_read(Encoding::kSRGB, Encoding::kSRGB, Encoding::kSRGB, smallError,
|
|
|
|
check_no_conversion, context, reporter);
|
2018-03-19 20:06:44 +00:00
|
|
|
// Reading back to untagged should be a pass through with no conversion.
|
|
|
|
test_write_read(Encoding::kSRGB, Encoding::kSRGB, Encoding::kUntagged, error,
|
|
|
|
check_no_conversion, context, reporter);
|
|
|
|
|
2018-02-13 22:13:31 +00:00
|
|
|
// Converts back to linear
|
2018-02-26 19:32:39 +00:00
|
|
|
test_write_read(Encoding::kSRGB, Encoding::kSRGB, Encoding::kLinear, error,
|
|
|
|
check_srgb_to_linear_conversion, context, reporter);
|
2018-02-13 22:13:31 +00:00
|
|
|
|
let's like, chill out about all these rules, man
There's really no reason to prevent any of these conversions;
they all have somewhat reasonable behavior:
- converting between grey in different color spaces
should probably work just fine
- we'll convert color to gray using a fixed set of
luminance coefficients, but that's better than failing
- we'll invent {r,g,b} = {0,0,0} if we convert alpha
to something with color
- converting to opaque formats without thinking about
premul/unpremul is probably fine, better than just
not working at all
- a missing src color space can always be assumed to be sRGB
Updates to ReadPixelsTest:
- skip more supported test cases in test_conversion(),
each with a TODO
- conversions from non-opaque to opaque should now work
- conversion from A8 to non-A8 should sometimes now
work on GPUs, and the test needed a little bit of
a tweak to not expect A8 to carry around color somehow.
Updates to SRGBReadWritePixelsTest:
- writing untagged pixels shouldn't fail anymore;
instead, it should behave like it was tagged sRGB
Change-Id: I19e78f3a6c89ef74fbcbc985d3fbd77fa984b1c2
Reviewed-on: https://skia-review.googlesource.com/147815
Commit-Queue: Mike Klein <mtklein@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
2018-08-17 18:09:55 +00:00
|
|
|
// Untagged source data should be interpreted as sRGB.
|
|
|
|
test_write_read(Encoding::kSRGB, Encoding::kUntagged, Encoding::kSRGB, smallError,
|
|
|
|
check_no_conversion, context, reporter);
|
2018-02-13 22:13:31 +00:00
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Write linear data to a sRGB context. It gets converted to sRGB on write. The reads
|
|
|
|
// are all the same as the above cases where the original data was untagged.
|
2018-02-26 19:32:39 +00:00
|
|
|
test_write_read(Encoding::kSRGB, Encoding::kLinear, Encoding::kSRGB, error,
|
|
|
|
check_linear_to_srgb_conversion, context, reporter);
|
2018-03-19 20:06:44 +00:00
|
|
|
// When the dst buffer is untagged there should be no conversion on the read.
|
|
|
|
test_write_read(Encoding::kSRGB, Encoding::kLinear, Encoding::kUntagged, error,
|
|
|
|
check_linear_to_srgb_conversion, context, reporter);
|
2018-02-26 19:32:39 +00:00
|
|
|
test_write_read(Encoding::kSRGB, Encoding::kLinear, Encoding::kLinear, error,
|
|
|
|
check_linear_to_srgb_to_linear_conversion, context, reporter);
|
2018-02-13 22:13:31 +00:00
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Write data to an untagged context. The write does no conversion no matter what encoding the
|
|
|
|
// src data has.
|
|
|
|
for (auto writeEncoding : {Encoding::kSRGB, Encoding::kUntagged, Encoding::kLinear}) {
|
2018-03-19 20:06:44 +00:00
|
|
|
// The read from untagged to sRGB also does no conversion.
|
2018-02-26 19:32:39 +00:00
|
|
|
test_write_read(Encoding::kUntagged, writeEncoding, Encoding::kSRGB, error,
|
|
|
|
check_no_conversion, context, reporter);
|
2018-02-13 22:13:31 +00:00
|
|
|
// Reading untagged back as untagged should do no conversion.
|
2018-02-26 19:32:39 +00:00
|
|
|
test_write_read(Encoding::kUntagged, writeEncoding, Encoding::kUntagged, error,
|
|
|
|
check_no_conversion, context, reporter);
|
2019-03-28 15:49:01 +00:00
|
|
|
// Reading untagged back as linear does convert (context is source, so treated as sRGB),
|
|
|
|
// dst is tagged.
|
2018-02-26 19:32:39 +00:00
|
|
|
test_write_read(Encoding::kUntagged, writeEncoding, Encoding::kLinear, error,
|
2019-03-28 15:49:01 +00:00
|
|
|
check_srgb_to_linear_conversion, context, reporter);
|
2015-07-30 22:34:56 +00:00
|
|
|
}
|
2018-02-13 22:13:31 +00:00
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Write sRGB data to a linear context - converts to sRGB on the write.
|
|
|
|
|
|
|
|
// converts back to sRGB on read.
|
2018-02-26 19:32:39 +00:00
|
|
|
test_write_read(Encoding::kLinear, Encoding::kSRGB, Encoding::kSRGB, error,
|
|
|
|
check_srgb_to_linear_to_srgb_conversion, context, reporter);
|
2018-03-19 20:06:44 +00:00
|
|
|
// Reading untagged data from linear currently does no conversion.
|
2018-02-26 19:32:39 +00:00
|
|
|
test_write_read(Encoding::kLinear, Encoding::kSRGB, Encoding::kUntagged, error,
|
|
|
|
check_srgb_to_linear_conversion, context, reporter);
|
2018-02-13 22:13:31 +00:00
|
|
|
// Stays linear when read.
|
2018-02-26 19:32:39 +00:00
|
|
|
test_write_read(Encoding::kLinear, Encoding::kSRGB, Encoding::kLinear, error,
|
|
|
|
check_srgb_to_linear_conversion, context, reporter);
|
2018-02-13 22:13:31 +00:00
|
|
|
|
let's like, chill out about all these rules, man
There's really no reason to prevent any of these conversions;
they all have somewhat reasonable behavior:
- converting between grey in different color spaces
should probably work just fine
- we'll convert color to gray using a fixed set of
luminance coefficients, but that's better than failing
- we'll invent {r,g,b} = {0,0,0} if we convert alpha
to something with color
- converting to opaque formats without thinking about
premul/unpremul is probably fine, better than just
not working at all
- a missing src color space can always be assumed to be sRGB
Updates to ReadPixelsTest:
- skip more supported test cases in test_conversion(),
each with a TODO
- conversions from non-opaque to opaque should now work
- conversion from A8 to non-A8 should sometimes now
work on GPUs, and the test needed a little bit of
a tweak to not expect A8 to carry around color somehow.
Updates to SRGBReadWritePixelsTest:
- writing untagged pixels shouldn't fail anymore;
instead, it should behave like it was tagged sRGB
Change-Id: I19e78f3a6c89ef74fbcbc985d3fbd77fa984b1c2
Reviewed-on: https://skia-review.googlesource.com/147815
Commit-Queue: Mike Klein <mtklein@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
2018-08-17 18:09:55 +00:00
|
|
|
// Untagged source data should be interpreted as sRGB.
|
|
|
|
test_write_read(Encoding::kLinear, Encoding::kUntagged, Encoding::kSRGB, error,
|
|
|
|
check_srgb_to_linear_to_srgb_conversion, context, reporter);
|
2018-02-13 22:13:31 +00:00
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Write linear data to a linear context. Does no conversion.
|
|
|
|
|
|
|
|
// Reading to sRGB does a conversion.
|
2018-02-26 19:32:39 +00:00
|
|
|
test_write_read(Encoding::kLinear, Encoding::kLinear, Encoding::kSRGB, error,
|
|
|
|
check_linear_to_srgb_conversion, context, reporter);
|
2018-03-19 20:06:44 +00:00
|
|
|
// Reading to untagged does no conversion.
|
2018-02-26 19:32:39 +00:00
|
|
|
test_write_read(Encoding::kLinear, Encoding::kLinear, Encoding::kUntagged, error,
|
|
|
|
check_no_conversion, context, reporter);
|
2018-02-13 22:13:31 +00:00
|
|
|
// Stays linear when read.
|
2018-02-26 19:32:39 +00:00
|
|
|
test_write_read(Encoding::kLinear, Encoding::kLinear, Encoding::kLinear, error,
|
|
|
|
check_no_conversion, context, reporter);
|
2015-07-30 22:34:56 +00:00
|
|
|
}
|