Implement sRGB conversion in the blitter.
Note that glReadPixels() does not perform sRGB conversion.
Change-Id: I3f9089b79652ce42cb5695d5b6a8ce92d15c27a8
Reviewed-on: https://swiftshader-review.googlesource.com/14492
Tested-by: Nicolas Capens <nicolascapens@google.com>
Reviewed-by: Alexis Hétu <sugoi@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/src/OpenGL/libGLESv2/Context.cpp b/src/OpenGL/libGLESv2/Context.cpp
index 05b7eaa..5862d2d 100644
--- a/src/OpenGL/libGLESv2/Context.cpp
+++ b/src/OpenGL/libGLESv2/Context.cpp
@@ -3341,7 +3341,7 @@
sw::Surface *externalSurface = sw::Surface::create(width, height, 1, egl::ConvertFormatType(format, type), pixels, outputPitch, outputPitch * outputHeight);
sw::SliceRectF sliceRect(rect);
sw::SliceRect dstSliceRect(dstRect);
- device->blit(renderTarget, sliceRect, externalSurface, dstSliceRect, false);
+ device->blit(renderTarget, sliceRect, externalSurface, dstSliceRect, false, false, false);
delete externalSurface;
renderTarget->release();
diff --git a/src/Renderer/Blitter.cpp b/src/Renderer/Blitter.cpp
index dffc10f..81cac44 100644
--- a/src/Renderer/Blitter.cpp
+++ b/src/Renderer/Blitter.cpp
@@ -14,6 +14,7 @@
#include "Blitter.hpp"
+#include "Shader/ShaderCore.hpp"
#include "Reactor/Reactor.hpp"
#include "Common/Memory.hpp"
#include "Common/Debug.hpp"
@@ -1101,7 +1102,25 @@
return false;
}
- if(unscale != scale)
+ bool srcSRGB = Surface::isSRGBformat(state.sourceFormat);
+ bool dstSRGB = Surface::isSRGBformat(state.destFormat);
+
+ if(state.convertSRGB && (srcSRGB ^ dstSRGB)) // One of the formats is sRGB encoded.
+ {
+ value = value * Float4(1.0f / unscale.x, 1.0f / unscale.y, 1.0f / unscale.z, 1.0f / unscale.w);
+
+ if(srcSRGB)
+ {
+ value = sRGBtoLinear(value);
+ }
+ else // dstSRGB
+ {
+ value = LinearToSRGB(value);
+ }
+
+ value = value * Float4(scale.x, scale.y, scale.z, scale.w);
+ }
+ else if(unscale != scale)
{
value *= Float4(scale.x / unscale.x, scale.y / unscale.y, scale.z / unscale.z, scale.w / unscale.w);
}
@@ -1133,6 +1152,30 @@
}
}
+ Float4 Blitter::LinearToSRGB(Float4 &c)
+ {
+ Float4 lc = Min(c, Float4(0.0031308f)) * Float4(12.92f);
+ Float4 ec = Float4(1.055f) * power(c, Float4(1.0f / 2.4f)) - Float4(0.055f);
+
+ Float4 s = c;
+ s.xyz = Max(lc, ec);
+
+ return s;
+ }
+
+ Float4 Blitter::sRGBtoLinear(Float4 &c)
+ {
+ Float4 lc = c * Float4(1.0f / 12.92f);
+ Float4 ec = power((c + Float4(0.055f)) * Float4(1.0f / 1.055f), Float4(2.4f));
+
+ Int4 linear = CmpLT(c, Float4(0.04045f));
+
+ Float4 s = c;
+ s.xyz = As<Float4>((linear & As<Int4>(lc)) | (~linear & As<Int4>(ec))); // FIXME: IfThenElse()
+
+ return s;
+ }
+
Routine *Blitter::generate(const State &state)
{
Function<Void(Pointer<Byte>)> function;
diff --git a/src/Renderer/Blitter.hpp b/src/Renderer/Blitter.hpp
index 66ef1f8..a132a7e 100644
--- a/src/Renderer/Blitter.hpp
+++ b/src/Renderer/Blitter.hpp
@@ -28,10 +28,10 @@
struct Options
{
Options() {}
- Options(bool filter, bool useStencil)
- : writeMask(0xF), clearOperation(false), filter(filter), useStencil(useStencil) {}
+ Options(bool filter, bool useStencil, bool convertSRGB)
+ : writeMask(0xF), clearOperation(false), filter(filter), useStencil(useStencil), convertSRGB(convertSRGB) {}
Options(unsigned int writeMask)
- : writeMask(writeMask), clearOperation(true), filter(false), useStencil(false) {}
+ : writeMask(writeMask), clearOperation(true), filter(false), useStencil(false), convertSRGB(true) {}
union
{
@@ -49,6 +49,7 @@
bool clearOperation : 1;
bool filter : 1;
bool useStencil : 1;
+ bool convertSRGB : 1;
};
struct State : Options
@@ -106,6 +107,8 @@
static bool GetScale(float4& scale, Format format);
static bool ApplyScaleAndClamp(Float4 &value, const State &state);
static Int ComputeOffset(Int &x, Int &y, Int &pitchB, int bytes, bool quadLayout);
+ static Float4 LinearToSRGB(Float4 &color);
+ static Float4 sRGBtoLinear(Float4 &color);
bool blitReactor(Surface *source, const SliceRectF &sRect, Surface *dest, const SliceRect &dRect, const Options &options);
Routine *generate(const State &state);
diff --git a/src/Renderer/Renderer.cpp b/src/Renderer/Renderer.cpp
index ffdb547..dbde7e3 100644
--- a/src/Renderer/Renderer.cpp
+++ b/src/Renderer/Renderer.cpp
@@ -682,9 +682,9 @@
blitter->clear(value, format, dest, clearRect, rgbaMask);
}
- void Renderer::blit(Surface *source, const SliceRectF &sRect, Surface *dest, const SliceRect &dRect, bool filter, bool isStencil)
+ void Renderer::blit(Surface *source, const SliceRectF &sRect, Surface *dest, const SliceRect &dRect, bool filter, bool isStencil, bool sRGBconversion)
{
- blitter->blit(source, sRect, dest, dRect, {filter, isStencil});
+ blitter->blit(source, sRect, dest, dRect, {filter, isStencil, sRGBconversion});
}
void Renderer::blit3D(Surface *source, Surface *dest)
diff --git a/src/Renderer/Renderer.hpp b/src/Renderer/Renderer.hpp
index bf74f79..8893fb5 100644
--- a/src/Renderer/Renderer.hpp
+++ b/src/Renderer/Renderer.hpp
@@ -322,7 +322,7 @@
void draw(DrawType drawType, unsigned int indexOffset, unsigned int count, bool update = true);
void clear(void *value, Format format, Surface *dest, const Rect &rect, unsigned int rgbaMask);
- void blit(Surface *source, const SliceRectF &sRect, Surface *dest, const SliceRect &dRect, bool filter, bool isStencil = false);
+ void blit(Surface *source, const SliceRectF &sRect, Surface *dest, const SliceRect &dRect, bool filter, bool isStencil = false, bool sRGBconversion = true);
void blit3D(Surface *source, Surface *dest);
void setIndexBuffer(Resource *indexBuffer);