OSDN Git Service

Fixed Float4 -> UInt4 conversion
authorAlexis Hetu <sugoi@google.com>
Wed, 28 Sep 2016 12:44:22 +0000 (08:44 -0400)
committerAlexis Hétu <sugoi@google.com>
Wed, 28 Sep 2016 14:14:03 +0000 (14:14 +0000)
It appears the Nucleus::createFPToUI function is broken and does
not yield the correct values for one pixel out of 4 when the f2u
operation is used. By manually rewriting the conversion using
signed int conversion and some arithmetic, the issue is solved.

This fixes at least 130 failures and also fixes many other tests
which were passing only due to the threshold being too lenient,
but which were showing obvious visual artefacts.

This affects, to the very least:
dEQP.functional.fbo.blit.conversion
dEQP.functional.shaders.functions.datatypes
dEQP.functional.shaders.operator.binary_operator
... and any other test using the f2u operation.

Change-Id: If38dad6b6ae8198f40e863d0847fa5080a2997e3
Reviewed-on: https://swiftshader-review.googlesource.com/7354
Tested-by: Alexis Hétu <sugoi@google.com>
Reviewed-by: Nicolas Capens <capn@google.com>
src/Reactor/Nucleus.cpp
src/Reactor/Nucleus.hpp

index bd13228..0a648bd 100644 (file)
@@ -475,10 +475,10 @@ namespace sw
                return builder->CreateSExt(V, destType);
        }
 
-       Value *Nucleus::createFPToUI(Value *V, Type *destType)
-       {
-               return builder->CreateFPToUI(V, destType);
-       }
+//     Value *Nucleus::createFPToUI(Value *V, Type *destType)
+//     {
+//             return builder->CreateFPToUI(V, destType);
+//     }
 
        Value *Nucleus::createFPToSI(Value *V, Type *destType)
        {
@@ -4293,9 +4293,21 @@ namespace sw
 
        UInt::UInt(RValue<Float> cast)
        {
-               Value *integer = Nucleus::createFPToUI(cast.value, UInt::getType());
+               // Note: createFPToUI is broken, must perform conversion using createFPtoSI
+               // Value *integer = Nucleus::createFPToUI(cast.value, UInt::getType());
 
-               storeValue(integer);
+               // Smallest positive value representable in UInt, but not in Int
+               const unsigned int ustart = 0x80000000u;
+               const float ustartf = float(ustart);
+
+               // If the value is negative, store 0, otherwise store the result of the conversion
+               storeValue((~(As<Int>(cast) >> 31) &
+               // Check if the value can be represented as an Int
+                       IfThenElse(cast >= ustartf,
+               // If the value is too large, subtract ustart and re-add it after conversion.
+                               As<Int>(As<UInt>(Int(cast - Float(ustartf))) + UInt(ustart)),
+               // Otherwise, just convert normally
+                               Int(cast))).value);
        }
 
        UInt::UInt()
@@ -5798,9 +5810,21 @@ namespace sw
        {
        //      xyzw.parent = this;
 
-               Value *xyzw = Nucleus::createFPToUI(cast.value, UInt4::getType());
-
-               storeValue(xyzw);
+               // Note: createFPToUI is broken, must perform conversion using createFPtoSI
+               // Value *xyzw = Nucleus::createFPToUI(cast.value, UInt4::getType());
+
+               // Smallest positive value representable in UInt, but not in Int
+               const unsigned int ustart = 0x80000000u;
+               const float ustartf = float(ustart);
+
+               // Check if the value can be represented as an Int
+               Int4 uiValue = CmpNLT(cast, Float4(ustartf));
+               // If the value is too large, subtract ustart and re-add it after conversion.
+               uiValue = (uiValue & As<Int4>(As<UInt4>(Int4(cast - Float4(ustartf))) + UInt4(ustart))) |
+               // Otherwise, just convert normally
+                         (~uiValue & Int4(cast));
+               // If the value is negative, store 0, otherwise store the result of the conversion
+               storeValue((~(As<Int4>(cast) >> 31) & uiValue).value);
        }
 
        UInt4::UInt4()
index 7e7e002..5d60382 100644 (file)
@@ -134,7 +134,7 @@ namespace sw
                static llvm::Value *createTrunc(llvm::Value *V, llvm::Type *destType);
                static llvm::Value *createZExt(llvm::Value *V, llvm::Type *destType);
                static llvm::Value *createSExt(llvm::Value *V, llvm::Type *destType);
-               static llvm::Value *createFPToUI(llvm::Value *V, llvm::Type *destType);
+               // static llvm::Value *createFPToUI(llvm::Value *V, llvm::Type *destType);
                static llvm::Value *createFPToSI(llvm::Value *V, llvm::Type *destType);
                static llvm::Value *createUIToFP(llvm::Value *V, llvm::Type *destType);
                static llvm::Value *createSIToFP(llvm::Value *V, llvm::Type *destType);