Commit 5555af49 by Nicolas Capens Committed by Nicolas Capens

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/15068Reviewed-by: 's avatarAlexis Hétu <sugoi@google.com> Reviewed-by: 's avatarNicolas Capens <nicolascapens@google.com> Tested-by: 's avatarNicolas Capens <nicolascapens@google.com>
parent e13238e0
...@@ -52,8 +52,6 @@ namespace ...@@ -52,8 +52,6 @@ namespace
RGB10A2UI, RGB10A2UI,
R11G11B10F, R11G11B10F,
RGB9E5, RGB9E5,
SRGB,
SRGBA,
D16, D16,
D24, D24,
D32, D32,
...@@ -298,36 +296,6 @@ namespace ...@@ -298,36 +296,6 @@ namespace
} }
template<> 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) void LoadImageRow<D16>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
{ {
const unsigned short *sourceD16 = reinterpret_cast<const unsigned short*>(source); const unsigned short *sourceD16 = reinterpret_cast<const unsigned short*>(source);
...@@ -559,6 +527,7 @@ namespace egl ...@@ -559,6 +527,7 @@ namespace egl
{ {
case GL_INT: return sw::FORMAT_A32B32G32R32I; case GL_INT: return sw::FORMAT_A32B32G32R32I;
case GL_UNSIGNED_INT: return sw::FORMAT_A32B32G32R32UI; case GL_UNSIGNED_INT: return sw::FORMAT_A32B32G32R32UI;
case GL_UNSIGNED_INT_2_10_10_10_REV: return sw::FORMAT_A2B10G10R10UI;
default: UNREACHABLE(type); default: UNREACHABLE(type);
} }
break; break;
...@@ -805,16 +774,18 @@ namespace egl ...@@ -805,16 +774,18 @@ namespace egl
case GL_RGB8_SNORM: case GL_RGB8_SNORM:
case GL_RGB8: case GL_RGB8:
case GL_RGB: case GL_RGB:
case GL_SRGB8:
return sw::FORMAT_X8B8G8R8; return sw::FORMAT_X8B8G8R8;
case GL_SRGB8:
return sw::FORMAT_SRGB8_X8;
case GL_RGB8UI: case GL_RGB8UI:
case GL_RGB_INTEGER: case GL_RGB_INTEGER:
return sw::FORMAT_X8B8G8R8UI; return sw::FORMAT_X8B8G8R8UI;
case GL_RGBA8_SNORM: case GL_RGBA8_SNORM:
case GL_RGBA8: case GL_RGBA8:
case GL_RGBA: case GL_RGBA:
case GL_SRGB8_ALPHA8:
return sw::FORMAT_A8B8G8R8; return sw::FORMAT_A8B8G8R8;
case GL_SRGB8_ALPHA8:
return sw::FORMAT_SRGB8_A8;
case GL_RGBA8UI: case GL_RGBA8UI:
case GL_RGBA_INTEGER: case GL_RGBA_INTEGER:
return sw::FORMAT_A8B8G8R8UI; return sw::FORMAT_A8B8G8R8UI;
...@@ -934,7 +905,7 @@ namespace egl ...@@ -934,7 +905,7 @@ namespace egl
case GL_UNSIGNED_INT_2_10_10_10_REV: case GL_UNSIGNED_INT_2_10_10_10_REV:
if(format == GL_RGB10_A2UI) if(format == GL_RGB10_A2UI)
{ {
return sw::FORMAT_A16B16G16R16UI; return sw::FORMAT_A2B10G10R10UI;
} }
else else
{ {
...@@ -1338,8 +1309,8 @@ namespace egl ...@@ -1338,8 +1309,8 @@ namespace egl
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) 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); sw::Format uploadFormat = SelectInternalFormat(format, type);
if(selectedInternalFormat == sw::FORMAT_NULL) if(uploadFormat == sw::FORMAT_NULL)
{ {
return; return;
} }
...@@ -1349,7 +1320,10 @@ namespace egl ...@@ -1349,7 +1320,10 @@ namespace egl
GLsizei inputHeight = (unpackInfo.imageHeight == 0) ? height : unpackInfo.imageHeight; GLsizei inputHeight = (unpackInfo.imageHeight == 0) ? height : unpackInfo.imageHeight;
input = ((char*)input) + ComputePackingOffset(format, type, inputWidth, inputHeight, unpackInfo.alignment, unpackInfo.skipImages, unpackInfo.skipRows, unpackInfo.skipPixels); 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); void *buffer = lock(0, 0, sw::LOCK_WRITEONLY);
...@@ -1427,6 +1401,7 @@ namespace egl ...@@ -1427,6 +1401,7 @@ namespace egl
case GL_RGB8_SNORM: case GL_RGB8_SNORM:
case GL_RGB: case GL_RGB:
case GL_RGB_INTEGER: case GL_RGB_INTEGER:
case GL_SRGB8:
LoadImageData<UByteRGB>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getSlice(), input, buffer); LoadImageData<UByteRGB>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getSlice(), input, buffer);
break; break;
case GL_RGBA8: case GL_RGBA8:
...@@ -1436,13 +1411,8 @@ namespace egl ...@@ -1436,13 +1411,8 @@ namespace egl
case GL_RGBA_INTEGER: case GL_RGBA_INTEGER:
case GL_BGRA_EXT: case GL_BGRA_EXT:
case GL_BGRA8_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: 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; break;
default: UNREACHABLE(format); default: UNREACHABLE(format);
} }
...@@ -1501,8 +1471,6 @@ namespace egl ...@@ -1501,8 +1471,6 @@ namespace egl
switch(format) switch(format)
{ {
case GL_RGB10_A2UI: 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_RGB10_A2:
case GL_RGBA: case GL_RGBA:
case GL_RGBA_INTEGER: case GL_RGBA_INTEGER:
......
...@@ -5062,7 +5062,7 @@ void TexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, ...@@ -5062,7 +5062,7 @@ void TexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width,
GLenum sizedInternalFormat = GetSizedInternalFormat(internalformat, type); 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) if(validationError != GL_NONE)
{ {
return error(validationError); return error(validationError);
...@@ -5423,8 +5423,6 @@ void TexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLs ...@@ -5423,8 +5423,6 @@ void TexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLs
if(context) if(context)
{ {
GLenum sizedInternalFormat = GetSizedInternalFormat(format, type);
if(target == GL_TEXTURE_2D) if(target == GL_TEXTURE_2D)
{ {
es2::Texture2D *texture = context->getTexture2D(); es2::Texture2D *texture = context->getTexture2D();
...@@ -5435,13 +5433,13 @@ void TexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLs ...@@ -5435,13 +5433,13 @@ void TexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLs
return error(validationError); 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) if(validationError != GL_NONE)
{ {
return error(validationError); 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)) else if(es2::IsCubemapTextureTarget(target))
{ {
...@@ -5453,13 +5451,13 @@ void TexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLs ...@@ -5453,13 +5451,13 @@ void TexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLs
return error(validationError); 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) if(validationError != GL_NONE)
{ {
return error(validationError); 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); else UNREACHABLE(target);
} }
...@@ -6342,21 +6340,19 @@ void TexSubImage3DOES(GLenum target, GLint level, GLint xoffset, GLint yoffset, ...@@ -6342,21 +6340,19 @@ void TexSubImage3DOES(GLenum target, GLint level, GLint xoffset, GLint yoffset,
{ {
es2::Texture3D *texture = context->getTexture3D(); 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()); GLenum validationError = ValidateSubImageParams(false, false, target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, texture, context->getClientVersion());
if(validationError != GL_NONE) if(validationError != GL_NONE)
{ {
return error(validationError); 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) if(validationError != GL_NONE)
{ {
return error(validationError); 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);
} }
} }
......
...@@ -2193,7 +2193,6 @@ namespace es2sw ...@@ -2193,7 +2193,6 @@ namespace es2sw
case GL_R16UI: return sw::FORMAT_R16UI; case GL_R16UI: return sw::FORMAT_R16UI;
case GL_RG16UI: return sw::FORMAT_G16R16UI; case GL_RG16UI: return sw::FORMAT_G16R16UI;
case GL_RGB16UI: return sw::FORMAT_X16B16G16R16UI; case GL_RGB16UI: return sw::FORMAT_X16B16G16R16UI;
case GL_RGB10_A2UI:
case GL_RGBA16UI: return sw::FORMAT_A16B16G16R16UI; case GL_RGBA16UI: return sw::FORMAT_A16B16G16R16UI;
case GL_R32I: return sw::FORMAT_R32I; case GL_R32I: return sw::FORMAT_R32I;
case GL_RG32I: return sw::FORMAT_G32R32I; case GL_RG32I: return sw::FORMAT_G32R32I;
...@@ -2213,6 +2212,7 @@ namespace es2sw ...@@ -2213,6 +2212,7 @@ namespace es2sw
case GL_RGB32F: return sw::FORMAT_B32G32R32F; case GL_RGB32F: return sw::FORMAT_B32G32R32F;
case GL_RGBA32F: return sw::FORMAT_A32B32G32R32F; case GL_RGBA32F: return sw::FORMAT_A32B32G32R32F;
case GL_RGB10_A2: return sw::FORMAT_A2B10G10R10; 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: return sw::FORMAT_SRGB8_X8;
case GL_SRGB8_ALPHA8: return sw::FORMAT_SRGB8_A8; case GL_SRGB8_ALPHA8: return sw::FORMAT_SRGB8_A8;
default: UNREACHABLE(format); return sw::FORMAT_NULL; default: UNREACHABLE(format); return sw::FORMAT_NULL;
......
...@@ -393,6 +393,7 @@ namespace sw ...@@ -393,6 +393,7 @@ namespace sw
c.z = Float(Int(*Pointer<UShort>(element) & UShort(0x001F))); c.z = Float(Int(*Pointer<UShort>(element) & UShort(0x001F)));
break; break;
case FORMAT_A2B10G10R10: case FORMAT_A2B10G10R10:
case FORMAT_A2B10G10R10UI:
c.x = Float(Int((*Pointer<UInt>(element) & UInt(0x000003FF)))); c.x = Float(Int((*Pointer<UInt>(element) & UInt(0x000003FF))));
c.y = Float(Int((*Pointer<UInt>(element) & UInt(0x000FFC00)) >> 10)); c.y = Float(Int((*Pointer<UInt>(element) & UInt(0x000FFC00)) >> 10));
c.z = Float(Int((*Pointer<UInt>(element) & UInt(0x3FF00000)) >> 20)); c.z = Float(Int((*Pointer<UInt>(element) & UInt(0x3FF00000)) >> 20));
...@@ -741,6 +742,7 @@ namespace sw ...@@ -741,6 +742,7 @@ namespace sw
} }
break; break;
case FORMAT_A2B10G10R10: case FORMAT_A2B10G10R10:
case FORMAT_A2B10G10R10UI:
if(writeRGBA) if(writeRGBA)
{ {
*Pointer<UInt>(element) = UInt(RoundInt(Float(c.x)) | *Pointer<UInt>(element) = UInt(RoundInt(Float(c.x)) |
...@@ -1047,6 +1049,7 @@ namespace sw ...@@ -1047,6 +1049,7 @@ namespace sw
case FORMAT_B32G32R32F: case FORMAT_B32G32R32F:
case FORMAT_G32R32F: case FORMAT_G32R32F:
case FORMAT_R32F: case FORMAT_R32F:
case FORMAT_A2B10G10R10UI:
scale = vector(1.0f, 1.0f, 1.0f, 1.0f); scale = vector(1.0f, 1.0f, 1.0f, 1.0f);
break; break;
case FORMAT_R5G6B5: case FORMAT_R5G6B5:
......
...@@ -96,7 +96,7 @@ namespace sw ...@@ -96,7 +96,7 @@ namespace sw
state.addressingModeV = getAddressingModeV(); state.addressingModeV = getAddressingModeV();
state.addressingModeW = getAddressingModeW(); state.addressingModeW = getAddressingModeW();
state.mipmapFilter = mipmapFilter(); state.mipmapFilter = mipmapFilter();
state.sRGB = sRGB && Surface::isSRGBreadable(externalTextureFormat); state.sRGB = (sRGB && Surface::isSRGBreadable(externalTextureFormat)) || Surface::isSRGBformat(internalTextureFormat);
state.swizzleR = swizzleR; state.swizzleR = swizzleR;
state.swizzleG = swizzleG; state.swizzleG = swizzleG;
state.swizzleB = swizzleB; state.swizzleB = swizzleB;
......
...@@ -169,6 +169,7 @@ namespace sw ...@@ -169,6 +169,7 @@ namespace sw
*(unsigned int*)element = (unorm<2>(color.a) << 30) | (unorm<10>(color.r) << 20) | (unorm<10>(color.g) << 10) | (unorm<10>(color.b) << 0); *(unsigned int*)element = (unorm<2>(color.a) << 30) | (unorm<10>(color.r) << 20) | (unorm<10>(color.g) << 10) | (unorm<10>(color.b) << 0);
break; break;
case FORMAT_A2B10G10R10: 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); *(unsigned int*)element = (unorm<2>(color.a) << 30) | (unorm<10>(color.b) << 20) | (unorm<10>(color.g) << 10) | (unorm<10>(color.r) << 0);
break; break;
case FORMAT_G8R8I_SNORM: case FORMAT_G8R8I_SNORM:
...@@ -701,6 +702,16 @@ namespace sw ...@@ -701,6 +702,16 @@ namespace sw
r = (abgr & 0x000003FF) * (1.0f / 0x000003FF); r = (abgr & 0x000003FF) * (1.0f / 0x000003FF);
} }
break; 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: case FORMAT_A16B16G16R16I:
{ {
short* abgr = (short*)element; short* abgr = (short*)element;
...@@ -1544,6 +1555,7 @@ namespace sw ...@@ -1544,6 +1555,7 @@ namespace sw
case FORMAT_A8B8G8R8I_SNORM: return 4; case FORMAT_A8B8G8R8I_SNORM: return 4;
case FORMAT_A2R10G10B10: return 4; case FORMAT_A2R10G10B10: return 4;
case FORMAT_A2B10G10R10: return 4; case FORMAT_A2B10G10R10: return 4;
case FORMAT_A2B10G10R10UI: return 4;
case FORMAT_G8R8I: return 2; case FORMAT_G8R8I: return 2;
case FORMAT_G8R8: return 2; case FORMAT_G8R8: return 2;
case FORMAT_G16R16I: return 4; case FORMAT_G16R16I: return 4;
...@@ -2824,6 +2836,7 @@ namespace sw ...@@ -2824,6 +2836,7 @@ namespace sw
case FORMAT_G8R8I: case FORMAT_G8R8I:
case FORMAT_G8R8: case FORMAT_G8R8:
case FORMAT_A2B10G10R10: case FORMAT_A2B10G10R10:
case FORMAT_A2B10G10R10UI:
case FORMAT_R8I_SNORM: case FORMAT_R8I_SNORM:
case FORMAT_G8R8I_SNORM: case FORMAT_G8R8I_SNORM:
case FORMAT_X8B8G8R8I_SNORM: case FORMAT_X8B8G8R8I_SNORM:
...@@ -2908,6 +2921,7 @@ namespace sw ...@@ -2908,6 +2921,7 @@ namespace sw
case FORMAT_SRGB8_A8: case FORMAT_SRGB8_A8:
case FORMAT_G8R8: case FORMAT_G8R8:
case FORMAT_A2B10G10R10: case FORMAT_A2B10G10R10:
case FORMAT_A2B10G10R10UI:
case FORMAT_R16UI: case FORMAT_R16UI:
case FORMAT_G16R16: case FORMAT_G16R16:
case FORMAT_G16R16UI: case FORMAT_G16R16UI:
...@@ -3027,6 +3041,18 @@ namespace sw ...@@ -3027,6 +3041,18 @@ namespace sw
} }
} }
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) bool Surface::isCompressed(Format format)
{ {
switch(format) switch(format)
...@@ -3166,6 +3192,7 @@ namespace sw ...@@ -3166,6 +3192,7 @@ namespace sw
case FORMAT_X8B8G8R8UI: return 3; case FORMAT_X8B8G8R8UI: return 3;
case FORMAT_A8B8G8R8UI: return 4; case FORMAT_A8B8G8R8UI: return 4;
case FORMAT_A2B10G10R10: return 4; case FORMAT_A2B10G10R10: return 4;
case FORMAT_A2B10G10R10UI: return 4;
case FORMAT_G16R16I: return 2; case FORMAT_G16R16I: return 2;
case FORMAT_G16R16UI: return 2; case FORMAT_G16R16UI: return 2;
case FORMAT_G16R16: return 2; case FORMAT_G16R16: return 2;
...@@ -3765,6 +3792,8 @@ namespace sw ...@@ -3765,6 +3792,8 @@ namespace sw
case FORMAT_A2B10G10R10: case FORMAT_A2B10G10R10:
case FORMAT_A16B16G16R16: case FORMAT_A16B16G16R16:
return FORMAT_A16B16G16R16; return FORMAT_A16B16G16R16;
case FORMAT_A2B10G10R10UI:
return FORMAT_A16B16G16R16UI;
case FORMAT_X32B32G32R32I: case FORMAT_X32B32G32R32I:
return FORMAT_X32B32G32R32I; return FORMAT_X32B32G32R32I;
case FORMAT_A32B32G32R32I: case FORMAT_A32B32G32R32I:
......
...@@ -107,6 +107,7 @@ namespace sw ...@@ -107,6 +107,7 @@ namespace sw
FORMAT_G32R32UI, FORMAT_G32R32UI,
FORMAT_A2R10G10B10, FORMAT_A2R10G10B10,
FORMAT_A2B10G10R10, FORMAT_A2B10G10R10,
FORMAT_A2B10G10R10UI,
FORMAT_A16B16G16R16, // D3D format FORMAT_A16B16G16R16, // D3D format
FORMAT_X16B16G16R16I, FORMAT_X16B16G16R16I,
FORMAT_X16B16G16R16UI, FORMAT_X16B16G16R16UI,
...@@ -368,6 +369,7 @@ namespace sw ...@@ -368,6 +369,7 @@ namespace sw
static bool isUnsignedComponent(Format format, int component); static bool isUnsignedComponent(Format format, int component);
static bool isSRGBreadable(Format format); static bool isSRGBreadable(Format format);
static bool isSRGBwritable(Format format); static bool isSRGBwritable(Format format);
static bool isSRGBformat(Format format);
static bool isCompressed(Format format); static bool isCompressed(Format format);
static bool isSignedNonNormalizedInteger(Format format); static bool isSignedNonNormalizedInteger(Format format);
static bool isUnsignedNonNormalizedInteger(Format format); static bool isUnsignedNonNormalizedInteger(Format format);
......
...@@ -264,17 +264,17 @@ namespace sw ...@@ -264,17 +264,17 @@ namespace sw
for(int i = 0; i < 256; i++) 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++) 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++) 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++) for(int i = 0; i < 0x1000; i++)
......
...@@ -22,7 +22,7 @@ namespace sw ...@@ -22,7 +22,7 @@ namespace sw
struct Constants struct Constants
{ {
Constants(); Constants();
unsigned int transposeBit0[16]; unsigned int transposeBit0[16];
unsigned int transposeBit1[16]; unsigned int transposeBit1[16];
unsigned int transposeBit2[16]; unsigned int transposeBit2[16];
...@@ -67,9 +67,9 @@ namespace sw ...@@ -67,9 +67,9 @@ namespace sw
dword4 maskD01X[4]; dword4 maskD01X[4];
word4 mask565Q[8]; word4 mask565Q[8];
unsigned short sRGBtoLinear8_12[256]; unsigned short sRGBtoLinear8_16[256];
unsigned short sRGBtoLinear6_12[64]; unsigned short sRGBtoLinear6_16[64];
unsigned short sRGBtoLinear5_12[32]; unsigned short sRGBtoLinear5_16[32];
unsigned short linearToSRGB12_16[4096]; unsigned short linearToSRGB12_16[4096];
unsigned short sRGBtoLinear12_16[4096]; unsigned short sRGBtoLinear12_16[4096];
......
...@@ -133,46 +133,23 @@ namespace sw ...@@ -133,46 +133,23 @@ namespace sw
if(fixed12 && !hasFloatTexture()) if(fixed12 && !hasFloatTexture())
{ {
if(has16bitTextureFormat()) if(state.textureFormat == FORMAT_R5G6B5)
{ {
switch(state.textureFormat) c.x = MulHigh(As<UShort4>(c.x), UShort4(0x10000000 / 0xF800));
{ c.y = MulHigh(As<UShort4>(c.y), UShort4(0x10000000 / 0xFC00));
case FORMAT_R5G6B5: c.z = MulHigh(As<UShort4>(c.z), UShort4(0x10000000 / 0xF800));
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);
}
} }
else else
{ {
for(int component = 0; component < textureComponentCount(); component++) 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 else
{ {
if(hasUnsignedTextureComponent(component)) c[component] = c[component] >> 3;
{
c[component] = As<UShort4>(c[component]) >> 4;
}
else
{
c[component] = c[component] >> 3;
}
} }
} }
} }
...@@ -316,8 +293,8 @@ namespace sw ...@@ -316,8 +293,8 @@ namespace sw
} }
else else
{ {
// FIXME: YUV and sRGB are not supported by the floating point path // FIXME: YUV is not supported by the floating point path
bool forceFloatFiltering = state.highPrecisionFiltering && !state.sRGB && !hasYuvFormat() && (state.textureFilter != FILTER_POINT); bool forceFloatFiltering = state.highPrecisionFiltering && !hasYuvFormat() && (state.textureFilter != FILTER_POINT);
bool seamlessCube = (state.addressingModeU == ADDRESSING_SEAMLESS); bool seamlessCube = (state.addressingModeU == ADDRESSING_SEAMLESS);
if(hasFloatTexture() || hasUnnormalizedIntegerTexture() || forceFloatFiltering || seamlessCube) // FIXME: Mostly identical to integer sampling if(hasFloatTexture() || hasUnnormalizedIntegerTexture() || forceFloatFiltering || seamlessCube) // FIXME: Mostly identical to integer sampling
{ {
...@@ -380,52 +357,23 @@ namespace sw ...@@ -380,52 +357,23 @@ namespace sw
{ {
Vector4s cs = sampleTexture(texture, u, v, w, q, bias, dsx, dsy, offset, function, false); Vector4s cs = sampleTexture(texture, u, v, w, q, bias, dsx, dsy, offset, function, false);
if(has16bitTextureFormat()) if(state.textureFormat == FORMAT_R5G6B5)
{ {
switch(state.textureFormat) c.x = Float4(As<UShort4>(cs.x)) * Float4(1.0f / 0xF800);
{ c.y = Float4(As<UShort4>(cs.y)) * Float4(1.0f / 0xFC00);
case FORMAT_R5G6B5: c.z = Float4(As<UShort4>(cs.z)) * Float4(1.0f / 0xF800);
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);
}
} }
else else
{ {
for(int component = 0; component < textureComponentCount(); component++) for(int component = 0; component < textureComponentCount(); component++)
{ {
// Normalized integer formats if(hasUnsignedTextureComponent(component))
if(state.sRGB && isRGBComponent(component))
{ {
sRGBtoLinear16_8_12(cs[component]); // FIXME: Perform linearization at surface level for read-only textures convertUnsigned16(c[component], cs[component]);
convertSigned12(c[component], cs[component]);
} }
else else
{ {
if(hasUnsignedTextureComponent(component)) convertSigned15(c[component], cs[component]);
{
convertUnsigned16(c[component], cs[component]);
}
else
{
convertSigned15(c[component], cs[component]);
}
} }
} }
} }
...@@ -2036,6 +1984,26 @@ namespace sw ...@@ -2036,6 +1984,26 @@ namespace sw
} }
else ASSERT(false); 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; return c;
} }
...@@ -2238,7 +2206,7 @@ namespace sw ...@@ -2238,7 +2206,7 @@ namespace sw
bool isInteger = Surface::isNonNormalizedInteger(state.textureFormat); bool isInteger = Surface::isNonNormalizedInteger(state.textureFormat);
int componentCount = textureComponentCount(); int componentCount = textureComponentCount();
for(int n = 0; n < componentCount; ++n) for(int n = 0; n < componentCount; n++)
{ {
if(hasUnsignedTextureComponent(n)) if(hasUnsignedTextureComponent(n))
{ {
...@@ -2555,11 +2523,11 @@ namespace sw ...@@ -2555,11 +2523,11 @@ namespace sw
cf = Float4(As<UShort4>(cs)) * Float4(1.0f / 0xFFFF); 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; 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, 0))), 0);
c = Insert(c, *Pointer<Short>(LUT + 2 * Int(Extract(c, 1))), 1); c = Insert(c, *Pointer<Short>(LUT + 2 * Int(Extract(c, 1))), 1);
...@@ -2567,11 +2535,11 @@ namespace sw ...@@ -2567,11 +2535,11 @@ namespace sw
c = Insert(c, *Pointer<Short>(LUT + 2 * Int(Extract(c, 3))), 3); 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; 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, 0))), 0);
c = Insert(c, *Pointer<Short>(LUT + 2 * Int(Extract(c, 1))), 1); c = Insert(c, *Pointer<Short>(LUT + 2 * Int(Extract(c, 1))), 1);
...@@ -2579,11 +2547,11 @@ namespace sw ...@@ -2579,11 +2547,11 @@ namespace sw
c = Insert(c, *Pointer<Short>(LUT + 2 * Int(Extract(c, 3))), 3); 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; 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, 0))), 0);
c = Insert(c, *Pointer<Short>(LUT + 2 * Int(Extract(c, 1))), 1); c = Insert(c, *Pointer<Short>(LUT + 2 * Int(Extract(c, 1))), 1);
......
...@@ -92,9 +92,9 @@ namespace sw ...@@ -92,9 +92,9 @@ namespace sw
void convertSigned12(Float4 &cf, Short4 &ci); void convertSigned12(Float4 &cf, Short4 &ci);
void convertSigned15(Float4 &cf, Short4 &ci); void convertSigned15(Float4 &cf, Short4 &ci);
void convertUnsigned16(Float4 &cf, Short4 &ci); void convertUnsigned16(Float4 &cf, Short4 &ci);
void sRGBtoLinear16_8_12(Short4 &c); void sRGBtoLinear16_8_16(Short4 &c);
void sRGBtoLinear16_6_12(Short4 &c); void sRGBtoLinear16_6_16(Short4 &c);
void sRGBtoLinear16_5_12(Short4 &c); void sRGBtoLinear16_5_16(Short4 &c);
bool hasFloatTexture() const; bool hasFloatTexture() const;
bool hasUnnormalizedIntegerTexture() const; bool hasUnnormalizedIntegerTexture() const;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment