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/15188
Tested-by: Alexis Hétu <sugoi@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/src/Renderer/ETC_Decoder.cpp b/src/Renderer/ETC_Decoder.cpp
index 8e109f3..71163ea 100644
--- a/src/Renderer/ETC_Decoder.cpp
+++ b/src/Renderer/ETC_Decoder.cpp
@@ -26,6 +26,13 @@
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
{
unsigned char b;
@@ -84,33 +91,51 @@
// 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)
{
- if(isSigned)
+ if(nbChannels <= 2) // EAC
{
- signed char* sDst = reinterpret_cast<signed char*>(dest);
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 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
{
- 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;
}
- dest += 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;
+ }
}
}
}
@@ -591,10 +616,14 @@
}
// 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;
- 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