diff options
author | bsalomon <bsalomon@google.com> | 2015-07-30 15:34:56 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-07-30 15:34:56 -0700 |
commit | 16921ec30a81976129d507b1148c93a322e61a4f (patch) | |
tree | 5eb7ceafe1b43b2a168de7f46d4ebdde3bc1d7cc | |
parent | 381b26f03bdccac1e3d9055fb4f7855792cfefb0 (diff) |
SRGB read and write pixels working and unit test
Review URL: https://codereview.chromium.org/1264003002
-rw-r--r-- | include/gpu/GrCaps.h | 2 | ||||
-rw-r--r-- | include/gpu/GrTypes.h | 11 | ||||
-rw-r--r-- | src/gpu/gl/GrGLCaps.cpp | 59 | ||||
-rw-r--r-- | src/gpu/gl/GrGLCaps.h | 15 | ||||
-rw-r--r-- | src/gpu/gl/GrGLGpu.cpp | 59 | ||||
-rw-r--r-- | src/gpu/gl/GrGLGpu.h | 1 | ||||
-rw-r--r-- | tests/SRGBReadWritePixelsTest.cpp | 235 |
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 |