Require sRGB write control for sRGB support. Add flag to GrPaint to suppress linear -> sRGB conversion on write. Use that to fix YUV conversion, which directly produces sRGB data. (Technically, it produces data in whatever the color space of the JPEG might be).

BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1830303002

Review URL: https://codereview.chromium.org/1830303002
This commit is contained in:
brianosman 2016-03-25 06:01:59 -07:00 committed by Commit bot
parent 73233a7575
commit 64d094d775
12 changed files with 56 additions and 28 deletions

View File

@ -137,6 +137,13 @@ public:
/** To avoid as-yet-unnecessary complexity we don't allow any partial support of MIP Maps (e.g. /** To avoid as-yet-unnecessary complexity we don't allow any partial support of MIP Maps (e.g.
only for POT textures) */ only for POT textures) */
bool mipMapSupport() const { return fMipMapSupport; } bool mipMapSupport() const { return fMipMapSupport; }
/**
* Skia convention is that a device only has sRGB support if it supports sRGB formats for both
* textures and framebuffers. In addition:
* Decoding to linear of an sRGB texture can be disabled.
* Encoding and gamma-correct blending to an sRGB framebuffer can be disabled.
*/
bool srgbSupport() const { return fSRGBSupport; } bool srgbSupport() const { return fSRGBSupport; }
bool twoSidedStencilSupport() const { return fTwoSidedStencilSupport; } bool twoSidedStencilSupport() const { return fTwoSidedStencilSupport; }
bool stencilWrapOpsSupport() const { return fStencilWrapOpsSupport; } bool stencilWrapOpsSupport() const { return fStencilWrapOpsSupport; }

View File

