Commit f46493fe by Alexis Hetu Committed by Alexis Hétu

Fixed EAC failures

The ETC2 decoder spec has a slight difference with the EAC decoder spec when it comes to handling the 0 multiplier corner case. For ETC2, we have (OpenGL ES 3.0 spec, section C.1.3): "An encoder is not allowed to produce a multiplier of zero, but the decoder should still be able to handle also this case (and produce 0 x modifier = 0 in that case)." For EAC, we have (OpenGL ES 3.0 spec, section C.1.5): "If the multiplier value is zero, we should set the multiplier to 1.0/8.0" In order to take this into account, the EAC decoded output can no longer be represented by an 8 bit value, but must be represented by a minimum of 11 bits, as the spec requires. For now, the EAC decoder decodes EAC into a 32 bit integer format, which then gets converted to a 32 bit float format internally. Eventually, it would be possible for the EAC decoder to decode the image to a signed 16 bit integer internal format, if it was supported. Fixes all failures in: dEQP-GLES3.functional.texture.wrap* Change-Id: I32106383ade56e375229231ff230a2574791caa6 Reviewed-on: https://swiftshader-review.googlesource.com/15188Tested-by: 's avatarAlexis Hétu <sugoi@google.com> Reviewed-by: 's avatarNicolas Capens <nicolascapens@google.com>
parent 4e2f4e29
...@@ -26,6 +26,13 @@ namespace ...@@ -26,6 +26,13 @@ namespace
return (value < -128) ? -128 : ((value > 127) ? 127 : value); return (value < -128) ? -128 : ((value > 127) ? 127 : value);
} }
inline int clampEAC(int value, bool isSigned)
{
int min = isSigned ? -1023 : 0;
int max = isSigned ? 1023 : 2047;
return (value < min) ? min : ((value > max) ? max : value);
}
struct bgra8 struct bgra8
{ {
unsigned char b; unsigned char b;
...@@ -84,33 +91,51 @@ namespace ...@@ -84,33 +91,51 @@ namespace
// Decodes unsigned single or dual channel block to bytes // Decodes unsigned single or dual channel block to bytes
static void DecodeBlock(const ETC2** sources, unsigned char *dest, int nbChannels, int x, int y, int w, int h, int pitch, bool isSigned) static void DecodeBlock(const ETC2** sources, unsigned char *dest, int nbChannels, int x, int y, int w, int h, int pitch, bool isSigned)
{ {
if(isSigned) if(nbChannels <= 2) // EAC
{ {
signed char* sDst = reinterpret_cast<signed char*>(dest);
for(int j = 0; j < 4 && (y + j) < h; j++) for(int j = 0; j < 4 && (y + j) < h; j++)
{ {
int* sDst = reinterpret_cast<int*>(dest);
for(int i = 0; i < 4 && (x + i) < w; i++) for(int i = 0; i < 4 && (x + i) < w; i++)
{ {
for(int c = nbChannels - 1; c >= 0; c--) for(int c = nbChannels - 1; c >= 0; c--)
{ {
sDst[i * nbChannels + c] = clampSByte(sources[c]->getSingleChannel(i, j, isSigned)); sDst[i * nbChannels + c] = clampEAC(sources[c]->getSingleChannel(i, j, isSigned, true), isSigned);
} }
} }
sDst += pitch; dest += pitch;
} }
} }
else else
{ {
for(int j = 0; j < 4 && (y + j) < h; j++) if(isSigned)
{ {
for(int i = 0; i < 4 && (x + i) < w; i++) signed char* sDst = reinterpret_cast<signed char*>(dest);
for(int j = 0; j < 4 && (y + j) < h; j++)
{ {
for(int c = nbChannels - 1; c >= 0; c--) for(int i = 0; i < 4 && (x + i) < w; i++)
{ {
dest[i * nbChannels + c] = clampByte(sources[c]->getSingleChannel(i, j, isSigned)); for(int c = nbChannels - 1; c >= 0; c--)
{
sDst[i * nbChannels + c] = clampSByte(sources[c]->getSingleChannel(i, j, isSigned, false));
}
} }
sDst += pitch;
}
}
else
{
for(int j = 0; j < 4 && (y + j) < h; j++)
{
for(int i = 0; i < 4 && (x + i) < w; i++)
{
for(int c = nbChannels - 1; c >= 0; c--)
{
dest[i * nbChannels + c] = clampByte(sources[c]->getSingleChannel(i, j, isSigned, false));
}
}
dest += pitch;
} }
dest += pitch;
} }
} }
} }
...@@ -591,10 +616,14 @@ namespace ...@@ -591,10 +616,14 @@ namespace
} }
// Single channel utility functions // Single channel utility functions
inline int getSingleChannel(int x, int y, bool isSigned) const inline int getSingleChannel(int x, int y, bool isSigned, bool isEAC) const
{ {
int codeword = isSigned ? signed_base_codeword : base_codeword; int codeword = isSigned ? signed_base_codeword : base_codeword;
return codeword + getSingleChannelModifier(x, y) * multiplier; return isEAC ?
((multiplier == 0) ?
(codeword * 8 + 4 + getSingleChannelModifier(x, y)) :
(codeword * 8 + 4 + getSingleChannelModifier(x, y) * multiplier * 8)) :
codeword + getSingleChannelModifier(x, y) * multiplier;
} }
inline int getSingleChannelIndex(int x, int y) const inline int getSingleChannelIndex(int x, int y) const
......
...@@ -2584,36 +2584,29 @@ namespace sw ...@@ -2584,36 +2584,29 @@ namespace sw
{ {
ASSERT(nbChannels == 1 || nbChannels == 2); ASSERT(nbChannels == 1 || nbChannels == 2);
ETC_Decoder::Decode((const byte*)external.lockRect(0, 0, 0, LOCK_READONLY), (byte*)internal.lockRect(0, 0, 0, LOCK_WRITEONLY), external.width, external.height, internal.width, internal.height, internal.pitchB, internal.bytes, byte *src = (byte*)internal.lockRect(0, 0, 0, LOCK_READWRITE);
ETC_Decoder::Decode((const byte*)external.lockRect(0, 0, 0, LOCK_READONLY), src, external.width, external.height, internal.width, internal.height, internal.pitchB, internal.bytes,
(nbChannels == 1) ? (isSigned ? ETC_Decoder::ETC_R_SIGNED : ETC_Decoder::ETC_R_UNSIGNED) : (isSigned ? ETC_Decoder::ETC_RG_SIGNED : ETC_Decoder::ETC_RG_UNSIGNED)); (nbChannels == 1) ? (isSigned ? ETC_Decoder::ETC_R_SIGNED : ETC_Decoder::ETC_R_UNSIGNED) : (isSigned ? ETC_Decoder::ETC_RG_SIGNED : ETC_Decoder::ETC_RG_UNSIGNED));
external.unlockRect(); external.unlockRect();
internal.unlockRect();
// FIXME: We convert signed data to float, until signed integer internal formats are supported // FIXME: We convert EAC data to float, until signed short internal formats are supported
// This code can be removed if signed ETC2 images are decoded to internal 8 bit signed R/RG formats // This code can be removed if ETC2 images are decoded to internal 16 bit signed R/RG formats
if(isSigned) const float normalization = isSigned ? (1.0f / (8.0f * 127.875f)) : (1.0f / (8.0f * 255.875f));
for(int y = 0; y < internal.height; y++)
{ {
sbyte *src = (sbyte*)internal.lockRect(0, 0, 0, LOCK_READWRITE); byte* srcRow = src + y * internal.pitchB;
for(int x = internal.width - 1; x >= 0; x--)
for(int y = 0; y < internal.height; y++)
{ {
sbyte* srcRow = src + y * internal.pitchB; int* srcPix = reinterpret_cast<int*>(srcRow + x * internal.bytes);
for(int x = internal.width - 1; x >= 0; x--) float* dstPix = reinterpret_cast<float*>(srcPix);
for(int c = nbChannels - 1; c >= 0; c--)
{ {
int dx = x & 0xFFFFFFFC; dstPix[c] = clamp(static_cast<float>(srcPix[c]) * normalization, -1.0f, 1.0f);
int mx = x - dx;
sbyte* srcPix = srcRow + dx * internal.bytes + mx * nbChannels;
float* dstPix = (float*)(srcRow + x * internal.bytes);
for(int c = nbChannels - 1; c >= 0; c--)
{
static const float normalization = 1.0f / 127.875f;
dstPix[c] = clamp(static_cast<float>(srcPix[c]) * normalization, -1.0f, 1.0f);
}
} }
} }
internal.unlockRect();
} }
internal.unlockRect();
} }
void Surface::decodeASTC(Buffer &internal, Buffer &external, int xBlockSize, int yBlockSize, int zBlockSize, bool isSRGB) void Surface::decodeASTC(Buffer &internal, Buffer &external, int xBlockSize, int yBlockSize, int zBlockSize, bool isSRGB)
...@@ -3887,13 +3880,13 @@ namespace sw ...@@ -3887,13 +3880,13 @@ namespace sw
// ASTC supports HDR, so a floating point format is required to represent it properly // ASTC supports HDR, so a floating point format is required to represent it properly
return FORMAT_A32B32G32R32F; // FIXME: 16FP is probably sufficient, but it's currently unsupported return FORMAT_A32B32G32R32F; // FIXME: 16FP is probably sufficient, but it's currently unsupported
case FORMAT_ATI1: case FORMAT_ATI1:
case FORMAT_R11_EAC:
return FORMAT_R8; return FORMAT_R8;
case FORMAT_R11_EAC:
case FORMAT_SIGNED_R11_EAC: case FORMAT_SIGNED_R11_EAC:
return FORMAT_R32F; // FIXME: Signed 8bit format would be sufficient return FORMAT_R32F; // FIXME: Signed 8bit format would be sufficient
case FORMAT_ATI2: case FORMAT_ATI2:
case FORMAT_RG11_EAC:
return FORMAT_G8R8; return FORMAT_G8R8;
case FORMAT_RG11_EAC:
case FORMAT_SIGNED_RG11_EAC: case FORMAT_SIGNED_RG11_EAC:
return FORMAT_G32R32F; // FIXME: Signed 8bit format would be sufficient return FORMAT_G32R32F; // FIXME: Signed 8bit format would be sufficient
case FORMAT_ETC1: case FORMAT_ETC1:
......
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