Update dEQP.
authorJarkko Poyry <jpoyry@google.com>
Thu, 11 Sep 2014 07:20:23 +0000 (10:20 +0300)
committerJarkko Poyry <jpoyry@google.com>
Thu, 11 Sep 2014 07:20:23 +0000 (10:20 +0300)
Migrate drawElements Quality Program changes from an internal repository.

Bug: 17388917

Change-Id: I21e3f7bc75813f0510025d697d91a2554dc995d4

80 files changed:
Android.mk
data/gles3/shaders/linkage.test
doc/testspecs/GLES2/functional.scissors.txt
framework/common/tcuTestContext.cpp
framework/common/tcuTexLookupVerifier.cpp
framework/common/tcuTexLookupVerifier.hpp
framework/common/tcuTexture.cpp
framework/common/tcuTexture.hpp
framework/common/tcuTextureUtil.cpp
framework/common/tcuTextureUtil.hpp
framework/common/tcuVector.hpp
framework/common/tcuVectorUtil.hpp
framework/delibs/debase/deMath.h
framework/delibs/dethread/win32/deMutexWin32.c
framework/opengl/gluES3PlusWrapperContext.cpp
framework/opengl/gluES3PlusWrapperFuncs.inl
framework/opengl/gluObjectWrapper.hpp
framework/opengl/simplereference/sglrReferenceContext.cpp
framework/opengl/wrapper/glwInitES31.inl
framework/opengl/wrapper/glwInitFunctions.cpp
framework/platform/win32/tcuWin32Platform.cpp
framework/referencerenderer/rrRenderer.cpp
modules/gles2/functional/es2fFlushFinishTests.cpp
modules/gles2/functional/es2fScissorTests.cpp
modules/gles2/performance/es2pShaderOperatorTests.cpp
modules/gles3/functional/es3fBlendTests.cpp
modules/gles3/functional/es3fFboCompletenessTests.cpp
modules/gles3/functional/es3fFboInvalidateTests.cpp
modules/gles3/functional/es3fFlushFinishTests.cpp
modules/gles3/functional/es3fScissorTests.cpp
modules/gles3/functional/es3fShaderPrecisionTests.cpp
modules/gles3/functional/es3fShaderTextureFunctionTests.cpp
modules/gles3/performance/CMakeLists.txt
modules/gles3/performance/es3pBufferDataUploadTests.cpp
modules/gles3/performance/es3pDepthTests.cpp [new file with mode: 0644]
modules/gles3/performance/es3pDepthTests.hpp [new file with mode: 0644]
modules/gles3/performance/es3pPerformanceTests.cpp
modules/gles3/performance/es3pShaderOperatorTests.cpp
modules/gles31/functional/CMakeLists.txt
modules/gles31/functional/es31fBasicComputeShaderTests.cpp
modules/gles31/functional/es31fComputeShaderBuiltinVarTests.cpp
modules/gles31/functional/es31fDrawTests.cpp
modules/gles31/functional/es31fFboColorbufferTests.cpp [new file with mode: 0644]
modules/gles31/functional/es31fFboColorbufferTests.hpp [new file with mode: 0644]
modules/gles31/functional/es31fFboTestCase.cpp [new file with mode: 0644]
modules/gles31/functional/es31fFboTestCase.hpp [new file with mode: 0644]
modules/gles31/functional/es31fFboTestUtil.cpp
modules/gles31/functional/es31fFboTestUtil.hpp
modules/gles31/functional/es31fFunctionalTests.cpp
modules/gles31/functional/es31fGeometryShaderTests.cpp
modules/gles31/functional/es31fLayoutBindingTests.cpp
modules/gles31/functional/es31fOpaqueTypeIndexingTests.cpp
modules/gles31/functional/es31fProgramInterfaceDefinitionUtil.cpp
modules/gles31/functional/es31fProgramInterfaceQueryTestCase.cpp
modules/gles31/functional/es31fProgramInterfaceQueryTests.cpp
modules/gles31/functional/es31fSSBOLayoutCase.cpp
modules/gles31/functional/es31fSampleVariableTests.cpp
modules/gles31/functional/es31fSeparateShaderTests.cpp
modules/gles31/functional/es31fShaderAtomicOpTests.cpp
modules/gles31/functional/es31fShaderCommonFunctionTests.cpp
modules/gles31/functional/es31fShaderHelperInvocationTests.cpp
modules/gles31/functional/es31fShaderImageLoadStoreTests.cpp
modules/gles31/functional/es31fShaderIntegerFunctionTests.cpp
modules/gles31/functional/es31fShaderMultisampleInterpolationTests.cpp
modules/gles31/functional/es31fShaderSharedVarTests.cpp
modules/gles31/functional/es31fShaderStateQueryTests.cpp
modules/gles31/functional/es31fShaderTextureSizeTests.cpp
modules/gles31/functional/es31fSynchronizationTests.cpp
modules/gles31/functional/es31fTessellationTests.cpp
modules/gles31/functional/es31fTextureFilteringTests.cpp [new file with mode: 0644]
modules/gles31/functional/es31fTextureFilteringTests.hpp [new file with mode: 0644]
modules/gles31/functional/es31fTextureFormatTests.cpp
modules/glshared/glsBuiltinPrecisionTests.cpp
modules/glshared/glsCalibration.cpp
modules/glshared/glsCalibration.hpp
modules/glshared/glsScissorTests.cpp
modules/glshared/glsScissorTests.hpp
modules/glshared/glsShaderExecUtil.cpp
modules/glshared/glsTextureTestUtil.cpp
modules/glshared/glsTextureTestUtil.hpp

index 3e5d1c2..da2aeb0 100644 (file)
@@ -235,7 +235,9 @@ LOCAL_SRC_FILES := \
        modules/gles31/functional/es31fComputeShaderBuiltinVarTests.cpp \
        modules/gles31/functional/es31fDebugTests.cpp \
        modules/gles31/functional/es31fDrawTests.cpp \
+       modules/gles31/functional/es31fFboColorbufferTests.cpp \
        modules/gles31/functional/es31fFboNoAttachmentTests.cpp \
+       modules/gles31/functional/es31fFboTestCase.cpp \
        modules/gles31/functional/es31fFboTestUtil.cpp \
        modules/gles31/functional/es31fFunctionalTests.cpp \
        modules/gles31/functional/es31fGeometryShaderTests.cpp \
@@ -281,6 +283,7 @@ LOCAL_SRC_FILES := \
        modules/gles31/functional/es31fTessellationGeometryInteractionTests.cpp \
        modules/gles31/functional/es31fTessellationTests.cpp \
        modules/gles31/functional/es31fTextureBufferTests.cpp \
+       modules/gles31/functional/es31fTextureFilteringTests.cpp \
        modules/gles31/functional/es31fTextureFormatTests.cpp \
        modules/gles31/functional/es31fTextureGatherTests.cpp \
        modules/gles31/functional/es31fTextureLevelStateQueryTests.cpp \
@@ -409,6 +412,7 @@ LOCAL_SRC_FILES := \
        modules/gles3/functional/es3fVertexTextureTests.cpp \
        modules/gles3/performance/es3pBlendTests.cpp \
        modules/gles3/performance/es3pBufferDataUploadTests.cpp \
+       modules/gles3/performance/es3pDepthTests.cpp \
        modules/gles3/performance/es3pPerformanceTests.cpp \
        modules/gles3/performance/es3pRedundantStateChangeTests.cpp \
        modules/gles3/performance/es3pShaderCompilationCases.cpp \
index 6ca0d3e..77b955e 100644 (file)
@@ -614,6 +614,121 @@ group varying "Varying linkage"
                                }
                        ""
                end
+
+               case invalid_type_struct_array
+                       version 300 es
+                       desc "float array inside struct"
+                       expect compile_fail
+                       vertex ""
+                               #version 300 es
+                               ${VERTEX_DECLARATIONS}
+                               struct S { mediump float a[3]; };
+                               out S var;
+                               void main()
+                               {
+                                       var.a[0] = 1.0;
+                                       var.a[1] = 1.0;
+                                       var.a[2] = 1.0;
+                                       ${VERTEX_OUTPUT}
+                               }
+                       ""
+                       fragment ""
+                               #version 300 es
+                               precision mediump float;
+                               ${FRAGMENT_DECLARATIONS}
+                               struct S { mediump float a[3]; };
+                               in S var;
+                               void main()
+                               {
+                                       ${FRAG_COLOR} = vec4(1.0);
+                               }
+                       ""
+               end
+
+               case invalid_type_struct_struct
+                       version 300 es
+                       desc "struct inside struct"
+                       expect compile_fail
+                       vertex ""
+                               #version 300 es
+                               ${VERTEX_DECLARATIONS}
+                               struct S { mediump float a; };
+                               struct T { S s; };
+                               out T var;
+                               void main()
+                               {
+                                       var.s.a = 1.0;
+                                       ${VERTEX_OUTPUT}
+                               }
+                       ""
+                       fragment ""
+                               #version 300 es
+                               precision mediump float;
+                               ${FRAGMENT_DECLARATIONS}
+                               struct S { mediump float a; };
+                               struct T { S s; };
+                               in T var;
+                               void main()
+                               {
+                                       ${FRAG_COLOR} = vec4(1.0);
+                               }
+                       ""
+               end
+
+               case invalid_type_array_struct
+                       version 300 es
+                       desc "array of structs"
+                       expect compile_fail
+                       vertex ""
+                               #version 300 es
+                               ${VERTEX_DECLARATIONS}
+                               struct S { mediump int a; };
+                               flat out S var[2];
+                               void main()
+                               {
+                                       ${VERTEX_SETUP}
+                                       var[0].a = 1;
+                                       var[1].a = 1;
+                                       ${VERTEX_OUTPUT}
+                               }
+                       ""
+                       fragment ""
+                               #version 300 es
+                               ${FRAGMENT_DECLARATIONS}
+                               struct S { mediump int a; };
+                               flat in S var[2];
+                               void main()
+                               {
+                                       ${FRAG_COLOR} = vec4(1.0);
+                               }
+                       ""
+               end
+
+               case invalid_type_array_array
+                       version 300 es
+                       desc "array of arrays"
+                       expect compile_fail
+                       vertex ""
+                               #version 300 es
+                               ${VERTEX_DECLARATIONS}
+                               out mediump float var[2][2];
+                               void main()
+                               {
+                                       ${VERTEX_SETUP}
+                                       var[0][0] = 1.0;
+                                       ${VERTEX_OUTPUT}
+                               }
+                       ""
+                       fragment ""
+                               #version 300 es
+                               ${FRAGMENT_DECLARATIONS}
+                               in mediump float var[2][2];
+                               void main()
+                               {
+                                       ${FRAG_COLOR} = vec4(1.0);
+                               }
+                       ""
+               end
        end
 
        group basic_types "Basic varying types"
@@ -1963,111 +2078,6 @@ group varying "Varying linkage"
                        ""
                end
 
-               case array_float
-                       version 300 es
-                       desc "float array inside struct"
-                       values
-                       {
-                               input vec3 in0          = [ vec3(-1.25, 1.25, -9.5) | vec3(-25.65, -7.25, 14.21) | vec3(0.0, 1.0, -1.0) | vec3(2.25, 2.25, 22.5) | vec3(3.4, 9.5, 19.5) | vec3(16.0, 32.0, -64.0) ];
-                               output vec3 out0        = [ vec3(-1.25, 1.25, -9.5) | vec3(-25.65, -7.25, 14.21) | vec3(0.0, 1.0, -1.0) | vec3(2.25, 2.25, 22.5) | vec3(3.4, 9.5, 19.5) | vec3(16.0, 32.0, -64.0) ];
-                       }
-                       vertex ""
-                               #version 300 es
-                               ${VERTEX_DECLARATIONS}
-                               struct S { mediump float a[3]; };
-                               out S var;
-                               void main()
-                               {
-                                       var.a[0] = in0.z;
-                                       var.a[1] = in0.y;
-                                       var.a[2] = in0.x;
-                                       ${VERTEX_OUTPUT}
-                               }
-                       ""
-                       fragment ""
-                               #version 300 es
-                               precision mediump float;
-                               ${FRAGMENT_DECLARATIONS}
-                               struct S { mediump float a[3]; };
-                               in S var;
-                               void main()
-                               {
-                                       out0 = vec3(var.a[2], var.a[1], var.a[0]);
-                                       ${FRAGMENT_OUTPUT}
-                               }
-                       ""
-               end
-
-               case array_int
-                       version 300 es
-                       desc "varying of type ivec3 inside struct"
-                       values
-                       {
-                               input ivec3 in0         = [ ivec3(-1, 1, -2) | ivec3(-25, 25, -3) | ivec3(1, 1, 1) | ivec3(2, 3, 4) | ivec3(16, 17, 18) ];
-                               output ivec3 out0       = [ ivec3(-1, 1, -2) | ivec3(-25, 25, -3) | ivec3(1, 1, 1) | ivec3(2, 3, 4) | ivec3(16, 17, 18) ];
-                       }
-                       vertex ""
-                               #version 300 es
-                               ${VERTEX_DECLARATIONS}
-                               struct S { mediump int a[3]; };
-                               flat out S var;
-                               void main()
-                               {
-                                       ${VERTEX_SETUP}
-                                       var.a[0] = in0.z;
-                                       var.a[1] = in0.y;
-                                       var.a[2] = in0.x;
-                                       ${VERTEX_OUTPUT}
-                               }
-                       ""
-                       fragment ""
-                               #version 300 es
-                               ${FRAGMENT_DECLARATIONS}
-                               struct S { mediump int a[3]; };
-                               flat in S var;
-                               void main()
-                               {
-                                       out0 = ivec3(var.a[2], var.a[1], var.a[0]);
-                                       ${FRAGMENT_OUTPUT}
-                               }
-                       ""
-               end
-
-               case array_uint
-                       version 300 es
-                       desc "varying of type ivec3 inside struct"
-                       values
-                       {
-                               input uvec3 in0         = [ uvec3(7, 1, 2) | uvec3(8, 25, 3) | uvec3(1, 7, 12) | uvec3(2, 3, 4) | uvec3(16, 17, 18) ];
-                               output uvec3 out0       = [ uvec3(7, 1, 2) | uvec3(8, 25, 3) | uvec3(1, 7, 12) | uvec3(2, 3, 4) | uvec3(16, 17, 18) ];
-                       }
-                       vertex ""
-                               #version 300 es
-                               ${VERTEX_DECLARATIONS}
-                               struct S { mediump uint a[3]; };
-                               flat out S var;
-                               void main()
-                               {
-                                       ${VERTEX_SETUP}
-                                       var.a[0] = in0.z;
-                                       var.a[1] = in0.y;
-                                       var.a[2] = in0.x;
-                                       ${VERTEX_OUTPUT}
-                               }
-                       ""
-                       fragment ""
-                               #version 300 es
-                               ${FRAGMENT_DECLARATIONS}
-                               struct S { mediump uint a[3]; };
-                               flat in S var;
-                               void main()
-                               {
-                                       out0 = uvec3(var.a[2], var.a[1], var.a[0]);
-                                       ${FRAGMENT_OUTPUT}
-                               }
-                       ""
-               end
-
                case float_vec3
                        version 300 es
                        desc "varyings of type float and vec3 inside struct"
@@ -2105,51 +2115,6 @@ group varying "Varying linkage"
                        ""
                end
 
-               case float_array_vec3
-                       version 300 es
-                       desc "varyings of type float and vec3 inside struct"
-                       values
-                       {
-                               input float in0         = [ -1.25 | -25.65 | 1.0 | 2.25 | 3.4 | 16.0 ];
-                               output float out0       = [ -1.25 | -25.65 | 1.0 | 2.25 | 3.4 | 16.0 ];
-                               input float in1         = [ 1.5 | -5.5 | -2.0 | 3.25 | 3.0 | -16.0 ];
-                               output float out1       = [ 1.5 | -5.5 | -2.0 | 3.25 | 3.0 | -16.0 ];
-                               input float in2         = [ 2.5 | 5.65 | 1.25 | 1.25 | -3.4 | 8.0 ];
-                               output float out2       = [ 2.5 | 5.65 | 1.25 | 1.25 | -3.4 | 8.0 ];
-                               input vec3 in3          = [ vec3(-1.25, 1.25, -9.5) | vec3(-25.65, -7.25, 14.21) | vec3(0.0, 1.0, -1.0) | vec3(2.25, 2.25, 22.5) | vec3(3.4, 9.5, 19.5) | vec3(16.0, 32.0, -64.0) ];
-                               output vec3 out3        = [ vec3(-1.25, 1.25, -9.5) | vec3(-25.65, -7.25, 14.21) | vec3(0.0, 1.0, -1.0) | vec3(2.25, 2.25, 22.5) | vec3(3.4, 9.5, 19.5) | vec3(16.0, 32.0, -64.0) ];
-                       }
-                       vertex ""
-                               #version 300 es
-                               ${VERTEX_DECLARATIONS}
-                               struct S { mediump float a[3]; highp vec3 b; };
-                               out S var;
-                               void main()
-                               {
-                                       var.a[0] = in0;
-                                       var.a[1] = in1;
-                                       var.a[2] = in2;
-                                       var.b = in3;
-                                       ${VERTEX_OUTPUT}
-                               }
-                       ""
-                       fragment ""
-                               #version 300 es
-                               precision mediump float;
-                               ${FRAGMENT_DECLARATIONS}
-                               struct S { mediump float a[3]; highp vec3 b; };
-                               in S var;
-                               void main()
-                               {
-                                       out0 = var.a[0];
-                                       out1 = var.a[1];
-                                       out2 = var.a[2];
-                                       out3 = var.b;
-                                       ${FRAGMENT_OUTPUT}
-                               }
-                       ""
-               end
-
                case float_uvec2_vec3
                        version 300 es
                        desc "varyings of type float and vec3 inside struct"
@@ -2192,52 +2157,6 @@ group varying "Varying linkage"
                        ""
                end
 
-               case float_uvec2_array_vec3
-                       version 300 es
-                       desc "varyings of type float and vec3 inside struct"
-                       values
-                       {
-                               input float in0         = [ -1.25 | -25.65 | 1.0 | 2.25 | 3.4 | 16.0 ];
-                               output float out0       = [ -1.25 | -25.65 | 1.0 | 2.25 | 3.4 | 16.0 ];
-                               input uvec2 in1         = [ uvec2(1, 1) | uvec2(25, 25) | uvec2(1, 1) | uvec2(2, 3) | uvec2(16, 17) | uvec2(9, 2) ];
-                               output uvec2 out1       = [ uvec2(1, 1) | uvec2(25, 25) | uvec2(1, 1) | uvec2(2, 3) | uvec2(16, 17) | uvec2(9, 2) ];
-                               input uvec2 in2         = [ uvec2(3, 2) | uvec2(15, 7) | uvec2(2, 1) | uvec2(2, 1) | uvec2(9, 7) | uvec2(0, 10) ];
-                               output uvec2 out2       = [ uvec2(3, 2) | uvec2(15, 7) | uvec2(2, 1) | uvec2(2, 1) | uvec2(9, 7) | uvec2(0, 10) ];
-                               input vec3 in3          = [ vec3(-1.25, 1.25, -9.5) | vec3(-25.65, -7.25, 14.21) | vec3(0.0, 1.0, -1.0) | vec3(2.25, 2.25, 22.5) | vec3(3.4, 9.5, 19.5) | vec3(16.0, 32.0, -64.0) ];
-                               output vec3 out3        = [ vec3(-1.25, 1.25, -9.5) | vec3(-25.65, -7.25, 14.21) | vec3(0.0, 1.0, -1.0) | vec3(2.25, 2.25, 22.5) | vec3(3.4, 9.5, 19.5) | vec3(16.0, 32.0, -64.0) ];
-                       }
-                       vertex ""
-                               #version 300 es
-                               ${VERTEX_DECLARATIONS}
-                               struct S { mediump float a; highp uvec2 b[2]; highp vec3 c; };
-                               flat out S var;
-                               void main()
-                               {
-                                       ${VERTEX_SETUP}
-                                       var.a = in0;
-                                       var.b[0] = in1;
-                                       var.b[1] = in2;
-                                       var.c = in3;
-                                       ${VERTEX_OUTPUT}
-                               }
-                       ""
-                       fragment ""
-                               #version 300 es
-                               precision mediump float;
-                               ${FRAGMENT_DECLARATIONS}
-                               struct S { mediump float a; highp uvec2 b[2]; highp vec3 c; };
-                               flat in S var;
-                               void main()
-                               {
-                                       out0 = var.a;
-                                       out1 = var.b[0];
-                                       out2 = var.b[1];
-                                       out3 = var.c;
-                                       ${FRAGMENT_OUTPUT}
-                               }
-                       ""
-               end
-
                case float_vec3_struct_array
                        version 300 es
                        desc "varyings of type float and vec3 inside struct"
@@ -2285,64 +2204,6 @@ group varying "Varying linkage"
                                }
                        ""
                end
-
-               case float_uvec2_vec3_struct_array
-                       version 300 es
-                       desc "varyings of type float and vec3 inside struct"
-                       values
-                       {
-                               input float in0         = [ -1.25 | -25.65 | 1.0 | 2.25 | 3.4 | 16.0 ];
-                               output float out0       = [ -1.25 | -25.65 | 1.0 | 2.25 | 3.4 | 16.0 ];
-                               input float in1         = [ 1.5 | -5.5 | -2.0 | 3.25 | 3.0 | -16.0 ];
-                               output float out1       = [ 1.5 | -5.5 | -2.0 | 3.25 | 3.0 | -16.0 ];
-                               input uvec2 in2         = [ uvec2(1, 1) | uvec2(25, 25) | uvec2(1, 1) | uvec2(2, 3) | uvec2(16, 17) | uvec2(9, 2) ];
-                               output uvec2 out2       = [ uvec2(1, 1) | uvec2(25, 25) | uvec2(1, 1) | uvec2(2, 3) | uvec2(16, 17) | uvec2(9, 2) ];
-                               input uvec2 in3         = [ uvec2(3, 2) | uvec2(15, 7) | uvec2(2, 1) | uvec2(2, 1) | uvec2(9, 7) | uvec2(0, 10) ];
-                               output uvec2 out3       = [ uvec2(3, 2) | uvec2(15, 7) | uvec2(2, 1) | uvec2(2, 1) | uvec2(9, 7) | uvec2(0, 10) ];
-                               input vec3 in4          = [ vec3(-1.25, 1.25, -9.5) | vec3(-25.65, -7.25, 14.21) | vec3(0.0, 1.0, -1.0) | vec3(2.25, 2.25, 22.5) | vec3(3.4, 9.5, 19.5) | vec3(16.0, 32.0, -64.0) ];
-                               output vec3 out4        = [ vec3(-1.25, 1.25, -9.5) | vec3(-25.65, -7.25, 14.21) | vec3(0.0, 1.0, -1.0) | vec3(2.25, 2.25, 22.5) | vec3(3.4, 9.5, 19.5) | vec3(16.0, 32.0, -64.0) ];
-                               input vec3 in5          = [ vec3(-1.0, 0.5, 0.0) | vec3(-2.5, 1.5, 14.0) | vec3(0.2, 1.9, -2.0) | vec3(2.6, -0.2, 2.5) | vec3(3.0, -9.5, 1.9) | vec3(8.0, -32.0, 64.0) ];
-                               output vec3 out5        = [ vec3(-1.0, 0.5, 0.0) | vec3(-2.5, 1.5, 14.0) | vec3(0.2, 1.9, -2.0) | vec3(2.6, -0.2, 2.5) | vec3(3.0, -9.5, 1.9) | vec3(8.0, -32.0, 64.0) ];
-                       }
-                       vertex ""
-                               #version 300 es
-                               ${VERTEX_DECLARATIONS}
-                               struct S { mediump float a; highp uvec2 b; highp vec3 c; };
-                               flat out S var[2];
-                               void main()
-                               {
-                                       ${VERTEX_SETUP}
-                                       var[0].a = in0;
-                                       var[1].a = in1;
-
-                                       var[0].b = in2;
-                                       var[1].b = in3;
-
-                                       var[0].c = in4;
-                                       var[1].c = in5;
-                                       ${VERTEX_OUTPUT}
-                               }
-                       ""
-                       fragment ""
-                               #version 300 es
-                               precision mediump float;
-                               ${FRAGMENT_DECLARATIONS}
-                               struct S { mediump float a; highp uvec2 b; highp vec3 c; };
-                               flat in S var[2];
-                               void main()
-                               {
-                                       out0 = var[0].a;
-                                       out1 = var[1].a;
-
-                                       out2 = var[0].b;
-                                       out3 = var[1].b;
-
-                                       out4 = var[0].c;
-                                       out5 = var[1].c;
-                                       ${FRAGMENT_OUTPUT}
-                               }
-                       ""
-               end
        end
 
        group interpolation "Varying interpolation modes"
index ec50a34..db1c81d 100644 (file)
@@ -42,19 +42,14 @@ Excludes:
 
 Description:
 
-This test set compares images rendered by a reference software
-rasterizer to images rendered by the target.
+This test set compares images rendered by the target with the scissor test
+enabled to references generated with the scissor test disabled but with
+areas outside the scissor rectangle cleared by the test logic.
 
-Primitives are tested one at a time with the scissor area in one of the
-above configurations.
+All primitive types are tested in all reasonable scissor configurations
+listed above. Points are tested in a somewhat limited fashion since
+support for point sizes above one is not required.
 
-Color clears are tested by clearing to a color with the scissor test disabled
-and then clearing to a different color with the scissor test enabled in each
-of the above scissor area configurations.
-
-Depth & stencil clears are tested by clearing only the scissor area to a value
-that will permit a subsequent primitive to be rendered in the presence of
-depth/stencil testing.
-
-Framebuffer blitting is tested like clearing but with the last clear replaced
-by a blit.
+After clearing with scissoring enabled, depth and stencil clears disable
+scissoring and render a colored fullscreen quad with depth & stencil
+tests requiring values set by the previous clears to produce the final output.
index d1bf61e..a3317b2 100644 (file)
@@ -61,6 +61,7 @@ static int testResultSeverity (qpTestResult testResult)
 {
        switch (testResult)
        {
+               case QP_TEST_RESULT_LAST:                                       return -1;
                case QP_TEST_RESULT_PASS:                                       return 0;
                case QP_TEST_RESULT_PENDING:                            return 10;
                case QP_TEST_RESULT_NOT_SUPPORTED:                      return 20;
@@ -79,7 +80,7 @@ static int testResultSeverity (qpTestResult testResult)
 ResultCollector::ResultCollector (void)
        : m_log         (DE_NULL)
        , m_prefix      ("")
-       , m_result      (QP_TEST_RESULT_PASS)
+       , m_result      (QP_TEST_RESULT_LAST)
        , m_message ("Pass")
 {
 }
@@ -87,7 +88,7 @@ ResultCollector::ResultCollector (void)
 ResultCollector::ResultCollector (TestLog& log, const std::string& prefix)
        : m_log         (&log)
        , m_prefix      (prefix)
-       , m_result      (QP_TEST_RESULT_PASS)
+       , m_result      (QP_TEST_RESULT_LAST)
        , m_message ("Pass")
 {
 }
@@ -123,7 +124,10 @@ bool ResultCollector::check (bool condition, const std::string& msg)
 
 void ResultCollector::setTestContextResult (TestContext& testCtx)
 {
-       testCtx.setTestResult(m_result, m_message.c_str());
+       if (m_result == QP_TEST_RESULT_LAST)
+               testCtx.setTestResult(QP_TEST_RESULT_PASS, m_message.c_str());
+       else
+               testCtx.setTestResult(m_result, m_message.c_str());
 }
 
 } // tcu
index b948668..de6254a 100644 (file)
@@ -1386,14 +1386,13 @@ bool isLookupResultValid (const Texture1DView& texture, const Sampler& sampler,
        return false;
 }
 
-static bool isSeamlessLinearSampleResultValid (const TextureCubeView&          texture,
-                                                                                          const int                                    levelNdx,
+static bool isSeamlessLinearSampleResultValid (const ConstPixelBufferAccess (&faces)[CUBEFACE_LAST],
                                                                                           const Sampler&                               sampler,
                                                                                           const LookupPrecision&               prec,
                                                                                           const CubeFaceFloatCoords&   coords,
                                                                                           const Vec4&                                  result)
 {
-       const int                                       size                    = texture.getLevelFace(levelNdx, coords.face).getWidth();
+       const int                                       size                    = faces[coords.face].getWidth();
 
        const Vec2                                      uBounds                 = computeNonNormalizedCoordBounds(sampler.normalizedCoords, size, coords.s, prec.coordBits.x(), prec.uvwBits.x());
        const Vec2                                      vBounds                 = computeNonNormalizedCoordBounds(sampler.normalizedCoords, size, coords.t, prec.coordBits.y(), prec.uvwBits.y());
@@ -1404,16 +1403,11 @@ static bool isSeamlessLinearSampleResultValid (const TextureCubeView&           texture,
        const int                                       minJ                    = deFloorFloatToInt32(vBounds.x()-0.5f);
        const int                                       maxJ                    = deFloorFloatToInt32(vBounds.y()-0.5f);
 
-       const TextureChannelClass       texClass                = getTextureChannelClass(texture.getLevelFace(levelNdx, coords.face).getFormat().type);
+       const TextureChannelClass       texClass                = getTextureChannelClass(faces[coords.face].getFormat().type);
        float                                           searchStep              = texClass == TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT  ? computeBilinearSearchStepForUnorm(prec) :
                                                                                                  texClass == TEXTURECHANNELCLASS_SIGNED_FIXED_POINT    ? computeBilinearSearchStepForSnorm(prec) :
                                                                                                  0.0f; // Step is computed for floating-point quads based on texel values.
 
-       // Face accesses
-       ConstPixelBufferAccess faces[CUBEFACE_LAST];
-       for (int face = 0; face < CUBEFACE_LAST; face++)
-               faces[face] = texture.getLevelFace(levelNdx, CubeFace(face));
-
        for (int j = minJ; j <= maxJ; j++)
        {
                for (int i = minI; i <= maxI; i++)
@@ -1451,8 +1445,8 @@ static bool isSeamlessLinearSampleResultValid (const TextureCubeView&             texture,
        return false;
 }
 
-static bool isSeamplessLinearMipmapLinearSampleResultValid (const TextureCubeView&                     texture,
-                                                                                                                       const int                                               baseLevelNdx,
+static bool isSeamplessLinearMipmapLinearSampleResultValid (const ConstPixelBufferAccess       (&faces0)[CUBEFACE_LAST],
+                                                                                                                       const ConstPixelBufferAccess    (&faces1)[CUBEFACE_LAST],
                                                                                                                        const Sampler&                                  sampler,
                                                                                                                        const LookupPrecision&                  prec,
                                                                                                                        const CubeFaceFloatCoords&              coords,
@@ -1462,8 +1456,8 @@ static bool isSeamplessLinearMipmapLinearSampleResultValid (const TextureCubeVie
        // \todo [2013-07-04 pyry] This is strictly not correct as coordinates between levels should be dependent.
        //                                                 Right now this allows pairing any two valid bilinear quads.
 
-       const int                                       size0                   = texture.getLevelFace(baseLevelNdx,    coords.face).getWidth();
-       const int                                       size1                   = texture.getLevelFace(baseLevelNdx+1,  coords.face).getWidth();
+       const int                                       size0                   = faces0[coords.face].getWidth();
+       const int                                       size1                   = faces1[coords.face].getWidth();
 
        const Vec2                                      uBounds0                = computeNonNormalizedCoordBounds(sampler.normalizedCoords, size0,      coords.s, prec.coordBits.x(), prec.uvwBits.x());
        const Vec2                                      uBounds1                = computeNonNormalizedCoordBounds(sampler.normalizedCoords, size1,      coords.s, prec.coordBits.x(), prec.uvwBits.x());
@@ -1480,20 +1474,11 @@ static bool isSeamplessLinearMipmapLinearSampleResultValid (const TextureCubeVie
        const int                                       minJ1                   = deFloorFloatToInt32(vBounds1.x()-0.5f);
        const int                                       maxJ1                   = deFloorFloatToInt32(vBounds1.y()-0.5f);
 
-       const TextureChannelClass       texClass                = getTextureChannelClass(texture.getLevelFace(baseLevelNdx, coords.face).getFormat().type);
+       const TextureChannelClass       texClass                = getTextureChannelClass(faces0[coords.face].getFormat().type);
        const float                                     cSearchStep             = texClass == TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT  ? computeBilinearSearchStepForUnorm(prec) :
                                                                                                  texClass == TEXTURECHANNELCLASS_SIGNED_FIXED_POINT    ? computeBilinearSearchStepForSnorm(prec) :
                                                                                                  0.0f; // Step is computed for floating-point quads based on texel values.
 
-       tcu::ConstPixelBufferAccess faces0[CUBEFACE_LAST];
-       tcu::ConstPixelBufferAccess faces1[CUBEFACE_LAST];
-
-       for (int face = 0; face < CUBEFACE_LAST; face++)
-       {
-               faces0[face] = texture.getLevelFace(baseLevelNdx,       CubeFace(face));
-               faces1[face] = texture.getLevelFace(baseLevelNdx+1,     CubeFace(face));
-       }
-
        for (int j0 = minJ0; j0 <= maxJ0; j0++)
        {
                for (int i0 = minI0; i0 <= maxI0; i0++)
@@ -1571,8 +1556,7 @@ static bool isSeamplessLinearMipmapLinearSampleResultValid (const TextureCubeVie
        return false;
 }
 
-static bool isCubeLevelSampleResultValid (const TextureCubeView&                       texture,
-                                                                                 const int                                                     levelNdx,
+static bool isCubeLevelSampleResultValid (const ConstPixelBufferAccess         (&level)[CUBEFACE_LAST],
                                                                                  const Sampler&                                        sampler,
                                                                                  const Sampler::FilterMode                     filterMode,
                                                                                  const LookupPrecision&                        prec,
@@ -1582,36 +1566,38 @@ static bool isCubeLevelSampleResultValid (const TextureCubeView&                        texture,
        if (filterMode == Sampler::LINEAR)
        {
                if (sampler.seamlessCubeMap)
-                       return isSeamlessLinearSampleResultValid(texture, levelNdx, sampler, prec, coords, result);
+                       return isSeamlessLinearSampleResultValid(level, sampler, prec, coords, result);
                else
-                       return isLinearSampleResultValid(texture.getLevelFace(levelNdx, coords.face), sampler, prec, Vec2(coords.s, coords.t), 0, result);
+                       return isLinearSampleResultValid(level[coords.face], sampler, prec, Vec2(coords.s, coords.t), 0, result);
        }
        else
-               return isNearestSampleResultValid(texture.getLevelFace(levelNdx, coords.face), sampler, prec, Vec2(coords.s, coords.t), 0, result);
+               return isNearestSampleResultValid(level[coords.face], sampler, prec, Vec2(coords.s, coords.t), 0, result);
 }
 
-static bool isCubeMipmapLinearSampleResultValid (const TextureCubeView&                texture,
-                                                                                                const int                                      baseLevelNdx,
-                                                                                                const Sampler&                         sampler,
-                                                                                                const Sampler::FilterMode      levelFilter,
-                                                                                                const LookupPrecision&         prec,
-                                                                                                const CubeFaceFloatCoords&     coords,
-                                                                                                const Vec2&                            fBounds,
-                                                                                                const Vec4&                            result)
+static bool isCubeMipmapLinearSampleResultValid (const ConstPixelBufferAccess  (&faces0)[CUBEFACE_LAST],
+                                                                                               const ConstPixelBufferAccess    (&faces1)[CUBEFACE_LAST],
+                                                                                                const Sampler&                                 sampler,
+                                                                                                const Sampler::FilterMode              levelFilter,
+                                                                                                const LookupPrecision&                 prec,
+                                                                                                const CubeFaceFloatCoords&             coords,
+                                                                                                const Vec2&                                    fBounds,
+                                                                                                const Vec4&                                    result)
 {
        if (levelFilter == Sampler::LINEAR)
        {
                if (sampler.seamlessCubeMap)
-                       return isSeamplessLinearMipmapLinearSampleResultValid(texture, baseLevelNdx, sampler, prec, coords, fBounds, result);
+                       return isSeamplessLinearMipmapLinearSampleResultValid(faces0, faces1, sampler, prec, coords, fBounds, result);
                else
-                       return isLinearMipmapLinearSampleResultValid(texture.getLevelFace(baseLevelNdx,         coords.face),
-                                                                                                                texture.getLevelFace(baseLevelNdx+1,   coords.face),
-                                                                                                                sampler, prec, Vec2(coords.s, coords.t), 0, fBounds, result);
+                       return isLinearMipmapLinearSampleResultValid(faces0[coords.face], faces1[coords.face], sampler, prec, Vec2(coords.s, coords.t), 0, fBounds, result);
        }
        else
-               return isNearestMipmapLinearSampleResultValid(texture.getLevelFace(baseLevelNdx,        coords.face),
-                                                                                                         texture.getLevelFace(baseLevelNdx+1,  coords.face),
-                                                                                                         sampler, prec, Vec2(coords.s, coords.t), 0, fBounds, result);
+               return isNearestMipmapLinearSampleResultValid(faces0[coords.face], faces1[coords.face], sampler, prec, Vec2(coords.s, coords.t), 0, fBounds, result);
+}
+
+static void getCubeLevelFaces (const TextureCubeView& texture, const int levelNdx, ConstPixelBufferAccess (&out)[CUBEFACE_LAST])
+{
+       for (int faceNdx = 0; faceNdx < CUBEFACE_LAST; faceNdx++)
+               out[faceNdx] = texture.getLevelFace(levelNdx, (CubeFace)faceNdx);
 }
 
 bool isLookupResultValid (const TextureCubeView& texture, const Sampler& sampler, const LookupPrecision& prec, const Vec3& coord, const Vec2& lodBounds, const Vec4& result)
@@ -1636,7 +1622,10 @@ bool isLookupResultValid (const TextureCubeView& texture, const Sampler& sampler
 
                if (canBeMagnified)
                {
-                       if (isCubeLevelSampleResultValid(texture, 0, sampler, sampler.magFilter, prec, faceCoords, result))
+                       ConstPixelBufferAccess faces[CUBEFACE_LAST];
+                       getCubeLevelFaces(texture, 0, faces);
+
+                       if (isCubeLevelSampleResultValid(faces, sampler, sampler.magFilter, prec, faceCoords, result))
                                return true;
                }
 
@@ -1651,17 +1640,23 @@ bool isLookupResultValid (const TextureCubeView& texture, const Sampler& sampler
 
                        if (isLinearMipmap && minTexLevel < maxTexLevel)
                        {
-                               const int               minLevel                = de::clamp((int)deFloatFloor(minLod), minTexLevel, maxTexLevel-1);
-                               const int               maxLevel                = de::clamp((int)deFloatFloor(maxLod), minTexLevel, maxTexLevel-1);
+                               const int       minLevel        = de::clamp((int)deFloatFloor(minLod), minTexLevel, maxTexLevel-1);
+                               const int       maxLevel        = de::clamp((int)deFloatFloor(maxLod), minTexLevel, maxTexLevel-1);
 
                                DE_ASSERT(minLevel <= maxLevel);
 
-                               for (int level = minLevel; level <= maxLevel; level++)
+                               for (int levelNdx = minLevel; levelNdx <= maxLevel; levelNdx++)
                                {
-                                       const float             minF    = de::clamp(minLod - float(level), 0.0f, 1.0f);
-                                       const float             maxF    = de::clamp(maxLod - float(level), 0.0f, 1.0f);
+                                       const float                             minF    = de::clamp(minLod - float(levelNdx), 0.0f, 1.0f);
+                                       const float                             maxF    = de::clamp(maxLod - float(levelNdx), 0.0f, 1.0f);
+
+                                       ConstPixelBufferAccess  faces0[CUBEFACE_LAST];
+                                       ConstPixelBufferAccess  faces1[CUBEFACE_LAST];
 
-                                       if (isCubeMipmapLinearSampleResultValid(texture, level, sampler, getLevelFilter(sampler.minFilter), prec, faceCoords, Vec2(minF, maxF), result))
+                                       getCubeLevelFaces(texture, levelNdx,            faces0);
+                                       getCubeLevelFaces(texture, levelNdx + 1,        faces1);
+
+                                       if (isCubeMipmapLinearSampleResultValid(faces0, faces1, sampler, getLevelFilter(sampler.minFilter), prec, faceCoords, Vec2(minF, maxF), result))
                                                return true;
                                }
                        }
@@ -1669,20 +1664,26 @@ bool isLookupResultValid (const TextureCubeView& texture, const Sampler& sampler
                        {
                                // \note The accurate formula for nearest mipmapping is level = ceil(lod + 0.5) - 1 but Khronos has made
                                //               decision to allow floor(lod + 0.5) as well.
-                               const int               minLevel                = de::clamp((int)deFloatCeil(minLod + 0.5f) - 1,        minTexLevel, maxTexLevel);
-                               const int               maxLevel                = de::clamp((int)deFloatFloor(maxLod + 0.5f),           minTexLevel, maxTexLevel);
+                               const int       minLevel        = de::clamp((int)deFloatCeil(minLod + 0.5f) - 1,        minTexLevel, maxTexLevel);
+                               const int       maxLevel        = de::clamp((int)deFloatFloor(maxLod + 0.5f),           minTexLevel, maxTexLevel);
 
                                DE_ASSERT(minLevel <= maxLevel);
 
-                               for (int level = minLevel; level <= maxLevel; level++)
+                               for (int levelNdx = minLevel; levelNdx <= maxLevel; levelNdx++)
                                {
-                                       if (isCubeLevelSampleResultValid(texture, level, sampler, getLevelFilter(sampler.minFilter), prec, faceCoords, result))
+                                       ConstPixelBufferAccess faces[CUBEFACE_LAST];
+                                       getCubeLevelFaces(texture, levelNdx, faces);
+
+                                       if (isCubeLevelSampleResultValid(faces, sampler, getLevelFilter(sampler.minFilter), prec, faceCoords, result))
                                                return true;
                                }
                        }
                        else
                        {
-                               if (isCubeLevelSampleResultValid(texture, 0, sampler, sampler.minFilter, prec, faceCoords, result))
+                               ConstPixelBufferAccess faces[CUBEFACE_LAST];
+                               getCubeLevelFaces(texture, 0, faces);
+
+                               if (isCubeLevelSampleResultValid(faces, sampler, sampler.minFilter, prec, faceCoords, result))
                                        return true;
                        }
                }
@@ -1935,6 +1936,115 @@ bool isLookupResultValid (const Texture3DView& texture, const Sampler& sampler,
        return false;
 }
 
+static void getCubeArrayLevelFaces (const TextureCubeArrayView& texture, const int levelNdx, const int layerNdx, ConstPixelBufferAccess (&out)[CUBEFACE_LAST])
+{
+       const ConstPixelBufferAccess&   level           = texture.getLevel(levelNdx);
+       const int                                               layerDepth      = layerNdx * 6;
+
+       for (int faceNdx = 0; faceNdx < CUBEFACE_LAST; faceNdx++)
+       {
+               const CubeFace face = (CubeFace)faceNdx;
+               out[faceNdx] = getSubregion(level, 0, 0, layerDepth + getCubeArrayFaceIndex(face), level.getWidth(), level.getHeight(), 1);
+       }
+}
+
+bool isLookupResultValid (const TextureCubeArrayView& texture, const Sampler& sampler, const LookupPrecision& prec, const IVec4& coordBits, const Vec4& coord, const Vec2& lodBounds, const Vec4& result)
+{
+       const IVec2     layerRange                                              = computeLayerRange(texture.getNumLayers(), coordBits.w(), coord.w());
+       const Vec3      layerCoord                                              = coord.toWidth<3>();
+       int                     numPossibleFaces                                = 0;
+       CubeFace        possibleFaces[CUBEFACE_LAST];
+
+       DE_ASSERT(isSamplerSupported(sampler));
+
+       getPossibleCubeFaces(layerCoord, prec.coordBits, &possibleFaces[0], numPossibleFaces);
+
+       if (numPossibleFaces == 0)
+               return true; // Result is undefined.
+
+       for (int layerNdx = layerRange.x(); layerNdx <= layerRange.y(); layerNdx++)
+       {
+               for (int tryFaceNdx = 0; tryFaceNdx < numPossibleFaces; tryFaceNdx++)
+               {
+                       const CubeFaceFloatCoords       faceCoords              (possibleFaces[tryFaceNdx], projectToFace(possibleFaces[tryFaceNdx], layerCoord));
+                       const float                                     minLod                  = lodBounds.x();
+                       const float                                     maxLod                  = lodBounds.y();
+                       const bool                                      canBeMagnified  = minLod <= sampler.lodThreshold;
+                       const bool                                      canBeMinified   = maxLod > sampler.lodThreshold;
+
+                       if (canBeMagnified)
+                       {
+                               ConstPixelBufferAccess faces[CUBEFACE_LAST];
+                               getCubeArrayLevelFaces(texture, 0, layerNdx, faces);
+
+                               if (isCubeLevelSampleResultValid(faces, sampler, sampler.magFilter, prec, faceCoords, result))
+                                       return true;
+                       }
+
+                       if (canBeMinified)
+                       {
+                               const bool      isNearestMipmap = isNearestMipmapFilter(sampler.minFilter);
+                               const bool      isLinearMipmap  = isLinearMipmapFilter(sampler.minFilter);
+                               const int       minTexLevel             = 0;
+                               const int       maxTexLevel             = texture.getNumLevels()-1;
+
+                               DE_ASSERT(minTexLevel <= maxTexLevel);
+
+                               if (isLinearMipmap && minTexLevel < maxTexLevel)
+                               {
+                                       const int       minLevel        = de::clamp((int)deFloatFloor(minLod), minTexLevel, maxTexLevel-1);
+                                       const int       maxLevel        = de::clamp((int)deFloatFloor(maxLod), minTexLevel, maxTexLevel-1);
+
+                                       DE_ASSERT(minLevel <= maxLevel);
+
+                                       for (int levelNdx = minLevel; levelNdx <= maxLevel; levelNdx++)
+                                       {
+                                               const float             minF    = de::clamp(minLod - float(levelNdx), 0.0f, 1.0f);
+                                               const float             maxF    = de::clamp(maxLod - float(levelNdx), 0.0f, 1.0f);
+
+                                               ConstPixelBufferAccess  faces0[CUBEFACE_LAST];
+                                               ConstPixelBufferAccess  faces1[CUBEFACE_LAST];
+
+                                               getCubeArrayLevelFaces(texture, levelNdx,               layerNdx,       faces0);
+                                               getCubeArrayLevelFaces(texture, levelNdx + 1,   layerNdx,       faces1);
+
+                                               if (isCubeMipmapLinearSampleResultValid(faces0, faces1, sampler, getLevelFilter(sampler.minFilter), prec, faceCoords, Vec2(minF, maxF), result))
+                                                       return true;
+                                       }
+                               }
+                               else if (isNearestMipmap)
+                               {
+                                       // \note The accurate formula for nearest mipmapping is level = ceil(lod + 0.5) - 1 but Khronos has made
+                                       //               decision to allow floor(lod + 0.5) as well.
+                                       const int       minLevel        = de::clamp((int)deFloatCeil(minLod + 0.5f) - 1,        minTexLevel, maxTexLevel);
+                                       const int       maxLevel        = de::clamp((int)deFloatFloor(maxLod + 0.5f),           minTexLevel, maxTexLevel);
+
+                                       DE_ASSERT(minLevel <= maxLevel);
+
+                                       for (int levelNdx = minLevel; levelNdx <= maxLevel; levelNdx++)
+                                       {
+                                               ConstPixelBufferAccess faces[CUBEFACE_LAST];
+                                               getCubeArrayLevelFaces(texture, levelNdx, layerNdx, faces);
+
+                                               if (isCubeLevelSampleResultValid(faces, sampler, getLevelFilter(sampler.minFilter), prec, faceCoords, result))
+                                                       return true;
+                                       }
+                               }
+                               else
+                               {
+                                       ConstPixelBufferAccess faces[CUBEFACE_LAST];
+                                       getCubeArrayLevelFaces(texture, 0, layerNdx, faces);
+
+                                       if (isCubeLevelSampleResultValid(faces, sampler, sampler.minFilter, prec, faceCoords, result))
+                                               return true;
+                               }
+                       }
+               }
+       }
+
+       return false;
+}
+
 Vec4 computeFixedPointThreshold (const IVec4& bits)
 {
        return computeFixedPointError(bits);
index 0e2428d..6f6aaec 100644 (file)
@@ -105,12 +105,13 @@ Vec2              computeCubeLodBoundsFromDerivates       (const Vec3& coord, const Vec3& coordDx,
 
 Vec2           clampLodBounds                                          (const Vec2& lodBounds, const Vec2& lodMinMax, const LodPrecision& prec);
 
-bool           isLookupResultValid                                     (const Texture1DView&           texture, const Sampler& sampler, const LookupPrecision& prec, const float coord, const Vec2& lodBounds, const Vec4& result);
-bool           isLookupResultValid                                     (const Texture2DView&           texture, const Sampler& sampler, const LookupPrecision& prec, const Vec2& coord, const Vec2& lodBounds, const Vec4& result);
-bool           isLookupResultValid                                     (const TextureCubeView&         texture, const Sampler& sampler, const LookupPrecision& prec, const Vec3& coord, const Vec2& lodBounds, const Vec4& result);
-bool           isLookupResultValid                                     (const Texture1DArrayView&      texture, const Sampler& sampler, const LookupPrecision& prec, const Vec2& coord, const Vec2& lodBounds, const Vec4& result);
-bool           isLookupResultValid                                     (const Texture2DArrayView&      texture, const Sampler& sampler, const LookupPrecision& prec, const Vec3& coord, const Vec2& lodBounds, const Vec4& result);
-bool           isLookupResultValid                                     (const Texture3DView&           texture, const Sampler& sampler, const LookupPrecision& prec, const Vec3& coord, const Vec2& lodBounds, const Vec4& result);
+bool           isLookupResultValid                                     (const Texture1DView&                   texture, const Sampler& sampler, const LookupPrecision& prec, const float coord, const Vec2& lodBounds, const Vec4& result);
+bool           isLookupResultValid                                     (const Texture2DView&                   texture, const Sampler& sampler, const LookupPrecision& prec, const Vec2& coord, const Vec2& lodBounds, const Vec4& result);
+bool           isLookupResultValid                                     (const TextureCubeView&                 texture, const Sampler& sampler, const LookupPrecision& prec, const Vec3& coord, const Vec2& lodBounds, const Vec4& result);
+bool           isLookupResultValid                                     (const Texture1DArrayView&              texture, const Sampler& sampler, const LookupPrecision& prec, const Vec2& coord, const Vec2& lodBounds, const Vec4& result);
+bool           isLookupResultValid                                     (const Texture2DArrayView&              texture, const Sampler& sampler, const LookupPrecision& prec, const Vec3& coord, const Vec2& lodBounds, const Vec4& result);
+bool           isLookupResultValid                                     (const Texture3DView&                   texture, const Sampler& sampler, const LookupPrecision& prec, const Vec3& coord, const Vec2& lodBounds, const Vec4& result);
+bool           isLookupResultValid                                     (const TextureCubeArrayView&    texture, const Sampler& sampler, const LookupPrecision& prec, const IVec4& coordBits, const Vec4& coord, const Vec2& lodBounds, const Vec4& result);
 
 bool           isLevel1DLookupResultValid                      (const ConstPixelBufferAccess& access, const Sampler& sampler, TexLookupScaleMode scaleMode, const LookupPrecision& prec, const float coordX, const int coordY, const Vec4& result);
 bool           isLevel1DLookupResultValid                      (const ConstPixelBufferAccess& access, const Sampler& sampler, TexLookupScaleMode scaleMode, const IntLookupPrecision& prec, const float coordX, const int coordY, const IVec4& result);
index 85613e0..13248fa 100644 (file)
@@ -2709,24 +2709,6 @@ static float sampleLevelArrayCubeSeamlessCompare (const ConstPixelBufferAccess*
 
 // Cube map array sampling
 
-static inline int getCubeArrayFaceIndex (CubeFace face)
-{
-       DE_ASSERT((int)face >= 0 && face < CUBEFACE_LAST);
-
-       switch (face)
-       {
-               case CUBEFACE_POSITIVE_X:       return 0;
-               case CUBEFACE_NEGATIVE_X:       return 1;
-               case CUBEFACE_POSITIVE_Y:       return 2;
-               case CUBEFACE_NEGATIVE_Y:       return 3;
-               case CUBEFACE_POSITIVE_Z:       return 4;
-               case CUBEFACE_NEGATIVE_Z:       return 5;
-
-               default:
-                       return -1;
-       }
-}
-
 static inline ConstPixelBufferAccess getCubeArrayFaceAccess (const ConstPixelBufferAccess* const levels, int levelNdx, int slice, CubeFace face)
 {
        const ConstPixelBufferAccess&   level   = levels[levelNdx];
@@ -3515,7 +3497,7 @@ TextureCubeArrayView::TextureCubeArrayView (int numLevels, const ConstPixelBuffe
 {
 }
 
-inline int TextureCubeArrayView::selectSlice (float q) const
+inline int TextureCubeArrayView::selectLayer (float q) const
 {
        DE_ASSERT(m_numLevels > 0 && m_levels);
        DE_ASSERT((m_levels[0].getDepth() % 6) == 0);
@@ -3526,13 +3508,13 @@ inline int TextureCubeArrayView::selectSlice (float q) const
 tcu::Vec4 TextureCubeArrayView::sample (const Sampler& sampler, float s, float t, float r, float q, float lod) const
 {
        const CubeFaceFloatCoords       coords          = getCubeFaceCoords(Vec3(s, t, r));
-       const int                                       slice           = selectSlice(q);
-       const int                                       faceDepth       = (slice * 6) + getCubeArrayFaceIndex(coords.face);
+       const int                                       layer           = selectLayer(q);
+       const int                                       faceDepth       = (layer * 6) + getCubeArrayFaceIndex(coords.face);
 
        DE_ASSERT(sampler.compare == Sampler::COMPAREMODE_NONE);
 
        if (sampler.seamlessCubeMap)
-               return sampleCubeArraySeamless(m_levels, m_numLevels, slice, coords.face, sampler, coords.s, coords.t, lod);
+               return sampleCubeArraySeamless(m_levels, m_numLevels, layer, coords.face, sampler, coords.s, coords.t, lod);
        else
                return sampleLevelArray2D(m_levels, m_numLevels, sampler, coords.s, coords.t, faceDepth, lod);
 }
@@ -3540,35 +3522,35 @@ tcu::Vec4 TextureCubeArrayView::sample (const Sampler& sampler, float s, float t
 float TextureCubeArrayView::sampleCompare (const Sampler& sampler, float ref, float s, float t, float r, float q, float lod) const
 {
        const CubeFaceFloatCoords       coords          = getCubeFaceCoords(Vec3(s, t, r));
-       const int                                       slice           = selectSlice(q);
-       const int                                       faceDepth       = (slice * 6) + getCubeArrayFaceIndex(coords.face);
+       const int                                       layer           = selectLayer(q);
+       const int                                       faceDepth       = (layer * 6) + getCubeArrayFaceIndex(coords.face);
 
        DE_ASSERT(sampler.compare != Sampler::COMPAREMODE_NONE);
 
        if (sampler.seamlessCubeMap)
-               return sampleCubeArraySeamlessCompare(m_levels, m_numLevels, slice, coords.face, sampler, ref, coords.s, coords.t, lod);
+               return sampleCubeArraySeamlessCompare(m_levels, m_numLevels, layer, coords.face, sampler, ref, coords.s, coords.t, lod);
        else
                return sampleLevelArray2DCompare(m_levels, m_numLevels, sampler, ref, coords.s, coords.t, lod, IVec3(0, 0, faceDepth));
 }
 
 // TextureCubeArray
 
-TextureCubeArray::TextureCubeArray (const TextureFormat& format, int size, int numLayers)
+TextureCubeArray::TextureCubeArray (const TextureFormat& format, int size, int depth)
        : TextureLevelPyramid   (format, computeMipPyramidLevels(size))
        , m_size                                (size)
-       , m_numLayers                   (numLayers)
+       , m_depth                               (depth)
        , m_view                                (getNumLevels(), getLevels())
 {
-       DE_ASSERT(m_numLayers % 6 == 0);
+       DE_ASSERT(m_depth % 6 == 0);
 }
 
 TextureCubeArray::TextureCubeArray (const TextureCubeArray& other)
        : TextureLevelPyramid   (other)
        , m_size                                (other.m_size)
-       , m_numLayers                   (other.m_numLayers)
+       , m_depth                               (other.m_depth)
        , m_view                                (getNumLevels(), getLevels())
 {
-       DE_ASSERT(m_numLayers % 6 == 0);
+       DE_ASSERT(m_depth % 6 == 0);
 }
 
 TextureCubeArray& TextureCubeArray::operator= (const TextureCubeArray& other)
@@ -3578,11 +3560,11 @@ TextureCubeArray& TextureCubeArray::operator= (const TextureCubeArray& other)
 
        TextureLevelPyramid::operator=(other);
 
-       m_size          = other.m_size;
-       m_numLayers     = other.m_numLayers;
-       m_view          = TextureCubeArrayView(getNumLevels(), getLevels());
+       m_size  = other.m_size;
+       m_depth = other.m_depth;
+       m_view  = TextureCubeArrayView(getNumLevels(), getLevels());
 
-       DE_ASSERT(m_numLayers % 6 == 0);
+       DE_ASSERT(m_depth % 6 == 0);
 
        return *this;
 }
@@ -3597,7 +3579,7 @@ void TextureCubeArray::allocLevel (int levelNdx)
 
        const int size = getMipPyramidLevelSize(m_size, levelNdx);
 
-       TextureLevelPyramid::allocLevel(levelNdx, size, size, m_numLayers);
+       TextureLevelPyramid::allocLevel(levelNdx, size, size, m_depth);
 }
 
 std::ostream& operator<< (std::ostream& str, TextureFormat::ChannelOrder order)
index 65e160a..43aab89 100644 (file)
@@ -1023,9 +1023,9 @@ class TextureCubeArrayView
 public:
                                                                        TextureCubeArrayView    (int numLevels, const ConstPixelBufferAccess* levels);
 
-       int                                                             getWidth                                (void) const    { return m_numLevels > 0 ? m_levels[0].getWidth()       : 0;    }
-       int                                                             getHeight                               (void) const    { return m_numLevels > 0 ? m_levels[0].getHeight()      : 0;    }
-       int                                                             getNumLayers                    (void) const    { return m_numLevels > 0 ? m_levels[0].getDepth()       : 0;    }
+       int                                                             getSize                                 (void) const    { return m_numLevels > 0 ? m_levels[0].getWidth()       : 0;    }
+       int                                                             getDepth                                (void) const    { return m_numLevels > 0 ? m_levels[0].getDepth()       : 0;    }
+       int                                                             getNumLayers                    (void) const    { return getDepth()     / 6;    }
        int                                                             getNumLevels                    (void) const    { return m_numLevels;                                                                           }
        const ConstPixelBufferAccess&   getLevel                                (int ndx) const { DE_ASSERT(de::inBounds(ndx, 0, m_numLevels)); return m_levels[ndx];   }
        const ConstPixelBufferAccess*   getLevels                               (void) const    { return m_levels;                                                                                      }
@@ -1036,7 +1036,7 @@ public:
        float                                                   sampleCompareOffset             (const Sampler& sampler, float ref, float s, float t, float r, float q, float lod, const IVec2& offset) const;
 
 protected:
-       int                                                             selectSlice                             (float q) const;
+       int                                                             selectLayer                             (float q) const;
 
        int                                                             m_numLevels;
        const ConstPixelBufferAccess*   m_levels;
@@ -1048,12 +1048,12 @@ protected:
 class TextureCubeArray : private TextureLevelPyramid
 {
 public:
-                                                                       TextureCubeArray        (const TextureFormat& format, int size, int numLayers);
+                                                                       TextureCubeArray        (const TextureFormat& format, int size, int depth);
                                                                        TextureCubeArray        (const TextureCubeArray& other);
                                                                        ~TextureCubeArray       (void);
 
-       int                                                             getSize                         (void) const    { return m_size;                }
-       int                                                             getNumLayers            (void) const    { return m_numLayers;   }
+       int                                                             getSize                         (void) const    { return m_size;        }
+       int                                                             getDepth                        (void) const    { return m_depth;       }
 
        void                                                    allocLevel                      (int levelNdx);
 
@@ -1074,7 +1074,7 @@ public:
 
 private:
        int                                                             m_size;
-       int                                                             m_numLayers;
+       int                                                             m_depth;
        TextureCubeArrayView                    m_view;
 };
 
index 391a0c0..abfaa15 100644 (file)
@@ -846,4 +846,22 @@ void computePixelScaleBias (const ConstPixelBufferAccess& access, Vec4& scale, V
        }
 }
 
+int getCubeArrayFaceIndex (CubeFace face)
+{
+       DE_ASSERT((int)face >= 0 && face < CUBEFACE_LAST);
+
+       switch (face)
+       {
+               case CUBEFACE_POSITIVE_X:       return 0;
+               case CUBEFACE_NEGATIVE_X:       return 1;
+               case CUBEFACE_POSITIVE_Y:       return 2;
+               case CUBEFACE_NEGATIVE_Y:       return 3;
+               case CUBEFACE_POSITIVE_Z:       return 4;
+               case CUBEFACE_NEGATIVE_Z:       return 5;
+
+               default:
+                       return -1;
+       }
+}
+
 } // tcu
index 37f7cac..c7a6bcc 100644 (file)
@@ -98,6 +98,8 @@ void  scale                                                   (const PixelBufferAccess& dst, const ConstPixelBufferAccess& sr
 void   estimatePixelValueRange                 (const ConstPixelBufferAccess& access, Vec4& minVal, Vec4& maxVal);
 void   computePixelScaleBias                   (const ConstPixelBufferAccess& access, Vec4& scale, Vec4& bias);
 
+int            getCubeArrayFaceIndex                   (CubeFace face);
+
 //! FP32->U8 with RTE rounding (extremely fast, always accurate).
 inline deUint8 floatToU8 (float fv)
 {
index d454b4c..1d9bca7 100644 (file)
@@ -256,7 +256,7 @@ inline Vector<T, NewSize> Vector<T, Size>::toWidth (void) const
        for (i = 0; i < deMin32(Size, NewSize); i++)
                res.m_data[i] = m_data[i];
        for (; i < NewSize; i++)
-               res.m_data[i] = 0.0f;
+               res.m_data[i] = T(0);
        return res;
 }
 
index 781c17c..00ca7ec 100644 (file)
@@ -77,6 +77,9 @@ inline float smoothStep               (float edge0, float edge1, float x)
        return t * t * (3.0f - 2.0f * t);
 }
 
+inline double mix                      (double x, double y, double a) { return x * (1.0 - a) + y * a; }
+inline double step                     (double edge, double x) { return (x < edge) ? 0.0 : 1.0; }
+
 inline float length                    (float f) { return deFloatAbs(f); }
 inline float distance          (float x, float y) { return deFloatAbs(x - y); }
 inline float dot                       (float x, float y) { return (x * y); }
@@ -209,6 +212,15 @@ Vector<float, Size> mix (const Vector<float, Size>& x, const Vector<float, Size>
        return res;
 }
 
+template <int Size>
+Vector<double, Size> mix (const Vector<double, Size>& x, const Vector<double, Size>& y, double a)
+{
+       Vector<double, Size> res;
+       for (int i = 0; i < Size; i++)
+               res.m_data[i] = deMix(x.m_data[i], y.m_data[i], a);
+       return res;
+}
+
 // Piece-wise compare operators.
 
 template <typename T, int Size>
index 2ef36f2..b6f5487 100644 (file)
@@ -174,7 +174,8 @@ DE_INLINE float             deFloatSmoothStep       (float e0, float e1, float v)
        return t * t * (3.0f - 2.0f * t);
 }
 
-
+DE_INLINE double       deMix                           (double a, double b, double t)  { return a*(1.0-t) + b*t; }
+DE_INLINE double       deStep                          (double limit, double val)              { return (val < limit) ? 0.0 : 1.0; }
 
 /* Comparison functions. */
 
index 8d26da8..1c1174a 100644 (file)
@@ -64,6 +64,7 @@ deMutex deMutex_create (const deMutexAttributes* attributes)
 
 void deMutex_destroy (deMutex mutex)
 {
+       DeleteCriticalSection((CRITICAL_SECTION*)mutex);
        deFree((CRITICAL_SECTION*)mutex);
 }
 
index d595296..94cf919 100644 (file)
@@ -454,29 +454,32 @@ static void initFunctions (glw::Functions* dst, const glw::Functions& src)
                const ExtFuncLoader                                     extFuncLoader   (extFuncMap);
 
                // OES_sample_shading
-               extFuncMap["glMinSampleShadingOES"]             = (glw::GenericFuncType)src.minSampleShading;
+               extFuncMap["glMinSampleShadingOES"]                     = (glw::GenericFuncType)src.minSampleShading;
+
+               // OES_texture_storage_multisample_2d_array
+               extFuncMap["glTexStorage3DMultisampleOES"]      = (glw::GenericFuncType)src.texStorage3DMultisample;
 
                // KHR_blend_equation_advanced
-               extFuncMap["glBlendBarrierKHR"]                 = (glw::GenericFuncType)blendBarrierKHR;
+               extFuncMap["glBlendBarrierKHR"]                         = (glw::GenericFuncType)blendBarrierKHR;
 
                // EXT_tessellation_shader
-               extFuncMap["glPatchParameteriEXT"]              = (glw::GenericFuncType)src.patchParameteri;
+               extFuncMap["glPatchParameteriEXT"]                      = (glw::GenericFuncType)src.patchParameteri;
 
                // EXT_geometry_shader
-               extFuncMap["glFramebufferTextureEXT"]   = (glw::GenericFuncType)src.framebufferTexture;
+               extFuncMap["glFramebufferTextureEXT"]           = (glw::GenericFuncType)src.framebufferTexture;
 
                // KHR_debug
-               extFuncMap["glDebugMessageControlKHR"]  = (glw::GenericFuncType)src.debugMessageControl;
-               extFuncMap["glDebugMessageInsertKHR"]   = (glw::GenericFuncType)src.debugMessageInsert;
-               extFuncMap["glDebugMessageCallbackKHR"] = (glw::GenericFuncType)src.debugMessageCallback;
-               extFuncMap["glGetDebugMessageLogKHR"]   = (glw::GenericFuncType)src.getDebugMessageLog;
-               extFuncMap["glGetPointervKHR"]                  = (glw::GenericFuncType)src.getPointerv;
-               extFuncMap["glPushDebugGroupKHR"]               = (glw::GenericFuncType)src.pushDebugGroup;
-               extFuncMap["glPopDebugGroupKHR"]                = (glw::GenericFuncType)src.popDebugGroup;
-               extFuncMap["glObjectLabelKHR"]                  = (glw::GenericFuncType)src.objectLabel;
-               extFuncMap["glGetObjectLabelKHR"]               = (glw::GenericFuncType)src.getObjectLabel;
-               extFuncMap["glObjectPtrLabelKHR"]               = (glw::GenericFuncType)src.objectPtrLabel;
-               extFuncMap["glGetObjectPtrLabelKHR"]    = (glw::GenericFuncType)src.getObjectPtrLabel;
+               extFuncMap["glDebugMessageControlKHR"]          = (glw::GenericFuncType)src.debugMessageControl;
+               extFuncMap["glDebugMessageInsertKHR"]           = (glw::GenericFuncType)src.debugMessageInsert;
+               extFuncMap["glDebugMessageCallbackKHR"]         = (glw::GenericFuncType)src.debugMessageCallback;
+               extFuncMap["glGetDebugMessageLogKHR"]           = (glw::GenericFuncType)src.getDebugMessageLog;
+               extFuncMap["glGetPointervKHR"]                          = (glw::GenericFuncType)src.getPointerv;
+               extFuncMap["glPushDebugGroupKHR"]                       = (glw::GenericFuncType)src.pushDebugGroup;
+               extFuncMap["glPopDebugGroupKHR"]                        = (glw::GenericFuncType)src.popDebugGroup;
+               extFuncMap["glObjectLabelKHR"]                          = (glw::GenericFuncType)src.objectLabel;
+               extFuncMap["glGetObjectLabelKHR"]                       = (glw::GenericFuncType)src.getObjectLabel;
+               extFuncMap["glObjectPtrLabelKHR"]                       = (glw::GenericFuncType)src.objectPtrLabel;
+               extFuncMap["glGetObjectPtrLabelKHR"]            = (glw::GenericFuncType)src.getObjectPtrLabel;
 
                {
                        int     numExts = 0;
index 69baf30..d77baec 100644 (file)
@@ -305,7 +305,6 @@ dst->getActiveAtomicCounterBufferiv                 = src.getActiveAtomicCounterBufferiv;
 dst->bindImageTexture                                          = src.bindImageTexture;
 dst->memoryBarrier                                                     = src.memoryBarrier;
 dst->texStorage2DMultisample                           = src.texStorage2DMultisample;
-dst->texStorage3DMultisample                           = src.texStorage3DMultisample;
 dst->getMultisamplefv                                          = src.getMultisamplefv;
 dst->sampleMaski                                                       = src.sampleMaski;
 dst->getTexLevelParameteriv                                    = src.getTexLevelParameteriv;
index 134293b..c29b310 100644 (file)
@@ -86,6 +86,7 @@ template<ObjectType Type> class TypedObjectWrapper : public ObjectWrapper
 {
 public:
        explicit        TypedObjectWrapper (const RenderContext& context) : ObjectWrapper(context.getFunctions(), objectTraits(Type)) {}
+       explicit        TypedObjectWrapper (const glw::Functions& gl) : ObjectWrapper(gl, objectTraits(Type)) {}
 };
 
 /*--------------------------------------------------------------------*//*!
@@ -120,6 +121,7 @@ template<ObjectType Type> class TypedObjectVector : public ObjectVector
 {
 public:
        explicit        TypedObjectVector (const RenderContext& context, size_t numObjects = 0) : ObjectVector(context.getFunctions(), objectTraits(Type), numObjects) {}
+       explicit        TypedObjectVector (const glw::Functions& gl, size_t numObjects = 0) : ObjectVector(gl, objectTraits(Type), numObjects) {}
 };
 
 // Typedefs for simple wrappers without functionality.
index 112eea1..db1eb44 100644 (file)
@@ -130,6 +130,17 @@ static tcu::CubeFace texTargetToFace (Framebuffer::TexTarget target)
        }
 }
 
+static Framebuffer::TexTarget texLayeredTypeToTarget (Texture::Type type)
+{
+       switch (type)
+       {
+               case Texture::TYPE_2D_ARRAY:            return Framebuffer::TEXTARGET_2D_ARRAY;
+               case Texture::TYPE_3D:                          return Framebuffer::TEXTARGET_3D;
+               case Texture::TYPE_CUBE_MAP_ARRAY:      return Framebuffer::TEXTARGET_CUBE_MAP_ARRAY;
+               default:                                                        return Framebuffer::TEXTARGET_LAST;
+       }
+}
+
 static tcu::CubeFace mapGLCubeFace (deUint32 face)
 {
        switch (face)
@@ -2029,10 +2040,11 @@ void ReferenceContext::framebufferTextureLayer (deUint32 target, deUint32 attach
                        RC_IF_ERROR(!texObj,            GL_INVALID_OPERATION,   RC_RET_VOID);
                        RC_IF_ERROR(level != 0,         GL_INVALID_VALUE,               RC_RET_VOID); // \todo [2012-03-19 pyry] We should allow other levels as well.
 
-                       RC_IF_ERROR(texObj->getType() != Texture::TYPE_2D_ARRAY &&
-                                               texObj->getType() != Texture::TYPE_3D,                                  GL_INVALID_OPERATION,   RC_RET_VOID);
+                       RC_IF_ERROR(texObj->getType() != Texture::TYPE_2D_ARRAY                 &&
+                                               texObj->getType() != Texture::TYPE_3D                           &&
+                                               texObj->getType() != Texture::TYPE_CUBE_MAP_ARRAY,                              GL_INVALID_OPERATION,   RC_RET_VOID);
 
-                       if (texObj->getType() == Texture::TYPE_2D_ARRAY)
+                       if (texObj->getType() == Texture::TYPE_2D_ARRAY || texObj->getType() == Texture::TYPE_CUBE_MAP_ARRAY)
                        {
                                RC_IF_ERROR((layer < 0) || (layer >= GL_MAX_ARRAY_TEXTURE_LAYERS),              GL_INVALID_VALUE,               RC_RET_VOID);
                                RC_IF_ERROR((level < 0) || (level > tcu::log2(GL_MAX_TEXTURE_SIZE)),    GL_INVALID_VALUE,               RC_RET_VOID);
@@ -2053,10 +2065,12 @@ void ReferenceContext::framebufferTextureLayer (deUint32 target, deUint32 attach
                {
                        fboAttachment.type                      = Framebuffer::ATTACHMENTTYPE_TEXTURE;
                        fboAttachment.name                      = texObj->getName();
-                       fboAttachment.texTarget         = texObj->getType() == Texture::TYPE_2D_ARRAY ? Framebuffer::TEXTARGET_2D_ARRAY : Framebuffer::TEXTARGET_3D;
+                       fboAttachment.texTarget         = texLayeredTypeToTarget(texObj->getType());
                        fboAttachment.level                     = level;
                        fboAttachment.layer                     = layer;
 
+                       DE_ASSERT(fboAttachment.texTarget != Framebuffer::TEXTARGET_LAST);
+
                        for (int ndx = 0; ndx < bindingRefCount; ndx++)
                                acquireFboAttachmentReference(fboAttachment);
                }
@@ -2181,6 +2195,14 @@ deUint32 ReferenceContext::checkFramebufferStatus (deUint32 target)
                                if (tex3D->hasLevel(attachment.level))
                                        level = tex3D->getLevel(attachment.level); // \note Slice doesn't matter here.
                        }
+                       else if (attachment.texTarget == Framebuffer::TEXTARGET_CUBE_MAP_ARRAY)
+                       {
+                               DE_ASSERT(texture->getType() == Texture::TYPE_CUBE_MAP_ARRAY);
+                               const TextureCubeArray* texCubeArr = static_cast<const TextureCubeArray*>(texture);
+
+                               if (texCubeArr->hasLevel(attachment.level))
+                                       level = texCubeArr->getLevel(attachment.level); // \note Slice doesn't matter here.
+                       }
                        else
                                TCU_FAIL("Framebuffer attached to a texture but no valid target specified");
 
@@ -2299,11 +2321,18 @@ tcu::PixelBufferAccess ReferenceContext::getFboAttachment (const rc::Framebuffer
                                return dynamic_cast<Texture2D*>(texture)->getLevel(attachment.level);
                        else if (texture->getType() == Texture::TYPE_CUBE_MAP)
                                return dynamic_cast<TextureCube*>(texture)->getFace(attachment.level, texTargetToFace(attachment.texTarget));
-                       else if (texture->getType() == Texture::TYPE_2D_ARRAY || texture->getType() == Texture::TYPE_3D)
+                       else if (texture->getType() == Texture::TYPE_2D_ARRAY   ||
+                                        texture->getType() == Texture::TYPE_3D                 ||
+                                        texture->getType() == Texture::TYPE_CUBE_MAP_ARRAY)
                        {
-                               tcu::PixelBufferAccess level = (texture->getType() == Texture::TYPE_2D_ARRAY)
-                                                                                        ? dynamic_cast<Texture2DArray*>(texture)->getLevel(attachment.level)
-                                                                                        : dynamic_cast<Texture3D*>(texture)->getLevel(attachment.level);
+                               tcu::PixelBufferAccess level;
+
+                               if (texture->getType() == Texture::TYPE_2D_ARRAY)
+                                       level = dynamic_cast<Texture2DArray*>(texture)->getLevel(attachment.level);
+                               else if (texture->getType() == Texture::TYPE_3D)
+                                       level = dynamic_cast<Texture3D*>(texture)->getLevel(attachment.level);
+                               else if (texture->getType() == Texture::TYPE_CUBE_MAP_ARRAY)
+                                       level = dynamic_cast<TextureCubeArray*>(texture)->getLevel(attachment.level);
 
                                void* layerData = static_cast<deUint8*>(level.getDataPtr()) + level.getSlicePitch() * attachment.layer;
 
@@ -3794,6 +3823,9 @@ void ReferenceContext::uniform1iv (deInt32 location, deInt32 count, const deInt3
                case glu::TYPE_SAMPLER_3D:
                case glu::TYPE_UINT_SAMPLER_3D:
                case glu::TYPE_INT_SAMPLER_3D:
+               case glu::TYPE_SAMPLER_CUBE_ARRAY:
+               case glu::TYPE_UINT_SAMPLER_CUBE_ARRAY:
+               case glu::TYPE_INT_SAMPLER_CUBE_ARRAY:
                        uniforms[location].value.i = *v;
                        return;
 
@@ -5223,7 +5255,7 @@ tcu::Vec4 TextureCubeArray::sample (float s, float t, float r, float q, float lo
 
 void TextureCubeArray::sample4 (tcu::Vec4 output[4], const tcu::Vec4 packetTexcoords[4], float lodBias) const
 {
-       const int               cubeSide                = m_view.getWidth();
+       const int               cubeSide                = m_view.getSize();
        const tcu::Vec3 cubeCoords[4]   =
        {
                packetTexcoords[0].toWidth<3>(),
index dda593a..e8ed768 100644 (file)
@@ -305,7 +305,6 @@ gl->getActiveAtomicCounterBufferiv          = (glGetActiveAtomicCounterBufferivFunc)                lo
 gl->bindImageTexture                                   = (glBindImageTextureFunc)                                              loader->get("glBindImageTexture");
 gl->memoryBarrier                                              = (glMemoryBarrierFunc)                                                 loader->get("glMemoryBarrier");
 gl->texStorage2DMultisample                            = (glTexStorage2DMultisampleFunc)                               loader->get("glTexStorage2DMultisample");
-gl->texStorage3DMultisample                            = (glTexStorage3DMultisampleFunc)                               loader->get("glTexStorage3DMultisample");
 gl->getMultisamplefv                                   = (glGetMultisamplefvFunc)                                              loader->get("glGetMultisamplefv");
 gl->sampleMaski                                                        = (glSampleMaskiFunc)                                                   loader->get("glSampleMaski");
 gl->getTexLevelParameteriv                             = (glGetTexLevelParameterivFunc)                                loader->get("glGetTexLevelParameteriv");
index 9d6acae..1a7e988 100644 (file)
@@ -142,7 +142,12 @@ void initExtensionsES (Functions* gl, const FunctionLoader* loader, int numExten
 
        if (de::contains(extSet, "GL_OES_sample_shading"))
        {
-               gl->minSampleShading    = (glMinSampleShadingFunc)              loader->get("glMinSampleShadingOES");
+               gl->minSampleShading            = (glMinSampleShadingFunc)                      loader->get("glMinSampleShadingOES");
+       }
+
+       if (de::contains(extSet, "GL_OES_texture_storage_multisample_2d_array"))
+       {
+               gl->texStorage3DMultisample     = (glTexStorage3DMultisampleFunc)       loader->get("glTexStorage3DMultisampleOES");
        }
 
        if (de::contains(extSet, "GL_KHR_debug"))
@@ -153,33 +158,33 @@ void initExtensionsES (Functions* gl, const FunctionLoader* loader, int numExten
                                by this extension must have a "KHR" suffix. When implemented in an
                                OpenGL context, all entry points must have NO suffix, as shown below.
                */
-               gl->debugMessageControl = (glDebugMessageControlFunc)   loader->get("glDebugMessageControlKHR");
-               gl->debugMessageInsert  = (glDebugMessageInsertFunc)    loader->get("glDebugMessageInsertKHR");
-               gl->debugMessageCallback= (glDebugMessageCallbackFunc)  loader->get("glDebugMessageCallbackKHR");
-               gl->getDebugMessageLog  = (glGetDebugMessageLogFunc)    loader->get("glGetDebugMessageLogKHR");
-               gl->getPointerv                 = (glGetPointervFunc)                   loader->get("glGetPointervKHR");
-               gl->pushDebugGroup              = (glPushDebugGroupFunc)                loader->get("glPushDebugGroupKHR");
-               gl->popDebugGroup               = (glPopDebugGroupFunc)                 loader->get("glPopDebugGroupKHR");
-               gl->objectLabel                 = (glObjectLabelFunc)                   loader->get("glObjectLabelKHR");
-               gl->getObjectLabel              = (glGetObjectLabelFunc)                loader->get("glGetObjectLabelKHR");
-               gl->objectPtrLabel              = (glObjectPtrLabelFunc)                loader->get("glObjectPtrLabelKHR");
-               gl->getObjectPtrLabel   = (glGetObjectPtrLabelFunc)             loader->get("glGetObjectPtrLabelKHR");
+               gl->debugMessageControl         = (glDebugMessageControlFunc)           loader->get("glDebugMessageControlKHR");
+               gl->debugMessageInsert          = (glDebugMessageInsertFunc)            loader->get("glDebugMessageInsertKHR");
+               gl->debugMessageCallback        = (glDebugMessageCallbackFunc)          loader->get("glDebugMessageCallbackKHR");
+               gl->getDebugMessageLog          = (glGetDebugMessageLogFunc)            loader->get("glGetDebugMessageLogKHR");
+               gl->getPointerv                         = (glGetPointervFunc)                           loader->get("glGetPointervKHR");
+               gl->pushDebugGroup                      = (glPushDebugGroupFunc)                        loader->get("glPushDebugGroupKHR");
+               gl->popDebugGroup                       = (glPopDebugGroupFunc)                         loader->get("glPopDebugGroupKHR");
+               gl->objectLabel                         = (glObjectLabelFunc)                           loader->get("glObjectLabelKHR");
+               gl->getObjectLabel                      = (glGetObjectLabelFunc)                        loader->get("glGetObjectLabelKHR");
+               gl->objectPtrLabel                      = (glObjectPtrLabelFunc)                        loader->get("glObjectPtrLabelKHR");
+               gl->getObjectPtrLabel           = (glGetObjectPtrLabelFunc)                     loader->get("glGetObjectPtrLabelKHR");
        }
 
        if (de::contains(extSet, "GL_EXT_tessellation_shader"))
        {
-               gl->patchParameteri             = (glPatchParameteriFunc)               loader->get("glPatchParameteriEXT");
+               gl->patchParameteri                     = (glPatchParameteriFunc)                       loader->get("glPatchParameteriEXT");
        }
 
        if (de::contains(extSet, "GL_EXT_geometry_shader"))
        {
-               gl->framebufferTexture  = (glFramebufferTextureFunc)    loader->get("glFramebufferTextureEXT");
+               gl->framebufferTexture          = (glFramebufferTextureFunc)            loader->get("glFramebufferTextureEXT");
        }
 
        if (de::contains(extSet, "GL_EXT_texture_buffer"))
        {
-               gl->texBuffer                   = (glTexBufferFunc)                             loader->get("glTexBufferEXT");
-               gl->texBufferRange              = (glTexBufferRangeFunc)                loader->get("glTexBufferRangeEXT");
+               gl->texBuffer                           = (glTexBufferFunc)                                     loader->get("glTexBufferEXT");
+               gl->texBufferRange                      = (glTexBufferRangeFunc)                        loader->get("glTexBufferRangeEXT");
        }
 }
 
index 3d3ad4a..dc509a5 100644 (file)
@@ -38,7 +38,31 @@ Win32Platform::Win32Platform (void)
        // Set process priority to lower.
        SetPriorityClass(GetCurrentProcess(), BELOW_NORMAL_PRIORITY_CLASS);
 
-       m_contextFactoryRegistry.registerFactory(new WGLContextFactory(m_instance));
+       {
+               WGLContextFactory* factory = DE_NULL;
+
+               try
+               {
+                       factory = new WGLContextFactory(m_instance);
+               }
+               catch (const std::exception& e)
+               {
+                       print("Warning: WGL not supported: %s\n", e.what());
+               }
+
+               if (factory)
+               {
+                       try
+                       {
+                               m_contextFactoryRegistry.registerFactory(factory);
+                       }
+                       catch (...)
+                       {
+                               delete factory;
+                               throw;
+                       }
+               }
+       }
 
 #if defined(DEQP_SUPPORT_EGL)
        m_nativeDisplayFactoryRegistry.registerFactory(new Win32EGLNativeDisplayFactory(m_instance));
index 7c41335..e18615a 100644 (file)
@@ -37,6 +37,10 @@ namespace rr
 namespace
 {
 
+typedef double ClipFloat; // floating point type used in clipping
+
+typedef tcu::Vector<ClipFloat, 4> ClipVec4;
+
 struct RasterizationInternalBuffers
 {
        std::vector<FragmentPacket>             fragmentPackets;
@@ -148,25 +152,17 @@ namespace cliputil
 /*--------------------------------------------------------------------*//*!
  * \brief Get clipped portion of the second endpoint
  *
- * Calculate the intersection of line segment v0-v1 and a positive clip plane
- * of component componentNdx.
- *
- *//*--------------------------------------------------------------------*/
-float getEdgeEndPositiveClipping (const tcu::Vec4& v0, const tcu::Vec4& v1, int componentNdx)
-{
-       return (v0[componentNdx] - v0.w()) / (-v0.w() + v1.w() + v0[componentNdx] - v1[componentNdx]);
-}
-
-/*--------------------------------------------------------------------*//*!
- * \brief Get clipped portion of the second endpoint
- *
- * Calculate the intersection of line segment v0-v1 and a negative clip plane
- * of component componentNdx.
+ * Calculate the intersection of line segment v0-v1 and a given plane. Line
+ * segment is defined by a pair of one-dimensional homogeneous coordinates.
  *
  *//*--------------------------------------------------------------------*/
-float getEdgeEndNegativeClipping (const tcu::Vec4& v0, const tcu::Vec4& v1, int componentNdx)
+ClipFloat getSegmentVolumeEdgeClip (const ClipFloat v0,
+                                                                       const ClipFloat w0,
+                                                                       const ClipFloat v1,
+                                                                       const ClipFloat w1,
+                                                                       const ClipFloat plane)
 {
-       return (v0[componentNdx] + v0.w()) / (v0.w() - v1.w() + v0[componentNdx] - v1[componentNdx]);
+       return (plane*w0 - v0) / ((v1 - v0) - plane*(w1 - w0));
 }
 
 /*--------------------------------------------------------------------*//*!
@@ -175,111 +171,130 @@ float getEdgeEndNegativeClipping (const tcu::Vec4& v0, const tcu::Vec4& v1, int
  * How much (in [0-1] range) of a line segment v0-v1 would be clipped
  * of the v0 end of the line segment by clipping.
  *//*--------------------------------------------------------------------*/
-float getLineEndpointClipping (const tcu::Vec4& v0, const tcu::Vec4& v1)
+ClipFloat getLineEndpointClipping (const ClipVec4& v0, const ClipVec4& v1)
 {
+       const ClipFloat clipVolumeSize = (ClipFloat)1.0;
+
        if (v0.z() > v0.w())
        {
                // Clip +Z
-               return getEdgeEndPositiveClipping(v0, v1, 2);
+               return getSegmentVolumeEdgeClip(v0.z(), v0.w(), v1.z(), v1.w(), clipVolumeSize);
        }
        else if (v0.z() < -v0.w())
        {
                // Clip -Z
-               return getEdgeEndNegativeClipping(v0, v1, 2);
+               return getSegmentVolumeEdgeClip(v0.z(), v0.w(), v1.z(), v1.w(), -clipVolumeSize);
        }
        else
        {
                // no clipping
-               return 0;
+               return (ClipFloat)0.0;
        }
 }
 
-tcu::Vec2 to2DCartesian(const tcu::Vec4& p)
+ClipVec4 vec4ToClipVec4 (const tcu::Vec4& v)
 {
-       return tcu::Vec2(p.x(), p.y()) / p.w();
+       return ClipVec4((ClipFloat)v.x(), (ClipFloat)v.y(), (ClipFloat)v.z(), (ClipFloat)v.w());
 }
 
-float cross2D(const tcu::Vec2& a, const tcu::Vec2& b)
+tcu::Vec4 clipVec4ToVec4 (const ClipVec4& v)
 {
-       return tcu::cross(tcu::Vec3(a.x(), a.y(), 0), tcu::Vec3(b.x(), b.y(), 0)).z();
+       return tcu::Vec4((float)v.x(), (float)v.y(), (float)v.z(), (float)v.w());
 }
 
 class ClipVolumePlane
 {
 public:
-       virtual bool inClipVolume (const tcu::Vec4& p) const = DE_NULL;
-       virtual float clipEdgeEnd (const tcu::Vec4& v0, const tcu::Vec4& v1) const = DE_NULL;
-       virtual tcu::Vec4 moveToPlane (tcu::Vec4 v) const = DE_NULL;
+       virtual bool            pointInClipVolume                       (const ClipVec4& p) const                                               = 0;
+       virtual ClipFloat       clipLineSegmentEnd                      (const ClipVec4& v0, const ClipVec4& v1) const  = 0;
+       virtual ClipVec4        getLineIntersectionPoint        (const ClipVec4& v0, const ClipVec4& v1) const  = 0;
 };
 
-template <int CompNdx>
-class PosComponentPlane : public ClipVolumePlane
+template <int Sign, int CompNdx>
+class ComponentPlane : public ClipVolumePlane
 {
+       DE_STATIC_ASSERT(Sign == +1 || Sign == -1);
+
 public:
-       bool inClipVolume (const tcu::Vec4& p) const
-       {
-               return p[CompNdx] <= p.w();
-       }
-       float clipEdgeEnd (const tcu::Vec4& v0, const tcu::Vec4& v1) const
-       {
-               return getEdgeEndPositiveClipping(v0, v1, CompNdx);
-       }
-       tcu::Vec4 moveToPlane (tcu::Vec4 p) const
-       {
-               p[CompNdx] = p.w();
-               return p;
-       }
+       bool            pointInClipVolume                       (const ClipVec4& p) const;
+       ClipFloat       clipLineSegmentEnd                      (const ClipVec4& v0, const ClipVec4& v1) const;
+       ClipVec4        getLineIntersectionPoint        (const ClipVec4& v0, const ClipVec4& v1) const;
 };
 
-template <int CompNdx>
-class NegComponentPlane : public ClipVolumePlane
+template <int Sign, int CompNdx>
+bool ComponentPlane<Sign, CompNdx>::pointInClipVolume (const ClipVec4& p) const
 {
-public:
-       bool inClipVolume (const tcu::Vec4& p) const
-       {
-               return p[CompNdx] >= -p.w();
-       }
-       float clipEdgeEnd (const tcu::Vec4& v0, const tcu::Vec4& v1) const
-       {
-               return getEdgeEndNegativeClipping(v0, v1, CompNdx);
-       }
-       tcu::Vec4 moveToPlane (tcu::Vec4 p) const
-       {
-               p[CompNdx] = -p.w();
-               return p;
-       }
-};
+       const ClipFloat clipVolumeSize = (ClipFloat)1.0;
+
+       return (ClipFloat)(Sign * p[CompNdx]) <= clipVolumeSize * p.w();
+}
+
+template <int Sign, int CompNdx>
+ClipFloat ComponentPlane<Sign, CompNdx>::clipLineSegmentEnd (const ClipVec4& v0, const ClipVec4& v1) const
+{
+       const ClipFloat clipVolumeSize = (ClipFloat)1.0;
+
+       return getSegmentVolumeEdgeClip(v0[CompNdx], v0.w(),
+                                                                       v1[CompNdx], v1.w(),
+                                                                       (ClipFloat)Sign * clipVolumeSize);
+}
+
+template <int Sign, int CompNdx>
+ClipVec4 ComponentPlane<Sign, CompNdx>::getLineIntersectionPoint (const ClipVec4& v0, const ClipVec4& v1) const
+{
+       // A point on line might be far away, causing clipping ratio (clipLineSegmentEnd) to become extremely close to 1.0
+       // even if the another point is not on the plane. Prevent clipping ratio from saturating by using points on line
+       // that are (nearly) on this and (nearly) on the opposite plane.
+       const ClipVec4 clippedV0 = tcu::mix(v0, v1, ComponentPlane<+1, CompNdx>().clipLineSegmentEnd(v0, v1));
+       const ClipVec4 clippedV1 = tcu::mix(v0, v1, ComponentPlane<-1, CompNdx>().clipLineSegmentEnd(v0, v1));
 
-typedef PosComponentPlane<0> PosXPlane;
-typedef NegComponentPlane<0> NegXPlane;
-typedef PosComponentPlane<1> PosYPlane;
-typedef NegComponentPlane<1> NegYPlane;
-typedef PosComponentPlane<2> PosZPlane;
-typedef NegComponentPlane<2> NegZPlane;
+       // Find intersection point of line from v0 to v1 and the current plane.
+       return tcu::mix(clippedV0, clippedV1, clipLineSegmentEnd(clippedV0, clippedV1));
+}
 
 struct TriangleVertex
 {
-       tcu::Vec4       position;
-       float           weight[3];              //!< barycentrics
+       ClipVec4        position;
+       ClipFloat       weight[3];              //!< barycentrics
+};
+
+struct SubTriangle
+{
+       TriangleVertex vertices[3];
 };
 
 void clipTriangleOneVertex (std::vector<TriangleVertex>& clippedEdges, const ClipVolumePlane& plane, const TriangleVertex& clipped, const TriangleVertex& v1, const TriangleVertex& v2)
 {
+       const ClipFloat degenerateLimit = (ClipFloat)1.0;
+
        // calc clip pos
-       TriangleVertex mid1, mid2;
+       TriangleVertex  mid1;
+       TriangleVertex  mid2;
+       bool                    outputDegenerate = false;
 
        {
-               const TriangleVertex& inside = v1;
-               const TriangleVertex& outside = clipped;
-                     TriangleVertex& middle = mid1;
+               const TriangleVertex& inside    = v1;
+               const TriangleVertex& outside   = clipped;
+                     TriangleVertex& middle    = mid1;
 
-               const float hitDist = plane.clipEdgeEnd(inside.position, outside.position);
-               DE_ASSERT(de::inRange(hitDist, 0.0f, 1.0f));
+               const ClipFloat hitDist = plane.clipLineSegmentEnd(inside.position, outside.position);
+               DE_ASSERT(hitDist >= (ClipFloat)0.0);
+
+               if (hitDist >= degenerateLimit)
+               {
+                       // do not generate degenerate triangles
+                       outputDegenerate = true;
+               }
+               else
+               {
+                       const ClipVec4 approximatedClipPoint    = tcu::mix(inside.position, outside.position, hitDist);
+                       const ClipVec4 anotherPointOnLine               = (hitDist > (ClipFloat)0.5) ? (inside.position) : (outside.position);
 
-               middle.position = plane.moveToPlane(tcu::mix(inside.position, outside.position, hitDist));
-               middle.weight[0] = tcu::mix(inside.weight[0], outside.weight[0], hitDist);
-               middle.weight[1] = tcu::mix(inside.weight[1], outside.weight[1], hitDist);
-               middle.weight[2] = tcu::mix(inside.weight[2], outside.weight[2], hitDist);
+                       middle.position = plane.getLineIntersectionPoint(approximatedClipPoint, anotherPointOnLine);
+                       middle.weight[0] = tcu::mix(inside.weight[0], outside.weight[0], hitDist);
+                       middle.weight[1] = tcu::mix(inside.weight[1], outside.weight[1], hitDist);
+                       middle.weight[2] = tcu::mix(inside.weight[2], outside.weight[2], hitDist);
+               }
        }
 
        {
@@ -287,39 +302,75 @@ void clipTriangleOneVertex (std::vector<TriangleVertex>& clippedEdges, const Cli
                const TriangleVertex& outside = clipped;
                      TriangleVertex& middle = mid2;
 
-               const float hitDist = plane.clipEdgeEnd(inside.position, outside.position);
-               DE_ASSERT(de::inRange(hitDist, 0.0f, 1.0f));
+               const ClipFloat hitDist = plane.clipLineSegmentEnd(inside.position, outside.position);
+               DE_ASSERT(hitDist >= (ClipFloat)0.0);
 
-               middle.position = plane.moveToPlane(tcu::mix(inside.position, outside.position, hitDist));
-               middle.weight[0] = tcu::mix(inside.weight[0], outside.weight[0], hitDist);
-               middle.weight[1] = tcu::mix(inside.weight[1], outside.weight[1], hitDist);
-               middle.weight[2] = tcu::mix(inside.weight[2], outside.weight[2], hitDist);
+               if (hitDist >= degenerateLimit)
+               {
+                       // do not generate degenerate triangles
+                       outputDegenerate = true;
+               }
+               else
+               {
+                       const ClipVec4 approximatedClipPoint    = tcu::mix(inside.position, outside.position, hitDist);
+                       const ClipVec4 anotherPointOnLine               = (hitDist > (ClipFloat)0.5) ? (inside.position) : (outside.position);
+
+                       middle.position = plane.getLineIntersectionPoint(approximatedClipPoint, anotherPointOnLine);
+                       middle.weight[0] = tcu::mix(inside.weight[0], outside.weight[0], hitDist);
+                       middle.weight[1] = tcu::mix(inside.weight[1], outside.weight[1], hitDist);
+                       middle.weight[2] = tcu::mix(inside.weight[2], outside.weight[2], hitDist);
+               }
        }
 
-       // gen quad (v1) -> mid1 -> mid2 -> (v2)
-       clippedEdges.push_back(v1);
-       clippedEdges.push_back(mid1);
-       clippedEdges.push_back(mid2);
-       clippedEdges.push_back(v2);
+       if (!outputDegenerate)
+       {
+               // gen quad (v1) -> mid1 -> mid2 -> (v2)
+               clippedEdges.push_back(v1);
+               clippedEdges.push_back(mid1);
+               clippedEdges.push_back(mid2);
+               clippedEdges.push_back(v2);
+       }
+       else
+       {
+               // don't modify
+               clippedEdges.push_back(v1);
+               clippedEdges.push_back(clipped);
+               clippedEdges.push_back(v2);
+       }
 }
 
 void clipTriangleTwoVertices (std::vector<TriangleVertex>& clippedEdges, const ClipVolumePlane& plane, const TriangleVertex& v0, const TriangleVertex& clipped1, const TriangleVertex& clipped2)
 {
+       const ClipFloat degenerateLimit = (ClipFloat)1.0;
+
        // calc clip pos
-       TriangleVertex mid1, mid2;
+       TriangleVertex  mid1;
+       TriangleVertex  mid2;
+       bool                    outputDegenerate = false;
 
        {
                const TriangleVertex& inside = v0;
                const TriangleVertex& outside = clipped1;
                      TriangleVertex& middle = mid1;
 
-               const float hitDist = plane.clipEdgeEnd(inside.position, outside.position);
-               DE_ASSERT(de::inRange(hitDist, 0.0f, 1.0f));
+               const ClipFloat hitDist = plane.clipLineSegmentEnd(inside.position, outside.position);
+               DE_ASSERT(hitDist >= (ClipFloat)0.0);
+
+               if (hitDist >= degenerateLimit)
+               {
+                       // do not generate degenerate triangles
+                       outputDegenerate = true;
+               }
+               else
+               {
+                       const ClipVec4 approximatedClipPoint    = tcu::mix(inside.position, outside.position, hitDist);
+                       const ClipVec4 anotherPointOnLine               = (hitDist > (ClipFloat)0.5) ? (inside.position) : (outside.position);
 
-               middle.position = plane.moveToPlane(tcu::mix(inside.position, outside.position, hitDist));
-               middle.weight[0] = tcu::mix(inside.weight[0], outside.weight[0], hitDist);
-               middle.weight[1] = tcu::mix(inside.weight[1], outside.weight[1], hitDist);
-               middle.weight[2] = tcu::mix(inside.weight[2], outside.weight[2], hitDist);
+                       middle.position = plane.getLineIntersectionPoint(approximatedClipPoint, anotherPointOnLine);
+                       middle.weight[0] = tcu::mix(inside.weight[0], outside.weight[0], hitDist);
+                       middle.weight[1] = tcu::mix(inside.weight[1], outside.weight[1], hitDist);
+                       middle.weight[2] = tcu::mix(inside.weight[2], outside.weight[2], hitDist);
+               }
        }
 
        {
@@ -327,26 +378,47 @@ void clipTriangleTwoVertices (std::vector<TriangleVertex>& clippedEdges, const C
                const TriangleVertex& outside = clipped2;
                      TriangleVertex& middle = mid2;
 
-               const float hitDist = plane.clipEdgeEnd(inside.position, outside.position);
-               DE_ASSERT(de::inRange(hitDist, 0.0f, 1.0f));
+               const ClipFloat hitDist = plane.clipLineSegmentEnd(inside.position, outside.position);
+               DE_ASSERT(hitDist >= (ClipFloat)0.0);
+
+               if (hitDist >= degenerateLimit)
+               {
+                       // do not generate degenerate triangles
+                       outputDegenerate = true;
+               }
+               else
+               {
+                       const ClipVec4 approximatedClipPoint    = tcu::mix(inside.position, outside.position, hitDist);
+                       const ClipVec4 anotherPointOnLine               = (hitDist > (ClipFloat)0.5) ? (inside.position) : (outside.position);
 
-               middle.position = plane.moveToPlane(tcu::mix(inside.position, outside.position, hitDist));
-               middle.weight[0] = tcu::mix(inside.weight[0], outside.weight[0], hitDist);
-               middle.weight[1] = tcu::mix(inside.weight[1], outside.weight[1], hitDist);
-               middle.weight[2] = tcu::mix(inside.weight[2], outside.weight[2], hitDist);
+                       middle.position = plane.getLineIntersectionPoint(approximatedClipPoint, anotherPointOnLine);
+                       middle.weight[0] = tcu::mix(inside.weight[0], outside.weight[0], hitDist);
+                       middle.weight[1] = tcu::mix(inside.weight[1], outside.weight[1], hitDist);
+                       middle.weight[2] = tcu::mix(inside.weight[2], outside.weight[2], hitDist);
+               }
        }
 
-       // gen triangle (v0) -> mid1 -> mid2
-       clippedEdges.push_back(v0);
-       clippedEdges.push_back(mid1);
-       clippedEdges.push_back(mid2);
+       if (!outputDegenerate)
+       {
+               // gen triangle (v0) -> mid1 -> mid2
+               clippedEdges.push_back(v0);
+               clippedEdges.push_back(mid1);
+               clippedEdges.push_back(mid2);
+       }
+       else
+       {
+               // don't modify
+               clippedEdges.push_back(v0);
+               clippedEdges.push_back(clipped1);
+               clippedEdges.push_back(clipped2);
+       }
 }
 
 void clipTriangleToPlane (std::vector<TriangleVertex>& clippedEdges, const TriangleVertex* vertices, const ClipVolumePlane& plane)
 {
-       const bool v0Clipped = !plane.inClipVolume(vertices[0].position);
-       const bool v1Clipped = !plane.inClipVolume(vertices[1].position);
-       const bool v2Clipped = !plane.inClipVolume(vertices[2].position);
+       const bool v0Clipped = !plane.pointInClipVolume(vertices[0].position);
+       const bool v1Clipped = !plane.pointInClipVolume(vertices[1].position);
+       const bool v2Clipped = !plane.pointInClipVolume(vertices[2].position);
        const int  clipCount = ((v0Clipped) ? (1) : (0)) + ((v1Clipped) ? (1) : (0)) + ((v2Clipped) ? (1) : (0));
 
        if (clipCount == 0)
@@ -380,6 +452,16 @@ void clipTriangleToPlane (std::vector<TriangleVertex>& clippedEdges, const Trian
 
 } // cliputil
 
+tcu::Vec2 to2DCartesian (const tcu::Vec4& p)
+{
+       return tcu::Vec2(p.x(), p.y()) / p.w();
+}
+
+float cross2D (const tcu::Vec2& a, const tcu::Vec2& b)
+{
+       return tcu::cross(tcu::Vec3(a.x(), a.y(), 0.0f), tcu::Vec3(b.x(), b.y(), 0.0f)).z();
+}
+
 void flatshadePrimitiveVertices (pa::Triangle& target, size_t outputNdx)
 {
        const rr::GenericVec4 flatValue = target.getProvokingVertex()->outputs[outputNdx];
@@ -413,123 +495,203 @@ void flatshadeVertices (const Program& program, ContainerType& list)
                                flatshadePrimitiveVertices(*it, inputNdx);
 }
 
-void clipPrimitives (std::vector<pa::Triangle>& list, const Program& program, bool clipWithZPlanes, VertexPacketAllocator& vpalloc)
+/*--------------------------------------------------------------------*//*!
+ * Clip triangles to the clip volume.
+ *//*--------------------------------------------------------------------*/
+void clipPrimitives (std::vector<pa::Triangle>&                list,
+                                        const Program&                                 program,
+                                        bool                                                   clipWithZPlanes,
+                                        VertexPacketAllocator&                 vpalloc)
 {
        using namespace cliputil;
 
-       PosXPlane clipPosX;
-       NegXPlane clipNegX;
-       PosYPlane clipPosY;
-       NegYPlane clipNegY;
-       PosZPlane clipPosZ;
-       NegZPlane clipNegZ;
+       cliputil::ComponentPlane<+1, 0> clipPosX;
+       cliputil::ComponentPlane<-1, 0> clipNegX;
+       cliputil::ComponentPlane<+1, 1> clipPosY;
+       cliputil::ComponentPlane<-1, 1> clipNegY;
+       cliputil::ComponentPlane<+1, 2> clipPosZ;
+       cliputil::ComponentPlane<-1, 2> clipNegZ;
 
        const std::vector<rr::VertexVaryingInfo>&       fragInputs                      = (program.geometryShader) ? (program.geometryShader->getOutputs()) : (program.vertexShader->getOutputs());
-       ClipVolumePlane*                                                        planes[]                        = { &clipPosX, &clipNegX, &clipPosY, &clipNegY, &clipPosZ, &clipNegZ };
+       const ClipVolumePlane*                                          planes[]                        = { &clipPosX, &clipNegX, &clipPosY, &clipNegY, &clipPosZ, &clipNegZ };
        const int                                                                       numPlanes                       = (clipWithZPlanes) ? (6) : (4);
-       std::vector<pa::Triangle>                                       currentTriangles;
 
-       // Move input triangles to modifiable vector
-       currentTriangles.swap(list);
+       std::vector<pa::Triangle>                                       outputTriangles;
 
-       // Clip triangles with every active plane
-       for (int planeNdx = 0; planeNdx < numPlanes; ++planeNdx)
+       for (int inputTriangleNdx = 0; inputTriangleNdx < (int)list.size(); ++inputTriangleNdx)
        {
-               const ClipVolumePlane* plane = planes[planeNdx];
-               std::vector<pa::Triangle> clipped;
+               bool clippedByPlane[6];
 
-               for (size_t ndx = 0; ndx < currentTriangles.size(); ++ndx)
+               // Needs clipping?
                {
-                       pa::Triangle& tri = currentTriangles[ndx];
-                       std::vector<TriangleVertex> clippedVertices;
-
-                       // All vertices clipped by the this clip plane?
-                       if (!plane->inClipVolume(tri.v0->position) &&
-                               !plane->inClipVolume(tri.v1->position) &&
-                               !plane->inClipVolume(tri.v2->position))
-                               continue; // discard
-                       // All vertices not clipped by the this clip plane?
-                       if (plane->inClipVolume(tri.v0->position) &&
-                               plane->inClipVolume(tri.v1->position) &&
-                               plane->inClipVolume(tri.v2->position))
+                       bool discardPrimitive   = false;
+                       bool fullyInClipVolume  = true;
+
+                       for (int planeNdx = 0; planeNdx < numPlanes; ++planeNdx)
                        {
-                               clipped.push_back(tri);
-                               continue; // don't modify
+                               const ClipVolumePlane*  plane                   = planes[planeNdx];
+                               const bool                              v0InsidePlane   = plane->pointInClipVolume(vec4ToClipVec4(list[inputTriangleNdx].v0->position));
+                               const bool                              v1InsidePlane   = plane->pointInClipVolume(vec4ToClipVec4(list[inputTriangleNdx].v1->position));
+                               const bool                              v2InsidePlane   = plane->pointInClipVolume(vec4ToClipVec4(list[inputTriangleNdx].v2->position));
+
+                               // Fully outside
+                               if (!v0InsidePlane && !v1InsidePlane && !v2InsidePlane)
+                               {
+                                       discardPrimitive = true;
+                                       break;
+                               }
+                               // Partially outside
+                               else if (!v0InsidePlane || !v1InsidePlane || !v2InsidePlane)
+                               {
+                                       clippedByPlane[planeNdx] = true;
+                                       fullyInClipVolume = false;
+                               }
+                               // Fully inside
+                               else
+                                       clippedByPlane[planeNdx] = false;
                        }
 
-                       // Clip triangle to the plane
+                       if (discardPrimitive)
+                               continue;
+
+                       if (fullyInClipVolume)
                        {
-                               TriangleVertex vertices[3];
-                               vertices[0].position    = tri.v0->position;     vertices[0].weight[0] = 1;      vertices[0].weight[1] = 0;      vertices[0].weight[2] = 0;
-                               vertices[1].position    = tri.v1->position;     vertices[1].weight[0] = 0;      vertices[1].weight[1] = 1;      vertices[1].weight[2] = 0;
-                               vertices[2].position    = tri.v2->position;     vertices[2].weight[0] = 0;      vertices[2].weight[1] = 0;      vertices[2].weight[2] = 1;
-                               clipTriangleToPlane(clippedVertices, vertices, *plane);
+                               outputTriangles.push_back(list[inputTriangleNdx]);
+                               continue;
                        }
+               }
 
-                       // Triangulate planar convex n-gon
+               // Clip
+               {
+                       std::vector<SubTriangle>        subTriangles    (1);
+                       SubTriangle&                            initialTri              = subTriangles[0];
+
+                       initialTri.vertices[0].position = vec4ToClipVec4(list[inputTriangleNdx].v0->position);
+                       initialTri.vertices[0].weight[0] = (ClipFloat)1.0;
+                       initialTri.vertices[0].weight[1] = (ClipFloat)0.0;
+                       initialTri.vertices[0].weight[2] = (ClipFloat)0.0;
+
+                       initialTri.vertices[1].position = vec4ToClipVec4(list[inputTriangleNdx].v1->position);
+                       initialTri.vertices[1].weight[0] = (ClipFloat)0.0;
+                       initialTri.vertices[1].weight[1] = (ClipFloat)1.0;
+                       initialTri.vertices[1].weight[2] = (ClipFloat)0.0;
+
+                       initialTri.vertices[2].position = vec4ToClipVec4(list[inputTriangleNdx].v2->position);
+                       initialTri.vertices[2].weight[0] = (ClipFloat)0.0;
+                       initialTri.vertices[2].weight[1] = (ClipFloat)0.0;
+                       initialTri.vertices[2].weight[2] = (ClipFloat)1.0;
+
+                       // Clip all subtriangles to all relevant planes
+                       for (int planeNdx = 0; planeNdx < numPlanes; ++planeNdx)
                        {
-                               DE_ASSERT(clippedVertices.size() == 3 || clippedVertices.size() == 4);
+                               std::vector<SubTriangle> nextPhaseSubTriangles;
+
+                               if (!clippedByPlane[planeNdx])
+                                       continue;
 
-                               TriangleVertex& v0 = clippedVertices[0];
-                               for (int triNdx = 1; triNdx + 1 < (int)clippedVertices.size(); ++triNdx)
+                               for (int subTriangleNdx = 0; subTriangleNdx < (int)subTriangles.size(); ++subTriangleNdx)
                                {
-                                       const float degenerateEpsilon = 1.0e-6f;
+                                       std::vector<TriangleVertex> convexPrimitive;
 
-                                       TriangleVertex& v1 = clippedVertices[triNdx];
-                                       TriangleVertex& v2 = clippedVertices[triNdx + 1];
+                                       // Clip triangle and form a convex n-gon ( n c {2, 3} )
+                                       clipTriangleToPlane(convexPrimitive, subTriangles[subTriangleNdx].vertices, *planes[planeNdx]);
 
-                                       // is a degenerate?
-                                       if (de::abs(cross2D(to2DCartesian(v1.position) - to2DCartesian(v0.position), to2DCartesian(v2.position) - to2DCartesian(v0.position))) < degenerateEpsilon)
+                                       // Subtriangle completely discarded
+                                       if (convexPrimitive.empty())
                                                continue;
 
-                                       // Gen clipped triangle
-                                       {
-                                               VertexPacket* p0 = vpalloc.alloc();
-                                               VertexPacket* p1 = vpalloc.alloc();
-                                               VertexPacket* p2 = vpalloc.alloc();
-
-                                               pa::Triangle ngonFragment(p0, p1, p2, -1);
+                                       DE_ASSERT(convexPrimitive.size() == 3 || convexPrimitive.size() == 4);
 
-                                               p0->position = v0.position;
-                                               p1->position = v1.position;
-                                               p2->position = v2.position;
+                                       //Triangulate planar convex n-gon
+                                       {
+                                               TriangleVertex& v0 = convexPrimitive[0];
 
-                                               for (size_t outputNdx = 0; outputNdx < fragInputs.size(); ++outputNdx)
+                                               for (int subsubTriangleNdx = 1; subsubTriangleNdx + 1 < (int)convexPrimitive.size(); ++subsubTriangleNdx)
                                                {
-                                                       if (fragInputs[outputNdx].type == GENERICVECTYPE_FLOAT)
+                                                       const float                             degenerateEpsilon       = 1.0e-6f;
+                                                       const TriangleVertex&   v1                                      = convexPrimitive[subsubTriangleNdx];
+                                                       const TriangleVertex&   v2                                      = convexPrimitive[subsubTriangleNdx + 1];
+                                                       const float                             visibleArea                     = de::abs(cross2D(to2DCartesian(clipVec4ToVec4(v1.position)) - to2DCartesian(clipVec4ToVec4(v0.position)),
+                                                                                                                                                                                 to2DCartesian(clipVec4ToVec4(v2.position)) - to2DCartesian(clipVec4ToVec4(v0.position))));
+
+                                                       // has surface area (is not a degenerate)
+                                                       if (visibleArea >= degenerateEpsilon)
                                                        {
-                                                               const tcu::Vec4 out0 = tri.v0->outputs[outputNdx].get<float>();
-                                                               const tcu::Vec4 out1 = tri.v1->outputs[outputNdx].get<float>();
-                                                               const tcu::Vec4 out2 = tri.v2->outputs[outputNdx].get<float>();
+                                                               SubTriangle subsubTriangle;
 
-                                                               p0->outputs[outputNdx] = v0.weight[0] * out0 + v0.weight[1] * out1 + v0.weight[2] * out2;
-                                                               p1->outputs[outputNdx] = v1.weight[0] * out0 + v1.weight[1] * out1 + v1.weight[2] * out2;
-                                                               p2->outputs[outputNdx] = v2.weight[0] * out0 + v2.weight[1] * out1 + v2.weight[2] * out2;
-                                                       }
-                                                       else
-                                                       {
-                                                               // only floats are interpolated, all others must be flatshaded then
-                                                               p0->outputs[outputNdx] = tri.getProvokingVertex()->outputs[outputNdx];
-                                                               p1->outputs[outputNdx] = tri.getProvokingVertex()->outputs[outputNdx];
-                                                               p2->outputs[outputNdx] = tri.getProvokingVertex()->outputs[outputNdx];
+                                                               subsubTriangle.vertices[0] = v0;
+                                                               subsubTriangle.vertices[1] = v1;
+                                                               subsubTriangle.vertices[2] = v2;
+
+                                                               nextPhaseSubTriangles.push_back(subsubTriangle);
                                                        }
                                                }
+                                       }
+                               }
+
+                               subTriangles.swap(nextPhaseSubTriangles);
+                       }
+
+                       // Rebuild pa::Triangles from subtriangles
+                       for (int subTriangleNdx = 0; subTriangleNdx < (int)subTriangles.size(); ++subTriangleNdx)
+                       {
+                               VertexPacket*   p0                              = vpalloc.alloc();
+                               VertexPacket*   p1                              = vpalloc.alloc();
+                               VertexPacket*   p2                              = vpalloc.alloc();
+                               pa::Triangle    ngonFragment    (p0, p1, p2, -1);
+
+                               p0->position = clipVec4ToVec4(subTriangles[subTriangleNdx].vertices[0].position);
+                               p1->position = clipVec4ToVec4(subTriangles[subTriangleNdx].vertices[1].position);
+                               p2->position = clipVec4ToVec4(subTriangles[subTriangleNdx].vertices[2].position);
+
+                               for (size_t outputNdx = 0; outputNdx < fragInputs.size(); ++outputNdx)
+                               {
+                                       if (fragInputs[outputNdx].type == GENERICVECTYPE_FLOAT)
+                                       {
+                                               const tcu::Vec4 out0 = list[inputTriangleNdx].v0->outputs[outputNdx].get<float>();
+                                               const tcu::Vec4 out1 = list[inputTriangleNdx].v1->outputs[outputNdx].get<float>();
+                                               const tcu::Vec4 out2 = list[inputTriangleNdx].v2->outputs[outputNdx].get<float>();
+
+                                               p0->outputs[outputNdx] = (float)subTriangles[subTriangleNdx].vertices[0].weight[0] * out0
+                                                                                          + (float)subTriangles[subTriangleNdx].vertices[0].weight[1] * out1
+                                                                                          + (float)subTriangles[subTriangleNdx].vertices[0].weight[2] * out2;
+
+                                               p1->outputs[outputNdx] = (float)subTriangles[subTriangleNdx].vertices[1].weight[0] * out0
+                                                                                          + (float)subTriangles[subTriangleNdx].vertices[1].weight[1] * out1
+                                                                                          + (float)subTriangles[subTriangleNdx].vertices[1].weight[2] * out2;
 
-                                               clipped.push_back(ngonFragment);
+                                               p2->outputs[outputNdx] = (float)subTriangles[subTriangleNdx].vertices[2].weight[0] * out0
+                                                                                          + (float)subTriangles[subTriangleNdx].vertices[2].weight[1] * out1
+                                                                                          + (float)subTriangles[subTriangleNdx].vertices[2].weight[2] * out2;
+                                       }
+                                       else
+                                       {
+                                               // only floats are interpolated, all others must be flatshaded then
+                                               p0->outputs[outputNdx] = list[inputTriangleNdx].getProvokingVertex()->outputs[outputNdx];
+                                               p1->outputs[outputNdx] = list[inputTriangleNdx].getProvokingVertex()->outputs[outputNdx];
+                                               p2->outputs[outputNdx] = list[inputTriangleNdx].getProvokingVertex()->outputs[outputNdx];
                                        }
                                }
+
+                               outputTriangles.push_back(ngonFragment);
                        }
                }
-
-               // Clipped triangles are input triangles for next plane
-               currentTriangles.swap(clipped);
        }
 
-       // return clipped in list
-       std::swap(currentTriangles, list);
+       // output result
+       list.swap(outputTriangles);
 }
 
-void clipPrimitives (std::vector<pa::Line>& list, const Program& program, bool clipWithZPlanes, VertexPacketAllocator& vpalloc)
+/*--------------------------------------------------------------------*//*!
+ * Clip lines to the near and far clip planes.
+ *
+ * Clipping to other planes is a by-product of the viewport test  (i.e.
+ * rasterization area selection).
+ *//*--------------------------------------------------------------------*/
+void clipPrimitives (std::vector<pa::Line>&            list,
+                                        const Program&                                 program,
+                                        bool                                                   clipWithZPlanes,
+                                        VertexPacketAllocator&                 vpalloc)
 {
        DE_UNREF(vpalloc);
 
@@ -555,26 +717,21 @@ void clipPrimitives (std::vector<pa::Line>& list, const Program& program, bool c
 
                // Something is visible
 
-               const float             t0      = getLineEndpointClipping(l.v0->position, l.v1->position);
-               const float             t1      = getLineEndpointClipping(l.v1->position, l.v0->position);
-               const tcu::Vec4 vt0     = tcu::Vec4(t0);
-               const tcu::Vec4 vt1     = tcu::Vec4(t1);
+               const ClipVec4  p0      = vec4ToClipVec4(l.v0->position);
+               const ClipVec4  p1      = vec4ToClipVec4(l.v1->position);
+               const ClipFloat t0      = getLineEndpointClipping(p0, p1);
+               const ClipFloat t1      = getLineEndpointClipping(p1, p0);
 
                // Not clipped at all?
-               if (t0 == 0.0f && t1 == 0.0f)
+               if (t0 == (ClipFloat)0.0 && t1 == (ClipFloat)0.0)
                {
                        visibleLines.push_back(pa::Line(l.v0, l.v1, -1));
                }
                else
                {
                        // Clip position
-                       {
-                               const tcu::Vec4 p0 = l.v0->position;
-                               const tcu::Vec4 p1 = l.v1->position;
-
-                               l.v0->position = tcu::mix(p0, p1, vt0);
-                               l.v1->position = tcu::mix(p1, p0, vt1);
-                       }
+                       l.v0->position = clipVec4ToVec4(tcu::mix(p0, p1, t0));
+                       l.v1->position = clipVec4ToVec4(tcu::mix(p1, p0, t1));
 
                        // Clip attributes
                        for (size_t outputNdx = 0; outputNdx < fragInputs.size(); ++outputNdx)
@@ -582,11 +739,11 @@ void clipPrimitives (std::vector<pa::Line>& list, const Program& program, bool c
                                // only floats are clipped, other types are flatshaded
                                if (fragInputs[outputNdx].type == GENERICVECTYPE_FLOAT)
                                {
-                                       const tcu::Vec4 p0 = l.v0->outputs[outputNdx].get<float>();
-                                       const tcu::Vec4 p1 = l.v1->outputs[outputNdx].get<float>();
+                                       const tcu::Vec4 a0 = l.v0->outputs[outputNdx].get<float>();
+                                       const tcu::Vec4 a1 = l.v1->outputs[outputNdx].get<float>();
 
-                                       l.v0->outputs[outputNdx] = tcu::mix(p0, p1, vt0);
-                                       l.v1->outputs[outputNdx] = tcu::mix(p1, p0, vt1);
+                                       l.v0->outputs[outputNdx] = tcu::mix(a0, a1, (float)t0);
+                                       l.v1->outputs[outputNdx] = tcu::mix(a1, a0, (float)t1);
                                }
                        }
 
@@ -598,7 +755,14 @@ void clipPrimitives (std::vector<pa::Line>& list, const Program& program, bool c
        std::swap(visibleLines, list);
 }
 
-void clipPrimitives (std::vector<pa::Point>& list, const Program& program, bool clipWithZPlanes, VertexPacketAllocator& vpalloc)
+/*--------------------------------------------------------------------*//*!
+ * Discard points not within clip volume. Clipping is a by-product
+ * of the viewport test.
+ *//*--------------------------------------------------------------------*/
+void clipPrimitives (std::vector<pa::Point>&           list,
+                                        const Program&                                 program,
+                                        bool                                                   clipWithZPlanes,
+                                        VertexPacketAllocator&                 vpalloc)
 {
        DE_UNREF(vpalloc);
        DE_UNREF(program);
@@ -839,7 +1003,15 @@ static float findPrimitiveMinimumResolvableDifference (const pa::Triangle& trian
        return 0.0f;
 }
 
-void writeFragmentPackets (const RenderState& state, const RenderTarget& renderTarget, const Program& program, const FragmentPacket* fragmentPackets, int numRasterizedPackets, rr::FaceType facetype, const std::vector<rr::GenericVec4>& fragmentOutputArray, const float* depthValues, std::vector<Fragment>& fragmentBuffer)
+void writeFragmentPackets (const RenderState&                                  state,
+                                                  const RenderTarget&                                  renderTarget,
+                                                  const Program&                                               program,
+                                                  const FragmentPacket*                                fragmentPackets,
+                                                  int                                                                  numRasterizedPackets,
+                                                  rr::FaceType                                                 facetype,
+                                                  const std::vector<rr::GenericVec4>&  fragmentOutputArray,
+                                                  const float*                                                 depthValues,
+                                                  std::vector<Fragment>&                               fragmentBuffer)
 {
        const int                       numSamples              = renderTarget.colorBuffers[0].getNumSamples();
        const size_t            numOutputs              = program.fragmentShader->getOutputs().size();
@@ -904,7 +1076,12 @@ void writeFragmentPackets (const RenderState& state, const RenderTarget& renderT
        }
 }
 
-void rasterizePrimitive (const RenderState& state, const RenderTarget& renderTarget, const Program& program, const pa::Triangle& triangle, const tcu::IVec4& renderTargetRect, RasterizationInternalBuffers& buffers)
+void rasterizePrimitive (const RenderState&                                    state,
+                                                const RenderTarget&                            renderTarget,
+                                                const Program&                                         program,
+                                                const pa::Triangle&                            triangle,
+                                                const tcu::IVec4&                                      renderTargetRect,
+                                                RasterizationInternalBuffers&          buffers)
 {
        const int                       numSamples              = renderTarget.colorBuffers[0].getNumSamples();
        const float                     depthClampMin   = de::min(state.viewport.zn, state.viewport.zf);
@@ -967,7 +1144,12 @@ void rasterizePrimitive (const RenderState& state, const RenderTarget& renderTar
        }
 }
 
-void rasterizePrimitive (const RenderState& state, const RenderTarget& renderTarget, const Program& program, const pa::Line& line, const tcu::IVec4& renderTargetRect, RasterizationInternalBuffers& buffers)
+void rasterizePrimitive (const RenderState&                                    state,
+                                                const RenderTarget&                            renderTarget,
+                                                const Program&                                         program,
+                                                const pa::Line&                                        line,
+                                                const tcu::IVec4&                                      renderTargetRect,
+                                                RasterizationInternalBuffers&          buffers)
 {
        const int                                       numSamples                      = renderTarget.colorBuffers[0].getNumSamples();
        const float                                     depthClampMin           = de::min(state.viewport.zn, state.viewport.zf);
@@ -1015,7 +1197,12 @@ void rasterizePrimitive (const RenderState& state, const RenderTarget& renderTar
        }
 }
 
-void rasterizePrimitive (const RenderState& state, const RenderTarget& renderTarget, const Program& program, const pa::Point& point, const tcu::IVec4& renderTargetRect, RasterizationInternalBuffers& buffers)
+void rasterizePrimitive (const RenderState&                                    state,
+                                                const RenderTarget&                            renderTarget,
+                                                const Program&                                         program,
+                                                const pa::Point&                                       point,
+                                                const tcu::IVec4&                                      renderTargetRect,
+                                                RasterizationInternalBuffers&          buffers)
 {
        const int                       numSamples              = renderTarget.colorBuffers[0].getNumSamples();
        const float                     depthClampMin   = de::min(state.viewport.zn, state.viewport.zf);
@@ -1076,7 +1263,10 @@ void rasterizePrimitive (const RenderState& state, const RenderTarget& renderTar
 }
 
 template <typename ContainerType>
-void rasterize (const RenderState& state, const RenderTarget& renderTarget, const Program& program, const ContainerType& list)
+void rasterize (const RenderState&                                     state,
+                               const RenderTarget&                                     renderTarget,
+                               const Program&                                          program,
+                               const ContainerType&                            list)
 {
        const int                                               numSamples                      = renderTarget.colorBuffers[0].getNumSamples();
        const int                                               numFragmentOutputs      = (int)program.fragmentShader->getOutputs().size();
@@ -1095,7 +1285,7 @@ void rasterize (const RenderState& state, const RenderTarget& renderTarget, cons
 
        RasterizationInternalBuffers    buffers;
 
-       // don't calculate depth if it is not used
+       // calculate depth only if we have a depth buffer
        if (!isEmpty(renderTarget.depthBuffer))
        {
                depthValues.resize(maxFragmentPackets*4*numSamples);
@@ -1174,7 +1364,7 @@ void copyVertexPacketPointers(const VertexPacket** dst, const pa::TriangleAdjace
 }
 
 template <PrimitiveType DrawPrimitiveType> // \note DrawPrimitiveType  can only be Points, line_strip, or triangle_strip
-void drawGeometryShaderOutputAsPrimitives(const RenderState& state, const RenderTarget& renderTarget, const Program& program, VertexPacket* const* vertices, size_t numVertices, VertexPacketAllocator& vpalloc)
+void drawGeometryShaderOutputAsPrimitives (const RenderState& state, const RenderTarget& renderTarget, const Program& program, VertexPacket* const* vertices, size_t numVertices, VertexPacketAllocator& vpalloc)
 {
        // Run primitive assembly for generated stream
 
index 49ebd96..9256e08 100644 (file)
@@ -55,7 +55,7 @@ using std::vector;
 using std::string;
 using tcu::TestLog;
 using tcu::Vec2;
-using deqp::gls::theilSenEstimator;
+using deqp::gls::theilSenLinearRegression;
 using deqp::gls::LineParameters;
 
 namespace
@@ -356,8 +356,8 @@ void FlushFinishCase::analyzeResults (const std::vector<Sample>& samples, const
 {
        const vector<Vec2>              waitTimes               = getPointsFromSamples(samples, &Sample::waitTime);
        const vector<Vec2>              readTimes               = getPointsFromSamples(samples, &Sample::readPixelsTime);
-       const LineParameters    waitLine                = theilSenEstimator(waitTimes);
-       const LineParameters    readLine                = theilSenEstimator(readTimes);
+       const LineParameters    waitLine                = theilSenLinearRegression(waitTimes);
+       const LineParameters    readLine                = theilSenLinearRegression(readTimes);
        const float                             normWaitCoef    = waitLine.coefficient * float(calibrationParams.maxDrawCalls) / float(MAX_SAMPLE_DURATION_US);
        const float                             normReadCoef    = readLine.coefficient * float(calibrationParams.maxDrawCalls) / float(MAX_SAMPLE_DURATION_US);
        bool                                    allOk                   = true;
index f102b87..288ff51 100644 (file)
@@ -48,52 +48,52 @@ ScissorTests::~ScissorTests (void)
 void ScissorTests::init (void)
 {
        using tcu::Vec4;
-       typedef gls::Functional::ScissorCase SC;
+       using namespace gls::Functional::ScissorTestInternal;
 
-       glu::RenderContext&             rc = m_context.getRenderContext();
        tcu::TestContext&               tc = m_context.getTestContext();
+       glu::RenderContext&             rc = m_context.getRenderContext();
 
        const struct
        {
-               const char*                     name;
-               const char*                     description;
-               const tcu::Vec4         scissor;
-               const tcu::Vec4         render;
-               SC::PrimitiveType       type;
-               const int                       primitives;
+               const char*             name;
+               const char*             desc;
+               const tcu::Vec4 scissor;
+               const tcu::Vec4 render;
+               PrimitiveType   type;
+               const int               primitives;
        } cases[] =
        {
-               { "contained_tris",                     "Triangles fully inside scissor area (single call)",            Vec4(0.1f, 0.1f, 0.8f, 0.8f), Vec4(0.2f, 0.2f, 0.6f, 0.6f), SC::TRIANGLE,       30 },
-               { "partial_tris",                       "Triangles partially inside scissor area (single call)",        Vec4(0.3f, 0.3f, 0.4f, 0.4f), Vec4(0.2f, 0.2f, 0.6f, 0.6f), SC::TRIANGLE,       30 },
-               { "contained_tri",                      "Triangle fully inside scissor area",                                           Vec4(0.1f, 0.1f, 0.8f, 0.8f), Vec4(0.2f, 0.2f, 0.6f, 0.6f), SC::TRIANGLE,       1  },
-               { "enclosing_tri",                      "Triangle fully covering scissor area",                                         Vec4(0.4f, 0.4f, 0.2f, 0.2f), Vec4(0.2f, 0.2f, 0.6f, 0.6f), SC::TRIANGLE,       1  },
-               { "partial_tri",                        "Triangle partially inside scissor area",                                       Vec4(0.4f, 0.4f, 0.6f, 0.6f), Vec4(0.0f, 0.0f, 1.0f, 1.0f), SC::TRIANGLE,       1  },
-               { "outside_render_tri",         "Triangle with scissor area outside render target",                     Vec4(1.4f, 1.4f, 0.6f, 0.6f), Vec4(0.0f, 0.0f, 0.6f, 0.6f), SC::TRIANGLE,       1  },
-               { "partial_lines",                      "Linse partially inside scissor area",                                          Vec4(0.4f, 0.4f, 0.6f, 0.6f), Vec4(0.0f, 0.0f, 1.0f, 1.0f), SC::LINE,           30 },
-               { "contained_line",                     "Line fully inside scissor area",                                                       Vec4(0.1f, 0.1f, 0.8f, 0.8f), Vec4(0.2f, 0.2f, 0.6f, 0.6f), SC::LINE,           1  },
-               { "partial_line",                       "Line partially inside scissor area",                                           Vec4(0.4f, 0.4f, 0.6f, 0.6f), Vec4(0.0f, 0.0f, 1.0f, 1.0f), SC::LINE,           1  },
-               { "outside_render_line",        "Line with scissor area outside render target",                         Vec4(1.4f, 1.4f, 0.6f, 0.6f), Vec4(0.0f, 0.0f, 0.6f, 0.6f), SC::LINE,           1  },
-               { "contained_point",            "Point fully inside scissor area",                                                      Vec4(0.1f, 0.1f, 0.8f, 0.8f), Vec4(0.5f, 0.5f, 0.0f, 0.0f), SC::POINT,          1  },
-               { "partial_points",                     "Points partially inside scissor area",                                         Vec4(0.4f, 0.4f, 0.6f, 0.6f), Vec4(0.0f, 0.0f, 1.0f, 1.0f), SC::POINT,          30 },
-               { "outside_point",                      "Point fully outside scissor area",                                                     Vec4(0.4f, 0.4f, 0.6f, 0.6f), Vec4(0.0f, 0.0f, 0.0f, 0.0f), SC::POINT,          1  },
-               { "outside_render_point",       "Point with scissor area outside render target",                        Vec4(1.4f, 1.4f, 0.6f, 0.6f), Vec4(0.5f, 0.5f, 0.0f, 0.0f),     SC::POINT,              1  }
+               { "contained_tris",                     "Triangles fully inside scissor area (single call)",            Vec4(0.1f, 0.1f, 0.8f, 0.8f), Vec4(0.2f, 0.2f, 0.6f, 0.6f), TRIANGLE,   30 },
+               { "partial_tris",                       "Triangles partially inside scissor area (single call)",        Vec4(0.3f, 0.3f, 0.4f, 0.4f), Vec4(0.2f, 0.2f, 0.6f, 0.6f), TRIANGLE,   30 },
+               { "contained_tri",                      "Triangle fully inside scissor area",                                           Vec4(0.1f, 0.1f, 0.8f, 0.8f), Vec4(0.2f, 0.2f, 0.6f, 0.6f), TRIANGLE,   1  },
+               { "enclosing_tri",                      "Triangle fully covering scissor area",                                         Vec4(0.4f, 0.4f, 0.2f, 0.2f), Vec4(0.2f, 0.2f, 0.6f, 0.6f), TRIANGLE,   1  },
+               { "partial_tri",                        "Triangle partially inside scissor area",                                       Vec4(0.4f, 0.4f, 0.6f, 0.6f), Vec4(0.0f, 0.0f, 1.0f, 1.0f), TRIANGLE,   1  },
+               { "outside_render_tri",         "Triangle with scissor area outside render target",                     Vec4(1.4f, 1.4f, 0.6f, 0.6f), Vec4(0.0f, 0.0f, 0.6f, 0.6f), TRIANGLE,   1  },
+               { "partial_lines",                      "Linse partially inside scissor area",                                          Vec4(0.4f, 0.4f, 0.6f, 0.6f), Vec4(0.0f, 0.0f, 1.0f, 1.0f), LINE,               30 },
+               { "contained_line",                     "Line fully inside scissor area",                                                       Vec4(0.1f, 0.1f, 0.8f, 0.8f), Vec4(0.2f, 0.2f, 0.6f, 0.6f), LINE,               1  },
+               { "partial_line",                       "Line partially inside scissor area",                                           Vec4(0.4f, 0.4f, 0.6f, 0.6f), Vec4(0.0f, 0.0f, 1.0f, 1.0f), LINE,               1  },
+               { "outside_render_line",        "Line with scissor area outside render target",                         Vec4(1.4f, 1.4f, 0.6f, 0.6f), Vec4(0.0f, 0.0f, 0.6f, 0.6f), LINE,               1  },
+               { "contained_point",            "Point fully inside scissor area",                                                      Vec4(0.1f, 0.1f, 0.8f, 0.8f), Vec4(0.5f, 0.5f, 0.0f, 0.0f), POINT,              1  },
+               { "partial_points",                     "Points partially inside scissor area",                                         Vec4(0.4f, 0.4f, 0.6f, 0.6f), Vec4(0.0f, 0.0f, 1.0f, 1.0f), POINT,              30 },
+               { "outside_point",                      "Point fully outside scissor area",                                                     Vec4(0.4f, 0.4f, 0.6f, 0.6f), Vec4(0.0f, 0.0f, 0.0f, 0.0f), POINT,              1  },
+               { "outside_render_point",       "Point with scissor area outside render target",                        Vec4(1.4f, 1.4f, 0.6f, 0.6f), Vec4(0.5f, 0.5f, 0.0f, 0.0f),     POINT,          1  }
        };
 
        for(int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(cases); caseNdx++)
        {
-               addChild(SC::createPrimitiveTest(rc,
-                                                                                tc,
-                                                                                cases[caseNdx].scissor,
-                                                                                cases[caseNdx].render,
-                                                                                cases[caseNdx].type,
-                                                                                cases[caseNdx].primitives,
-                                                                                cases[caseNdx].name,
-                                                                                cases[caseNdx].description));
+               addChild(createPrimitiveTest(tc,
+                                                                        rc,
+                                                                        cases[caseNdx].name,
+                                                                        cases[caseNdx].desc,
+                                                                        cases[caseNdx].scissor,
+                                                                        cases[caseNdx].render,
+                                                                        cases[caseNdx].type,
+                                                                        cases[caseNdx].primitives));
        }
 
-       addChild(SC::createClearTest(rc, tc, Vec4(0.1f, 0.1f, 0.8f, 0.8f), GL_DEPTH_BUFFER_BIT,         "clear_depth",          "Depth buffer clear"));
-       addChild(SC::createClearTest(rc, tc, Vec4(0.1f, 0.1f, 0.8f, 0.8f), GL_STENCIL_BUFFER_BIT,       "clear_stencil",        "Stencil buffer clear"));
-       addChild(SC::createClearTest(rc, tc, Vec4(0.1f, 0.1f, 0.8f, 0.8f), GL_COLOR_BUFFER_BIT,         "clear_color",          "Color buffer clear"));
+       addChild(createClearTest(tc, rc, "clear_depth",         "Depth buffer clear",   Vec4(0.1f, 0.1f, 0.8f, 0.8f), GL_DEPTH_BUFFER_BIT));
+       addChild(createClearTest(tc, rc, "clear_stencil",       "Stencil buffer clear", Vec4(0.1f, 0.1f, 0.8f, 0.8f), GL_STENCIL_BUFFER_BIT));
+       addChild(createClearTest(tc, rc, "clear_color",         "Color buffer clear",   Vec4(0.1f, 0.1f, 0.8f, 0.8f), GL_COLOR_BUFFER_BIT));
 }
 
 } // Functional
index 9dd2f61..b2c82ec 100644 (file)
@@ -545,13 +545,13 @@ static SegmentedEstimator computeSegmentedEstimator (const vector<Vec2>& data)
        }
 
        {
-               const gls::LineParameters leftLine              = gls::theilSenEstimator(leftData);
-               const gls::LineParameters rightLine             = gls::theilSenEstimator(rightData);
+               const gls::LineParameters leftLine              = gls::theilSenLinearRegression(leftData);
+               const gls::LineParameters rightLine             = gls::theilSenLinearRegression(rightData);
 
                if (numDistinctX(leftData) < 2 || leftLine.coefficient > rightLine.coefficient*0.5f)
                {
                        // Left data doesn't seem credible; assume the data is just a single line.
-                       const gls::LineParameters entireLine = gls::theilSenEstimator(data);
+                       const gls::LineParameters entireLine = gls::theilSenLinearRegression(data);
                        return SegmentedEstimator(gls::LineParameters(entireLine.offset, 0.0f), entireLine, -std::numeric_limits<float>::infinity());
                }
                else
index f91573a..c17ff9b 100644 (file)
@@ -319,7 +319,7 @@ BlendCase::IterateResult BlendCase::iterate (void)
        // \note In sRGB cases, convert to linear space for comparison.
 
        UVec4 compareThreshold = (m_useSrgbFbo ? tcu::PixelFormat(8, 8, 8, 8) : m_context.getRenderTarget().getPixelFormat()).getColorThreshold().toIVec().asUint()
-                                                        * UVec4(5) / UVec4(2) + UVec4(m_useSrgbFbo ? 4 : 2); // \note Non-scientific ad hoc formula. Need big threshold when few color bits; blending brings extra inaccuracy.
+                                                        * UVec4(5) / UVec4(2) + UVec4(m_useSrgbFbo ? 5 : 2); // \note Non-scientific ad hoc formula. Need big threshold when few color bits; blending brings extra inaccuracy.
 
        bool comparePass = tcu::intThresholdCompare(m_testCtx.getLog(), "CompareResult", "Image Comparison Result",
                                                                                                (m_useSrgbFbo ? sRGBATextureLevelToLinear(*m_refColorBuffer) : *m_refColorBuffer).getAccess(),
index e3239d2..c594e4c 100644 (file)
@@ -120,6 +120,13 @@ static const FormatKey s_extColorBufferFloatFormats[] =
        GL_RGBA32F, GL_RGBA16F, GL_R11F_G11F_B10F, GL_RG32F, GL_RG16F, GL_R32F, GL_R16F,
 };
 
+// GL_OES_texture_stencil8
+static const FormatKey s_extOESTextureStencil8[] =
+{
+       GL_STENCIL_INDEX8,
+};
+
+
 static const FormatExtEntry s_es3ExtFormats[] =
 {
        { "GL_EXT_color_buffer_float",
@@ -127,6 +134,11 @@ static const FormatExtEntry s_es3ExtFormats[] =
          // support and makes them color-renderable.
          REQUIRED_RENDERABLE | COLOR_RENDERABLE | RENDERBUFFER_VALID,
          GLS_ARRAY_RANGE(s_extColorBufferFloatFormats) },
+       { "GL_OES_texture_stencil8",
+         // Note: es3 RBO tests actually cover the first two requirements
+      // - kept here for completeness
+      REQUIRED_RENDERABLE | STENCIL_RENDERABLE | TEXTURE_VALID,
+         GLS_ARRAY_RANGE(s_extOESTextureStencil8) }
 };
 
 class ES3Checker : public Checker
index 4a02c29..7fc9f26 100644 (file)
@@ -1211,7 +1211,9 @@ protected:
                const tcu::TextureFormatInfo    colorFmtInfo                    = tcu::getTextureFormatInfo(colorFmt);
                const tcu::Vec4&                                cBias                                   = colorFmtInfo.valueMin;
                const tcu::Vec4                                 cScale                                  = colorFmtInfo.valueMax-colorFmtInfo.valueMin;
-               const bool                                              isDiscarded                             = (m_invalidateTarget == GL_FRAMEBUFFER && m_boundTarget == GL_DRAW_FRAMEBUFFER) || (m_invalidateTarget == m_boundTarget);
+               const bool                                              isDiscarded                             = (m_boundTarget == GL_FRAMEBUFFER) ||
+                                                                                                                                 (m_invalidateTarget == GL_FRAMEBUFFER && m_boundTarget == GL_DRAW_FRAMEBUFFER) ||
+                                                                                                                                 (m_invalidateTarget == m_boundTarget);
                const bool                                              isColorDiscarded                = isDiscarded && hasAttachment(m_invalidateAttachments, GL_COLOR_ATTACHMENT0);
                const bool                                              isDepthDiscarded                = isDiscarded && (hasAttachment(m_invalidateAttachments, GL_DEPTH_ATTACHMENT) || hasAttachment(m_invalidateAttachments, GL_DEPTH_STENCIL_ATTACHMENT));
                const bool                                              isStencilDiscarded              = isDiscarded && (hasAttachment(m_invalidateAttachments, GL_STENCIL_ATTACHMENT) || hasAttachment(m_invalidateAttachments, GL_DEPTH_STENCIL_ATTACHMENT));
index 16ea854..19da1c1 100644 (file)
@@ -54,7 +54,7 @@ using std::vector;
 using std::string;
 using tcu::TestLog;
 using tcu::Vec2;
-using deqp::gls::theilSenEstimator;
+using deqp::gls::theilSenLinearRegression;
 using deqp::gls::LineParameters;
 
 namespace
@@ -427,8 +427,8 @@ void FlushFinishCase::analyzeResults (const std::vector<Sample>& samples, const
 {
        const vector<Vec2>              waitTimes               = getPointsFromSamples(samples, &Sample::waitTime);
        const vector<Vec2>              readTimes               = getPointsFromSamples(samples, &Sample::readPixelsTime);
-       const LineParameters    waitLine                = theilSenEstimator(waitTimes);
-       const LineParameters    readLine                = theilSenEstimator(readTimes);
+       const LineParameters    waitLine                = theilSenLinearRegression(waitTimes);
+       const LineParameters    readLine                = theilSenLinearRegression(readTimes);
        const float                             normWaitCoef    = waitLine.coefficient * float(calibrationParams.maxDrawCalls) / float(MAX_SAMPLE_DURATION_US);
        const float                             normReadCoef    = readLine.coefficient * float(calibrationParams.maxDrawCalls) / float(MAX_SAMPLE_DURATION_US);
        bool                                    allOk                   = true;
index 3ef5bc6..a3b16f2 100644 (file)
@@ -45,320 +45,6 @@ namespace gles3
 {
 namespace Functional
 {
-namespace
-{
-
-using tcu::ConstPixelBufferAccess;
-
-class FramebufferCase : public tcu::TestCase
-{
-public:
-                                                                       FramebufferCase                 (glu::RenderContext& context, tcu::TestContext& testContext, const char* name, const char* description);
-       virtual                                                 ~FramebufferCase                (void) {}
-
-       virtual IterateResult                   iterate                                 (void);
-
-protected:
-       // Must do its own 'readPixels', wrapper does not need to care about formats this way
-       virtual ConstPixelBufferAccess  render                                  (sglr::Context& context, std::vector<deUint8>& pixelBuffer) = DE_NULL;
-
-       glu::RenderContext&                             m_renderContext;
-};
-
-FramebufferCase::FramebufferCase (glu::RenderContext& context, tcu::TestContext& testContext, const char* name, const char* description)
-       : tcu::TestCase         (testContext, name, description)
-       , m_renderContext       (context)
-{
-}
-
-FramebufferCase::IterateResult FramebufferCase::iterate (void)
-{
-       const tcu::Vec4                         clearColor                              (0.0f, 0.0f, 0.0f, 1.0f);
-       const tcu::RenderTarget&        renderTarget                    = m_renderContext.getRenderTarget();
-       const char*                                     failReason                              = DE_NULL;
-
-       const int                                       width                                   = 64;
-       const int                                       height                                  = 64;
-
-       tcu::TestLog&                           log                                             = m_testCtx.getLog();
-       glu::RenderContext&                     renderCtx                               = m_renderContext;
-
-       tcu::ConstPixelBufferAccess glesAccess;
-       tcu::ConstPixelBufferAccess refAccess;
-
-       std::vector<deUint8>            glesFrame;
-       std::vector<deUint8>            refFrame;
-       deUint32                                        glesError;
-
-       {
-               // Render using GLES
-               sglr::GLContext context(renderCtx, log, sglr::GLCONTEXT_LOG_CALLS, tcu::IVec4(0, 0, width, height));
-
-               context.clearColor(clearColor.x(), clearColor.y(), clearColor.z(), clearColor.w());
-               context.clear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
-
-               glesAccess = render(context, glesFrame); // Call actual render func
-               glesError = context.getError();
-       }
-
-       // Render reference image
-       {
-               sglr::ReferenceContextBuffers   buffers (tcu::PixelFormat(8,8,8,renderTarget.getPixelFormat().alphaBits?8:0), renderTarget.getDepthBits(), renderTarget.getStencilBits(), width, height);
-               sglr::ReferenceContext                  context (sglr::ReferenceContextLimits(renderCtx), buffers.getColorbuffer(), buffers.getDepthbuffer(), buffers.getStencilbuffer());
-
-               context.clearColor(clearColor.x(), clearColor.y(), clearColor.z(), clearColor.w());
-               context.clear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
-
-               refAccess = render(context, refFrame);
-               DE_ASSERT(context.getError() == GL_NO_ERROR);
-       }
-
-       if (glesError != GL_NO_ERROR)
-       {
-               log << tcu::TestLog::Message << "Unexpected error: got " << glu::getErrorStr(glesError) << tcu::TestLog::EndMessage;
-               m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got unexpected error");
-       }
-       else
-       {
-               // Compare images
-               const tcu::Vec4         threshold       (0.02f, 0.02f, 0.02f, 0.02f);
-               const bool                      imagesOk        = tcu::floatThresholdCompare(log, "ComparisonResult", "Image comparison result", refAccess, glesAccess, threshold, tcu::COMPARE_LOG_RESULT);
-
-               if (!imagesOk && !failReason)
-                       failReason = "Image comparison failed";
-
-               // Store test result
-               m_testCtx.setTestResult(imagesOk ? QP_TEST_RESULT_PASS  : QP_TEST_RESULT_FAIL,
-                                                               imagesOk ? "Pass"                               : failReason);
-       }
-
-       return STOP;
-}
-
-class FramebufferClearCase : public FramebufferCase
-{
-public:
-       enum ClearType
-       {
-               COLOR_FIXED = 0,
-               COLOR_FLOAT,
-               COLOR_INT,
-               COLOR_UINT,
-               DEPTH,
-               STENCIL,
-               DEPTH_STENCIL,
-
-               CLEAR_TYPE_LAST
-       };
-
-                                                                       FramebufferClearCase    (glu::RenderContext& context, tcu::TestContext& testContext, ClearType clearType, const char* name, const char* description);
-       virtual                                                 ~FramebufferClearCase   (void) {}
-
-       tcu::ConstPixelBufferAccess             render                                  (sglr::Context& context, std::vector<deUint8>& pixelBuffer);
-
-private:
-       const ClearType                                 m_clearType;
-};
-
-FramebufferClearCase::FramebufferClearCase (glu::RenderContext& context, tcu::TestContext& testContext, ClearType clearType, const char* name, const char* description)
-       : FramebufferCase       (context, testContext, name, description)
-       , m_clearType           (clearType)
-{
-}
-
-ConstPixelBufferAccess FramebufferClearCase::render (sglr::Context& context, std::vector<deUint8>& pixelBuffer)
-{
-       using gls::Functional::ScissorTestShader;
-
-       ScissorTestShader       shader;
-       const deUint32          shaderID                        = context.createProgram(&shader);
-
-       const int                       width                           = 64;
-       const int                       height                          = 64;
-
-       const tcu::Vec4         clearColor                      (1.0f, 1.0f, 0.5f, 1.0f);
-       const tcu::IVec4        clearInt                        (127, -127, 0, 127);
-       const tcu::UVec4        clearUint                       (255, 255, 0, 255);
-
-       const tcu::Vec4         baseColor                       (0.0f, 0.0f, 0.0f, 1.0f);
-       const tcu::IVec4        baseIntColor            (0, 0, 0, 0);
-       const tcu::UVec4        baseUintColor           (0, 0, 0, 0);
-
-       const int                       clearStencil            = 123;
-       const float                     clearDepth                      = 1.0f;
-
-       deUint32                        framebuf, colorbuf, dsbuf;
-
-       deUint32                        colorBufferFormat       = GL_RGBA8;
-       deUint32                        readFormat                      = GL_RGBA;
-       deUint32                        readType                        = GL_UNSIGNED_BYTE;
-       tcu::TextureFormat      textureFormat           (tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8);
-
-       context.genFramebuffers(1, &framebuf);
-       context.bindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuf);
-
-       switch (m_clearType)
-       {
-               case COLOR_FLOAT:
-                       colorBufferFormat       = GL_RGBA16F;
-                       textureFormat           = tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::HALF_FLOAT);
-                       DE_ASSERT(!"Floating point clear not implemented");// \todo [2014-1-23 otto] pixel read format & type, nothing guaranteed, need extension...
-                       break;
-
-               case COLOR_INT:
-                       colorBufferFormat       = GL_RGBA8I;
-                       readFormat                      = GL_RGBA_INTEGER;
-                       readType                        = GL_INT;
-                       textureFormat           = tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::SIGNED_INT32);
-                       pixelBuffer.resize(width*height*4*4);
-                       break;
-
-               case COLOR_UINT:
-                       colorBufferFormat       = GL_RGBA8UI;
-                       readFormat                      = GL_RGBA_INTEGER;
-                       readType                        = GL_UNSIGNED_INT;
-                       textureFormat           = tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNSIGNED_INT32);
-                       pixelBuffer.resize(width*height*4*4);
-                       break;
-
-               default:
-                       pixelBuffer.resize(width*height*1*4);
-                       break;
-       }
-
-       // Color
-       context.genRenderbuffers(1, &colorbuf);
-       context.bindRenderbuffer(GL_RENDERBUFFER, colorbuf);
-       context.renderbufferStorage(GL_RENDERBUFFER, colorBufferFormat, width, height);
-       context.framebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorbuf);
-
-       // Depth/stencil
-       context.genRenderbuffers(1, &dsbuf);
-       context.bindRenderbuffer(GL_RENDERBUFFER, dsbuf);
-       context.renderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
-       context.framebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, dsbuf);
-
-       context.clearBufferfi(GL_DEPTH_STENCIL, 0, 1.0f-clearDepth, ~clearStencil);
-       switch (m_clearType)
-       {
-               case COLOR_INT:         context.clearBufferiv(GL_COLOR, 0, baseIntColor.getPtr());              break;
-               case COLOR_UINT:        context.clearBufferuiv(GL_COLOR, 0, baseUintColor.getPtr());    break;
-               default:                        context.clearBufferfv(GL_COLOR, 0, baseColor.getPtr());
-       }
-
-       context.enable(GL_SCISSOR_TEST);
-       context.scissor(8, 8, 48, 48);
-
-       switch (m_clearType)
-       {
-               case COLOR_FIXED:               context.clearBufferfv(GL_COLOR, 0, clearColor.getPtr());                                break;
-               case COLOR_FLOAT:               context.clearBufferfv(GL_COLOR, 0, clearColor.getPtr());                                break;
-               case COLOR_INT:                 context.clearBufferiv(GL_COLOR, 0, clearInt.getPtr());                                  break;
-               case COLOR_UINT:                context.clearBufferuiv(GL_COLOR, 0, clearUint.getPtr());                                break;
-               case DEPTH:                             context.clearBufferfv(GL_DEPTH, 0, &clearDepth);                                                break;
-               case STENCIL:                   context.clearBufferiv(GL_STENCIL, 0, &clearStencil);                                    break;
-               case DEPTH_STENCIL:             context.clearBufferfi(GL_DEPTH_STENCIL, 0, clearDepth, clearStencil);   break;
-
-               default:                                DE_ASSERT(false);                                                                                                               break;
-       }
-
-       context.disable(GL_SCISSOR_TEST);
-
-       const bool useDepth             = (m_clearType==DEPTH   || m_clearType==DEPTH_STENCIL);
-       const bool useStencil   = (m_clearType==STENCIL || m_clearType==DEPTH_STENCIL);
-
-       if (useDepth)
-               context.enable(GL_DEPTH_TEST);
-
-       if (useStencil)
-       {
-               context.enable(GL_STENCIL_TEST);
-               context.stencilFunc(GL_EQUAL, clearStencil, ~0u);
-       }
-
-       if (useDepth || useStencil)
-       {
-               shader.setColor(context, shaderID, clearColor);
-               sglr::drawQuad(context, shaderID, tcu::Vec3(-1.0f, -1.0f, 0.2f), tcu::Vec3(1.0f, 1.0f, 0.2f));
-       }
-
-       context.bindFramebuffer(GL_READ_FRAMEBUFFER, framebuf);
-       context.readPixels(0, 0, width, height, readFormat, readType, &pixelBuffer[0]);
-
-       context.deleteFramebuffers(1, &framebuf);
-       context.deleteRenderbuffers(1, &colorbuf);
-       context.deleteRenderbuffers(1, &dsbuf);
-
-       return tcu::PixelBufferAccess(textureFormat, width, height, 1, &pixelBuffer[0]);
-}
-
-class FramebufferBlitCase : public gls::Functional::ScissorCase
-{
-public:
-                                                       FramebufferBlitCase             (glu::RenderContext& context, tcu::TestContext& testContext, const tcu::Vec4& scissorArea, const char* name, const char* description);
-       virtual                                 ~FramebufferBlitCase    (void) {}
-
-       virtual void                    init                                    (void);
-
-protected:
-       virtual void                    render                                  (sglr::Context& context, const tcu::IVec4& viewport);
-};
-
-FramebufferBlitCase::FramebufferBlitCase (glu::RenderContext& context, tcu::TestContext& testContext, const tcu::Vec4& scissorArea, const char* name, const char* description):
-       ScissorCase(context, testContext, scissorArea, name, description)
-{
-}
-
-void FramebufferBlitCase::init (void)
-{
-       if (m_renderContext.getRenderTarget().getNumSamples())
-               throw tcu::NotSupportedError("Cannot blit to multisampled render buffer", "", __FILE__, __LINE__);
-}
-
-void FramebufferBlitCase::render (sglr::Context& context, const tcu::IVec4& viewport)
-{
-       deUint32                        framebuf;
-       deUint32                        colorbuf;
-
-       const int                       fboWidth                        = 64;
-       const int                       fboHeight                       = 64;
-       const tcu::Vec4         clearColor                      (1.0f, 1.0f, 0.5f, 1.0f);
-       const int                       width                           = viewport.z();
-       const int                       height                          = viewport.w();
-       const tcu::IVec4        scissorArea                     (int(m_scissorArea.x()*width) + viewport.x(),
-                                                                                        int(m_scissorArea.y()*height) + viewport.y(),
-                                                                                        int(m_scissorArea.z()*width),
-                                                                                        int(m_scissorArea.w()*height));
-       const deInt32           defaultFramebuffer      = m_renderContext.getDefaultFramebuffer();
-
-       context.genFramebuffers(1, &framebuf);
-       context.bindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuf);
-
-       context.genRenderbuffers(1, &colorbuf);
-       context.bindRenderbuffer(GL_RENDERBUFFER, colorbuf);
-       context.renderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, fboWidth, fboHeight);
-       context.framebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorbuf);
-
-       context.clearBufferfv(GL_COLOR, 0, clearColor.getPtr());
-
-       context.enable(GL_SCISSOR_TEST);
-       context.scissor(scissorArea.x(), scissorArea.y(), scissorArea.z(), scissorArea.w());
-
-       // blit to default framebuffer
-       context.bindFramebuffer(GL_READ_FRAMEBUFFER, framebuf);
-       context.bindFramebuffer(GL_DRAW_FRAMEBUFFER, defaultFramebuffer);
-
-       context.blitFramebuffer(0, 0, fboWidth, fboHeight, viewport.x(), viewport.y(), viewport.x() + width, viewport.y() + height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
-
-       context.bindFramebuffer(GL_READ_FRAMEBUFFER, defaultFramebuffer);
-
-       context.disable(GL_SCISSOR_TEST);
-
-       context.deleteFramebuffers(1, &framebuf);
-       context.deleteRenderbuffers(1, &colorbuf);
-}
-
-} // Anonymous
 
 ScissorTests::ScissorTests (Context& context):
        TestCaseGroup   (context, "scissor", "Scissor Tests")
@@ -372,63 +58,63 @@ ScissorTests::~ScissorTests (void)
 void ScissorTests::init (void)
 {
        using tcu::Vec4;
-       typedef gls::Functional::ScissorCase SC;
+       using namespace gls::Functional::ScissorTestInternal;
 
-       glu::RenderContext&             rc = m_context.getRenderContext();
        tcu::TestContext&               tc = m_context.getTestContext();
+       glu::RenderContext&             rc = m_context.getRenderContext();
 
-       static const struct
+       const struct
        {
-               const char*                             name;
-               const char*                             description;
-               const tcu::Vec4                 scissor;
-               const tcu::Vec4                 render;
-               const SC::PrimitiveType type;
-               const int                               primitives;
+               const char*                     name;
+               const char*                     desc;
+               const tcu::Vec4         scissor;
+               const tcu::Vec4         render;
+               const PrimitiveType     type;
+               const int                       primitives;
        } cases[] =
        {
-               { "contained_quads",            "Triangles fully inside scissor area (single call)",            Vec4(0.1f, 0.1f, 0.8f, 0.8f), Vec4(0.2f, 0.2f, 0.6f, 0.6f), SC::TRIANGLE,       30 },
-               { "partial_quads",                      "Triangles partially inside scissor area (single call)",        Vec4(0.3f, 0.3f, 0.4f, 0.4f), Vec4(0.2f, 0.2f, 0.6f, 0.6f), SC::TRIANGLE,       30 },
-               { "contained_tri",                      "Triangle fully inside scissor area",                                           Vec4(0.1f, 0.1f, 0.8f, 0.8f), Vec4(0.2f, 0.2f, 0.6f, 0.6f), SC::TRIANGLE,       1  },
-               { "enclosing_tri",                      "Triangle fully covering scissor area",                                         Vec4(0.4f, 0.4f, 0.2f, 0.2f), Vec4(0.2f, 0.2f, 0.6f, 0.6f), SC::TRIANGLE,       1  },
-               { "partial_tri",                        "Triangle partially inside scissor area",                                       Vec4(0.4f, 0.4f, 0.6f, 0.6f), Vec4(0.0f, 0.0f, 1.0f, 1.0f), SC::TRIANGLE,       1  },
-               { "outside_render_tri",         "Triangle with scissor area outside render target",                     Vec4(1.4f, 1.4f, 0.6f, 0.6f), Vec4(0.0f, 0.0f, 0.6f, 0.6f), SC::TRIANGLE,       1  },
-               { "partial_lines",                      "Linse partially inside scissor area",                                          Vec4(0.4f, 0.4f, 0.6f, 0.6f), Vec4(0.0f, 0.0f, 1.0f, 1.0f), SC::LINE,           30 },
-               { "contained_line",                     "Line fully inside scissor area",                                                       Vec4(0.1f, 0.1f, 0.8f, 0.8f), Vec4(0.2f, 0.2f, 0.6f, 0.6f), SC::LINE,           1  },
-               { "partial_line",                       "Line partially inside scissor area",                                           Vec4(0.4f, 0.4f, 0.6f, 0.6f), Vec4(0.0f, 0.0f, 1.0f, 1.0f), SC::LINE,           1  },
-               { "outside_render_line",        "Line with scissor area outside render target",                         Vec4(1.4f, 1.4f, 0.6f, 0.6f), Vec4(0.0f, 0.0f, 0.6f, 0.6f), SC::LINE,           1  },
-               { "contained_point",            "Point fully inside scissor area",                                                      Vec4(0.1f, 0.1f, 0.8f, 0.8f), Vec4(0.5f, 0.5f, 0.0f, 0.0f), SC::POINT,          1  },
-               { "partial_points",                     "Points partially inside scissor area",                                         Vec4(0.4f, 0.4f, 0.6f, 0.6f), Vec4(0.0f, 0.0f, 1.0f, 1.0f), SC::POINT,          30 },
-               { "outside_point",                      "Point fully outside scissor area",                                                     Vec4(0.4f, 0.4f, 0.6f, 0.6f), Vec4(0.0f, 0.0f, 0.0f, 0.0f), SC::POINT,          1  },
-               { "outside_render_point",       "Point with scissor area outside render target",                        Vec4(1.4f, 1.4f, 0.6f, 0.6f), Vec4(0.5f, 0.5f, 0.0f, 0.0f),     SC::POINT,              1  }
+               { "contained_quads",            "Triangles fully inside scissor area (single call)",            Vec4(0.1f, 0.1f, 0.8f, 0.8f), Vec4(0.2f, 0.2f, 0.6f, 0.6f), TRIANGLE,   30 },
+               { "partial_quads",                      "Triangles partially inside scissor area (single call)",        Vec4(0.3f, 0.3f, 0.4f, 0.4f), Vec4(0.2f, 0.2f, 0.6f, 0.6f), TRIANGLE,   30 },
+               { "contained_tri",                      "Triangle fully inside scissor area",                                           Vec4(0.1f, 0.1f, 0.8f, 0.8f), Vec4(0.2f, 0.2f, 0.6f, 0.6f), TRIANGLE,   1  },
+               { "enclosing_tri",                      "Triangle fully covering scissor area",                                         Vec4(0.4f, 0.4f, 0.2f, 0.2f), Vec4(0.2f, 0.2f, 0.6f, 0.6f), TRIANGLE,   1  },
+               { "partial_tri",                        "Triangle partially inside scissor area",                                       Vec4(0.4f, 0.4f, 0.6f, 0.6f), Vec4(0.0f, 0.0f, 1.0f, 1.0f), TRIANGLE,   1  },
+               { "outside_render_tri",         "Triangle with scissor area outside render target",                     Vec4(1.4f, 1.4f, 0.6f, 0.6f), Vec4(0.0f, 0.0f, 0.6f, 0.6f), TRIANGLE,   1  },
+               { "partial_lines",                      "Linse partially inside scissor area",                                          Vec4(0.4f, 0.4f, 0.6f, 0.6f), Vec4(0.0f, 0.0f, 1.0f, 1.0f), LINE,               30 },
+               { "contained_line",                     "Line fully inside scissor area",                                                       Vec4(0.1f, 0.1f, 0.8f, 0.8f), Vec4(0.2f, 0.2f, 0.6f, 0.6f), LINE,               1  },
+               { "partial_line",                       "Line partially inside scissor area",                                           Vec4(0.4f, 0.4f, 0.6f, 0.6f), Vec4(0.0f, 0.0f, 1.0f, 1.0f), LINE,               1  },
+               { "outside_render_line",        "Line with scissor area outside render target",                         Vec4(1.4f, 1.4f, 0.6f, 0.6f), Vec4(0.0f, 0.0f, 0.6f, 0.6f), LINE,               1  },
+               { "contained_point",            "Point fully inside scissor area",                                                      Vec4(0.1f, 0.1f, 0.8f, 0.8f), Vec4(0.5f, 0.5f, 0.0f, 0.0f), POINT,              1  },
+               { "partial_points",                     "Points partially inside scissor area",                                         Vec4(0.4f, 0.4f, 0.6f, 0.6f), Vec4(0.0f, 0.0f, 1.0f, 1.0f), POINT,              30 },
+               { "outside_point",                      "Point fully outside scissor area",                                                     Vec4(0.4f, 0.4f, 0.6f, 0.6f), Vec4(0.0f, 0.0f, 0.0f, 0.0f), POINT,              1  },
+               { "outside_render_point",       "Point with scissor area outside render target",                        Vec4(1.4f, 1.4f, 0.6f, 0.6f), Vec4(0.5f, 0.5f, 0.0f, 0.0f),     POINT,          1  }
        };
 
        for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(cases); caseNdx++)
        {
-               addChild(SC::createPrimitiveTest(rc,
-                                                                                tc,
-                                                                                cases[caseNdx].scissor,
-                                                                                cases[caseNdx].render,
-                                                                                cases[caseNdx].type,
-                                                                                cases[caseNdx].primitives,
-                                                                                cases[caseNdx].name,
-                                                                                cases[caseNdx].description));
+               addChild(createPrimitiveTest(tc,
+                                                                        rc,
+                                                                        cases[caseNdx].name,
+                                                                        cases[caseNdx].desc,
+                                                                        cases[caseNdx].scissor,
+                                                                        cases[caseNdx].render,
+                                                                        cases[caseNdx].type,
+                                                                        cases[caseNdx].primitives));
        }
 
-       addChild(SC::createClearTest(rc, tc, Vec4(0.1f, 0.1f, 0.8f, 0.8f), GL_DEPTH_BUFFER_BIT,         "clear_depth",          "Depth buffer clear"));
-       addChild(SC::createClearTest(rc, tc, Vec4(0.1f, 0.1f, 0.8f, 0.8f), GL_STENCIL_BUFFER_BIT,       "clear_stencil",        "Stencil buffer clear"));
-       addChild(SC::createClearTest(rc, tc, Vec4(0.1f, 0.1f, 0.8f, 0.8f), GL_COLOR_BUFFER_BIT,         "clear_color",          "Color buffer clear"));
+       addChild(createClearTest(tc, rc, "clear_depth",         "Depth buffer clear",   Vec4(0.1f, 0.1f, 0.8f, 0.8f), GL_DEPTH_BUFFER_BIT));
+       addChild(createClearTest(tc, rc, "clear_stencil",       "Stencil buffer clear", Vec4(0.1f, 0.1f, 0.8f, 0.8f), GL_STENCIL_BUFFER_BIT));
+       addChild(createClearTest(tc, rc, "clear_color",         "Color buffer clear",   Vec4(0.1f, 0.1f, 0.8f, 0.8f), GL_COLOR_BUFFER_BIT));
 
-       addChild(new FramebufferClearCase(rc, tc, FramebufferClearCase::COLOR_FIXED,    "clear_fixed_buffer",                   "Fixed point color clear"));
-       addChild(new FramebufferClearCase(rc, tc, FramebufferClearCase::COLOR_INT,              "clear_int_buffer",                             "Integer color clear"));
-       addChild(new FramebufferClearCase(rc, tc, FramebufferClearCase::COLOR_UINT,             "clear_uint_buffer",                    "Unsigned integer buffer clear"));
-       addChild(new FramebufferClearCase(rc, tc, FramebufferClearCase::DEPTH,                  "clear_depth_buffer",                   "Depth buffer clear"));
-       addChild(new FramebufferClearCase(rc, tc, FramebufferClearCase::STENCIL,                "clear_stencil_buffer",                 "Stencil buffer clear"));
-       addChild(new FramebufferClearCase(rc, tc, FramebufferClearCase::DEPTH_STENCIL,  "clear_depth_stencil_buffer",   "Fixed point color buffer clear"));
+       addChild(createFramebufferClearTest(tc, rc, "clear_fixed_buffer",                       "Fixed point color clear",                      CLEAR_COLOR_FIXED));
+       addChild(createFramebufferClearTest(tc, rc, "clear_int_buffer",                         "Integer color clear",                          CLEAR_COLOR_INT));
+       addChild(createFramebufferClearTest(tc, rc, "clear_uint_buffer",                        "Unsigned integer buffer clear",        CLEAR_COLOR_UINT));
+       addChild(createFramebufferClearTest(tc, rc, "clear_depth_buffer",                       "Depth buffer clear",                           CLEAR_DEPTH));
+       addChild(createFramebufferClearTest(tc, rc, "clear_stencil_buffer",                     "Stencil buffer clear",                         CLEAR_STENCIL));
+       addChild(createFramebufferClearTest(tc, rc, "clear_depth_stencil_buffer",       "Fixed point color buffer clear",       CLEAR_DEPTH_STENCIL));
 
-       addChild(new FramebufferBlitCase(rc, tc, Vec4(0.1f, 0.1f, 0.8f, 0.8f), "framebuffer_blit_center",       "Blit to default framebuffer, scissor away edges"));
-       addChild(new FramebufferBlitCase(rc, tc, Vec4(0.6f, 0.6f, 0.5f, 0.5f), "framebuffer_blit_corner",       "Blit to default framebuffer, scissor all but a corner"));
-       addChild(new FramebufferBlitCase(rc, tc, Vec4(1.6f, 0.6f, 0.5f, 0.5f), "framebuffer_blit_none",         "Blit to default framebuffer, scissor area outside screen"));
+       addChild(createFramebufferBlitTest(tc, rc, "framebuffer_blit_center",   "Blit to default framebuffer, scissor away edges",                      Vec4(0.1f, 0.1f, 0.8f, 0.8f)));
+       addChild(createFramebufferBlitTest(tc, rc, "framebuffer_blit_corner",   "Blit to default framebuffer, scissor all but a corner",        Vec4(0.6f, 0.6f, 0.5f, 0.5f)));
+       addChild(createFramebufferBlitTest(tc, rc, "framebuffer_blit_none",             "Blit to default framebuffer, scissor area outside screen", Vec4(1.6f, 0.6f, 0.5f, 0.5f)));
 }
 
 } // Functional
index 0b405fe..c05b763 100644 (file)
@@ -288,8 +288,8 @@ bool ShaderFloatPrecisionCase::compare (float in0, float in1, double reference,
        // Comparison is done using 64-bit reference value to accurately evaluate rounding mode error.
        // If 32-bit reference value is used, 2 bits of rounding error must be allowed.
 
-       // For mediump and lowp types the comparison currently allows 2 bits of rounding error:
-       // one bit from conversion and another from actual operation.
+       // For mediump and lowp types the comparison currently allows 3 bits of rounding error:
+       // two bits from conversions and one from actual operation.
 
        // \todo [2013-09-30 pyry] Make this more strict: determine if rounding can actually happen.
 
@@ -301,7 +301,7 @@ bool ShaderFloatPrecisionCase::compare (float in0, float in1, double reference,
        const int               resExp                          = tcu::Float32(result).exponent();
        const int               numLostBits                     = de::max(de::max(in0Exp-resExp, in1Exp-resExp), 0); // Lost due to mantissa shift.
 
-       const int               roundingUlpError        = m_precision == glu::PRECISION_HIGHP ? 1 : 2;
+       const int               roundingUlpError        = m_precision == glu::PRECISION_HIGHP ? 1 : 3;
        const int               maskBits                        = numLostBits + numPrecBits;
 
        m_testCtx.getLog() << TestLog::Message << "Assuming " << mantissaBits << " mantissa bits, " << numLostBits << " bits lost in operation, and " << roundingUlpError << " ULP rounding error."
index 7c9d436..a72950b 100644 (file)
@@ -690,7 +690,19 @@ void ShaderTextureFunctionCase::initTexture (void)
                                        Vec4                    colorB  = cBias + cScale*f.swizzle(swzB[0], swzB[1], swzB[2], swzB[3]);
 
                                        m_textureCube->getRefTexture().allocLevel((tcu::CubeFace)face, level);
-                                       tcu::fillWithGrid(m_textureCube->getRefTexture().getLevelFace(level, (tcu::CubeFace)face), de::max(1, baseCellSize>>level), colorA, colorB);
+
+                                       {
+                                               const tcu::PixelBufferAccess    access          = m_textureCube->getRefTexture().getLevelFace(level, (tcu::CubeFace)face);
+                                               const int                                               lastPix         = access.getWidth()-1;
+
+                                               tcu::fillWithGrid(access, de::max(1, baseCellSize>>level), colorA, colorB);
+
+                                               // Ensure all corners have identical colors in order to avoid dealing with ambiguous corner texel filtering
+                                               access.setPixel(colorA, 0, 0);
+                                               access.setPixel(colorA, 0, lastPix);
+                                               access.setPixel(colorA, lastPix, 0);
+                                               access.setPixel(colorA, lastPix, lastPix);
+                                       }
                                }
                        }
                        m_textureCube->upload();
index 896954e..8840b3f 100644 (file)
@@ -31,6 +31,8 @@ set(DEQP_GLES3_PERFORMANCE_SRCS
        es3pBufferDataUploadTests.hpp
        es3pShaderOperatorTests.cpp
        es3pShaderOperatorTests.hpp
+       es3pDepthTests.hpp
+       es3pDepthTests.cpp
        )
 
 add_library(deqp-gles3-performance STATIC ${DEQP_GLES3_PERFORMANCE_SRCS})
index c9758c4..45bd25f 100644 (file)
@@ -22,6 +22,7 @@
  *//*--------------------------------------------------------------------*/
 
 #include "es3pBufferDataUploadTests.hpp"
+#include "glsCalibration.hpp"
 #include "tcuTestLog.hpp"
 #include "tcuVectorUtil.hpp"
 #include "tcuSurface.hpp"
@@ -54,6 +55,9 @@ namespace Performance
 namespace
 {
 
+using gls::theilSenSiegelLinearRegression;
+using gls::LineParametersWithConfidence;
+
 static const char* const s_dummyVertexShader =         "#version 300 es\n"
                                                                                                        "in highp vec4 a_position;\n"
                                                                                                        "void main (void)\n"
@@ -497,16 +501,6 @@ struct SampleTypeTraits<RenderUploadRenderReadDuration>
        enum { LOG_UNRELATED_UPLOAD_SIZE        = 1 };
 };
 
-struct TheilSenLineFit
-{
-       float coefficient;
-       float coefficient60ConfidenceUpper;
-       float coefficient60ConfidenceLower;
-       float offset;
-       float offset60ConfidenceUpper;
-       float offset60ConfidenceLower;
-};
-
 struct UploadSampleAnalyzeResult
 {
        float transferRateMedian;
@@ -689,63 +683,6 @@ static float linearSample (const std::vector<T>& values, float position)
        return tcu::mix((float)values[lowerNdx], (float)values[higherNdx], interpolationFactor);
 }
 
-static TheilSenLineFit theilSenLinearRegression (const std::vector<tcu::Vec2>& dataPoints)
-{
-       DE_ASSERT(!dataPoints.empty());
-
-       // \note Based on gls::theilSenEstimator()
-       // Siegel's variation
-
-       const float                     epsilon                                 = 1e-6f;
-       int                                     numDataPoints                   = (int)dataPoints.size();
-       std::vector<float>      medianSlopes;
-       std::vector<float>      pointwiseOffsets;
-       TheilSenLineFit         result;
-
-       // Compute the median slope via each element
-       for (int i = 0; i < numDataPoints; i++)
-       {
-               const tcu::Vec2&        ptA             = dataPoints[i];
-               std::vector<float>      slopes;
-
-               for (int j = 0; j < numDataPoints; j++)
-               {
-                       const tcu::Vec2& ptB = dataPoints[j];
-
-                       if (de::abs(ptA.x() - ptB.x()) > epsilon)
-                               slopes.push_back((ptA.y() - ptB.y()) / (ptA.x() - ptB.x()));
-               }
-
-               std::sort(slopes.begin(), slopes.end());
-               medianSlopes.push_back(linearSample(slopes, 0.5f));
-       }
-
-       DE_ASSERT(!medianSlopes.empty());
-
-       // Find the median of the pairwise coefficients.
-       std::sort(medianSlopes.begin(), medianSlopes.end());
-       result.coefficient = linearSample(medianSlopes, 0.5f);
-
-       // Compute the offsets corresponding to the median coefficient, for all data points.
-       for (int i = 0; i < numDataPoints; i++)
-               pointwiseOffsets.push_back(dataPoints[i].y() - result.coefficient*dataPoints[i].x());
-
-       // Find the median of the offsets.
-       std::sort(pointwiseOffsets.begin(), pointwiseOffsets.end());
-       result.offset = linearSample(pointwiseOffsets, 0.5f);
-
-       // calculate 60% confidence intervals
-       {
-               result.coefficient60ConfidenceLower = linearSample(medianSlopes, 0.2f);
-               result.coefficient60ConfidenceUpper = linearSample(medianSlopes, 0.8f);
-
-               result.offset60ConfidenceLower = linearSample(pointwiseOffsets, 0.2f);
-               result.offset60ConfidenceUpper = linearSample(pointwiseOffsets, 0.8f);
-       }
-
-       return result;
-}
-
 template <typename T>
 SingleOperationStatistics calculateSingleOperationStatistics (const std::vector<T>& samples, deUint64 T::SampleType::*target)
 {
@@ -767,7 +704,7 @@ SingleOperationStatistics calculateSingleOperationStatistics (const std::vector<
 }
 
 template <typename StatisticsType, typename SampleType>
-void calculateBasicStatistics (StatisticsType& stats, const TheilSenLineFit& fit, const std::vector<SampleType>& samples, int SampleType::*predictor)
+void calculateBasicStatistics (StatisticsType& stats, const LineParametersWithConfidence& fit, const std::vector<SampleType>& samples, int SampleType::*predictor)
 {
        std::vector<deUint64> values(samples.size());
 
@@ -842,18 +779,18 @@ void calculateBasicStatistics (StatisticsType& stats, const TheilSenLineFit& fit
 }
 
 template <typename StatisticsType, typename SampleType>
-void calculateBasicTransferStatistics (StatisticsType& stats, const TheilSenLineFit& fit, const std::vector<SampleType>& samples)
+void calculateBasicTransferStatistics (StatisticsType& stats, const LineParametersWithConfidence& fit, const std::vector<SampleType>& samples)
 {
        calculateBasicStatistics(stats, fit, samples, &SampleType::writtenSize);
 }
 
 template <typename StatisticsType, typename SampleType>
-void calculateBasicRenderStatistics (StatisticsType& stats, const TheilSenLineFit& fit, const std::vector<SampleType>& samples)
+void calculateBasicRenderStatistics (StatisticsType& stats, const LineParametersWithConfidence& fit, const std::vector<SampleType>& samples)
 {
        calculateBasicStatistics(stats, fit, samples, &SampleType::renderDataSize);
 }
 
-static SingleCallStatistics calculateSampleStatistics (const TheilSenLineFit& fit, const std::vector<UploadSampleResult<SingleOperationDuration> >& samples)
+static SingleCallStatistics calculateSampleStatistics (const LineParametersWithConfidence& fit, const std::vector<UploadSampleResult<SingleOperationDuration> >& samples)
 {
        SingleCallStatistics stats;
 
@@ -862,7 +799,7 @@ static SingleCallStatistics calculateSampleStatistics (const TheilSenLineFit& fi
        return stats;
 }
 
-static MapCallStatistics calculateSampleStatistics (const TheilSenLineFit& fit, const std::vector<UploadSampleResult<MapBufferRangeDuration> >& samples)
+static MapCallStatistics calculateSampleStatistics (const LineParametersWithConfidence& fit, const std::vector<UploadSampleResult<MapBufferRangeDuration> >& samples)
 {
        MapCallStatistics stats;
 
@@ -876,7 +813,7 @@ static MapCallStatistics calculateSampleStatistics (const TheilSenLineFit& fit,
        return stats;
 }
 
-static MapFlushCallStatistics calculateSampleStatistics (const TheilSenLineFit& fit, const std::vector<UploadSampleResult<MapBufferRangeFlushDuration> >& samples)
+static MapFlushCallStatistics calculateSampleStatistics (const LineParametersWithConfidence& fit, const std::vector<UploadSampleResult<MapBufferRangeFlushDuration> >& samples)
 {
        MapFlushCallStatistics stats;
 
@@ -891,7 +828,7 @@ static MapFlushCallStatistics calculateSampleStatistics (const TheilSenLineFit&
        return stats;
 }
 
-static MapCallStatistics calculateSampleStatistics (const TheilSenLineFit& fit, const std::vector<UploadSampleResult<MapBufferRangeDurationNoAlloc> >& samples)
+static MapCallStatistics calculateSampleStatistics (const LineParametersWithConfidence& fit, const std::vector<UploadSampleResult<MapBufferRangeDurationNoAlloc> >& samples)
 {
        MapCallStatistics stats;
 
@@ -904,7 +841,7 @@ static MapCallStatistics calculateSampleStatistics (const TheilSenLineFit& fit,
        return stats;
 }
 
-static MapFlushCallStatistics calculateSampleStatistics (const TheilSenLineFit& fit, const std::vector<UploadSampleResult<MapBufferRangeFlushDurationNoAlloc> >& samples)
+static MapFlushCallStatistics calculateSampleStatistics (const LineParametersWithConfidence& fit, const std::vector<UploadSampleResult<MapBufferRangeFlushDurationNoAlloc> >& samples)
 {
        MapFlushCallStatistics stats;
 
@@ -918,7 +855,7 @@ static MapFlushCallStatistics calculateSampleStatistics (const TheilSenLineFit&
        return stats;
 }
 
-static RenderReadStatistics calculateSampleStatistics (const TheilSenLineFit& fit, const std::vector<RenderSampleResult<RenderReadDuration> >& samples)
+static RenderReadStatistics calculateSampleStatistics (const LineParametersWithConfidence& fit, const std::vector<RenderSampleResult<RenderReadDuration> >& samples)
 {
        RenderReadStatistics stats;
 
@@ -931,7 +868,7 @@ static RenderReadStatistics calculateSampleStatistics (const TheilSenLineFit& fi
        return stats;
 }
 
-static RenderReadStatistics calculateSampleStatistics (const TheilSenLineFit& fit, const std::vector<RenderSampleResult<UnrelatedUploadRenderReadDuration> >& samples)
+static RenderReadStatistics calculateSampleStatistics (const LineParametersWithConfidence& fit, const std::vector<RenderSampleResult<UnrelatedUploadRenderReadDuration> >& samples)
 {
        RenderReadStatistics stats;
 
@@ -944,7 +881,7 @@ static RenderReadStatistics calculateSampleStatistics (const TheilSenLineFit& fi
        return stats;
 }
 
-static UploadRenderReadStatistics calculateSampleStatistics (const TheilSenLineFit& fit, const std::vector<RenderSampleResult<UploadRenderReadDuration> >& samples)
+static UploadRenderReadStatistics calculateSampleStatistics (const LineParametersWithConfidence& fit, const std::vector<RenderSampleResult<UploadRenderReadDuration> >& samples)
 {
        UploadRenderReadStatistics stats;
 
@@ -958,7 +895,7 @@ static UploadRenderReadStatistics calculateSampleStatistics (const TheilSenLineF
        return stats;
 }
 
-static UploadRenderReadStatistics calculateSampleStatistics (const TheilSenLineFit& fit, const std::vector<RenderSampleResult<UploadRenderReadDurationWithUnrelatedUploadSize> >& samples)
+static UploadRenderReadStatistics calculateSampleStatistics (const LineParametersWithConfidence& fit, const std::vector<RenderSampleResult<UploadRenderReadDurationWithUnrelatedUploadSize> >& samples)
 {
        UploadRenderReadStatistics stats;
 
@@ -972,7 +909,7 @@ static UploadRenderReadStatistics calculateSampleStatistics (const TheilSenLineF
        return stats;
 }
 
-static RenderUploadRenderReadStatistics calculateSampleStatistics (const TheilSenLineFit& fit, const std::vector<RenderSampleResult<RenderUploadRenderReadDuration> >& samples)
+static RenderUploadRenderReadStatistics calculateSampleStatistics (const LineParametersWithConfidence& fit, const std::vector<RenderSampleResult<RenderUploadRenderReadDuration> >& samples)
 {
        RenderUploadRenderReadStatistics stats;
 
@@ -988,7 +925,7 @@ static RenderUploadRenderReadStatistics calculateSampleStatistics (const TheilSe
 }
 
 template <typename DurationType>
-static TheilSenLineFit fitLineToSamples (const std::vector<UploadSampleResult<DurationType> >& samples, int beginNdx, int endNdx, int step, deUint64 DurationType::*target = &DurationType::fitResponseDuration)
+static LineParametersWithConfidence fitLineToSamples (const std::vector<UploadSampleResult<DurationType> >& samples, int beginNdx, int endNdx, int step, deUint64 DurationType::*target = &DurationType::fitResponseDuration)
 {
        std::vector<tcu::Vec2> samplePoints;
 
@@ -1002,11 +939,11 @@ static TheilSenLineFit fitLineToSamples (const std::vector<UploadSampleResult<Du
                samplePoints.push_back(point);
        }
 
-       return theilSenLinearRegression(samplePoints);
+       return theilSenSiegelLinearRegression(samplePoints, 0.6f);
 }
 
 template <typename DurationType>
-static TheilSenLineFit fitLineToSamples (const std::vector<RenderSampleResult<DurationType> >& samples, int beginNdx, int endNdx, int step, deUint64 DurationType::*target = &DurationType::fitResponseDuration)
+static LineParametersWithConfidence fitLineToSamples (const std::vector<RenderSampleResult<DurationType> >& samples, int beginNdx, int endNdx, int step, deUint64 DurationType::*target = &DurationType::fitResponseDuration)
 {
        std::vector<tcu::Vec2> samplePoints;
 
@@ -1020,17 +957,17 @@ static TheilSenLineFit fitLineToSamples (const std::vector<RenderSampleResult<Du
                samplePoints.push_back(point);
        }
 
-       return theilSenLinearRegression(samplePoints);
+       return theilSenSiegelLinearRegression(samplePoints, 0.6f);
 }
 
 template <typename T>
-static TheilSenLineFit fitLineToSamples (const std::vector<T>& samples, int beginNdx, int endNdx, deUint64 T::SampleType::*target = &T::SampleType::fitResponseDuration)
+static LineParametersWithConfidence fitLineToSamples (const std::vector<T>& samples, int beginNdx, int endNdx, deUint64 T::SampleType::*target = &T::SampleType::fitResponseDuration)
 {
        return fitLineToSamples(samples, beginNdx, endNdx, 1, target);
 }
 
 template <typename T>
-static TheilSenLineFit fitLineToSamples (const std::vector<T>& samples, deUint64 T::SampleType::*target = &T::SampleType::fitResponseDuration)
+static LineParametersWithConfidence fitLineToSamples (const std::vector<T>& samples, deUint64 T::SampleType::*target = &T::SampleType::fitResponseDuration)
 {
        return fitLineToSamples(samples, 0, (int)samples.size(), target);
 }
@@ -1083,8 +1020,8 @@ static float calculateSampleFitLinearity (const std::vector<T>& samples, int T::
 
        const float                             epsilon                         = 1.e-6f;
        const int                               midPoint                        = (int)samples.size() / 2;
-       const TheilSenLineFit   startApproximation      = fitLineToSamples(samples, 0, midPoint, &T::SampleType::fitResponseDuration);
-       const TheilSenLineFit   endApproximation        = fitLineToSamples(samples, midPoint, (int)samples.size(), &T::SampleType::fitResponseDuration);
+       const LineParametersWithConfidence      startApproximation      = fitLineToSamples(samples, 0, midPoint, &T::SampleType::fitResponseDuration);
+       const LineParametersWithConfidence      endApproximation        = fitLineToSamples(samples, midPoint, (int)samples.size(), &T::SampleType::fitResponseDuration);
 
        const float                             aabbMinX                        = (float)(samples.front().*predictor);
        const float                             aabbMinY                        = de::min(startApproximation.offset + startApproximation.coefficient*aabbMinX, endApproximation.offset + endApproximation.coefficient*aabbMinX);
@@ -1119,8 +1056,8 @@ static float calculateSampleTemporalStability (const std::vector<T>& samples, in
        // the lines and the AABB.
 
        const float                             epsilon                         = 1.e-6f;
-       const TheilSenLineFit   evenApproximation       = fitLineToSamples(samples, 0, (int)samples.size(), 2, &T::SampleType::fitResponseDuration);
-       const TheilSenLineFit   oddApproximation        = fitLineToSamples(samples, 1, (int)samples.size(), 2, &T::SampleType::fitResponseDuration);
+       const LineParametersWithConfidence      evenApproximation       = fitLineToSamples(samples, 0, (int)samples.size(), 2, &T::SampleType::fitResponseDuration);
+       const LineParametersWithConfidence      oddApproximation        = fitLineToSamples(samples, 1, (int)samples.size(), 2, &T::SampleType::fitResponseDuration);
 
        const float                             aabbMinX                        = (float)(samples.front().*predictor);
        const float                             aabbMinY                        = de::min(evenApproximation.offset + evenApproximation.coefficient*aabbMinX, oddApproximation.offset + oddApproximation.coefficient*aabbMinX);
@@ -1259,7 +1196,7 @@ static typename EnableIfNot<void, SampleTypeTraits<SampleType>::HAS_ALLOC_STATS>
 template <typename SampleType>
 static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_MAP_STATS>::Type logMapContribution (tcu::TestLog& log, const std::vector<UploadSampleResult<SampleType> >& samples, const typename SampleTypeTraits<SampleType>::StatsType& stats)
 {
-       const TheilSenLineFit contributionFitting = fitLineToSamples(samples, &SampleType::mapDuration);
+       const LineParametersWithConfidence contributionFitting = fitLineToSamples(samples, &SampleType::mapDuration);
        log     << tcu::TestLog::Float("MapConstantCost", "Map: Approximated contant cost", "us", QP_KEY_TAG_TIME, contributionFitting.offset)
                << tcu::TestLog::Float("MapLinearCost", "Map: Approximated linear cost", "us / MB", QP_KEY_TAG_TIME, contributionFitting.coefficient * 1024.0f * 1024.0f)
                << tcu::TestLog::Float("MapMedianCost", "Map: Median cost", "us", QP_KEY_TAG_TIME, stats.map.medianTime);
@@ -1268,7 +1205,7 @@ static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_MAP_STATS>::Typ
 template <typename SampleType>
 static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_UNMAP_STATS>::Type logUnmapContribution (tcu::TestLog& log, const std::vector<UploadSampleResult<SampleType> >& samples, const typename SampleTypeTraits<SampleType>::StatsType& stats)
 {
-       const TheilSenLineFit contributionFitting = fitLineToSamples(samples, &SampleType::unmapDuration);
+       const LineParametersWithConfidence contributionFitting = fitLineToSamples(samples, &SampleType::unmapDuration);
        log     << tcu::TestLog::Float("UnmapConstantCost", "Unmap: Approximated contant cost", "us", QP_KEY_TAG_TIME, contributionFitting.offset)
                << tcu::TestLog::Float("UnmapLinearCost", "Unmap: Approximated linear cost", "us / MB", QP_KEY_TAG_TIME, contributionFitting.coefficient * 1024.0f * 1024.0f)
                << tcu::TestLog::Float("UnmapMedianCost", "Unmap: Median cost", "us", QP_KEY_TAG_TIME, stats.unmap.medianTime);
@@ -1277,7 +1214,7 @@ static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_UNMAP_STATS>::T
 template <typename SampleType>
 static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_WRITE_STATS>::Type logWriteContribution (tcu::TestLog& log, const std::vector<UploadSampleResult<SampleType> >& samples, const typename SampleTypeTraits<SampleType>::StatsType& stats)
 {
-       const TheilSenLineFit contributionFitting = fitLineToSamples(samples, &SampleType::writeDuration);
+       const LineParametersWithConfidence contributionFitting = fitLineToSamples(samples, &SampleType::writeDuration);
        log     << tcu::TestLog::Float("WriteConstantCost", "Write: Approximated contant cost", "us", QP_KEY_TAG_TIME, contributionFitting.offset)
                << tcu::TestLog::Float("WriteLinearCost", "Write: Approximated linear cost", "us / MB", QP_KEY_TAG_TIME, contributionFitting.coefficient * 1024.0f * 1024.0f)
                << tcu::TestLog::Float("WriteMedianCost", "Write: Median cost", "us", QP_KEY_TAG_TIME, stats.write.medianTime);
@@ -1286,7 +1223,7 @@ static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_WRITE_STATS>::T
 template <typename SampleType>
 static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_FLUSH_STATS>::Type logFlushContribution (tcu::TestLog& log, const std::vector<UploadSampleResult<SampleType> >& samples, const typename SampleTypeTraits<SampleType>::StatsType& stats)
 {
-       const TheilSenLineFit contributionFitting = fitLineToSamples(samples, &SampleType::flushDuration);
+       const LineParametersWithConfidence contributionFitting = fitLineToSamples(samples, &SampleType::flushDuration);
        log     << tcu::TestLog::Float("FlushConstantCost", "Flush: Approximated contant cost", "us", QP_KEY_TAG_TIME, contributionFitting.offset)
                << tcu::TestLog::Float("FlushLinearCost", "Flush: Approximated linear cost", "us / MB", QP_KEY_TAG_TIME, contributionFitting.coefficient * 1024.0f * 1024.0f)
                << tcu::TestLog::Float("FlushMedianCost", "Flush: Median cost", "us", QP_KEY_TAG_TIME, stats.flush.medianTime);
@@ -1295,7 +1232,7 @@ static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_FLUSH_STATS>::T
 template <typename SampleType>
 static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_ALLOC_STATS>::Type logAllocContribution (tcu::TestLog& log, const std::vector<UploadSampleResult<SampleType> >& samples, const typename SampleTypeTraits<SampleType>::StatsType& stats)
 {
-       const TheilSenLineFit contributionFitting = fitLineToSamples(samples, &SampleType::allocDuration);
+       const LineParametersWithConfidence contributionFitting = fitLineToSamples(samples, &SampleType::allocDuration);
        log     << tcu::TestLog::Float("AllocConstantCost", "Alloc: Approximated contant cost", "us", QP_KEY_TAG_TIME, contributionFitting.offset)
                << tcu::TestLog::Float("AllocLinearCost", "Alloc: Approximated linear cost", "us / MB", QP_KEY_TAG_TIME, contributionFitting.coefficient * 1024.0f * 1024.0f)
                << tcu::TestLog::Float("AllocMedianCost", "Alloc: Median cost", "us", QP_KEY_TAG_TIME, stats.alloc.medianTime);
@@ -1304,7 +1241,7 @@ static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_ALLOC_STATS>::T
 template <typename SampleType>
 static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_RENDER_STATS>::Type logRenderContribution (tcu::TestLog& log, const std::vector<RenderSampleResult<SampleType> >& samples, const typename SampleTypeTraits<SampleType>::StatsType& stats)
 {
-       const TheilSenLineFit contributionFitting = fitLineToSamples(samples, &SampleType::renderDuration);
+       const LineParametersWithConfidence contributionFitting = fitLineToSamples(samples, &SampleType::renderDuration);
        log     << tcu::TestLog::Float("DrawCallConstantCost", "DrawCall: Approximated contant cost", "us", QP_KEY_TAG_TIME, contributionFitting.offset)
                << tcu::TestLog::Float("DrawCallLinearCost", "DrawCall: Approximated linear cost", "us / MB", QP_KEY_TAG_TIME, contributionFitting.coefficient * 1024.0f * 1024.0f)
                << tcu::TestLog::Float("DrawCallMedianCost", "DrawCall: Median cost", "us", QP_KEY_TAG_TIME, stats.render.medianTime);
@@ -1313,7 +1250,7 @@ static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_RENDER_STATS>::
 template <typename SampleType>
 static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_READ_STATS>::Type logReadContribution (tcu::TestLog& log, const std::vector<RenderSampleResult<SampleType> >& samples, const typename SampleTypeTraits<SampleType>::StatsType& stats)
 {
-       const TheilSenLineFit contributionFitting = fitLineToSamples(samples, &SampleType::readDuration);
+       const LineParametersWithConfidence contributionFitting = fitLineToSamples(samples, &SampleType::readDuration);
        log     << tcu::TestLog::Float("ReadConstantCost", "Read: Approximated contant cost", "us", QP_KEY_TAG_TIME, contributionFitting.offset)
                << tcu::TestLog::Float("ReadLinearCost", "Read: Approximated linear cost", "us / MB", QP_KEY_TAG_TIME, contributionFitting.coefficient * 1024.0f * 1024.0f)
                << tcu::TestLog::Float("ReadMedianCost", "Read: Median cost", "us", QP_KEY_TAG_TIME, stats.read.medianTime);
@@ -1322,7 +1259,7 @@ static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_READ_STATS>::Ty
 template <typename SampleType>
 static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_UPLOAD_STATS>::Type logUploadContribution (tcu::TestLog& log, const std::vector<RenderSampleResult<SampleType> >& samples, const typename SampleTypeTraits<SampleType>::StatsType& stats)
 {
-       const TheilSenLineFit contributionFitting = fitLineToSamples(samples, &SampleType::uploadDuration);
+       const LineParametersWithConfidence contributionFitting = fitLineToSamples(samples, &SampleType::uploadDuration);
        log     << tcu::TestLog::Float("UploadConstantCost", "Upload: Approximated contant cost", "us", QP_KEY_TAG_TIME, contributionFitting.offset)
                << tcu::TestLog::Float("UploadLinearCost", "Upload: Approximated linear cost", "us / MB", QP_KEY_TAG_TIME, contributionFitting.coefficient * 1024.0f * 1024.0f)
                << tcu::TestLog::Float("UploadMedianCost", "Upload: Median cost", "us", QP_KEY_TAG_TIME, stats.upload.medianTime);
@@ -1331,7 +1268,7 @@ static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_UPLOAD_STATS>::
 template <typename SampleType>
 static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_TOTAL_STATS>::Type logTotalContribution (tcu::TestLog& log, const std::vector<RenderSampleResult<SampleType> >& samples, const typename SampleTypeTraits<SampleType>::StatsType& stats)
 {
-       const TheilSenLineFit contributionFitting = fitLineToSamples(samples, &SampleType::totalDuration);
+       const LineParametersWithConfidence contributionFitting = fitLineToSamples(samples, &SampleType::totalDuration);
        log     << tcu::TestLog::Float("TotalConstantCost", "Total: Approximated contant cost", "us", QP_KEY_TAG_TIME, contributionFitting.offset)
                << tcu::TestLog::Float("TotalLinearCost", "Total: Approximated linear cost", "us / MB", QP_KEY_TAG_TIME, contributionFitting.coefficient * 1024.0f * 1024.0f)
                << tcu::TestLog::Float("TotalMedianCost", "Total: Median cost", "us", QP_KEY_TAG_TIME, stats.total.medianTime);
@@ -1340,7 +1277,7 @@ static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_TOTAL_STATS>::T
 template <typename SampleType>
 static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_FIRST_RENDER_STATS>::Type logFirstRenderContribution (tcu::TestLog& log, const std::vector<RenderSampleResult<SampleType> >& samples, const typename SampleTypeTraits<SampleType>::StatsType& stats)
 {
-       const TheilSenLineFit contributionFitting = fitLineToSamples(samples, &SampleType::firstRenderDuration);
+       const LineParametersWithConfidence contributionFitting = fitLineToSamples(samples, &SampleType::firstRenderDuration);
        log     << tcu::TestLog::Float("FirstDrawCallConstantCost", "First DrawCall: Approximated contant cost", "us", QP_KEY_TAG_TIME, contributionFitting.offset)
                << tcu::TestLog::Float("FirstDrawCallLinearCost", "First DrawCall: Approximated linear cost", "us / MB", QP_KEY_TAG_TIME, contributionFitting.coefficient * 1024.0f * 1024.0f)
                << tcu::TestLog::Float("FirstDrawCallMedianCost", "First DrawCall: Median cost", "us", QP_KEY_TAG_TIME, stats.firstRender.medianTime);
@@ -1349,7 +1286,7 @@ static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_FIRST_RENDER_ST
 template <typename SampleType>
 static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_SECOND_RENDER_STATS>::Type logSecondRenderContribution (tcu::TestLog& log, const std::vector<RenderSampleResult<SampleType> >& samples, const typename SampleTypeTraits<SampleType>::StatsType& stats)
 {
-       const TheilSenLineFit contributionFitting = fitLineToSamples(samples, &SampleType::secondRenderDuration);
+       const LineParametersWithConfidence contributionFitting = fitLineToSamples(samples, &SampleType::secondRenderDuration);
        log     << tcu::TestLog::Float("SecondDrawCallConstantCost", "Second DrawCall: Approximated contant cost", "us", QP_KEY_TAG_TIME, contributionFitting.offset)
                << tcu::TestLog::Float("SecondDrawCallLinearCost", "Second DrawCall: Approximated linear cost", "us / MB", QP_KEY_TAG_TIME, contributionFitting.coefficient * 1024.0f * 1024.0f)
                << tcu::TestLog::Float("SecondDrawCallMedianCost", "Second DrawCall: Median cost", "us", QP_KEY_TAG_TIME, stats.secondRender.medianTime);
@@ -1443,7 +1380,7 @@ static typename EnableIfNot<void, SampleTypeTraits<SampleType>::HAS_SECOND_RENDE
        DE_UNREF(stats);
 }
 
-void logSampleList (tcu::TestLog& log, const TheilSenLineFit& theilSenFitting, const std::vector<UploadSampleResult<SingleOperationDuration> >& samples)
+void logSampleList (tcu::TestLog& log, const LineParametersWithConfidence& theilSenFitting, const std::vector<UploadSampleResult<SingleOperationDuration> >& samples)
 {
        log << tcu::TestLog::SampleList("Samples", "Samples")
                << tcu::TestLog::SampleInfo
@@ -1467,7 +1404,7 @@ void logSampleList (tcu::TestLog& log, const TheilSenLineFit& theilSenFitting, c
        log << tcu::TestLog::EndSampleList;
 }
 
-void logSampleList (tcu::TestLog& log, const TheilSenLineFit& theilSenFitting, const std::vector<UploadSampleResult<MapBufferRangeDuration> >& samples)
+void logSampleList (tcu::TestLog& log, const LineParametersWithConfidence& theilSenFitting, const std::vector<UploadSampleResult<MapBufferRangeDuration> >& samples)
 {
        log << tcu::TestLog::SampleList("Samples", "Samples")
                << tcu::TestLog::SampleInfo
@@ -1499,7 +1436,7 @@ void logSampleList (tcu::TestLog& log, const TheilSenLineFit& theilSenFitting, c
        log << tcu::TestLog::EndSampleList;
 }
 
-void logSampleList (tcu::TestLog& log, const TheilSenLineFit& theilSenFitting, const std::vector<UploadSampleResult<MapBufferRangeDurationNoAlloc> >& samples)
+void logSampleList (tcu::TestLog& log, const LineParametersWithConfidence& theilSenFitting, const std::vector<UploadSampleResult<MapBufferRangeDurationNoAlloc> >& samples)
 {
        log << tcu::TestLog::SampleList("Samples", "Samples")
                << tcu::TestLog::SampleInfo
@@ -1529,7 +1466,7 @@ void logSampleList (tcu::TestLog& log, const TheilSenLineFit& theilSenFitting, c
        log << tcu::TestLog::EndSampleList;
 }
 
-void logSampleList (tcu::TestLog& log, const TheilSenLineFit& theilSenFitting, const std::vector<UploadSampleResult<MapBufferRangeFlushDuration> >& samples)
+void logSampleList (tcu::TestLog& log, const LineParametersWithConfidence& theilSenFitting, const std::vector<UploadSampleResult<MapBufferRangeFlushDuration> >& samples)
 {
        log << tcu::TestLog::SampleList("Samples", "Samples")
                << tcu::TestLog::SampleInfo
@@ -1563,7 +1500,7 @@ void logSampleList (tcu::TestLog& log, const TheilSenLineFit& theilSenFitting, c
        log << tcu::TestLog::EndSampleList;
 }
 
-void logSampleList (tcu::TestLog& log, const TheilSenLineFit& theilSenFitting, const std::vector<UploadSampleResult<MapBufferRangeFlushDurationNoAlloc> >& samples)
+void logSampleList (tcu::TestLog& log, const LineParametersWithConfidence& theilSenFitting, const std::vector<UploadSampleResult<MapBufferRangeFlushDurationNoAlloc> >& samples)
 {
        log << tcu::TestLog::SampleList("Samples", "Samples")
                << tcu::TestLog::SampleInfo
@@ -1595,7 +1532,7 @@ void logSampleList (tcu::TestLog& log, const TheilSenLineFit& theilSenFitting, c
        log << tcu::TestLog::EndSampleList;
 }
 
-void logSampleList (tcu::TestLog& log, const TheilSenLineFit& theilSenFitting, const std::vector<RenderSampleResult<RenderReadDuration> >& samples)
+void logSampleList (tcu::TestLog& log, const LineParametersWithConfidence& theilSenFitting, const std::vector<RenderSampleResult<RenderReadDuration> >& samples)
 {
        log << tcu::TestLog::SampleList("Samples", "Samples")
                << tcu::TestLog::SampleInfo
@@ -1623,7 +1560,7 @@ void logSampleList (tcu::TestLog& log, const TheilSenLineFit& theilSenFitting, c
        log << tcu::TestLog::EndSampleList;
 }
 
-void logSampleList (tcu::TestLog& log, const TheilSenLineFit& theilSenFitting, const std::vector<RenderSampleResult<UnrelatedUploadRenderReadDuration> >& samples)
+void logSampleList (tcu::TestLog& log, const LineParametersWithConfidence& theilSenFitting, const std::vector<RenderSampleResult<UnrelatedUploadRenderReadDuration> >& samples)
 {
        log << tcu::TestLog::SampleList("Samples", "Samples")
                << tcu::TestLog::SampleInfo
@@ -1653,7 +1590,7 @@ void logSampleList (tcu::TestLog& log, const TheilSenLineFit& theilSenFitting, c
        log << tcu::TestLog::EndSampleList;
 }
 
-void logSampleList (tcu::TestLog& log, const TheilSenLineFit& theilSenFitting, const std::vector<RenderSampleResult<UploadRenderReadDuration> >& samples)
+void logSampleList (tcu::TestLog& log, const LineParametersWithConfidence& theilSenFitting, const std::vector<RenderSampleResult<UploadRenderReadDuration> >& samples)
 {
        log << tcu::TestLog::SampleList("Samples", "Samples")
                << tcu::TestLog::SampleInfo
@@ -1687,7 +1624,7 @@ void logSampleList (tcu::TestLog& log, const TheilSenLineFit& theilSenFitting, c
        log << tcu::TestLog::EndSampleList;
 }
 
-void logSampleList (tcu::TestLog& log, const TheilSenLineFit& theilSenFitting, const std::vector<RenderSampleResult<UploadRenderReadDurationWithUnrelatedUploadSize> >& samples)
+void logSampleList (tcu::TestLog& log, const LineParametersWithConfidence& theilSenFitting, const std::vector<RenderSampleResult<UploadRenderReadDurationWithUnrelatedUploadSize> >& samples)
 {
        log << tcu::TestLog::SampleList("Samples", "Samples")
                << tcu::TestLog::SampleInfo
@@ -1723,7 +1660,7 @@ void logSampleList (tcu::TestLog& log, const TheilSenLineFit& theilSenFitting, c
        log << tcu::TestLog::EndSampleList;
 }
 
-void logSampleList (tcu::TestLog& log, const TheilSenLineFit& theilSenFitting, const std::vector<RenderSampleResult<RenderUploadRenderReadDuration> >& samples)
+void logSampleList (tcu::TestLog& log, const LineParametersWithConfidence& theilSenFitting, const std::vector<RenderSampleResult<RenderUploadRenderReadDuration> >& samples)
 {
        log << tcu::TestLog::SampleList("Samples", "Samples")
                << tcu::TestLog::SampleInfo
@@ -1763,7 +1700,7 @@ template <typename SampleType>
 static UploadSampleAnalyzeResult analyzeSampleResults (tcu::TestLog& log, const std::vector<UploadSampleResult<SampleType> >& samples, bool logBucketPerformance)
 {
        // Assume data is linear with some outliers, fit a line
-       const TheilSenLineFit                                                                   theilSenFitting                                         = fitLineToSamples(samples);
+       const LineParametersWithConfidence                                                                      theilSenFitting                                         = fitLineToSamples(samples);
        const typename SampleTypeTraits<SampleType>::StatsType  resultStats                                                     = calculateSampleStatistics(theilSenFitting, samples);
        float                                                                                                   approximatedTransferRate;
        float                                                                                                   approximatedTransferRateNoConstant;
@@ -1845,11 +1782,11 @@ static UploadSampleAnalyzeResult analyzeSampleResults (tcu::TestLog& log, const
                log     << tcu::TestLog::Float("ResultLinearity", "Sample linearity", "%", QP_KEY_TAG_QUALITY, sampleLinearity * 100.0f)
                        << tcu::TestLog::Float("SampleTemporalStability", "Sample temporal stability", "%", QP_KEY_TAG_QUALITY, sampleTemporalStability * 100.0f)
                        << tcu::TestLog::Float("ApproximatedConstantCost", "Approximated contant cost", "us", QP_KEY_TAG_TIME, theilSenFitting.offset)
-                       << tcu::TestLog::Float("ApproximatedConstantCostConfidence60Lower", "Approximated contant cost 60% confidence lower limit", "us", QP_KEY_TAG_TIME, theilSenFitting.offset60ConfidenceLower)
-                       << tcu::TestLog::Float("ApproximatedConstantCostConfidence60Upper", "Approximated contant cost 60% confidence upper limit", "us", QP_KEY_TAG_TIME, theilSenFitting.offset60ConfidenceUpper)
+                       << tcu::TestLog::Float("ApproximatedConstantCostConfidence60Lower", "Approximated contant cost 60% confidence lower limit", "us", QP_KEY_TAG_TIME, theilSenFitting.offsetConfidenceLower)
+                       << tcu::TestLog::Float("ApproximatedConstantCostConfidence60Upper", "Approximated contant cost 60% confidence upper limit", "us", QP_KEY_TAG_TIME, theilSenFitting.offsetConfidenceUpper)
                        << tcu::TestLog::Float("ApproximatedLinearCost", "Approximated linear cost", "us / MB", QP_KEY_TAG_TIME, theilSenFitting.coefficient * 1024.0f * 1024.0f)
-                       << tcu::TestLog::Float("ApproximatedLinearCostConfidence60Lower", "Approximated linear cost 60% confidence lower limit", "us / MB", QP_KEY_TAG_TIME, theilSenFitting.coefficient60ConfidenceLower * 1024.0f * 1024.0f)
-                       << tcu::TestLog::Float("ApproximatedLinearCostConfidence60Upper", "Approximated linear cost 60% confidence upper limit", "us / MB", QP_KEY_TAG_TIME, theilSenFitting.coefficient60ConfidenceUpper * 1024.0f * 1024.0f)
+                       << tcu::TestLog::Float("ApproximatedLinearCostConfidence60Lower", "Approximated linear cost 60% confidence lower limit", "us / MB", QP_KEY_TAG_TIME, theilSenFitting.coefficientConfidenceLower * 1024.0f * 1024.0f)
+                       << tcu::TestLog::Float("ApproximatedLinearCostConfidence60Upper", "Approximated linear cost 60% confidence upper limit", "us / MB", QP_KEY_TAG_TIME, theilSenFitting.coefficientConfidenceUpper * 1024.0f * 1024.0f)
                        << tcu::TestLog::Float("ApproximatedTransferRate", "Approximated transfer rate", "MB / s", QP_KEY_TAG_PERFORMANCE, approximatedTransferRate / 1024.0f / 1024.0f)
                        << tcu::TestLog::Float("ApproximatedTransferRateNoConstant", "Approximated transfer rate without constant cost", "MB / s", QP_KEY_TAG_PERFORMANCE, approximatedTransferRateNoConstant / 1024.0f / 1024.0f)
                        << tcu::TestLog::Float("SampleMedianTime", "Median sample time", "us", QP_KEY_TAG_TIME, resultStats.result.medianTime)
@@ -1872,7 +1809,7 @@ template <typename SampleType>
 static RenderSampleAnalyzeResult analyzeSampleResults (tcu::TestLog& log, const std::vector<RenderSampleResult<SampleType> >& samples)
 {
        // Assume data is linear with some outliers, fit a line
-       const TheilSenLineFit                                                                   theilSenFitting                                         = fitLineToSamples(samples);
+       const LineParametersWithConfidence                                                                      theilSenFitting                                         = fitLineToSamples(samples);
        const typename SampleTypeTraits<SampleType>::StatsType  resultStats                                                     = calculateSampleStatistics(theilSenFitting, samples);
        float                                                                                                   approximatedProcessingRate;
        float                                                                                                   approximatedProcessingRateNoConstant;
@@ -1912,11 +1849,11 @@ static RenderSampleAnalyzeResult analyzeSampleResults (tcu::TestLog& log, const
                log     << tcu::TestLog::Float("ResultLinearity", "Sample linearity", "%", QP_KEY_TAG_QUALITY, sampleLinearity * 100.0f)
                        << tcu::TestLog::Float("SampleTemporalStability", "Sample temporal stability", "%", QP_KEY_TAG_QUALITY, sampleTemporalStability * 100.0f)
                        << tcu::TestLog::Float("ApproximatedConstantCost", "Approximated contant cost", "us", QP_KEY_TAG_TIME, theilSenFitting.offset)
-                       << tcu::TestLog::Float("ApproximatedConstantCostConfidence60Lower", "Approximated contant cost 60% confidence lower limit", "us", QP_KEY_TAG_TIME, theilSenFitting.offset60ConfidenceLower)
-                       << tcu::TestLog::Float("ApproximatedConstantCostConfidence60Upper", "Approximated contant cost 60% confidence upper limit", "us", QP_KEY_TAG_TIME, theilSenFitting.offset60ConfidenceUpper)
+                       << tcu::TestLog::Float("ApproximatedConstantCostConfidence60Lower", "Approximated contant cost 60% confidence lower limit", "us", QP_KEY_TAG_TIME, theilSenFitting.offsetConfidenceLower)
+                       << tcu::TestLog::Float("ApproximatedConstantCostConfidence60Upper", "Approximated contant cost 60% confidence upper limit", "us", QP_KEY_TAG_TIME, theilSenFitting.offsetConfidenceUpper)
                        << tcu::TestLog::Float("ApproximatedLinearCost", "Approximated linear cost", "us / MB", QP_KEY_TAG_TIME, theilSenFitting.coefficient * 1024.0f * 1024.0f)
-                       << tcu::TestLog::Float("ApproximatedLinearCostConfidence60Lower", "Approximated linear cost 60% confidence lower limit", "us / MB", QP_KEY_TAG_TIME, theilSenFitting.coefficient60ConfidenceLower * 1024.0f * 1024.0f)
-                       << tcu::TestLog::Float("ApproximatedLinearCostConfidence60Upper", "Approximated linear cost 60% confidence upper limit", "us / MB", QP_KEY_TAG_TIME, theilSenFitting.coefficient60ConfidenceUpper * 1024.0f * 1024.0f)
+                       << tcu::TestLog::Float("ApproximatedLinearCostConfidence60Lower", "Approximated linear cost 60% confidence lower limit", "us / MB", QP_KEY_TAG_TIME, theilSenFitting.coefficientConfidenceLower * 1024.0f * 1024.0f)
+                       << tcu::TestLog::Float("ApproximatedLinearCostConfidence60Upper", "Approximated linear cost 60% confidence upper limit", "us / MB", QP_KEY_TAG_TIME, theilSenFitting.coefficientConfidenceUpper * 1024.0f * 1024.0f)
                        << tcu::TestLog::Float("ApproximatedProcessRate", "Approximated processing rate", "MB / s", QP_KEY_TAG_PERFORMANCE, approximatedProcessingRate / 1024.0f / 1024.0f)
                        << tcu::TestLog::Float("ApproximatedProcessRateNoConstant", "Approximated processing rate without constant cost", "MB / s", QP_KEY_TAG_PERFORMANCE, approximatedProcessingRateNoConstant / 1024.0f / 1024.0f)
                        << tcu::TestLog::Float("SampleMedianTime", "Median sample time", "us", QP_KEY_TAG_TIME, resultStats.result.medianTime)
@@ -6233,9 +6170,9 @@ bool UploadWaitDrawCase::checkSampleTemporalStability (deUint64 (UploadWaitDrawC
 {
        // Try to find correlation with sample order and sample times
 
-       const int                               numDataPoints   = (int)m_iterationOrder.size();
-       std::vector<tcu::Vec2>  dataPoints              (m_iterationOrder.size());
-       TheilSenLineFit                 lineFit;
+       const int                                               numDataPoints   = (int)m_iterationOrder.size();
+       std::vector<tcu::Vec2>                  dataPoints              (m_iterationOrder.size());
+       LineParametersWithConfidence    lineFit;
 
        for (int ndx = 0; ndx < (int)m_iterationOrder.size(); ++ndx)
        {
@@ -6243,7 +6180,7 @@ bool UploadWaitDrawCase::checkSampleTemporalStability (deUint64 (UploadWaitDrawC
                dataPoints[m_iterationOrder[ndx]].y() = (float)(m_results[m_iterationOrder[ndx]].*target);
        }
 
-       lineFit = theilSenLinearRegression(dataPoints);
+       lineFit = theilSenSiegelLinearRegression(dataPoints, 0.6f);
 
        // Difference of more than 25% of the offset along the whole sample range
        if (de::abs(lineFit.coefficient) * numDataPoints > de::abs(lineFit.offset) * 0.25f)
diff --git a/modules/gles3/performance/es3pDepthTests.cpp b/modules/gles3/performance/es3pDepthTests.cpp
new file mode 100644 (file)
index 0000000..2638a1e
--- /dev/null
@@ -0,0 +1,1911 @@
+/*-------------------------------------------------------------------------
+ * drawElements Quality Program OpenGL ES 3.0 Module
+ * -------------------------------------------------
+ *
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *//*!
+ * \file
+ * \brief Depth buffer performance tests.
+ *//*--------------------------------------------------------------------*/
+
+#include "es3pDepthTests.hpp"
+
+#include "glsCalibration.hpp"
+
+#include "gluShaderProgram.hpp"
+#include "gluObjectWrapper.hpp"
+#include "gluPixelTransfer.hpp"
+
+#include "glwFunctions.hpp"
+#include "glwEnums.hpp"
+
+#include "tcuTestLog.hpp"
+#include "tcuStringTemplate.hpp"
+#include "tcuCPUWarmup.hpp"
+#include "tcuCommandLine.hpp"
+
+#include "deClock.h"
+#include "deString.h"
+#include "deMath.h"
+#include "deStringUtil.hpp"
+#include "deRandom.hpp"
+#include "deUniquePtr.hpp"
+
+#include <vector>
+#include <algorithm>
+
+namespace deqp
+{
+namespace gles3
+{
+namespace Performance
+{
+namespace
+{
+using namespace glw;
+using de::MovePtr;
+using tcu::TestContext;
+using tcu::TestLog;
+using tcu::Vec4;
+using tcu::Vec3;
+using tcu::Vec2;
+using glu::RenderContext;
+using glu::ProgramSources;
+using glu::ShaderSource;
+using std::vector;
+using std::string;
+using std::map;
+
+struct Sample
+{
+       deInt64 nullTime;
+       deInt64 baseTime;
+       deInt64 testTime;
+       int             order;
+       int             workload;
+};
+
+struct SampleParams
+{
+       int step;
+       int measurement;
+
+       SampleParams(int step_, int measurement_) : step(step_), measurement(measurement_) {}
+};
+
+typedef vector<float> Geometry;
+
+struct ObjectData
+{
+       ProgramSources  shader;
+       Geometry                geometry;
+
+       ObjectData (const ProgramSources& shader_, const Geometry& geometry_) : shader(shader_), geometry(geometry_) {}
+};
+
+class RenderData
+{
+public:
+                                                               RenderData              (const ObjectData& object, const glu::RenderContext& renderCtx, TestLog& log);
+                                                               ~RenderData             (void) {};
+
+       const glu::ShaderProgram        m_program;
+       const glu::VertexArray          m_vao;
+       const glu::Buffer                       m_vbo;
+
+       const int                                       m_numVertices;
+};
+
+RenderData::RenderData (const ObjectData& object, const  glu::RenderContext& renderCtx, TestLog& log)
+       : m_program             (renderCtx, object.shader)
+       , m_vao                 (renderCtx.getFunctions())
+       , m_vbo                 (renderCtx.getFunctions())
+       , m_numVertices (int(object.geometry.size())/4)
+{
+       const glw::Functions& gl = renderCtx.getFunctions();
+
+       if (!m_program.isOk())
+               log << m_program;
+
+       gl.bindBuffer(GL_ARRAY_BUFFER, *m_vbo);
+       gl.bufferData(GL_ARRAY_BUFFER, object.geometry.size() * sizeof(float), &object.geometry[0], GL_STATIC_DRAW);
+       gl.bindAttribLocation(m_program.getProgram(), 0, "a_position");
+
+       gl.bindVertexArray(*m_vao);
+       gl.vertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
+       gl.enableVertexAttribArray(0);
+       gl.bindVertexArray(0);
+}
+
+namespace Utils
+{
+       vector<float> getFullscreenQuad (float depth)
+       {
+               const float data[] =
+               {
+                       +1.0f, +1.0f, depth, 0.0f, // .w is gl_VertexId%3 since Nexus 4&5 can't handle that on their own
+                       +1.0f, -1.0f, depth, 1.0f,
+                       -1.0f, -1.0f, depth, 2.0f,
+                       -1.0f, -1.0f, depth, 0.0f,
+                       -1.0f, +1.0f, depth, 1.0f,
+                       +1.0f, +1.0f, depth, 2.0f,
+               };
+
+               return vector<float>(DE_ARRAY_BEGIN(data), DE_ARRAY_END(data));
+       }
+
+       vector<float> getFullscreenQuadWithGradient (float depth0, float depth1)
+       {
+               const float data[] =
+               {
+                       +1.0f, +1.0f, depth0, 0.0f,
+                       +1.0f, -1.0f, depth0, 1.0f,
+                       -1.0f, -1.0f, depth1, 2.0f,
+                       -1.0f, -1.0f, depth1, 0.0f,
+                       -1.0f, +1.0f, depth1, 1.0f,
+                       +1.0f, +1.0f, depth0, 2.0f,
+               };
+
+               return vector<float>(DE_ARRAY_BEGIN(data), DE_ARRAY_END(data));
+       }
+
+       vector<float> getPartScreenQuad (float coverage, float depth)
+       {
+               const float xMax        = -1.0f + 2.0f*coverage;
+               const float data[]      =
+               {
+                        xMax, +1.0f, depth, 0.0f,
+                        xMax, -1.0f, depth, 1.0f,
+                       -1.0f, -1.0f, depth, 2.0f,
+                       -1.0f, -1.0f, depth, 0.0f,
+                       -1.0f, +1.0f, depth, 1.0f,
+                        xMax, +1.0f, depth, 2.0f,
+               };
+
+               return vector<float>(DE_ARRAY_BEGIN(data), DE_ARRAY_END(data));
+       }
+
+       // Axis aligned grid. Depth of vertices is baseDepth +/- depthNoise
+       vector<float> getFullScreenGrid (int resolution, deUint32 seed, float baseDepth, float depthNoise, float xyNoise)
+       {
+               const int               gridsize        = resolution+1;
+               vector<Vec3>    vertices        (gridsize*gridsize);
+               vector<float>   retval;
+               de::Random              rng                     (seed);
+
+               for (int y = 0; y < gridsize; y++)
+               for (int x = 0; x < gridsize; x++)
+               {
+                       const bool      isEdge  = x == 0 || y == 0 || x == resolution || y == resolution;
+                       const float x_          = float(x)/float(resolution)*2.0f - 1.0f + (isEdge ? 0.0f : rng.getFloat(-xyNoise, +xyNoise));
+                       const float y_          = float(y)/float(resolution)*2.0f - 1.0f + (isEdge ? 0.0f : rng.getFloat(-xyNoise, +xyNoise));
+                       const float z_          = baseDepth + rng.getFloat(-depthNoise, +depthNoise);
+
+                       vertices[y*gridsize + x] = Vec3(x_, y_, z_);
+               }
+
+               retval.reserve(resolution*resolution*6);
+
+               for (int y = 0; y < resolution; y++)
+               for (int x = 0; x < resolution; x++)
+               {
+                       const Vec3& p0 = vertices[(y+0)*gridsize + (x+0)];
+                       const Vec3& p1 = vertices[(y+0)*gridsize + (x+1)];
+                       const Vec3& p2 = vertices[(y+1)*gridsize + (x+0)];
+                       const Vec3& p3 = vertices[(y+1)*gridsize + (x+1)];
+
+                       const float temp[6*4] =
+                       {
+                               p0.x(), p0.y(), p0.z(), 0.0f,
+                               p2.x(), p2.y(), p2.z(), 1.0f,
+                               p1.x(), p1.y(), p1.z(), 2.0f,
+
+                               p3.x(), p3.y(), p3.z(), 0.0f,
+                               p1.x(), p1.y(), p1.z(), 1.0f,
+                               p2.x(), p2.y(), p2.z(), 2.0f,
+                       };
+
+                       retval.insert(retval.end(), DE_ARRAY_BEGIN(temp), DE_ARRAY_END(temp));
+               }
+
+               return retval;
+       }
+
+       // Outputs barycentric coordinates as v_bcoords. Otherwise a passthrough shader
+       string getBaseVertexShader (void)
+       {
+               return "#version 300 es\n"
+                               "in highp vec4 a_position;\n"
+                               "out mediump vec3 v_bcoords;\n"
+                               "void main()\n"
+                               "{\n"
+                               "       v_bcoords = vec3(0, 0, 0);\n"
+                               "       v_bcoords[int(a_position.w)] = 1.0;\n"
+                               "       gl_Position = vec4(a_position.xyz, 1.0);\n"
+                               "}\n";
+       }
+
+       // Adds noise to coordinates based on InstanceID Outputs barycentric coordinates as v_bcoords
+       string getInstanceNoiseVertexShader (void)
+       {
+               return "#version 300 es\n"
+                               "in highp vec4 a_position;\n"
+                               "out mediump vec3 v_bcoords;\n"
+                               "void main()\n"
+                               "{\n"
+                               "       v_bcoords = vec3(0, 0, 0);\n"
+                               "       v_bcoords[int(a_position.w)] = 1.0;\n"
+                               "       vec3 noise = vec3(sin(float(gl_InstanceID)*1.05), sin(float(gl_InstanceID)*1.23), sin(float(gl_InstanceID)*1.71));\n"
+                               "       gl_Position = vec4(a_position.xyz + noise * 0.005, 1.0);\n"
+                               "}\n";
+       }
+
+       // Renders green triangles with edges highlighted. Exact shade depends on depth.
+       string getDepthAsGreenFragmentShader (void)
+       {
+               return  "#version 300 es\n"
+                               "in mediump vec3 v_bcoords;\n"
+                               "out mediump vec4 fragColor;\n"
+                               "void main()\n"
+                               "{\n"
+                               "       mediump float d = gl_FragCoord.z;\n"
+                               "       if (v_bcoords.x < 0.02 || v_bcoords.y < 0.02 || v_bcoords.z < 0.02)\n"
+                               "               fragColor = vec4(d,1,d,1);\n"
+                               "       else\n"
+                               "               fragColor = vec4(0,d,0,1);\n"
+                               "}\n";
+       }
+
+       // Renders green triangles with edges highlighted. Exact shade depends on depth.
+       string getDepthAsRedFragmentShader (void)
+       {
+               return  "#version 300 es\n"
+                               "in mediump vec3 v_bcoords;\n"
+                               "out mediump vec4 fragColor;\n"
+                               "void main()\n"
+                               "{\n"
+                               "       mediump float d = gl_FragCoord.z;\n"
+                               "       if (v_bcoords.x < 0.02 || v_bcoords.y < 0.02 || v_bcoords.z < 0.02)\n"
+                               "               fragColor = vec4(1,d,d,1);\n"
+                               "       else\n"
+                               "               fragColor = vec4(d,0,0,1);\n"
+                               "}\n";
+       }
+
+       // Basic time waster. Renders red triangles with edges highlighted. Exact shade depends on depth.
+       string getArithmeticWorkloadFragmentShader (void)
+       {
+
+               return  "#version 300 es\n"
+                               "in mediump vec3 v_bcoords;\n"
+                               "out mediump vec4 fragColor;\n"
+                               "uniform mediump int u_iterations;\n"
+                               "void main()\n"
+                               "{\n"
+                               "       mediump float d = gl_FragCoord.z;\n"
+                               "       for (int i = 0; i<u_iterations; i++)\n"
+                               // cos(a)^2 + sin(a)^2 == 1. since d is in range [0,1] this will lose a few ULP's of precision per iteration but should not significantly change the value of d without extreme iteration counts
+                               "               d = d*sin(d)*sin(d) + d*cos(d)*cos(d);\n"
+                               "       if (v_bcoords.x < 0.02 || v_bcoords.y < 0.02 || v_bcoords.z < 0.02)\n"
+                               "               fragColor = vec4(1,d,d,1);\n"
+                               "       else\n"
+                               "               fragColor = vec4(d,0,0,1);\n"
+                               "}\n";
+       }
+
+       // Arithmetic workload shader but contains discard
+       string getArithmeticWorkloadDiscardFragmentShader (void)
+       {
+               return  "#version 300 es\n"
+                               "in mediump vec3 v_bcoords;\n"
+                               "out mediump vec4 fragColor;\n"
+                               "uniform mediump int u_iterations;\n"
+                               "void main()\n"
+                               "{\n"
+                               "       mediump float d = gl_FragCoord.z;\n"
+                               "       for (int i = 0; i<u_iterations; i++)\n"
+                               "               d = d*sin(d)*sin(d) + d*cos(d)*cos(d);\n"
+                               "       if (d < 0.5) discard;\n"
+                               "       if (v_bcoords.x < 0.02 || v_bcoords.y < 0.02 || v_bcoords.z < 0.02)\n"
+                               "               fragColor = vec4(1,d,d,1);\n"
+                               "       else\n"
+                               "               fragColor = vec4(d,0,0,1);\n"
+                               "}\n";
+       }
+
+       // Texture fetch based time waster. Renders red triangles with edges highlighted. Exact shade depends on depth.
+       string getTextureWorkloadFragmentShader (void)
+       {
+               return  "#version 300 es\n"
+                               "in mediump vec3 v_bcoords;\n"
+                               "out mediump vec4 fragColor;\n"
+                               "uniform mediump int u_iterations;\n"
+                               "uniform sampler2D u_texture;\n"
+                               "void main()\n"
+                               "{\n"
+                               "       mediump float d = gl_FragCoord.z;\n"
+                               "       for (int i = 0; i<u_iterations; i++)\n"
+                               "               d *= texture(u_texture, (gl_FragCoord.xy+vec2(i))/512.0).r;\n" // Texture is expected to be fully white
+                               "       if (v_bcoords.x < 0.02 || v_bcoords.y < 0.02 || v_bcoords.z < 0.02)\n"
+                               "               fragColor = vec4(1,1,1,1);\n"
+                               "       else\n"
+                               "               fragColor = vec4(d,0,0,1);\n"
+                               "}\n";
+       }
+
+       // Discard fragments in a grid pattern
+       string getGridDiscardFragmentShader (int gridsize)
+       {
+               const string            fragSrc = "#version 300 es\n"
+                                                                         "in mediump vec3 v_bcoords;\n"
+                                                                         "out mediump vec4 fragColor;\n"
+                                                                         "void main()\n"
+                                                                         "{\n"
+                                                                         "     mediump float d = gl_FragCoord.z;\n"
+                                                                         "     if ((int(gl_FragCoord.x)/${GRIDRENDER_SIZE} + int(gl_FragCoord.y)/${GRIDRENDER_SIZE})%2 == 0)\n"
+                                                                         "             discard;\n"
+                                                                         "     if (v_bcoords.x < 0.02 || v_bcoords.y < 0.02 || v_bcoords.z < 0.02)\n"
+                                                                         "             fragColor = vec4(d,1,d,1);\n"
+                                                                         "     else\n"
+                                                                         "             fragColor = vec4(0,d,0,1);\n"
+                                                                         "}\n";
+               map<string, string>     params;
+
+               params["GRIDRENDER_SIZE"] = de::toString(gridsize);
+
+               return tcu::StringTemplate(fragSrc).specialize(params);
+       }
+
+       // A static increment to frag depth
+       string getStaticFragDepthFragmentShader (void)
+       {
+               return  "#version 300 es\n"
+                               "in mediump vec3 v_bcoords;\n"
+                               "out mediump vec4 fragColor;\n"
+                               "void main()\n"
+                               "{\n"
+                               "       mediump float d = gl_FragCoord.z;\n"
+                               "       gl_FragDepth = gl_FragCoord.z + 0.1;\n"
+                               "       if (v_bcoords.x < 0.02 || v_bcoords.y < 0.02 || v_bcoords.z < 0.02)\n"
+                               "               fragColor = vec4(d,1,d,1);\n"
+                               "       else\n"
+                               "               fragColor = vec4(0,d,0,1);\n"
+                               "}\n";
+       }
+
+       // A trivial dynamic change to frag depth
+       string getDynamicFragDepthFragmentShader (void)
+       {
+               return  "#version 300 es\n"
+                               "in mediump vec3 v_bcoords;\n"
+                               "out mediump vec4 fragColor;\n"
+                               "void main()\n"
+                               "{\n"
+                               "       mediump float d = gl_FragCoord.z;\n"
+                               "       gl_FragDepth = gl_FragCoord.z + (v_bcoords.x + v_bcoords.y + v_bcoords.z)*0.05;\n" // Sum of v_bcoords components is allways 1
+                               "       if (v_bcoords.x < 0.02 || v_bcoords.y < 0.02 || v_bcoords.z < 0.02)\n"
+                               "               fragColor = vec4(d,1,d,1);\n"
+                               "       else\n"
+                               "               fragColor = vec4(0,d,0,1);\n"
+                               "}\n";
+       }
+
+       // A static increment to frag depth
+       string getStaticFragDepthArithmeticWorkloadFragmentShader (void)
+       {
+               return  "#version 300 es\n"
+                               "in mediump vec3 v_bcoords;\n"
+                               "out mediump vec4 fragColor;\n"
+                               "uniform mediump int u_iterations;\n"
+                               "void main()\n"
+                               "{\n"
+                               "       mediump float d = gl_FragCoord.z;\n"
+                               "       gl_FragDepth = gl_FragCoord.z + 0.1;\n"
+                               "       for (int i = 0; i<u_iterations; i++)\n"
+                               "               d = d*sin(d)*sin(d) + d*cos(d)*cos(d);\n"
+                               "       if (v_bcoords.x < 0.02 || v_bcoords.y < 0.02 || v_bcoords.z < 0.02)\n"
+                               "               fragColor = vec4(1,d,d,1);\n"
+                               "       else\n"
+                               "               fragColor = vec4(d,0,0,1);\n"
+                               "}\n";
+       }
+
+       // A trivial dynamic change to frag depth
+       string getDynamicFragDepthArithmeticWorkloadFragmentShader (void)
+       {
+               return  "#version 300 es\n"
+                               "in mediump vec3 v_bcoords;\n"
+                               "out mediump vec4 fragColor;\n"
+                               "uniform mediump int u_iterations;\n"
+                               "void main()\n"
+                               "{\n"
+                               "       mediump float d = gl_FragCoord.z;\n"
+                               "       gl_FragDepth = gl_FragCoord.z + (v_bcoords.x + v_bcoords.y + v_bcoords.z)*0.05;\n" // Sum of v_bcoords components is allways 1
+                               "       for (int i = 0; i<u_iterations; i++)\n"
+                               "               d = d*sin(d)*sin(d) + d*cos(d)*cos(d);\n"
+                               "       if (v_bcoords.x < 0.02 || v_bcoords.y < 0.02 || v_bcoords.z < 0.02)\n"
+                               "               fragColor = vec4(1,d,d,1);\n"
+                               "       else\n"
+                               "               fragColor = vec4(d,0,0,1);\n"
+                               "}\n";
+       }
+
+       glu::ProgramSources getBaseShader (void)
+       {
+               return glu::makeVtxFragSources(getBaseVertexShader(), getDepthAsGreenFragmentShader());
+       }
+
+       glu::ProgramSources getArithmeticWorkloadShader (void)
+       {
+               return glu::makeVtxFragSources(getBaseVertexShader(), getArithmeticWorkloadFragmentShader());
+       }
+
+       glu::ProgramSources getArithmeticWorkloadDiscardShader (void)
+       {
+               return glu::makeVtxFragSources(getBaseVertexShader(), getArithmeticWorkloadDiscardFragmentShader());
+       }
+
+       glu::ProgramSources getTextureWorkloadShader (void)
+       {
+               return glu::makeVtxFragSources(getBaseVertexShader(), getTextureWorkloadFragmentShader());
+       }
+
+       glu::ProgramSources getGridDiscardShader (int gridsize)
+       {
+               return glu::makeVtxFragSources(getBaseVertexShader(), getGridDiscardFragmentShader(gridsize));
+       }
+
+       inline ObjectData quadWith (const glu::ProgramSources& shader, float depth)
+       {
+               return ObjectData(shader, getFullscreenQuad(depth));
+       }
+
+       inline ObjectData quadWith (const string& fragShader, float depth)
+       {
+               return ObjectData(glu::makeVtxFragSources(getBaseVertexShader(), fragShader), getFullscreenQuad(depth));
+       }
+
+       inline ObjectData variableQuad (float depth)
+       {
+               return ObjectData(glu::makeVtxFragSources(getInstanceNoiseVertexShader(), getDepthAsRedFragmentShader()), getFullscreenQuad(depth));
+       }
+
+       inline ObjectData fastQuad (float depth)
+       {
+               return ObjectData(getBaseShader(), getFullscreenQuad(depth));
+       }
+
+       inline ObjectData slowQuad (float depth)
+       {
+               return ObjectData(getArithmeticWorkloadShader(), getFullscreenQuad(depth));
+       }
+
+       inline ObjectData fastQuadWithGradient (float depth0, float depth1)
+       {
+               return ObjectData(getBaseShader(), getFullscreenQuadWithGradient(depth0, depth1));
+       }
+} // Utils
+
+// Shared base
+class BaseCase : public tcu::TestCase
+{
+public:
+       enum {RENDER_SIZE = 512};
+
+                                                       BaseCase                        (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc);
+       virtual                                 ~BaseCase                       (void) {}
+
+       virtual IterateResult   iterate                         (void);
+
+protected:
+       void                                    logSamples                      (const vector<Sample>& samples, const string& name, const string& desc);
+       void                                    logGeometry                     (const tcu::ConstPixelBufferAccess& sample, const glu::ShaderProgram& occluderProg, const glu::ShaderProgram& occludedProg);
+       virtual void                    logAnalysis                     (const vector<Sample>& samples) = 0;
+       virtual void                    logDescription          (void) = 0;
+
+       virtual ObjectData              genOccluderGeometry     (void) const = 0;
+       virtual ObjectData              genOccludedGeometry     (void) const = 0;
+
+       virtual int                             calibrate                       (void) const = 0;
+       virtual Sample                  renderSample            (const RenderData& occluder, const RenderData& occluded, int workload) const = 0;
+
+       void                                    render                          (const RenderData& data) const;
+       void                                    render                          (const RenderData& data, int instances) const;
+
+       const RenderContext&    m_renderCtx;
+       tcu::ResultCollector    m_results;
+
+       enum {ITERATION_STEPS = 10, ITERATION_SAMPLES = 16};
+};
+
+BaseCase::BaseCase (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc)
+       : TestCase              (testCtx, tcu::NODETYPE_PERFORMANCE, name, desc)
+       , m_renderCtx   (renderCtx)
+{
+}
+
+BaseCase::IterateResult BaseCase::iterate (void)
+{
+       typedef de::MovePtr<RenderData> RenderDataP;
+
+       const glw::Functions&   gl                                      = m_renderCtx.getFunctions();
+       TestLog&                                log                                     = m_testCtx.getLog();
+
+       const glu::Framebuffer  framebuffer                     (gl);
+       const glu::Renderbuffer renderbuffer            (gl);
+       const glu::Renderbuffer depthbuffer                     (gl);
+
+       vector<Sample>                  results;
+       vector<int>                             params;
+       RenderDataP                             occluderData;
+       RenderDataP                             occludedData;
+       tcu::TextureLevel               resultTex                       (tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), RENDER_SIZE, RENDER_SIZE);
+       int                                             maxWorkload                     = 0;
+       de::Random                              rng                                     (deInt32Hash(deStringHash(getName())) ^ m_testCtx.getCommandLine().getBaseSeed());
+
+       logDescription();
+
+       gl.bindRenderbuffer(GL_RENDERBUFFER, *renderbuffer);
+       gl.renderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, RENDER_SIZE, RENDER_SIZE);
+       gl.bindRenderbuffer(GL_RENDERBUFFER, *depthbuffer);
+       gl.renderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, RENDER_SIZE, RENDER_SIZE);
+
+       gl.bindFramebuffer(GL_FRAMEBUFFER, *framebuffer);
+       gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, *renderbuffer);
+       gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, *depthbuffer);
+       gl.viewport(0, 0, RENDER_SIZE, RENDER_SIZE);
+       gl.clearColor(0.125f, 0.25f, 0.5f, 1.0f);
+
+       maxWorkload = calibrate();
+
+       // Setup data
+       occluderData = RenderDataP(new RenderData (genOccluderGeometry(), m_renderCtx, log));
+       occludedData = RenderDataP(new RenderData (genOccludedGeometry(), m_renderCtx, log));
+
+       TCU_CHECK(occluderData->m_program.isOk());
+       TCU_CHECK(occludedData->m_program.isOk());
+
+       // Force initialization of GPU resources
+       gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+       gl.enable(GL_DEPTH_TEST);
+
+       render(*occluderData);
+       render(*occludedData);
+       glu::readPixels(m_renderCtx, 0, 0, resultTex.getAccess());
+
+       logGeometry(resultTex.getAccess(), occluderData->m_program, occludedData->m_program);
+
+       params.reserve(ITERATION_STEPS*ITERATION_SAMPLES);
+
+       // Setup parameters
+       for (int step = 0; step < ITERATION_STEPS; step++)
+       {
+               const int workload = maxWorkload*step/ITERATION_STEPS;
+
+               for (int count = 0; count < ITERATION_SAMPLES; count++)
+                       params.push_back(workload);
+       }
+
+       rng.shuffle(params.begin(), params.end());
+
+       // Render samples
+       for (size_t ndx = 0; ndx < params.size(); ndx++)
+       {
+               const int       workload        = params[ndx];
+               Sample          sample          = renderSample(*occluderData, *occludedData, workload);
+
+               sample.workload = workload;
+               sample.order = int(ndx);
+
+               results.push_back(sample);
+       }
+
+       logSamples(results, "Samples", "Samples");
+       logAnalysis(results);
+
+       m_results.setTestContextResult(m_testCtx);
+
+       return STOP;
+}
+
+void BaseCase::logSamples (const vector<Sample>& samples, const string& name, const string& desc)
+{
+       TestLog& log = m_testCtx.getLog();
+
+       bool testOnly = true;
+
+       for (size_t ndx = 0; ndx < samples.size(); ndx++)
+       {
+               if (samples[ndx].baseTime != 0 || samples[ndx].nullTime != 0)
+               {
+                       testOnly = false;
+                       break;
+               }
+       }
+
+       log << TestLog::SampleList(name, desc);
+
+       if (testOnly)
+       {
+               log << TestLog::SampleInfo
+                       << TestLog::ValueInfo("Workload",       "Workload",                     "",                             QP_SAMPLE_VALUE_TAG_PREDICTOR)
+                       << TestLog::ValueInfo("Order",          "Order of sample",      "",                             QP_SAMPLE_VALUE_TAG_PREDICTOR)
+                       << TestLog::ValueInfo("TestTime",       "Test render time",     "us",                   QP_SAMPLE_VALUE_TAG_RESPONSE)
+                       << TestLog::EndSampleInfo;
+
+               for (size_t sampleNdx = 0; sampleNdx < samples.size(); sampleNdx++)
+               {
+                       const Sample& sample = samples[sampleNdx];
+
+                       log << TestLog::Sample << sample.workload << sample.order << sample.testTime << TestLog::EndSample;
+               }
+       }
+       else
+       {
+               log << TestLog::SampleInfo
+                       << TestLog::ValueInfo("Workload",       "Workload",                     "",                             QP_SAMPLE_VALUE_TAG_PREDICTOR)
+                       << TestLog::ValueInfo("Order",          "Order of sample",      "",                             QP_SAMPLE_VALUE_TAG_PREDICTOR)
+                       << TestLog::ValueInfo("TestTime",       "Test render time",     "us",                   QP_SAMPLE_VALUE_TAG_RESPONSE)
+                       << TestLog::ValueInfo("NullTime",       "Read pixels time",     "us",                   QP_SAMPLE_VALUE_TAG_RESPONSE)
+                       << TestLog::ValueInfo("BaseTime",       "Base render time",     "us",                   QP_SAMPLE_VALUE_TAG_RESPONSE)
+                       << TestLog::EndSampleInfo;
+
+               for (size_t sampleNdx = 0; sampleNdx < samples.size(); sampleNdx++)
+               {
+                       const Sample& sample = samples[sampleNdx];
+
+                       log << TestLog::Sample << sample.workload << sample.order << sample.testTime << sample.nullTime << sample.baseTime << TestLog::EndSample;
+               }
+       }
+
+       log << TestLog::EndSampleList;
+}
+
+void BaseCase::logGeometry (const tcu::ConstPixelBufferAccess& sample, const glu::ShaderProgram& occluderProg, const glu::ShaderProgram& occludedProg)
+{
+       TestLog& log = m_testCtx.getLog();
+
+       log << TestLog::Section("Geometry", "Geometry");
+       log << TestLog::Message << "Occluding geometry is green with shade dependent on depth (rgb == 0, depth, 0)" << TestLog::EndMessage;
+       log << TestLog::Message << "Occluded geometry is red with shade dependent on depth (rgb == depth, 0, 0)" << TestLog::EndMessage;
+       log << TestLog::Message << "Primitive edges are a lighter shade of red/green" << TestLog::EndMessage;
+
+       log << TestLog::Image("Test Geometry", "Test Geometry",  sample);
+       log << TestLog::EndSection;
+
+       log << TestLog::Section("Occluder", "Occluder");
+       log << occluderProg;
+       log << TestLog::EndSection;
+
+       log << TestLog::Section("Occluded", "Occluded");
+       log << occludedProg;
+       log << TestLog::EndSection;
+}
+
+void BaseCase::render (const RenderData& data) const
+{
+       const glw::Functions& gl = m_renderCtx.getFunctions();
+
+       gl.useProgram(data.m_program.getProgram());
+
+       gl.bindVertexArray(*data.m_vao);
+       gl.drawArrays(GL_TRIANGLES, 0, data.m_numVertices);
+       gl.bindVertexArray(0);
+}
+
+void BaseCase::render (const RenderData& data, int instances) const
+{
+       const glw::Functions& gl = m_renderCtx.getFunctions();
+
+       gl.useProgram(data.m_program.getProgram());
+
+       gl.bindVertexArray(*data.m_vao);
+       gl.drawArraysInstanced(GL_TRIANGLES, 0, data.m_numVertices, instances);
+       gl.bindVertexArray(0);
+}
+
+// Render occluder once, then repeatedly render occluded geometry. Sample with multiple repetition counts & establish time per call with linear regression
+class RenderCountCase : public BaseCase
+{
+public:
+                                       RenderCountCase         (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc);
+                                       ~RenderCountCase        (void) {}
+
+protected:
+       virtual void    logAnalysis                     (const vector<Sample>& samples);
+
+private:
+       virtual int             calibrate                       (void) const;
+       virtual Sample  renderSample            (const RenderData& occluder, const RenderData& occluded, int callcount) const;
+};
+
+RenderCountCase::RenderCountCase (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc)
+       : BaseCase      (testCtx, renderCtx, name, desc)
+{
+}
+
+void RenderCountCase::logAnalysis (const vector<Sample>& samples)
+{
+       using namespace gls;
+
+       TestLog&                log                     = m_testCtx.getLog();
+       int                             maxWorkload     = 0;
+       vector<Vec2>    testSamples     (samples.size());
+
+       for (size_t ndx = 0; ndx < samples.size(); ndx++)
+       {
+               const Sample& sample = samples[ndx];
+
+               testSamples[ndx] = Vec2((float)sample.workload, (float)sample.testTime);
+
+               maxWorkload = de::max(maxWorkload, sample.workload);
+       }
+
+       {
+               const float                                                     confidence      = 0.60f;
+               const LineParametersWithConfidence      testParam       = theilSenSiegelLinearRegression(testSamples, confidence);
+               const float                                                     usPerCall       = testParam.coefficient;
+               const float                                                     pxPerCall       = RENDER_SIZE*RENDER_SIZE;
+               const float                                                     pxPerUs         = pxPerCall/usPerCall;
+               const float                                                     mpxPerS         = pxPerUs;
+
+               log << TestLog::Section("Linear Regression", "Linear Regression");
+               log << TestLog::Message << "Offset & coefficient presented as [confidence interval min, estimate, confidence interval max]. Reported confidence interval for this test is " << confidence << TestLog::EndMessage;
+               log << TestLog::Message << "Render time for scene with depth test was\n\t"
+                       << "[" << testParam.offsetConfidenceLower << ", " << testParam.offset <<  ", " << testParam.offsetConfidenceUpper << "]us +"
+                       << "[" << testParam.coefficientConfidenceLower << ", " << testParam.coefficient << ", " << testParam.coefficientConfidenceUpper << "]"
+                       << "us/workload" << TestLog::EndMessage;
+               log << TestLog::EndSection;
+
+               log << TestLog::Section("Result", "Result");
+
+               if (testParam.coefficientConfidenceLower < 0.0f)
+               {
+                       log << TestLog::Message << "Coefficient confidence bounds include values below 0.0, the operation likely has neglible per-pixel cost" << TestLog::EndMessage;
+                       m_results.addResult(QP_TEST_RESULT_PASS, "Pass");
+               }
+               else if (testParam.coefficientConfidenceLower < testParam.coefficientConfidenceUpper*0.25)
+               {
+                       log << TestLog::Message << "Coefficient confidence range is extremely large, cannot give reliable result" << TestLog::EndMessage;
+                       m_results.addResult(QP_TEST_RESULT_PASS, "Result confidence extremely low");
+               }
+               else
+               {
+                       log << TestLog::Message << "Culled hidden pixels @ " << mpxPerS << "Mpx/s" << TestLog::EndMessage;
+                       m_results.addResult(QP_TEST_RESULT_PASS, de::floatToString(mpxPerS, 2));
+               }
+
+               log << TestLog::EndSection;
+       }
+}
+
+Sample RenderCountCase::renderSample (const RenderData& occluder, const RenderData& occluded, int callcount) const
+{
+       const glw::Functions&   gl              = m_renderCtx.getFunctions();
+       Sample                                  sample;
+       deUint64                                now             = 0;
+       deUint64                                prev    = 0;
+       deUint8                                 buffer[4];
+
+       // Stabilize
+       {
+               gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+               gl.enable(GL_DEPTH_TEST);
+               gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
+       }
+
+       prev = deGetMicroseconds();
+
+       gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+       gl.enable(GL_DEPTH_TEST);
+
+       render(occluder);
+       render(occluded, callcount);
+
+       gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
+
+       now = deGetMicroseconds();
+
+       sample.testTime = now - prev;
+       sample.baseTime = 0;
+       sample.nullTime = 0;
+       sample.workload = callcount;
+
+       return sample;
+}
+
+int RenderCountCase::calibrate (void) const
+{
+       using namespace gls;
+
+       const glw::Functions&   gl                                      = m_renderCtx.getFunctions();
+       TestLog&                                log                                     = m_testCtx.getLog();
+
+       const RenderData                occluderGeometry        (genOccluderGeometry(), m_renderCtx, log);
+       const RenderData                occludedGeometry        (genOccludedGeometry(), m_renderCtx, log);
+
+       TheilSenCalibrator              calibrator                      (CalibratorParameters(20, // Initial workload
+                                                                                                                                         10, // Max iteration frames
+                                                                                                                                         20.0f, // Iteration shortcut threshold ms
+                                                                                                                                         20, // Max iterations
+                                                                                                                                         33.0f, // Target frame time
+                                                                                                                                         40.0f, // Frame time cap
+                                                                                                                                         1000.0f // Target measurement duration
+                                                                                                                                         ));
+
+       while (true)
+       {
+               switch(calibrator.getState())
+               {
+                       case TheilSenCalibrator::STATE_FINISHED:
+                               logCalibrationInfo(m_testCtx.getLog(), calibrator);
+                               return calibrator.getCallCount();
+
+                       case TheilSenCalibrator::STATE_MEASURE:
+                       {
+                               deUint8 buffer[4];
+                               deInt64 now;
+                               deInt64 prev;
+
+                               prev = deGetMicroseconds();
+
+                               gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+                               gl.disable(GL_DEPTH_TEST);
+
+                               render(occluderGeometry);
+                               render(occludedGeometry, calibrator.getCallCount());
+
+                               gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
+
+                               now = deGetMicroseconds();
+
+                               calibrator.recordIteration(now - prev);
+                               break;
+                       }
+
+                       case TheilSenCalibrator::STATE_RECOMPUTE_PARAMS:
+                               calibrator.recomputeParameters();
+                               break;
+                       default:
+                               DE_ASSERT(false);
+                               return 1;
+               }
+       }
+}
+
+// Compares time/workload gradients of same geometry with and without depth testing
+class RelativeChangeCase : public BaseCase
+{
+public:
+                                       RelativeChangeCase      (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc);
+       virtual                 ~RelativeChangeCase     (void) {}
+
+protected:
+       Sample                  renderSample            (const RenderData& occluder, const RenderData& occluded, int workload) const;
+
+       virtual void    logAnalysis                     (const vector<Sample>& samples);
+
+private:
+       int                             calibrate                       (void) const;
+};
+
+RelativeChangeCase::RelativeChangeCase (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc)
+       : BaseCase              (testCtx, renderCtx, name, desc)
+{
+}
+
+int RelativeChangeCase::calibrate (void) const
+{
+       using namespace gls;
+
+       const glw::Functions&   gl              = m_renderCtx.getFunctions();
+       TestLog&                                log             = m_testCtx.getLog();
+
+       const RenderData                geom    (genOccludedGeometry(), m_renderCtx, log);
+
+       TheilSenCalibrator calibrator(CalibratorParameters( 20, // Initial workload
+                                                                                                               10, // Max iteration frames
+                                                                                                               20.0f, // Iteration shortcut threshold ms
+                                                                                                               20, // Max iterations
+                                                                                                               10.0f, // Target frame time
+                                                                                                               15.0f, // Frame time cap
+                                                                                                               1000.0f // Target measurement duration
+                                                                                                               ));
+
+       while (true)
+       {
+               switch(calibrator.getState())
+               {
+                       case TheilSenCalibrator::STATE_FINISHED:
+                               logCalibrationInfo(m_testCtx.getLog(), calibrator);
+                               return calibrator.getCallCount();
+
+                       case TheilSenCalibrator::STATE_MEASURE:
+                       {
+                               deUint8                 buffer[4];
+                               const GLuint    program = geom.m_program.getProgram();
+
+                               gl.useProgram(program);
+                               gl.uniform1i(gl.getUniformLocation(program, "u_iterations"), calibrator.getCallCount());
+
+                               const deInt64 prev = deGetMicroseconds();
+
+                               gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+                               gl.disable(GL_DEPTH_TEST);
+
+                               render(geom);
+
+                               gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
+
+                               const deInt64 now = deGetMicroseconds();
+
+                               calibrator.recordIteration(now - prev);
+                               break;
+                       }
+
+                       case TheilSenCalibrator::STATE_RECOMPUTE_PARAMS:
+                               calibrator.recomputeParameters();
+                               break;
+                       default:
+                               DE_ASSERT(false);
+                               return 1;
+               }
+       }
+}
+
+Sample RelativeChangeCase::renderSample (const RenderData& occluder, const RenderData& occluded, int workload) const
+{
+       const glw::Functions&   gl              = m_renderCtx.getFunctions();
+       const GLuint                    program = occluded.m_program.getProgram();
+       Sample                                  sample;
+       deUint64                                now             = 0;
+       deUint64                                prev    = 0;
+       deUint8                                 buffer[4];
+
+       gl.useProgram(program);
+       gl.uniform1i(gl.getUniformLocation(program, "u_iterations"), workload);
+
+       // Warmup (this workload seems to reduce variation in following workloads)
+       {
+               gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+               gl.disable(GL_DEPTH_TEST);
+
+               gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
+       }
+
+       // Null time
+       {
+               prev = deGetMicroseconds();
+
+               gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+               gl.disable(GL_DEPTH_TEST);
+
+               gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
+
+               now = deGetMicroseconds();
+
+               sample.nullTime = now - prev;
+       }
+
+       // Test time
+       {
+               prev = deGetMicroseconds();
+
+               gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+               gl.enable(GL_DEPTH_TEST);
+
+               render(occluder);
+               render(occluded);
+
+               gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
+
+               now = deGetMicroseconds();
+
+               sample.testTime = now - prev;
+       }
+
+       // Base time
+       {
+               prev = deGetMicroseconds();
+
+               gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+               gl.disable(GL_DEPTH_TEST);
+
+               render(occluder);
+               render(occluded);
+
+               gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
+
+               now = deGetMicroseconds();
+
+               sample.baseTime = now - prev;
+       }
+
+       sample.workload = 0;
+
+       return sample;
+}
+
+void RelativeChangeCase::logAnalysis (const vector<Sample>& samples)
+{
+       using namespace gls;
+
+       TestLog&                log                     = m_testCtx.getLog();
+
+       int                             maxWorkload     = 0;
+
+       vector<Vec2>    nullSamples     (samples.size());
+       vector<Vec2>    baseSamples     (samples.size());
+       vector<Vec2>    testSamples     (samples.size());
+
+       for (size_t ndx = 0; ndx < samples.size(); ndx++)
+       {
+               const Sample& sample = samples[ndx];
+
+               nullSamples[ndx] = Vec2((float)sample.workload, (float)sample.nullTime);
+               baseSamples[ndx] = Vec2((float)sample.workload, (float)sample.baseTime);
+               testSamples[ndx] = Vec2((float)sample.workload, (float)sample.testTime);
+
+               maxWorkload = de::max(maxWorkload, sample.workload);
+       }
+
+       {
+               const float                                                     confidence      = 0.60f;
+
+               const LineParametersWithConfidence      nullParam       = theilSenSiegelLinearRegression(nullSamples, confidence);
+               const LineParametersWithConfidence      baseParam       = theilSenSiegelLinearRegression(baseSamples, confidence);
+               const LineParametersWithConfidence      testParam       = theilSenSiegelLinearRegression(testSamples, confidence);
+
+               if (!de::inRange(0.0f, nullParam.coefficientConfidenceLower, nullParam.coefficientConfidenceUpper))
+               {
+                       m_results.addResult(QP_TEST_RESULT_FAIL, "Constant operation sequence duration not constant");
+                       log << TestLog::Message << "Constant operation sequence timing may vary as a function of workload. Result quality extremely low" << TestLog::EndMessage;
+               }
+
+               if (de::inRange(0.0f, baseParam.coefficientConfidenceLower, baseParam.coefficientConfidenceUpper))
+               {
+                       m_results.addResult(QP_TEST_RESULT_FAIL, "Workload has no effect on duration");
+                       log << TestLog::Message << "Workload factor has no effect on duration of sample (smart optimizer?)" << TestLog::EndMessage;
+               }
+
+               log << TestLog::Section("Linear Regression", "Linear Regression");
+               log << TestLog::Message << "Offset & coefficient presented as [confidence interval min, estimate, confidence interval max]. Reported confidence interval for this test is " << confidence << TestLog::EndMessage;
+
+               log << TestLog::Message << "Render time for empty scene was\n\t"
+                       << "[" << nullParam.offsetConfidenceLower << ", " << nullParam.offset <<  ", " << nullParam.offsetConfidenceUpper << "]us +"
+                       << "[" << nullParam.coefficientConfidenceLower << ", " << nullParam.coefficient << ", " << nullParam.coefficientConfidenceUpper << "]"
+                       << "us/workload" << TestLog::EndMessage;
+
+               log << TestLog::Message << "Render time for scene without depth test was\n\t"
+                       << "[" << baseParam.offsetConfidenceLower << ", " << baseParam.offset <<  ", " << baseParam.offsetConfidenceUpper << "]us +"
+                       << "[" << baseParam.coefficientConfidenceLower << ", " << baseParam.coefficient << ", " << baseParam.coefficientConfidenceUpper << "]"
+                       << "us/workload" << TestLog::EndMessage;
+
+               log << TestLog::Message << "Render time for scene with depth test was\n\t"
+                       << "[" << testParam.offsetConfidenceLower << ", " << testParam.offset <<  ", " << testParam.offsetConfidenceUpper << "]us +"
+                       << "[" << testParam.coefficientConfidenceLower << ", " << testParam.coefficient << ", " << testParam.coefficientConfidenceUpper << "]"
+                       << "us/workload" << TestLog::EndMessage;
+
+               log << TestLog::EndSection;
+
+               if (de::inRange(0.0f, testParam.coefficientConfidenceLower, testParam.coefficientConfidenceUpper))
+               {
+                       log << TestLog::Message << "Test duration not dependent on culled workload" << TestLog::EndMessage;
+                       m_results.addResult(QP_TEST_RESULT_PASS, "0.0");
+               }
+               else if (testParam.coefficientConfidenceLower < testParam.coefficientConfidenceUpper*0.25)
+               {
+                       log << TestLog::Message << "Coefficient confidence range is extremely large, cannot give reliable result" << TestLog::EndMessage;
+                       m_results.addResult(QP_TEST_RESULT_PASS, "Result confidence extremely low");
+               }
+               else if (baseParam.coefficientConfidenceLower < baseParam.coefficientConfidenceUpper*0.25)
+               {
+                       log << TestLog::Message << "Coefficient confidence range for base render time is extremely large, cannot give reliable result" << TestLog::EndMessage;
+                       m_results.addResult(QP_TEST_RESULT_PASS, "Result confidence extremely low");
+               }
+               else
+               {
+                       log << TestLog::Message << "Test duration is dependent on culled workload" << TestLog::EndMessage;
+                       m_results.addResult(QP_TEST_RESULT_PASS, de::floatToString(de::abs(testParam.coefficient)/de::abs(baseParam.coefficient), 2));
+               }
+       }
+}
+
+// Speed of trivial culling
+class BaseCostCase : public RenderCountCase
+{
+public:
+                                               BaseCostCase            (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc)
+                                                       : RenderCountCase (testCtx, renderCtx, name, desc) {}
+
+                                               ~BaseCostCase           (void) {}
+
+private:
+       virtual ObjectData      genOccluderGeometry     (void) const { return Utils::fastQuad(0.2f); }
+       virtual ObjectData      genOccludedGeometry     (void) const { return Utils::variableQuad(0.8f); }
+
+       virtual void            logDescription          (void)
+       {
+               TestLog& log = m_testCtx.getLog();
+
+               log << TestLog::Section("Description", "Test description");
+               log << TestLog::Message << "Testing hidden fragment culling speed" << TestLog::EndMessage;
+               log << TestLog::Message << "Geometry consists of two fullsceen quads. The first (occluding) is rendered once, the second (occluded) is rendered repeatedly" << TestLog::EndMessage;
+               log << TestLog::Message << "Workload indicates the number of times the occluded quad is rendered"  << TestLog::EndMessage;
+               log << TestLog::Message << "The time per culled pixel is estimated from the rate of change of rendering time as a function of workload"  << TestLog::EndMessage;
+               log << TestLog::EndSection;
+       }
+};
+
+// Gradient
+class GradientCostCase : public RenderCountCase
+{
+public:
+                                               GradientCostCase        (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc, float gradientDistance)
+                                                       : RenderCountCase               (testCtx, renderCtx, name, desc)
+                                                       , m_gradientDistance    (gradientDistance)
+                                               {
+                                               }
+
+                                               ~GradientCostCase       (void) {}
+
+private:
+       virtual ObjectData      genOccluderGeometry     (void) const { return Utils::fastQuadWithGradient(0.0f, 1.0f - m_gradientDistance); }
+       virtual ObjectData      genOccludedGeometry     (void) const
+       {
+               return ObjectData(glu::makeVtxFragSources(Utils::getInstanceNoiseVertexShader(), Utils::getDepthAsRedFragmentShader()), Utils::getFullscreenQuadWithGradient(m_gradientDistance, 1.0f));
+       }
+
+       virtual void            logDescription          (void)
+       {
+               TestLog& log = m_testCtx.getLog();
+
+               log << TestLog::Section("Description", "Test description");
+               log << TestLog::Message << "Testing hidden fragment culling speed" << TestLog::EndMessage;
+               log << TestLog::Message << "Geometry consists of two fullsceen quads. The first (occluding) is rendered once, the second (occluded) is rendered repeatedly" << TestLog::EndMessage;
+               log << TestLog::Message << "Workload indicates the number of times the occluded quad is rendered" << TestLog::EndMessage;
+               log << TestLog::Message << "The quads are tilted so that the left edge of the occluded quad has a depth of 1.0 and the right edge of the occluding quad has a depth of 0.0." << TestLog::EndMessage;
+               log << TestLog::Message << "The quads are spaced to have a depth difference of " << m_gradientDistance << " at all points." << TestLog::EndMessage;
+               log << TestLog::Message << "The time per culled pixel is estimated from the rate of change of rendering time as a function of workload"  << TestLog::EndMessage;
+               log << TestLog::EndSection;
+       }
+
+       const float                     m_gradientDistance;
+};
+
+// Constant offset to frag depth in occluder
+class OccluderStaticFragDepthCostCase : public RenderCountCase
+{
+public:
+                                               OccluderStaticFragDepthCostCase         (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc)
+                                                       : RenderCountCase(testCtx, renderCtx, name, desc)
+                                               {
+                                               }
+
+                                               ~OccluderStaticFragDepthCostCase        (void) {}
+
+private:
+       virtual ObjectData      genOccluderGeometry                                     (void) const { return Utils::quadWith(Utils::getStaticFragDepthFragmentShader(), 0.2f); }
+       virtual ObjectData      genOccludedGeometry                                     (void) const { return Utils::fastQuad(0.8f); }
+
+       virtual void            logDescription                                          (void)
+       {
+               TestLog& log = m_testCtx.getLog();
+
+               log << TestLog::Section("Description", "Test description");
+               log << TestLog::Message << "Testing hidden fragment culling speed" << TestLog::EndMessage;
+               log << TestLog::Message << "Geometry consists of two fullsceen quads. The first (occluding) is rendered once, the second (occluded) is rendered repeatedly" << TestLog::EndMessage;
+               log << TestLog::Message << "Workload indicates the number of times the occluded quad is rendered" << TestLog::EndMessage;
+               log << TestLog::Message << "The occluder quad has a static offset applied to gl_FragDepth" << TestLog::EndMessage;
+               log << TestLog::Message << "The time per culled pixel is estimated from the rate of change of rendering time as a function of workload"  << TestLog::EndMessage;
+               log << TestLog::EndSection;
+       }
+};
+
+// Dynamic offset to frag depth in occluder
+class OccluderDynamicFragDepthCostCase : public RenderCountCase
+{
+public:
+                                               OccluderDynamicFragDepthCostCase        (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc)
+                                                       : RenderCountCase(testCtx, renderCtx, name, desc)
+                                               {
+                                               }
+
+                                               ~OccluderDynamicFragDepthCostCase       (void) {}
+
+private:
+       virtual ObjectData      genOccluderGeometry                                     (void) const { return Utils::quadWith(Utils::getDynamicFragDepthFragmentShader(), 0.2f); }
+       virtual ObjectData      genOccludedGeometry                                     (void) const { return Utils::fastQuad(0.8f); }
+
+       virtual void            logDescription                                          (void)
+       {
+               TestLog& log = m_testCtx.getLog();
+
+               log << TestLog::Section("Description", "Test description");
+               log << TestLog::Message << "Testing hidden fragment culling speed" << TestLog::EndMessage;
+               log << TestLog::Message << "Geometry consists of two fullsceen quads. The first (occluding) is rendered once, the second (occluded) is rendered repeatedly" << TestLog::EndMessage;
+               log << TestLog::Message << "Workload indicates the number of times the occluded quad is rendered" << TestLog::EndMessage;
+               log << TestLog::Message << "The occluder quad has a dynamic offset applied to gl_FragDepth" << TestLog::EndMessage;
+               log << TestLog::Message << "The time per culled pixel is estimated from the rate of change of rendering time as a function of workload"  << TestLog::EndMessage;
+               log << TestLog::EndSection;
+       }
+};
+
+// Constant offset to frag depth in occluder
+class OccludedStaticFragDepthCostCase : public RenderCountCase
+{
+public:
+                                               OccludedStaticFragDepthCostCase         (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc)
+                                                       : RenderCountCase(testCtx, renderCtx, name, desc)
+                                               {
+                                               }
+
+                                               ~OccludedStaticFragDepthCostCase        (void) {}
+
+private:
+       virtual ObjectData      genOccluderGeometry                                     (void) const { return Utils::fastQuad(0.2f); }
+       virtual ObjectData      genOccludedGeometry                                     (void) const { return Utils::quadWith(Utils::getStaticFragDepthFragmentShader(), 0.2f); }
+
+       virtual void            logDescription                                          (void)
+       {
+               TestLog& log = m_testCtx.getLog();
+
+               log << TestLog::Section("Description", "Test description");
+               log << TestLog::Message << "Testing hidden fragment culling speed" << TestLog::EndMessage;
+               log << TestLog::Message << "Geometry consists of two fullsceen quads. The first (occluding) is rendered once, the second (occluded) is rendered repeatedly" << TestLog::EndMessage;
+               log << TestLog::Message << "Workload indicates the number of times the occluded quad is rendered" << TestLog::EndMessage;
+               log << TestLog::Message << "The occluded quad has a static offset applied to gl_FragDepth" << TestLog::EndMessage;
+               log << TestLog::Message << "The time per culled pixel is estimated from the rate of change of rendering time as a function of workload"  << TestLog::EndMessage;
+               log << TestLog::EndSection;
+       }
+};
+
+// Dynamic offset to frag depth in occluder
+class OccludedDynamicFragDepthCostCase : public RenderCountCase
+{
+public:
+                                               OccludedDynamicFragDepthCostCase        (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc)
+                                                       : RenderCountCase(testCtx, renderCtx, name, desc)
+                                               {
+                                               }
+
+                                               ~OccludedDynamicFragDepthCostCase       (void) {}
+
+private:
+       virtual ObjectData      genOccluderGeometry                                     (void) const { return Utils::fastQuad(0.2f); }
+       virtual ObjectData      genOccludedGeometry                                     (void) const { return Utils::quadWith(Utils::getDynamicFragDepthFragmentShader(), 0.2f); }
+
+       virtual void            logDescription                                          (void)
+       {
+               TestLog& log = m_testCtx.getLog();
+
+               log << TestLog::Section("Description", "Test description");
+               log << TestLog::Message << "Testing hidden fragment culling speed" << TestLog::EndMessage;
+               log << TestLog::Message << "Geometry consists of two fullsceen quads. The first (occluding) is rendered once, the second (occluded) is rendered repeatedly" << TestLog::EndMessage;
+               log << TestLog::Message << "Workload indicates the number of times the occluded quad is rendered" << TestLog::EndMessage;
+               log << TestLog::Message << "The occluded quad has a dynamic offset applied to gl_FragDepth" << TestLog::EndMessage;
+               log << TestLog::Message << "The time per culled pixel is estimated from the rate of change of rendering time as a function of workload"  << TestLog::EndMessage;
+               log << TestLog::EndSection;
+       }
+};
+
+// Culling speed with slightly less trivial geometry
+class OccludingGeometryComplexityCostCase : public RenderCountCase
+{
+public:
+                                               OccludingGeometryComplexityCostCase             (TestContext&                   testCtx,
+                                                                                                                                const RenderContext&   renderCtx,
+                                                                                                                                const char*                    name,
+                                                                                                                                const char*                    desc,
+                                                                                                                                int                                    resolution,
+                                                                                                                                float                                  xyNoise,
+                                                                                                                                float                                  zNoise)
+                                                       : RenderCountCase       (testCtx, renderCtx, name, desc)
+                                                       , m_resolution          (resolution)
+                                                       , m_xyNoise                     (xyNoise)
+                                                       , m_zNoise                      (zNoise)
+                                               {
+                                               }
+
+                                               ~OccludingGeometryComplexityCostCase    (void) {}
+
+private:
+       virtual ObjectData      genOccluderGeometry                                             (void) const
+       {
+               return ObjectData(Utils::getBaseShader(),
+                                                 Utils::getFullScreenGrid(m_resolution,
+                                                 deInt32Hash(deStringHash(getName())) ^ m_testCtx.getCommandLine().getBaseSeed(),
+                                                 0.2f,
+                                                 m_zNoise,
+                                                 m_xyNoise));
+       }
+
+       virtual ObjectData      genOccludedGeometry                                             (void) const { return Utils::variableQuad(0.8f); }
+
+       virtual void            logDescription          (void)
+       {
+               TestLog& log = m_testCtx.getLog();
+
+               log << TestLog::Section("Description", "Test description");
+               log << TestLog::Message << "Testing hidden fragment culling speed" << TestLog::EndMessage;
+               log << TestLog::Message << "Geometry consists of an occluding grid and an occluded fullsceen quad. The occluding geometry is rendered once, the occluded one is rendered repeatedly" << TestLog::EndMessage;
+               log << TestLog::Message << "Workload indicates the number of times the occluded quad is rendered"  << TestLog::EndMessage;
+               log << TestLog::Message << "The time per culled pixel is estimated from the rate of change of rendering time as a function of workload"  << TestLog::EndMessage;
+               log << TestLog::EndSection;
+       }
+
+       const int                       m_resolution;
+       const float                     m_xyNoise;
+       const float                     m_zNoise;
+};
+
+
+// Cases with varying workloads in the fragment shader
+class FragmentWorkloadCullCase : public RelativeChangeCase
+{
+public:
+                                               FragmentWorkloadCullCase        (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc);
+       virtual                         ~FragmentWorkloadCullCase       (void) {}
+
+private:
+       virtual ObjectData      genOccluderGeometry                     (void) const { return Utils::fastQuad(0.2f); }
+
+       virtual void            logDescription                          (void);
+};
+
+FragmentWorkloadCullCase::FragmentWorkloadCullCase (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc)
+       : RelativeChangeCase    (testCtx, renderCtx, name, desc)
+{
+}
+
+void FragmentWorkloadCullCase::logDescription (void)
+{
+       TestLog& log = m_testCtx.getLog();
+
+       log << TestLog::Section("Description", "Test description");
+       log << TestLog::Message << "Testing effects of culled fragment workload on render time" << TestLog::EndMessage;
+       log << TestLog::Message << "Geometry consists of two fullsceen quads. The first (occluding) quad uses a trivial shader,"
+               "the second (occluded) contains significant fragment shader work" << TestLog::EndMessage;
+       log << TestLog::Message << "Workload indicates the number of iterations of dummy work done in the occluded quad's fragment shader"  << TestLog::EndMessage;
+       log << TestLog::Message << "The ratio of rendering times of this scene with/without depth testing are compared"  << TestLog::EndMessage;
+       log << TestLog::Message << "Successfull early Z-testing should result in no correlation between workload and render time"  << TestLog::EndMessage;
+       log << TestLog::EndSection;
+}
+
+// Additional workload consists of texture lookups
+class FragmentTextureWorkloadCullCase : public FragmentWorkloadCullCase
+{
+public:
+                                               FragmentTextureWorkloadCullCase         (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc);
+       virtual                         ~FragmentTextureWorkloadCullCase        (void) {}
+
+       virtual void            init                                                            (void);
+       virtual void            deinit                                                          (void);
+
+private:
+       typedef MovePtr<glu::Texture> TexPtr;
+
+       virtual ObjectData      genOccludedGeometry                                     (void) const
+       {
+               return ObjectData(Utils::getTextureWorkloadShader(), Utils::getFullscreenQuad(0.8f));
+       }
+
+       TexPtr                          m_texture;
+};
+
+FragmentTextureWorkloadCullCase::FragmentTextureWorkloadCullCase (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc)
+       : FragmentWorkloadCullCase      (testCtx, renderCtx, name, desc)
+{
+}
+
+void FragmentTextureWorkloadCullCase::init (void)
+{
+       const glw::Functions&   gl              = m_renderCtx.getFunctions();
+       const int                               size    = 128;
+       const vector<deUint8>   data    (size*size*4, 255);
+
+       m_texture = MovePtr<glu::Texture>(new glu::Texture(gl));
+
+       gl.bindTexture(GL_TEXTURE_2D, m_texture);
+       gl.texImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, size, size, 0, GL_RGBA, GL_UNSIGNED_BYTE, &data[0]);
+       gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+       gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+}
+
+void FragmentTextureWorkloadCullCase::deinit (void)
+{
+       m_texture.clear();
+}
+
+// Additional workload consists of arithmetic
+class FragmentArithmeticWorkloadCullCase : public FragmentWorkloadCullCase
+{
+public:
+                                               FragmentArithmeticWorkloadCullCase      (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc)
+                                               : FragmentWorkloadCullCase      (testCtx, renderCtx, name, desc)
+                                       {
+                                       }
+       virtual                         ~FragmentArithmeticWorkloadCullCase     (void) {}
+
+private:
+       virtual ObjectData      genOccludedGeometry                                     (void) const
+       {
+               return ObjectData(Utils::getArithmeticWorkloadShader(), Utils::getFullscreenQuad(0.8f));
+       }
+};
+
+// Contains dynamicly unused discard after a series of calculations
+class FragmentDiscardArithmeticWorkloadCullCase : public FragmentWorkloadCullCase
+{
+public:
+                                               FragmentDiscardArithmeticWorkloadCullCase       (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc)
+                                               : FragmentWorkloadCullCase      (testCtx, renderCtx, name, desc)
+                                       {
+                                       }
+
+       virtual                         ~FragmentDiscardArithmeticWorkloadCullCase      (void) {}
+
+private:
+       virtual ObjectData      genOccludedGeometry                                                     (void) const
+       {
+               return ObjectData(Utils::getArithmeticWorkloadDiscardShader(), Utils::getFullscreenQuad(0.8f));
+       }
+
+       virtual void            logDescription                                                          (void)
+       {
+               TestLog& log = m_testCtx.getLog();
+
+               log << TestLog::Section("Description", "Test description");
+               log << TestLog::Message << "Testing effects of culled fragment workload on render time" << TestLog::EndMessage;
+               log << TestLog::Message << "Geometry consists of two fullsceen quads. The first (occluding) quad uses a trivial shader,"
+                       "the second (occluded) contains significant fragment shader work and a discard that is never triggers but has a dynamic condition" << TestLog::EndMessage;
+               log << TestLog::Message << "Workload indicates the number of iterations of dummy work done in the occluded quad's fragment shader"  << TestLog::EndMessage;
+               log << TestLog::Message << "The ratio of rendering times of this scene with/without depth testing are compared"  << TestLog::EndMessage;
+               log << TestLog::Message << "Successfull early Z-testing should result in no correlation between workload and render time"  << TestLog::EndMessage;
+               log << TestLog::EndSection;
+       }
+};
+
+// Discards fragments from the occluder in a grid pattern
+class PartialOccluderDiscardCullCase : public RelativeChangeCase
+{
+public:
+                                               PartialOccluderDiscardCullCase  (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc, int gridsize)
+                                                       : RelativeChangeCase            (testCtx, renderCtx, name, desc)
+                                                       , m_gridsize    (gridsize)
+                                               {
+                                               }
+       virtual                         ~PartialOccluderDiscardCullCase (void) {}
+
+private:
+       virtual ObjectData      genOccluderGeometry                             (void) const { return Utils::quadWith(Utils::getGridDiscardShader(m_gridsize), 0.2f); }
+       virtual ObjectData      genOccludedGeometry                             (void) const { return Utils::slowQuad(0.8f); }
+
+       virtual void            logDescription                                  (void)
+       {
+               TestLog& log = m_testCtx.getLog();
+
+               log << TestLog::Section("Description", "Test description");
+               log << TestLog::Message << "Testing effects of partially discarded occluder on rendering time" << TestLog::EndMessage;
+               log << TestLog::Message << "Geometry consists of two fullsceen quads. The first (occluding) quad discards half the "
+                       "fragments in a grid pattern, the second (partially occluded) contains significant fragment shader work" << TestLog::EndMessage;
+               log << TestLog::Message << "Workload indicates the number of iterations of dummy work done in the occluded quad's fragment shader"  << TestLog::EndMessage;
+               log << TestLog::Message << "The ratio of rendering times of this scene with/without depth testing are compared"  << TestLog::EndMessage;
+               log << TestLog::Message << "Successfull early Z-testing should result in depth testing halving the render time"  << TestLog::EndMessage;
+               log << TestLog::EndSection;
+       }
+
+       const int                       m_gridsize;
+};
+
+// Trivial occluder covering part of screen
+class PartialOccluderCullCase : public RelativeChangeCase
+{
+public:
+                                               PartialOccluderCullCase         (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc, float coverage)
+                                                       : RelativeChangeCase            (testCtx, renderCtx, name, desc)
+                                                       , m_coverage    (coverage)
+                                               {
+                                               }
+                                               ~PartialOccluderCullCase        (void) {}
+
+private:
+       virtual ObjectData      genOccluderGeometry                     (void) const { return ObjectData(Utils::getBaseShader(), Utils::getPartScreenQuad(m_coverage, 0.2f)); }
+       virtual ObjectData      genOccludedGeometry                     (void) const {return Utils::slowQuad(0.8f); }
+
+       virtual void            logDescription                          (void)
+       {
+               TestLog& log = m_testCtx.getLog();
+
+               log << TestLog::Section("Description", "Test description");
+               log << TestLog::Message << "Testing effects of partial occluder on rendering time" << TestLog::EndMessage;
+               log << TestLog::Message << "Geometry consists of two quads. The first (occluding) quad covers " << m_coverage*100.0f
+                       << "% of the screen, while the second (partially occluded, fullscreen) contains significant fragment shader work" << TestLog::EndMessage;
+               log << TestLog::Message << "Workload indicates the number of iterations of dummy work done in the occluded quad's fragment shader"  << TestLog::EndMessage;
+               log << TestLog::Message << "The ratio of rendering times of this scene with/without depth testing are compared"  << TestLog::EndMessage;
+               log << TestLog::Message << "Successfull early Z-testing should result in render time increasing proportionally with unoccluded area"  << TestLog::EndMessage;
+               log << TestLog::EndSection;
+       }
+
+       const float                     m_coverage;
+};
+
+// Constant offset to frag depth in occluder
+class StaticOccluderFragDepthCullCase : public RelativeChangeCase
+{
+public:
+                                               StaticOccluderFragDepthCullCase         (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc)
+                                                       : RelativeChangeCase(testCtx, renderCtx, name, desc)
+                                               {
+                                               }
+
+                                               ~StaticOccluderFragDepthCullCase        (void) {}
+
+private:
+       virtual ObjectData      genOccluderGeometry                                     (void) const { return Utils::quadWith(Utils::getStaticFragDepthFragmentShader(), 0.2f); }
+       virtual ObjectData      genOccludedGeometry                                     (void) const { return Utils::slowQuad(0.8f); }
+
+       virtual void            logDescription                                          (void)
+       {
+               TestLog& log = m_testCtx.getLog();
+
+               log << TestLog::Section("Description", "Test description");
+               log << TestLog::Message << "Testing effects of non-default frag depth on culling efficiency" << TestLog::EndMessage;
+               log << TestLog::Message << "Geometry consists of two fullscreen quads. The first (occluding) quad is trivial, while the second (occluded) contains significant fragment shader work" << TestLog::EndMessage;
+               log << TestLog::Message << "Workload indicates the number of iterations of dummy work done in the occluded quad's fragment shader"  << TestLog::EndMessage;
+               log << TestLog::Message << "The occluder quad has a static offset applied to gl_FragDepth" << TestLog::EndMessage;
+               log << TestLog::Message << "The ratio of rendering times of this scene with/without depth testing are compared"  << TestLog::EndMessage;
+               log << TestLog::Message << "Successfull early Z-testing should result in no correlation between workload and render time"  << TestLog::EndMessage;
+               log << TestLog::EndSection;
+       }
+};
+
+// Dynamic offset to frag depth in occluder
+class DynamicOccluderFragDepthCullCase : public RelativeChangeCase
+{
+public:
+                                               DynamicOccluderFragDepthCullCase        (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc)
+                                                       : RelativeChangeCase(testCtx, renderCtx, name, desc)
+                                               {
+                                               }
+
+                                               ~DynamicOccluderFragDepthCullCase       (void) {}
+
+private:
+       virtual ObjectData      genOccluderGeometry                                     (void) const { return Utils::quadWith(Utils::getDynamicFragDepthFragmentShader(), 0.2f); }
+       virtual ObjectData      genOccludedGeometry                                     (void) const { return Utils::slowQuad(0.8f); }
+
+       virtual void            logDescription                                          (void)
+       {
+               TestLog& log = m_testCtx.getLog();
+
+               log << TestLog::Section("Description", "Test description");
+               log << TestLog::Message << "Testing effects of non-default frag depth on culling efficiency" << TestLog::EndMessage;
+               log << TestLog::Message << "Geometry consists of two fullscreen quads. The first (occluding) quad is trivial, while the second (occluded) contains significant fragment shader work" << TestLog::EndMessage;
+               log << TestLog::Message << "Workload indicates the number of iterations of dummy work done in the occluded quad's fragment shader"  << TestLog::EndMessage;
+               log << TestLog::Message << "The occluder quad has a dynamic offset applied to gl_FragDepth" << TestLog::EndMessage;
+               log << TestLog::Message << "The ratio of rendering times of this scene with/without depth testing are compared"  << TestLog::EndMessage;
+               log << TestLog::Message << "Successfull early Z-testing should result in no correlation between workload and render time"  << TestLog::EndMessage;
+               log << TestLog::EndSection;
+       }
+};
+
+// Constant offset to frag depth in occluded
+class StaticOccludedFragDepthCullCase : public RelativeChangeCase
+{
+public:
+                                               StaticOccludedFragDepthCullCase (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc)
+                                                       : RelativeChangeCase(testCtx, renderCtx, name, desc)
+                                               {
+                                               }
+
+                                               ~StaticOccludedFragDepthCullCase        (void) {}
+
+private:
+       virtual ObjectData      genOccluderGeometry                                     (void) const { return Utils::fastQuad(0.2f); }
+       virtual ObjectData      genOccludedGeometry                                     (void) const { return Utils::quadWith(Utils::getStaticFragDepthArithmeticWorkloadFragmentShader(), 0.2f); }
+
+       virtual void            logDescription                                          (void)
+       {
+               TestLog& log = m_testCtx.getLog();
+
+               log << TestLog::Section("Description", "Test description");
+               log << TestLog::Message << "Testing effects of non-default frag depth on rendering time" << TestLog::EndMessage;
+               log << TestLog::Message << "Geometry consists of two fullscreen quads. The first (occluding) quad is trivial, while the second (occluded) contains significant fragment shader work" << TestLog::EndMessage;
+               log << TestLog::Message << "Workload indicates the number of iterations of dummy work done in the occluded quad's fragment shader"  << TestLog::EndMessage;
+               log << TestLog::Message << "The occluded quad has a static offset applied to gl_FragDepth" << TestLog::EndMessage;
+               log << TestLog::Message << "The ratio of rendering times of this scene with/without depth testing are compared"  << TestLog::EndMessage;
+               log << TestLog::Message << "Successfull early Z-testing should result in no correlation between workload and render time"  << TestLog::EndMessage;
+               log << TestLog::EndSection;
+       }
+};
+
+// Dynamic offset to frag depth in occluded
+class DynamicOccludedFragDepthCullCase : public RelativeChangeCase
+{
+public:
+                                               DynamicOccludedFragDepthCullCase        (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc)
+                                                       : RelativeChangeCase(testCtx, renderCtx, name, desc)
+                                               {
+                                               }
+
+                                               ~DynamicOccludedFragDepthCullCase       (void) {}
+
+private:
+       virtual ObjectData      genOccluderGeometry                                     (void) const { return Utils::fastQuad(0.2f); }
+       virtual ObjectData      genOccludedGeometry                                     (void) const { return Utils::quadWith(Utils::getDynamicFragDepthArithmeticWorkloadFragmentShader(), 0.2f); }
+
+       virtual void            logDescription                                          (void)
+       {
+               TestLog& log = m_testCtx.getLog();
+
+               log << TestLog::Section("Description", "Test description");
+               log << TestLog::Message << "Testing effects of non-default frag depth on rendering time" << TestLog::EndMessage;
+               log << TestLog::Message << "Geometry consists of two fullscreen quads. The first (occluding) quad is trivial, while the second (occluded) contains significant fragment shader work" << TestLog::EndMessage;
+               log << TestLog::Message << "Workload indicates the number of iterations of dummy work done in the occluded quad's fragment shader"  << TestLog::EndMessage;
+               log << TestLog::Message << "The occluded quad has a dynamic offset applied to gl_FragDepth" << TestLog::EndMessage;
+               log << TestLog::Message << "The ratio of rendering times of this scene with/without depth testing are compared"  << TestLog::EndMessage;
+               log << TestLog::Message << "Successfull early Z-testing should result in no correlation between workload and render time"  << TestLog::EndMessage;
+               log << TestLog::EndSection;
+       }
+};
+
+// Dynamic offset to frag depth in occluded
+class ReversedDepthOrderCullCase : public RelativeChangeCase
+{
+public:
+                                               ReversedDepthOrderCullCase      (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc)
+                                                       : RelativeChangeCase(testCtx, renderCtx, name, desc)
+                                               {
+                                               }
+
+                                               ~ReversedDepthOrderCullCase     (void) {}
+
+private:
+       virtual ObjectData      genOccluderGeometry                     (void) const { return Utils::fastQuad(0.2f); }
+       virtual ObjectData      genOccludedGeometry                     (void) const { return Utils::slowQuad(0.8f); }
+
+       virtual void            logDescription                          (void)
+       {
+               TestLog& log = m_testCtx.getLog();
+
+               log << TestLog::Section("Description", "Test description");
+               log << TestLog::Message << "Testing effects of of back first rendering order on culling efficiency" << TestLog::EndMessage;
+               log << TestLog::Message << "Geometry consists of two fullscreen quads. The second (occluding) quad is trivial, while the first (occluded) contains significant fragment shader work" << TestLog::EndMessage;
+               log << TestLog::Message << "Workload indicates the number of iterations of dummy work done in the occluded quad's fragment shader"  << TestLog::EndMessage;
+               log << TestLog::Message << "The ratio of rendering times of this scene with/without depth testing are compared"  << TestLog::EndMessage;
+               log << TestLog::Message << "Successfull early Z-testing should result in no correlation between workload and render time"  << TestLog::EndMessage;
+               log << TestLog::EndSection;
+       }
+
+       // Rendering order of occluder & occluded is reversed, otherwise identical to parent version
+       Sample                          renderSample                            (const RenderData& occluder, const RenderData& occluded, int workload) const
+       {
+               const glw::Functions&   gl              = m_renderCtx.getFunctions();
+               const GLuint                    program = occluded.m_program.getProgram();
+               Sample                                  sample;
+               deUint64                                now             = 0;
+               deUint64                                prev    = 0;
+               deUint8                                 buffer[4];
+
+               gl.useProgram(program);
+               gl.uniform1i(gl.getUniformLocation(program, "u_iterations"), workload);
+
+               // Warmup (this workload seems to reduce variation in following workloads)
+               {
+                       gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+                       gl.disable(GL_DEPTH_TEST);
+
+                       gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
+               }
+
+               // Null time
+               {
+                       prev = deGetMicroseconds();
+
+                       gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+                       gl.disable(GL_DEPTH_TEST);
+
+                       gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
+
+                       now = deGetMicroseconds();
+
+                       sample.nullTime = now - prev;
+               }
+
+               // Test time
+               {
+                       prev = deGetMicroseconds();
+
+                       gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+                       gl.enable(GL_DEPTH_TEST);
+
+                       render(occluded);
+                       render(occluder);
+
+                       gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
+
+                       now = deGetMicroseconds();
+
+                       sample.testTime = now - prev;
+               }
+
+               // Base time
+               {
+                       prev = deGetMicroseconds();
+
+                       gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+                       gl.disable(GL_DEPTH_TEST);
+
+                       render(occluded);
+                       render(occluder);
+
+                       gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
+
+                       now = deGetMicroseconds();
+
+                       sample.baseTime = now - prev;
+               }
+
+               sample.workload = 0;
+
+               return sample;
+       }
+};
+
+} // Anonymous
+
+DepthTests::DepthTests (Context& context)
+       : TestCaseGroup (context, "depth", "Depth culling performance")
+{
+}
+
+void DepthTests::init (void)
+{
+       TestContext&                    testCtx         = m_context.getTestContext();
+       const RenderContext&    renderCtx       = m_context.getRenderContext();
+
+       {
+               tcu::TestCaseGroup* const cullEfficiencyGroup = new tcu::TestCaseGroup(m_testCtx, "cull_efficiency", "Fragment cull efficiency");
+
+               addChild(cullEfficiencyGroup);
+
+               {
+                       tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "workload", "Workload");
+
+                       cullEfficiencyGroup->addChild(group);
+
+                       group->addChild(new FragmentTextureWorkloadCullCase(                    testCtx, renderCtx, "workload_texture",                         "Fragment shader with texture lookup workload"));
+                       group->addChild(new FragmentArithmeticWorkloadCullCase(                 testCtx, renderCtx, "workload_arithmetic",                      "Fragment shader with arithmetic workload"));
+                       group->addChild(new FragmentDiscardArithmeticWorkloadCullCase(  testCtx, renderCtx, "workload_arithmetic_discard",      "Fragment shader that may discard with arithmetic workload"));
+               }
+
+               {
+                       tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "occluder_discard", "Discard");
+
+                       cullEfficiencyGroup->addChild(group);
+
+                       group->addChild(new PartialOccluderDiscardCullCase(testCtx, renderCtx, "grid_256",      "Parts of occluder geometry discarded", 256));
+                       group->addChild(new PartialOccluderDiscardCullCase(testCtx, renderCtx, "grid_128",      "Parts of occluder geometry discarded", 128));
+                       group->addChild(new PartialOccluderDiscardCullCase(testCtx, renderCtx, "grid_64",       "Parts of occluder geometry discarded", 64));
+                       group->addChild(new PartialOccluderDiscardCullCase(testCtx, renderCtx, "grid_32",       "Parts of occluder geometry discarded", 32));
+                       group->addChild(new PartialOccluderDiscardCullCase(testCtx, renderCtx, "grid_16",       "Parts of occluder geometry discarded", 16));
+                       group->addChild(new PartialOccluderDiscardCullCase(testCtx, renderCtx, "grid_8",        "Parts of occluder geometry discarded", 8));
+                       group->addChild(new PartialOccluderDiscardCullCase(testCtx, renderCtx, "grid_4",        "Parts of occluder geometry discarded", 4));
+                       group->addChild(new PartialOccluderDiscardCullCase(testCtx, renderCtx, "grid_2",        "Parts of occluder geometry discarded", 2));
+                       group->addChild(new PartialOccluderDiscardCullCase(testCtx, renderCtx, "grid_1",        "Parts of occluder geometry discarded", 1));
+               }
+
+               {
+                       tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "partial_coverage", "Partial Coverage");
+
+                       cullEfficiencyGroup->addChild(group);
+
+                       group->addChild(new PartialOccluderCullCase(testCtx, renderCtx, "100", "Occluder covering only part of occluded geometry", 1.00f));
+                       group->addChild(new PartialOccluderCullCase(testCtx, renderCtx, "099", "Occluder covering only part of occluded geometry", 0.99f));
+                       group->addChild(new PartialOccluderCullCase(testCtx, renderCtx, "095", "Occluder covering only part of occluded geometry", 0.95f));
+                       group->addChild(new PartialOccluderCullCase(testCtx, renderCtx, "090", "Occluder covering only part of occluded geometry", 0.90f));
+                       group->addChild(new PartialOccluderCullCase(testCtx, renderCtx, "080", "Occluder covering only part of occluded geometry", 0.80f));
+                       group->addChild(new PartialOccluderCullCase(testCtx, renderCtx, "070", "Occluder covering only part of occluded geometry", 0.70f));
+                       group->addChild(new PartialOccluderCullCase(testCtx, renderCtx, "050", "Occluder covering only part of occluded geometry", 0.50f));
+                       group->addChild(new PartialOccluderCullCase(testCtx, renderCtx, "025", "Occluder covering only part of occluded geometry", 0.25f));
+                       group->addChild(new PartialOccluderCullCase(testCtx, renderCtx, "010", "Occluder covering only part of occluded geometry", 0.10f));
+               }
+
+               {
+                       tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "frag_depth", "Partial Coverage");
+
+                       cullEfficiencyGroup->addChild(group);
+
+                       group->addChild(new StaticOccluderFragDepthCullCase( testCtx, renderCtx, "occluder_static", ""));
+                       group->addChild(new DynamicOccluderFragDepthCullCase(testCtx, renderCtx, "occluder_dynamic", ""));
+                       group->addChild(new StaticOccludedFragDepthCullCase( testCtx, renderCtx, "occluded_static", ""));
+                       group->addChild(new DynamicOccludedFragDepthCullCase(testCtx, renderCtx, "occluded_dynamic", ""));
+               }
+
+               {
+                       tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "order", "Rendering order");
+
+                       cullEfficiencyGroup->addChild(group);
+
+                       group->addChild(new ReversedDepthOrderCullCase(testCtx, renderCtx, "reversed", "Back to front rendering order"));
+               }
+       }
+
+       {
+               tcu::TestCaseGroup* const testCostGroup = new tcu::TestCaseGroup(m_testCtx, "culled_pixel_cost", "Fragment cull efficiency");
+
+               addChild(testCostGroup);
+
+               {
+                       tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "gradient", "Gradients with small depth differences");
+
+                       testCostGroup->addChild(group);
+
+                       group->addChild(new BaseCostCase(testCtx, renderCtx, "flat", ""));
+                       group->addChild(new GradientCostCase(testCtx, renderCtx, "gradient_050", "", 0.50f));
+                       group->addChild(new GradientCostCase(testCtx, renderCtx, "gradient_010", "", 0.10f));
+                       group->addChild(new GradientCostCase(testCtx, renderCtx, "gradient_005", "", 0.05f));
+                       group->addChild(new GradientCostCase(testCtx, renderCtx, "gradient_002", "", 0.02f));
+                       group->addChild(new GradientCostCase(testCtx, renderCtx, "gradient_001", "", 0.01f));
+               }
+
+               {
+                       tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "occluder_geometry", "Occluders with varying geometry complexity");
+
+                       testCostGroup->addChild(group);
+
+                       group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "flat_uniform_grid_5",   "", 5,   0.0f, 0.0f));
+                       group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "flat_uniform_grid_15",  "", 15,  0.0f, 0.0f));
+                       group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "flat_uniform_grid_25",  "", 25,  0.0f, 0.0f));
+                       group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "flat_uniform_grid_50",  "", 50,  0.0f, 0.0f));
+                       group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "flat_uniform_grid_100", "", 100, 0.0f, 0.0f));
+
+                       group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "flat_noisy_grid_5",   "", 5,   1.0f/5.0f,   0.0f));
+                       group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "flat_noisy_grid_15",  "", 15,  1.0f/15.0f,  0.0f));
+                       group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "flat_noisy_grid_25",  "", 25,  1.0f/25.0f,  0.0f));
+                       group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "flat_noisy_grid_50",  "", 50,  1.0f/50.0f,  0.0f));
+                       group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "flat_noisy_grid_100", "", 100, 1.0f/100.0f, 0.0f));
+
+                       group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "uneven_uniform_grid_5",   "", 5,   0.0f, 0.2f));
+                       group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "uneven_uniform_grid_15",  "", 15,  0.0f, 0.2f));
+                       group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "uneven_uniform_grid_25",  "", 25,  0.0f, 0.2f));
+                       group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "uneven_uniform_grid_50",  "", 50,  0.0f, 0.2f));
+                       group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "uneven_uniform_grid_100", "", 100, 0.0f, 0.2f));
+
+                       group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "uneven_noisy_grid_5",   "", 5,   1.0f/5.0f,   0.2f));
+                       group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "uneven_noisy_grid_15",  "", 15,  1.0f/15.0f,  0.2f));
+                       group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "uneven_noisy_grid_25",  "", 25,  1.0f/25.0f,  0.2f));
+                       group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "uneven_noisy_grid_50",  "", 50,  1.0f/50.0f,  0.2f));
+                       group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "uneven_noisy_grid_100", "", 100, 1.0f/100.0f, 0.2f));
+               }
+
+               {
+                       tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "frag_depth", "Modifying gl_FragDepth");
+
+                       testCostGroup->addChild(group);
+
+                       group->addChild(new OccluderStaticFragDepthCostCase( testCtx, renderCtx, "occluder_static", ""));
+                       group->addChild(new OccluderDynamicFragDepthCostCase(testCtx, renderCtx, "occluder_dynamic", ""));
+                       group->addChild(new OccludedStaticFragDepthCostCase( testCtx, renderCtx, "occluded_static", ""));
+                       group->addChild(new OccludedDynamicFragDepthCostCase(testCtx, renderCtx, "occluded_dynamic", ""));
+               }
+       }
+}
+
+} // Performance
+} // gles3
+} // deqp
diff --git a/modules/gles3/performance/es3pDepthTests.hpp b/modules/gles3/performance/es3pDepthTests.hpp
new file mode 100644 (file)
index 0000000..5b861b5
--- /dev/null
@@ -0,0 +1,53 @@
+#ifndef _ES3PDEPTHTESTS_HPP
+#define _ES3PDEPTHTESTS_HPP
+/*-------------------------------------------------------------------------
+ * drawElements Quality Program OpenGL ES 3.0 Module
+ * -------------------------------------------------
+ *
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *//*!
+ * \file
+ * \brief Depth buffer performance tests.
+ *//*--------------------------------------------------------------------*/
+
+#include "tcuDefs.hpp"
+#include "tes3TestCase.hpp"
+
+namespace deqp
+{
+namespace gles3
+{
+namespace Performance
+{
+
+class DepthTests : public TestCaseGroup
+{
+public:
+                                       DepthTests      (Context& context);
+                                       ~DepthTests     (void) {}
+
+       virtual void    init            (void);
+
+private:
+                                       DepthTests      (const DepthTests& other);
+       DepthTests&             operator=       (const DepthTests& other);
+};
+
+} // Performance
+} // gles3
+} // deqp
+
+#endif // _ES3PDEPTHTESTS_HPP
index f7377cc..7c05a03 100644 (file)
@@ -35,6 +35,7 @@
 #include "es3pStateChangeCallTests.hpp"
 #include "es3pStateChangeTests.hpp"
 #include "es3pBufferDataUploadTests.hpp"
+#include "es3pDepthTests.hpp"
 
 namespace deqp
 {
@@ -131,6 +132,7 @@ void PerformanceTests::init (void)
        addChild(new ShaderCompilerTests        (m_context));
        addChild(new APITests                           (m_context));
        addChild(new BufferTestGroup            (m_context));
+       addChild(new DepthTests                         (m_context));
 }
 
 } // Performance
index f4254b1..ac502be 100644 (file)
@@ -545,13 +545,13 @@ static SegmentedEstimator computeSegmentedEstimator (const vector<Vec2>& data)
        }
 
        {
-               const gls::LineParameters leftLine              = gls::theilSenEstimator(leftData);
-               const gls::LineParameters rightLine             = gls::theilSenEstimator(rightData);
+               const gls::LineParameters leftLine              = gls::theilSenLinearRegression(leftData);
+               const gls::LineParameters rightLine             = gls::theilSenLinearRegression(rightData);
 
                if (numDistinctX(leftData) < 2 || leftLine.coefficient > rightLine.coefficient*0.5f)
                {
                        // Left data doesn't seem credible; assume the data is just a single line.
-                       const gls::LineParameters entireLine = gls::theilSenEstimator(data);
+                       const gls::LineParameters entireLine = gls::theilSenLinearRegression(data);
                        return SegmentedEstimator(gls::LineParameters(entireLine.offset, 0.0f), entireLine, -std::numeric_limits<float>::infinity());
                }
                else
index 8197733..fd5f764 100644 (file)
@@ -55,8 +55,14 @@ set(DEQP_GLES31_FUNCTIONAL_SRCS
        es31fShaderTextureSizeTests.cpp
        es31fSynchronizationTests.hpp
        es31fSynchronizationTests.cpp
-       es31fFboTestUtil.hpp
+       es31fFboColorbufferTests.cpp
+       es31fFboColorbufferTests.hpp
+       es31fFboTestCase.cpp
+       es31fFboTestCase.hpp
        es31fFboTestUtil.cpp
+       es31fFboTestUtil.hpp
+       es31fTextureFilteringTests.cpp
+       es31fTextureFilteringTests.hpp
        es31fTextureFormatTests.hpp
        es31fTextureFormatTests.cpp
        es31fTextureLevelStateQueryTests.hpp
index 1357751..1b2513e 100644 (file)
@@ -825,7 +825,7 @@ public:
                        << "    uint localOffs  = gl_WorkGroupSize.x*gl_WorkGroupSize.y*gl_LocalInvocationID.z + gl_WorkGroupSize.x*gl_LocalInvocationID.y + gl_LocalInvocationID.x;\n"
                        << "\n"
                        << "    offsets[localSize-localOffs-1u] = globalOffs + localOffs*localOffs;\n"
-                       << "    memoryBarrierShared();\n"
+                       << "    barrier();\n"
                        << "    sb_out.values[globalOffs + localOffs] = offsets[localOffs];\n"
                        << "}\n";
 
@@ -916,7 +916,7 @@ public:
                        << "    uint globalOffs = localSize*globalNdx;\n"
                        << "\n"
                        << "    count = 0u;\n"
-                       << "    memoryBarrierShared();\n"
+                       << "    barrier();\n"
                        << "    uint oldVal = atomicAdd(count, 1u);\n"
                        << "    sb_out.values[globalOffs+oldVal] = oldVal+1u;\n"
                        << "}\n";
@@ -1029,6 +1029,8 @@ public:
                gl.bindTexture(GL_TEXTURE_2D, *inputTexture);
                gl.texStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, m_imageSize[0], m_imageSize[1]);
                gl.texSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_imageSize[0], m_imageSize[1], GL_RED_INTEGER, GL_UNSIGNED_INT, &inputValues[0]);
+               gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+               gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
                GLU_EXPECT_NO_ERROR(gl.getError(), "Uploading image data failed");
 
                // Bind to unit 1
@@ -1153,6 +1155,8 @@ public:
                // Output image setup
                gl.bindTexture(GL_TEXTURE_2D, *outputTexture);
                gl.texStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, m_imageSize[0], m_imageSize[1]);
+               gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+               gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
                GLU_EXPECT_NO_ERROR(gl.getError(), "Uploading image data failed");
 
                // Bind to unit 1
@@ -1229,7 +1233,7 @@ public:
                        << "\n"
                        << "    if (gl_LocalInvocationIndex == 0u)\n"
                        << "        imageStore(u_dstImg, ivec2(gl_WorkGroupID.xy), uvec4(0));\n"
-                       << "    memoryBarrierImage();\n"
+                       << "    barrier();\n"
                        << "    imageAtomicAdd(u_dstImg, ivec2(gl_WorkGroupID.xy), value);\n"
                        << "}\n";
 
@@ -1278,6 +1282,8 @@ public:
                // Output image setup
                gl.bindTexture(GL_TEXTURE_2D, *outputTexture);
                gl.texStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, m_imageSize[0], m_imageSize[1]);
+               gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+               gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
                GLU_EXPECT_NO_ERROR(gl.getError(), "Uploading image data failed");
 
                // Bind to unit 1
@@ -1370,6 +1376,8 @@ public:
                // Temp texture setup
                gl.bindTexture(GL_TEXTURE_2D, *tempTexture);
                gl.texStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, m_workSize[0], m_workSize[1]);
+               gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+               gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
                GLU_EXPECT_NO_ERROR(gl.getError(), "Uploading image data failed");
 
                // Bind to unit 2
index d074306..f833892 100644 (file)
@@ -325,8 +325,8 @@ public:
                m_subCases.push_back(SubCase(UVec3(1,3,1), UVec3(1,1,1)));
                m_subCases.push_back(SubCase(UVec3(1,1,7), UVec3(1,1,1)));
                m_subCases.push_back(SubCase(UVec3(1,1,7), UVec3(3,3,1)));
-               m_subCases.push_back(SubCase(UVec3(11,3,8), UVec3(1,1,1)));
-               m_subCases.push_back(SubCase(UVec3(11,3,8), UVec3(3,1,2)));
+               m_subCases.push_back(SubCase(UVec3(10,3,4), UVec3(1,1,1)));
+               m_subCases.push_back(SubCase(UVec3(10,3,4), UVec3(3,1,2)));
        }
 
        UVec3 computeReference (const UVec3& numWorkGroups, const UVec3& workGroupSize, const UVec3& workGroupID, const UVec3& localInvocationID) const
@@ -374,8 +374,8 @@ public:
                m_subCases.push_back(SubCase(UVec3(1,3,1), UVec3(1,1,1)));
                m_subCases.push_back(SubCase(UVec3(1,1,7), UVec3(1,1,1)));
                m_subCases.push_back(SubCase(UVec3(1,1,7), UVec3(3,3,1)));
-               m_subCases.push_back(SubCase(UVec3(11,3,8), UVec3(1,1,1)));
-               m_subCases.push_back(SubCase(UVec3(11,3,8), UVec3(3,1,2)));
+               m_subCases.push_back(SubCase(UVec3(10,3,4), UVec3(1,1,1)));
+               m_subCases.push_back(SubCase(UVec3(10,3,4), UVec3(3,1,2)));
        }
 
        UVec3 computeReference (const UVec3& numWorkGroups, const UVec3& workGroupSize, const UVec3& workGroupID, const UVec3& localInvocationID) const
@@ -399,8 +399,8 @@ public:
                m_subCases.push_back(SubCase(UVec3(1,1,1), UVec3(1,1,78)));
                m_subCases.push_back(SubCase(UVec3(1,1,1), UVec3(4,7,11)));
                m_subCases.push_back(SubCase(UVec3(2,3,4), UVec3(4,7,11)));
-               m_subCases.push_back(SubCase(UVec3(11,3,8), UVec3(1,1,1)));
-               m_subCases.push_back(SubCase(UVec3(11,3,8), UVec3(3,1,2)));
+               m_subCases.push_back(SubCase(UVec3(10,3,4), UVec3(1,1,1)));
+               m_subCases.push_back(SubCase(UVec3(10,3,4), UVec3(3,1,2)));
        }
 
        UVec3 computeReference (const UVec3& numWorkGroups, const UVec3& workGroupSize, const UVec3& workGroupID, const UVec3& localInvocationID) const
@@ -420,8 +420,8 @@ public:
                m_subCases.push_back(SubCase(UVec3(1,1,1), UVec3(1,39,1)));
                m_subCases.push_back(SubCase(UVec3(1,1,1), UVec3(4,7,11)));
                m_subCases.push_back(SubCase(UVec3(2,3,4), UVec3(4,7,11)));
-               m_subCases.push_back(SubCase(UVec3(11,3,8), UVec3(1,1,1)));
-               m_subCases.push_back(SubCase(UVec3(11,3,8), UVec3(3,1,2)));
+               m_subCases.push_back(SubCase(UVec3(10,3,4), UVec3(1,1,1)));
+               m_subCases.push_back(SubCase(UVec3(10,3,4), UVec3(3,1,2)));
        }
 
        UVec3 computeReference (const UVec3& numWorkGroups, const UVec3& workGroupSize, const UVec3& workGroupID, const UVec3& localInvocationID) const
index 3ec945c..f0265e2 100644 (file)
@@ -2611,7 +2611,7 @@ BadDrawModeCase::IterateResult BadDrawModeCase::iterate (void)
                0, 2, 1,
        };
 
-       sglr::GLContext gl(m_context.getRenderContext(), m_testCtx.getLog(), sglr::GLCONTEXT_LOG_CALLS, tcu::IVec4(0, 0, 1, 1));
+       sglr::GLContext         gl                              (m_context.getRenderContext(), m_testCtx.getLog(), sglr::GLCONTEXT_LOG_CALLS, tcu::IVec4(0, 0, 1, 1));
 
        deUint32                        error;
        glu::ShaderProgram      program                 (m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(s_commonVertexShaderSource) << glu::FragmentSource(s_commonFragmentShaderSource));
@@ -2643,7 +2643,7 @@ BadDrawModeCase::IterateResult BadDrawModeCase::iterate (void)
 
        // index
 
-       if (m_drawType == DRAW_ELEMENTS)
+       if (m_drawType == DRAW_ELEMENTS || m_drawType == DRAW_ELEMENTS_BAD_INDEX)
        {
                gl.genBuffers(1, &indexBufferID);
                gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferID);
diff --git a/modules/gles31/functional/es31fFboColorbufferTests.cpp b/modules/gles31/functional/es31fFboColorbufferTests.cpp
new file mode 100644 (file)
index 0000000..618f78e
--- /dev/null
@@ -0,0 +1,334 @@
+/*-------------------------------------------------------------------------
+ * drawElements Quality Program OpenGL ES 3.1 Module
+ * -------------------------------------------------
+ *
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *//*!
+ * \file
+ * \brief FBO colorbuffer tests.
+ *//*--------------------------------------------------------------------*/
+
+#include "es31fFboColorbufferTests.hpp"
+#include "es31fFboTestCase.hpp"
+#include "es31fFboTestUtil.hpp"
+
+#include "gluTextureUtil.hpp"
+#include "gluContextInfo.hpp"
+
+#include "tcuCommandLine.hpp"
+#include "tcuImageCompare.hpp"
+#include "tcuRGBA.hpp"
+#include "tcuTestLog.hpp"
+#include "tcuTextureUtil.hpp"
+
+#include "sglrContextUtil.hpp"
+
+#include "deRandom.hpp"
+#include "deString.h"
+
+#include "glwEnums.hpp"
+
+namespace deqp
+{
+namespace gles31
+{
+namespace Functional
+{
+
+using std::string;
+using tcu::Vec2;
+using tcu::Vec3;
+using tcu::Vec4;
+using tcu::IVec2;
+using tcu::IVec3;
+using tcu::IVec4;
+using tcu::UVec4;
+using tcu::TestLog;
+using namespace FboTestUtil;
+
+const tcu::RGBA MIN_THRESHOLD(12, 12, 12, 12);
+
+static tcu::Vec4 generateRandomColor (de::Random& random)
+{
+       tcu::Vec4 retVal;
+
+       retVal[0] = random.getFloat();
+       retVal[1] = random.getFloat();
+       retVal[2] = random.getFloat();
+       retVal[3] = 1.0f;
+
+       return retVal;
+}
+
+static tcu::CubeFace getCubeFaceFromNdx (int ndx)
+{
+       switch (ndx)
+       {
+               case 0: return tcu::CUBEFACE_POSITIVE_X;
+               case 1: return tcu::CUBEFACE_NEGATIVE_X;
+               case 2: return tcu::CUBEFACE_POSITIVE_Y;
+               case 3: return tcu::CUBEFACE_NEGATIVE_Y;
+               case 4: return tcu::CUBEFACE_POSITIVE_Z;
+               case 5: return tcu::CUBEFACE_NEGATIVE_Z;
+               default:
+                       DE_ASSERT(false);
+                       return tcu::CUBEFACE_LAST;
+       }
+}
+
+class FboColorbufferCase : public FboTestCase
+{
+public:
+       FboColorbufferCase (Context& context, const char* name, const char* desc, const deUint32 format)
+               : FboTestCase   (context, name, desc)
+               , m_format              (format)
+       {
+       }
+
+       bool compare (const tcu::Surface& reference, const tcu::Surface& result)
+       {
+               const tcu::RGBA threshold (tcu::max(getFormatThreshold(m_format), MIN_THRESHOLD));
+
+               m_testCtx.getLog() << TestLog::Message << "Comparing images, threshold: " << threshold << TestLog::EndMessage;
+
+               return tcu::bilinearCompare(m_testCtx.getLog(), "Result", "Image comparison result", reference.getAccess(), result.getAccess(), threshold, tcu::COMPARE_LOG_RESULT);
+       }
+
+protected:
+       const deUint32  m_format;
+};
+
+class FboColorTexCubeArrayCase : public FboColorbufferCase
+{
+public:
+       FboColorTexCubeArrayCase (Context& context, const char* name, const char* description, deUint32 texFmt, const IVec3& texSize)
+               : FboColorbufferCase    (context, name, description, texFmt)
+               , m_texSize                             (texSize)
+       {
+               DE_ASSERT(texSize.z() % 6 == 0);
+       }
+
+protected:
+       void preCheck (void)
+       {
+               if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_texture_cube_map_array"))
+                       throw tcu::NotSupportedError("GL_EXT_texture_cube_map_array not supported");
+
+               checkFormatSupport(m_format);
+       }
+
+       void render (tcu::Surface& dst)
+       {
+               TestLog&                                log                                     = m_testCtx.getLog();
+               de::Random                              rnd                                     (deStringHash(getName()) ^ 0xed607a89 ^ m_testCtx.getCommandLine().getBaseSeed());
+               tcu::TextureFormat              texFmt                          = glu::mapGLInternalFormat(m_format);
+               tcu::TextureFormatInfo  fmtInfo                         = tcu::getTextureFormatInfo(texFmt);
+
+               Texture2DShader                 texToFboShader          (DataTypes() << glu::TYPE_SAMPLER_2D, getFragmentOutputType(texFmt), fmtInfo.valueMax-fmtInfo.valueMin, fmtInfo.valueMin);
+               TextureCubeArrayShader  arrayTexShader          (glu::getSamplerCubeArrayType(texFmt), glu::TYPE_FLOAT_VEC4);
+
+               deUint32                                texToFboShaderID        = getCurrentContext()->createProgram(&texToFboShader);
+               deUint32                                arrayTexShaderID        = getCurrentContext()->createProgram(&arrayTexShader);
+
+               // Setup textures
+               texToFboShader.setUniforms(*getCurrentContext(), texToFboShaderID);
+               arrayTexShader.setTexScaleBias(fmtInfo.lookupScale, fmtInfo.lookupBias);
+
+               // Framebuffers.
+               std::vector<deUint32>   fbos;
+               deUint32                                tex;
+
+               {
+                       glu::TransferFormat     transferFmt             = glu::getTransferFormat(texFmt);
+                       bool                            isFilterable    = glu::isGLInternalColorFormatFilterable(m_format);
+                       const IVec3&            size                    = m_texSize;
+
+                       log << TestLog::Message
+                               << "Creating a cube map array texture ("
+                               << size.x() << "x" << size.y()
+                               << ", depth: "
+                               << size.z() << ")"
+                               << TestLog::EndMessage;
+
+                       glGenTextures(1, &tex);
+
+                       glBindTexture(GL_TEXTURE_CUBE_MAP_ARRAY, tex);
+                       glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY,      GL_TEXTURE_WRAP_S,              GL_CLAMP_TO_EDGE);
+                       glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY,      GL_TEXTURE_WRAP_T,              GL_CLAMP_TO_EDGE);
+                       glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY,      GL_TEXTURE_WRAP_R,              GL_CLAMP_TO_EDGE);
+                       glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY,      GL_TEXTURE_MIN_FILTER,  isFilterable ? GL_LINEAR : GL_NEAREST);
+                       glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY,      GL_TEXTURE_MAG_FILTER,  isFilterable ? GL_LINEAR : GL_NEAREST);
+                       glTexImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, 0, m_format, size.x(), size.y(), size.z(), 0, transferFmt.format, transferFmt.dataType, DE_NULL);
+
+                       log << TestLog::Message << "Creating a framebuffer object for each layer-face" << TestLog::EndMessage;
+
+                       // Generate an FBO for each layer-face
+                       for (int ndx = 0; ndx < m_texSize.z(); ndx++)
+                       {
+                               deUint32 layerFbo;
+
+                               glGenFramebuffers(1, &layerFbo);
+                               glBindFramebuffer(GL_FRAMEBUFFER, layerFbo);
+                               glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex, 0, ndx);
+                               checkError();
+                               checkFramebufferStatus(GL_FRAMEBUFFER);
+
+                               fbos.push_back(layerFbo);
+                       }
+               }
+
+               log << TestLog::Message << "Rendering test images to layer-faces in randomized order" << TestLog::EndMessage;
+
+               {
+                       std::vector<int> order(fbos.size());
+
+                       for (size_t n = 0; n < order.size(); n++)
+                               order[n] = (int)n;
+                       rnd.shuffle(order.begin(), order.end());
+
+                       for (size_t ndx = 0; ndx < order.size(); ndx++)
+                       {
+                               const int                       layerFace       = order[ndx];
+                               const deUint32          format          = GL_RGBA;
+                               const deUint32          dataType        = GL_UNSIGNED_BYTE;
+                               const int                       texW            = 128;
+                               const int                       texH            = 128;
+                               deUint32                        tmpTex          = 0;
+                               const deUint32          fbo                     = fbos[layerFace];
+                               const IVec3&            viewport        = m_texSize;
+                               tcu::TextureLevel       data            (glu::mapGLTransferFormat(format, dataType), texW, texH, 1);
+
+                               tcu::fillWithGrid(data.getAccess(), 8, generateRandomColor(rnd), Vec4(0.0f));
+
+                               glGenTextures(1, &tmpTex);
+                               glBindTexture(GL_TEXTURE_2D, tmpTex);
+                               glTexParameteri(GL_TEXTURE_2D,  GL_TEXTURE_WRAP_S,              GL_CLAMP_TO_EDGE);
+                               glTexParameteri(GL_TEXTURE_2D,  GL_TEXTURE_WRAP_T,              GL_CLAMP_TO_EDGE);
+                               glTexParameteri(GL_TEXTURE_2D,  GL_TEXTURE_MIN_FILTER,  GL_LINEAR);
+                               glTexParameteri(GL_TEXTURE_2D,  GL_TEXTURE_MAG_FILTER,  GL_LINEAR);
+                               glTexImage2D(GL_TEXTURE_2D, 0, format, texW, texH, 0, format, dataType, data.getAccess().getDataPtr());
+
+                               glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+                               glViewport(0, 0, viewport.x(), viewport.y());
+                               sglr::drawQuad(*getCurrentContext(), texToFboShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
+                               checkError();
+
+                               // Render to framebuffer
+                               {
+                                       const Vec3                      p0              = Vec3(float(ndx % 2) - 1.0f, float(ndx / 2) - 1.0f, 0.0f);
+                                       const Vec3                      p1              = p0 + Vec3(1.0f, 1.0f, 0.0f);
+                                       const int                       layer   = layerFace / 6;
+                                       const tcu::CubeFace     face    = getCubeFaceFromNdx(layerFace % 6);
+
+                                       glBindFramebuffer(GL_FRAMEBUFFER, 0);
+                                       glViewport(0, 0, getWidth(), getHeight());
+
+                                       glActiveTexture(GL_TEXTURE0);
+                                       glBindTexture(GL_TEXTURE_CUBE_MAP_ARRAY, tex);
+
+                                       arrayTexShader.setLayer(layer);
+                                       arrayTexShader.setFace(face);
+                                       arrayTexShader.setUniforms(*getCurrentContext(), arrayTexShaderID);
+
+                                       sglr::drawQuad(*getCurrentContext(), arrayTexShaderID, p0, p1);
+                                       checkError();
+                               }
+                       }
+               }
+
+               readPixels(dst, 0, 0, getWidth(), getHeight());
+       }
+
+private:
+       IVec3 m_texSize;
+};
+
+FboColorTests::FboColorTests (Context& context)
+       : TestCaseGroup(context, "color", "Colorbuffer tests")
+{
+}
+
+FboColorTests::~FboColorTests (void)
+{
+}
+
+void FboColorTests::init (void)
+{
+       static const deUint32 colorFormats[] =
+       {
+               // RGBA formats
+               GL_RGBA32I,
+               GL_RGBA32UI,
+               GL_RGBA16I,
+               GL_RGBA16UI,
+               GL_RGBA8,
+               GL_RGBA8I,
+               GL_RGBA8UI,
+               GL_SRGB8_ALPHA8,
+               GL_RGB10_A2,
+               GL_RGB10_A2UI,
+               GL_RGBA4,
+               GL_RGB5_A1,
+
+               // RGB formats
+               GL_RGB8,
+               GL_RGB565,
+
+               // RG formats
+               GL_RG32I,
+               GL_RG32UI,
+               GL_RG16I,
+               GL_RG16UI,
+               GL_RG8,
+               GL_RG8I,
+               GL_RG8UI,
+
+               // R formats
+               GL_R32I,
+               GL_R32UI,
+               GL_R16I,
+               GL_R16UI,
+               GL_R8,
+               GL_R8I,
+               GL_R8UI,
+
+               // GL_EXT_color_buffer_float
+               GL_RGBA32F,
+               GL_RGBA16F,
+               GL_R11F_G11F_B10F,
+               GL_RG32F,
+               GL_RG16F,
+               GL_R32F,
+               GL_R16F,
+
+               // GL_EXT_color_buffer_half_float
+               GL_RGB16F
+       };
+
+       // .texcubearray
+       {
+               tcu::TestCaseGroup* texCubeArrayGroup = new tcu::TestCaseGroup(m_testCtx, "texcubearray", "Cube map array texture tests");
+               addChild(texCubeArrayGroup);
+
+               for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(colorFormats); fmtNdx++)
+                       texCubeArrayGroup->addChild(new FboColorTexCubeArrayCase(m_context, getFormatName(colorFormats[fmtNdx]), "",
+                                                                                                                                        colorFormats[fmtNdx], IVec3(128, 128, 12)));
+       }
+}
+
+} // Functional
+} // gles31
+} // deqp
diff --git a/modules/gles31/functional/es31fFboColorbufferTests.hpp b/modules/gles31/functional/es31fFboColorbufferTests.hpp
new file mode 100644 (file)
index 0000000..27e038a
--- /dev/null
@@ -0,0 +1,53 @@
+#ifndef _ES31FFBOCOLORBUFFERTESTS_HPP
+#define _ES31FFBOCOLORBUFFERTESTS_HPP
+/*-------------------------------------------------------------------------
+ * drawElements Quality Program OpenGL ES 3.1 Module
+ * -------------------------------------------------
+ *
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *//*!
+ * \file
+ * \brief FBO colorbuffer tests.
+ *//*--------------------------------------------------------------------*/
+
+#include "tcuDefs.hpp"
+#include "tes31TestCase.hpp"
+
+namespace deqp
+{
+namespace gles31
+{
+namespace Functional
+{
+
+class FboColorTests : public TestCaseGroup
+{
+public:
+                                               FboColorTests                   (Context& context);
+                                               ~FboColorTests                  (void);
+
+       void                            init                                    (void);
+
+private:
+                                               FboColorTests                   (const FboColorTests& other);
+       FboColorTests&          operator=                               (const FboColorTests& other);
+};
+
+} // Functional
+} // gles31
+} // deqp
+
+#endif // _ES31FFBOCOLORBUFFERTESTS_HPP
diff --git a/modules/gles31/functional/es31fFboTestCase.cpp b/modules/gles31/functional/es31fFboTestCase.cpp
new file mode 100644 (file)
index 0000000..4d03eab
--- /dev/null
@@ -0,0 +1,369 @@
+/*-------------------------------------------------------------------------
+ * drawElements Quality Program OpenGL ES 3.1 Module
+ * -------------------------------------------------
+ *
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *//*!
+ * \file
+ * \brief Base class for FBO tests.
+ *//*--------------------------------------------------------------------*/
+
+#include "es31fFboTestCase.hpp"
+#include "es31fFboTestUtil.hpp"
+#include "tcuTestLog.hpp"
+#include "tcuImageCompare.hpp"
+#include "tcuRenderTarget.hpp"
+#include "sglrGLContext.hpp"
+#include "sglrReferenceContext.hpp"
+#include "gluStrUtil.hpp"
+#include "gluContextInfo.hpp"
+#include "deRandom.hpp"
+#include "glwEnums.hpp"
+#include "glwFunctions.hpp"
+
+#include <algorithm>
+
+namespace deqp
+{
+namespace gles31
+{
+namespace Functional
+{
+
+using tcu::TestLog;
+using std::string;
+
+FboTestCase::FboTestCase (Context& context, const char* name, const char* description, bool useScreenSizedViewport)
+       : TestCase                      (context, name, description)
+       , m_viewportWidth       (useScreenSizedViewport ? context.getRenderTarget().getWidth() : 128)
+       , m_viewportHeight      (useScreenSizedViewport ? context.getRenderTarget().getHeight() : 128)
+{
+}
+
+FboTestCase::~FboTestCase (void)
+{
+}
+
+FboTestCase::IterateResult FboTestCase::iterate (void)
+{
+       glu::RenderContext&                     renderCtx               = TestCase::m_context.getRenderContext();
+       const tcu::RenderTarget&        renderTarget    = renderCtx.getRenderTarget();
+       TestLog&                                        log                             = m_testCtx.getLog();
+
+       // Viewport.
+       de::Random                                      rnd                             (deStringHash(getName()));
+       int                                                     width                   = deMin32(renderTarget.getWidth(),      m_viewportWidth);
+       int                                                     height                  = deMin32(renderTarget.getHeight(),     m_viewportHeight);
+       int                                                     x                               = rnd.getInt(0, renderTarget.getWidth()         - width);
+       int                                                     y                               = rnd.getInt(0, renderTarget.getHeight()        - height);
+
+       // Surface format and storage is choosen by render().
+       tcu::Surface                            reference;
+       tcu::Surface                            result;
+
+       // Call preCheck() that can throw exception if some requirement is not met.
+       preCheck();
+
+       log << TestLog::Message << "Rendering with GL driver" << TestLog::EndMessage;
+
+       // Render using GLES3.1
+       try
+       {
+               sglr::GLContext context(renderCtx, log, 0, tcu::IVec4(x, y, width, height));
+               setContext(&context);
+               render(result);
+
+               // Check error.
+               deUint32 err = glGetError();
+               if (err != GL_NO_ERROR)
+                       throw glu::Error(err, glu::getErrorStr(err).toString().c_str(), DE_NULL, __FILE__, __LINE__);
+
+               setContext(DE_NULL);
+       }
+       catch (const FboTestUtil::FboIncompleteException& e)
+       {
+               if (e.getReason() == GL_FRAMEBUFFER_UNSUPPORTED)
+               {
+                       log << e;
+                       m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not supported");
+                       return STOP;
+               }
+               else
+                       throw;
+       }
+
+       log << TestLog::Message << "Rendering reference image" << TestLog::EndMessage;
+
+       // Render reference.
+       {
+               sglr::ReferenceContextBuffers   buffers (tcu::PixelFormat(8,8,8,renderTarget.getPixelFormat().alphaBits?8:0), renderTarget.getDepthBits(), renderTarget.getStencilBits(), width, height);
+               sglr::ReferenceContext                  context (sglr::ReferenceContextLimits(renderCtx), buffers.getColorbuffer(), buffers.getDepthbuffer(), buffers.getStencilbuffer());
+
+               setContext(&context);
+               render(reference);
+               setContext(DE_NULL);
+       }
+
+       bool isOk = compare(reference, result);
+       m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS      : QP_TEST_RESULT_FAIL,
+                                                       isOk ? "Pass"                           : "Image comparison failed");
+       return STOP;
+}
+
+bool FboTestCase::compare (const tcu::Surface& reference, const tcu::Surface& result)
+{
+       return tcu::fuzzyCompare(m_testCtx.getLog(), "Result", "Image comparison result", reference, result, 0.05f, tcu::COMPARE_LOG_RESULT);
+}
+
+void FboTestCase::readPixels (tcu::Surface& dst, int x, int y, int width, int height, const tcu::TextureFormat& format, const tcu::Vec4& scale, const tcu::Vec4& bias)
+{
+       FboTestUtil::readPixels(*getCurrentContext(), dst, x, y, width, height, format, scale, bias);
+}
+
+void FboTestCase::readPixels (tcu::Surface& dst, int x, int y, int width, int height)
+{
+       getCurrentContext()->readPixels(dst, x, y, width, height);
+}
+
+void FboTestCase::checkFramebufferStatus (deUint32 target)
+{
+       deUint32 status = glCheckFramebufferStatus(target);
+       if (status != GL_FRAMEBUFFER_COMPLETE)
+               throw FboTestUtil::FboIncompleteException(status, __FILE__, __LINE__);
+}
+
+void FboTestCase::checkError (void)
+{
+       deUint32 err = glGetError();
+       if (err != GL_NO_ERROR)
+               throw glu::Error((int)err, (string("Got ") + glu::getErrorStr(err).toString()).c_str(), DE_NULL, __FILE__, __LINE__);
+}
+
+static bool isRequiredFormat (deUint32 format)
+{
+       switch (format)
+       {
+               // Color-renderable formats
+               case GL_RGBA32I:
+               case GL_RGBA32UI:
+               case GL_RGBA16I:
+               case GL_RGBA16UI:
+               case GL_RGBA8:
+               case GL_RGBA8I:
+               case GL_RGBA8UI:
+               case GL_SRGB8_ALPHA8:
+               case GL_RGB10_A2:
+               case GL_RGB10_A2UI:
+               case GL_RGBA4:
+               case GL_RGB5_A1:
+               case GL_RGB8:
+               case GL_RGB565:
+               case GL_RG32I:
+               case GL_RG32UI:
+               case GL_RG16I:
+               case GL_RG16UI:
+               case GL_RG8:
+               case GL_RG8I:
+               case GL_RG8UI:
+               case GL_R32I:
+               case GL_R32UI:
+               case GL_R16I:
+               case GL_R16UI:
+               case GL_R8:
+               case GL_R8I:
+               case GL_R8UI:
+                       return true;
+
+               // Depth formats
+               case GL_DEPTH_COMPONENT32F:
+               case GL_DEPTH_COMPONENT24:
+               case GL_DEPTH_COMPONENT16:
+                       return true;
+
+               // Depth+stencil formats
+               case GL_DEPTH32F_STENCIL8:
+               case GL_DEPTH24_STENCIL8:
+                       return true;
+
+               // Stencil formats
+               case GL_STENCIL_INDEX8:
+                       return true;
+
+               default:
+                       return false;
+       }
+}
+
+static std::vector<std::string> getEnablingExtensions (deUint32 format)
+{
+       std::vector<std::string> out;
+
+       DE_ASSERT(!isRequiredFormat(format));
+
+       switch (format)
+       {
+               case GL_RGB16F:
+                       out.push_back("GL_EXT_color_buffer_half_float");
+                       break;
+
+               case GL_RGBA16F:
+               case GL_RG16F:
+               case GL_R16F:
+                       out.push_back("GL_EXT_color_buffer_half_float");
+
+               case GL_RGBA32F:
+               case GL_RGB32F:
+               case GL_R11F_G11F_B10F:
+               case GL_RG32F:
+               case GL_R32F:
+                       out.push_back("GL_EXT_color_buffer_float");
+                       break;
+
+               default:
+                       break;
+       }
+
+       return out;
+}
+
+static bool isAnyExtensionSupported (Context& context, const std::vector<std::string>& requiredExts)
+{
+       for (std::vector<std::string>::const_iterator iter = requiredExts.begin(); iter != requiredExts.end(); iter++)
+       {
+               const std::string& extension = *iter;
+
+               if (context.getContextInfo().isExtensionSupported(extension.c_str()))
+                       return true;
+       }
+
+       return false;
+}
+
+void FboTestCase::checkFormatSupport (deUint32 sizedFormat)
+{
+       const bool                                              isCoreFormat    = isRequiredFormat(sizedFormat);
+       const std::vector<std::string>  requiredExts    = (!isCoreFormat) ? getEnablingExtensions(sizedFormat) : std::vector<std::string>();
+
+       // Check that we don't try to use invalid formats.
+       DE_ASSERT(isCoreFormat || !requiredExts.empty());
+
+       if (!requiredExts.empty() && !isAnyExtensionSupported(m_context, requiredExts))
+               throw tcu::NotSupportedError("Format not supported");
+}
+
+static int getMinimumSampleCount (deUint32 format)
+{
+       switch (format)
+       {
+               // Core formats
+               case GL_RGBA32I:
+               case GL_RGBA32UI:
+               case GL_RGBA16I:
+               case GL_RGBA16UI:
+               case GL_RGBA8:
+               case GL_RGBA8I:
+               case GL_RGBA8UI:
+               case GL_SRGB8_ALPHA8:
+               case GL_RGB10_A2:
+               case GL_RGB10_A2UI:
+               case GL_RGBA4:
+               case GL_RGB5_A1:
+               case GL_RGB8:
+               case GL_RGB565:
+               case GL_RG32I:
+               case GL_RG32UI:
+               case GL_RG16I:
+               case GL_RG16UI:
+               case GL_RG8:
+               case GL_RG8I:
+               case GL_RG8UI:
+               case GL_R32I:
+               case GL_R32UI:
+               case GL_R16I:
+               case GL_R16UI:
+               case GL_R8:
+               case GL_R8I:
+               case GL_R8UI:
+               case GL_DEPTH_COMPONENT32F:
+               case GL_DEPTH_COMPONENT24:
+               case GL_DEPTH_COMPONENT16:
+               case GL_DEPTH32F_STENCIL8:
+               case GL_DEPTH24_STENCIL8:
+               case GL_STENCIL_INDEX8:
+                       return 4;
+
+               // GL_EXT_color_buffer_float
+               case GL_R11F_G11F_B10F:
+               case GL_RG16F:
+               case GL_R16F:
+                       return 4;
+
+               case GL_RGBA32F:
+               case GL_RGBA16F:
+               case GL_RG32F:
+               case GL_R32F:
+                       return 0;
+
+               // GL_EXT_color_buffer_half_float
+               case GL_RGB16F:
+                       return 0;
+
+               default:
+                       DE_ASSERT(!"Unknown format");
+                       return 0;
+       }
+}
+
+static std::vector<int> querySampleCounts (const glw::Functions& gl, deUint32 format)
+{
+       int                                     numSampleCounts         = 0;
+       std::vector<int>        sampleCounts;
+
+       gl.getInternalformativ(GL_RENDERBUFFER, format, GL_NUM_SAMPLE_COUNTS, 1, &numSampleCounts);
+
+       if (numSampleCounts > 0)
+       {
+               sampleCounts.resize(numSampleCounts);
+               gl.getInternalformativ(GL_RENDERBUFFER, format, GL_SAMPLES, (glw::GLsizei)sampleCounts.size(), &sampleCounts[0]);
+       }
+
+       GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to query sample counts for format");
+
+       return sampleCounts;
+}
+
+void FboTestCase::checkSampleCount (deUint32 sizedFormat, int numSamples)
+{
+       const int minSampleCount = getMinimumSampleCount(sizedFormat);
+
+       if (numSamples > minSampleCount)
+       {
+               // Exceeds spec-mandated minimum - need to check.
+               const std::vector<int> supportedSampleCounts = querySampleCounts(m_context.getRenderContext().getFunctions(), sizedFormat);
+
+               if (std::find(supportedSampleCounts.begin(), supportedSampleCounts.end(), numSamples) == supportedSampleCounts.end())
+                       throw tcu::NotSupportedError("Sample count not supported");
+       }
+}
+
+void FboTestCase::clearColorBuffer (const tcu::TextureFormat& format, const tcu::Vec4& value)
+{
+       FboTestUtil::clearColorBuffer(*getCurrentContext(), format, value);
+}
+
+} // Functional
+} // gles31
+} // deqp
diff --git a/modules/gles31/functional/es31fFboTestCase.hpp b/modules/gles31/functional/es31fFboTestCase.hpp
new file mode 100644 (file)
index 0000000..1a3d612
--- /dev/null
@@ -0,0 +1,77 @@
+#ifndef _ES31FFBOTESTCASE_HPP
+#define _ES31FFBOTESTCASE_HPP
+/*-------------------------------------------------------------------------
+ * drawElements Quality Program OpenGL ES 3.1 Module
+ * -------------------------------------------------
+ *
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *//*!
+ * \file
+ * \brief Base class for FBO tests.
+ *//*--------------------------------------------------------------------*/
+
+#include "tcuDefs.hpp"
+#include "tes31TestCase.hpp"
+#include "sglrContextWrapper.hpp"
+
+namespace tcu
+{
+class Surface;
+class TextureFormat;
+}
+
+namespace deqp
+{
+namespace gles31
+{
+namespace Functional
+{
+
+class FboTestCase : public TestCase, public sglr::ContextWrapper
+{
+public:
+                                               FboTestCase                             (Context& context, const char* name, const char* description, bool useScreenSizedViewport = false);
+                                               ~FboTestCase                    (void);
+
+       IterateResult           iterate                                 (void);
+
+protected:
+       virtual void            preCheck                                (void) {}
+       virtual void            render                                  (tcu::Surface& dst) = DE_NULL;
+       virtual bool            compare                                 (const tcu::Surface& reference, const tcu::Surface& result);
+
+       // Utilities.
+       void                            checkFormatSupport              (deUint32 sizedFormat);
+       void                            checkSampleCount                (deUint32 sizedFormat, int numSamples);
+       void                            readPixels                              (tcu::Surface& dst, int x, int y, int width, int height, const tcu::TextureFormat& format, const tcu::Vec4& scale, const tcu::Vec4& bias);
+       void                            readPixels                              (tcu::Surface& dst, int x, int y, int width, int height);
+       void                            checkFramebufferStatus  (deUint32 target);
+       void                            checkError                              (void);
+       void                            clearColorBuffer                (const tcu::TextureFormat& format, const tcu::Vec4& value = tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f));
+
+       int                                     m_viewportWidth;
+       int                                     m_viewportHeight;
+
+private:
+                                               FboTestCase                             (const FboTestCase& other);
+       FboTestCase&            operator=                               (const FboTestCase& other);
+};
+
+} // Functional
+} // gles31
+} // deqp
+
+#endif // _ES31FFBOTESTCASE_HPP
index ac4572d..0febea7 100644 (file)
@@ -74,6 +74,194 @@ static tcu::Vector<T, 4> castVectorSaturate (const tcu::Vec4& in)
                                                         (in.w() + 0.5f >= std::numeric_limits<T>::max()) ? (std::numeric_limits<T>::max()) : ((in.w() - 0.5f <= std::numeric_limits<T>::min()) ? (std::numeric_limits<T>::min()) : (T(in.w()))));
 }
 
+static string genTexFragmentShader (const vector<glu::DataType>& samplerTypes, glu::DataType outputType)
+{
+       const char*                     precision       = "highp";
+       std::ostringstream      src;
+
+       src << "#version 300 es\n"
+               << "layout(location = 0) out highp " << glu::getDataTypeName(outputType) << " o_color0;\n";
+
+       src << "in highp vec2 v_coord;\n";
+
+       for (int samplerNdx = 0; samplerNdx < (int)samplerTypes.size(); samplerNdx++)
+       {
+               src << "uniform " << precision << " " << glu::getDataTypeName(samplerTypes[samplerNdx]) << " u_sampler" << samplerNdx << ";\n";
+               src << "uniform " << precision << " vec4 u_texScale" << samplerNdx << ";\n";
+               src << "uniform " << precision << " vec4 u_texBias" << samplerNdx << ";\n";
+       }
+
+       // Output scale & bias
+       src << "uniform " << precision << " vec4 u_outScale0;\n"
+               << "uniform " << precision << " vec4 u_outBias0;\n";
+
+       src << "\n"
+               << "void main (void)\n"
+               << "{\n"
+               << "    " << precision << " vec4 out0 = vec4(0.0);\n";
+
+       // Texture input fetch and combine.
+       for (int inNdx = 0; inNdx < (int)samplerTypes.size(); inNdx++)
+               src << "\tout0 += vec4("
+                       << "texture(u_sampler" << inNdx << ", v_coord)) * u_texScale" << inNdx << " + u_texBias" << inNdx << ";\n";
+
+       // Write output.
+       src << "        o_color0 = " << glu::getDataTypeName(outputType) << "(out0 * u_outScale0 + u_outBias0);\n";
+
+       src << "}\n";
+
+       return src.str();
+}
+
+static sglr::pdec::ShaderProgramDeclaration genTexture2DShaderDecl (const DataTypes& samplerTypes, glu::DataType outputType)
+{
+       sglr::pdec::ShaderProgramDeclaration decl;
+
+       decl << sglr::pdec::VertexAttribute("a_position", rr::GENERICVECTYPE_FLOAT);
+       decl << sglr::pdec::VertexAttribute("a_coord", rr::GENERICVECTYPE_FLOAT);
+       decl << sglr::pdec::VertexToFragmentVarying(rr::GENERICVECTYPE_FLOAT);
+       decl << sglr::pdec::FragmentOutput(mapDataTypeToGenericVecType(outputType));
+
+       decl << sglr::pdec::VertexSource(
+               "#version 300 es\n"
+               "in highp vec4 a_position;\n"
+               "in highp vec2 a_coord;\n"
+               "out highp vec2 v_coord;\n"
+               "void main(void)\n"
+               "{\n"
+               "       gl_Position = a_position;\n"
+               "       v_coord = a_coord;\n"
+               "}\n");
+       decl << sglr::pdec::FragmentSource(genTexFragmentShader(samplerTypes.vec, outputType));
+
+       decl << sglr::pdec::Uniform("u_outScale0", glu::TYPE_FLOAT_VEC4);
+       decl << sglr::pdec::Uniform("u_outBias0", glu::TYPE_FLOAT_VEC4);
+
+       for (size_t ndx = 0; ndx < samplerTypes.vec.size(); ++ndx)
+       {
+               decl << sglr::pdec::Uniform(std::string("u_sampler")  + de::toString(ndx), samplerTypes.vec[ndx]);
+               decl << sglr::pdec::Uniform(std::string("u_texScale") + de::toString(ndx), glu::TYPE_FLOAT_VEC4);
+               decl << sglr::pdec::Uniform(std::string("u_texBias")  + de::toString(ndx), glu::TYPE_FLOAT_VEC4);
+       }
+
+       return decl;
+}
+
+Texture2DShader::Texture2DShader (const DataTypes& samplerTypes, glu::DataType outputType, const Vec4& outScale, const Vec4& outBias)
+       : sglr::ShaderProgram   (genTexture2DShaderDecl(samplerTypes, outputType))
+       , m_outScale                    (outScale)
+       , m_outBias                             (outBias)
+       , m_outputType                  (outputType)
+{
+       m_inputs.resize(samplerTypes.vec.size());
+
+       // Initialize units.
+       for (int ndx = 0; ndx < (int)m_inputs.size(); ndx++)
+       {
+               m_inputs[ndx].unitNdx   = ndx;
+               m_inputs[ndx].scale             = Vec4(1.0f);
+               m_inputs[ndx].bias              = Vec4(0.0f);
+       }
+}
+
+void Texture2DShader::setUnit (int inputNdx, int unitNdx)
+{
+       m_inputs[inputNdx].unitNdx = unitNdx;
+}
+
+void Texture2DShader::setTexScaleBias (int inputNdx, const Vec4& scale, const Vec4& bias)
+{
+       m_inputs[inputNdx].scale        = scale;
+       m_inputs[inputNdx].bias         = bias;
+}
+
+void Texture2DShader::setOutScaleBias (const Vec4& scale, const Vec4& bias)
+{
+       m_outScale      = scale;
+       m_outBias       = bias;
+}
+
+void Texture2DShader::setUniforms (sglr::Context& gl, deUint32 program) const
+{
+       gl.useProgram(program);
+
+       for (int texNdx = 0; texNdx < (int)m_inputs.size(); texNdx++)
+       {
+               string  samplerName     = string("u_sampler") + de::toString(texNdx);
+               string  scaleName       = string("u_texScale") + de::toString(texNdx);
+               string  biasName        = string("u_texBias") + de::toString(texNdx);
+
+               gl.uniform1i(gl.getUniformLocation(program, samplerName.c_str()), m_inputs[texNdx].unitNdx);
+               gl.uniform4fv(gl.getUniformLocation(program, scaleName.c_str()), 1, m_inputs[texNdx].scale.getPtr());
+               gl.uniform4fv(gl.getUniformLocation(program, biasName.c_str()), 1, m_inputs[texNdx].bias.getPtr());
+       }
+
+       gl.uniform4fv(gl.getUniformLocation(program, "u_outScale0"), 1, m_outScale.getPtr());
+       gl.uniform4fv(gl.getUniformLocation(program, "u_outBias0"), 1, m_outBias.getPtr());
+}
+
+void Texture2DShader::shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
+{
+       for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
+       {
+               rr::VertexPacket& packet = *packets[packetNdx];
+
+               packet.position         = rr::readVertexAttribFloat(inputs[0], packet.instanceNdx, packet.vertexNdx);
+               packet.outputs[0]       = rr::readVertexAttribFloat(inputs[1], packet.instanceNdx, packet.vertexNdx);
+       }
+}
+
+void Texture2DShader::shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
+{
+       const tcu::Vec4 outScale (m_uniforms[0].value.f4);
+       const tcu::Vec4 outBias  (m_uniforms[1].value.f4);
+
+       tcu::Vec2 texCoords[4];
+       tcu::Vec4 colors[4];
+
+       for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
+       {
+               // setup tex coords
+               for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
+               {
+                       const tcu::Vec4 coord = rr::readTriangleVarying<float>(packets[packetNdx], context, 0, fragNdx);
+                       texCoords[fragNdx] = tcu::Vec2(coord.x(), coord.y());
+               }
+
+               // clear result
+               for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
+                       colors[fragNdx] = tcu::Vec4(0.0f);
+
+               // sample each texture
+               for (int ndx = 0; ndx < (int)m_inputs.size(); ndx++)
+               {
+                       const sglr::rc::Texture2D*      tex             = m_uniforms[2 + ndx*3].sampler.tex2D;
+                       const tcu::Vec4                         scale   (m_uniforms[2 + ndx*3 + 1].value.f4);
+                       const tcu::Vec4                         bias    (m_uniforms[2 + ndx*3 + 2].value.f4);
+                       tcu::Vec4 tmpColors[4];
+
+                       tex->sample4(tmpColors, texCoords);
+
+                       for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
+                               colors[fragNdx] += tmpColors[fragNdx] * scale + bias;
+               }
+
+               // write out
+               for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
+               {
+                       const tcu::Vec4         color   = colors[fragNdx] * outScale + outBias;
+                       const tcu::IVec4        icolor  = castVectorSaturate<deInt32>(color);
+                       const tcu::UVec4        uicolor = castVectorSaturate<deUint32>(color);
+
+                       if (m_outputType == glu::TYPE_FLOAT_VEC4)                       rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, color);
+                       else if (m_outputType == glu::TYPE_INT_VEC4)            rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, icolor);
+                       else if (m_outputType == glu::TYPE_UINT_VEC4)           rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, uicolor);
+                       else
+                               DE_ASSERT(DE_FALSE);
+               }
+       }
+}
+
 TextureCubeArrayShader::TextureCubeArrayShader (glu::DataType samplerType, glu::DataType outputType)
        : sglr::ShaderProgram(sglr::pdec::ShaderProgramDeclaration()
                                                        << sglr::pdec::VertexAttribute("a_position", rr::GENERICVECTYPE_FLOAT)
@@ -84,6 +272,7 @@ TextureCubeArrayShader::TextureCubeArrayShader (glu::DataType samplerType, glu::
                                                        << sglr::pdec::Uniform("u_sampler0", samplerType)
                                                        << sglr::pdec::Uniform("u_scale", glu::TYPE_FLOAT_VEC4)
                                                        << sglr::pdec::Uniform("u_bias", glu::TYPE_FLOAT_VEC4)
+                                                       << sglr::pdec::Uniform("u_layer", glu::TYPE_INT)
                                                        << sglr::pdec::VertexSource(
                                                                        "#version 310 es\n"
                                                                        "#extension GL_EXT_texture_cube_map_array : require\n"
@@ -222,6 +411,211 @@ void TextureCubeArrayShader::shadeFragments (rr::FragmentPacket* packets, const
        }
 }
 
+void clearColorBuffer (sglr::Context& ctx, const tcu::TextureFormat& format, const tcu::Vec4& value)
+{
+       const tcu::TextureChannelClass fmtClass = tcu::getTextureChannelClass(format.type);
+
+       switch (fmtClass)
+       {
+               case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
+               case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
+               case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
+                       ctx.clearBufferfv(GL_COLOR, 0, value.getPtr());
+                       break;
+
+               case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
+                       ctx.clearBufferuiv(GL_COLOR, 0, value.asUint().getPtr());
+                       break;
+
+               case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
+                       ctx.clearBufferiv(GL_COLOR, 0, value.asInt().getPtr());
+                       break;
+
+               default:
+                       DE_ASSERT(DE_FALSE);
+       }
+}
+
+void readPixels (sglr::Context& ctx, tcu::Surface& dst, int x, int y, int width, int height, const tcu::TextureFormat& format, const tcu::Vec4& scale, const tcu::Vec4& bias)
+{
+       tcu::TextureFormat              readFormat              = getFramebufferReadFormat(format);
+       glu::TransferFormat             transferFmt             = glu::getTransferFormat(readFormat);
+       int                                             alignment               = 4; // \note GL_PACK_ALIGNMENT = 4 is assumed.
+       int                                             rowSize                 = deAlign32(readFormat.getPixelSize()*width, alignment);
+       vector<deUint8>                 data                    (rowSize*height);
+
+       ctx.readPixels(x, y, width, height, transferFmt.format, transferFmt.dataType, &data[0]);
+
+       // Convert to surface.
+       tcu::ConstPixelBufferAccess src(readFormat, width, height, 1, rowSize, 0, &data[0]);
+
+       dst.setSize(width, height);
+       tcu::PixelBufferAccess dstAccess = dst.getAccess();
+
+       for (int yo = 0; yo < height; yo++)
+       for (int xo = 0; xo < width; xo++)
+               dstAccess.setPixel(src.getPixel(xo, yo) * scale + bias, xo, yo);
+}
+
+static const char* getFboIncompleteReasonName (deUint32 reason)
+{
+       switch (reason)
+       {
+               case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:                      return "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT";
+               case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:      return "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT";
+               case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:                      return "GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS";
+               case GL_FRAMEBUFFER_UNSUPPORTED:                                        return "GL_FRAMEBUFFER_UNSUPPORTED";
+               case GL_FRAMEBUFFER_COMPLETE:                                           return "GL_FRAMEBUFFER_COMPLETE";
+               default:                                                                                        return "UNKNOWN";
+       }
+}
+
+FboIncompleteException::FboIncompleteException (deUint32 reason, const char* file, int line)
+       : TestError             ("Framebuffer is not complete", getFboIncompleteReasonName(reason), file, line)
+       , m_reason              (reason)
+{
+}
+
+const char* getFormatName (deUint32 format)
+{
+       switch (format)
+       {
+               case GL_RGB565:                         return "rgb565";
+               case GL_RGB5_A1:                        return "rgb5_a1";
+               case GL_RGBA4:                          return "rgba4";
+               case GL_DEPTH_COMPONENT16:      return "depth_component16";
+               case GL_STENCIL_INDEX8:         return "stencil_index8";
+               case GL_RGBA32F:                        return "rgba32f";
+               case GL_RGBA32I:                        return "rgba32i";
+               case GL_RGBA32UI:                       return "rgba32ui";
+               case GL_RGBA16F:                        return "rgba16f";
+               case GL_RGBA16I:                        return "rgba16i";
+               case GL_RGBA16UI:                       return "rgba16ui";
+               case GL_RGBA8:                          return "rgba8";
+               case GL_RGBA8I:                         return "rgba8i";
+               case GL_RGBA8UI:                        return "rgba8ui";
+               case GL_SRGB8_ALPHA8:           return "srgb8_alpha8";
+               case GL_RGB10_A2:                       return "rgb10_a2";
+               case GL_RGB10_A2UI:                     return "rgb10_a2ui";
+               case GL_RGBA8_SNORM:            return "rgba8_snorm";
+               case GL_RGB8:                           return "rgb8";
+               case GL_R11F_G11F_B10F:         return "r11f_g11f_b10f";
+               case GL_RGB32F:                         return "rgb32f";
+               case GL_RGB32I:                         return "rgb32i";
+               case GL_RGB32UI:                        return "rgb32ui";
+               case GL_RGB16F:                         return "rgb16f";
+               case GL_RGB16I:                         return "rgb16i";
+               case GL_RGB16UI:                        return "rgb16ui";
+               case GL_RGB8_SNORM:                     return "rgb8_snorm";
+               case GL_RGB8I:                          return "rgb8i";
+               case GL_RGB8UI:                         return "rgb8ui";
+               case GL_SRGB8:                          return "srgb8";
+               case GL_RGB9_E5:                        return "rgb9_e5";
+               case GL_RG32F:                          return "rg32f";
+               case GL_RG32I:                          return "rg32i";
+               case GL_RG32UI:                         return "rg32ui";
+               case GL_RG16F:                          return "rg16f";
+               case GL_RG16I:                          return "rg16i";
+               case GL_RG16UI:                         return "rg16ui";
+               case GL_RG8:                            return "rg8";
+               case GL_RG8I:                           return "rg8i";
+               case GL_RG8UI:                          return "rg8ui";
+               case GL_RG8_SNORM:                      return "rg8_snorm";
+               case GL_R32F:                           return "r32f";
+               case GL_R32I:                           return "r32i";
+               case GL_R32UI:                          return "r32ui";
+               case GL_R16F:                           return "r16f";
+               case GL_R16I:                           return "r16i";
+               case GL_R16UI:                          return "r16ui";
+               case GL_R8:                                     return "r8";
+               case GL_R8I:                            return "r8i";
+               case GL_R8UI:                           return "r8ui";
+               case GL_R8_SNORM:                       return "r8_snorm";
+               case GL_DEPTH_COMPONENT32F:     return "depth_component32f";
+               case GL_DEPTH_COMPONENT24:      return "depth_component24";
+               case GL_DEPTH32F_STENCIL8:      return "depth32f_stencil8";
+               case GL_DEPTH24_STENCIL8:       return "depth24_stencil8";
+
+               default:
+                       TCU_FAIL("Unknown format");
+       }
+}
+
+glu::DataType getFragmentOutputType (const tcu::TextureFormat& format)
+{
+       switch (tcu::getTextureChannelClass(format.type))
+       {
+               case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
+               case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
+               case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
+                       return glu::TYPE_FLOAT_VEC4;
+
+               case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
+                       return glu::TYPE_UINT_VEC4;
+
+               case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
+                       return glu::TYPE_INT_VEC4;
+
+               default:
+                       DE_ASSERT(!"Unknown format");
+                       return glu::TYPE_LAST;
+       }
+}
+
+tcu::TextureFormat getFramebufferReadFormat (const tcu::TextureFormat& format)
+{
+       switch (tcu::getTextureChannelClass(format.type))
+       {
+               case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
+                       return tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::FLOAT);
+
+               case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
+               case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
+                       return tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8);
+
+               case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
+                       return tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNSIGNED_INT32);
+
+               case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
+                       return tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::SIGNED_INT32);
+
+               default:
+                       DE_ASSERT(!"Unknown format");
+                       return tcu::TextureFormat();
+       }
+}
+
+static int calculateU8ConversionError (int srcBits)
+{
+       if (srcBits > 0)
+       {
+               const int clampedBits   = de::clamp<int>(srcBits, 0, 8);
+               const int srcMaxValue   = de::max((1<<clampedBits) - 1, 1);
+               const int error                 = int(deFloatCeil(255.0f * 2.0f / float(srcMaxValue)));
+
+               return de::clamp<int>(error, 0, 255);
+       }
+       else
+               return 1;
+}
+
+tcu::RGBA getFormatThreshold (const tcu::TextureFormat& format)
+{
+       const tcu::IVec4 bits = tcu::getTextureFormatBitDepth(format);
+
+       return tcu::RGBA(calculateU8ConversionError(bits.x()),
+                                        calculateU8ConversionError(bits.y()),
+                                        calculateU8ConversionError(bits.z()),
+                                        calculateU8ConversionError(bits.w()));
+}
+
+tcu::RGBA getFormatThreshold (deUint32 glFormat)
+{
+       const tcu::TextureFormat format = glu::mapGLInternalFormat(glFormat);
+
+       return getFormatThreshold(format);
+}
+
 } // FboTestUtil
 } // Functional
 } // gles31
index 50d554c..1e06a47 100644 (file)
@@ -52,6 +52,36 @@ struct DataTypes
 
 // Shaders.
 
+class Texture2DShader : public sglr::ShaderProgram
+{
+public:
+                                       Texture2DShader                 (const DataTypes& samplerTypes, glu::DataType outputType, const tcu::Vec4& outScale = tcu::Vec4(1.0f), const tcu::Vec4& outBias = tcu::Vec4(0.0f));
+                                       ~Texture2DShader                (void) {}
+
+       void                    setUnit                                 (int samplerNdx, int unitNdx);
+       void                    setTexScaleBias                 (int samplerNdx, const tcu::Vec4& scale, const tcu::Vec4& bias);
+       void                    setOutScaleBias                 (const tcu::Vec4& scale, const tcu::Vec4& bias);
+
+       void                    setUniforms                             (sglr::Context& context, deUint32 program) const;
+
+       void                    shadeVertices                   (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const;
+       void                    shadeFragments                  (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const;
+
+private:
+       struct Input
+       {
+               int                     unitNdx;
+               tcu::Vec4       scale;
+               tcu::Vec4       bias;
+       };
+
+       std::vector<Input>      m_inputs;
+       tcu::Vec4                       m_outScale;
+       tcu::Vec4                       m_outBias;
+
+       const glu::DataType     m_outputType;
+};
+
 class TextureCubeArrayShader : public sglr::ShaderProgram
 {
 public:
@@ -76,6 +106,32 @@ private:
        const glu::DataType     m_outputType;
 };
 
+// Framebuffer incomplete exception.
+class FboIncompleteException : public tcu::TestError
+{
+public:
+                                               FboIncompleteException          (deUint32 reason, const char* file, int line);
+       virtual                         ~FboIncompleteException         (void) throw() {}
+
+       deUint32                        getReason                                       (void) const { return m_reason; }
+
+private:
+       deUint32                        m_reason;
+};
+
+// Utility functions
+
+glu::DataType                  getFragmentOutputType                           (const tcu::TextureFormat& format);
+tcu::TextureFormat             getFramebufferReadFormat                        (const tcu::TextureFormat& format);
+
+const char*                            getFormatName                                           (deUint32 format);
+
+void                                   clearColorBuffer                                        (sglr::Context& ctx, const tcu::TextureFormat& format, const tcu::Vec4& value);
+void                                   readPixels                                                      (sglr::Context& ctx, tcu::Surface& dst, int x, int y, int width, int height, const tcu::TextureFormat& format, const tcu::Vec4& scale, const tcu::Vec4& bias);
+
+tcu::RGBA                              getFormatThreshold                                      (const tcu::TextureFormat& format);
+tcu::RGBA                              getFormatThreshold                                      (const deUint32 glFormat);
+
 } // FboTestUtil
 } // Functional
 } // gles31
index 3b07e6e..3aef6a5 100644 (file)
@@ -44,6 +44,7 @@
 #include "es31fTextureLevelStateQueryTests.hpp"
 #include "es31fIntegerStateQueryTests.hpp"
 #include "es31fInternalFormatQueryTests.hpp"
+#include "es31fTextureFilteringTests.hpp"
 #include "es31fTextureFormatTests.hpp"
 #include "es31fTextureSpecificationTests.hpp"
 #include "es31fTextureMultisampleTests.hpp"
@@ -66,6 +67,7 @@
 #include "es31fTessellationGeometryInteractionTests.hpp"
 #include "es31fUniformBlockTests.hpp"
 #include "es31fDebugTests.hpp"
+#include "es31fFboColorbufferTests.hpp"
 #include "es31fFboNoAttachmentTests.hpp"
 #include "es31fProgramInterfaceQueryTests.hpp"
 #include "es31fTextureGatherTests.hpp"
@@ -226,6 +228,7 @@ public:
 
        void init (void)
        {
+               addChild(new TextureFilteringTests              (m_context));
                addChild(new TextureFormatTests                 (m_context));
                addChild(new TextureSpecificationTests  (m_context));
                addChild(new TextureMultisampleTests    (m_context));
@@ -263,6 +266,7 @@ public:
 
        void init (void)
        {
+               addChild(new FboColorTests                                              (m_context));
                addChild(createFboNoAttachmentTests                             (m_context));
                addChild(createFboNoAttachmentCompletenessTests (m_context));
        }
index a8401aa..6e374a5 100644 (file)
@@ -1149,6 +1149,7 @@ std::string BuiltinVariableShader::genFragmentSource (VariableTest test) const
        else if (test == TEST_PRIMITIVE_ID)
        {
                return  "#version 310 es\n"
+                               "#extension GL_EXT_geometry_shader : require\n"
                                "layout(location = 0) out mediump vec4 fragColor;\n"
                                "void main (void)\n"
                                "{\n"
index c345412..21ee901 100644 (file)
@@ -1263,7 +1263,7 @@ glu::ShaderProgram* ImageBindingRenderCase::generateShaders (void) const
        // Generate the uniform declarations for the vertex and fragment shaders
        for (int declNdx = 0; declNdx < numDeclarations; ++declNdx)
        {
-               shaderUniformDecl << "layout(rgba8, binding = " << m_bindings[declNdx] << ") uniform readonly " << imageType
+               shaderUniformDecl << "layout(rgba8, binding = " << m_bindings[declNdx] << ") uniform readonly highp " << imageType
                        << " " << (arrayInstance ? getUniformName(m_uniformName, declNdx, m_numBindings) : getUniformName(m_uniformName, declNdx)) << ";\n";
        }
 
@@ -1353,9 +1353,9 @@ glu::ShaderProgram* ImageBindingNegativeCase::generateShaders (void) const
        // Generate the uniform declarations for the vertex and fragment shaders
        for (int declNdx = 0; declNdx < numDeclarations; ++declNdx)
        {
-               vertexUniformDecl << "layout(rgba8, binding = " << m_vertexShaderBinding[declNdx] << ") uniform readonly " << imageType
+               vertexUniformDecl << "layout(rgba8, binding = " << m_vertexShaderBinding[declNdx] << ") uniform readonly highp " << imageType
                        << " " << (arrayInstance ? getUniformName(m_uniformName, declNdx, m_numBindings) : getUniformName(m_uniformName, declNdx)) << ";\n";
-               fragmentUniformDecl << "layout(rgba8, binding = " << m_fragmentShaderBinding[declNdx] << ") uniform readonly " << imageType
+               fragmentUniformDecl << "layout(rgba8, binding = " << m_fragmentShaderBinding[declNdx] << ") uniform readonly highp " << imageType
                        << " " << (arrayInstance ? getUniformName(m_uniformName, declNdx, m_numBindings) : getUniformName(m_uniformName, declNdx)) << ";\n";
        }
 
index 623f54a..e31091b 100644 (file)
@@ -68,6 +68,7 @@ typedef de::UniquePtr<ShaderExecutor> ShaderExecutorPtr;
 enum IndexExprType
 {
        INDEX_EXPR_TYPE_CONST_LITERAL   = 0,
+       INDEX_EXPR_TYPE_CONST_EXPRESSION,
        INDEX_EXPR_TYPE_UNIFORM,
        INDEX_EXPR_TYPE_DYNAMIC_UNIFORM,
 
@@ -364,6 +365,9 @@ void SamplerIndexingCase::getShaderSpec (ShaderSpec* spec, int numSamplers, int
        if (m_indexExprType != INDEX_EXPR_TYPE_CONST_LITERAL)
                global << "#extension GL_EXT_gpu_shader5 : require\n";
 
+       if (m_indexExprType == INDEX_EXPR_TYPE_CONST_EXPRESSION)
+               global << "const highp int indexBase = 1;\n";
+
        global <<
                "uniform highp " << getDataTypeName(m_samplerType) << " " << samplersName << "[" << numSamplers << "];\n";
 
@@ -390,6 +394,8 @@ void SamplerIndexingCase::getShaderSpec (ShaderSpec* spec, int numSamplers, int
 
                if (m_indexExprType == INDEX_EXPR_TYPE_CONST_LITERAL)
                        code << lookupIndices[lookupNdx];
+               else if (m_indexExprType == INDEX_EXPR_TYPE_CONST_EXPRESSION)
+                       code << "indexBase + " << (lookupIndices[lookupNdx]-1);
                else
                        code << indicesPrefix << lookupNdx;
 
@@ -656,6 +662,8 @@ private:
        const BlockType                         m_blockType;
        const IndexExprType                     m_indexExprType;
        const ShaderType                        m_shaderType;
+
+       const int                                       m_numInstances;
 };
 
 BlockArrayIndexingCase::BlockArrayIndexingCase (Context& context, const char* name, const char* description, BlockType blockType, IndexExprType indexExprType, ShaderType shaderType)
@@ -663,6 +671,7 @@ BlockArrayIndexingCase::BlockArrayIndexingCase (Context& context, const char* na
        , m_blockType           (blockType)
        , m_indexExprType       (indexExprType)
        , m_shaderType          (shaderType)
+       , m_numInstances        (4)
 {
 }
 
@@ -677,6 +686,28 @@ void BlockArrayIndexingCase::init (void)
        if (m_indexExprType != INDEX_EXPR_TYPE_CONST_LITERAL &&
                !m_context.getContextInfo().isExtensionSupported(extName))
                throw tcu::NotSupportedError(string(extName) + " extension is required for dynamic indexing of interface blocks");
+
+       if (m_blockType == BLOCKTYPE_BUFFER)
+       {
+               const deUint32 limitPnames[] =
+               {
+                       GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS,
+                       GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS,
+                       GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS,
+                       GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS,
+                       GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS,
+                       GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS
+               };
+
+               const glw::Functions&   gl                      = m_context.getRenderContext().getFunctions();
+               int                                             maxBlocks       = 0;
+
+               gl.getIntegerv(limitPnames[m_shaderType], &maxBlocks);
+               GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv()");
+
+               if (maxBlocks < m_numInstances)
+                       throw tcu::NotSupportedError("Not enough shader storage blocks supported for shader type");
+       }
 }
 
 void BlockArrayIndexingCase::getShaderSpec (ShaderSpec* spec, int numInstances, int numReads, const int* readIndices) const
@@ -693,6 +724,9 @@ void BlockArrayIndexingCase::getShaderSpec (ShaderSpec* spec, int numInstances,
        if (m_indexExprType != INDEX_EXPR_TYPE_CONST_LITERAL)
                global << "#extension GL_EXT_gpu_shader5 : require\n";
 
+       if (m_indexExprType == INDEX_EXPR_TYPE_CONST_EXPRESSION)
+               global << "const highp int indexBase = 1;\n";
+
        global <<
                "layout(" << layout << ", binding = " << binding << ") " << interfaceName << " " << blockName << "\n"
                "{\n"
@@ -722,6 +756,8 @@ void BlockArrayIndexingCase::getShaderSpec (ShaderSpec* spec, int numInstances,
 
                if (m_indexExprType == INDEX_EXPR_TYPE_CONST_LITERAL)
                        code << readIndices[readNdx];
+               else if (m_indexExprType == INDEX_EXPR_TYPE_CONST_EXPRESSION)
+                       code << "indexBase + " << (readIndices[readNdx]-1);
                else
                        code << indicesPrefix << readNdx;
 
@@ -736,7 +772,7 @@ void BlockArrayIndexingCase::getShaderSpec (ShaderSpec* spec, int numInstances,
 BlockArrayIndexingCase::IterateResult BlockArrayIndexingCase::iterate (void)
 {
        const int                       numInvocations          = 32;
-       const int                       numInstances            = 4;
+       const int                       numInstances            = m_numInstances;
        const int                       numReads                        = 4;
        vector<int>                     readIndices                     (numReads);
        vector<deUint32>        inValues                        (numInstances);
@@ -885,6 +921,9 @@ void AtomicCounterIndexingCase::getShaderSpec (ShaderSpec* spec, int numCounters
        if (m_indexExprType != INDEX_EXPR_TYPE_CONST_LITERAL)
                global << "#extension GL_EXT_gpu_shader5 : require\n";
 
+       if (m_indexExprType == INDEX_EXPR_TYPE_CONST_EXPRESSION)
+               global << "const highp int indexBase = 1;\n";
+
        global <<
                "layout(binding = 0) uniform atomic_uint counter[" << numCounters << "];\n";
 
@@ -911,6 +950,8 @@ void AtomicCounterIndexingCase::getShaderSpec (ShaderSpec* spec, int numCounters
 
                if (m_indexExprType == INDEX_EXPR_TYPE_CONST_LITERAL)
                        code << opIndices[opNdx];
+               else if (m_indexExprType == INDEX_EXPR_TYPE_CONST_EXPRESSION)
+                       code << "indexBase + " << (opIndices[opNdx]-1);
                else
                        code << indicesPrefix << opNdx;
 
@@ -1110,7 +1151,8 @@ void OpaqueTypeIndexingTests::init (void)
                const char*             description;
        } indexingTypes[] =
        {
-               { INDEX_EXPR_TYPE_CONST_LITERAL,        "const_literal",                "Indexing by constant literal expression"               },
+               { INDEX_EXPR_TYPE_CONST_LITERAL,        "const_literal",                "Indexing by constant literal"                                  },
+               { INDEX_EXPR_TYPE_CONST_EXPRESSION,     "const_expression",             "Indexing by constant expression"                               },
                { INDEX_EXPR_TYPE_UNIFORM,                      "uniform",                              "Indexing by uniform value"                                             },
                { INDEX_EXPR_TYPE_DYNAMIC_UNIFORM,      "dynamically_uniform",  "Indexing by dynamically uniform expression"    }
        };
@@ -1200,8 +1242,10 @@ void OpaqueTypeIndexingTests::init (void)
                                const string                    name                    = string(indexExprName) + "_" + shaderTypes[shaderTypeNdx].name;
 
                                uboGroup->addChild      (new BlockArrayIndexingCase             (m_context, name.c_str(), indexExprDesc, BlockArrayIndexingCase::BLOCKTYPE_UNIFORM,     indexExprType, shaderType));
-                               ssboGroup->addChild     (new BlockArrayIndexingCase             (m_context, name.c_str(), indexExprDesc, BlockArrayIndexingCase::BLOCKTYPE_BUFFER,      indexExprType, shaderType));
                                acGroup->addChild       (new AtomicCounterIndexingCase  (m_context, name.c_str(), indexExprDesc, indexExprType, shaderType));
+
+                               if (indexExprType == INDEX_EXPR_TYPE_CONST_LITERAL || indexExprType == INDEX_EXPR_TYPE_CONST_EXPRESSION)
+                                       ssboGroup->addChild     (new BlockArrayIndexingCase             (m_context, name.c_str(), indexExprDesc, BlockArrayIndexingCase::BLOCKTYPE_BUFFER,      indexExprType, shaderType));
                        }
                }
        }
index c8a3067..a9d32ca 100644 (file)
@@ -994,6 +994,42 @@ std::vector<std::string> getProgramInterfaceResourceList (const ProgramInterface
                                }
                        }
 
+                       // built-ins
+                       if (interface == PROGRAMINTERFACE_PROGRAM_INPUT)
+                       {
+                               if (shaderType == glu::SHADERTYPE_VERTEX && resources.empty())
+                                       resources.push_back("gl_VertexID"); // only read from when there are no other inputs
+                               else if (shaderType == glu::SHADERTYPE_FRAGMENT && resources.empty())
+                                       resources.push_back("gl_FragCoord"); // only read from when there are no other inputs
+                               else if (shaderType == glu::SHADERTYPE_GEOMETRY && resources.empty())
+                                       resources.push_back("gl_in[0].gl_Position");
+                               else if (shaderType == glu::SHADERTYPE_TESSELLATION_CONTROL)
+                               {
+                                       const bool noInputs = resources.empty();
+                                       resources.push_back("gl_InvocationID");
+
+                                       if (noInputs)
+                                               resources.push_back("gl_in[0].gl_Position"); // only read from when there are no other inputs
+                               }
+                               else if (shaderType == glu::SHADERTYPE_TESSELLATION_EVALUATION && resources.empty())
+                                       resources.push_back("gl_in[0].gl_Position"); // only read from when there are no other inputs
+                               else if (shaderType == glu::SHADERTYPE_COMPUTE && resources.empty())
+                                       resources.push_back("gl_NumWorkGroups"); // only read from when there are no other inputs
+                       }
+                       else if (interface == PROGRAMINTERFACE_PROGRAM_OUTPUT)
+                       {
+                               if (shaderType == glu::SHADERTYPE_VERTEX)
+                                       resources.push_back("gl_Position");
+                               else if (shaderType == glu::SHADERTYPE_FRAGMENT && resources.empty())
+                                       resources.push_back("gl_FragDepth"); // only written to when there are no other outputs
+                               else if (shaderType == glu::SHADERTYPE_GEOMETRY)
+                                       resources.push_back("gl_Position");
+                               else if (shaderType == glu::SHADERTYPE_TESSELLATION_CONTROL)
+                                       resources.push_back("gl_out[0].gl_Position");
+                               else if (shaderType == glu::SHADERTYPE_TESSELLATION_EVALUATION)
+                                       resources.push_back("gl_Position");
+                       }
+
                        break;
                }
 
index 382328e..e9acce4 100644 (file)
@@ -350,25 +350,48 @@ void TypeValidator::validateSingleVariable (const std::vector<VariablePathCompon
 
        DE_UNREF(resource);
 
+       m_testCtx.getLog() << tcu::TestLog::Message << "Verifying type, expecting " << glu::getDataTypeName(variable->getBasicType()) << tcu::TestLog::EndMessage;
+
        if (variable->getBasicType() != glu::getDataTypeFromGLType(propValue))
        {
-               m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << glu::getDataTypeFromGLType(propValue) << tcu::TestLog::EndMessage;
+               m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << glu::getDataTypeName(glu::getDataTypeFromGLType(propValue)) << tcu::TestLog::EndMessage;
                setError("resource type invalid");
        }
 }
 
 void TypeValidator::validateBuiltinVariable (const std::string& resource, glw::GLint propValue) const
 {
-       if (resource == "gl_Position")
+       static const struct
+       {
+               const char*             name;
+               glu::DataType   type;
+       } builtins[] =
+       {
+               { "gl_Position",                        glu::TYPE_FLOAT_VEC4    },
+               { "gl_FragCoord",                       glu::TYPE_FLOAT_VEC4    },
+               { "gl_in[0].gl_Position",       glu::TYPE_FLOAT_VEC4    },
+               { "gl_VertexID",                        glu::TYPE_INT                   },
+               { "gl_InvocationID",            glu::TYPE_INT                   },
+               { "gl_NumWorkGroups",           glu::TYPE_UINT_VEC3             },
+               { "gl_FragDepth",                       glu::TYPE_FLOAT                 },
+       };
+
+       for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(builtins); ++ndx)
        {
-               if (glu::getDataTypeFromGLType(propValue) != glu::TYPE_FLOAT_VEC4)
+               if (resource == builtins[ndx].name)
                {
-                       m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << glu::getDataTypeFromGLType(propValue) << tcu::TestLog::EndMessage;
-                       setError("resource type invalid");
+                       m_testCtx.getLog() << tcu::TestLog::Message << "Verifying type, expecting " << glu::getDataTypeName(builtins[ndx].type) << tcu::TestLog::EndMessage;
+
+                       if (glu::getDataTypeFromGLType(propValue) != builtins[ndx].type)
+                       {
+                               m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << glu::getDataTypeName(glu::getDataTypeFromGLType(propValue)) << tcu::TestLog::EndMessage;
+                               setError("resource type invalid");
+                       }
+                       return;
                }
        }
-       else
-               DE_ASSERT(false);
+
+       DE_ASSERT(false);
 }
 
 class ArraySizeValidator : public SingleVariableValidator
@@ -376,6 +399,7 @@ class ArraySizeValidator : public SingleVariableValidator
 public:
                                ArraySizeValidator                              (Context& context, glw::GLuint programID, const VariableSearchFilter& filter);
        void            validateSingleVariable                  (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue) const;
+       void            validateBuiltinVariable                 (const std::string& resource, glw::GLint propValue) const;
 };
 
 ArraySizeValidator::ArraySizeValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
@@ -403,6 +427,29 @@ void ArraySizeValidator::validateSingleVariable (const std::vector<VariablePathC
        }
 }
 
+void ArraySizeValidator::validateBuiltinVariable (const std::string& resource, glw::GLint propValue) const
+{
+       // support all built-ins that getProgramInterfaceResourceList supports
+       if (resource == "gl_Position"                   ||
+               resource == "gl_VertexID"                       ||
+               resource == "gl_FragCoord"                      ||
+               resource == "gl_in[0].gl_Position"      ||
+               resource == "gl_InvocationID"           ||
+               resource == "gl_NumWorkGroups"          ||
+               resource == "gl_FragDepth")
+       {
+               m_testCtx.getLog() << tcu::TestLog::Message << "Verifying array size, expecting 1" << tcu::TestLog::EndMessage;
+
+               if (propValue != 1)
+               {
+                       m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
+                       setError("resource array size invalid");
+               }
+       }
+       else
+               DE_ASSERT(false);
+}
+
 class ArrayStrideValidator : public SingleVariableValidator
 {
 public:
@@ -672,6 +719,7 @@ class LocationValidator : public SingleVariableValidator
 public:
                                LocationValidator               (Context& context, glw::GLuint programID, const VariableSearchFilter& filter);
        void            validateSingleVariable  (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue) const;
+       void            validateBuiltinVariable (const std::string& resource, glw::GLint propValue) const;
 };
 
 LocationValidator::LocationValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
@@ -905,6 +953,21 @@ void LocationValidator::validateSingleVariable (const std::vector<VariablePathCo
        }
 }
 
+void LocationValidator::validateBuiltinVariable (const std::string& resource, glw::GLint propValue) const
+{
+       DE_UNREF(resource);
+
+       // built-ins have no location
+
+       m_testCtx.getLog() << tcu::TestLog::Message << "Verifying location, expecting -1" << tcu::TestLog::EndMessage;
+
+       if (propValue != -1)
+       {
+               m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
+               setError("resource location invalid");
+       }
+}
+
 class VariableNameLengthValidator : public SingleVariableValidator
 {
 public:
index 27c14f9..28aff5e 100644 (file)
@@ -436,7 +436,7 @@ static glu::Precision getDataTypeDefaultPrecision (const glu::DataType& type)
        else if (glu::isDataTypeSampler(type))
                return glu::PRECISION_HIGHP;
        else if (glu::isDataTypeImage(type))
-               return glu::PRECISION_LAST;
+               return glu::PRECISION_HIGHP;
        else if (type == glu::TYPE_UINT_ATOMIC_COUNTER)
                return glu::PRECISION_HIGHP;
 
@@ -922,11 +922,16 @@ bool ResourceListTestCase::verifyResourceList (const std::vector<std::string>& r
 
        for (int ndx = 0; ndx < (int)resourceList.size(); ++ndx)
        {
-               // Ignore all builtin variables
-               if (deStringBeginsWith(resourceList[ndx].c_str(), "gl_") == DE_FALSE && !de::contains(expectedResources.begin(), expectedResources.end(), resourceList[ndx]))
+               if (!de::contains(expectedResources.begin(), expectedResources.end(), resourceList[ndx]))
                {
-                       m_testCtx.getLog() << tcu::TestLog::Message << "Error, resource list contains unexpected resource name " << resourceList[ndx] << tcu::TestLog::EndMessage;
-                       error = true;
+                       // Ignore all builtin variables, mismatch causes errors otherwise
+                       if (deStringBeginsWith(resourceList[ndx].c_str(), "gl_") == DE_FALSE)
+                       {
+                               m_testCtx.getLog() << tcu::TestLog::Message << "Error, resource list contains unexpected resource name " << resourceList[ndx] << tcu::TestLog::EndMessage;
+                               error = true;
+                       }
+                       else
+                               m_testCtx.getLog() << tcu::TestLog::Message << "Note, resource list contains unknown built-in " << resourceList[ndx] << ". This variable is ignored." << tcu::TestLog::EndMessage;
                }
        }
 
@@ -1007,7 +1012,7 @@ bool ResourceListTestCase::verifyMaxNameLength (const std::vector<std::string>&
        for (int ndx = 0; ndx < (int)resourceList.size(); ++ndx)
                expectedMaxNameLength = de::max(expectedMaxNameLength, (int)resourceList[ndx].size() + 1);
 
-       m_testCtx.getLog() << tcu::TestLog::Message << "Verifying MAX_NAME_LENGTH, expecting " << expectedMaxNameLength << tcu::TestLog::EndMessage;
+       m_testCtx.getLog() << tcu::TestLog::Message << "Verifying MAX_NAME_LENGTH, expecting " << expectedMaxNameLength << " (i.e. consistent with the queried resource list)" << tcu::TestLog::EndMessage;
 
        if (expectedMaxNameLength != maxNameLength)
        {
index 23d36e2..4741fe4 100644 (file)
@@ -180,42 +180,10 @@ struct BufferVarLayoutEntry
        bool                            isRowMajor;
 };
 
-// \note For arrays of basic types (not aggregate types), TOP_LEVEL_ARRAY_SIZE = 1,
-//              but for practical reasons these functions report ARRAY_SIZE as top level
-//              array size for such arrays (and 1 as array size).
-//              See Khronos bug 11753
-
-static bool isBasicTypeArray (const BufferVarLayoutEntry& entry)
-{
-       // \note Fails to differentiate cases like a[1][1] where implementation assigns
-       //               0 as both top-level and bottom-level array stride (which is valid for
-       //               impl-dependent layouts) but this doesn't matter in practice.
-       return entry.topLevelArraySize == 1 && entry.topLevelArrayStride == 0 && (entry.arraySize != 1 || entry.arrayStride != 0);
-}
-
-static int getTopLevelArraySize (const BufferVarLayoutEntry& entry)
-{
-       return isBasicTypeArray(entry) ? entry.arraySize : entry.topLevelArraySize;
-}
-
-static int getTopLevelArrayStride (const BufferVarLayoutEntry& entry)
-{
-       return isBasicTypeArray(entry) ? entry.arrayStride : entry.topLevelArrayStride;
-}
-
-static int getArraySize (const BufferVarLayoutEntry& entry)
-{
-       return isBasicTypeArray(entry) ? 1 : entry.arraySize;
-}
-
-static int getArrayStride (const BufferVarLayoutEntry& entry)
-{
-       return isBasicTypeArray(entry) ? 0 : entry.arrayStride;
-}
-
-static bool isUnsizedTopLevelArray (const BufferVarLayoutEntry& entry)
+static bool isUnsizedArray (const BufferVarLayoutEntry& entry)
 {
-       return getTopLevelArraySize(entry) == 0;
+       DE_ASSERT(entry.arraySize != 0 || entry.topLevelArraySize != 0);
+       return entry.arraySize == 0 || entry.topLevelArraySize == 0;
 }
 
 std::ostream& operator<< (std::ostream& stream, const BufferVarLayoutEntry& entry)
@@ -760,23 +728,24 @@ void computeReferenceLayout (BufferLayout& layout, const ShaderInterface& interf
 
 // Value generator.
 
-void generateValue (const BufferVarLayoutEntry& entry, int topLevelArraySize, void* basePtr, de::Random& rnd)
+void generateValue (const BufferVarLayoutEntry& entry, int unsizedArraySize, void* basePtr, de::Random& rnd)
 {
        const glu::DataType     scalarType              = glu::getDataTypeScalarType(entry.type);
        const int                       scalarSize              = glu::getDataTypeScalarSize(entry.type);
-       const int                       arraySize               = getArraySize(entry);
-       const int                       topLevelStride  = getTopLevelArrayStride(entry);
-       const int                       arrayStride             = getArrayStride(entry);
+       const int                       arraySize               = entry.arraySize == 0 ? unsizedArraySize : entry.arraySize;
+       const int                       arrayStride             = entry.arrayStride;
+       const int                       topLevelSize    = entry.topLevelArraySize == 0 ? unsizedArraySize : entry.topLevelArraySize;
+       const int                       topLevelStride  = entry.topLevelArrayStride;
        const bool                      isMatrix                = glu::isDataTypeMatrix(entry.type);
        const int                       numVecs                 = isMatrix ? (entry.isRowMajor ? glu::getDataTypeMatrixNumRows(entry.type) : glu::getDataTypeMatrixNumColumns(entry.type)) : 1;
        const int                       vecSize                 = scalarSize / numVecs;
        const int                       compSize                = sizeof(deUint32);
 
        DE_ASSERT(scalarSize%numVecs == 0);
-       DE_ASSERT(topLevelArraySize >= 0);
-       DE_ASSERT(arraySize > 0);
+       DE_ASSERT(topLevelSize >= 0);
+       DE_ASSERT(arraySize >= 0);
 
-       for (int topElemNdx = 0; topElemNdx < topLevelArraySize; topElemNdx++)
+       for (int topElemNdx = 0; topElemNdx < topLevelSize; topElemNdx++)
        {
                deUint8* const topElemPtr = (deUint8*)basePtr + entry.offset + topElemNdx*topLevelStride;
 
@@ -824,12 +793,10 @@ void generateValues (const BufferLayout& layout, const vector<BlockDataPtr>& blo
 
                for (int entryNdx = 0; entryNdx < numEntries; entryNdx++)
                {
-                       const int                                       varNdx                          = blockLayout.activeVarIndices[entryNdx];
-                       const BufferVarLayoutEntry&     varEntry                        = layout.bufferVars[varNdx];
-                       const bool                                      unsizedArray            = (entryNdx+1 == numEntries) && isUnsizedTopLevelArray(varEntry);
-                       const int                                       topLevelArraySize       = unsizedArray ? blockPtr.lastUnsizedArraySize : getTopLevelArraySize(varEntry);
+                       const int                                       varNdx          = blockLayout.activeVarIndices[entryNdx];
+                       const BufferVarLayoutEntry&     varEntry        = layout.bufferVars[varNdx];
 
-                       generateValue(varEntry, topLevelArraySize, blockPtr.ptr, rnd);
+                       generateValue(varEntry, blockPtr.lastUnsizedArraySize, blockPtr.ptr, rnd);
                }
        }
 }
@@ -1143,10 +1110,10 @@ string getShaderName (const BufferBlock& block, int instanceNdx, const BufferVar
 
 int computeOffset (const BufferVarLayoutEntry& varLayout, const glu::TypeComponentVector& accessPath)
 {
-       const int       topLevelNdx             = (!accessPath.empty() && accessPath.front().type == glu::VarTypeComponent::ARRAY_ELEMENT) ? accessPath.front().index : 0;
-       const int       bottomLevelNdx  = (accessPath.size() > 1 && accessPath.back().type == glu::VarTypeComponent::ARRAY_ELEMENT) ? accessPath.back().index : 0;
+       const int       topLevelNdx             = (accessPath.size() > 1 && accessPath.front().type == glu::VarTypeComponent::ARRAY_ELEMENT) ? accessPath.front().index : 0;
+       const int       bottomLevelNdx  = (!accessPath.empty() && accessPath.back().type == glu::VarTypeComponent::ARRAY_ELEMENT) ? accessPath.back().index : 0;
 
-       return varLayout.offset + getTopLevelArrayStride(varLayout)*topLevelNdx + getArrayStride(varLayout)*bottomLevelNdx;
+       return varLayout.offset + varLayout.topLevelArrayStride*topLevelNdx + varLayout.arrayStride*bottomLevelNdx;
 }
 
 void generateCompareSrc (
@@ -1512,14 +1479,14 @@ void copyBufferVarData (const BufferVarLayoutEntry& dstEntry, const BlockDataPtr
        const int                               scalarSize                      = glu::getDataTypeScalarSize(dstEntry.type);
        const bool                              isMatrix                        = glu::isDataTypeMatrix(dstEntry.type);
        const int                               compSize                        = sizeof(deUint32);
-       const int                               dstArraySize            = getArraySize(dstEntry);
-       const int                               dstArrayStride          = getArrayStride(dstEntry);
-       const int                               dstTopLevelSize         = isUnsizedTopLevelArray(dstEntry) ? dstBlockPtr.lastUnsizedArraySize : getTopLevelArraySize(dstEntry);
-       const int                               dstTopLevelStride       = getTopLevelArrayStride(dstEntry);
-       const int                               srcArraySize            = getArraySize(srcEntry);
-       const int                               srcArrayStride          = getArrayStride(srcEntry);
-       const int                               srcTopLevelSize         = isUnsizedTopLevelArray(srcEntry) ? srcBlockPtr.lastUnsizedArraySize : getTopLevelArraySize(srcEntry);
-       const int                               srcTopLevelStride       = getTopLevelArrayStride(srcEntry);
+       const int                               dstArraySize            = dstEntry.arraySize == 0 ? dstBlockPtr.lastUnsizedArraySize : dstEntry.arraySize;
+       const int                               dstArrayStride          = dstEntry.arrayStride;
+       const int                               dstTopLevelSize         = dstEntry.topLevelArraySize == 0 ? dstBlockPtr.lastUnsizedArraySize : dstEntry.topLevelArraySize;
+       const int                               dstTopLevelStride       = dstEntry.topLevelArrayStride;
+       const int                               srcArraySize            = srcEntry.arraySize == 0 ? srcBlockPtr.lastUnsizedArraySize : srcEntry.arraySize;
+       const int                               srcArrayStride          = srcEntry.arrayStride;
+       const int                               srcTopLevelSize         = srcEntry.topLevelArraySize == 0 ? srcBlockPtr.lastUnsizedArraySize : srcEntry.topLevelArraySize;
+       const int                               srcTopLevelStride       = srcEntry.topLevelArrayStride;
 
        DE_ASSERT(dstArraySize <= srcArraySize && dstTopLevelSize <= srcTopLevelSize);
        DE_UNREF(srcArraySize && srcTopLevelSize);
@@ -1722,14 +1689,14 @@ bool compareBufferVarData (tcu::TestLog& log, const BufferVarLayoutEntry& refEnt
        const int                               maxPrints                       = 3;
        int                                             numFailed                       = 0;
 
-       const int                               resArraySize            = getArraySize(resEntry);
-       const int                               resArrayStride          = getArrayStride(resEntry);
-       const int                               resTopLevelSize         = isUnsizedTopLevelArray(resEntry) ? resBlockPtr.lastUnsizedArraySize : getTopLevelArraySize(resEntry);
-       const int                               resTopLevelStride       = getTopLevelArrayStride(resEntry);
-       const int                               refArraySize            = getArraySize(refEntry);
-       const int                               refArrayStride          = getArrayStride(refEntry);
-       const int                               refTopLevelSize         = isUnsizedTopLevelArray(refEntry) ? refBlockPtr.lastUnsizedArraySize : getTopLevelArraySize(refEntry);
-       const int                               refTopLevelStride       = getTopLevelArrayStride(refEntry);
+       const int                               resArraySize            = resEntry.arraySize == 0 ? resBlockPtr.lastUnsizedArraySize : resEntry.arraySize;
+       const int                               resArrayStride          = resEntry.arrayStride;
+       const int                               resTopLevelSize         = resEntry.topLevelArraySize == 0 ? resBlockPtr.lastUnsizedArraySize : resEntry.topLevelArraySize;
+       const int                               resTopLevelStride       = resEntry.topLevelArrayStride;
+       const int                               refArraySize            = refEntry.arraySize == 0 ? refBlockPtr.lastUnsizedArraySize : refEntry.arraySize;
+       const int                               refArrayStride          = refEntry.arrayStride;
+       const int                               refTopLevelSize         = refEntry.topLevelArraySize == 0 ? refBlockPtr.lastUnsizedArraySize : refEntry.topLevelArraySize;
+       const int                               refTopLevelStride       = refEntry.topLevelArrayStride;
 
        DE_ASSERT(resArraySize <= refArraySize && resTopLevelSize <= refTopLevelSize);
        DE_UNREF(refArraySize && refTopLevelSize);
@@ -1852,6 +1819,37 @@ string getBlockAPIName (const BufferBlock& block, int instanceNdx)
        return block.getBlockName() + (block.isArray() ? ("[" + de::toString(instanceNdx) + "]") : string());
 }
 
+// \note Some implementations don't report block members in the order they are declared.
+//              For checking whether size has to be adjusted by some top-level array actual size,
+//              we only need to know a) whether there is a unsized top-level array, and b)
+//              what is stride of that array.
+
+static bool hasUnsizedArray (const BufferLayout& layout, const BlockLayoutEntry& entry)
+{
+       for (vector<int>::const_iterator varNdx = entry.activeVarIndices.begin(); varNdx != entry.activeVarIndices.end(); ++varNdx)
+       {
+               if (isUnsizedArray(layout.bufferVars[*varNdx]))
+                       return true;
+       }
+
+       return false;
+}
+
+static int getUnsizedArrayStride (const BufferLayout& layout, const BlockLayoutEntry& entry)
+{
+       for (vector<int>::const_iterator varNdx = entry.activeVarIndices.begin(); varNdx != entry.activeVarIndices.end(); ++varNdx)
+       {
+               const BufferVarLayoutEntry& varEntry = layout.bufferVars[*varNdx];
+
+               if (varEntry.arraySize == 0)
+                       return varEntry.arrayStride;
+               else if (varEntry.topLevelArraySize == 0)
+                       return varEntry.topLevelArrayStride;
+       }
+
+       return 0;
+}
+
 vector<int> computeBufferSizes (const ShaderInterface& interface, const BufferLayout& layout)
 {
        vector<int> sizes(layout.blocks.size());
@@ -1871,11 +1869,9 @@ vector<int> computeBufferSizes (const ShaderInterface& interface, const BufferLa
                        {
                                const BlockLayoutEntry&         blockLayout             = layout.blocks[blockNdx];
                                const int                                       baseSize                = blockLayout.size;
-                               const int                                       lastVarNdx              = !layout.bufferVars.empty() ? blockLayout.activeVarIndices.back() : -1;
-                               const BufferVarLayoutEntry*     lastEntry               = lastVarNdx >= 0 ? &layout.bufferVars[lastVarNdx] : DE_NULL;
-                               const bool                                      isLastUnsized   = lastEntry && isUnsizedTopLevelArray(*lastEntry);
+                               const bool                                      isLastUnsized   = hasUnsizedArray(layout, blockLayout);
                                const int                                       lastArraySize   = isLastUnsized ? block.getLastUnsizedArraySize(instanceNdx) : 0;
-                               const int                                       stride                  = isLastUnsized ? getTopLevelArrayStride(*lastEntry) : 0;
+                               const int                                       stride                  = isLastUnsized ? getUnsizedArrayStride(layout, blockLayout) : 0;
 
                                sizes[blockNdx] = baseSize + lastArraySize*stride;
                        }
@@ -1887,14 +1883,12 @@ vector<int> computeBufferSizes (const ShaderInterface& interface, const BufferLa
 
 BlockDataPtr getBlockDataPtr (const BufferLayout& layout, const BlockLayoutEntry& blockLayout, void* ptr, int bufferSize)
 {
-       const int                                                       lastVarNdx              = !blockLayout.activeVarIndices.empty() ? blockLayout.activeVarIndices.back() : -1;
-       const BufferVarLayoutEntry* const       lastEntry               = lastVarNdx >= 0 ? &layout.bufferVars[lastVarNdx] : DE_NULL;
-       const bool                                                      isLastUnsized   = lastEntry && isUnsizedTopLevelArray(*lastEntry);
-       const int                                                       baseSize                = blockLayout.size;
+       const bool      isLastUnsized   = hasUnsizedArray(layout, blockLayout);
+       const int       baseSize                = blockLayout.size;
 
        if (isLastUnsized)
        {
-               const int               lastArrayStride = getTopLevelArrayStride(*lastEntry);
+               const int               lastArrayStride = getUnsizedArrayStride(layout, blockLayout);
                const int               lastArraySize   = (bufferSize-baseSize) / (lastArrayStride ? lastArrayStride : 1);
 
                DE_ASSERT(baseSize + lastArraySize*lastArrayStride == bufferSize);
@@ -2247,7 +2241,9 @@ SSBOLayoutCase::IterateResult SSBOLayoutCase::iterate (void)
                                if (layoutNdx >= 0)
                                {
                                        const BlockLocation& blockLoc = blockLocations[layoutNdx];
-                                       gl.bindBufferRange(GL_SHADER_STORAGE_BUFFER, bindingPoint, buffers[blockLoc.index].buffer, blockLoc.offset, blockLoc.size);
+
+                                       if (blockLoc.size > 0)
+                                               gl.bindBufferRange(GL_SHADER_STORAGE_BUFFER, bindingPoint, buffers[blockLoc.index].buffer, blockLoc.offset, blockLoc.size);
                                }
 
                                bindingPoint += 1;
@@ -2540,17 +2536,17 @@ bool SSBOLayoutCase::checkLayoutBounds (const BufferLayout& layout) const
        {
                const BufferVarLayoutEntry& var = layout.bufferVars[varNdx];
 
-               if (var.blockNdx < 0 || isUnsizedTopLevelArray(var))
+               if (var.blockNdx < 0 || isUnsizedArray(var))
                        continue;
 
                const BlockLayoutEntry&         block                   = layout.blocks[var.blockNdx];
                const bool                                      isMatrix                = glu::isDataTypeMatrix(var.type);
                const int                                       numVecs                 = isMatrix ? (var.isRowMajor ? glu::getDataTypeMatrixNumRows(var.type) : glu::getDataTypeMatrixNumColumns(var.type)) : 1;
                const int                                       numComps                = isMatrix ? (var.isRowMajor ? glu::getDataTypeMatrixNumColumns(var.type) : glu::getDataTypeMatrixNumRows(var.type)) : glu::getDataTypeScalarSize(var.type);
-               const int                                       numElements             = getArraySize(var);
-               const int                                       topLevelSize    = getTopLevelArraySize(var);
-               const int                                       arrayStride             = getArrayStride(var);
-               const int                                       topLevelStride  = getTopLevelArrayStride(var);
+               const int                                       numElements             = var.arraySize;
+               const int                                       topLevelSize    = var.topLevelArraySize;
+               const int                                       arrayStride             = var.arrayStride;
+               const int                                       topLevelStride  = var.topLevelArrayStride;
                const int                                       compSize                = sizeof(deUint32);
                const int                                       vecSize                 = numComps*compSize;
 
index 4699047..3172a5e 100644 (file)
@@ -389,7 +389,7 @@ std::string MaxSamplesCase::genFragmentSource (int numTargetSamples) const
                        "void main (void)\n"
                        "{\n"
                        "       fragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
-                       "       if (gl_MaxSamples != u_maxSamples)\n"
+                       "       if (gl_MaxSamples == u_maxSamples)\n"
                        "               fragColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
                        "}\n";
 
@@ -503,7 +503,7 @@ std::string SampleIDCase::genFragmentSource (int numTargetSamples) const
                                        "void main (void)\n"
                                        "{\n"
                                        "       highp vec2 relPosition = (v_position.xy + vec2(1.0, 1.0)) / 2.0;\n"
-                                       "       highp ivec2 pixelPos = ivec2(floor(relPosition * " << RENDER_SIZE << ".0));\n"
+                                       "       highp ivec2 pixelPos = ivec2(floor(relPosition * " << (int)RENDER_SIZE << ".0));\n"
                                        "       highp int selectedID = abs(pixelPos.x + 17 * pixelPos.y) % " << numTargetSamples << ";\n"
                                        "\n"
                                        "       if (gl_SampleID == selectedID)\n"
@@ -951,8 +951,8 @@ std::string SamplePosCorrectnessCase::genVertexSource (int numTargetSamples) con
        std::ostringstream buf;
 
        buf <<  "#version 310 es\n"
-                       "in highp vec4 a_position;\n"
                <<      ((m_useSampleQualifier) ? ("#extension GL_OES_shader_multisample_interpolation : require\n") : (""))
+               <<      "in highp vec4 a_position;\n"
                <<      ((m_useSampleQualifier) ? ("sample ") : ("")) << "out highp vec4 v_position;\n"
                        "void main (void)\n"
                        "{\n"
@@ -979,7 +979,7 @@ std::string SamplePosCorrectnessCase::genFragmentSource (int numTargetSamples) c
                        "{\n"
                        "       const highp float maxDistance = 0.15625; // 4 subpixel bits. Assume 3 accurate bits + 0.03125 for other errors\n" // 0.03125 = mediump epsilon when value = 32 (RENDER_SIZE)
                        "\n"
-                       "       highp vec2 screenSpacePosition = (v_position.xy + vec2(1.0, 1.0)) / 2.0 * " << RENDER_SIZE << ".0;\n"
+                       "       highp vec2 screenSpacePosition = (v_position.xy + vec2(1.0, 1.0)) / 2.0 * " << (int)RENDER_SIZE << ".0;\n"
                        "       highp ivec2 nearbyPixel = ivec2(floor(screenSpacePosition));\n"
                        "       bool allOk = false;\n"
                        "\n"
index 83a3d4b..9de1a37 100644 (file)
@@ -676,6 +676,10 @@ bool paramsValid (const TestParams& params)
                // CreateShaderProgram would never get called
                if (!params.switchVtx && !params.switchFrg && params.useCreateHelper)
                        return false;
+
+               // Must switch either all or nothing
+               if (params.switchVtx != params.switchFrg)
+                       return false;
        }
 
        // ProgramUniform would never get called
@@ -756,6 +760,7 @@ TestParams genParams (deUint32 seed)
 {
        Random          rnd             (seed);
        TestParams      params;
+       int                     tryNdx  = 0;
 
        do
        {
@@ -784,7 +789,11 @@ TestParams genParams (deUint32 seed)
                        params.varyings.vtxInterp       = glu::INTERPOLATION_LAST;
                        params.varyings.frgInterp       = glu::INTERPOLATION_LAST;
                }
-       } while (!paramsValid(params));
+
+               tryNdx += 1;
+       } while (!paramsValid(params) && tryNdx < 16);
+
+       DE_ASSERT(paramsValid(params));
 
        return params;
 }
@@ -963,6 +972,7 @@ SeparateShaderTest::SeparateShaderTest (Context&                    ctx,
        , m_status                      (log(), "// ")
        , m_varyings            (genVaryingInterface(params.varyings, m_rnd))
 {
+       DE_ASSERT(paramsValid(params));
 }
 
 MovePtr<ProgramWrapper> SeparateShaderTest::createShaderProgram (const string* vtxSource,
@@ -1419,6 +1429,16 @@ enum ParamFlags
        PARAMFLAGS_MASK                         = PARAMFLAGS_LAST - 1
 };
 
+bool areCaseParamFlagsValid (ParamFlags flags)
+{
+       const ParamFlags switchAll = ParamFlags(PARAMFLAGS_SWITCH_VERTEX|PARAMFLAGS_SWITCH_FRAGMENT);
+
+       if ((flags & PARAMFLAGS_INIT_SINGLE) != 0)
+               return (flags & switchAll) == 0 ||
+                          (flags & switchAll) == switchAll;
+       else
+               return true;
+}
 
 bool addRenderTest (TestCaseGroup& group, const string& namePrefix, const string& descPrefix,
                                        int numIterations, ParamFlags flags, TestParams params)
@@ -1426,6 +1446,8 @@ bool addRenderTest (TestCaseGroup& group, const string& namePrefix, const string
        ostringstream   name;
        ostringstream   desc;
 
+       DE_ASSERT(areCaseParamFlagsValid(flags));
+
        name << namePrefix;
        desc << descPrefix;
 
@@ -1516,6 +1538,9 @@ TestCaseGroup* createSeparateShaderTests (Context& ctx)
                ostringstream   name;
                ostringstream   desc;
 
+               if (!areCaseParamFlagsValid(ParamFlags(flags & PARAMFLAGS_MASK)))
+                       continue;
+
                if (flags & (PARAMFLAGS_LAST << 1))
                {
                        params.useSameName = true;
@@ -1552,6 +1577,9 @@ TestCaseGroup* createSeparateShaderTests (Context& ctx)
        {
                TestParams              params                  = defaultParams;
 
+               if (!areCaseParamFlagsValid(ParamFlags(flags)))
+                       continue;
+
                params.useUniform = true;
                params.useProgramUniform = true;
 
@@ -1566,6 +1594,9 @@ TestCaseGroup* createSeparateShaderTests (Context& ctx)
        {
                TestParams              params                  = defaultParams;
 
+               if (!areCaseParamFlagsValid(ParamFlags(flags)))
+                       continue;
+
                params.useCreateHelper = true;
 
                addRenderTest(*createShaderProgramGroup, "", "", numIterations,
index 0cdd461..2758566 100644 (file)
@@ -150,9 +150,9 @@ void ShaderAtomicOpCase::init (void)
        {
                src << "        if (gl_LocalInvocationIndex == 0u)\n"
                        << "            s_var = " << typeName << "(" << tcu::toHex(m_initialValue) << "u);\n"
-                       << "    memoryBarrierShared();\n"
+                       << "    barrier();\n"
                        << "    sb_inout.outputValues[offset] = " << m_funcName << "(s_var, sb_inout.inputValues[offset]);\n"
-                       << "    memoryBarrierShared();\n"
+                       << "    barrier();\n"
                        << "    if (gl_LocalInvocationIndex == 0u)\n"
                        << "            sb_inout.groupValues[globalNdx] = s_var;\n";
        }
@@ -846,26 +846,30 @@ void ShaderAtomicCompSwapCase::init (void)
        {
                src << "        if (gl_LocalInvocationIndex == 0u)\n"
                        << "            s_var = " << typeName << "(" << 0 << ");\n"
-                       << "    memoryBarrierShared();\n"
                        << "\n";
        }
 
        src << "        " << precName << " " << typeName << " compare = sb_inout.compareValues[offset];\n"
                << "    " << precName << " " << typeName << " exchange = sb_inout.exchangeValues[offset];\n"
                << "    " << precName << " " << typeName << " result;\n"
+               << "    bool swapDone = false;\n"
                << "\n"
                << "    for (uint ndx = 0u; ndx < localSize; ndx++)\n"
                << "    {\n"
-               << "            result = atomicCompSwap(" << (isSSBO ? "sb_inout.groupValues[globalNdx]" : "s_var") << ", compare, exchange);\n"
-               << "            if (result == compare)\n"
-               << "                    break;\n"
+               << "            barrier();\n"
+               << "            if (!swapDone)\n"
+               << "            {\n"
+               << "                    result = atomicCompSwap(" << (isSSBO ? "sb_inout.groupValues[globalNdx]" : "s_var") << ", compare, exchange);\n"
+               << "                    if (result == compare)\n"
+               << "                            swapDone = true;\n"
+               << "            }\n"
                << "    }\n"
                << "\n"
                << "    sb_inout.outputValues[offset] = result;\n";
 
        if (!isSSBO)
        {
-               src << "        memoryBarrierShared();\n"
+               src << "        barrier();\n"
                        << "    if (gl_LocalInvocationIndex == 0u)\n"
                        << "            sb_inout.groupValues[globalNdx] = s_var;\n";
        }
index e444dfa..f939bd6 100644 (file)
@@ -838,26 +838,28 @@ public:
                        for (int compNdx = 0; compNdx < scalarSize; compNdx++)
                        {
                                const float             in0             = ((const float*)inputs[0])[compNdx];
-                               const deUint32  out0    = ((const deUint32*)outputs[0])[compNdx];
-                               const deUint32  ref             = tcu::Float32(in0).isNaN() ? 1u : 0u;
+                               const bool              out0    = ((const deUint32*)outputs[0])[compNdx] != 0;
+                               const bool              ref             = tcu::Float32(in0).isNaN();
 
                                if (out0 != ref)
                                {
-                                       m_failMsg << "Expected [" << compNdx << "] = " << HexBool(ref);
+                                       m_failMsg << "Expected [" << compNdx << "] = " << (ref ? "true" : "false");
                                        return false;
                                }
                        }
                }
-               else
+               else if (precision == glu::PRECISION_MEDIUMP || precision == glu::PRECISION_LOWP)
                {
-                       // Value can be either 0 or 1
+                       // NaN support is optional, check that inputs that are not NaN don't result in true.
                        for (int compNdx = 0; compNdx < scalarSize; compNdx++)
                        {
-                               const int out0 = ((const int*)outputs[0])[compNdx];
+                               const float             in0             = ((const float*)inputs[0])[compNdx];
+                               const bool              out0    = ((const deUint32*)outputs[0])[compNdx] != 0;
+                               const bool              ref             = tcu::Float32(in0).isNaN();
 
-                               if (out0 != 0 && out0 != 1)
+                               if (!ref && out0)
                                {
-                                       m_failMsg << "Expected [" << compNdx << "] = 0 / 1";
+                                       m_failMsg << "Expected [" << compNdx << "] = " << (ref ? "true" : "false");
                                        return false;
                                }
                        }
@@ -919,8 +921,8 @@ public:
                        for (int compNdx = 0; compNdx < scalarSize; compNdx++)
                        {
                                const float             in0             = ((const float*)inputs[0])[compNdx];
-                               const deUint32  out0    = ((const deUint32*)outputs[0])[compNdx];
-                               const deUint32  ref             = tcu::Float32(in0).isInf() ? 1u : 0u;
+                               const bool              out0    = ((const deUint32*)outputs[0])[compNdx] != 0;
+                               const bool              ref             = tcu::Float32(in0).isInf();
 
                                if (out0 != ref)
                                {
@@ -929,20 +931,23 @@ public:
                                }
                        }
                }
-               else
+               else if (precision == glu::PRECISION_MEDIUMP)
                {
-                       // Value can be either 0 or 1
+                       // Inf support is optional, check that inputs that are not Inf in mediump don't result in true.
                        for (int compNdx = 0; compNdx < scalarSize; compNdx++)
                        {
-                               const int out0 = ((const int*)outputs[0])[compNdx];
+                               const float             in0             = ((const float*)inputs[0])[compNdx];
+                               const bool              out0    = ((const deUint32*)outputs[0])[compNdx] != 0;
+                               const bool              ref             = tcu::Float16(in0).isInf();
 
-                               if (out0 != 0 && out0 != 1)
+                               if (!ref && out0)
                                {
-                                       m_failMsg << "Expected [" << compNdx << "] = 0 / 1";
+                                       m_failMsg << "Expected [" << compNdx << "] = " << (ref ? "true" : "false");
                                        return false;
                                }
                        }
                }
+               // else: no verification can be performed
 
                return true;
        }
index 928f3dd..c0d1038 100644 (file)
@@ -203,7 +203,7 @@ FboHelper::FboHelper (const glu::RenderContext& renderCtx, int width, int height
        gl.bindFramebuffer(GL_FRAMEBUFFER, *m_framebuffer);
        gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, *m_colorbuffer);
 
-       if (m_numSamples > maxSamples && gl.checkFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_UNSUPPORTED)
+       if (m_numSamples > maxSamples && gl.checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
                throw tcu::NotSupportedError("Sample count exceeds GL_MAX_SAMPLES");
 
        TCU_CHECK(gl.checkFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
index 76ae9c1..ea23ab2 100644 (file)
@@ -110,6 +110,12 @@ static string arrayStr (const T (&arr)[Size])
        return result;
 }
 
+template <typename T, int N>
+static int arrayIndexOf (const T (&arr)[N], const T& e)
+{
+       return (int)(std::find(DE_ARRAY_BEGIN(arr), DE_ARRAY_END(arr), e) - DE_ARRAY_BEGIN(arr));
+}
+
 static const char* getTextureTypeName (TextureType type)
 {
        switch (type)
@@ -1421,7 +1427,7 @@ ImageLoadAndStoreCase::IterateResult ImageLoadAndStoreCase::iterate (void)
                                                                                                                "{\n"
                                                                                                                + (shaderImageType == TEXTURETYPE_BUFFER ?
                                                                                                                        "       int pos = int(gl_GlobalInvocationID.x);\n"
-                                                                                                                       "       imageStore(u_image1, pos, imageLoad(u_image0, " + toString(imageSize.x()-1) + "-pos.x));\n"
+                                                                                                                       "       imageStore(u_image1, pos, imageLoad(u_image0, " + toString(imageSize.x()-1) + "-pos));\n"
                                                                                                                 : shaderImageType == TEXTURETYPE_2D ?
                                                                                                                        "       ivec2 pos = ivec2(gl_GlobalInvocationID.xy);\n"
                                                                                                                        "       imageStore(u_image1, pos, imageLoad(u_image0, ivec2(" + toString(imageSize.x()-1) + "-pos.x, pos.y)));\n"
@@ -2247,47 +2253,48 @@ public:
                        // Due to the way the compare and assign arguments to the atomic calls are organized
                        // among the different invocations contributing to the same pixel -- i.e. one invocation
                        // compares to A and assigns B, another compares to B and assigns C, and so on, where
-                       // A<B<C etc -- the return value sequence must be (assuming 4 invocations operating
-                       // on one result image pixel, for example) A A A A, A B B B, A B C C or A B C D
-                       // depending on the execution order.
+                       // A<B<C etc -- the first value in the return value sequence must be A, and each following
+                       // value must be either the same as or the smallest value (among A, B, C, ...) bigger than
+                       // the one just before it. E.g. sequences A A A A A A A A, A B C D E F G H and
+                       // A A B B B C D E are all valid sequences (if there were 8 invocations contributing
+                       // to each pixel).
 
                        {
-                               bool success = true;
+                               int failingNdx = -1;
 
                                {
-                                       bool flatPartStarted = false;
-
-                                       for (int i = 0; i < NUM_INVOCATIONS_PER_PIXEL && success; i++)
+                                       int currentAtomicValueNdx = 0;
+                                       for (int i = 0; i < NUM_INVOCATIONS_PER_PIXEL; i++)
                                        {
-                                               if (returnValues[i] == compareArgs[i])
-                                                       success = !flatPartStarted;
-                                               else
+                                               if (returnValues[i] == compareArgs[currentAtomicValueNdx])
+                                                       continue;
+                                               if (i > 0 && returnValues[i] == compareArgs[currentAtomicValueNdx+1])
                                                {
-                                                       success = i > 0 && returnValues[i] == returnValues[i-1];
-                                                       flatPartStarted = true;
+                                                       currentAtomicValueNdx++;
+                                                       continue;
                                                }
+                                               failingNdx = i;
+                                               break;
                                        }
                                }
 
-                               if (!success)
+                               if (failingNdx >= 0)
                                {
                                        log << TestLog::Message << "// Failure: intermediate return values at pixels " << arrayStr(pixelCoords) << " of current layer are "
                                                                                        << arrayStr(returnValues) << TestLog::EndMessage
                                                << TestLog::Message << "// Note: relevant shader invocation global IDs are " << arrayStr(invocationGlobalIDs) << TestLog::EndMessage
-                                               << TestLog::Message << "// Note: 'compare' argument values for the IDs are " << arrayStr(compareArgs) << TestLog::EndMessage;
-
-                                       {
-                                               std::ostringstream validReturnValueSequences;
-                                               for (int flatPartStartNdx = 0; flatPartStartNdx < NUM_INVOCATIONS_PER_PIXEL; flatPartStartNdx++)
-                                               {
-                                                       int curSeq[NUM_INVOCATIONS_PER_PIXEL];
-                                                       for (int i = 0; i < NUM_INVOCATIONS_PER_PIXEL; i++)
-                                                               curSeq[i] = compareArgs[de::min(i, flatPartStartNdx)];
-                                                       validReturnValueSequences << "// " << arrayStr(curSeq) << "\n";
-                                               }
-
-                                               log << TestLog::Message << "// Note: expected one of the following return value sequences:\n" << validReturnValueSequences.str() << TestLog::EndMessage;
-                                       }
+                                               << TestLog::Message << "// Note: 'compare' argument values for the IDs are " << arrayStr(compareArgs) << TestLog::EndMessage
+                                               << TestLog::Message << "// Note: expected the return value sequence to fulfill the following conditions:\n"
+                                                                                       << "// - first value is " << compareArgs[0] << "\n"
+                                                                                       << "// - each value other than the first is either the same as the one just before it, or the smallest value (in the sequence "
+                                                                                       << arrayStr(compareArgs) << ") bigger than the one just before it" << TestLog::EndMessage;
+                                       if (failingNdx == 0)
+                                               log << TestLog::Message << "// Note: the first return value (" << returnValues[0] << ") isn't " << compareArgs[0] << TestLog::EndMessage;
+                                       else
+                                               log << TestLog::Message << "// Note: the return value at index " << failingNdx << " (value " << returnValues[failingNdx] << ") "
+                                                                                               << "is neither " << returnValues[failingNdx-1] << " (the one just before it) "
+                                                                                               << "nor " << compareArgs[arrayIndexOf(compareArgs, returnValues[failingNdx-1])+1] << " (the smallest value bigger than the one just before it)"
+                                                                                               << TestLog::EndMessage;
 
                                        return false;
                                }
index c72c482..fc064fb 100644 (file)
@@ -1024,6 +1024,32 @@ static int findMSB (deUint32 value)
                return -1;
 }
 
+static int toPrecision (deUint32 value, glu::Precision precision)
+{
+       switch (precision)
+       {
+               case glu::PRECISION_LOWP:               return value&0xffu;
+               case glu::PRECISION_MEDIUMP:    return value&0xffffu;
+               case glu::PRECISION_HIGHP:              return value;
+               default:
+                       DE_ASSERT(false);
+                       return 0;
+       }
+}
+
+static int toPrecision (int value, glu::Precision precision)
+{
+       switch (precision)
+       {
+               case glu::PRECISION_LOWP:               return (deInt8)value;
+               case glu::PRECISION_MEDIUMP:    return (deInt16)value;
+               case glu::PRECISION_HIGHP:              return value;
+               default:
+                       DE_ASSERT(false);
+                       return 0;
+       }
+}
+
 class FindMSBCase : public IntegerFunctionCase
 {
 public:
@@ -1057,19 +1083,17 @@ public:
 
        bool compare (const void* const* inputs, const void* const* outputs)
        {
-               const deUint32                  masks[]                 = { 0xffu, 0xffffu, 0xffffffffu };
                const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
                const glu::Precision    precision               = m_spec.inputs[0].varType.getPrecision();
                const bool                              isSigned                = glu::isDataTypeIntOrIVec(type);
                const int                               scalarSize              = glu::getDataTypeScalarSize(type);
-               const deUint32                  mask                    = masks[precision];
 
                for (int compNdx = 0; compNdx < scalarSize; compNdx++)
                {
                        const deUint32  value   = ((const deUint32*)inputs[0])[compNdx];
                        const int               out             = ((const int*)outputs[0])[compNdx];
-                       const int               minRef  = isSigned ? findMSB(int(value&mask))   : findMSB(value&mask);
-                       const int               maxRef  = isSigned ? findMSB(int(value))                : findMSB(value);
+                       const int               minRef  = isSigned ? findMSB(toPrecision(int(value), precision))        : findMSB(toPrecision(value, precision));
+                       const int               maxRef  = isSigned ? findMSB(int(value))                                                        : findMSB(value);
 
                        if (!de::inRange(out, minRef, maxRef))
                        {
index 7b8d53a..2612887 100644 (file)
@@ -679,7 +679,7 @@ std::string SingleSampleInterpolateAtSampleCase::genVertexSource (int numTargetS
                        "void main (void)\n"
                        "{\n"
                        "       gl_Position = a_position;\n"
-                       "       v_position = (a_position.xy + vec2(1.0, 1.0)) / 2.0 * vec2(" << RENDER_SIZE << ".0, " << RENDER_SIZE << ".0);\n"
+                       "       v_position = (a_position.xy + vec2(1.0, 1.0)) / 2.0 * vec2(" << (int)RENDER_SIZE << ".0, " << (int)RENDER_SIZE << ".0);\n"
                        "}\n";
 
        return buf.str();
@@ -966,7 +966,7 @@ std::string InterpolateAtSampleIDCase::genVertexSource (int numTargetSamples) co
                        "void main (void)\n"
                        "{\n"
                        "       gl_Position = a_position;\n"
-                       "       v_screenPosition = (a_position.xy + vec2(1.0, 1.0)) / 2.0 * vec2(" << RENDER_SIZE << ".0, " << RENDER_SIZE << ".0);\n"
+                       "       v_screenPosition = (a_position.xy + vec2(1.0, 1.0)) / 2.0 * vec2(" << (int)RENDER_SIZE << ".0, " << (int)RENDER_SIZE << ".0);\n"
                        "}\n";
 
        return buf.str();
@@ -977,6 +977,7 @@ std::string InterpolateAtSampleIDCase::genFragmentSource (int numTargetSamples)
        DE_UNREF(numTargetSamples);
 
        return  "#version 310 es\n"
+                       "#extension GL_OES_sample_variables : require\n"
                        "#extension GL_OES_shader_multisample_interpolation : require\n"
                        "sample in highp vec2 v_screenPosition;\n"
                        "layout(location = 0) out mediump vec4 fragColor;\n"
@@ -1241,10 +1242,10 @@ std::string InterpolateAtOffsetCase::genVertexSource (int numTargetSamples) cons
                << "    gl_Position = a_position;\n";
 
        if (m_testType != TEST_ARRAY_ELEMENT)
-               buf     << "    v_screenPosition = (a_position.xy + vec2(1.0, 1.0)) / 2.0 * vec2(" << RENDER_SIZE << ".0, " << RENDER_SIZE << ".0);\n";
+               buf     << "    v_screenPosition = (a_position.xy + vec2(1.0, 1.0)) / 2.0 * vec2(" << (int)RENDER_SIZE << ".0, " << (int)RENDER_SIZE << ".0);\n";
        else
                buf     << "    v_screenPosition[0] = a_position.xy; // not used\n"
-                               "       v_screenPosition[1] = (a_position.xy + vec2(1.0, 1.0)) / 2.0 * vec2(" << RENDER_SIZE << ".0, " << RENDER_SIZE << ".0);\n";
+                               "       v_screenPosition[1] = (a_position.xy + vec2(1.0, 1.0)) / 2.0 * vec2(" << (int)RENDER_SIZE << ".0, " << (int)RENDER_SIZE << ".0);\n";
 
        buf     << "    v_offset = a_position.xy * 0.5f;\n"
                << "}\n";
@@ -1359,7 +1360,7 @@ std::string InterpolateAtSamplePositionCase::genVertexSource (int numTargetSampl
                        "void main (void)\n"
                        "{\n"
                        "       gl_Position = a_position;\n"
-                       "       v_screenPosition = (a_position.xy + vec2(1.0, 1.0)) / 2.0 * vec2(" << RENDER_SIZE << ".0, " << RENDER_SIZE << ".0);\n"
+                       "       v_screenPosition = (a_position.xy + vec2(1.0, 1.0)) / 2.0 * vec2(" << (int)RENDER_SIZE << ".0, " << (int)RENDER_SIZE << ".0);\n"
                        "}\n";
 
        return buf.str();
@@ -1370,6 +1371,7 @@ std::string InterpolateAtSamplePositionCase::genFragmentSource (int numTargetSam
        DE_UNREF(numTargetSamples);
 
        return  "#version 310 es\n"
+                       "#extension GL_OES_sample_variables : require\n"
                        "#extension GL_OES_shader_multisample_interpolation : require\n"
                        "sample in highp vec2 v_screenPosition;\n"
                        "layout(location = 0) out mediump vec4 fragColor;\n"
index dc134d4..9409107 100644 (file)
@@ -55,7 +55,7 @@ using namespace glu;
 
 enum
 {
-       MAX_VALUE_ARRAY_LENGTH  = 16    // * 2 * sizeof(mat4) = 512
+       MAX_VALUE_ARRAY_LENGTH  = 15    // * 2 * sizeof(mat4) + sizeof(int) = 481 uniform components (limit 512)
 };
 
 template<typename T, int Size>
@@ -141,7 +141,7 @@ void SharedBasicVarCase::init (void)
                << "            if (ndx == gl_LocalInvocationIndex)\n"
                << "                    s_var = u_val[ndx%uint(u_val.length())];\n"
                << "\n"
-               << "            memoryBarrierShared();\n"
+               << "            barrier();\n"
                << "\n"
                << "            if (s_var != u_ref[ndx%uint(u_ref.length())])\n"
                << "                    allOk = false;\n"
@@ -391,25 +391,25 @@ void ShaderSharedVarTests::init (void)
                workGroupSizeGroup->addChild(new SharedBasicVarCase(m_context, "float_64_1_1",          TYPE_FLOAT,                     PRECISION_HIGHP,        tcu::UVec3(64,1,1)));
                workGroupSizeGroup->addChild(new SharedBasicVarCase(m_context, "float_1_64_1",          TYPE_FLOAT,                     PRECISION_HIGHP,        tcu::UVec3(1,64,1)));
                workGroupSizeGroup->addChild(new SharedBasicVarCase(m_context, "float_1_1_64",          TYPE_FLOAT,                     PRECISION_HIGHP,        tcu::UVec3(1,1,64)));
-               workGroupSizeGroup->addChild(new SharedBasicVarCase(m_context, "float_256_1_1",         TYPE_FLOAT,                     PRECISION_HIGHP,        tcu::UVec3(256,1,1)));
-               workGroupSizeGroup->addChild(new SharedBasicVarCase(m_context, "float_1_256_1",         TYPE_FLOAT,                     PRECISION_HIGHP,        tcu::UVec3(1,256,1)));
-               workGroupSizeGroup->addChild(new SharedBasicVarCase(m_context, "float_17_5_9",          TYPE_FLOAT,                     PRECISION_HIGHP,        tcu::UVec3(17,5,9)));
+               workGroupSizeGroup->addChild(new SharedBasicVarCase(m_context, "float_128_1_1",         TYPE_FLOAT,                     PRECISION_HIGHP,        tcu::UVec3(128,1,1)));
+               workGroupSizeGroup->addChild(new SharedBasicVarCase(m_context, "float_1_128_1",         TYPE_FLOAT,                     PRECISION_HIGHP,        tcu::UVec3(1,128,1)));
+               workGroupSizeGroup->addChild(new SharedBasicVarCase(m_context, "float_13_2_4",          TYPE_FLOAT,                     PRECISION_HIGHP,        tcu::UVec3(13,2,4)));
 
                workGroupSizeGroup->addChild(new SharedBasicVarCase(m_context, "vec4_1_1_1",            TYPE_FLOAT_VEC4,        PRECISION_HIGHP,        tcu::UVec3(1,1,1)));
                workGroupSizeGroup->addChild(new SharedBasicVarCase(m_context, "vec4_64_1_1",           TYPE_FLOAT_VEC4,        PRECISION_HIGHP,        tcu::UVec3(64,1,1)));
                workGroupSizeGroup->addChild(new SharedBasicVarCase(m_context, "vec4_1_64_1",           TYPE_FLOAT_VEC4,        PRECISION_HIGHP,        tcu::UVec3(1,64,1)));
                workGroupSizeGroup->addChild(new SharedBasicVarCase(m_context, "vec4_1_1_64",           TYPE_FLOAT_VEC4,        PRECISION_HIGHP,        tcu::UVec3(1,1,64)));
-               workGroupSizeGroup->addChild(new SharedBasicVarCase(m_context, "vec4_256_1_1",          TYPE_FLOAT_VEC4,        PRECISION_HIGHP,        tcu::UVec3(256,1,1)));
-               workGroupSizeGroup->addChild(new SharedBasicVarCase(m_context, "vec4_1_256_1",          TYPE_FLOAT_VEC4,        PRECISION_HIGHP,        tcu::UVec3(1,256,1)));
-               workGroupSizeGroup->addChild(new SharedBasicVarCase(m_context, "vec4_17_5_9",           TYPE_FLOAT_VEC4,        PRECISION_HIGHP,        tcu::UVec3(17,5,9)));
+               workGroupSizeGroup->addChild(new SharedBasicVarCase(m_context, "vec4_128_1_1",          TYPE_FLOAT_VEC4,        PRECISION_HIGHP,        tcu::UVec3(128,1,1)));
+               workGroupSizeGroup->addChild(new SharedBasicVarCase(m_context, "vec4_1_128_1",          TYPE_FLOAT_VEC4,        PRECISION_HIGHP,        tcu::UVec3(1,128,1)));
+               workGroupSizeGroup->addChild(new SharedBasicVarCase(m_context, "vec4_13_2_4",           TYPE_FLOAT_VEC4,        PRECISION_HIGHP,        tcu::UVec3(13,2,4)));
 
                workGroupSizeGroup->addChild(new SharedBasicVarCase(m_context, "mat4_1_1_1",            TYPE_FLOAT_MAT4,        PRECISION_HIGHP,        tcu::UVec3(1,1,1)));
                workGroupSizeGroup->addChild(new SharedBasicVarCase(m_context, "mat4_64_1_1",           TYPE_FLOAT_MAT4,        PRECISION_HIGHP,        tcu::UVec3(64,1,1)));
                workGroupSizeGroup->addChild(new SharedBasicVarCase(m_context, "mat4_1_64_1",           TYPE_FLOAT_MAT4,        PRECISION_HIGHP,        tcu::UVec3(1,64,1)));
                workGroupSizeGroup->addChild(new SharedBasicVarCase(m_context, "mat4_1_1_64",           TYPE_FLOAT_MAT4,        PRECISION_HIGHP,        tcu::UVec3(1,1,64)));
-               workGroupSizeGroup->addChild(new SharedBasicVarCase(m_context, "mat4_256_1_1",          TYPE_FLOAT_MAT4,        PRECISION_HIGHP,        tcu::UVec3(256,1,1)));
-               workGroupSizeGroup->addChild(new SharedBasicVarCase(m_context, "mat4_1_256_1",          TYPE_FLOAT_MAT4,        PRECISION_HIGHP,        tcu::UVec3(1,256,1)));
-               workGroupSizeGroup->addChild(new SharedBasicVarCase(m_context, "mat4_17_5_9",           TYPE_FLOAT_MAT4,        PRECISION_HIGHP,        tcu::UVec3(17,5,9)));
+               workGroupSizeGroup->addChild(new SharedBasicVarCase(m_context, "mat4_128_1_1",          TYPE_FLOAT_MAT4,        PRECISION_HIGHP,        tcu::UVec3(128,1,1)));
+               workGroupSizeGroup->addChild(new SharedBasicVarCase(m_context, "mat4_1_128_1",          TYPE_FLOAT_MAT4,        PRECISION_HIGHP,        tcu::UVec3(1,128,1)));
+               workGroupSizeGroup->addChild(new SharedBasicVarCase(m_context, "mat4_13_2_4",           TYPE_FLOAT_MAT4,        PRECISION_HIGHP,        tcu::UVec3(13,2,4)));
        }
 
        // .atomic
index 36a7b98..effdf78 100644 (file)
@@ -26,6 +26,7 @@
 #include "tcuStringTemplate.hpp"
 #include "gluShaderProgram.hpp"
 #include "gluRenderContext.hpp"
+#include "gluContextInfo.hpp"
 #include "glwFunctions.hpp"
 #include "glwEnums.hpp"
 
@@ -56,82 +57,92 @@ SamplerTypeCase::IterateResult SamplerTypeCase::iterate (void)
 {
        static const struct SamplerType
        {
-               glw::GLenum glType;
-               const char* typeStr;
-               const char* samplePosStr;
+               glw::GLenum     glType;
+               const char*     typeStr;
+               const char*     samplePosStr;
+               bool            isArray;
        } samplerTypes[] =
        {
-               { GL_SAMPLER_2D_MULTISAMPLE,                                            "sampler2DMS",                  "ivec2(gl_FragCoord.xy)"        },
-               { GL_INT_SAMPLER_2D_MULTISAMPLE,                                        "isampler2DMS",                 "ivec2(gl_FragCoord.xy)"        },
-               { GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE,                       "usampler2DMS",                 "ivec2(gl_FragCoord.xy)"        },
-               { GL_SAMPLER_2D_MULTISAMPLE_ARRAY,                                      "sampler2DMSArray",             "ivec3(gl_FragCoord.xyz)"       },
-               { GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY,                          "isampler2DMSArray",    "ivec3(gl_FragCoord.xyz)"       },
-               { GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY,         "usampler2DMSArray",    "ivec3(gl_FragCoord.xyz)"       },
+               { GL_SAMPLER_2D_MULTISAMPLE,                                            "sampler2DMS",                  "ivec2(gl_FragCoord.xy)",       false   },
+               { GL_INT_SAMPLER_2D_MULTISAMPLE,                                        "isampler2DMS",                 "ivec2(gl_FragCoord.xy)",       false   },
+               { GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE,                       "usampler2DMS",                 "ivec2(gl_FragCoord.xy)",       false   },
+               { GL_SAMPLER_2D_MULTISAMPLE_ARRAY,                                      "sampler2DMSArray",             "ivec3(gl_FragCoord.xyz)",      true    },
+               { GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY,                          "isampler2DMSArray",    "ivec3(gl_FragCoord.xyz)",      true    },
+               { GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY,         "usampler2DMSArray",    "ivec3(gl_FragCoord.xyz)",      true    },
        };
 
-       static const char* const vertexSource                   =       "#version 310 es\n"
-                                                                                                               "in highp vec4 a_position;\n"
-                                                                                                               "void main(void)\n"
-                                                                                                               "{\n"
-                                                                                                               "       gl_Position = a_position;\n"
-                                                                                                               "}\n";
-       static const char* const fragmentSourceTemplate =       "#version 310 es\n"
-                                                                                                               "uniform highp ${SAMPLERTYPE} u_sampler;\n"
-                                                                                                               "layout(location = 0) out highp vec4 dEQP_FragColor;\n"
-                                                                                                               "void main(void)\n"
-                                                                                                               "{\n"
-                                                                                                               "       dEQP_FragColor = vec4(texelFetch(u_sampler, ${POSITION}, 0));\n"
-                                                                                                               "}\n";
-
-       bool error = false;
+       static const char* const        vertexSource                    =       "#version 310 es\n"
+                                                                                                                       "in highp vec4 a_position;\n"
+                                                                                                                       "void main(void)\n"
+                                                                                                                       "{\n"
+                                                                                                                       "       gl_Position = a_position;\n"
+                                                                                                                       "}\n";
+       static const char* const        fragmentSourceTemplate  =       "#version 310 es\n"
+                                                                                                                       "${EXTENSIONSTATEMENT}"
+                                                                                                                       "uniform highp ${SAMPLERTYPE} u_sampler;\n"
+                                                                                                                       "layout(location = 0) out highp vec4 dEQP_FragColor;\n"
+                                                                                                                       "void main(void)\n"
+                                                                                                                       "{\n"
+                                                                                                                       "       dEQP_FragColor = vec4(texelFetch(u_sampler, ${POSITION}, 0));\n"
+                                                                                                                       "}\n";
+       const bool                                      textureArraySupported   =       m_context.getContextInfo().isExtensionSupported("GL_OES_texture_storage_multisample_2d_array");
+       bool                                            error                                   =       false;
 
        for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(samplerTypes); ++typeNdx)
        {
-               const tcu::ScopedLogSection                     section         (m_testCtx.getLog(), std::string(samplerTypes[typeNdx].typeStr), std::string() + "Sampler type " + samplerTypes[typeNdx].typeStr);
-               std::map<std::string, std::string>      shaderArgs;
-
-               shaderArgs["SAMPLERTYPE"]       = samplerTypes[typeNdx].typeStr;
-               shaderArgs["POSITION"]          = samplerTypes[typeNdx].samplePosStr;
+               const tcu::ScopedLogSection section(m_testCtx.getLog(), std::string(samplerTypes[typeNdx].typeStr), std::string() + "Sampler type " + samplerTypes[typeNdx].typeStr);
 
+               if (samplerTypes[typeNdx].isArray && !textureArraySupported)
                {
-                       const std::string                       fragmentSource  = tcu::StringTemplate(fragmentSourceTemplate).specialize(shaderArgs);
-                       const glw::Functions&           gl                              = m_context.getRenderContext().getFunctions();
-                       glu::ShaderProgram                      program                 (m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(vertexSource) << glu::FragmentSource(fragmentSource));
-
-                       m_testCtx.getLog() << tcu::TestLog::Message << "Building program with uniform sampler of type " << samplerTypes[typeNdx].typeStr << tcu::TestLog::EndMessage;
+                       m_testCtx.getLog() << tcu::TestLog::Message << "GL_OES_texture_storage_multisample_2d_array not supported, skipping type " << samplerTypes[typeNdx].typeStr << tcu::TestLog::EndMessage;
+               }
+               else
+               {
+                       std::map<std::string, std::string>      shaderArgs;
+                       shaderArgs["SAMPLERTYPE"]                       = samplerTypes[typeNdx].typeStr;
+                       shaderArgs["POSITION"]                          = samplerTypes[typeNdx].samplePosStr;
+                       shaderArgs["EXTENSIONSTATEMENT"]        = (samplerTypes[typeNdx].isArray) ? ("#extension GL_OES_texture_storage_multisample_2d_array : require\n") : ("");
 
-                       if (!program.isOk())
                        {
-                               m_testCtx.getLog() << program;
-                               throw tcu::TestError("could not build shader");
-                       }
+                               const std::string                       fragmentSource  = tcu::StringTemplate(fragmentSourceTemplate).specialize(shaderArgs);
+                               const glw::Functions&           gl                              = m_context.getRenderContext().getFunctions();
+                               glu::ShaderProgram                      program                 (m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(vertexSource) << glu::FragmentSource(fragmentSource));
 
-                       // only one uniform -- uniform at index 0
-                       {
-                               int uniforms = 0;
-                               gl.getProgramiv(program.getProgram(), GL_ACTIVE_UNIFORMS, &uniforms);
+                               m_testCtx.getLog() << tcu::TestLog::Message << "Building program with uniform sampler of type " << samplerTypes[typeNdx].typeStr << tcu::TestLog::EndMessage;
 
-                               if (uniforms != 1)
-                                       throw tcu::TestError("Unexpected GL_ACTIVE_UNIFORMS, expected 1");
-                       }
+                               if (!program.isOk())
+                               {
+                                       m_testCtx.getLog() << program;
+                                       throw tcu::TestError("could not build shader");
+                               }
 
-                       m_testCtx.getLog() << tcu::TestLog::Message << "Verifying uniform type." << tcu::TestLog::EndMessage;
+                               // only one uniform -- uniform at index 0
+                               {
+                                       int uniforms = 0;
+                                       gl.getProgramiv(program.getProgram(), GL_ACTIVE_UNIFORMS, &uniforms);
 
-                       // check type
-                       {
-                               const glw::GLuint       uniformIndex    = 0;
-                               glw::GLint                      type                    = 0;
+                                       if (uniforms != 1)
+                                               throw tcu::TestError("Unexpected GL_ACTIVE_UNIFORMS, expected 1");
+                               }
 
-                               gl.getActiveUniformsiv(program.getProgram(), 1, &uniformIndex, GL_UNIFORM_TYPE, &type);
+                               m_testCtx.getLog() << tcu::TestLog::Message << "Verifying uniform type." << tcu::TestLog::EndMessage;
 
-                               if (type != (glw::GLint)samplerTypes[typeNdx].glType)
+                               // check type
                                {
-                                       m_testCtx.getLog() << tcu::TestLog::Message << "Invalid type, expected " << samplerTypes[typeNdx].glType << ", got " << type << tcu::TestLog::EndMessage;
-                                       error = true;
+                                       const glw::GLuint       uniformIndex    = 0;
+                                       glw::GLint                      type                    = 0;
+
+                                       gl.getActiveUniformsiv(program.getProgram(), 1, &uniformIndex, GL_UNIFORM_TYPE, &type);
+
+                                       if (type != (glw::GLint)samplerTypes[typeNdx].glType)
+                                       {
+                                               m_testCtx.getLog() << tcu::TestLog::Message << "Invalid type, expected " << samplerTypes[typeNdx].glType << ", got " << type << tcu::TestLog::EndMessage;
+                                               error = true;
+                                       }
                                }
-                       }
 
-                       GLU_EXPECT_NO_ERROR(gl.getError(), "");
+                               GLU_EXPECT_NO_ERROR(gl.getError(), "");
+                       }
                }
        }
 
index 6d68791..8e15758 100644 (file)
@@ -127,7 +127,8 @@ void TextureSizeCase::init (void)
                tcu::IVec2(4,   8),
                tcu::IVec2(21,  11),
                tcu::IVec2(107, 254),
-               tcu::IVec2(-1,  -1),
+               tcu::IVec2(-1,  3),
+               tcu::IVec2(3,   -1),
        };
        static const tcu::IVec3 testSizes3D[] =
        {
@@ -136,9 +137,9 @@ void TextureSizeCase::init (void)
                tcu::IVec3(4,   8,              12),
                tcu::IVec3(21,  11,             9),
                tcu::IVec3(107, 254,    2),
-               tcu::IVec3(-1,  -1,             3),
+               tcu::IVec3(-1,  3,              3),
+               tcu::IVec3(3,   -1,             3),
                tcu::IVec3(4,   4,              -1),
-               tcu::IVec3(-1,  -1,             -1),
        };
        static const tcu::Vec4 fullscreenQuad[] =
        {
index 3e67c1b..7c13068 100644 (file)
@@ -221,16 +221,24 @@ void InterInvocationTestCase::init (void)
        {
                const int                               bufferElements  = m_workWidth * m_workHeight * m_elementsPerInvocation;
                const int                               bufferSize              = bufferElements * sizeof(deUint32);
-               std::vector<deUint32>   zeroBuffer              (bufferElements, 0);
 
-               m_testCtx.getLog() << tcu::TestLog::Message << "Allocating zero-filled image for storage, size " << m_workWidth << "x" << m_workHeight * m_elementsPerInvocation << ", " << bufferSize << " bytes." << tcu::TestLog::EndMessage;
+               m_testCtx.getLog() << tcu::TestLog::Message << "Allocating image for storage, size " << m_workWidth << "x" << m_workHeight * m_elementsPerInvocation << ", " << bufferSize << " bytes." << tcu::TestLog::EndMessage;
 
                gl.genTextures(1, &m_storageTex);
                gl.bindTexture(GL_TEXTURE_2D, m_storageTex);
-               gl.texImage2D(GL_TEXTURE_2D, 0, GL_R32I, m_workWidth, m_workHeight * m_elementsPerInvocation, 0, GL_RED_INTEGER, GL_INT, &zeroBuffer[0]);
+               gl.texStorage2D(GL_TEXTURE_2D, 1, GL_R32I, m_workWidth, m_workHeight * m_elementsPerInvocation);
                gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
                gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
                GLU_EXPECT_NO_ERROR(gl.getError(), "gen storage image");
+
+               // Zero-fill
+               m_testCtx.getLog() << tcu::TestLog::Message << "Filling image with 0." << tcu::TestLog::EndMessage;
+
+               {
+                       const std::vector<deInt32> zeroBuffer(m_workWidth * m_workHeight * m_elementsPerInvocation, 0);
+                       gl.texSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_workWidth, m_workHeight * m_elementsPerInvocation, GL_RED_INTEGER, GL_INT, &zeroBuffer[0]);
+                       GLU_EXPECT_NO_ERROR(gl.getError(), "specify image contents");
+               }
        }
        else
                DE_ASSERT(DE_FALSE);
@@ -1659,19 +1667,31 @@ glw::GLuint InterCallTestCase::genStorage (int friendlyName)
                gl.bindTexture(GL_TEXTURE_2D, retVal);
 
                if (m_formatInteger)
+                       gl.texStorage2D(GL_TEXTURE_2D, 1, GL_R32I, imageWidth, imageHeight);
+               else
+                       gl.texStorage2D(GL_TEXTURE_2D, 1, GL_R32F, imageWidth, imageHeight);
+
+               gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+               gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+               GLU_EXPECT_NO_ERROR(gl.getError(), "gen image");
+
+               m_testCtx.getLog()
+                       << tcu::TestLog::Message
+                       << "Filling image with 0"
+                       << tcu::TestLog::EndMessage;
+
+               if (m_formatInteger)
                {
-                       const std::vector<deUint32> zeroBuffer(imageWidth * imageHeight, 0);
-                       gl.texImage2D(GL_TEXTURE_2D, 0, GL_R32I, imageWidth, imageHeight, 0, GL_RED_INTEGER, GL_INT, &zeroBuffer[0]);
+                       const std::vector<deInt32> zeroBuffer(imageWidth * imageHeight, 0);
+                       gl.texSubImage2D(GL_TEXTURE_2D, 0, 0, 0, imageWidth, imageHeight, GL_RED_INTEGER, GL_INT, &zeroBuffer[0]);
                }
                else
                {
                        const std::vector<float> zeroBuffer(imageWidth * imageHeight, 0.0f);
-                       gl.texImage2D(GL_TEXTURE_2D, 0, GL_R32F, imageWidth, imageHeight, 0, GL_RED, GL_FLOAT, &zeroBuffer[0]);
+                       gl.texSubImage2D(GL_TEXTURE_2D, 0, 0, 0, imageWidth, imageHeight, GL_RED, GL_FLOAT, &zeroBuffer[0]);
                }
 
-               gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-               gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-               GLU_EXPECT_NO_ERROR(gl.getError(), "gen image");
+               GLU_EXPECT_NO_ERROR(gl.getError(), "specify image contents");
 
                return retVal;
        }
@@ -1801,16 +1821,30 @@ glu::ShaderProgram* InterCallTestCase::genReadProgram (int seed)
        if (m_storage == STORAGE_BUFFER)
        {
                for (int readNdx = 0; readNdx < m_perInvocationSize; ++readNdx)
-                       buf << "        allOk = allOk && ("
-                               << ((m_useAtomic) ? ("atomicExchange(") : ("")) << "sb_in.values[(groupNdx + " << seed + readNdx*m_invocationGridSize*m_invocationGridSize << ") % " << m_invocationGridSize*m_invocationGridSize*m_perInvocationSize << "]"
-                               << ((m_useAtomic) ? (", zero)") : ("")) << " == " << ((m_formatInteger) ? ("int") : ("float")) << "(groupNdx));\n";
+               {
+                       if (!m_useAtomic)
+                               buf << "        allOk = allOk && (sb_in.values[(groupNdx + "
+                                       << seed + readNdx*m_invocationGridSize*m_invocationGridSize << ") % " << m_invocationGridSize*m_invocationGridSize*m_perInvocationSize << "] == "
+                                       << ((m_formatInteger) ? ("int") : ("float")) << "(groupNdx));\n";
+                       else
+                               buf << "        allOk = allOk && (atomicExchange(sb_in.values[(groupNdx + "
+                                       << seed + readNdx*m_invocationGridSize*m_invocationGridSize << ") % " << m_invocationGridSize*m_invocationGridSize*m_perInvocationSize << "], zero) == "
+                                       << ((m_formatInteger) ? ("int") : ("float")) << "(groupNdx));\n";
+               }
        }
        else if (m_storage == STORAGE_IMAGE)
        {
                for (int readNdx = 0; readNdx < m_perInvocationSize; ++readNdx)
-                       buf << "        allOk = allOk && ("
-                       << ((m_useAtomic) ? ("imageAtomicExchange") : ("imageLoad")) << "(u_imageIn, ivec2((gl_GlobalInvocationID.x + " << (seed + readNdx*100) << "u) % " << m_invocationGridSize << "u, gl_GlobalInvocationID.y + " << readNdx*m_invocationGridSize << "u)"
-                       << ((m_useAtomic) ? (", zero") : ("")) << ").x == " << ((m_formatInteger) ? ("int") : ("float")) << "(groupNdx));\n";
+               {
+                       if (!m_useAtomic)
+                               buf     << "    allOk = allOk && (imageLoad(u_imageIn, ivec2((gl_GlobalInvocationID.x + "
+                                       << (seed + readNdx*100) << "u) % " << m_invocationGridSize << "u, gl_GlobalInvocationID.y + " << readNdx*m_invocationGridSize << "u)).x == "
+                                       << ((m_formatInteger) ? ("int") : ("float")) << "(groupNdx));\n";
+                       else
+                               buf << "        allOk = allOk && (imageAtomicExchange(u_imageIn, ivec2((gl_GlobalInvocationID.x + "
+                                       << (seed + readNdx*100) << "u) % " << m_invocationGridSize << "u, gl_GlobalInvocationID.y + " << readNdx*m_invocationGridSize << "u), zero) == "
+                                       << ((m_formatInteger) ? ("int") : ("float")) << "(groupNdx));\n";
+               }
        }
        else
                DE_ASSERT(DE_FALSE);
@@ -1869,8 +1903,8 @@ glu::ShaderProgram* InterCallTestCase::genReadMultipleProgram (int seed0, int se
        else if (m_storage == STORAGE_IMAGE)
        {
                for (int readNdx = 0; readNdx < m_perInvocationSize; ++readNdx)
-                       buf << "        allOk = allOk && (" << ((m_useAtomic) ? ("imageAtomicExchange") : ("imageLoad")) << "(u_imageIn0, ivec2((gl_GlobalInvocationID.x + " << (seed0 + readNdx*100) << "u) % " << m_invocationGridSize << "u, gl_GlobalInvocationID.y + " << readNdx*m_invocationGridSize << "u)" << ((m_useAtomic) ? (", zero") : ("")) << ").x == " << ((m_formatInteger) ? ("int") : ("float")) << "(groupNdx));\n"
-                               << "    allOk = allOk && (" << ((m_useAtomic) ? ("imageAtomicExchange") : ("imageLoad")) << "(u_imageIn1, ivec2((gl_GlobalInvocationID.x + " << (seed1 + readNdx*100) << "u) % " << m_invocationGridSize << "u, gl_GlobalInvocationID.y + " << readNdx*m_invocationGridSize << "u)" << ((m_useAtomic) ? (", zero") : ("")) << ").x == " << ((m_formatInteger) ? ("int") : ("float")) << "(groupNdx));\n";
+                       buf << "        allOk = allOk && (" << ((m_useAtomic) ? ("imageAtomicExchange") : ("imageLoad")) << "(u_imageIn0, ivec2((gl_GlobalInvocationID.x + " << (seed0 + readNdx*100) << "u) % " << m_invocationGridSize << "u, gl_GlobalInvocationID.y + " << readNdx*m_invocationGridSize << "u)" << ((m_useAtomic) ? (", zero)") : (").x")) << " == " << ((m_formatInteger) ? ("int") : ("float")) << "(groupNdx));\n"
+                               << "    allOk = allOk && (" << ((m_useAtomic) ? ("imageAtomicExchange") : ("imageLoad")) << "(u_imageIn1, ivec2((gl_GlobalInvocationID.x + " << (seed1 + readNdx*100) << "u) % " << m_invocationGridSize << "u, gl_GlobalInvocationID.y + " << readNdx*m_invocationGridSize << "u)" << ((m_useAtomic) ? (", zero)") : (").x")) << " == " << ((m_formatInteger) ? ("int") : ("float")) << "(groupNdx));\n";
        }
        else
                DE_ASSERT(DE_FALSE);
@@ -2010,7 +2044,7 @@ glu::ShaderProgram* InterCallTestCase::genReadInterleavedProgram (int seed0, int
                        buf << "                allOk = allOk && ("
                                << ((m_useAtomic) ? ("imageAtomicExchange") : ("imageLoad"))
                                << "(u_imageIn, ivec2(((int(gl_GlobalInvocationID.x >> 1U) + " << (seed0 + readNdx*100) << ") % " << m_invocationGridSize / 2 << ") * 2 + 0, int(gl_GlobalInvocationID.y) + " << readNdx*m_invocationGridSize << ")"
-                               << ((m_useAtomic) ? (", zero") : ("")) << ").x == " << ((m_formatInteger) ? ("int") : ("float")) << "(interleavedGroupNdx));\n";
+                               << ((m_useAtomic) ? (", zero)") : (").x")) << " == " << ((m_formatInteger) ? ("int") : ("float")) << "(interleavedGroupNdx));\n";
                buf << "        }\n"
                        << "    else\n"
                        << "    {\n";
@@ -2018,7 +2052,7 @@ glu::ShaderProgram* InterCallTestCase::genReadInterleavedProgram (int seed0, int
                        buf << "                allOk = allOk && ("
                                << ((m_useAtomic) ? ("imageAtomicExchange") : ("imageLoad"))
                                << "(u_imageIn, ivec2(((int(gl_GlobalInvocationID.x >> 1U) + " << (seed1 + readNdx*100) << ") % " << m_invocationGridSize / 2 << ") * 2 + 1, int(gl_GlobalInvocationID.y) + " << readNdx*m_invocationGridSize << ")"
-                               << ((m_useAtomic) ? (", zero") : ("")) << ").x == " << ((m_formatInteger) ? ("int") : ("float")) << "(interleavedGroupNdx));\n";
+                               << ((m_useAtomic) ? (", zero)") : (").x")) << " == " << ((m_formatInteger) ? ("int") : ("float")) << "(interleavedGroupNdx));\n";
                buf << "        }\n";
        }
        else
@@ -2076,7 +2110,7 @@ glu::ShaderProgram*       InterCallTestCase::genReadZeroProgram (void)
                for (int readNdx = 0; readNdx < m_perInvocationSize; ++readNdx)
                        buf << "        allOk = allOk && ("
                        << ((m_useAtomic) ? ("imageAtomicExchange") : ("imageLoad")) << "(u_imageIn, ivec2(gl_GlobalInvocationID.x, gl_GlobalInvocationID.y + " << (readNdx*m_invocationGridSize) << "u)"
-                       << ((m_useAtomic) ? (", anything") : ("")) << ").x == " << ((m_formatInteger) ? ("0") : ("0.0")) << ");\n";
+                       << ((m_useAtomic) ? (", anything)") : (").x")) << " == " << ((m_formatInteger) ? ("0") : ("0.0")) << ");\n";
        }
        else
                DE_ASSERT(DE_FALSE);
@@ -2595,6 +2629,8 @@ void ConcurrentImageAtomicCase::init (void)
        gl.genTextures(1, &m_imageID);
        gl.bindTexture(GL_TEXTURE_2D, m_imageID);
        gl.texStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, m_workSize, m_workSize);
+       gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+       gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
        GLU_EXPECT_NO_ERROR(gl.getError(), "gen tex");
 
        // gen buffers
@@ -2855,7 +2891,7 @@ std::string ConcurrentImageAtomicCase::genComputeSource (void) const
                << "    highp uint values[" << m_workSize * m_workSize << "];\n"
                << "} sb_ires;\n"
                << "\n"
-               << "layout (binding = 2, r32ui) volatile uniform uimage2D u_workImage;\n"
+               << "layout (binding = 2, r32ui) volatile uniform highp uimage2D u_workImage;\n"
                << "uniform highp uint u_atomicDelta;\n"
                << "\n"
                << "void main ()\n"
@@ -2879,7 +2915,7 @@ std::string ConcurrentImageAtomicCase::genImageReadSource (void) const
                << "    highp uint values[" << m_workSize * m_workSize << "];\n"
                << "} sb_res;\n"
                << "\n"
-               << "layout (binding = 2, r32ui) readonly uniform uimage2D u_workImage;\n"
+               << "layout (binding = 2, r32ui) readonly uniform highp uimage2D u_workImage;\n"
                << "\n"
                << "void main ()\n"
                << "{\n"
@@ -2897,7 +2933,7 @@ std::string ConcurrentImageAtomicCase::genImageClearSource (void) const
        buf     << "#version 310 es\n"
                << "\n"
                << "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
-               << "layout (binding = 2, r32ui) writeonly uniform uimage2D u_workImage;\n"
+               << "layout (binding = 2, r32ui) writeonly uniform highp uimage2D u_workImage;\n"
                << "\n"
                << "void main ()\n"
                << "{\n"
index 518336d..adc94a8 100644 (file)
@@ -1660,10 +1660,10 @@ void CommonEdgeCase::init (void)
                                                                                                         "      // Offset the position slightly, based on the parity of the bits in the float representation.\n"
                                                                                                         "      // This is done to detect possible small differences in edge vertex positions between patches.\n"
                                                                                                         "      uvec2 bits = floatBitsToUint(pos);\n"
-                                                                                                        "      uint numBits = 0;\n"
-                                                                                                        "      for (int i = 0; i < 32; i++)\n"
-                                                                                                        "              numBits += ((bits[0] >> i) & 1) + ((bits[1] >> i) & 1);\n"
-                                                                                                        "      pos += float(numBits&1)*0.04;\n"
+                                                                                                        "      uint numBits = 0u;\n"
+                                                                                                        "      for (uint i = 0u; i < 32u; i++)\n"
+                                                                                                        "              numBits += ((bits[0] >> i) & 1u) + ((bits[1] >> i) & 1u);\n"
+                                                                                                        "      pos += float(numBits&1u)*0.04;\n"
                                                                                                         "\n"
                                                                                                         "      gl_Position = vec4(pos, 0.0, 1.0);\n"
                                                                                                         "}\n")
@@ -3376,7 +3376,7 @@ void BarrierCase::init (void)
                                                                                                         "      highp float x = gl_TessCoord.x*2.0 - 1.0;\n"
                                                                                                         "      highp float y = gl_TessCoord.y - in_te_attr[int(round(gl_TessCoord.x*float(" + numVertsStr + "-1)))];\n"
                                                                                                         "      gl_Position = vec4(x, y, 0.0, 1.0);\n"
-                                                                                                        "      in_f_blue = abs(in_te_patchAttr - (" + numVertsStr + "-1));\n"
+                                                                                                        "      in_f_blue = abs(in_te_patchAttr - float(" + numVertsStr + "-1));\n"
                                                                                                         "}\n")
 
                        << glu::FragmentSource                                  ("#version 310 es\n"
diff --git a/modules/gles31/functional/es31fTextureFilteringTests.cpp b/modules/gles31/functional/es31fTextureFilteringTests.cpp
new file mode 100644 (file)
index 0000000..67eadb1
--- /dev/null
@@ -0,0 +1,618 @@
+/*-------------------------------------------------------------------------
+ * drawElements Quality Program OpenGL ES 3.1 Module
+ * -------------------------------------------------
+ *
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *//*!
+ * \file
+ * \brief Texture filtering tests.
+ *//*--------------------------------------------------------------------*/
+
+#include "es31fTextureFilteringTests.hpp"
+
+#include "glsTextureTestUtil.hpp"
+
+#include "gluPixelTransfer.hpp"
+#include "gluTexture.hpp"
+#include "gluTextureUtil.hpp"
+
+#include "tcuCommandLine.hpp"
+#include "tcuTextureUtil.hpp"
+#include "tcuImageCompare.hpp"
+#include "tcuTexLookupVerifier.hpp"
+#include "tcuVectorUtil.hpp"
+
+#include "deStringUtil.hpp"
+#include "deString.h"
+
+#include "glwFunctions.hpp"
+#include "glwEnums.hpp"
+
+namespace deqp
+{
+namespace gles31
+{
+namespace Functional
+{
+
+using std::vector;
+using std::string;
+using tcu::TestLog;
+using namespace gls::TextureTestUtil;
+
+static const char* getFaceDesc (const tcu::CubeFace face)
+{
+       switch (face)
+       {
+               case tcu::CUBEFACE_NEGATIVE_X:  return "-X";
+               case tcu::CUBEFACE_POSITIVE_X:  return "+X";
+               case tcu::CUBEFACE_NEGATIVE_Y:  return "-Y";
+               case tcu::CUBEFACE_POSITIVE_Y:  return "+Y";
+               case tcu::CUBEFACE_NEGATIVE_Z:  return "-Z";
+               case tcu::CUBEFACE_POSITIVE_Z:  return "+Z";
+               default:
+                       DE_ASSERT(false);
+                       return DE_NULL;
+       }
+}
+
+static void logCubeArrayTexCoords(TestLog& log, vector<float>& texCoord)
+{
+       const size_t numVerts = texCoord.size() / 4;
+
+       DE_ASSERT(texCoord.size() % 4 == 0);
+
+       for (size_t vertNdx = 0; vertNdx < numVerts; vertNdx++)
+       {
+               const size_t    coordNdx        = vertNdx * 4;
+
+               const float             u                       = texCoord[coordNdx + 0];
+               const float             v                       = texCoord[coordNdx + 1];
+               const float             w                       = texCoord[coordNdx + 2];
+               const float             q                       = texCoord[coordNdx + 3];
+
+               log << TestLog::Message
+                       << vertNdx << ": ("
+                       << u << ", "
+                       << v << ", "
+                       << w << ", "
+                       << q << ")"
+                       << TestLog::EndMessage;
+       }
+}
+
+// Cube map array filtering
+
+class TextureCubeArrayFilteringCase : public TestCase
+{
+public:
+                                                                       TextureCubeArrayFilteringCase   (Context& context,
+                                                                                                                                        const char* name,
+                                                                                                                                        const char* desc,
+                                                                                                                                        deUint32 minFilter,
+                                                                                                                                        deUint32 magFilter,
+                                                                                                                                        deUint32 wrapS,
+                                                                                                                                        deUint32 wrapT,
+                                                                                                                                        deUint32 internalFormat,
+                                                                                                                                        int size,
+                                                                                                                                        int depth,
+                                                                                                                                        bool onlySampleFaceInterior = false);
+
+                                                                       ~TextureCubeArrayFilteringCase  (void);
+
+       void                                                    init                                                    (void);
+       void                                                    deinit                                                  (void);
+       IterateResult                                   iterate                                                 (void);
+
+private:
+                                                                       TextureCubeArrayFilteringCase   (const TextureCubeArrayFilteringCase&);
+       TextureCubeArrayFilteringCase&  operator=                                               (const TextureCubeArrayFilteringCase&);
+
+       const deUint32                                  m_minFilter;
+       const deUint32                                  m_magFilter;
+       const deUint32                                  m_wrapS;
+       const deUint32                                  m_wrapT;
+
+       const deUint32                                  m_internalFormat;
+       const int                                               m_size;
+       const int                                               m_depth;
+
+       const bool                                              m_onlySampleFaceInterior; //!< If true, we avoid sampling anywhere near a face's edges.
+
+       struct FilterCase
+       {
+               const glu::TextureCubeArray*    texture;
+               tcu::Vec2                                               bottomLeft;
+               tcu::Vec2                                               topRight;
+               tcu::Vec2                                               layerRange;
+
+               FilterCase (void)
+                       : texture(DE_NULL)
+               {
+               }
+
+               FilterCase (const glu::TextureCubeArray* tex_, const tcu::Vec2& bottomLeft_, const tcu::Vec2& topRight_, const tcu::Vec2& layerRange_)
+                       : texture               (tex_)
+                       , bottomLeft    (bottomLeft_)
+                       , topRight              (topRight_)
+                       , layerRange    (layerRange_)
+               {
+               }
+       };
+
+       glu::TextureCubeArray*  m_gradientTex;
+       glu::TextureCubeArray*  m_gridTex;
+
+       TextureRenderer                 m_renderer;
+
+       std::vector<FilterCase> m_cases;
+       int                                             m_caseNdx;
+};
+
+TextureCubeArrayFilteringCase::TextureCubeArrayFilteringCase (Context& context,
+                                                                                                                         const char* name,
+                                                                                                                         const char* desc,
+                                                                                                                         deUint32 minFilter,
+                                                                                                                         deUint32 magFilter,
+                                                                                                                         deUint32 wrapS,
+                                                                                                                         deUint32 wrapT,
+                                                                                                                         deUint32 internalFormat,
+                                                                                                                         int size,
+                                                                                                                         int depth,
+                                                                                                                         bool onlySampleFaceInterior)
+       : TestCase                                      (context, name, desc)
+       , m_minFilter                           (minFilter)
+       , m_magFilter                           (magFilter)
+       , m_wrapS                                       (wrapS)
+       , m_wrapT                                       (wrapT)
+       , m_internalFormat                      (internalFormat)
+       , m_size                                        (size)
+       , m_depth                                       (depth)
+       , m_onlySampleFaceInterior      (onlySampleFaceInterior)
+       , m_gradientTex                         (DE_NULL)
+       , m_gridTex                                     (DE_NULL)
+       , m_renderer                            (m_context.getRenderContext(), context.getTestContext(), glu::GLSL_VERSION_310_ES, glu::PRECISION_HIGHP)
+       , m_caseNdx                                     (0)
+{
+}
+
+TextureCubeArrayFilteringCase::~TextureCubeArrayFilteringCase (void)
+{
+       TextureCubeArrayFilteringCase::deinit();
+}
+
+void TextureCubeArrayFilteringCase::init (void)
+{
+       if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_texture_cube_map_array"))
+               throw tcu::NotSupportedError("GL_EXT_texture_cube_map_array not supported");
+
+       try
+       {
+               const tcu::TextureFormat                texFmt          = glu::mapGLInternalFormat(m_internalFormat);
+               const tcu::TextureFormatInfo    fmtInfo         = tcu::getTextureFormatInfo(texFmt);
+               const tcu::Vec4                                 cScale          = fmtInfo.valueMax-fmtInfo.valueMin;
+               const tcu::Vec4                                 cBias           = fmtInfo.valueMin;
+               const int                                               numLevels       = deLog2Floor32(m_size) + 1;
+               const int                                               numLayers       = m_depth / 6;
+
+               // Create textures.
+               m_gradientTex   = new glu::TextureCubeArray(m_context.getRenderContext(), m_internalFormat, m_size, m_depth);
+               m_gridTex               = new glu::TextureCubeArray(m_context.getRenderContext(), m_internalFormat, m_size, m_depth);
+
+               const tcu::IVec4 levelSwz[] =
+               {
+                       tcu::IVec4(0,1,2,3),
+                       tcu::IVec4(2,1,3,0),
+                       tcu::IVec4(3,0,1,2),
+                       tcu::IVec4(1,3,2,0),
+               };
+
+               // Fill first gradient texture (gradient direction varies between layers).
+               for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
+               {
+                       m_gradientTex->getRefTexture().allocLevel(levelNdx);
+
+                       const tcu::PixelBufferAccess levelBuf = m_gradientTex->getRefTexture().getLevel(levelNdx);
+
+                       for (int layerFaceNdx = 0; layerFaceNdx < m_depth; layerFaceNdx++)
+                       {
+                               const tcu::IVec4        swz             = levelSwz[layerFaceNdx % DE_LENGTH_OF_ARRAY(levelSwz)];
+                               const tcu::Vec4         gMin    = tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f).swizzle(swz[0],swz[1],swz[2],swz[3])*cScale + cBias;
+                               const tcu::Vec4         gMax    = tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f).swizzle(swz[0],swz[1],swz[2],swz[3])*cScale + cBias;
+
+                               tcu::fillWithComponentGradients(tcu::getSubregion(levelBuf, 0, 0, layerFaceNdx, levelBuf.getWidth(), levelBuf.getHeight(), 1), gMin, gMax);
+                       }
+               }
+
+               // Fill second with grid texture (each layer has unique colors).
+               for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
+               {
+                       m_gridTex->getRefTexture().allocLevel(levelNdx);
+
+                       const tcu::PixelBufferAccess levelBuf = m_gridTex->getRefTexture().getLevel(levelNdx);
+
+                       for (int layerFaceNdx = 0; layerFaceNdx < m_depth; layerFaceNdx++)
+                       {
+                               const deUint32  step    = 0x00ffffff / (numLevels*m_depth - 1);
+                               const deUint32  rgb             = step * (levelNdx + layerFaceNdx*numLevels);
+                               const deUint32  colorA  = 0xff000000 | rgb;
+                               const deUint32  colorB  = 0xff000000 | ~rgb;
+
+                               tcu::fillWithGrid(tcu::getSubregion(levelBuf, 0, 0, layerFaceNdx, levelBuf.getWidth(), levelBuf.getHeight(), 1),
+                                                                 4, tcu::RGBA(colorA).toVec()*cScale + cBias, tcu::RGBA(colorB).toVec()*cScale + cBias);
+                       }
+               }
+
+               // Upload.
+               m_gradientTex->upload();
+               m_gridTex->upload();
+
+               // Test cases
+               {
+                       const glu::TextureCubeArray* const      tex0    = m_gradientTex;
+                       const glu::TextureCubeArray* const      tex1    = m_gridTex;
+
+                       if (m_onlySampleFaceInterior)
+                       {
+                               m_cases.push_back(FilterCase(tex0, tcu::Vec2(-0.8f, -0.8f),     tcu::Vec2(0.8f,  0.8f), tcu::Vec2(-0.5f, float(numLayers)+0.5f)));      // minification
+                               m_cases.push_back(FilterCase(tex0, tcu::Vec2(0.5f, 0.65f),      tcu::Vec2(0.8f,  0.8f), tcu::Vec2(-0.5f, float(numLayers)+0.5f)));      // magnification
+                               m_cases.push_back(FilterCase(tex1, tcu::Vec2(-0.8f, -0.8f),     tcu::Vec2(0.8f,  0.8f), tcu::Vec2(float(numLayers)+0.5f, -0.5f)));      // minification
+                               m_cases.push_back(FilterCase(tex1, tcu::Vec2(0.2f, 0.2f),       tcu::Vec2(0.6f,  0.5f), tcu::Vec2(float(numLayers)+0.5f, -0.5f)));      // magnification
+                       }
+                       else
+                       {
+                               const bool isSingleSample = (m_context.getRenderTarget().getNumSamples() == 0);
+
+                               // minification - w/ tweak to avoid hitting triangle edges with a face switchpoint in multisample configs
+                               if (isSingleSample)
+                                       m_cases.push_back(FilterCase(tex0, tcu::Vec2(-1.25f, -1.2f), tcu::Vec2(1.2f, 1.25f), tcu::Vec2(-0.5f, float(numLayers)+0.5f)));
+                               else
+                                       m_cases.push_back(FilterCase(tex0, tcu::Vec2(-1.19f, -1.3f), tcu::Vec2(1.1f, 1.35f), tcu::Vec2(-0.5f, float(numLayers)+0.5f)));
+
+                               m_cases.push_back(FilterCase(tex0, tcu::Vec2(0.8f, 0.8f),               tcu::Vec2(1.25f, 1.20f),        tcu::Vec2(-0.5f, float(numLayers)+0.5f)));      // magnification
+                               m_cases.push_back(FilterCase(tex1, tcu::Vec2(-1.19f, -1.3f),    tcu::Vec2(1.1f, 1.35f),         tcu::Vec2(float(numLayers)+0.5f, -0.5f)));      // minification
+                               m_cases.push_back(FilterCase(tex1, tcu::Vec2(-1.2f, -1.1f),             tcu::Vec2(-0.8f, -0.8f),        tcu::Vec2(float(numLayers)+0.5f, -0.5f)));      // magnification
+
+                               // Layer rounding - only in single-sample configs as multisample configs may produce smooth transition at the middle.
+                               if (isSingleSample && (numLayers > 1))
+                                       m_cases.push_back(FilterCase(tex0,      tcu::Vec2(-2.0f, -1.5f  ),      tcu::Vec2(-0.1f,  0.9f), tcu::Vec2(1.50001f, 1.49999f)));
+                       }
+               }
+
+               m_caseNdx = 0;
+               m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
+       }
+       catch (...)
+       {
+               // Clean up to save memory.
+               TextureCubeArrayFilteringCase::deinit();
+               throw;
+       }
+}
+
+void TextureCubeArrayFilteringCase::deinit (void)
+{
+       delete m_gradientTex;
+       delete m_gridTex;
+
+       m_gradientTex   = DE_NULL;
+       m_gridTex               = DE_NULL;
+
+       m_renderer.clear();
+       m_cases.clear();
+}
+
+TextureCubeArrayFilteringCase::IterateResult TextureCubeArrayFilteringCase::iterate (void)
+{
+       TestLog&                                                log                             = m_testCtx.getLog();
+       const glu::RenderContext&               renderCtx               = m_context.getRenderContext();
+       const glw::Functions&                   gl                              = renderCtx.getFunctions();
+       const int                                               viewportSize    = 28;
+       const deUint32                                  randomSeed              = deStringHash(getName()) ^ deInt32Hash(m_caseNdx) ^ m_testCtx.getCommandLine().getBaseSeed();
+       const RandomViewport                    viewport                (m_context.getRenderTarget(), viewportSize, viewportSize, randomSeed);
+       const FilterCase&                               curCase                 = m_cases[m_caseNdx];
+       const tcu::TextureFormat                texFmt                  = curCase.texture->getRefTexture().getFormat();
+       const tcu::TextureFormatInfo    fmtInfo                 = tcu::getTextureFormatInfo(texFmt);
+       const tcu::ScopedLogSection             section                 (m_testCtx.getLog(), string("Test") + de::toString(m_caseNdx), string("Test ") + de::toString(m_caseNdx));
+       ReferenceParams                                 refParams               (TEXTURETYPE_CUBE_ARRAY);
+
+       if (viewport.width < viewportSize || viewport.height < viewportSize)
+               throw tcu::NotSupportedError("Render target too small", "", __FILE__, __LINE__);
+
+       // Params for reference computation.
+       refParams.sampler                                       = glu::mapGLSampler(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, m_minFilter, m_magFilter);
+       refParams.sampler.seamlessCubeMap       = true;
+       refParams.samplerType                           = getSamplerType(texFmt);
+       refParams.colorBias                                     = fmtInfo.lookupBias;
+       refParams.colorScale                            = fmtInfo.lookupScale;
+       refParams.lodMode                                       = LODMODE_EXACT;
+
+       gl.bindTexture  (GL_TEXTURE_CUBE_MAP_ARRAY, curCase.texture->getGLTexture());
+       gl.texParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_MIN_FILTER,      m_minFilter);
+       gl.texParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_MAG_FILTER,      m_magFilter);
+       gl.texParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_WRAP_S,          m_wrapS);
+       gl.texParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_WRAP_T,          m_wrapT);
+
+       gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
+
+       m_testCtx.getLog() << TestLog::Message << "Coordinates: " << curCase.bottomLeft << " -> " << curCase.topRight << TestLog::EndMessage;
+
+       for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; faceNdx++)
+       {
+               const tcu::CubeFace             face            = tcu::CubeFace(faceNdx);
+               tcu::Surface                    result          (viewport.width, viewport.height);
+               vector<float>                   texCoord;
+
+               computeQuadTexCoordCubeArray(texCoord, face, curCase.bottomLeft, curCase.topRight, curCase.layerRange);
+
+               log << TestLog::Message << "Face " << getFaceDesc(face) << TestLog::EndMessage;
+
+               log << TestLog::Message << "Texture coordinates:" << TestLog::EndMessage;
+
+               logCubeArrayTexCoords(log, texCoord);
+
+               m_renderer.renderQuad(0, &texCoord[0], refParams);
+               GLU_EXPECT_NO_ERROR(gl.getError(), "Draw");
+
+               glu::readPixels(renderCtx, viewport.x, viewport.y, result.getAccess());
+               GLU_EXPECT_NO_ERROR(gl.getError(), "Read pixels");
+
+               {
+                       const bool                              isNearestOnly   = m_minFilter == GL_NEAREST && m_magFilter == GL_NEAREST;
+                       const tcu::PixelFormat  pixelFormat             = renderCtx.getRenderTarget().getPixelFormat();
+                       const tcu::IVec4                coordBits               = tcu::IVec4(10);
+                       const tcu::IVec4                colorBits               = max(getBitsVec(pixelFormat) - (isNearestOnly ? 1 : 2), tcu::IVec4(0)); // 1 inaccurate bit if nearest only, 2 otherwise
+                       tcu::LodPrecision               lodPrecision;
+                       tcu::LookupPrecision    lookupPrecision;
+
+                       lodPrecision.derivateBits               = 10;
+                       lodPrecision.lodBits                    = 5;
+                       lookupPrecision.colorThreshold  = tcu::computeFixedPointThreshold(colorBits) / refParams.colorScale;
+                       lookupPrecision.coordBits               = coordBits.toWidth<3>();
+                       lookupPrecision.uvwBits                 = tcu::IVec3(6);
+                       lookupPrecision.colorMask               = getCompareMask(pixelFormat);
+
+                       const bool isHighQuality = verifyTextureResult(m_testCtx, result.getAccess(), curCase.texture->getRefTexture(),
+                                                                                                                  &texCoord[0], refParams, lookupPrecision, coordBits, lodPrecision, pixelFormat);
+
+                       if (!isHighQuality)
+                       {
+                               // Evaluate against lower precision requirements.
+                               lodPrecision.lodBits    = 4;
+                               lookupPrecision.uvwBits = tcu::IVec3(4);
+
+                               m_testCtx.getLog() << TestLog::Message << "Warning: Verification against high precision requirements failed, trying with lower requirements." << TestLog::EndMessage;
+
+                               const bool isOk = verifyTextureResult(m_testCtx, result.getAccess(), curCase.texture->getRefTexture(),
+                                                                                                         &texCoord[0], refParams, lookupPrecision, coordBits, lodPrecision, pixelFormat);
+
+                               if (!isOk)
+                               {
+                                       m_testCtx.getLog() << TestLog::Message << "ERROR: Verification against low precision requirements failed, failing test case." << TestLog::EndMessage;
+                                       m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
+                               }
+                               else if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
+                                       m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, "Low-quality filtering result");
+                       }
+               }
+       }
+
+       m_caseNdx += 1;
+       return m_caseNdx < (int)m_cases.size() ? CONTINUE : STOP;
+}
+
+TextureFilteringTests::TextureFilteringTests (Context& context)
+       : TestCaseGroup(context, "filtering", "Texture Filtering Tests")
+{
+}
+
+TextureFilteringTests::~TextureFilteringTests (void)
+{
+}
+
+void TextureFilteringTests::init (void)
+{
+       static const struct
+       {
+               const char*             name;
+               deUint32                mode;
+       } wrapModes[] =
+       {
+               { "clamp",              GL_CLAMP_TO_EDGE },
+               { "repeat",             GL_REPEAT },
+               { "mirror",             GL_MIRRORED_REPEAT }
+       };
+
+       static const struct
+       {
+               const char*             name;
+               deUint32                mode;
+       } minFilterModes[] =
+       {
+               { "nearest",                            GL_NEAREST                                      },
+               { "linear",                                     GL_LINEAR                                       },
+               { "nearest_mipmap_nearest",     GL_NEAREST_MIPMAP_NEAREST       },
+               { "linear_mipmap_nearest",      GL_LINEAR_MIPMAP_NEAREST        },
+               { "nearest_mipmap_linear",      GL_NEAREST_MIPMAP_LINEAR        },
+               { "linear_mipmap_linear",       GL_LINEAR_MIPMAP_LINEAR         }
+       };
+
+       static const struct
+       {
+               const char*             name;
+               deUint32                mode;
+       } magFilterModes[] =
+       {
+               { "nearest",    GL_NEAREST },
+               { "linear",             GL_LINEAR }
+       };
+
+       static const struct
+       {
+               int size;
+               int depth;
+       } sizesCubeArray[] =
+       {
+               {   8,   6 },
+               {  64,  12 },
+               { 128,  12 },
+               {   7,  12 },
+               {  63,  18 }
+       };
+
+       static const struct
+       {
+               const char*             name;
+               deUint32                format;
+       } filterableFormatsByType[] =
+       {
+               { "rgba16f",            GL_RGBA16F                      },
+               { "r11f_g11f_b10f",     GL_R11F_G11F_B10F       },
+               { "rgb9_e5",            GL_RGB9_E5                      },
+               { "rgba8",                      GL_RGBA8                        },
+               { "rgba8_snorm",        GL_RGBA8_SNORM          },
+               { "rgb565",                     GL_RGB565                       },
+               { "rgba4",                      GL_RGBA4                        },
+               { "rgb5_a1",            GL_RGB5_A1                      },
+               { "srgb8_alpha8",       GL_SRGB8_ALPHA8         },
+               { "rgb10_a2",           GL_RGB10_A2                     }
+       };
+
+       // Cube map array texture filtering.
+       {
+               tcu::TestCaseGroup* const groupCubeArray = new tcu::TestCaseGroup(m_testCtx, "cube_array", "Cube Map Array Texture Filtering");
+               addChild(groupCubeArray);
+
+               // Formats.
+               {
+                       tcu::TestCaseGroup* const formatsGroup = new tcu::TestCaseGroup(m_testCtx, "formats", "Cube Map Array Texture Formats");
+                       groupCubeArray->addChild(formatsGroup);
+
+                       for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(filterableFormatsByType); fmtNdx++)
+                       {
+                               for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++)
+                               {
+                                       const deUint32  minFilter       = minFilterModes[filterNdx].mode;
+                                       const char*             filterName      = minFilterModes[filterNdx].name;
+                                       const deUint32  format          = filterableFormatsByType[fmtNdx].format;
+                                       const char*             formatName      = filterableFormatsByType[fmtNdx].name;
+                                       const bool              isMipmap        = minFilter != GL_NEAREST && minFilter != GL_LINEAR;
+                                       const deUint32  magFilter       = isMipmap ? GL_LINEAR : minFilter;
+                                       const string    name            = string(formatName) + "_" + filterName;
+                                       const deUint32  wrapS           = GL_REPEAT;
+                                       const deUint32  wrapT           = GL_REPEAT;
+                                       const int               size            = 64;
+                                       const int               depth           = 12;
+
+                                       formatsGroup->addChild(new TextureCubeArrayFilteringCase(m_context,
+                                                                                                                                                        name.c_str(), "",
+                                                                                                                                                        minFilter, magFilter,
+                                                                                                                                                        wrapS, wrapT,
+                                                                                                                                                        format,
+                                                                                                                                                        size, depth));
+                               }
+                       }
+               }
+
+               // Sizes.
+               {
+                       tcu::TestCaseGroup* const sizesGroup = new tcu::TestCaseGroup(m_testCtx, "sizes", "Texture Sizes");
+                       groupCubeArray->addChild(sizesGroup);
+
+                       for (int sizeNdx = 0; sizeNdx < DE_LENGTH_OF_ARRAY(sizesCubeArray); sizeNdx++)
+                       {
+                               for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++)
+                               {
+                                       const deUint32  minFilter       = minFilterModes[filterNdx].mode;
+                                       const char*             filterName      = minFilterModes[filterNdx].name;
+                                       const deUint32  format          = GL_RGBA8;
+                                       const bool              isMipmap        = minFilter != GL_NEAREST && minFilter != GL_LINEAR;
+                                       const deUint32  magFilter       = isMipmap ? GL_LINEAR : minFilter;
+                                       const deUint32  wrapS           = GL_REPEAT;
+                                       const deUint32  wrapT           = GL_REPEAT;
+                                       const int               size            = sizesCubeArray[sizeNdx].size;
+                                       const int               depth           = sizesCubeArray[sizeNdx].depth;
+                                       const string    name            = de::toString(size) + "x" + de::toString(size) + "x" + de::toString(depth) + "_" + filterName;
+
+                                       sizesGroup->addChild(new TextureCubeArrayFilteringCase(m_context,
+                                                                                                                                                  name.c_str(), "",
+                                                                                                                                                  minFilter, magFilter,
+                                                                                                                                                  wrapS, wrapT,
+                                                                                                                                                  format,
+                                                                                                                                                  size, depth));
+                               }
+                       }
+               }
+
+               // Wrap modes.
+               {
+                       tcu::TestCaseGroup* const combinationsGroup = new tcu::TestCaseGroup(m_testCtx, "combinations", "Filter and wrap mode combinations");
+                       groupCubeArray->addChild(combinationsGroup);
+
+                       for (int minFilterNdx = 0; minFilterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); minFilterNdx++)
+                       {
+                               for (int magFilterNdx = 0; magFilterNdx < DE_LENGTH_OF_ARRAY(magFilterModes); magFilterNdx++)
+                               {
+                                       for (int wrapSNdx = 0; wrapSNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapSNdx++)
+                                       {
+                                               for (int wrapTNdx = 0; wrapTNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapTNdx++)
+                                               {
+                                                       const deUint32  minFilter       = minFilterModes[minFilterNdx].mode;
+                                                       const deUint32  magFilter       = magFilterModes[magFilterNdx].mode;
+                                                       const deUint32  format          = GL_RGBA8;
+                                                       const deUint32  wrapS           = wrapModes[wrapSNdx].mode;
+                                                       const deUint32  wrapT           = wrapModes[wrapTNdx].mode;
+                                                       const int               size            = 63;
+                                                       const int               depth           = 12;
+                                                       const string    name            = string(minFilterModes[minFilterNdx].name) + "_" + magFilterModes[magFilterNdx].name + "_" + wrapModes[wrapSNdx].name + "_" + wrapModes[wrapTNdx].name;
+
+                                                       combinationsGroup->addChild(new TextureCubeArrayFilteringCase(m_context,
+                                                                                                                                                                                 name.c_str(), "",
+                                                                                                                                                                                 minFilter, magFilter,
+                                                                                                                                                                                 wrapS, wrapT,
+                                                                                                                                                                                 format,
+                                                                                                                                                                                 size, depth));
+                                               }
+                                       }
+                               }
+                       }
+               }
+
+               // Cases with no visible cube edges.
+               {
+                       tcu::TestCaseGroup* const onlyFaceInteriorGroup = new tcu::TestCaseGroup(m_testCtx, "no_edges_visible", "Don't sample anywhere near a face's edges");
+                       groupCubeArray->addChild(onlyFaceInteriorGroup);
+
+                       for (int isLinearI = 0; isLinearI <= 1; isLinearI++)
+                       {
+                               const bool              isLinear        = isLinearI != 0;
+                               const deUint32  filter          = isLinear ? GL_LINEAR : GL_NEAREST;
+
+                               onlyFaceInteriorGroup->addChild(new TextureCubeArrayFilteringCase(m_context,
+                                                                                                                                                                 isLinear ? "linear" : "nearest", "",
+                                                                                                                                                                 filter, filter,
+                                                                                                                                                                 GL_REPEAT, GL_REPEAT,
+                                                                                                                                                                 GL_RGBA8,
+                                                                                                                                                                 63, 12,
+                                                                                                                                                                 true));
+                       }
+               }
+       }
+}
+
+} // Functional
+} // gles31
+} // deqp
diff --git a/modules/gles31/functional/es31fTextureFilteringTests.hpp b/modules/gles31/functional/es31fTextureFilteringTests.hpp
new file mode 100644 (file)
index 0000000..1162829
--- /dev/null
@@ -0,0 +1,57 @@
+#ifndef _ES31FTEXTUREFILTERINGTESTS_HPP
+#define _ES31FTEXTUREFILTERINGTESTS_HPP
+/*-------------------------------------------------------------------------
+ * drawElements Quality Program OpenGL ES 3.1 Module
+ * -------------------------------------------------
+ *
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *//*!
+ * \file
+ * \brief Texture filtering tests.
+ *//*--------------------------------------------------------------------*/
+
+#ifndef _TCUDEFS_HPP
+#      include "tcuDefs.hpp"
+#endif
+#ifndef _TES3TESTCASE_HPP
+#      include "tes31TestCase.hpp"
+#endif
+
+namespace deqp
+{
+namespace gles31
+{
+namespace Functional
+{
+
+class TextureFilteringTests : public TestCaseGroup
+{
+public:
+                                                               TextureFilteringTests           (Context& context);
+                                                               ~TextureFilteringTests          (void);
+
+       void                                            init                                            (void);
+
+private:
+                                                               TextureFilteringTests           (const TextureFilteringTests& other);
+       TextureFilteringTests&          operator=                                       (const TextureFilteringTests& other);
+};
+
+} // Functional
+} // gles31
+} // deqp
+
+#endif // _ES31FTEXTUREFILTERINGTESTS_HPP
index 91adc29..f6c9da8 100644 (file)
@@ -190,9 +190,10 @@ bool TextureCubeArrayFormatCase::testLayerFace (int layerFaceNdx)
        renderParams.colorBias                                  = spec.lookupBias;
 
        // Layer here specifies the cube slice
-       computeQuadTexCoordCubeArray(texCoord, layerNdx, face, tcu::Vec2(0.0f, 0.0f), tcu::Vec2(1.0f, 1.0f));
+       computeQuadTexCoordCubeArray(texCoord, face, tcu::Vec2(0.0f, 0.0f), tcu::Vec2(1.0f, 1.0f), tcu::Vec2((float)layerNdx));
 
        // Setup base viewport.
+       gl.clear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
        gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
 
        // Upload texture data to GL.
@@ -234,7 +235,7 @@ TextureCubeArrayFormatCase::IterateResult TextureCubeArrayFormatCase::iterate (v
 
        m_curLayerFace += 1;
 
-       return m_curLayerFace < m_texture->getRefTexture().getNumLayers() ? CONTINUE : STOP;
+       return m_curLayerFace < m_texture->getRefTexture().getDepth() ? CONTINUE : STOP;
 }
 
 // TextureBufferFormatCase
@@ -329,6 +330,7 @@ TextureBufferFormatCase::IterateResult TextureBufferFormatCase::iterate (void)
        gl.clear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
 
        // Setup base viewport.
+       gl.clear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
        gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
 
        // Upload texture data to GL.
index e2b6f4f..7a3be4c 100644 (file)
@@ -840,14 +840,19 @@ template <typename T>
 typename Traits<T>::IVal Expr<T>::evaluate (const EvalContext& ctx) const
 {
 #ifdef GLS_ENABLE_TRACE
-       EvalContext                     newCtx  (ctx.format, ctx.floatPrecision, ctx.env, ctx.callDepth + 1);
-       const IVal                      ret             = this->doEvaluate(newCtx);
+       static const FloatFormat        highpFmt        (-126, 127, 23, true,
+                                                                                        tcu::MAYBE,
+                                                                                        tcu::YES,
+                                                                                        tcu::MAYBE);
+       EvalContext                                     newCtx          (ctx.format, ctx.floatPrecision,
+                                                                                        ctx.env, ctx.callDepth + 1);
+       const IVal                                      ret                     = this->doEvaluate(newCtx);
 
        if (isTypeValid<T>())
        {
                std::cerr << string(ctx.callDepth, ' ');
                this->printExpr(std::cerr);
-               std::cerr << " -> " << intervalToString<T>(ctx.format, ret) << std::endl;
+               std::cerr << " -> " << intervalToString<T>(highpFmt, ret) << std::endl;
        }
        return ret;
 #else
@@ -3637,7 +3642,7 @@ public:
 
        string                  getRequiredExtension    (void) const
        {
-               return "GL_EXT_gpu_ shader5";
+               return "GL_EXT_gpu_shader5";
        }
 
 protected:
@@ -3900,9 +3905,9 @@ template <typename T>
 class Sampling
 {
 public:
-       virtual void    genFixeds       (const FloatFormat&, vector<T>&)        const {}
-       virtual T               genRandom       (const FloatFormat&, Random&)           const { return T(); }
-       virtual double  getWeight       (void)                                                          const { return 0.0; }
+       virtual void    genFixeds       (const FloatFormat&, vector<T>&)                        const {}
+       virtual T               genRandom       (const FloatFormat&, Precision, Random&)        const { return T(); }
+       virtual double  getWeight       (void)                                                                          const { return 0.0; }
 };
 
 template <>
@@ -3927,9 +3932,9 @@ template <>
 class DefaultSampling<int> : public Sampling<int>
 {
 public:
-       int             genRandom       (const FloatFormat&, Random& rnd) const
+       int             genRandom       (const FloatFormat&, Precision prec, Random& rnd) const
        {
-               const int       exp             = rnd.getInt(0, 30);
+               const int       exp             = rnd.getInt(0, getNumBits(prec)-2);
                const int       sign    = rnd.getBool() ? -1 : 1;
 
                return sign * rnd.getInt(0, 1L << exp);
@@ -3942,19 +3947,34 @@ public:
                dst.push_back(1);
        }
        double  getWeight       (void) const { return 1.0; }
+
+private:
+       static inline int getNumBits (Precision prec)
+       {
+               switch (prec)
+               {
+                       case glu::PRECISION_LOWP:               return 8;
+                       case glu::PRECISION_MEDIUMP:    return 16;
+                       case glu::PRECISION_HIGHP:              return 32;
+                       default:
+                               DE_ASSERT(false);
+                               return 0;
+               }
+       }
 };
 
 template <>
 class DefaultSampling<float> : public Sampling<float>
 {
 public:
-       float   genRandom       (const FloatFormat& format, Random& rnd) const;
+       float   genRandom       (const FloatFormat& format, Precision prec, Random& rnd) const;
        void    genFixeds       (const FloatFormat& format, vector<float>& dst) const;
        double  getWeight       (void) const { return 1.0; }
 };
 
 //! Generate a random float from a reasonable general-purpose distribution.
 float DefaultSampling<float>::genRandom (const FloatFormat& format,
+                                                                                Precision,
                                                                                 Random&                        rnd) const
 {
        const int               minExp                  = format.getMinExp();
@@ -4066,12 +4086,12 @@ class DefaultSampling<Vector<T, Size> > : public Sampling<Vector<T, Size> >
 public:
        typedef Vector<T, Size>         Value;
 
-       Value   genRandom       (const FloatFormat& fmt, Random& rnd) const
+       Value   genRandom       (const FloatFormat& fmt, Precision prec, Random& rnd) const
        {
                Value ret;
 
                for (int ndx = 0; ndx < Size; ++ndx)
-                       ret[ndx] = instance<DefaultSampling<T> >().genRandom(fmt, rnd);
+                       ret[ndx] = instance<DefaultSampling<T> >().genRandom(fmt, prec, rnd);
 
                return ret;
        }
@@ -4098,13 +4118,13 @@ class DefaultSampling<Matrix<T, Rows, Columns> > : public Sampling<Matrix<T, Row
 public:
        typedef Matrix<T, Rows, Columns>                Value;
 
-       Value   genRandom       (const FloatFormat& fmt, Random& rnd) const
+       Value   genRandom       (const FloatFormat& fmt, Precision prec, Random& rnd) const
        {
                Value ret;
 
                for (int rowNdx = 0; rowNdx < Rows; ++rowNdx)
                        for (int colNdx = 0; colNdx < Columns; ++colNdx)
-                               ret(rowNdx, colNdx) = instance<DefaultSampling<T> >().genRandom(fmt, rnd);
+                               ret(rowNdx, colNdx) = instance<DefaultSampling<T> >().genRandom(fmt, prec, rnd);
 
                return ret;
        }
@@ -4262,14 +4282,16 @@ public:
 
 protected:
                                                PrecisionCase   (const Context&         context,
-                                                                                const string&          name)
-                                                       : TestCase      (context.testContext,
-                                                                                name.c_str(),
-                                                                                name.c_str())
-                                                       , m_ctx         (context)
-                                                       , m_status      ()
-                                                       , m_rnd         (0xdeadbeefu +
-                                                                                context.testContext.getCommandLine().getBaseSeed())
+                                                                                const string&          name,
+                                                                                const string&          extension       = "")
+                                                       : TestCase              (context.testContext,
+                                                                                        name.c_str(),
+                                                                                        name.c_str())
+                                                       , m_ctx                 (context)
+                                                       , m_status              ()
+                                                       , m_rnd                 (0xdeadbeefu +
+                                                                                        context.testContext.getCommandLine().getBaseSeed())
+                                                       , m_extension   (extension)
        {
        }
 
@@ -4295,6 +4317,7 @@ protected:
        Context                         m_ctx;
        ResultCollector         m_status;
        Random                          m_rnd;
+       const string            m_extension;
 };
 
 IterateResult PrecisionCase::iterate (void)
@@ -4362,6 +4385,10 @@ void PrecisionCase::testStatement (const Variables<In, Out>&     variables,
        }
 
        spec.version = getContextTypeGLSLVersion(getRenderContext().getType());
+
+       if (!m_extension.empty())
+               spec.globalDeclarations = "#extension " + m_extension + " : require\n";
+
        spec.inputs.resize(inCount);
 
        switch (inCount)
@@ -4630,6 +4657,7 @@ struct InputLess<InTuple<In> >
 template<typename In>
 Inputs<In> generateInputs (const Samplings<In>&        samplings,
                                                   const FloatFormat&   floatFormat,
+                                                  Precision                    intPrecision,
                                                   size_t                               numSamples,
                                                   Random&                              rnd)
 {
@@ -4667,10 +4695,10 @@ Inputs<In> generateInputs (const Samplings<In>& samplings,
 
        for (size_t ndx = 0; ndx < numSamples; ++ndx)
        {
-               const typename In::In0  in0             = samplings.in0.genRandom(floatFormat, rnd);
-               const typename In::In1  in1             = samplings.in1.genRandom(floatFormat, rnd);
-               const typename In::In2  in2             = samplings.in2.genRandom(floatFormat, rnd);
-               const typename In::In3  in3             = samplings.in3.genRandom(floatFormat, rnd);
+               const typename In::In0  in0             = samplings.in0.genRandom(floatFormat, intPrecision, rnd);
+               const typename In::In1  in1             = samplings.in1.genRandom(floatFormat, intPrecision, rnd);
+               const typename In::In2  in2             = samplings.in2.genRandom(floatFormat, intPrecision, rnd);
+               const typename In::In3  in3             = samplings.in3.genRandom(floatFormat, intPrecision, rnd);
                const InTuple<In>               tuple   (in0, in1, in2, in3);
 
                if (de::contains(seenInputs, tuple))
@@ -4695,10 +4723,7 @@ protected:
                                        FuncCaseBase    (const Context&         context,
                                                                         const string&          name,
                                                                         const FuncBase&        func)
-                                               : PrecisionCase (context, name)
-                                               , m_extension   (func.getRequiredExtension()) {}
-
-       const string    m_extension;
+                                               : PrecisionCase (context, name, func.getRequiredExtension()) {}
 };
 
 IterateResult FuncCaseBase::iterate (void)
@@ -4750,6 +4775,7 @@ void FuncCase<Sig>::runTest (void)
 {
        const Inputs<In>        inputs  (generateInputs(getSamplings(),
                                                                                                m_ctx.floatFormat,
+                                                                                               m_ctx.precision,
                                                                                                m_ctx.numRandoms,
                                                                                                m_rnd));
        Variables<In, Out>      variables;
@@ -4807,6 +4833,7 @@ void InOutFuncCase<Sig>::runTest (void)
 {
        const Inputs<In>        inputs  (generateInputs(getSamplings(),
                                                                                                m_ctx.floatFormat,
+                                                                                               m_ctx.precision,
                                                                                                m_ctx.numRandoms,
                                                                                                m_rnd));
        Variables<In, Out>      variables;
index e204774..133a8b7 100644 (file)
@@ -23,6 +23,7 @@
 
 #include "glsCalibration.hpp"
 #include "tcuTestLog.hpp"
+#include "tcuVectorUtil.hpp"
 #include "deStringUtil.hpp"
 #include "deMath.h"
 #include "deClock.h"
@@ -42,7 +43,21 @@ namespace deqp
 namespace gls
 {
 
-LineParameters theilSenEstimator (const std::vector<tcu::Vec2>& dataPoints)
+// Reorders input arbitrarily, linear complexity and no allocations
+template<typename T>
+float destructiveMedian (vector<T>& data)
+{
+       const typename vector<T>::iterator mid = data.begin()+data.size()/2;
+
+       std::nth_element(data.begin(), mid, data.end());
+
+       if (data.size()%2 == 0) // Even number of elements, need average of two centermost elements
+               return (*mid + *std::max_element(data.begin(), mid))*0.5f; // Data is partially sorted around mid, mid is half an item after center
+       else
+               return *mid;
+}
+
+LineParameters theilSenLinearRegression (const std::vector<tcu::Vec2>& dataPoints)
 {
        const float             epsilon                                 = 1e-6f;
 
@@ -67,12 +82,8 @@ LineParameters theilSenEstimator (const std::vector<tcu::Vec2>& dataPoints)
 
        // Find the median of the pairwise coefficients.
        // \note If there are no data point pairs with differing x values, the coefficient variable will stay zero as initialized.
-       std::sort(pairwiseCoefficients.begin(), pairwiseCoefficients.end());
-       int numCoeffs = (int)pairwiseCoefficients.size();
-       if (numCoeffs > 0)
-               result.coefficient = numCoeffs % 2 == 0
-                                                  ? (pairwiseCoefficients[numCoeffs/2 - 1] + pairwiseCoefficients[numCoeffs/2]) / 2
-                                                  : pairwiseCoefficients[numCoeffs/2];
+       if (!pairwiseCoefficients.empty())
+               result.coefficient = destructiveMedian(pairwiseCoefficients);
 
        // Compute the offsets corresponding to the median coefficient, for all data points.
        for (int i = 0; i < numDataPoints; i++)
@@ -80,12 +91,86 @@ LineParameters theilSenEstimator (const std::vector<tcu::Vec2>& dataPoints)
 
        // Find the median of the offsets.
        // \note If there are no data points, the offset variable will stay zero as initialized.
+       if (!pointwiseOffsets.empty())
+               result.offset = destructiveMedian(pointwiseOffsets);
+
+       return result;
+}
+
+// Sample from given values using linear interpolation at a given position as if values were laid to range [0, 1]
+template <typename T>
+static float linearSample (const std::vector<T>& values, float position)
+{
+       DE_ASSERT(position >= 0.0f);
+       DE_ASSERT(position <= 1.0f);
+
+       const int       maxNdx                          = (int)values.size() - 1;
+       const float     floatNdx                        = maxNdx * position;
+       const int       lowerNdx                        = (int)deFloatFloor(floatNdx);
+       const int       higherNdx                       = lowerNdx + (lowerNdx == maxNdx ? 0 : 1); // Use only last element if position is 1.0
+       const float     interpolationFactor = floatNdx - (float)lowerNdx;
+
+       DE_ASSERT(lowerNdx >= 0 && lowerNdx < (int)values.size());
+       DE_ASSERT(higherNdx >= 0 && higherNdx < (int)values.size());
+       DE_ASSERT(interpolationFactor >= 0 && interpolationFactor < 1.0f);
+
+       return tcu::mix((float)values[lowerNdx], (float)values[higherNdx], interpolationFactor);
+}
+
+LineParametersWithConfidence theilSenSiegelLinearRegression (const std::vector<tcu::Vec2>& dataPoints, float reportedConfidence)
+{
+       DE_ASSERT(!dataPoints.empty());
+
+       // Siegel's variation
+
+       const float                                             epsilon                         = 1e-6f;
+       const int                                               numDataPoints           = (int)dataPoints.size();
+       std::vector<float>                              medianSlopes;
+       std::vector<float>                              pointwiseOffsets;
+       LineParametersWithConfidence    result;
+
+       // Compute the median slope via each element
+       for (int i = 0; i < numDataPoints; i++)
+       {
+               const tcu::Vec2&        ptA             = dataPoints[i];
+               std::vector<float>      slopes;
+
+               slopes.reserve(numDataPoints);
+
+               for (int j = 0; j < numDataPoints; j++)
+               {
+                       const tcu::Vec2& ptB = dataPoints[j];
+
+                       if (de::abs(ptA.x() - ptB.x()) > epsilon)
+                               slopes.push_back((ptA.y() - ptB.y()) / (ptA.x() - ptB.x()));
+               }
+
+               // Add median of slopes through point i
+               medianSlopes.push_back(destructiveMedian(slopes));
+       }
+
+       DE_ASSERT(!medianSlopes.empty());
+
+       // Find the median of the pairwise coefficients.
+       std::sort(medianSlopes.begin(), medianSlopes.end());
+       result.coefficient = linearSample(medianSlopes, 0.5f);
+
+       // Compute the offsets corresponding to the median coefficient, for all data points.
+       for (int i = 0; i < numDataPoints; i++)
+               pointwiseOffsets.push_back(dataPoints[i].y() - result.coefficient*dataPoints[i].x());
+
+       // Find the median of the offsets.
        std::sort(pointwiseOffsets.begin(), pointwiseOffsets.end());
-       int numOffsets = (int)pointwiseOffsets.size();
-       if (numOffsets > 0)
-               result.offset = numOffsets % 2 == 0
-                                         ? (pointwiseOffsets[numOffsets/2 - 1] + pointwiseOffsets[numOffsets/2]) / 2
-                                         : pointwiseOffsets[numOffsets/2];
+       result.offset = linearSample(pointwiseOffsets, 0.5f);
+
+       // calculate confidence intervals
+       result.coefficientConfidenceLower = linearSample(medianSlopes, 0.5f - reportedConfidence*0.5f);
+       result.coefficientConfidenceUpper = linearSample(medianSlopes, 0.5f + reportedConfidence*0.5f);
+
+       result.offsetConfidenceLower = linearSample(pointwiseOffsets, 0.5f - reportedConfidence*0.5f);
+       result.offsetConfidenceUpper = linearSample(pointwiseOffsets, 0.5f + reportedConfidence*0.5f);
+
+       result.confidence = reportedConfidence;
 
        return result;
 }
@@ -277,7 +362,7 @@ void TheilSenCalibrator::recomputeParameters (void)
                                const float                             targetFrameTimeUs       = m_params.targetFrameTimeUs;
                                const float                             coeffEpsilon            = 0.001f; // Coefficient must be large enough (and positive) to be considered sensible.
 
-                               const LineParameters    estimatorLine           = theilSenEstimator(dataPoints);
+                               const LineParameters    estimatorLine           = theilSenLinearRegression(dataPoints);
 
                                int                                             prevMaxCalls            = 0;
 
index c4b89c6..c0c9558 100644 (file)
@@ -44,7 +44,26 @@ struct LineParameters
        LineParameters (float offset_, float coefficient_) : offset(offset_), coefficient(coefficient_) {}
 };
 
-LineParameters theilSenEstimator (const std::vector<tcu::Vec2>& dataPoints);
+// Basic Theil-Sen linear estimate. Calculates median of all possible slope coefficients through two of the data points
+// and median of offsets corresponding with the median slope
+LineParameters theilSenLinearRegression (const std::vector<tcu::Vec2>& dataPoints);
+
+struct LineParametersWithConfidence
+{
+       float offset;
+       float offsetConfidenceUpper;
+       float offsetConfidenceLower;
+
+       float coefficient;
+       float coefficientConfidenceUpper;
+       float coefficientConfidenceLower;
+
+       float confidence;
+};
+
+// Median-of-medians version of Theil-Sen estimate. Calculates median of medians of slopes through a point and all other points.
+// Confidence interval is given as the range that contains the given fraction of all slopes/offsets
+LineParametersWithConfidence theilSenSiegelLinearRegression (const std::vector<tcu::Vec2>& dataPoints, float reportedConfidence);
 
 struct MeasureState
 {
index 315301f..42f23d9 100644 (file)
 #include "glsTextureTestUtil.hpp"
 
 #include "deMath.h"
+#include "deRandom.hpp"
+#include "deUniquePtr.hpp"
 
 #include "tcuTestCase.hpp"
-#include "tcuRenderTarget.hpp"
 #include "tcuImageCompare.hpp"
 #include "tcuVector.hpp"
 #include "tcuVectorUtil.hpp"
 #include "tcuTexture.hpp"
-
-#include "sglrReferenceContext.hpp"
-#include "sglrContextUtil.hpp"
+#include "tcuStringTemplate.hpp"
 
 #include "gluStrUtil.hpp"
 #include "gluDrawUtil.hpp"
+#include "gluPixelTransfer.hpp"
+#include "gluObjectWrapper.hpp"
 
 #include "glwEnums.hpp"
+#include "glwFunctions.hpp"
 
-#include "deRandom.hpp"
+#include <map>
 
 namespace deqp
 {
@@ -49,209 +51,140 @@ namespace gls
 {
 namespace Functional
 {
-
-using std::vector;
-
-ScissorTestShader::ScissorTestShader (void)
-       : sglr::ShaderProgram(sglr::pdec::ShaderProgramDeclaration()
-                                                       << sglr::pdec::VertexAttribute("a_position", rr::GENERICVECTYPE_FLOAT)
-                                                       << sglr::pdec::FragmentOutput(rr::GENERICVECTYPE_FLOAT)
-                                                       << sglr::pdec::Uniform("u_color", glu::TYPE_FLOAT_VEC4)
-                                                       << sglr::pdec::VertexSource("attribute highp vec4 a_position;\n"
-                                                                                                               "void main (void)\n"
-                                                                                                               "{\n"
-                                                                                                               "       gl_Position = a_position;\n"
-                                                                                                               "}\n")
-                                                       << sglr::pdec::FragmentSource("uniform mediump vec4 u_color;\n"
-                                                                                                                 "void main (void)\n"
-                                                                                                                 "{\n"
-                                                                                                                 "     gl_FragColor = u_color;\n"
-                                                                                                                 "}\n"))
-       , u_color                       (getUniformByName("u_color"))
+namespace
 {
-}
 
-void ScissorTestShader::setColor (sglr::Context& ctx, deUint32 programID, const tcu::Vec4& color)
-{
-       ctx.useProgram(programID);
-       ctx.uniform4fv(ctx.getUniformLocation(programID, "u_color"), 1, color.getPtr());
-}
+using namespace ScissorTestInternal;
+using namespace glw; // GL types
 
-void ScissorTestShader::shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
-{
-       for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
-               packets[packetNdx]->position = rr::readVertexAttribFloat(inputs[0], packets[packetNdx]->instanceNdx, packets[packetNdx]->vertexNdx);
-}
+using tcu::ConstPixelBufferAccess;
+using tcu::PixelBufferAccess;
+using tcu::TestLog;
 
-void ScissorTestShader::shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
+using std::vector;
+using std::string;
+using std::map;
+using tcu::Vec3;
+using tcu::Vec4;
+using tcu::IVec4;
+using tcu::UVec4;
+
+void drawQuad (const glw::Functions& gl, deUint32 program, const Vec3& p0, const Vec3& p1)
 {
-       const tcu::Vec4 color(u_color.value.f4);
-
-       DE_UNREF(packets);
+       // Vertex data.
+       const float hz = (p0.z() + p1.z()) * 0.5f;
+       const float position[] =
+       {
+               p0.x(), p0.y(), p0.z(), 1.0f,
+               p0.x(), p1.y(), hz,             1.0f,
+               p1.x(), p0.y(), hz,             1.0f,
+               p1.x(), p1.y(), p1.z(), 1.0f
+       };
 
-       for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
-               for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
-                       rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, color);
-}
+       const deUint16  indices[]       = { 0, 1, 2, 2, 1, 3 };
 
-namespace
-{
+       const deInt32   posLoc          = gl.getAttribLocation(program, "a_position");
 
-void drawPrimitives (sglr::Context& ctx, deUint32 program, const deUint32 type, const float *vertPos, int numIndices, const deUint16 *indices)
-{
-       const deInt32   posLoc  = ctx.getAttribLocation(program, "a_position");
+       gl.useProgram(program);
+       gl.enableVertexAttribArray(posLoc);
+       gl.vertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, 0, &position[0]);
 
-       TCU_CHECK(posLoc >= 0);
+       gl.drawElements(GL_TRIANGLES, DE_LENGTH_OF_ARRAY(indices), GL_UNSIGNED_SHORT, &indices[0]);
 
-       ctx.useProgram(program);
-       ctx.enableVertexAttribArray(posLoc);
-       ctx.vertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, 0, vertPos);
+       gl.disableVertexAttribArray(posLoc);
 
-       ctx.drawElements(type, numIndices, GL_UNSIGNED_SHORT, indices);
-       ctx.disableVertexAttribArray(posLoc);
 }
 
-// Mark pixel pairs with a large color difference starting with the given points and moving by advance count times
-vector<deUint8> findBorderPairs (const tcu::ConstPixelBufferAccess& image, const tcu::IVec2& start0, const tcu::IVec2& start1, const tcu::IVec2& advance, int count)
+void drawPrimitives (const glw::Functions& gl, deUint32 program, const deUint32 type, const vector<float>& vertices, const vector<deUint16>& indices)
 {
-       using tcu::Vec4;
-       using tcu::IVec2;
+       const deInt32 posLoc = gl.getAttribLocation(program, "a_position");
 
-       const Vec4              threshold       (0.1f, 0.1f, 0.1f, 0.1f);
-       IVec2                   p0                      = start0;
-       IVec2                   p1                      = start1;
-       vector<deUint8> res;
+       TCU_CHECK(posLoc >= 0);
 
-       res.resize(count);
+       gl.useProgram(program);
+       gl.enableVertexAttribArray(posLoc);
+       gl.vertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, 0, &vertices[0]);
 
-       for (int ndx = 0; ndx < count; ndx++)
-       {
-               const Vec4      diff            = abs(image.getPixel(p0.x(), p0.y()) - image.getPixel(p1.x(), p1.y()));
+       gl.drawElements(type, GLsizei(indices.size()), GL_UNSIGNED_SHORT, &indices[0]);
 
-               res[ndx] = !boolAll(lessThanEqual(diff, threshold));
-               p0  += advance;
-               p1  += advance;
-       }
-       return res;
+       gl.disableVertexAttribArray(posLoc);
 }
 
-// make all elements within range of a 'true' element 'true' as well
-vector<deUint8> fuzz (const vector<deUint8>& ref, int range)
+template<typename T>
+void clearEdges(const tcu::PixelBufferAccess& access, const T& color, const IVec4& scissorArea)
 {
-       vector<deUint8> res;
-
-       res.resize(ref.size());
-
-       for (int ndx = 0; ndx < int(ref.size()); ndx++)
+       for (int y = 0; y < access.getHeight(); y++)
+       for (int x = 0; x < access.getWidth(); x++)
        {
-               if (ref[ndx])
-               {
-                       const int begin = de::max(0, ndx-range);
-                       const int end   = de::min(ndx+range, int(ref.size())-1);
-
-                       for (int i = begin; i <= end; i++)
-                               res[i] = 1;
-               }
+               if (y < scissorArea.y() ||
+                       y >= scissorArea.y() + scissorArea.w() ||
+                       x < scissorArea.x() ||
+                       x >= scissorArea.x()+ scissorArea.z())
+                       access.setPixel(color, x, y);
        }
-
-       return res;
 }
 
-bool bordersEquivalent (tcu::TestLog& log, const tcu::ConstPixelBufferAccess& reference, const tcu::ConstPixelBufferAccess& result, const tcu::IVec2& start0, const tcu::IVec2& start1, const tcu::IVec2& advance, int count)
+glu::ProgramSources genShaders(glu::GLSLVersion version)
 {
-       const vector<deUint8>   refBorders              = fuzz(findBorderPairs(reference,       start0, start1, advance, count), 1);
-       const vector<deUint8>   resBorders              = findBorderPairs(result,                       start0, start1, advance, count);
-
-       // Helps deal with primitives that are within 1px of the scissor edge and thus may (not) create an edge for findBorderPairs. This number is largely resolution-independent since the typical  triggers are points rather than edges.
-       const int                               errorThreshold  = 2;
-       const int                               floodThreshold  = 8;
-       int                                             messageCount    = 0;
-
-       for (int ndx = 0; ndx < int(resBorders.size()); ndx++)
+       const string vtxSource = "${VERSION}\n"
+                                                        "${IN} highp vec4 a_position;\n"
+                                                        "void main(){\n"
+                                                        "      gl_Position = a_position;\n"
+                                                        "}\n";
+
+       const string frgSource = "${VERSION}\n"
+                                                        "${OUT_DECL}"
+                                                        "uniform highp vec4 u_color;\n"
+                                                        "void main(){\n"
+                                                        "      ${OUTPUT} = u_color;\n"
+                                                        "}\n";
+
+       map<string, string>     params;
+
+       switch(version)
        {
-               if (resBorders[ndx] && !refBorders[ndx])
-               {
-                       messageCount++;
-
-                       if (messageCount <= floodThreshold)
-                       {
-                               const tcu::IVec2 coord = start0 + advance*ndx;
-                               log << tcu::TestLog::Message << "No matching border near " << coord << tcu::TestLog::EndMessage;
-                       }
-               }
+               case glu::GLSL_VERSION_100_ES:
+                       params["VERSION"] = "#version 100";
+                       params["IN"] = "attribute";
+                       params["OUT_DECL"] = "";
+                       params["OUTPUT"] = "gl_FragColor";
+                       break;
+
+               case glu::GLSL_VERSION_300_ES:
+               case glu::GLSL_VERSION_310_ES: // Assumed to support 3.0
+                       params["VERSION"] = "#version 300 es";
+                       params["IN"] = "in";
+                       params["OUT_DECL"] = "out mediump vec4 f_color;\n";
+                       params["OUTPUT"] = "f_color";
+                       break;
+
+               default:
+                       DE_ASSERT(!"Unsupported version");
        }
 
-       if (messageCount > floodThreshold)
-               log << tcu::TestLog::Message << "Omitted " << messageCount - floodThreshold << " more errors" << tcu::TestLog::EndMessage;
-
-       return messageCount <= errorThreshold;
+       return glu::makeVtxFragSources(tcu::StringTemplate(vtxSource).specialize(params), tcu::StringTemplate(frgSource).specialize(params));
 }
 
-// Try to find a clear border between [area.xy, area.zw) and the rest of the image, check that the reference and result images have a roughly matching number of border pixel pairs
-bool compareBorders (tcu::TestLog& log, const tcu::ConstPixelBufferAccess& reference, const tcu::ConstPixelBufferAccess& result, const tcu::IVec4& area)
-{
-       using tcu::IVec2;
-       using tcu::IVec4;
-
-       const IVec4                     testableArea    (0, 0, reference.getWidth(), reference.getHeight());
-       const tcu::BVec4        testableEdges   (area.x()>testableArea.x() && area.x()<testableArea.z(),
-                                                                                area.y()>testableArea.y() && area.y()<testableArea.w(),
-                                                                                area.z()<testableArea.z() && area.z()>testableArea.x(),
-                                                                                area.w()<testableArea.w() && area.w()>testableArea.y());
-       const IVec4                     testArea                (std::max(area.x(), testableArea.x()), std::max(area.y(), testableArea.y()), std::min(area.z(), testableArea.z()), std::min(area.w(), testableArea.w()) );
-
-       if (testArea.x() > testArea.z() || testArea.y() > testArea.w()) // invalid area
-               return true;
-
-       if (testableEdges.x() &&
-               !bordersEquivalent(log,
-                                                  reference,
-                                                  result,
-                                                  IVec2(testArea.x(), testArea.y()),
-                                                  IVec2(testArea.x()-1, testArea.y()),
-                                                  IVec2(0, 1),
-                                                  testArea.w()-testArea.y()))
-               return false;
-
-       if (testableEdges.z() &&
-               !bordersEquivalent(log,
-                                                  reference,
-                                                  result,
-                                                  IVec2(testArea.z(), testArea.y()),
-                                                  IVec2(testArea.z()-1, testArea.y()),
-                                                  IVec2(0, 1),
-                                                  testArea.w()-testArea.y()))
-               return false;
-
-       if (testableEdges.y() &&
-               !bordersEquivalent(log,
-                                                  reference,
-                                                  result,
-                                                  IVec2(testArea.x(), testArea.y()),
-                                                  IVec2(testArea.x(), testArea.y()-1),
-                                                  IVec2(1, 0),
-                                                  testArea.z()-testArea.x()))
-               return false;
-
-       if (testableEdges.w() &&
-               !bordersEquivalent(log,
-                                                  reference,
-                                                  result,
-                                                  IVec2(testArea.x(), testArea.w()),
-                                                  IVec2(testArea.x(), testArea.w()-1),
-                                                  IVec2(1, 0),
-                                                  testArea.z()-testArea.x()))
-               return false;
-
-       return true;
-}
+// Wrapper class, provides iterator & reporting logic
+class ScissorCase : public tcu::TestCase
+{
+public:
+                                                       ScissorCase             (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char *name, const char* desc, const Vec4& scissorArea);
+       virtual                                 ~ScissorCase    (void) {}
 
-} // anonymous
+       virtual IterateResult   iterate                 (void);
 
-ScissorCase::ScissorCase (glu::RenderContext& context, tcu::TestContext& testContext, const tcu::Vec4& scissorArea, const char* name, const char* description)
-       : TestCase                      (testContext, name, description)
-       , m_renderContext       (context)
-       , m_scissorArea         (scissorArea)
+protected:
+       virtual void                    render                  (GLuint program, const IVec4& viewport) const = 0;
+
+       glu::RenderContext&             m_renderCtx;
+       const Vec4                              m_scissorArea;
+};
+
+ScissorCase::ScissorCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char *name, const char* desc, const Vec4& scissorArea)
+       : TestCase              (testCtx, name, desc)
+       , m_renderCtx   (renderCtx)
+       , m_scissorArea (scissorArea)
 {
 }
 
@@ -259,73 +192,86 @@ ScissorCase::IterateResult ScissorCase::iterate (void)
 {
        using TextureTestUtil::RandomViewport;
 
-       const tcu::Vec4                         clearColor                              (0.0f, 0.0f, 0.0f, 1.0f);
-       glu::RenderContext&                     renderCtx                               = m_renderContext;
-       const tcu::RenderTarget&        renderTarget                    = renderCtx.getRenderTarget();
-       tcu::TestLog&                           log                                             = m_testCtx.getLog();
+       const glw::Functions&           gl                              = m_renderCtx.getFunctions();
+       TestLog&                                        log                             = m_testCtx.getLog();
+       const glu::ShaderProgram        shader                  (m_renderCtx, genShaders(glu::getContextTypeGLSLVersion(m_renderCtx.getType())));
 
-       const RandomViewport            viewport                                (renderTarget, 256, 256, deStringHash(getName()));
+       const RandomViewport            viewport                (m_renderCtx.getRenderTarget(), 256, 256, deStringHash(getName()));
+       const IVec4                                     relScissorArea  (int(m_scissorArea.x()*viewport.width),
+                                                                                                int(m_scissorArea.y()*viewport.height),
+                                                                                                int(m_scissorArea.z()*viewport.width),
+                                                                                                int(m_scissorArea.w()*viewport.height));
+       const IVec4                                     absScissorArea  (relScissorArea.x() + viewport.x,
+                                                                                                relScissorArea.y() + viewport.y,
+                                                                                                relScissorArea.z(),
+                                                                                                relScissorArea.w());
 
-       tcu::Surface                            glesFrame                               (viewport.width, viewport.height);
-       tcu::Surface                            refFrame                                (viewport.width, viewport.height);
-       deUint32                                        glesError;
+       tcu::Surface                            refImage                (viewport.width, viewport.height);
+       tcu::Surface                            resImage                (viewport.width, viewport.height);
 
-       // Render using GLES
+       if (!shader.isOk())
        {
-               sglr::GLContext context(renderCtx, log, sglr::GLCONTEXT_LOG_CALLS, tcu::IVec4(0, 0, renderTarget.getWidth(), renderTarget.getHeight()));
+               log << shader;
+               m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Shader compile/link failed");
+               return STOP;
+       }
 
-               context.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
+       log << TestLog::Message << "Viewport area is " << IVec4(viewport.x, viewport.y, viewport.width, viewport.height) << TestLog::EndMessage;
+       log << TestLog::Message << "Scissor area is " << absScissorArea << TestLog::EndMessage;
+
+       // Render reference (no scissors)
+       {
+               log << TestLog::Message << "Rendering reference (scissors disabled)" << TestLog::EndMessage;
 
-               context.clearColor(clearColor.x(), clearColor.y(), clearColor.z(), clearColor.w());
-               context.clear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
+               gl.useProgram(shader.getProgram());
+               gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
 
-               render(context, tcu::IVec4(viewport.x, viewport.y, viewport.width, viewport.height)); // Call actual render func
-               context.readPixels(glesFrame, viewport.x, viewport.y, viewport.width, viewport.height);
-               glesError = context.getError();
+               gl.clearColor(0.125f, 0.25f, 0.5f, 1.0f);
+               gl.clearDepthf(1.0f);
+               gl.clearStencil(0);
+               gl.disable(GL_DEPTH_TEST);
+               gl.disable(GL_STENCIL_TEST);
+               gl.disable(GL_SCISSOR_TEST);
+               gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+
+               render(shader.getProgram(), IVec4(viewport.x, viewport.y, viewport.width, viewport.height));
+
+               glu::readPixels(m_renderCtx, viewport.x, viewport.y, refImage.getAccess());
+               GLU_CHECK_ERROR(gl.getError());
        }
 
-       // Render reference image
+       // Render result (scissors)
        {
-               sglr::ReferenceContextBuffers   buffers (tcu::PixelFormat(8,8,8,renderTarget.getPixelFormat().alphaBits?8:0),
-                                                                                                renderTarget.getDepthBits(),
-                                                                                                renderTarget.getStencilBits(),
-                                                                                                renderTarget.getWidth(),
-                                                                                                renderTarget.getHeight());
-               sglr::ReferenceContext                  context (sglr::ReferenceContextLimits(renderCtx), buffers.getColorbuffer(), buffers.getDepthbuffer(), buffers.getStencilbuffer());
+               log << TestLog::Message << "Rendering result (scissors enabled)" << TestLog::EndMessage;
 
-               context.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
+               gl.useProgram(shader.getProgram());
+               gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
 
-               context.clearColor(clearColor.x(), clearColor.y(), clearColor.z(), clearColor.w());
-               context.clear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
+               gl.clearColor(0.125f, 0.25f, 0.5f, 1.0f);
+               gl.clearDepthf(1.0f);
+               gl.clearStencil(0);
+               gl.disable(GL_DEPTH_TEST);
+               gl.disable(GL_STENCIL_TEST);
+               gl.disable(GL_SCISSOR_TEST);
+               gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
 
-               render(context, tcu::IVec4(viewport.x, viewport.y, viewport.width, viewport.height));
-               context.readPixels(refFrame, viewport.x, viewport.y, viewport.width, viewport.height);
-               DE_ASSERT(context.getError() == GL_NO_ERROR);
-       }
+               gl.scissor(absScissorArea.x(), absScissorArea.y(), absScissorArea.z(), absScissorArea.w());
+               gl.enable(GL_SCISSOR_TEST);
 
-       if (glesError != GL_NO_ERROR)
-       {
-               log << tcu::TestLog::Message << "Unexpected error: got " << glu::getErrorStr(glesError) << tcu::TestLog::EndMessage;
-               m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got unexpected error");
+               render(shader.getProgram(), IVec4(viewport.x, viewport.y, viewport.width, viewport.height));
+
+               glu::readPixels(m_renderCtx, viewport.x, viewport.y, resImage.getAccess());
+               GLU_CHECK_ERROR(gl.getError());
        }
+
+       // Manual 'scissors' for reference image
+       log << TestLog::Message << "Clearing area outside scissor area from reference" << TestLog::EndMessage;
+       clearEdges(refImage.getAccess(), IVec4(32, 64, 128, 255), relScissorArea);
+
+       if (tcu::floatThresholdCompare(log, "ComparisonResult", "Image comparison result", refImage.getAccess(), resImage.getAccess(), Vec4(0.02f, 0.02f, 0.02f, 0.02f), tcu::COMPARE_LOG_RESULT))
+               m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
        else
-       {
-               // Compare images
-               const float                     threshold       = 0.02f;
-               const tcu::IVec4        scissorArea     (int(m_scissorArea.x()*viewport.width ),
-                                                                                int(m_scissorArea.y()*viewport.height),
-                                                                                int(m_scissorArea.x()*viewport.width ) + int(m_scissorArea.z()*viewport.width ),
-                                                                                int(m_scissorArea.y()*viewport.height) + int(m_scissorArea.w()*viewport.height));
-               const bool                      bordersOk       = compareBorders(log, refFrame.getAccess(), glesFrame.getAccess(), scissorArea);
-               const bool                      imagesOk        = tcu::fuzzyCompare(log, "ComparisonResult", "Image comparison result", refFrame, glesFrame, threshold, tcu::COMPARE_LOG_RESULT);
-
-               if (!imagesOk)
-                       m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
-               else if (!bordersOk)
-                       m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Scissor area border mismatch");
-               else
-                       m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
-       }
+               m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
 
        return STOP;
 }
@@ -334,56 +280,48 @@ ScissorCase::IterateResult ScissorCase::iterate (void)
 class ScissorPrimitiveCase : public ScissorCase
 {
 public:
-                                                               ScissorPrimitiveCase    (glu::RenderContext&    context,
-                                                                                                                tcu::TestContext&              testContext,
-                                                                                                                const tcu::Vec4&               scissorArea,
-                                                                                                                const tcu::Vec4&               renderArea,
-                                                                                                                PrimitiveType                  type,
-                                                                                                                int                                    primitiveCount,
+                                                               ScissorPrimitiveCase    (tcu::TestContext&              testCtx,
+                                                                                                                glu::RenderContext&    renderCtx,
                                                                                                                 const char*                    name,
-                                                                                                                const char*                    description);
+                                                                                                                const char*                    desc,
+                                                                                                                const Vec4&                    scissorArea,
+                                                                                                                const Vec4&                    renderArea,
+                                                                                                                PrimitiveType                  type,
+                                                                                                                int                                    primitiveCount);
        virtual                                         ~ScissorPrimitiveCase   (void){}
 
 protected:
-       virtual void                            render                                  (sglr::Context& context, const tcu::IVec4& viewport);
+       virtual void                            render                                  (GLuint program, const IVec4& viewport) const;
 
 private:
-       const tcu::Vec4                         m_renderArea;
+       const Vec4                                      m_renderArea;
        const PrimitiveType                     m_primitiveType;
        const int                                       m_primitiveCount;
 };
 
-ScissorPrimitiveCase::ScissorPrimitiveCase     (glu::RenderContext&    context,
-                                                                                        tcu::TestContext&              testContext,
-                                                                                        const tcu::Vec4&               scissorArea,
-                                                                                        const tcu::Vec4&               renderArea,
-                                                                                        PrimitiveType                  type,
-                                                                                        int                                    primitiveCount,
+ScissorPrimitiveCase::ScissorPrimitiveCase     (tcu::TestContext&              testCtx,
+                                                                                        glu::RenderContext&    renderCtx,
                                                                                         const char*                    name,
-                                                                                        const char*                    description)
-       : ScissorCase           (context, testContext, scissorArea, name, description)
+                                                                                        const char*                    desc,
+                                                                                        const Vec4&                    scissorArea,
+                                                                                        const Vec4&                    renderArea,
+                                                                                        PrimitiveType                  type,
+                                                                                        int                                    primitiveCount)
+       : ScissorCase           (testCtx, renderCtx, name, desc, scissorArea)
        , m_renderArea          (renderArea)
        , m_primitiveType       (type)
        , m_primitiveCount      (primitiveCount)
 {
 }
 
-void ScissorPrimitiveCase::render (sglr::Context& context, const tcu::IVec4& viewport)
+void ScissorPrimitiveCase::render (GLuint program, const IVec4&) const
 {
-       const tcu::Vec4                         red                             (0.6f, 0.1f, 0.1f, 1.0);
-
-       ScissorTestShader                       shader;
-       const int                                       width                   = viewport.w();
-       const int                                       height                  = viewport.z();
-       const deUint32                          shaderID                = context.createProgram(&shader);
-       const tcu::Vec4                         primitiveArea   (m_renderArea.x()*2.0f-1.0f,
+       const glw::Functions&           gl                              = m_renderCtx.getFunctions();
+       const Vec4                                      white                   (1.0f, 1.0f, 1.0f, 1.0);
+       const Vec4                                      primitiveArea   (m_renderArea.x()*2.0f-1.0f,
                                                                                                 m_renderArea.x()*2.0f-1.0f,
                                                                                                 m_renderArea.z()*2.0f,
                                                                                                 m_renderArea.w()*2.0f);
-       const tcu::IVec4                        scissorArea             (int(m_scissorArea.x()*width) + viewport.x(),
-                                                                                                int(m_scissorArea.y()*height) + viewport.y(),
-                                                                                                int(m_scissorArea.z()*width),
-                                                                                                int(m_scissorArea.w()*height));
 
        static const float quadPositions[] =
        {
@@ -408,26 +346,26 @@ void ScissorPrimitiveCase::render (sglr::Context& context, const tcu::IVec4& vie
                 0.5f,  0.5f
        };
 
-       const float*                            positionSet[]   = { pointPosition, linePositions, triPositions, quadPositions };
-       const int                                       vertexCountSet[]= { 1, 2, 3, 4 };
-       const int                                       indexCountSet[] = { 1, 2, 3, 6 };
+       const float*            positionSet[]   = { pointPosition, linePositions, triPositions, quadPositions };
+       const int                       vertexCountSet[]= { 1, 2, 3, 4 };
+       const int                       indexCountSet[] = { 1, 2, 3, 6 };
 
-       const deUint16                          baseIndices[]   = { 0, 1, 2, 2, 1, 3 };
-       const float*                            basePositions   = positionSet[m_primitiveType];
-       const int                                       vertexCount             = vertexCountSet[m_primitiveType];
-       const int                                       indexCount              = indexCountSet[m_primitiveType];
+       const deUint16          baseIndices[]   = { 0, 1, 2, 2, 1, 3 };
+       const float*            basePositions   = positionSet[m_primitiveType];
+       const int                       vertexCount             = vertexCountSet[m_primitiveType];
+       const int                       indexCount              = indexCountSet[m_primitiveType];
 
-       const float                                     scale                   = 1.44f/deFloatSqrt(float(m_primitiveCount)*2.0f);
-       std::vector<float>                      positions               (4*vertexCount*m_primitiveCount);
-       std::vector<deUint16>           indices                 (indexCount*m_primitiveCount);
-       de::Random                                      rng                             (1234);
+       const float                     scale                   = 1.44f/deFloatSqrt(float(m_primitiveCount)*2.0f); // Magic value to roughly fill the render area with primitives at a readable density
+       vector<float>           positions               (4*vertexCount*m_primitiveCount);
+       vector<deUint16>        indices                 (indexCount*m_primitiveCount);
+       de::Random                      rng                             (1234);
 
        for (int primNdx = 0; primNdx < m_primitiveCount; primNdx++)
        {
                const float dx = m_primitiveCount>1 ? rng.getFloat() : 0.0f;
                const float dy = m_primitiveCount>1 ? rng.getFloat() : 0.0f;
 
-               for (int vertNdx = 0; vertNdx<vertexCount; vertNdx++)
+               for (int vertNdx = 0; vertNdx < vertexCount; vertNdx++)
                {
                        const int ndx = primNdx*4*vertexCount + vertNdx*4;
                        positions[ndx+0] = (basePositions[vertNdx*2 + 0]*scale + dx)*primitiveArea.z() + primitiveArea.x();
@@ -440,129 +378,503 @@ void ScissorPrimitiveCase::render (sglr::Context& context, const tcu::IVec4& vie
                        indices[primNdx*indexCount + ndx] = baseIndices[ndx] + primNdx*vertexCount;
        }
 
-       // Enable scissor test.
-       context.enable(GL_SCISSOR_TEST);
-       context.scissor(scissorArea.x(), scissorArea.y(), scissorArea.z(), scissorArea.w());
-
-       shader.setColor(context, shaderID, red);
+       gl.uniform4fv(gl.getUniformLocation(program, "u_color"), 1, white.m_data);
 
        switch (m_primitiveType)
        {
-               case QUAD:                      // Fall-through, no real quads...
-               case TRIANGLE:          drawPrimitives(context, shaderID, GL_TRIANGLES, &positions[0], indexCount*m_primitiveCount, &indices[0]);               break;
-               case LINE:                      drawPrimitives(context, shaderID, GL_LINES,             &positions[0], indexCount*m_primitiveCount, &indices[0]);               break;
-               case POINT:                     drawPrimitives(context, shaderID, GL_POINTS,    &positions[0], indexCount*m_primitiveCount, &indices[0]);               break;
-               default:                        DE_ASSERT(false);                                                                                                                                                                                               break;
+               case TRIANGLE:  drawPrimitives(gl, program, GL_TRIANGLES,       positions, indices);    break;
+               case LINE:              drawPrimitives(gl, program, GL_LINES,           positions, indices);    break;
+               case POINT:             drawPrimitives(gl, program, GL_POINTS,          positions, indices);    break;
+               default:                DE_ASSERT(false);                                                                                                       break;
        }
-
-       context.disable(GL_SCISSOR_TEST);
 }
 
+// Test effect of scissor on default framebuffer clears
 class ScissorClearCase : public ScissorCase
 {
 public:
-                                                               ScissorClearCase                (glu::RenderContext&    context,
-                                                                                                                tcu::TestContext&              testContext,
-                                                                                                                const tcu::Vec4&               scissorArea,
-                                                                                                                deUint32                               clearMode,
-                                                                                                                const char*                    name,
-                                                                                                                const char*                    description);
-       virtual                                         ~ScissorClearCase               (void) {}
+                                       ScissorClearCase        (tcu::TestContext&              testCtx,
+                                                                                glu::RenderContext&    renderCtx,
+                                                                                const char*                    name,
+                                                                                const char*                    desc,
+                                                                                const Vec4&                    scissorArea,
+                                                                                deUint32                               clearMode);
+       virtual                 ~ScissorClearCase       (void) {}
 
-       virtual void                            init                                    (void);
+       virtual void    init                            (void);
 
 protected:
-       virtual void                            render                                  (sglr::Context& context, const tcu::IVec4& viewport);
+       virtual void    render                          (GLuint program, const IVec4& viewport) const;
 
 private:
-       const deUint32                          m_clearMode; //!< Combination of the flags accepted by glClear
+       const deUint32  m_clearMode; //!< Combination of the flags accepted by glClear
 };
 
-ScissorClearCase::ScissorClearCase     (glu::RenderContext&    context,
-                                                                        tcu::TestContext&              testContext,
-                                                                        const tcu::Vec4&               scissorArea,
-                                                                        deUint32                               clearMode,
+ScissorClearCase::ScissorClearCase     (tcu::TestContext&              testCtx,
+                                                                        glu::RenderContext&    renderCtx,
                                                                         const char*                    name,
-                                                                        const char*                    description)
-       : ScissorCase   (context, testContext, scissorArea, name, description)
+                                                                        const char*                    desc,
+                                                                        const Vec4&                    scissorArea,
+                                                                        deUint32                               clearMode)
+       : ScissorCase   (testCtx, renderCtx, name, desc, scissorArea)
        , m_clearMode   (clearMode)
 {
 }
 
 void ScissorClearCase::init (void)
 {
-       if ((m_clearMode & GL_DEPTH_BUFFER_BIT) && m_renderContext.getRenderTarget().getDepthBits()==0)
+       if ((m_clearMode & GL_DEPTH_BUFFER_BIT) && m_renderCtx.getRenderTarget().getDepthBits() == 0)
                throw tcu::NotSupportedError("Cannot clear depth; no depth buffer present", "", __FILE__, __LINE__);
-       else if ((m_clearMode & GL_STENCIL_BUFFER_BIT) && m_renderContext.getRenderTarget().getStencilBits()==0)
+       else if ((m_clearMode & GL_STENCIL_BUFFER_BIT) && m_renderCtx.getRenderTarget().getStencilBits() == 0)
                throw tcu::NotSupportedError("Cannot clear stencil; no stencil buffer present", "", __FILE__, __LINE__);
 }
 
-void ScissorClearCase::render (sglr::Context& context, const tcu::IVec4& viewport)
+void ScissorClearCase::render (GLuint program, const IVec4&) const
 {
-       ScissorTestShader                       shader;
-       const deUint32                          shaderID                = context.createProgram(&shader);
-       const int                                       width                   = viewport.z();
-       const int                                       height                  = viewport.w();
-       const tcu::Vec4                         green                   (0.1f, 0.6f, 0.1f, 1.0);
-       const tcu::IVec4                        scissorArea             (int(m_scissorArea.x()*width) + viewport.x(),
-                                                                                                int(m_scissorArea.y()*height) + viewport.y(),
-                                                                                                int(m_scissorArea.z()*width),
-                                                                                                int(m_scissorArea.w()*height));
+       const glw::Functions&   gl              = m_renderCtx.getFunctions();
+       const Vec4                              white   (1.0f, 1.0f, 1.0f, 1.0);
 
-       context.clearColor(0.125f, 0.25f, 0.5f, 1.0f);
-       context.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
-       context.clearColor(0.6f, 0.1f, 0.1f, 1.0);
-
-       context.enable(GL_SCISSOR_TEST);
-       context.scissor(scissorArea.x(), scissorArea.y(), scissorArea.z(), scissorArea.w());
-
-       context.clearDepthf(0.0f);
+       gl.clearColor(0.6f, 0.1f, 0.1f, 1.0);
+       gl.clearDepthf(0.0f);
 
        if (m_clearMode & GL_DEPTH_BUFFER_BIT)
        {
-               context.enable(GL_DEPTH_TEST);
-               context.depthFunc(GL_GREATER);
+               gl.enable(GL_DEPTH_TEST);
+               gl.depthFunc(GL_GREATER);
        }
 
        if (m_clearMode & GL_STENCIL_BUFFER_BIT)
        {
-               context.clearStencil(123);
-               context.enable(GL_STENCIL_TEST);
-               context.stencilFunc(GL_EQUAL, 123, ~0u);
+               gl.clearStencil(123);
+               gl.enable(GL_STENCIL_TEST);
+               gl.stencilFunc(GL_EQUAL, 123, ~0u);
        }
 
        if (m_clearMode & GL_COLOR_BUFFER_BIT)
-               context.clearColor(0.1f, 0.6f, 0.1f, 1.0);
+               gl.clearColor(0.1f, 0.6f, 0.1f, 1.0);
 
-       context.clear(m_clearMode);
-       context.disable(GL_SCISSOR_TEST);
+       gl.clear(m_clearMode);
+       gl.disable(GL_SCISSOR_TEST);
 
-       shader.setColor(context, shaderID, green);
+       gl.uniform4fv(gl.getUniformLocation(program, "u_color"), 1, white.getPtr());
 
        if (!(m_clearMode & GL_COLOR_BUFFER_BIT))
-               sglr::drawQuad(context, shaderID, tcu::Vec3(-1.0f, -1.0f, 0.5f), tcu::Vec3(1.0f, 1.0f, 0.5f));
+               drawQuad(gl, program, Vec3(-1.0f, -1.0f, 0.5f), Vec3(1.0f, 1.0f, 0.5f));
+
+       gl.disable(GL_DEPTH_TEST);
+       gl.disable(GL_STENCIL_TEST);
+}
+
+class FramebufferBlitCase : public ScissorCase
+{
+public:
+                                       FramebufferBlitCase             (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* desc, const Vec4& scissorArea);
+       virtual                 ~FramebufferBlitCase    (void) {}
+
+       virtual void    init                                    (void);
+       virtual void    deinit                                  (void);
+
+protected:
+       typedef de::MovePtr<glu::Framebuffer> FramebufferP;
+
+       enum {SIZE = 64};
+
+       virtual void    render                                  (GLuint program, const IVec4& viewport) const;
+
+       FramebufferP    m_fbo;
+};
+
+FramebufferBlitCase::FramebufferBlitCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* desc, const Vec4& scissorArea)
+       : ScissorCase(testCtx, renderCtx, name, desc, scissorArea)
+{
+}
 
-       context.disable(GL_DEPTH_TEST);
-       context.disable(GL_STENCIL_TEST);
+void FramebufferBlitCase::init (void)
+{
+       if (m_renderCtx.getRenderTarget().getNumSamples())
+               throw tcu::NotSupportedError("Cannot blit to multisampled framebuffer", "", __FILE__, __LINE__);
+
+       const glw::Functions&   gl                      = m_renderCtx.getFunctions();
+       const glu::Renderbuffer colorbuf        (gl);
+       const tcu::Vec4                 clearColor      (1.0f, 0.5, 0.125f, 1.0f);
+
+       m_fbo = FramebufferP(new glu::Framebuffer(gl));
+
+       gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, **m_fbo);
+
+       gl.bindRenderbuffer(GL_RENDERBUFFER, *colorbuf);
+       gl.renderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, SIZE, SIZE);
+       gl.framebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, *colorbuf);
+
+       gl.clearBufferfv(GL_COLOR, 0, clearColor.getPtr());
+       gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, m_renderCtx.getDefaultFramebuffer());
+}
+
+void FramebufferBlitCase::deinit (void)
+{
+       m_fbo.clear();
+}
+
+void FramebufferBlitCase::render(GLuint program, const IVec4& viewport) const
+{
+       const glw::Functions&   gl                                      = m_renderCtx.getFunctions();
+
+       const int                               width                           = viewport.z();
+       const int                               height                          = viewport.w();
+       const deInt32                   defaultFramebuffer      = m_renderCtx.getDefaultFramebuffer();
+
+       DE_UNREF(program);
+
+       // blit to default framebuffer
+       gl.bindFramebuffer(GL_READ_FRAMEBUFFER, **m_fbo);
+       gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, defaultFramebuffer);
+
+       gl.blitFramebuffer(0, 0, SIZE, SIZE, viewport.x(), viewport.y(), viewport.x() + width, viewport.y() + height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
+
+       gl.bindFramebuffer(GL_READ_FRAMEBUFFER, defaultFramebuffer);
+}
+
+struct BufferFmtDesc
+{
+       tcu::TextureFormat      texFmt;
+       GLenum                          colorFmt;
+};
+
+struct Color
+{
+       enum Type {FLOAT, INT, UINT};
+
+       Type type;
+
+       union
+       {
+               float           f[4];
+               deInt32         i[4];
+               deUint32        u[4];
+       };
+
+       Color(const float f_[4])    : type(FLOAT) { f[0] = f_[0]; f[1] = f_[1]; f[2] = f_[2]; f[3] = f_[3]; }
+       Color(const deInt32 i_[4])  : type(INT)   { i[0] = i_[0]; i[1] = i_[1]; i[2] = i_[2]; i[3] = i_[3]; }
+       Color(const deUint32 u_[4]) : type(UINT)  { u[0] = u_[0]; u[1] = u_[1]; u[2] = u_[2]; u[3] = u_[3]; }
+};
+
+class FramebufferClearCase : public tcu::TestCase
+{
+public:
+                                                       FramebufferClearCase    (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* desc, ClearType clearType);
+       virtual                                 ~FramebufferClearCase   (void) {}
+
+       virtual IterateResult   iterate                                 (void);
+
+private:
+       static void                             clearBuffers                    (const glw::Functions& gl, Color color, float depth, int stencil);
+       static Color                    getBaseColor                    (const BufferFmtDesc& bufferFmt);
+       static Color                    getMainColor                    (const BufferFmtDesc& bufferFmt);
+       static BufferFmtDesc    getBufferFormat                 (ClearType type);
+
+       virtual void                    render                                  (GLuint program) const;
+
+       glu::RenderContext&             m_renderCtx;
+       const ClearType                 m_clearType;
+};
+
+FramebufferClearCase::FramebufferClearCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* desc, ClearType clearType)
+       : tcu::TestCase (testCtx, name, desc)
+       , m_renderCtx   (renderCtx)
+       , m_clearType   (clearType)
+{
+}
+
+void FramebufferClearCase::clearBuffers (const glw::Functions& gl, Color color, float depth, int stencil)
+{
+       switch(color.type)
+       {
+               case Color::FLOAT:      gl.clearBufferfv (GL_COLOR, 0, color.f); break;
+               case Color::INT:        gl.clearBufferiv (GL_COLOR, 0, color.i); break;
+               case Color::UINT:       gl.clearBufferuiv(GL_COLOR, 0, color.u); break;
+               default:
+                       DE_ASSERT(false);
+       }
+
+       gl.clearBufferfv(GL_DEPTH, 0, &depth);
+       gl.clearBufferiv(GL_STENCIL, 0, &stencil);
+}
+
+FramebufferClearCase::IterateResult FramebufferClearCase::iterate (void)
+{
+       TestLog&                                        log                             = m_testCtx.getLog();
+       const glw::Functions&           gl                              = m_renderCtx.getFunctions();
+       const glu::ShaderProgram        shader                  (m_renderCtx, genShaders(glu::getContextTypeGLSLVersion(m_renderCtx.getType())));
+
+       const glu::Framebuffer          fbo                             (gl);
+       const glu::Renderbuffer         colorbuf                (gl);
+       const glu::Renderbuffer         depthbuf                (gl);
+
+       const BufferFmtDesc                     bufferFmt               = getBufferFormat(m_clearType);
+       const Color                                     baseColor               = getBaseColor(bufferFmt);
+
+       const int                                       width                   = 64;
+       const int                                       height                  = 64;
+
+       const IVec4                                     scissorArea             (8, 8, 48, 48);
+
+       vector<deUint8>                         refData                 (width*height*bufferFmt.texFmt.getPixelSize());
+       vector<deUint8>                         resData                 (width*height*bufferFmt.texFmt.getPixelSize());
+
+       tcu::PixelBufferAccess          refAccess               (bufferFmt.texFmt, width, height, 1, &refData[0]);
+       tcu::PixelBufferAccess          resAccess               (bufferFmt.texFmt, width, height, 1, &resData[0]);
+
+       if (!shader.isOk())
+       {
+               log << shader;
+               m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Shader compile/link failed");
+               return STOP;
+       }
+
+       gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, *fbo);
+       gl.bindFramebuffer(GL_READ_FRAMEBUFFER, *fbo);
+
+       // Color
+       gl.bindRenderbuffer(GL_RENDERBUFFER, *colorbuf);
+       gl.renderbufferStorage(GL_RENDERBUFFER, bufferFmt.colorFmt, width, height);
+       gl.framebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, *colorbuf);
+
+       // Depth/stencil
+       gl.bindRenderbuffer(GL_RENDERBUFFER, *depthbuf);
+       gl.renderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
+       gl.framebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, *depthbuf);
+
+       log << TestLog::Message << "Scissor area is " << scissorArea << TestLog::EndMessage;
+
+       // Render reference
+       {
+               log << TestLog::Message << "Rendering reference (scissors disabled)" << TestLog::EndMessage;
+
+               gl.useProgram(shader.getProgram());
+               gl.viewport(0, 0, width, height);
+
+               gl.disable(GL_DEPTH_TEST);
+               gl.disable(GL_STENCIL_TEST);
+               gl.disable(GL_SCISSOR_TEST);
+
+               clearBuffers(gl, baseColor, 1.0f, 0);
+
+               render(shader.getProgram());
+
+               glu::readPixels(m_renderCtx, 0, 0, refAccess);
+               GLU_CHECK_ERROR(gl.getError());
+       }
+
+       // Render result
+       {
+               log << TestLog::Message << "Rendering result (scissors enabled)" << TestLog::EndMessage;
+
+               gl.useProgram(shader.getProgram());
+               gl.viewport(0, 0, width, height);
+
+               gl.disable(GL_DEPTH_TEST);
+               gl.disable(GL_STENCIL_TEST);
+               gl.disable(GL_SCISSOR_TEST);
+
+               clearBuffers(gl, baseColor, 1.0f, 0);
+
+               gl.enable(GL_SCISSOR_TEST);
+               gl.scissor(scissorArea.x(), scissorArea.y(), scissorArea.z(), scissorArea.w());
+
+               render(shader.getProgram());
+
+               glu::readPixels(m_renderCtx, 0, 0, resAccess);
+               GLU_CHECK_ERROR(gl.getError());
+       }
+
+       {
+               bool resultOk = false;
+
+               switch (baseColor.type)
+               {
+                       case Color::FLOAT:
+                               clearEdges(refAccess, Vec4(baseColor.f[0], baseColor.f[1], baseColor.f[2], baseColor.f[3]), scissorArea);
+                               resultOk = tcu::floatThresholdCompare(log, "ComparisonResult", "Image comparison result", refAccess, resAccess, Vec4(0.02f, 0.02f, 0.02f, 0.02f), tcu::COMPARE_LOG_RESULT);
+                               break;
+
+                       case Color::INT:
+                               clearEdges(refAccess, IVec4(baseColor.i[0], baseColor.i[1], baseColor.i[2], baseColor.i[3]), scissorArea);
+                               resultOk = tcu::intThresholdCompare(log, "ComparisonResult", "Image comparison result", refAccess, resAccess, UVec4(2, 2, 2, 2), tcu::COMPARE_LOG_RESULT);
+                               break;
+
+                       case Color::UINT:
+                               clearEdges(refAccess, UVec4(baseColor.u[0], baseColor.u[1], baseColor.u[2], baseColor.u[3]), scissorArea);
+                               resultOk = tcu::intThresholdCompare(log, "ComparisonResult", "Image comparison result", refAccess, resAccess, UVec4(2, 2, 2, 2), tcu::COMPARE_LOG_RESULT);
+                               break;
+               }
+
+               if (resultOk)
+                       m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
+               else
+                       m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
+       }
+
+       return STOP;
+}
+
+Color FramebufferClearCase::getBaseColor (const BufferFmtDesc& bufferFmt)
+{
+       const float             f[4] = {0.125f, 0.25f, 0.5f, 1.0f};
+       const deInt32   i[4] = {0, 0, 0, 0};
+       const deUint32  u[4] = {0, 0, 0, 0};
+
+       switch(bufferFmt.colorFmt)
+       {
+               case GL_RGBA8:          return Color(f);
+               case GL_RGBA8I:         return Color(i);
+               case GL_RGBA8UI:        return Color(u);
+               default:
+                       DE_ASSERT(false);
+       }
+
+       return Color(f);
+}
+
+Color FramebufferClearCase::getMainColor (const BufferFmtDesc& bufferFmt)
+{
+       const float             f[4] = {1.0f, 1.0f, 0.5f, 1.0f};
+       const deInt32   i[4] = {127, -127, 0, 127};
+       const deUint32  u[4] = {255, 255, 0, 255};
+
+       switch(bufferFmt.colorFmt)
+       {
+               case GL_RGBA8:          return Color(f);
+               case GL_RGBA8I:         return Color(i);
+               case GL_RGBA8UI:        return Color(u);
+               default:
+                       DE_ASSERT(false);
+       }
+
+       return Color(f);
+}
+
+BufferFmtDesc FramebufferClearCase::getBufferFormat (ClearType type)
+{
+       BufferFmtDesc retval;
+
+       switch (type)
+       {
+               case CLEAR_COLOR_FLOAT:
+                       retval.colorFmt = GL_RGBA16F;
+                       retval.texFmt   = tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::HALF_FLOAT);
+                       DE_ASSERT(!"Floating point clear not implemented");// \todo [2014-1-23 otto] pixel read format & type, nothing guaranteed, need extension...
+                       break;
+
+               case CLEAR_COLOR_INT:
+                       retval.colorFmt = GL_RGBA8I;
+                       retval.texFmt   = tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::SIGNED_INT32);
+                       break;
+
+               case CLEAR_COLOR_UINT:
+                       retval.colorFmt = GL_RGBA8UI;
+                       retval.texFmt   = tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNSIGNED_INT32);
+                       break;
+
+               default:
+                       retval.colorFmt = GL_RGBA8;
+                       retval.texFmt   = tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8);
+                       break;
+       }
+
+       return retval;
+}
+
+void FramebufferClearCase::render (GLuint program) const
+{
+       const glw::Functions&   gl                                      = m_renderCtx.getFunctions();
+
+       const BufferFmtDesc             bufferFmt                       = getBufferFormat(m_clearType);
+       const Color                             clearColor                      = getMainColor(bufferFmt);
+
+       const int                               clearStencil            = 123;
+       const float                             clearDepth                      = 0.5f;
+
+       switch (m_clearType)
+       {
+               case CLEAR_COLOR_FIXED:         gl.clearBufferfv (GL_COLOR, 0, clearColor.f);                                           break;
+               case CLEAR_COLOR_FLOAT:         gl.clearBufferfv (GL_COLOR, 0, clearColor.f);                                           break;
+               case CLEAR_COLOR_INT:           gl.clearBufferiv (GL_COLOR, 0, clearColor.i);                                           break;
+               case CLEAR_COLOR_UINT:          gl.clearBufferuiv(GL_COLOR, 0, clearColor.u);                                           break;
+               case CLEAR_DEPTH:                       gl.clearBufferfv (GL_DEPTH, 0, &clearDepth);                                            break;
+               case CLEAR_STENCIL:                     gl.clearBufferiv (GL_STENCIL, 0, &clearStencil);                                        break;
+               case CLEAR_DEPTH_STENCIL:       gl.clearBufferfi (GL_DEPTH_STENCIL, 0, clearDepth, clearStencil);       break;
+
+               default:
+                       DE_ASSERT(false);
+       }
+
+       const bool useDepth             = (m_clearType == CLEAR_DEPTH   || m_clearType == CLEAR_DEPTH_STENCIL);
+       const bool useStencil   = (m_clearType == CLEAR_STENCIL || m_clearType == CLEAR_DEPTH_STENCIL);
+
+       // Render something to expose changes to depth/stencil buffer
+       if (useDepth || useStencil)
+       {
+               if (useDepth)
+                       gl.enable(GL_DEPTH_TEST);
+
+               if (useStencil)
+                       gl.enable(GL_STENCIL_TEST);
+
+               gl.stencilFunc(GL_EQUAL, clearStencil, ~0u);
+               gl.depthFunc(GL_GREATER);
+               gl.disable(GL_SCISSOR_TEST);
+
+               gl.uniform4fv(gl.getUniformLocation(program, "u_color"), 1, clearColor.f);
+               drawQuad(gl, program, tcu::Vec3(-1.0f, -1.0f, 0.6f), tcu::Vec3(1.0f, 1.0f, 0.6f));
+       }
+}
+
+} // Anonymous
+
+namespace ScissorTestInternal
+{
+
+tcu::TestNode* createPrimitiveTest (tcu::TestContext&  testCtx,
+                                                                       glu::RenderContext&     renderCtx,
+                                                                       const char*                     name,
+                                                                       const char*                     desc,
+                                                                       const Vec4&                     scissorArea,
+                                                                       const Vec4&                     renderArea,
+                                                                       PrimitiveType           type,
+                                                                       int                                     primitiveCount)
+{
+       return new ScissorPrimitiveCase(testCtx, renderCtx, name, desc, scissorArea, renderArea, type, primitiveCount);
+}
+
+tcu::TestNode* createClearTest (tcu::TestContext&      testCtx,
+                                                               glu::RenderContext&     renderCtx,
+                                                               const char*                     name,
+                                                               const char*                     desc,
+                                                               const Vec4&                     scissorArea,
+                                                               deUint32                        clearMode)
+{
+       return new ScissorClearCase(testCtx, renderCtx, name, desc, scissorArea, clearMode);
 }
 
-tcu::TestNode* ScissorCase::createPrimitiveTest (glu::RenderContext&   context,
-                                                                                                tcu::TestContext&              testContext,
-                                                                                                const tcu::Vec4&               scissorArea,
-                                                                                                const tcu::Vec4&               renderArea,
-                                                                                                PrimitiveType                  type,
-                                                                                                int                                    primitiveCount,
-                                                                                                const char*                    name,
-                                                                                                const char*                    description)
+tcu::TestNode* createFramebufferClearTest (tcu::TestContext&   testCtx,
+                                                                                  glu::RenderContext&  renderCtx,
+                                                                                  const char*                  name,
+                                                                                  const char*                  desc,
+                                                                                  ClearType                    clearType)
 {
-       return new Functional::ScissorPrimitiveCase(context, testContext, scissorArea, renderArea, type, primitiveCount, name, description);
+       return new FramebufferClearCase(testCtx, renderCtx, name, desc, clearType);
 }
 
-tcu::TestNode* ScissorCase::createClearTest (glu::RenderContext& context, tcu::TestContext& testContext, const tcu::Vec4& scissorArea, deUint32 clearMode, const char* name, const char* description)
+tcu::TestNode* createFramebufferBlitTest (tcu::TestContext&            testCtx,
+                                                                                 glu::RenderContext&   renderCtx,
+                                                                                 const char*                   name,
+                                                                                 const char*                   desc,
+                                                                                 const Vec4&                   scissorArea)
 {
-       return new Functional::ScissorClearCase(context, testContext, scissorArea, clearMode, name, description);
+       return new FramebufferBlitCase(testCtx, renderCtx, name, desc, scissorArea);
 }
 
+} // ScissorTestInternal
 } // Functional
 } // gls
 } // deqp
index e3b853c..e1b1b81 100644 (file)
@@ -45,63 +45,62 @@ namespace gls
 {
 namespace Functional
 {
-
-// Wrapper class, provides iterator & reporting logic
-class ScissorCase : public tcu::TestCase
+namespace ScissorTestInternal
 {
-public:
-       enum PrimitiveType
-       {
-               POINT = 0,
-               LINE,
-               TRIANGLE,
-               QUAD,
-
-               PRIMITIVETYPE_LAST
-       };
-
-                                                               ScissorCase                             (glu::RenderContext& context, tcu::TestContext& testContext, const tcu::Vec4& scissorArea, const char* name, const char* description);
-       virtual                                         ~ScissorCase                    (void) {}
-
-       virtual IterateResult           iterate                                 (void);
 
-       // Areas are of the form (x,y,widht,height) in the range [0,1]. Vertex counts 1-3 result in single point/line/tri, higher ones result in the indicated number of quads in pseudorandom locations.
-       static tcu::TestNode*           createPrimitiveTest             (glu::RenderContext&    context,
-                                                                                                                tcu::TestContext&              testContext,
-                                                                                                                const tcu::Vec4&               scissorArea,
-                                                                                                                const tcu::Vec4&               renderArea,
-                                                                                                                PrimitiveType                  type,
-                                                                                                                int                                    primitiveCount,
-                                                                                                                const char*                    name,
-                                                                                                                const char*                    description);
-       static tcu::TestNode*           createClearTest                 (glu::RenderContext&    context,
-                                                                                                                tcu::TestContext&              testContext,
-                                                                                                                const tcu::Vec4&               scissorArea,
-                                                                                                                deUint32                               clearMode,
-                                                                                                                const char*                    name,
-                                                                                                                const char*                    description);
+using tcu::Vec4;
 
-protected:
-       virtual void                            render                                  (sglr::Context& context, const tcu::IVec4& viewport) = 0;
+enum PrimitiveType
+{
+       POINT = 0,
+       LINE,
+       TRIANGLE,
 
-       glu::RenderContext&                     m_renderContext;
-       const tcu::Vec4                         m_scissorArea;
+       PRIMITIVETYPE_LAST
 };
 
-class ScissorTestShader : public sglr::ShaderProgram
+enum ClearType
 {
-public:
-                                                               ScissorTestShader       (void);
-
-       void                                            setColor                        (sglr::Context& ctx, deUint32 programID, const tcu::Vec4& color);
-
-private:
-       void                                            shadeVertices           (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const;
-       void                                            shadeFragments          (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const;
-
-       const sglr::UniformSlot&        u_color;
+       CLEAR_COLOR_FIXED = 0,
+       CLEAR_COLOR_FLOAT,
+       CLEAR_COLOR_INT,
+       CLEAR_COLOR_UINT,
+       CLEAR_DEPTH,
+       CLEAR_STENCIL,
+       CLEAR_DEPTH_STENCIL,
+
+       CLEAR_LAST
 };
 
+// Areas are of the form (x,y,widht,height) in the range [0,1]
+tcu::TestNode* createPrimitiveTest     (tcu::TestContext&              testCtx,
+                                                                        glu::RenderContext&    renderCtx,
+                                                                        const char*                    name,
+                                                                        const char*                    desc,
+                                                                        const Vec4&                    scissorArea,
+                                                                        const Vec4&                    renderArea,
+                                                                        PrimitiveType                  type,
+                                                                        int                                    primitiveCount);
+tcu::TestNode* createClearTest         (tcu::TestContext&              testCtx,
+                                                                        glu::RenderContext&    renderCtx,
+                                                                        const char*                    name,
+                                                                        const char*                    desc,
+                                                                        const Vec4&                    scissorArea,
+                                                                        deUint32                               clearMode);
+
+tcu::TestNode* createFramebufferClearTest (tcu::TestContext&   testCtx,
+                                                                                  glu::RenderContext&  renderCtx,
+                                                                                  const char*                  name,
+                                                                                  const char*                  desc,
+                                                                                  ClearType                    clearType);
+
+tcu::TestNode* createFramebufferBlitTest (tcu::TestContext&            testCtx,
+                                                                                 glu::RenderContext&   renderCtx,
+                                                                                 const char*                   name,
+                                                                                 const char*                   desc,
+                                                                                 const Vec4&                   scissorArea);
+
+} // ScissorTestInternal
 } // Functional
 } // gls
 } // deqp
index fd6ce61..9597f63 100644 (file)
@@ -563,20 +563,29 @@ VertexShaderExecutor::VertexShaderExecutor (const glu::RenderContext& renderCtx,
 
 // GeometryShaderExecutor
 
-class GeometryShaderExecutor : public VertexProcessorExecutor
+class CheckGeomSupport
+{
+public:
+       inline CheckGeomSupport (const glu::RenderContext& renderCtx)
+       {
+               if (renderCtx.getType().getAPI().getProfile() == glu::PROFILE_ES)
+                       checkExtension(renderCtx, "GL_EXT_geometry_shader");
+       }
+};
+
+class GeometryShaderExecutor : private CheckGeomSupport, public VertexProcessorExecutor
 {
 public:
                                                                GeometryShaderExecutor  (const glu::RenderContext& renderCtx, const ShaderSpec& shaderSpec);
 };
 
 GeometryShaderExecutor::GeometryShaderExecutor (const glu::RenderContext& renderCtx, const ShaderSpec& shaderSpec)
-       : VertexProcessorExecutor       (renderCtx, shaderSpec,
+       : CheckGeomSupport                      (renderCtx)
+       , VertexProcessorExecutor       (renderCtx, shaderSpec,
                                                                 glu::ProgramSources() << glu::VertexSource(generatePassthroughVertexShader(shaderSpec, "", "geom_"))
                                                                                                           << glu::GeometrySource(generateGeometryShader(shaderSpec))
                                                                                                           << glu::FragmentSource(generateEmptyFragmentSource(shaderSpec.version)))
 {
-       if (renderCtx.getType().getAPI() == glu::ApiType::es(3,1))
-               checkExtension(renderCtx, "GL_EXT_geometry_shader");
 }
 
 // FragmentShaderExecutor
@@ -1270,9 +1279,19 @@ static std::string generateVertexShaderForTess (glu::GLSLVersion version)
        return src.str();
 }
 
+class CheckTessSupport
+{
+public:
+       inline CheckTessSupport (const glu::RenderContext& renderCtx)
+       {
+               if (renderCtx.getType().getAPI().getProfile() == glu::PROFILE_ES)
+                       checkExtension(renderCtx, "GL_EXT_tessellation_shader");
+       }
+};
+
 // TessControlExecutor
 
-class TessControlExecutor : public BufferIoExecutor
+class TessControlExecutor : private CheckTessSupport, public BufferIoExecutor
 {
 public:
                                                TessControlExecutor                     (const glu::RenderContext& renderCtx, const ShaderSpec& shaderSpec);
@@ -1337,14 +1356,13 @@ static std::string generateEmptyTessEvalShader (glu::GLSLVersion version)
 }
 
 TessControlExecutor::TessControlExecutor (const glu::RenderContext& renderCtx, const ShaderSpec& shaderSpec)
-       : BufferIoExecutor      (renderCtx, shaderSpec, glu::ProgramSources()
+       : CheckTessSupport      (renderCtx)
+       , BufferIoExecutor      (renderCtx, shaderSpec, glu::ProgramSources()
                                                        << glu::VertexSource(generateVertexShaderForTess(shaderSpec.version))
                                                        << glu::TessellationControlSource(generateTessControlShader(shaderSpec))
                                                        << glu::TessellationEvaluationSource(generateEmptyTessEvalShader(shaderSpec.version))
                                                        << glu::FragmentSource(generateEmptyFragmentSource(shaderSpec.version)))
 {
-       if (renderCtx.getType().getAPI() == glu::ApiType::es(3,1))
-               checkExtension(renderCtx, "GL_EXT_tessellation_shader");
 }
 
 TessControlExecutor::~TessControlExecutor (void)
@@ -1375,7 +1393,7 @@ void TessControlExecutor::execute (int numValues, const void* const* inputs, voi
 
 // TessEvaluationExecutor
 
-class TessEvaluationExecutor : public BufferIoExecutor
+class TessEvaluationExecutor : private CheckTessSupport, public BufferIoExecutor
 {
 public:
                                                TessEvaluationExecutor  (const glu::RenderContext& renderCtx, const ShaderSpec& shaderSpec);
@@ -1441,14 +1459,13 @@ std::string TessEvaluationExecutor::generateTessEvalShader (const ShaderSpec& sh
 }
 
 TessEvaluationExecutor::TessEvaluationExecutor (const glu::RenderContext& renderCtx, const ShaderSpec& shaderSpec)
-       : BufferIoExecutor      (renderCtx, shaderSpec, glu::ProgramSources()
+       : CheckTessSupport      (renderCtx)
+       , BufferIoExecutor      (renderCtx, shaderSpec, glu::ProgramSources()
                                                        << glu::VertexSource(generateVertexShaderForTess(shaderSpec.version))
                                                        << glu::TessellationControlSource(generatePassthroughTessControlShader(shaderSpec.version))
                                                        << glu::TessellationEvaluationSource(generateTessEvalShader(shaderSpec))
                                                        << glu::FragmentSource(generateEmptyFragmentSource(shaderSpec.version)))
 {
-       if (renderCtx.getType().getAPI() == glu::ApiType::es(3,1))
-               checkExtension(renderCtx, "GL_EXT_tessellation_shader");
 }
 
 TessEvaluationExecutor::~TessEvaluationExecutor (void)
index 914008b..cae9d87 100644 (file)
@@ -106,7 +106,7 @@ static tcu::Texture1DView getSubView (const tcu::Texture1DView& view, int baseLe
 {
        const int       clampedBase     = de::clamp(baseLevel, 0, view.getNumLevels()-1);
        const int       clampedMax      = de::clamp(maxLevel, clampedBase, view.getNumLevels()-1);
-       const int       numLevels       = de::min(clampedMax-clampedBase+1, view.getNumLevels()-clampedBase);
+       const int       numLevels       = clampedMax-clampedBase+1;
        return tcu::Texture1DView(numLevels, view.getLevels()+clampedBase);
 }
 
@@ -114,7 +114,7 @@ static tcu::Texture2DView getSubView (const tcu::Texture2DView& view, int baseLe
 {
        const int       clampedBase     = de::clamp(baseLevel, 0, view.getNumLevels()-1);
        const int       clampedMax      = de::clamp(maxLevel, clampedBase, view.getNumLevels()-1);
-       const int       numLevels       = de::min(clampedMax-clampedBase+1, view.getNumLevels()-clampedBase);
+       const int       numLevels       = clampedMax-clampedBase+1;
        return tcu::Texture2DView(numLevels, view.getLevels()+clampedBase);
 }
 
@@ -122,7 +122,7 @@ static tcu::TextureCubeView getSubView (const tcu::TextureCubeView& view, int ba
 {
        const int                                                       clampedBase     = de::clamp(baseLevel, 0, view.getNumLevels()-1);
        const int                                                       clampedMax      = de::clamp(maxLevel, clampedBase, view.getNumLevels()-1);
-       const int                                                       numLevels       = de::min(clampedMax-clampedBase+1, view.getNumLevels()-clampedBase);
+       const int                                                       numLevels       = clampedMax-clampedBase+1;
        const tcu::ConstPixelBufferAccess*      levels[tcu::CUBEFACE_LAST];
 
        for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
@@ -135,10 +135,18 @@ static tcu::Texture3DView getSubView (const tcu::Texture3DView& view, int baseLe
 {
        const int       clampedBase     = de::clamp(baseLevel, 0, view.getNumLevels()-1);
        const int       clampedMax      = de::clamp(maxLevel, clampedBase, view.getNumLevels()-1);
-       const int       numLevels       = de::min(clampedMax-clampedBase+1, view.getNumLevels()-clampedBase);
+       const int       numLevels       = clampedMax-clampedBase+1;
        return tcu::Texture3DView(numLevels, view.getLevels()+clampedBase);
 }
 
+static tcu::TextureCubeArrayView getSubView (const tcu::TextureCubeArrayView& view, int baseLevel, int maxLevel)
+{
+       const int       clampedBase     = de::clamp(baseLevel, 0, view.getNumLevels()-1);
+       const int       clampedMax      = de::clamp(maxLevel, clampedBase, view.getNumLevels()-1);
+       const int       numLevels       = clampedMax-clampedBase+1;
+       return tcu::TextureCubeArrayView(numLevels, view.getLevels()+clampedBase);
+}
+
 inline float linearInterpolate (float t, float minVal, float maxVal)
 {
        return minVal + (maxVal - minVal) * t;
@@ -904,7 +912,7 @@ static void sampleTexture (const SurfaceAccess& dst, const tcu::TextureCubeArray
                                                                         triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
                                                                         triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx));
 
-                       const float             lod                     = de::clamp(computeCubeLodFromDerivates(params.lodMode, coord, coordDx, coordDy, src.getWidth()) + lodBias, params.minLod, params.maxLod);
+                       const float             lod             = de::clamp(computeCubeLodFromDerivates(params.lodMode, coord, coordDx, coordDy, src.getSize()) + lodBias, params.minLod, params.maxLod);
 
                        dst.setPixel(execSample(src, params, coord.x(), coord.y(), coord.z(), coordQ, lod) * params.colorScale + params.colorBias, px, py);
                }
@@ -1084,6 +1092,7 @@ glu::ShaderProgram* ProgramLibrary::getProgram (Program program)
 
        bool    is3D            = de::inRange<int>(program, PROGRAM_3D_FLOAT, PROGRAM_3D_UINT_BIAS);
        bool    isCubeArray     = de::inRange<int>(program, PROGRAM_CUBE_ARRAY_FLOAT, PROGRAM_CUBE_ARRAY_SHADOW);
+       bool    isBuffer        = de::inRange<int>(program, PROGRAM_BUFFER_FLOAT, PROGRAM_BUFFER_UINT);
 
        if (m_glslVersion == glu::GLSL_VERSION_100_ES)
        {
@@ -1096,11 +1105,16 @@ glu::ShaderProgram* ProgramLibrary::getProgram (Program program)
        }
        else if (m_glslVersion == glu::GLSL_VERSION_300_ES || m_glslVersion == glu::GLSL_VERSION_310_ES || m_glslVersion == glu::GLSL_VERSION_330)
        {
-               const string version    = glu::getGLSLVersionDeclaration(m_glslVersion);
-               const string ext                = (isCubeArray && glu::glslVersionIsES(m_glslVersion)) ? "\n#extension GL_EXT_texture_cube_map_array : require" : "";
+               const string    version = glu::getGLSLVersionDeclaration(m_glslVersion);
+               const char*             ext             = DE_NULL;
+
+               if (isCubeArray && glu::glslVersionIsES(m_glslVersion))
+                       ext = "GL_EXT_texture_cube_map_array";
+               else if (isBuffer && glu::glslVersionIsES(m_glslVersion))
+                       ext = "GL_EXT_texture_buffer";
 
-               params["FRAG_HEADER"]   = version + ext + "\nlayout(location = 0) out mediump vec4 dEQP_FragColor;\n";
-               params["VTX_HEADER"]    = version + ext + "\n";
+               params["FRAG_HEADER"]   = version + (ext ? string("\n#extension ") + ext + " : require" : string()) + "\nlayout(location = 0) out mediump vec4 dEQP_FragColor;\n";
+               params["VTX_HEADER"]    = version + "\n";
                params["VTX_IN"]                = "in";
                params["VTX_OUT"]               = "out";
                params["FRAG_IN"]               = "in";
@@ -1592,7 +1606,7 @@ void computeQuadTexCoordCube (std::vector<float>& dst, tcu::CubeFace face, const
        dst[9+tRow] = tSign * topRight.y();
 }
 
-void computeQuadTexCoordCubeArray (std::vector<float>& dst, int sliceNdx, tcu::CubeFace face, const tcu::Vec2& bottomLeft, const tcu::Vec2& topRight)
+void computeQuadTexCoordCubeArray (std::vector<float>& dst, tcu::CubeFace face, const tcu::Vec2& bottomLeft, const tcu::Vec2& topRight, const tcu::Vec2& layerRange)
 {
        int                     sRow    = 0;
        int                     tRow    = 0;
@@ -1601,7 +1615,8 @@ void computeQuadTexCoordCubeArray (std::vector<float>& dst, int sliceNdx, tcu::C
        float           sSign   = 1.0f;
        float           tSign   = 1.0f;
        float           mSign   = 1.0f;
-       const float     q               = (float)sliceNdx;
+       const float     l0              = layerRange.x();
+       const float     l1              = layerRange.y();
 
        switch (face)
        {
@@ -1633,10 +1648,20 @@ void computeQuadTexCoordCubeArray (std::vector<float>& dst, int sliceNdx, tcu::C
        dst[ 8+tRow] = tSign * bottomLeft.y();
        dst[12+tRow] = tSign * topRight.y();
 
-       dst[ 0+qRow] = q;
-       dst[ 4+qRow] = q;
-       dst[ 8+qRow] = q;
-       dst[12+qRow] = q;
+       if (l0 != l1)
+       {
+               dst[ 0+qRow] = l0;
+               dst[ 4+qRow] = l0*0.5f + l1*0.5f;
+               dst[ 8+qRow] = l0*0.5f + l1*0.5f;
+               dst[12+qRow] = l1;
+       }
+       else
+       {
+               dst[ 0+qRow] = l0;
+               dst[ 4+qRow] = l0;
+               dst[ 8+qRow] = l0;
+               dst[12+qRow] = l0;
+       }
 }
 
 // Texture result verification
@@ -2554,6 +2579,191 @@ bool verifyTextureResult (tcu::TestContext&                                             testCtx,
        return numFailedPixels == 0;
 }
 
+//! Verifies texture lookup results and returns number of failed pixels.
+int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess&       result,
+                                                         const tcu::ConstPixelBufferAccess&    reference,
+                                                         const tcu::PixelBufferAccess&                 errorMask,
+                                                         const tcu::TextureCubeArrayView&              baseView,
+                                                         const float*                                                  texCoord,
+                                                         const ReferenceParams&                                sampleParams,
+                                                         const tcu::LookupPrecision&                   lookupPrec,
+                                                         const tcu::IVec4&                                             coordBits,
+                                                         const tcu::LodPrecision&                              lodPrec,
+                                                         qpWatchDog*                                                   watchDog)
+{
+       DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
+       DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
+
+       const tcu::TextureCubeArrayView src     = getSubView(baseView, sampleParams.baseLevel, sampleParams.maxLevel);
+
+       // What is the 'q' in all these names? Also a two char name for something that is in scope for ~120 lines and only used twice each seems excessive
+       const tcu::Vec4         sq                              = tcu::Vec4(texCoord[0+0], texCoord[4+0], texCoord[8+0], texCoord[12+0]);
+       const tcu::Vec4         tq                              = tcu::Vec4(texCoord[0+1], texCoord[4+1], texCoord[8+1], texCoord[12+1]);
+       const tcu::Vec4         rq                              = tcu::Vec4(texCoord[0+2], texCoord[4+2], texCoord[8+2], texCoord[12+2]);
+       const tcu::Vec4         qq                              = tcu::Vec4(texCoord[0+3], texCoord[4+3], texCoord[8+3], texCoord[12+3]);
+
+       const tcu::IVec2        dstSize                 = tcu::IVec2(result.getWidth(), result.getHeight());
+       const float                     dstW                    = float(dstSize.x());
+       const float                     dstH                    = float(dstSize.y());
+       const int                       srcSize                 = src.getSize();
+
+       // Coordinates per triangle.
+       const tcu::Vec3         triS[2]                 = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
+       const tcu::Vec3         triT[2]                 = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
+       const tcu::Vec3         triR[2]                 = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
+       const tcu::Vec3         triQ[2]                 = { qq.swizzle(0, 1, 2), qq.swizzle(3, 2, 1) };
+       const tcu::Vec3         triW[2]                 = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
+
+       const tcu::Vec2         lodBias                 ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
+
+       const float                     posEps                  = 1.0f / float((1<<4) + 1); // ES3 requires at least 4 subpixel bits.
+
+       int                                     numFailed               = 0;
+
+       const tcu::Vec2 lodOffsets[] =
+       {
+               tcu::Vec2(-1,  0),
+               tcu::Vec2(+1,  0),
+               tcu::Vec2( 0, -1),
+               tcu::Vec2( 0, +1),
+
+               // \note Not strictly allowed by spec, but implementations do this in practice.
+               tcu::Vec2(-1, -1),
+               tcu::Vec2(-1, +1),
+               tcu::Vec2(+1, -1),
+               tcu::Vec2(+1, -1),
+       };
+
+       tcu::clear(errorMask, tcu::RGBA::green.toVec());
+
+       for (int py = 0; py < result.getHeight(); py++)
+       {
+               // Ugly hack, validation can take way too long at the moment.
+               if (watchDog)
+                       qpWatchDog_touch(watchDog);
+
+               for (int px = 0; px < result.getWidth(); px++)
+               {
+                       const tcu::Vec4 resPix  = (result.getPixel(px, py)              - sampleParams.colorBias) / sampleParams.colorScale;
+                       const tcu::Vec4 refPix  = (reference.getPixel(px, py)   - sampleParams.colorBias) / sampleParams.colorScale;
+
+                       // Try comparison to ideal reference first, and if that fails use slower verificator.
+                       if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
+                       {
+                               const float             wx              = (float)px + 0.5f;
+                               const float             wy              = (float)py + 0.5f;
+                               const float             nx              = wx / dstW;
+                               const float             ny              = wy / dstH;
+
+                               const bool              tri0    = nx + ny - posEps <= 1.0f;
+                               const bool              tri1    = nx + ny + posEps >= 1.0f;
+
+                               bool                    isOk    = false;
+
+                               DE_ASSERT(tri0 || tri1);
+
+                               // Pixel can belong to either of the triangles if it lies close enough to the edge.
+                               for (int triNdx = (tri0?0:1); triNdx <= (tri1?1:0); triNdx++)
+                               {
+                                       const float             triWx           = triNdx ? dstW - wx : wx;
+                                       const float             triWy           = triNdx ? dstH - wy : wy;
+                                       const float             triNx           = triNdx ? 1.0f - nx : nx;
+                                       const float             triNy           = triNdx ? 1.0f - ny : ny;
+
+                                       const tcu::Vec4 coord           (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
+                                                                                                projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
+                                                                                                projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy),
+                                                                                                projectedTriInterpolate(triQ[triNdx], triW[triNdx], triNx, triNy));
+                                       const tcu::Vec3 coordDx         (triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
+                                                                                                triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
+                                                                                                triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy));
+                                       const tcu::Vec3 coordDy         (triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
+                                                                                                triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
+                                                                                                triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx));
+
+                                       tcu::Vec2               lodBounds       = tcu::computeCubeLodBoundsFromDerivates(coord.toWidth<3>(), coordDx, coordDy, srcSize, lodPrec);
+
+                                       // Compute lod bounds across lodOffsets range.
+                                       for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
+                                       {
+                                               const float             wxo                     = triWx + lodOffsets[lodOffsNdx].x();
+                                               const float             wyo                     = triWy + lodOffsets[lodOffsNdx].y();
+                                               const float             nxo                     = wxo/dstW;
+                                               const float             nyo                     = wyo/dstH;
+
+                                               const tcu::Vec3 coordO          (projectedTriInterpolate(triS[triNdx], triW[triNdx], nxo, nyo),
+                                                                                                        projectedTriInterpolate(triT[triNdx], triW[triNdx], nxo, nyo),
+                                                                                                        projectedTriInterpolate(triR[triNdx], triW[triNdx], nxo, nyo));
+                                               const tcu::Vec3 coordDxo        (triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
+                                                                                                        triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo),
+                                                                                                        triDerivateX(triR[triNdx], triW[triNdx], wxo, dstW, nyo));
+                                               const tcu::Vec3 coordDyo        (triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
+                                                                                                        triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo),
+                                                                                                        triDerivateY(triR[triNdx], triW[triNdx], wyo, dstH, nxo));
+                                               const tcu::Vec2 lodO            = tcu::computeCubeLodBoundsFromDerivates(coordO, coordDxo, coordDyo, srcSize, lodPrec);
+
+                                               lodBounds.x() = de::min(lodBounds.x(), lodO.x());
+                                               lodBounds.y() = de::max(lodBounds.y(), lodO.y());
+                                       }
+
+                                       const tcu::Vec2 clampedLod      = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
+
+                                       if (tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coordBits, coord, clampedLod, resPix))
+                                       {
+                                               isOk = true;
+                                               break;
+                                       }
+                               }
+
+                               if (!isOk)
+                               {
+                                       errorMask.setPixel(tcu::RGBA::red.toVec(), px, py);
+                                       numFailed += 1;
+                               }
+                       }
+               }
+       }
+
+       return numFailed;
+}
+
+bool verifyTextureResult (tcu::TestContext&                                            testCtx,
+                                                 const tcu::ConstPixelBufferAccess&    result,
+                                                 const tcu::TextureCubeArrayView&              src,
+                                                 const float*                                                  texCoord,
+                                                 const ReferenceParams&                                sampleParams,
+                                                 const tcu::LookupPrecision&                   lookupPrec,
+                                                 const tcu::IVec4&                                             coordBits,
+                                                 const tcu::LodPrecision&                              lodPrec,
+                                                 const tcu::PixelFormat&                               pixelFormat)
+{
+       tcu::TestLog&   log                             = testCtx.getLog();
+       tcu::Surface    reference               (result.getWidth(), result.getHeight());
+       tcu::Surface    errorMask               (result.getWidth(), result.getHeight());
+       int                             numFailedPixels;
+
+       DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
+
+       sampleTexture(SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
+       numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, coordBits, lodPrec, testCtx.getWatchDog());
+
+       if (numFailedPixels > 0)
+               log << TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
+
+       log << TestLog::ImageSet("VerifyResult", "Verification result")
+               << TestLog::Image("Rendered", "Rendered image", result);
+
+       if (numFailedPixels > 0)
+       {
+               log << TestLog::Image("Reference", "Ideal reference image", reference)
+                       << TestLog::Image("ErrorMask", "Error mask", errorMask);
+       }
+
+       log << TestLog::EndImageSet;
+
+       return numFailedPixels == 0;
+}
+
 // Shadow lookup verification
 
 int computeTextureCompareDiff (const tcu::ConstPixelBufferAccess&      result,
index 45ea65f..e1b01bc 100644 (file)
@@ -374,7 +374,7 @@ void                        computeQuadTexCoord2DArray              (std::vector<float>& dst, int layerNdx, const
 void                   computeQuadTexCoord3D                   (std::vector<float>& dst, const tcu::Vec3& p0, const tcu::Vec3& p1, const tcu::IVec3& dirSwz);
 void                   computeQuadTexCoordCube                 (std::vector<float>& dst, tcu::CubeFace face);
 void                   computeQuadTexCoordCube                 (std::vector<float>& dst, tcu::CubeFace face, const tcu::Vec2& bottomLeft, const tcu::Vec2& topRight);
-void                   computeQuadTexCoordCubeArray    (std::vector<float>& dst, int sliceNdx, tcu::CubeFace face, const tcu::Vec2& bottomLeft, const tcu::Vec2& topRight);
+void                   computeQuadTexCoordCubeArray    (std::vector<float>& dst, tcu::CubeFace face, const tcu::Vec2& bottomLeft, const tcu::Vec2& topRight, const tcu::Vec2& layerRange);
 
 bool                   compareImages                           (tcu::TestLog& log, const char* name, const char* desc, const tcu::Surface& reference, const tcu::Surface& rendered, tcu::RGBA threshold);
 bool                   compareImages                           (tcu::TestLog& log, const tcu::Surface& reference, const tcu::Surface& rendered, tcu::RGBA threshold);
@@ -440,6 +440,17 @@ int                                computeTextureLookupDiff        (const tcu::ConstPixelBufferAccess&     result,
                                                                                         const tcu::LodPrecision&                       lodPrec,
                                                                                         qpWatchDog*                                            watchDog);
 
+int                            computeTextureLookupDiff        (const tcu::ConstPixelBufferAccess&     result,
+                                                                                        const tcu::ConstPixelBufferAccess&     reference,
+                                                                                        const tcu::PixelBufferAccess&          errorMask,
+                                                                                        const tcu::TextureCubeArrayView&       src,
+                                                                                        const float*                                           texCoord,
+                                                                                        const ReferenceParams&                         sampleParams,
+                                                                                        const tcu::LookupPrecision&            lookupPrec,
+                                                                                        const tcu::IVec4&                                      coordBits,
+                                                                                        const tcu::LodPrecision&                       lodPrec,
+                                                                                        qpWatchDog*                                            watchDog);
+
 bool                   verifyTextureResult                     (tcu::TestContext&                                      testCtx,
                                                                                         const tcu::ConstPixelBufferAccess&     result,
                                                                                         const tcu::Texture1DView&                      src,
@@ -494,6 +505,16 @@ bool                       verifyTextureResult                     (tcu::TestContext&                                      testCtx,
                                                                                         const tcu::LodPrecision&                       lodPrec,
                                                                                         const tcu::PixelFormat&                        pixelFormat);
 
+bool                   verifyTextureResult                     (tcu::TestContext&                                      testCtx,
+                                                                                        const tcu::ConstPixelBufferAccess&     result,
+                                                                                        const tcu::TextureCubeArrayView&       src,
+                                                                                        const float*                                           texCoord,
+                                                                                        const ReferenceParams&                         sampleParams,
+                                                                                        const tcu::LookupPrecision&            lookupPrec,
+                                                                                        const tcu::IVec4&                                      coordBits,
+                                                                                        const tcu::LodPrecision&                       lodPrec,
+                                                                                        const tcu::PixelFormat&                        pixelFormat);
+
 int                            computeTextureCompareDiff       (const tcu::ConstPixelBufferAccess&     result,
                                                                                         const tcu::ConstPixelBufferAccess&     reference,
                                                                                         const tcu::PixelBufferAccess&          errorMask,