@ -56,6 +56,13 @@ public:
void setAntiAlias(bool aa) { fAntiAlias = aa; } void setAntiAlias(bool aa) { fAntiAlias = aa; }
bool isAntiAlias() const { return fAntiAlias; } bool isAntiAlias() const { return fAntiAlias; }
/**
* Should shader output conversion from linear to sRGB be disabled.
* Only relevant if the destination is sRGB. Defaults to false.
*/
void setDisableOutputConversionToSRGB(bool srgb) { fDisableOutputConversionToSRGB = srgb; }
bool getDisableOutputConversionToSRGB() const { return fDisableOutputConversionToSRGB; }
const GrXPFactory* setXPFactory(const GrXPFactory* xpFactory) { const GrXPFactory* setXPFactory(const GrXPFactory* xpFactory) {
fXPFactory.reset(SkSafeRef(xpFactory)); fXPFactory.reset(SkSafeRef(xpFactory));
return xpFactory; return xpFactory;
@ -112,6 +119,7 @@ public:
GrPaint& operator=(const GrPaint& paint) { GrPaint& operator=(const GrPaint& paint) {
fAntiAlias = paint.fAntiAlias; fAntiAlias = paint.fAntiAlias;
fDisableOutputConversionToSRGB = paint.fDisableOutputConversionToSRGB;
fColor = paint.fColor; fColor = paint.fColor;
this->resetFragmentProcessors(); this->resetFragmentProcessors();
@ -154,6 +162,7 @@ private:
SkSTArray<2, const GrFragmentProcessor*, true> fCoverageFragmentProcessors; SkSTArray<2, const GrFragmentProcessor*, true> fCoverageFragmentProcessors;
bool fAntiAlias; bool fAntiAlias;
bool fDisableOutputConversionToSRGB;
GrColor fColor; GrColor fColor;
}; };

View File

@ -15,6 +15,7 @@
GrPaint::GrPaint() GrPaint::GrPaint()
: fAntiAlias(false) : fAntiAlias(false)
, fDisableOutputConversionToSRGB(false)
, fColor(GrColor_WHITE) {} , fColor(GrColor_WHITE) {}
void GrPaint::setCoverageSetOpXPFactory(SkRegion::Op regionOp, bool invertCoverage) { void GrPaint::setCoverageSetOpXPFactory(SkRegion::Op regionOp, bool invertCoverage) {

View File

@ -81,6 +81,9 @@ GrPipeline* GrPipeline::CreateAt(void* memory, const CreateArgs& args,
if (builder.snapVerticesToPixelCenters()) { if (builder.snapVerticesToPixelCenters()) {
pipeline->fFlags |= kSnapVertices_Flag; pipeline->fFlags |= kSnapVertices_Flag;
} }
if (builder.getDisableOutputConversionToSRGB()) {
pipeline->fFlags |= kDisableOutputConversionToSRGB_Flag;
}
int firstColorProcessorIdx = args.fOpts.fColorPOI.firstEffectiveProcessorIndex(); int firstColorProcessorIdx = args.fOpts.fColorPOI.firstEffectiveProcessorIndex();

View File

@ -145,6 +145,9 @@ public:
bool isHWAntialiasState() const { return SkToBool(fFlags & kHWAA_Flag); } bool isHWAntialiasState() const { return SkToBool(fFlags & kHWAA_Flag); }
bool snapVerticesToPixelCenters() const { return SkToBool(fFlags & kSnapVertices_Flag); } bool snapVerticesToPixelCenters() const { return SkToBool(fFlags & kSnapVertices_Flag); }
bool getDisableOutputConversionToSRGB() const {
return SkToBool(fFlags & kDisableOutputConversionToSRGB_Flag);
}
GrXferBarrierType xferBarrierType(const GrCaps& caps) const { GrXferBarrierType xferBarrierType(const GrCaps& caps) const {
return this->getXferProcessor().xferBarrierType(fRenderTarget.get(), caps); return this->getXferProcessor().xferBarrierType(fRenderTarget.get(), caps);
@ -184,8 +187,9 @@ private:
const GrCaps&); const GrCaps&);
enum Flags { enum Flags {
kHWAA_Flag = 0x1, kHWAA_Flag = 0x1,
kSnapVertices_Flag = 0x2, kSnapVertices_Flag = 0x2,
kDisableOutputConversionToSRGB_Flag = 0x4,
}; };
typedef GrPendingIOResource<GrRenderTarget, kWrite_GrIOType> RenderTarget; typedef GrPendingIOResource<GrRenderTarget, kWrite_GrIOType> RenderTarget;

View File

@ -44,6 +44,8 @@ GrPipelineBuilder::GrPipelineBuilder(const GrPaint& paint, GrRenderTarget* rt, c
this->setState(GrPipelineBuilder::kHWAntialias_Flag, this->setState(GrPipelineBuilder::kHWAntialias_Flag,
rt->isUnifiedMultisampled() && paint.isAntiAlias()); rt->isUnifiedMultisampled() && paint.isAntiAlias());
this->setState(GrPipelineBuilder::kDisableOutputConversionToSRGB_Flag,
paint.getDisableOutputConversionToSRGB());
} }
//////////////////////////////////////////////////////////////////////////////s //////////////////////////////////////////////////////////////////////////////s

View File

@ -283,12 +283,19 @@ public:
*/ */
kSnapVerticesToPixelCenters_Flag = 0x02, kSnapVerticesToPixelCenters_Flag = 0x02,
kLast_Flag = kSnapVerticesToPixelCenters_Flag, /**
* Suppress linear -> sRGB conversion when rendering to sRGB render targets.
*/
kDisableOutputConversionToSRGB_Flag = 0x04,
kLast_Flag = kDisableOutputConversionToSRGB_Flag,
}; };
bool isHWAntialias() const { return SkToBool(fFlags & kHWAntialias_Flag); } bool isHWAntialias() const { return SkToBool(fFlags & kHWAntialias_Flag); }
bool snapVerticesToPixelCenters() const { bool snapVerticesToPixelCenters() const {
return SkToBool(fFlags & kSnapVerticesToPixelCenters_Flag); } return SkToBool(fFlags & kSnapVerticesToPixelCenters_Flag); }
bool getDisableOutputConversionToSRGB() const {
return SkToBool(fFlags & kDisableOutputConversionToSRGB_Flag); }
/** /**
* Enable render state settings. * Enable render state settings.

View File

@ -123,6 +123,9 @@ GrTexture* GrYUVProvider::refAsTexture(GrContext* ctx, const GrSurfaceDesc& desc
SkASSERT(renderTarget); SkASSERT(renderTarget);
GrPaint paint; GrPaint paint;
// We may be decoding an sRGB image, but the result of our linear math on the YUV planes
// is already in sRGB in that case. Don't convert (which will make the image too bright).
paint.setDisableOutputConversionToSRGB(true);
SkAutoTUnref<const GrFragmentProcessor> yuvToRgbProcessor( SkAutoTUnref<const GrFragmentProcessor> yuvToRgbProcessor(
GrYUVEffect::CreateYUVToRGB(yuvTextures[0], GrYUVEffect::CreateYUVToRGB(yuvTextures[0],
yuvTextures[1], yuvTextures[1],

View File

@ -46,7 +46,6 @@ GrGLCaps::GrGLCaps(const GrContextOptions& contextOptions,
fBindFragDataLocationSupport = false; fBindFragDataLocationSupport = false;
fRectangleTextureSupport = false; fRectangleTextureSupport = false;
fTextureSwizzleSupport = false; fTextureSwizzleSupport = false;
fSRGBWriteControl = false;
fRGBA8888PixelsOpsAreSlow = false; fRGBA8888PixelsOpsAreSlow = false;
fPartialFBOReadIsSlow = false; fPartialFBOReadIsSlow = false;
fMipMapLevelAndLodControlSupport = false; fMipMapLevelAndLodControlSupport = false;
@ -1080,7 +1079,6 @@ SkString GrGLCaps::dump() const {
r.appendf("Base instance support: %s\n", (fBaseInstanceSupport ? "YES" : "NO")); r.appendf("Base instance support: %s\n", (fBaseInstanceSupport ? "YES" : "NO"));
r.appendf("Use non-VBO for dynamic data: %s\n", r.appendf("Use non-VBO for dynamic data: %s\n",
(fUseNonVBOVertexAndIndexDynamicData ? "YES" : "NO")); (fUseNonVBOVertexAndIndexDynamicData ? "YES" : "NO"));
r.appendf("SRGB write contol: %s\n", (fSRGBWriteControl ? "YES" : "NO"));
r.appendf("RGBA 8888 pixel ops are slow: %s\n", (fRGBA8888PixelsOpsAreSlow ? "YES" : "NO")); r.appendf("RGBA 8888 pixel ops are slow: %s\n", (fRGBA8888PixelsOpsAreSlow ? "YES" : "NO"));
r.appendf("Partial FBO read is slow: %s\n", (fPartialFBOReadIsSlow ? "YES" : "NO")); r.appendf("Partial FBO read is slow: %s\n", (fPartialFBOReadIsSlow ? "YES" : "NO"));
r.appendf("Bind uniform location support: %s\n", (fBindUniformLocationSupport ? "YES" : "NO")); r.appendf("Bind uniform location support: %s\n", (fBindUniformLocationSupport ? "YES" : "NO"));
@ -1434,7 +1432,8 @@ void GrGLCaps::initConfigTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
fConfigTable[kBGRA_8888_GrPixelConfig].fSwizzle = GrSwizzle::RGBA(); fConfigTable[kBGRA_8888_GrPixelConfig].fSwizzle = GrSwizzle::RGBA();
// We only enable srgb support if both textures and FBOs support srgb, // We only enable srgb support if both textures and FBOs support srgb,
// *and* we can disable sRGB decode-on-read, to support "legacy" mode. // *and* we can disable sRGB decode-on-read, to support "legacy" mode,
// *and* we can disable sRGB encode-on-write.
if (kGL_GrGLStandard == standard) { if (kGL_GrGLStandard == standard) {
if (ctxInfo.version() >= GR_GL_VER(3,0)) { if (ctxInfo.version() >= GR_GL_VER(3,0)) {
fSRGBSupport = true; fSRGBSupport = true;
@ -1445,14 +1444,13 @@ void GrGLCaps::initConfigTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
} }
} }
// All the above srgb extensions support toggling srgb writes // All the above srgb extensions support toggling srgb writes
fSRGBWriteControl = fSRGBSupport;
} else { } else {
// See https://bug.skia.org/4148 for PowerVR issue. // See https://bug.skia.org/4148 for PowerVR issue.
fSRGBSupport = kPowerVRRogue_GrGLRenderer != ctxInfo.renderer() && fSRGBSupport = kPowerVRRogue_GrGLRenderer != ctxInfo.renderer() &&
(ctxInfo.version() >= GR_GL_VER(3,0) || ctxInfo.hasExtension("GL_EXT_sRGB")); (ctxInfo.version() >= GR_GL_VER(3,0) || ctxInfo.hasExtension("GL_EXT_sRGB"));
// ES through 3.1 requires EXT_srgb_write_control to support toggling // ES through 3.1 requires EXT_srgb_write_control to support toggling
// sRGB writing for destinations. // sRGB writing for destinations.
fSRGBWriteControl = ctxInfo.hasExtension("GL_EXT_sRGB_write_control"); fSRGBSupport = fSRGBSupport && ctxInfo.hasExtension("GL_EXT_sRGB_write_control");
} }
if (!ctxInfo.hasExtension("GL_EXT_texture_sRGB_decode")) { if (!ctxInfo.hasExtension("GL_EXT_texture_sRGB_decode")) {
// To support "legacy" L32 mode, we require the ability to turn off sRGB decode: // To support "legacy" L32 mode, we require the ability to turn off sRGB decode:

View File

@ -323,13 +323,6 @@ public:
/// GL_ARB_texture_swizzle /// GL_ARB_texture_swizzle
bool textureSwizzleSupport() const { return fTextureSwizzleSupport; } bool textureSwizzleSupport() const { return fTextureSwizzleSupport; }
/**
* 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; }
bool mipMapLevelAndLodControlSupport() const { return fMipMapLevelAndLodControlSupport; } bool mipMapLevelAndLodControlSupport() const { return fMipMapLevelAndLodControlSupport; }
/** /**
@ -402,7 +395,6 @@ private:
bool fUseNonVBOVertexAndIndexDynamicData : 1; bool fUseNonVBOVertexAndIndexDynamicData : 1;
bool fIsCoreProfile : 1; bool fIsCoreProfile : 1;
bool fBindFragDataLocationSupport : 1; bool fBindFragDataLocationSupport : 1;
bool fSRGBWriteControl : 1;
bool fRGBA8888PixelsOpsAreSlow : 1; bool fRGBA8888PixelsOpsAreSlow : 1;
bool fPartialFBOReadIsSlow : 1; bool fPartialFBOReadIsSlow : 1;
bool fBindUniformLocationSupport : 1; bool fBindUniformLocationSupport : 1;

View File

@ -2114,7 +2114,7 @@ bool GrGLGpu::flushGLState(const GrPipeline& pipeline, const GrPrimitiveProcesso
// This must come after textures are flushed because a texture may need // This must come after textures are flushed because a texture may need
// to be msaa-resolved (which will modify bound FBO state). // to be msaa-resolved (which will modify bound FBO state).
this->flushRenderTarget(glRT, nullptr); this->flushRenderTarget(glRT, nullptr, pipeline.getDisableOutputConversionToSRGB());
return true; return true;
} }
@ -2833,7 +2833,7 @@ void GrGLGpu::finishDrawTarget() {
} }
} }
void GrGLGpu::flushRenderTarget(GrGLRenderTarget* target, const SkIRect* bounds) { void GrGLGpu::flushRenderTarget(GrGLRenderTarget* target, const SkIRect* bounds, bool disableSRGB) {
SkASSERT(target); SkASSERT(target);
uint32_t rtID = target->getUniqueID(); uint32_t rtID = target->getUniqueID();
@ -2855,17 +2855,19 @@ void GrGLGpu::flushRenderTarget(GrGLRenderTarget* target, const SkIRect* bounds)
#endif #endif
fHWBoundRenderTargetUniqueID = rtID; fHWBoundRenderTargetUniqueID = rtID;
this->flushViewport(target->getViewport()); this->flushViewport(target->getViewport());
if (this->glCaps().srgbWriteControl()) { }
bool enableSRGBWrite = GrPixelConfigIsSRGB(target->config());
if (enableSRGBWrite && kYes_TriState != fHWSRGBFramebuffer) { if (this->glCaps().srgbSupport()) {
GL_CALL(Enable(GR_GL_FRAMEBUFFER_SRGB)); bool enableSRGBWrite = GrPixelConfigIsSRGB(target->config()) && !disableSRGB;
fHWSRGBFramebuffer = kYes_TriState; if (enableSRGBWrite && kYes_TriState != fHWSRGBFramebuffer) {
} else if (!enableSRGBWrite && kNo_TriState != fHWSRGBFramebuffer) { GL_CALL(Enable(GR_GL_FRAMEBUFFER_SRGB));
GL_CALL(Disable(GR_GL_FRAMEBUFFER_SRGB)); fHWSRGBFramebuffer = kYes_TriState;
fHWSRGBFramebuffer = kNo_TriState; } else if (!enableSRGBWrite && kNo_TriState != fHWSRGBFramebuffer) {
} GL_CALL(Disable(GR_GL_FRAMEBUFFER_SRGB));
fHWSRGBFramebuffer = kNo_TriState;
} }
} }
this->didWriteToSurface(target, bounds); this->didWriteToSurface(target, bounds);
} }

View File

@ -328,7 +328,7 @@ private:
// bounds is region that may be modified. // bounds is region that may be modified.
// nullptr means whole target. Can be an empty rect. // nullptr means whole target. Can be an empty rect.
void flushRenderTarget(GrGLRenderTarget*, const SkIRect* bounds); void flushRenderTarget(GrGLRenderTarget*, const SkIRect* bounds, bool disableSRGB = false);
// Handles cases where a surface will be updated without a call to flushRenderTarget // Handles cases where a surface will be updated without a call to flushRenderTarget
void didWriteToSurface(GrSurface*, const SkIRect* bounds) const; void didWriteToSurface(GrSurface*, const SkIRect* bounds) const;