OSDN Git Service

Fixed EAC failures
authorAlexis Hetu <sugoi@google.com>
Mon, 18 Dec 2017 20:32:26 +0000 (15:32 -0500)
committerAlexis Hétu <sugoi@google.com>
Mon, 18 Dec 2017 21:01:13 +0000 (21:01 +0000)
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>
src/Renderer/ETC_Decoder.cpp
src/Renderer/Surface.cpp

index 8e109f3..71163ea 100644 (file)
@@ -26,6 +26,13 @@ namespace
                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 @@ namespace
                // 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;
+                                       }
+                               }
+                               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
                }
 
                // 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
index b809148..e732fb8 100644 (file)
@@ -2584,36 +2584,29 @@ namespace sw
        {
                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));
                external.unlockRect();
-               internal.unlockRect();
 
-               // FIXME: We convert signed data to float, until signed integer internal formats are supported
-               //        This code can be removed if signed ETC2 images are decoded to internal 8 bit signed R/RG formats
-               if(isSigned)
+               // FIXME: We convert EAC data to float, until signed short internal formats are supported
+               //        This code can be removed if ETC2 images are decoded to internal 16 bit signed R/RG formats
+               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);
-
-                       for(int y = 0; y < internal.height; y++)
+                       byte* srcRow = src + y * internal.pitchB;
+                       for(int x = internal.width - 1; x >= 0; x--)
                        {
-                               sbyte* srcRow = src + y * internal.pitchB;
-                               for(int x = internal.width - 1; x >= 0; x--)
+                               int* srcPix = reinterpret_cast<int*>(srcRow + x * internal.bytes);
+                               float* dstPix = reinterpret_cast<float*>(srcPix);
+                               for(int c = nbChannels - 1; c >= 0; c--)
                                {
-                                       int dx = x & 0xFFFFFFFC;
-                                       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);
-                                       }
+                                       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)
@@ -3887,13 +3880,13 @@ namespace sw
                        // 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
                case FORMAT_ATI1:
-               case FORMAT_R11_EAC:
                        return FORMAT_R8;
+               case FORMAT_R11_EAC:
                case FORMAT_SIGNED_R11_EAC:
                        return FORMAT_R32F; // FIXME: Signed 8bit format would be sufficient
                case FORMAT_ATI2:
-               case FORMAT_RG11_EAC:
                        return FORMAT_G8R8;
+               case FORMAT_RG11_EAC:
                case FORMAT_SIGNED_RG11_EAC:
                        return FORMAT_G32R32F; // FIXME: Signed 8bit format would be sufficient
                case FORMAT_ETC1: