Implement sRGB texture sampling.
Previously sRGB data was converted to linear space on upload. This
caused a loss of precision. This change performs the conversion after
texel lookup. Note that we had a code path for performing the
conversion after filtering, but that leads to failures in dEQP and
unacceptable darkening between texels.
Also, glTexSubImage calls can update sRGB textures using a format/type
combination with no indication of the color space, which caused an
unintentional conversion on upload. Likewise we were missing support
for an A2B10G10R10UI implementation format.
Change-Id: Ib10845f628fb2d1849e88d7a9350868cdec32fa2
Reviewed-on: https://swiftshader-review.googlesource.com/15068
Reviewed-by: Alexis Hétu <sugoi@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
Tested-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/src/OpenGL/common/Image.cpp b/src/OpenGL/common/Image.cpp
index 9fab82e..3ed148e 100644
--- a/src/OpenGL/common/Image.cpp
+++ b/src/OpenGL/common/Image.cpp
@@ -52,8 +52,6 @@
RGB10A2UI,
R11G11B10F,
RGB9E5,
- SRGB,
- SRGBA,
D16,
D24,
D32,
@@ -298,36 +296,6 @@
}
template<>
- void LoadImageRow<SRGB>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
- {
- dest += xoffset * 4;
-
- for(int x = 0; x < width; x++)
- {
- for(int rgb = 0; rgb < 3; ++rgb)
- {
- *dest++ = sw::sRGB8toLinear8(*source++);
- }
- *dest++ = 255;
- }
- }
-
- template<>
- void LoadImageRow<SRGBA>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
- {
- dest += xoffset * 4;
-
- for(int x = 0; x < width; x++)
- {
- for(int rgb = 0; rgb < 3; ++rgb)
- {
- *dest++ = sw::sRGB8toLinear8(*source++);
- }
- *dest++ = *source++;
- }
- }
-
- template<>
void LoadImageRow<D16>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
{
const unsigned short *sourceD16 = reinterpret_cast<const unsigned short*>(source);
@@ -559,6 +527,7 @@
{
case GL_INT: return sw::FORMAT_A32B32G32R32I;
case GL_UNSIGNED_INT: return sw::FORMAT_A32B32G32R32UI;
+ case GL_UNSIGNED_INT_2_10_10_10_REV: return sw::FORMAT_A2B10G10R10UI;
default: UNREACHABLE(type);
}
break;
@@ -805,16 +774,18 @@
case GL_RGB8_SNORM:
case GL_RGB8:
case GL_RGB:
- case GL_SRGB8:
return sw::FORMAT_X8B8G8R8;
+ case GL_SRGB8:
+ return sw::FORMAT_SRGB8_X8;
case GL_RGB8UI:
case GL_RGB_INTEGER:
return sw::FORMAT_X8B8G8R8UI;
case GL_RGBA8_SNORM:
case GL_RGBA8:
case GL_RGBA:
- case GL_SRGB8_ALPHA8:
return sw::FORMAT_A8B8G8R8;
+ case GL_SRGB8_ALPHA8:
+ return sw::FORMAT_SRGB8_A8;
case GL_RGBA8UI:
case GL_RGBA_INTEGER:
return sw::FORMAT_A8B8G8R8UI;
@@ -934,7 +905,7 @@
case GL_UNSIGNED_INT_2_10_10_10_REV:
if(format == GL_RGB10_A2UI)
{
- return sw::FORMAT_A16B16G16R16UI;
+ return sw::FORMAT_A2B10G10R10UI;
}
else
{
@@ -1338,8 +1309,8 @@
void Image::loadImageData(Context *context, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const UnpackInfo& unpackInfo, const void *input)
{
- sw::Format selectedInternalFormat = SelectInternalFormat(format, type);
- if(selectedInternalFormat == sw::FORMAT_NULL)
+ sw::Format uploadFormat = SelectInternalFormat(format, type);
+ if(uploadFormat == sw::FORMAT_NULL)
{
return;
}
@@ -1349,7 +1320,10 @@
GLsizei inputHeight = (unpackInfo.imageHeight == 0) ? height : unpackInfo.imageHeight;
input = ((char*)input) + ComputePackingOffset(format, type, inputWidth, inputHeight, unpackInfo.alignment, unpackInfo.skipImages, unpackInfo.skipRows, unpackInfo.skipPixels);
- if(selectedInternalFormat == internalFormat)
+ if(uploadFormat == internalFormat ||
+ (uploadFormat == sw::FORMAT_A8B8G8R8 && internalFormat == sw::FORMAT_SRGB8_A8) ||
+ (uploadFormat == sw::FORMAT_X8B8G8R8 && internalFormat == sw::FORMAT_SRGB8_X8) ||
+ (uploadFormat == sw::FORMAT_A2B10G10R10 && internalFormat == sw::FORMAT_A2B10G10R10UI))
{
void *buffer = lock(0, 0, sw::LOCK_WRITEONLY);
@@ -1427,6 +1401,7 @@
case GL_RGB8_SNORM:
case GL_RGB:
case GL_RGB_INTEGER:
+ case GL_SRGB8:
LoadImageData<UByteRGB>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getSlice(), input, buffer);
break;
case GL_RGBA8:
@@ -1436,13 +1411,8 @@
case GL_RGBA_INTEGER:
case GL_BGRA_EXT:
case GL_BGRA8_EXT:
- LoadImageData<Bytes_4>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getSlice(), input, buffer);
- break;
- case GL_SRGB8:
- LoadImageData<SRGB>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getSlice(), input, buffer);
- break;
case GL_SRGB8_ALPHA8:
- LoadImageData<SRGBA>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getSlice(), input, buffer);
+ LoadImageData<Bytes_4>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getSlice(), input, buffer);
break;
default: UNREACHABLE(format);
}
@@ -1501,8 +1471,6 @@
switch(format)
{
case GL_RGB10_A2UI:
- LoadImageData<RGB10A2UI>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getSlice(), input, buffer);
- break;
case GL_RGB10_A2:
case GL_RGBA:
case GL_RGBA_INTEGER:
diff --git a/src/OpenGL/libGLESv2/libGLESv2.cpp b/src/OpenGL/libGLESv2/libGLESv2.cpp
index 93a59a6..b834e00 100644
--- a/src/OpenGL/libGLESv2/libGLESv2.cpp
+++ b/src/OpenGL/libGLESv2/libGLESv2.cpp
@@ -5062,7 +5062,7 @@
GLenum sizedInternalFormat = GetSizedInternalFormat(internalformat, type);
- validationError = context->getPixels(&data, type, context->getRequiredBufferSize(width, height, 1, sizedInternalFormat, type));
+ validationError = context->getPixels(&data, type, context->getRequiredBufferSize(width, height, 1, format, type));
if(validationError != GL_NONE)
{
return error(validationError);
@@ -5423,8 +5423,6 @@
if(context)
{
- GLenum sizedInternalFormat = GetSizedInternalFormat(format, type);
-
if(target == GL_TEXTURE_2D)
{
es2::Texture2D *texture = context->getTexture2D();
@@ -5435,13 +5433,13 @@
return error(validationError);
}
- validationError = context->getPixels(&data, type, context->getRequiredBufferSize(width, height, 1, sizedInternalFormat, type));
+ validationError = context->getPixels(&data, type, context->getRequiredBufferSize(width, height, 1, format, type));
if(validationError != GL_NONE)
{
return error(validationError);
}
- texture->subImage(context, level, xoffset, yoffset, width, height, sizedInternalFormat, type, context->getUnpackInfo(), data);
+ texture->subImage(context, level, xoffset, yoffset, width, height, format, type, context->getUnpackInfo(), data);
}
else if(es2::IsCubemapTextureTarget(target))
{
@@ -5453,13 +5451,13 @@
return error(validationError);
}
- validationError = context->getPixels(&data, type, context->getRequiredBufferSize(width, height, 1, sizedInternalFormat, type));
+ validationError = context->getPixels(&data, type, context->getRequiredBufferSize(width, height, 1, format, type));
if(validationError != GL_NONE)
{
return error(validationError);
}
- texture->subImage(context, target, level, xoffset, yoffset, width, height, sizedInternalFormat, type, context->getUnpackInfo(), data);
+ texture->subImage(context, target, level, xoffset, yoffset, width, height, format, type, context->getUnpackInfo(), data);
}
else UNREACHABLE(target);
}
@@ -6342,21 +6340,19 @@
{
es2::Texture3D *texture = context->getTexture3D();
- GLenum sizedInternalFormat = GetSizedInternalFormat(format, type);
-
GLenum validationError = ValidateSubImageParams(false, false, target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, texture, context->getClientVersion());
if(validationError != GL_NONE)
{
return error(validationError);
}
- validationError = context->getPixels(&data, type, context->getRequiredBufferSize(width, height, depth, sizedInternalFormat, type));
+ validationError = context->getPixels(&data, type, context->getRequiredBufferSize(width, height, depth, format, type));
if(validationError != GL_NONE)
{
return error(validationError);
}
- texture->subImage(context, level, xoffset, yoffset, zoffset, width, height, depth, sizedInternalFormat, type, context->getUnpackInfo(), data);
+ texture->subImage(context, level, xoffset, yoffset, zoffset, width, height, depth, format, type, context->getUnpackInfo(), data);
}
}
diff --git a/src/OpenGL/libGLESv2/utilities.cpp b/src/OpenGL/libGLESv2/utilities.cpp
index e4f54ed..e068b6a 100644
--- a/src/OpenGL/libGLESv2/utilities.cpp
+++ b/src/OpenGL/libGLESv2/utilities.cpp
@@ -2193,7 +2193,6 @@
case GL_R16UI: return sw::FORMAT_R16UI;
case GL_RG16UI: return sw::FORMAT_G16R16UI;
case GL_RGB16UI: return sw::FORMAT_X16B16G16R16UI;
- case GL_RGB10_A2UI:
case GL_RGBA16UI: return sw::FORMAT_A16B16G16R16UI;
case GL_R32I: return sw::FORMAT_R32I;
case GL_RG32I: return sw::FORMAT_G32R32I;
@@ -2213,6 +2212,7 @@
case GL_RGB32F: return sw::FORMAT_B32G32R32F;
case GL_RGBA32F: return sw::FORMAT_A32B32G32R32F;
case GL_RGB10_A2: return sw::FORMAT_A2B10G10R10;
+ case GL_RGB10_A2UI: return sw::FORMAT_A2B10G10R10UI;
case GL_SRGB8: return sw::FORMAT_SRGB8_X8;
case GL_SRGB8_ALPHA8: return sw::FORMAT_SRGB8_A8;
default: UNREACHABLE(format); return sw::FORMAT_NULL;
diff --git a/src/Renderer/Blitter.cpp b/src/Renderer/Blitter.cpp
index f0de2f2..e41b937 100644
--- a/src/Renderer/Blitter.cpp
+++ b/src/Renderer/Blitter.cpp
@@ -393,6 +393,7 @@
c.z = Float(Int(*Pointer<UShort>(element) & UShort(0x001F)));
break;
case FORMAT_A2B10G10R10:
+ case FORMAT_A2B10G10R10UI:
c.x = Float(Int((*Pointer<UInt>(element) & UInt(0x000003FF))));
c.y = Float(Int((*Pointer<UInt>(element) & UInt(0x000FFC00)) >> 10));
c.z = Float(Int((*Pointer<UInt>(element) & UInt(0x3FF00000)) >> 20));
@@ -741,6 +742,7 @@
}
break;
case FORMAT_A2B10G10R10:
+ case FORMAT_A2B10G10R10UI:
if(writeRGBA)
{
*Pointer<UInt>(element) = UInt(RoundInt(Float(c.x)) |
@@ -1047,6 +1049,7 @@
case FORMAT_B32G32R32F:
case FORMAT_G32R32F:
case FORMAT_R32F:
+ case FORMAT_A2B10G10R10UI:
scale = vector(1.0f, 1.0f, 1.0f, 1.0f);
break;
case FORMAT_R5G6B5:
diff --git a/src/Renderer/Sampler.cpp b/src/Renderer/Sampler.cpp
index 5862996..85448b9 100644
--- a/src/Renderer/Sampler.cpp
+++ b/src/Renderer/Sampler.cpp
@@ -96,7 +96,7 @@
state.addressingModeV = getAddressingModeV();
state.addressingModeW = getAddressingModeW();
state.mipmapFilter = mipmapFilter();
- state.sRGB = sRGB && Surface::isSRGBreadable(externalTextureFormat);
+ state.sRGB = (sRGB && Surface::isSRGBreadable(externalTextureFormat)) || Surface::isSRGBformat(internalTextureFormat);
state.swizzleR = swizzleR;
state.swizzleG = swizzleG;
state.swizzleB = swizzleB;
diff --git a/src/Renderer/Surface.cpp b/src/Renderer/Surface.cpp
index e732fb8..899e7e1 100644
--- a/src/Renderer/Surface.cpp
+++ b/src/Renderer/Surface.cpp
@@ -169,6 +169,7 @@
*(unsigned int*)element = (unorm<2>(color.a) << 30) | (unorm<10>(color.r) << 20) | (unorm<10>(color.g) << 10) | (unorm<10>(color.b) << 0);
break;
case FORMAT_A2B10G10R10:
+ case FORMAT_A2B10G10R10UI:
*(unsigned int*)element = (unorm<2>(color.a) << 30) | (unorm<10>(color.b) << 20) | (unorm<10>(color.g) << 10) | (unorm<10>(color.r) << 0);
break;
case FORMAT_G8R8I_SNORM:
@@ -701,6 +702,16 @@
r = (abgr & 0x000003FF) * (1.0f / 0x000003FF);
}
break;
+ case FORMAT_A2B10G10R10UI:
+ {
+ unsigned int abgr = *(unsigned int*)element;
+
+ a = static_cast<float>((abgr & 0xC0000000) >> 30);
+ b = static_cast<float>((abgr & 0x3FF00000) >> 20);
+ g = static_cast<float>((abgr & 0x000FFC00) >> 10);
+ r = static_cast<float>(abgr & 0x000003FF);
+ }
+ break;
case FORMAT_A16B16G16R16I:
{
short* abgr = (short*)element;
@@ -1544,6 +1555,7 @@
case FORMAT_A8B8G8R8I_SNORM: return 4;
case FORMAT_A2R10G10B10: return 4;
case FORMAT_A2B10G10R10: return 4;
+ case FORMAT_A2B10G10R10UI: return 4;
case FORMAT_G8R8I: return 2;
case FORMAT_G8R8: return 2;
case FORMAT_G16R16I: return 4;
@@ -2824,6 +2836,7 @@
case FORMAT_G8R8I:
case FORMAT_G8R8:
case FORMAT_A2B10G10R10:
+ case FORMAT_A2B10G10R10UI:
case FORMAT_R8I_SNORM:
case FORMAT_G8R8I_SNORM:
case FORMAT_X8B8G8R8I_SNORM:
@@ -2908,6 +2921,7 @@
case FORMAT_SRGB8_A8:
case FORMAT_G8R8:
case FORMAT_A2B10G10R10:
+ case FORMAT_A2B10G10R10UI:
case FORMAT_R16UI:
case FORMAT_G16R16:
case FORMAT_G16R16UI:
@@ -3027,6 +3041,18 @@
}
}
+ bool Surface::isSRGBformat(Format format)
+ {
+ switch(format)
+ {
+ case FORMAT_SRGB8_X8:
+ case FORMAT_SRGB8_A8:
+ return true;
+ default:
+ return false;
+ }
+ }
+
bool Surface::isCompressed(Format format)
{
switch(format)
@@ -3166,6 +3192,7 @@
case FORMAT_X8B8G8R8UI: return 3;
case FORMAT_A8B8G8R8UI: return 4;
case FORMAT_A2B10G10R10: return 4;
+ case FORMAT_A2B10G10R10UI: return 4;
case FORMAT_G16R16I: return 2;
case FORMAT_G16R16UI: return 2;
case FORMAT_G16R16: return 2;
@@ -3765,6 +3792,8 @@
case FORMAT_A2B10G10R10:
case FORMAT_A16B16G16R16:
return FORMAT_A16B16G16R16;
+ case FORMAT_A2B10G10R10UI:
+ return FORMAT_A16B16G16R16UI;
case FORMAT_X32B32G32R32I:
return FORMAT_X32B32G32R32I;
case FORMAT_A32B32G32R32I:
diff --git a/src/Renderer/Surface.hpp b/src/Renderer/Surface.hpp
index 7ea7bee..c32c14f 100644
--- a/src/Renderer/Surface.hpp
+++ b/src/Renderer/Surface.hpp
@@ -107,6 +107,7 @@
FORMAT_G32R32UI,
FORMAT_A2R10G10B10,
FORMAT_A2B10G10R10,
+ FORMAT_A2B10G10R10UI,
FORMAT_A16B16G16R16, // D3D format
FORMAT_X16B16G16R16I,
FORMAT_X16B16G16R16UI,
@@ -368,6 +369,7 @@
static bool isUnsignedComponent(Format format, int component);
static bool isSRGBreadable(Format format);
static bool isSRGBwritable(Format format);
+ static bool isSRGBformat(Format format);
static bool isCompressed(Format format);
static bool isSignedNonNormalizedInteger(Format format);
static bool isUnsignedNonNormalizedInteger(Format format);
diff --git a/src/Shader/Constants.cpp b/src/Shader/Constants.cpp
index e02ba03..06dda32 100644
--- a/src/Shader/Constants.cpp
+++ b/src/Shader/Constants.cpp
@@ -264,17 +264,17 @@
for(int i = 0; i < 256; i++)
{
- sRGBtoLinear8_12[i] = (unsigned short)(sw::sRGBtoLinear((float)i / 0xFF) * 0x1000 + 0.5f);
+ sRGBtoLinear8_16[i] = (unsigned short)(sw::sRGBtoLinear((float)i / 0xFF) * 0xFFFF + 0.5f);
}
for(int i = 0; i < 64; i++)
{
- sRGBtoLinear6_12[i] = (unsigned short)(sw::sRGBtoLinear((float)i / 0x3F) * 0x1000 + 0.5f);
+ sRGBtoLinear6_16[i] = (unsigned short)(sw::sRGBtoLinear((float)i / 0x3F) * 0xFFFF + 0.5f);
}
for(int i = 0; i < 32; i++)
{
- sRGBtoLinear5_12[i] = (unsigned short)(sw::sRGBtoLinear((float)i / 0x1F) * 0x1000 + 0.5f);
+ sRGBtoLinear5_16[i] = (unsigned short)(sw::sRGBtoLinear((float)i / 0x1F) * 0xFFFF + 0.5f);
}
for(int i = 0; i < 0x1000; i++)
diff --git a/src/Shader/Constants.hpp b/src/Shader/Constants.hpp
index 5210643..6b70e04 100644
--- a/src/Shader/Constants.hpp
+++ b/src/Shader/Constants.hpp
@@ -22,7 +22,7 @@
struct Constants
{
Constants();
-
+
unsigned int transposeBit0[16];
unsigned int transposeBit1[16];
unsigned int transposeBit2[16];
@@ -67,9 +67,9 @@
dword4 maskD01X[4];
word4 mask565Q[8];
- unsigned short sRGBtoLinear8_12[256];
- unsigned short sRGBtoLinear6_12[64];
- unsigned short sRGBtoLinear5_12[32];
+ unsigned short sRGBtoLinear8_16[256];
+ unsigned short sRGBtoLinear6_16[64];
+ unsigned short sRGBtoLinear5_16[32];
unsigned short linearToSRGB12_16[4096];
unsigned short sRGBtoLinear12_16[4096];
diff --git a/src/Shader/SamplerCore.cpp b/src/Shader/SamplerCore.cpp
index a50c1e8..8aebbd8 100644
--- a/src/Shader/SamplerCore.cpp
+++ b/src/Shader/SamplerCore.cpp
@@ -133,46 +133,23 @@
if(fixed12 && !hasFloatTexture())
{
- if(has16bitTextureFormat())
+ if(state.textureFormat == FORMAT_R5G6B5)
{
- switch(state.textureFormat)
- {
- case FORMAT_R5G6B5:
- if(state.sRGB)
- {
- sRGBtoLinear16_5_12(c.x);
- sRGBtoLinear16_6_12(c.y);
- sRGBtoLinear16_5_12(c.z);
- }
- else
- {
- c.x = MulHigh(As<UShort4>(c.x), UShort4(0x10000000 / 0xF800));
- c.y = MulHigh(As<UShort4>(c.y), UShort4(0x10000000 / 0xFC00));
- c.z = MulHigh(As<UShort4>(c.z), UShort4(0x10000000 / 0xF800));
- }
- break;
- default:
- ASSERT(false);
- }
+ c.x = MulHigh(As<UShort4>(c.x), UShort4(0x10000000 / 0xF800));
+ c.y = MulHigh(As<UShort4>(c.y), UShort4(0x10000000 / 0xFC00));
+ c.z = MulHigh(As<UShort4>(c.z), UShort4(0x10000000 / 0xF800));
}
else
{
for(int component = 0; component < textureComponentCount(); component++)
{
- if(state.sRGB && isRGBComponent(component))
+ if(hasUnsignedTextureComponent(component))
{
- sRGBtoLinear16_8_12(c[component]); // FIXME: Perform linearization at surface level for read-only textures
+ c[component] = As<UShort4>(c[component]) >> 4;
}
else
{
- if(hasUnsignedTextureComponent(component))
- {
- c[component] = As<UShort4>(c[component]) >> 4;
- }
- else
- {
- c[component] = c[component] >> 3;
- }
+ c[component] = c[component] >> 3;
}
}
}
@@ -316,8 +293,8 @@
}
else
{
- // FIXME: YUV and sRGB are not supported by the floating point path
- bool forceFloatFiltering = state.highPrecisionFiltering && !state.sRGB && !hasYuvFormat() && (state.textureFilter != FILTER_POINT);
+ // FIXME: YUV is not supported by the floating point path
+ bool forceFloatFiltering = state.highPrecisionFiltering && !hasYuvFormat() && (state.textureFilter != FILTER_POINT);
bool seamlessCube = (state.addressingModeU == ADDRESSING_SEAMLESS);
if(hasFloatTexture() || hasUnnormalizedIntegerTexture() || forceFloatFiltering || seamlessCube) // FIXME: Mostly identical to integer sampling
{
@@ -380,52 +357,23 @@
{
Vector4s cs = sampleTexture(texture, u, v, w, q, bias, dsx, dsy, offset, function, false);
- if(has16bitTextureFormat())
+ if(state.textureFormat == FORMAT_R5G6B5)
{
- switch(state.textureFormat)
- {
- case FORMAT_R5G6B5:
- if(state.sRGB)
- {
- sRGBtoLinear16_5_12(cs.x);
- sRGBtoLinear16_6_12(cs.y);
- sRGBtoLinear16_5_12(cs.z);
-
- convertSigned12(c.x, cs.x);
- convertSigned12(c.y, cs.y);
- convertSigned12(c.z, cs.z);
- }
- else
- {
- c.x = Float4(As<UShort4>(cs.x)) * Float4(1.0f / 0xF800);
- c.y = Float4(As<UShort4>(cs.y)) * Float4(1.0f / 0xFC00);
- c.z = Float4(As<UShort4>(cs.z)) * Float4(1.0f / 0xF800);
- }
- break;
- default:
- ASSERT(false);
- }
+ c.x = Float4(As<UShort4>(cs.x)) * Float4(1.0f / 0xF800);
+ c.y = Float4(As<UShort4>(cs.y)) * Float4(1.0f / 0xFC00);
+ c.z = Float4(As<UShort4>(cs.z)) * Float4(1.0f / 0xF800);
}
else
{
for(int component = 0; component < textureComponentCount(); component++)
{
- // Normalized integer formats
- if(state.sRGB && isRGBComponent(component))
+ if(hasUnsignedTextureComponent(component))
{
- sRGBtoLinear16_8_12(cs[component]); // FIXME: Perform linearization at surface level for read-only textures
- convertSigned12(c[component], cs[component]);
+ convertUnsigned16(c[component], cs[component]);
}
else
{
- if(hasUnsignedTextureComponent(component))
- {
- convertUnsigned16(c[component], cs[component]);
- }
- else
- {
- convertSigned15(c[component], cs[component]);
- }
+ convertSigned15(c[component], cs[component]);
}
}
}
@@ -2036,6 +1984,26 @@
}
else ASSERT(false);
+ if(state.sRGB)
+ {
+ if(state.textureFormat == FORMAT_R5G6B5)
+ {
+ sRGBtoLinear16_5_16(c.x);
+ sRGBtoLinear16_6_16(c.y);
+ sRGBtoLinear16_5_16(c.z);
+ }
+ else
+ {
+ for(int i = 0; i < textureComponentCount(); i++)
+ {
+ if(isRGBComponent(i))
+ {
+ sRGBtoLinear16_8_16(c[i]);
+ }
+ }
+ }
+ }
+
return c;
}
@@ -2238,7 +2206,7 @@
bool isInteger = Surface::isNonNormalizedInteger(state.textureFormat);
int componentCount = textureComponentCount();
- for(int n = 0; n < componentCount; ++n)
+ for(int n = 0; n < componentCount; n++)
{
if(hasUnsignedTextureComponent(n))
{
@@ -2555,11 +2523,11 @@
cf = Float4(As<UShort4>(cs)) * Float4(1.0f / 0xFFFF);
}
- void SamplerCore::sRGBtoLinear16_8_12(Short4 &c)
+ void SamplerCore::sRGBtoLinear16_8_16(Short4 &c)
{
c = As<UShort4>(c) >> 8;
- Pointer<Byte> LUT = Pointer<Byte>(constants + OFFSET(Constants,sRGBtoLinear8_12));
+ Pointer<Byte> LUT = Pointer<Byte>(constants + OFFSET(Constants,sRGBtoLinear8_16));
c = Insert(c, *Pointer<Short>(LUT + 2 * Int(Extract(c, 0))), 0);
c = Insert(c, *Pointer<Short>(LUT + 2 * Int(Extract(c, 1))), 1);
@@ -2567,11 +2535,11 @@
c = Insert(c, *Pointer<Short>(LUT + 2 * Int(Extract(c, 3))), 3);
}
- void SamplerCore::sRGBtoLinear16_6_12(Short4 &c)
+ void SamplerCore::sRGBtoLinear16_6_16(Short4 &c)
{
c = As<UShort4>(c) >> 10;
- Pointer<Byte> LUT = Pointer<Byte>(constants + OFFSET(Constants,sRGBtoLinear6_12));
+ Pointer<Byte> LUT = Pointer<Byte>(constants + OFFSET(Constants,sRGBtoLinear6_16));
c = Insert(c, *Pointer<Short>(LUT + 2 * Int(Extract(c, 0))), 0);
c = Insert(c, *Pointer<Short>(LUT + 2 * Int(Extract(c, 1))), 1);
@@ -2579,11 +2547,11 @@
c = Insert(c, *Pointer<Short>(LUT + 2 * Int(Extract(c, 3))), 3);
}
- void SamplerCore::sRGBtoLinear16_5_12(Short4 &c)
+ void SamplerCore::sRGBtoLinear16_5_16(Short4 &c)
{
c = As<UShort4>(c) >> 11;
- Pointer<Byte> LUT = Pointer<Byte>(constants + OFFSET(Constants,sRGBtoLinear5_12));
+ Pointer<Byte> LUT = Pointer<Byte>(constants + OFFSET(Constants,sRGBtoLinear5_16));
c = Insert(c, *Pointer<Short>(LUT + 2 * Int(Extract(c, 0))), 0);
c = Insert(c, *Pointer<Short>(LUT + 2 * Int(Extract(c, 1))), 1);
diff --git a/src/Shader/SamplerCore.hpp b/src/Shader/SamplerCore.hpp
index 6004bd7..684c1a7 100644
--- a/src/Shader/SamplerCore.hpp
+++ b/src/Shader/SamplerCore.hpp
@@ -92,9 +92,9 @@
void convertSigned12(Float4 &cf, Short4 &ci);
void convertSigned15(Float4 &cf, Short4 &ci);
void convertUnsigned16(Float4 &cf, Short4 &ci);
- void sRGBtoLinear16_8_12(Short4 &c);
- void sRGBtoLinear16_6_12(Short4 &c);
- void sRGBtoLinear16_5_12(Short4 &c);
+ void sRGBtoLinear16_8_16(Short4 &c);
+ void sRGBtoLinear16_6_16(Short4 &c);
+ void sRGBtoLinear16_5_16(Short4 &c);
bool hasFloatTexture() const;
bool hasUnnormalizedIntegerTexture() const;