aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar bsalomon <bsalomon@google.com>2015-07-30 15:34:56 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2015-07-30 15:34:56 -0700
commit16921ec30a81976129d507b1148c93a322e61a4f (patch)
tree5eb7ceafe1b43b2a168de7f46d4ebdde3bc1d7cc
parent381b26f03bdccac1e3d9055fb4f7855792cfefb0 (diff)
SRGB read and write pixels working and unit test
-rw-r--r--include/gpu/GrCaps.h2
-rw-r--r--include/gpu/GrTypes.h11
-rw-r--r--src/gpu/gl/GrGLCaps.cpp59
-rw-r--r--src/gpu/gl/GrGLCaps.h15
-rw-r--r--src/gpu/gl/GrGLGpu.cpp59
-rw-r--r--src/gpu/gl/GrGLGpu.h1
-rw-r--r--tests/SRGBReadWritePixelsTest.cpp235
7 files changed, 339 insertions, 43 deletions
diff --git a/include/gpu/GrCaps.h b/include/gpu/GrCaps.h
index 6b24ecd6bf..5452eb329f 100644
--- a/include/gpu/GrCaps.h
+++ b/include/gpu/GrCaps.h
@@ -106,8 +106,6 @@ private:
*/
class GrCaps : public SkRefCnt {
public:
-
-
GrCaps(const GrContextOptions&);
virtual SkString dump() const;
diff --git a/include/gpu/GrTypes.h b/include/gpu/GrTypes.h
index 1f83b64d9d..082cdf1dc4 100644
--- a/include/gpu/GrTypes.h
+++ b/include/gpu/GrTypes.h
@@ -313,6 +313,17 @@ static inline bool GrPixelConfigIs8888(GrPixelConfig config) {
}
}
+// Returns true if the color (non-alpha) components represent sRGB values. It does NOT indicate that
+// all three color components are present in the config or anything about their order.
+static inline bool GrPixelConfigIsSRGB(GrPixelConfig config) {
+ switch (config) {
+ case kSRGBA_8888_GrPixelConfig:
+ return true;
+ default:
+ return false;
+ }
+}
+
// Takes a config and returns the equivalent config with the R and B order
// swapped if such a config exists. Otherwise, kUnknown_GrPixelConfig
static inline GrPixelConfig GrPixelConfigSwapRAndB(GrPixelConfig config) {
diff --git a/src/gpu/gl/GrGLCaps.cpp b/src/gpu/gl/GrGLCaps.cpp
index 318426b5bc..161dac6e9f 100644
--- a/src/gpu/gl/GrGLCaps.cpp
+++ b/src/gpu/gl/GrGLCaps.cpp
@@ -49,6 +49,7 @@ GrGLCaps::GrGLCaps(const GrContextOptions& contextOptions,
fIsCoreProfile = false;
fFullClearIsFree = false;
fBindFragDataLocationSupport = false;
+ fSRGBWriteControl = false;
fReadPixelsSupportedCache.reset();
@@ -191,6 +192,27 @@ void GrGLCaps::init(const GrContextOptions& contextOptions,
// can change based on which render target is bound
fTwoFormatLimit = kGLES_GrGLStandard == standard;
+ // We only enable srgb support if both textures and FBOs support srgb.
+ bool srgbSupport = false;
+ if (kGL_GrGLStandard == standard) {
+ if (ctxInfo.version() >= GR_GL_VER(3,0)) {
+ srgbSupport = true;
+ } else if (ctxInfo.hasExtension("GL_EXT_texture_sRGB")) {
+ if (ctxInfo.hasExtension("GL_ARB_framebuffer_sRGB") ||
+ ctxInfo.hasExtension("GL_EXT_framebuffer_sRGB")) {
+ srgbSupport = true;
+ }
+ }
+ // All the above srgb extensions support toggling srgb writes
+ fSRGBWriteControl = srgbSupport;
+ } else {
+ srgbSupport = ctxInfo.version() >= GR_GL_VER(3,0) ||
+ ctxInfo.hasExtension("GL_EXT_sRGB");
+ // ES through 3.1 requires EXT_srgb_write_control to support toggling
+ // sRGB writing for destinations.
+ fSRGBWriteControl = ctxInfo.hasExtension("GL_EXT_sRGB_write_control");
+ }
+
// Frag Coords Convention support is not part of ES
// Known issue on at least some Intel platforms:
// http://code.google.com/p/skia/issues/detail?id=946
@@ -455,8 +477,8 @@ void GrGLCaps::init(const GrContextOptions& contextOptions,
ctxInfo.hasExtension("GL_EXT_instanced_arrays"));
}
- this->initConfigTexturableTable(ctxInfo, gli);
- this->initConfigRenderableTable(ctxInfo);
+ this->initConfigTexturableTable(ctxInfo, gli, srgbSupport);
+ this->initConfigRenderableTable(ctxInfo, srgbSupport);
this->initShaderPrecisionTable(ctxInfo, gli, glslCaps);
this->applyOptionsOverrides(contextOptions);
@@ -496,7 +518,7 @@ bool GrGLCaps::hasPathRenderingSupport(const GrGLContextInfo& ctxInfo, const GrG
return true;
}
-void GrGLCaps::initConfigRenderableTable(const GrGLContextInfo& ctxInfo) {
+void GrGLCaps::initConfigRenderableTable(const GrGLContextInfo& ctxInfo, bool srgbSupport) {
// OpenGL < 3.0
// no support for render targets unless the GL_ARB_framebuffer_object
// extension is supported (in which case we get ALPHA, RED, RG, RGB,
@@ -574,21 +596,9 @@ void GrGLCaps::initConfigRenderableTable(const GrGLContextInfo& ctxInfo) {
}
}
- if (this->fRGBA8RenderbufferSupport && this->isConfigTexturable(kSRGBA_8888_GrPixelConfig)) {
- if (kGL_GrGLStandard == standard) {
- if (ctxInfo.version() >= GR_GL_VER(3,0) ||
- ctxInfo.hasExtension("GL_ARB_framebuffer_sRGB") ||
- ctxInfo.hasExtension("GL_EXT_framebuffer_sRGB")) {
- fConfigRenderSupport[kSRGBA_8888_GrPixelConfig][kNo_MSAA] = true;
- fConfigRenderSupport[kSRGBA_8888_GrPixelConfig][kYes_MSAA] = true;
- }
- } else {
- if (ctxInfo.version() >= GR_GL_VER(3,0) ||
- ctxInfo.hasExtension("GL_EXT_sRGB")) {
- fConfigRenderSupport[kSRGBA_8888_GrPixelConfig][kNo_MSAA] = true;
- fConfigRenderSupport[kSRGBA_8888_GrPixelConfig][kYes_MSAA] = true;
- }
- }
+ if (this->fRGBA8RenderbufferSupport && srgbSupport) {
+ fConfigRenderSupport[kSRGBA_8888_GrPixelConfig][kNo_MSAA] = true;
+ fConfigRenderSupport[kSRGBA_8888_GrPixelConfig][kYes_MSAA] = true;
}
if (this->isConfigTexturable(kRGBA_float_GrPixelConfig)) {
@@ -658,7 +668,8 @@ void GrGLCaps::initConfigRenderableTable(const GrGLContextInfo& ctxInfo) {
}
}
-void GrGLCaps::initConfigTexturableTable(const GrGLContextInfo& ctxInfo, const GrGLInterface* gli) {
+void GrGLCaps::initConfigTexturableTable(const GrGLContextInfo& ctxInfo, const GrGLInterface* gli,
+ bool srgbSupport) {
GrGLStandard standard = ctxInfo.standard();
GrGLVersion version = ctxInfo.version();
@@ -697,14 +708,7 @@ void GrGLCaps::initConfigTexturableTable(const GrGLContextInfo& ctxInfo, const G
kSkia8888_GrPixelConfig != kBGRA_8888_GrPixelConfig);
}
- // Check for sRGBA
- if (kGL_GrGLStandard == standard) {
- fConfigTextureSupport[kSRGBA_8888_GrPixelConfig] =
- (version >= GR_GL_VER(3,0) || ctxInfo.hasExtension("GL_EXT_texture_sRGB"));
- } else {
- fConfigTextureSupport[kSRGBA_8888_GrPixelConfig] =
- (version >= GR_GL_VER(3,0) || ctxInfo.hasExtension("GL_EXT_sRGB"));
- }
+ fConfigTextureSupport[kSRGBA_8888_GrPixelConfig] = srgbSupport;
// Compressed texture support
@@ -1118,6 +1122,7 @@ SkString GrGLCaps::dump() const {
r.appendf("Use non-VBO for dynamic data: %s\n",
(fUseNonVBOVertexAndIndexDynamicData ? "YES" : "NO"));
r.appendf("Full screen clear is free: %s\n", (fFullClearIsFree ? "YES" : "NO"));
+ r.appendf("SRGB write contol: %s\n", (fSRGBWriteControl ? "YES" : "NO"));
return r;
}
diff --git a/src/gpu/gl/GrGLCaps.h b/src/gpu/gl/GrGLCaps.h
index ac90aa1db6..0622e68edc 100644
--- a/src/gpu/gl/GrGLCaps.h
+++ b/src/gpu/gl/GrGLCaps.h
@@ -26,8 +26,6 @@ class GrGLSLCaps;
*/
class GrGLCaps : public GrCaps {
public:
-
-
typedef GrGLStencilAttachment::Format StencilFormat;
/**
@@ -254,12 +252,18 @@ public:
bool isCoreProfile() const { return fIsCoreProfile; }
-
bool fullClearIsFree() const { return fFullClearIsFree; }
bool bindFragDataLocationSupport() const { return fBindFragDataLocationSupport; }
/**
+ * Is there support for enabling/disabling sRGB writes for sRGB-capable color attachments?
+ * If false this does not mean sRGB is not supported but rather that if it is supported
+ * it cannot be turned off for configs that support it.
+ */
+ bool srgbWriteControl() const { return fSRGBWriteControl; }
+
+ /**
* Returns a string containing the caps info.
*/
SkString dump() const override;
@@ -324,8 +328,8 @@ private:
void initBlendEqationSupport(const GrGLContextInfo&);
void initStencilFormats(const GrGLContextInfo&);
// This must be called after initFSAASupport().
- void initConfigRenderableTable(const GrGLContextInfo&);
- void initConfigTexturableTable(const GrGLContextInfo&, const GrGLInterface*);
+ void initConfigRenderableTable(const GrGLContextInfo&, bool srgbSupport);
+ void initConfigTexturableTable(const GrGLContextInfo&, const GrGLInterface*, bool srgbSupport);
bool doReadPixelsSupported(const GrGLInterface* intf, GrGLenum format, GrGLenum type) const;
@@ -375,6 +379,7 @@ private:
bool fIsCoreProfile : 1;
bool fFullClearIsFree : 1;
bool fBindFragDataLocationSupport : 1;
+ bool fSRGBWriteControl : 1;
struct ReadPixelsSupportedFormat {
GrGLenum fFormat;
diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp
index 74f7e0bc10..3eee2f6dfc 100644
--- a/src/gpu/gl/GrGLGpu.cpp
+++ b/src/gpu/gl/GrGLGpu.cpp
@@ -355,6 +355,7 @@ void GrGLGpu::onResetContext(uint32_t resetBits) {
if (resetBits & kRenderTarget_GrGLBackendState) {
fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID;
+ fHWSRGBFramebuffer = kUnknown_TriState;
}
if (resetBits & kPathRendering_GrGLBackendState) {
@@ -519,6 +520,10 @@ bool GrGLGpu::onGetWritePixelsInfo(GrSurface* dstSurface, int width, int height,
ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
}
+ if (GrPixelConfigIsSRGB(dstSurface->config()) != GrPixelConfigIsSRGB(srcConfig)) {
+ ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
+ }
+
tempDrawInfo->fSwapRAndB = false;
// These settings we will always want if a temp draw is performed. Initially set the config
@@ -566,11 +571,17 @@ bool GrGLGpu::onWritePixels(GrSurface* surface,
if (NULL == buffer) {
return false;
}
+
GrGLTexture* glTex = static_cast<GrGLTexture*>(surface->asTexture());
if (!glTex) {
return false;
}
+ // OpenGL doesn't do sRGB <-> linear conversions when reading and writing pixels.
+ if (GrPixelConfigIsSRGB(surface->config()) != GrPixelConfigIsSRGB(config)) {
+ return false;
+ }
+
this->setScratchTextureUnit();
GL_CALL(BindTexture(GR_GL_TEXTURE_2D, glTex->textureID()));
@@ -1737,6 +1748,10 @@ bool GrGLGpu::onGetReadPixelsInfo(GrSurface* srcSurface, int width, int height,
ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
}
+ if (GrPixelConfigIsSRGB(srcSurface->config()) != GrPixelConfigIsSRGB(readConfig)) {
+ ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
+ }
+
tempDrawInfo->fSwapRAndB = false;
// These settings we will always want if a temp draw is performed. The config is set below
@@ -1797,6 +1812,11 @@ bool GrGLGpu::onReadPixels(GrSurface* surface,
return false;
}
+ // OpenGL doesn't do sRGB <-> linear conversions when reading and writing pixels.
+ if (GrPixelConfigIsSRGB(surface->config()) != GrPixelConfigIsSRGB(config)) {
+ return false;
+ }
+
GrGLenum format = 0;
GrGLenum type = 0;
bool flipY = kBottomLeft_GrSurfaceOrigin == surface->origin();
@@ -1804,6 +1824,12 @@ bool GrGLGpu::onReadPixels(GrSurface* surface,
return false;
}
+ // glReadPixels does not allow GL_SRGB_ALPHA. Instead use GL_RGBA. This will not trigger a
+ // conversion when the src is srgb.
+ if (GR_GL_SRGB_ALPHA == format) {
+ format = GR_GL_RGBA;
+ }
+
// resolve the render target if necessary
switch (tgt->getResolveType()) {
case GrGLRenderTarget::kCantResolve_ResolveType:
@@ -1931,6 +1957,16 @@ void GrGLGpu::flushRenderTarget(GrGLRenderTarget* target, const SkIRect* bound)
vp.pushToGLViewport(this->glInterface());
fHWViewport = vp;
}
+ if (this->glCaps().srgbWriteControl()) {
+ bool enableSRGBWrite = GrPixelConfigIsSRGB(target->config());
+ if (enableSRGBWrite && kYes_TriState != fHWSRGBFramebuffer) {
+ GL_CALL(Enable(GR_GL_FRAMEBUFFER_SRGB));
+ fHWSRGBFramebuffer = kYes_TriState;
+ } else if (!enableSRGBWrite && kNo_TriState != fHWSRGBFramebuffer) {
+ GL_CALL(Disable(GR_GL_FRAMEBUFFER_SRGB));
+ fHWSRGBFramebuffer = kNo_TriState;
+ }
+ }
}
if (NULL == bound || !bound->isEmpty()) {
target->flagAsNeedingResolve(bound);
@@ -2437,19 +2473,24 @@ bool GrGLGpu::configToGLFormats(GrPixelConfig config,
*externalType = GR_GL_UNSIGNED_BYTE;
break;
case kSRGBA_8888_GrPixelConfig:
- *internalFormat = GR_GL_SRGB_ALPHA;
- *externalFormat = GR_GL_SRGB_ALPHA;
- if (getSizedInternalFormat || kGL_GrGLStandard == this->glStandard()) {
- // desktop or ES 3.0
- SkASSERT(this->glVersion() >= GR_GL_VER(3, 0));
+ if (getSizedInternalFormat) {
*internalFormat = GR_GL_SRGB8_ALPHA8;
- *externalFormat = GR_GL_RGBA;
} else {
- // ES 2.0 with EXT_sRGB
- SkASSERT(kGL_GrGLStandard != this->glStandard() &&
- this->glVersion() < GR_GL_VER(3, 0));
*internalFormat = GR_GL_SRGB_ALPHA;
+ }
+ // OpenGL ES 2.0 + GL_EXT_sRGB allows GL_SRGB_ALPHA to be specified as the <format>
+ // param to Tex(Sub)Image2D. ES 2.0 requires the internalFormat and format to match.
+ // Thus, on ES 2.0 we will use GL_SRGB_ALPHA as the externalFormat. However,
+ // onReadPixels needs code to override that because GL_SRGB_ALPHA is not allowed as a
+ // glReadPixels format.
+ // On OpenGL and ES 3.0 GL_SRGB_ALPHA does not work for the <format> param to
+ // glReadPixels nor does it work with Tex(Sub)Image2D So we always set the externalFormat
+ // return to GL_RGBA.
+ if (this->glStandard() == kGLES_GrGLStandard &&
+ this->glVersion() == GR_GL_VER(2,0)) {
*externalFormat = GR_GL_SRGB_ALPHA;
+ } else {
+ *externalFormat = GR_GL_RGBA;
}
*externalType = GR_GL_UNSIGNED_BYTE;
break;
diff --git a/src/gpu/gl/GrGLGpu.h b/src/gpu/gl/GrGLGpu.h
index 5724107223..eb9795ca16 100644
--- a/src/gpu/gl/GrGLGpu.h
+++ b/src/gpu/gl/GrGLGpu.h
@@ -489,6 +489,7 @@ private:
TriState fHWWriteToColor;
TriState fHWDitherEnabled;
uint32_t fHWBoundRenderTargetUniqueID;
+ TriState fHWSRGBFramebuffer;
SkTArray<uint32_t, true> fHWBoundTextureUniqueIDs;
///@}
diff --git a/tests/SRGBReadWritePixelsTest.cpp b/tests/SRGBReadWritePixelsTest.cpp
new file mode 100644
index 0000000000..f0e747a400
--- /dev/null
+++ b/tests/SRGBReadWritePixelsTest.cpp
@@ -0,0 +1,235 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "Test.h"
+#if SK_SUPPORT_GPU
+#include "SkCanvas.h"
+
+#include "SkSurface.h"
+#include "GrContextFactory.h"
+#include "GrCaps.h"
+
+// 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));
+ float lower = SkTMax(0.f, (float) inputComponent - error);
+ float upper = SkTMin(255.f, (float) inputComponent + error);
+ 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));
+ float lower = SkTMax(0.f, (float) inputComponent - error);
+ float upper = SkTMin(255.f, (float) inputComponent + error);
+ 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);
+ lower = SkTMax(0.f, (float) lowerComponent - error);
+ upper = SkTMin(255.f, (float) upperComponent + error);
+ 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);
+}
+
+typedef bool (*CheckFn) (uint32_t orig, uint32_t actual, float error);
+
+void read_and_check_pixels(skiatest::Reporter* reporter, GrTexture* texture, uint32_t* origData,
+ GrPixelConfig readConfig, CheckFn checker, float error,
+ const char* subtestName) {
+ int w = texture->width();
+ int h = texture->height();
+ SkAutoTMalloc<uint32_t> readData(w * h);
+ memset(readData.get(), 0, sizeof(uint32_t) * w * h);
+ if (!texture->readPixels(0, 0, w, h, readConfig, readData.get())) {
+ ERRORF(reporter, "Could not read pixels for %s.", subtestName);
+ return;
+ }
+ 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)) {
+ ERRORF(reporter, "Expected 0x%08x, read back as 0x%08x in %s at %d, %d).",
+ orig, read, subtestName, i, j);
+ return;
+ }
+ }
+ }
+}
+
+// TODO: Add tests for copySurface between srgb/linear textures. Add tests for unpremul/premul
+// conversion during read/write along with srgb/linear conversions.
+DEF_GPUTEST(SRGBReadWritePixels, reporter, factory) {
+ static const int kW = 255;
+ static const int kH = 255;
+ uint32_t origData[kW * kH];
+ for (int j = 0; j < kH; ++j) {
+ for (int i = 0; i < kW; ++i) {
+ origData[j * kW + i] = (j << 24) | (i << 16) | (i << 8) | i;
+ }
+ }
+
+ for (int t = 0; t < GrContextFactory::kGLContextTypeCnt; ++t) {
+ GrContextFactory::GLContextType glType = (GrContextFactory::GLContextType) t;
+ GrContext* context;
+ // We allow more error on GPUs with lower precision shader variables.
+ if (!GrContextFactory::IsRenderingGLContext(glType) || !(context = factory->get(glType))) {
+ continue;
+ }
+
+ GrSurfaceDesc desc;
+ desc.fFlags = kRenderTarget_GrSurfaceFlag;
+ desc.fWidth = kW;
+ desc.fHeight = kH;
+ desc.fConfig = kSRGBA_8888_GrPixelConfig;
+ if (context->caps()->isConfigRenderable(desc.fConfig, false) &&
+ context->caps()->isConfigTexturable(desc.fConfig)) {
+ SkAutoTUnref<GrTexture> tex(context->textureProvider()->createTexture(desc, false));
+ if (!tex) {
+ ERRORF(reporter, "Could not create SRGBA texture.");
+ continue;
+ }
+
+ float error = context->caps()->shaderCaps()->floatPrecisionVaries() ? 1.2f : 0.5f;
+
+ // Write srgba data and read as srgba and then as rgba
+ if (tex->writePixels(0, 0, kW, kH, kSRGBA_8888_GrPixelConfig, origData)) {
+ // For the all-srgba case, we allow a small error only for devices that have
+ // precision variation because the srgba data gets converted to linear and back in
+ // the shader.
+ float smallError = context->caps()->shaderCaps()->floatPrecisionVaries() ? 1.f :
+ 0.0f;
+ read_and_check_pixels(reporter, tex, origData, kSRGBA_8888_GrPixelConfig,
+ check_srgb_to_linear_to_srgb_conversion, smallError,
+ "write/read srgba to srgba texture");
+ read_and_check_pixels(reporter, tex, origData, kRGBA_8888_GrPixelConfig,
+ check_srgb_to_linear_conversion, error,
+ "write srgba/read rgba with srgba texture");
+ } else {
+ ERRORF(reporter, "Could not write srgba data to srgba texture.");
+ }
+
+ // Now verify that we can write linear data
+ if (tex->writePixels(0, 0, kW, kH, kRGBA_8888_GrPixelConfig, origData)) {
+ // We allow more error on GPUs with lower precision shader variables.
+ read_and_check_pixels(reporter, tex, origData, kSRGBA_8888_GrPixelConfig,
+ check_linear_to_srgb_conversion, error,
+ "write rgba/read srgba with srgba texture");
+ read_and_check_pixels(reporter, tex, origData, kRGBA_8888_GrPixelConfig,
+ check_linear_to_srgb_to_linear_conversion, error,
+ "write/read rgba with srgba texture");
+ } else {
+ ERRORF(reporter, "Could not write rgba data to srgba texture.");
+ }
+
+ desc.fConfig = kRGBA_8888_GrPixelConfig;
+ tex.reset(context->textureProvider()->createTexture(desc, false));
+ if (!tex) {
+ ERRORF(reporter, "Could not create RGBA texture.");
+ continue;
+ }
+
+ // Write srgba data to a rgba texture and read back as srgba and rgba
+ if (tex->writePixels(0, 0, kW, kH, kSRGBA_8888_GrPixelConfig, origData)) {
+ read_and_check_pixels(reporter, tex, origData, kSRGBA_8888_GrPixelConfig,
+ check_srgb_to_linear_to_srgb_conversion, error,
+ "write/read srgba to rgba texture");
+ read_and_check_pixels(reporter, tex, origData, kRGBA_8888_GrPixelConfig,
+ check_srgb_to_linear_conversion, error,
+ "write srgba/read rgba to rgba texture");
+ } else {
+ ERRORF(reporter, "Could not write srgba data to rgba texture.");
+ }
+
+ // Write rgba data to a rgba texture and read back as srgba
+ if (tex->writePixels(0, 0, kW, kH, kRGBA_8888_GrPixelConfig, origData)) {
+ read_and_check_pixels(reporter, tex, origData, kSRGBA_8888_GrPixelConfig,
+ check_linear_to_srgb_conversion, 1.2f,
+ "write rgba/read srgba to rgba texture");
+ } else {
+ ERRORF(reporter, "Could not write rgba data to rgba texture.");
+ }
+}
+ }
+}
+#endif