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 \
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 \
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 \
}
""
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"
""
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"
""
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"
""
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"
}
""
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"
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.
{
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;
ResultCollector::ResultCollector (void)
: m_log (DE_NULL)
, m_prefix ("")
- , m_result (QP_TEST_RESULT_PASS)
+ , m_result (QP_TEST_RESULT_LAST)
, m_message ("Pass")
{
}
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")
{
}
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
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());
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++)
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,
// \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());
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++)
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,
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)
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;
}
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;
}
}
{
// \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;
}
}
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);
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);
// 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];
{
}
-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);
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);
}
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)
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;
}
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)
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; }
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;
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);
private:
int m_size;
- int m_numLayers;
+ int m_depth;
TextureCubeArrayView m_view;
};
}
}
+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
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)
{
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;
}
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); }
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>
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. */
void deMutex_destroy (deMutex mutex)
{
+ DeleteCriticalSection((CRITICAL_SECTION*)mutex);
deFree((CRITICAL_SECTION*)mutex);
}
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;
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;
{
public:
explicit TypedObjectWrapper (const RenderContext& context) : ObjectWrapper(context.getFunctions(), objectTraits(Type)) {}
+ explicit TypedObjectWrapper (const glw::Functions& gl) : ObjectWrapper(gl, objectTraits(Type)) {}
};
/*--------------------------------------------------------------------*//*!
{
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.
}
}
+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)
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);
{
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);
}
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");
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;
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;
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>(),
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");
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"))
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");
}
}
// 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));
namespace
{
+typedef double ClipFloat; // floating point type used in clipping
+
+typedef tcu::Vector<ClipFloat, 4> ClipVec4;
+
struct RasterizationInternalBuffers
{
std::vector<FragmentPacket> fragmentPackets;
/*--------------------------------------------------------------------*//*!
* \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));
}
/*--------------------------------------------------------------------*//*!
* 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);
+ }
}
{
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);
+ }
}
{
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)
} // 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];
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);
// 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)
// 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);
}
}
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);
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();
}
}
-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);
}
}
-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);
}
}
-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);
}
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();
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);
}
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
using std::string;
using tcu::TestLog;
using tcu::Vec2;
-using deqp::gls::theilSenEstimator;
+using deqp::gls::theilSenLinearRegression;
using deqp::gls::LineParameters;
namespace
{
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;
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
}
{
- 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
// \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(),
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",
// 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
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));
using std::string;
using tcu::TestLog;
using tcu::Vec2;
-using deqp::gls::theilSenEstimator;
+using deqp::gls::theilSenLinearRegression;
using deqp::gls::LineParameters;
namespace
{
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;
{
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")
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
// 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.
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."
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();
es3pBufferDataUploadTests.hpp
es3pShaderOperatorTests.cpp
es3pShaderOperatorTests.hpp
+ es3pDepthTests.hpp
+ es3pDepthTests.cpp
)
add_library(deqp-gles3-performance STATIC ${DEQP_GLES3_PERFORMANCE_SRCS})
*//*--------------------------------------------------------------------*/
#include "es3pBufferDataUploadTests.hpp"
+#include "glsCalibration.hpp"
#include "tcuTestLog.hpp"
#include "tcuVectorUtil.hpp"
#include "tcuSurface.hpp"
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"
enum { LOG_UNRELATED_UPLOAD_SIZE = 1 };
};
-struct TheilSenLineFit
-{
- float coefficient;
- float coefficient60ConfidenceUpper;
- float coefficient60ConfidenceLower;
- float offset;
- float offset60ConfidenceUpper;
- float offset60ConfidenceLower;
-};
-
struct UploadSampleAnalyzeResult
{
float transferRateMedian;
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)
{
}
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());
}
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
}
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;
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;
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);
}
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);
// 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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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
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
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
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
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
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
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
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
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
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
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;
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)
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;
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)
{
// 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)
{
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)
--- /dev/null
+/*-------------------------------------------------------------------------
+ * 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
--- /dev/null
+#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
#include "es3pStateChangeCallTests.hpp"
#include "es3pStateChangeTests.hpp"
#include "es3pBufferDataUploadTests.hpp"
+#include "es3pDepthTests.hpp"
namespace deqp
{
addChild(new ShaderCompilerTests (m_context));
addChild(new APITests (m_context));
addChild(new BufferTestGroup (m_context));
+ addChild(new DepthTests (m_context));
}
} // Performance
}
{
- 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
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
<< " 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";
<< " 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";
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
// 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
<< "\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";
// 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
// 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
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
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
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
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
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));
// 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);
--- /dev/null
+/*-------------------------------------------------------------------------
+ * 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
--- /dev/null
+#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
--- /dev/null
+/*-------------------------------------------------------------------------
+ * 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
--- /dev/null
+#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
(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)
<< 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"
}
}
+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
// 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:
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
#include "es31fTextureLevelStateQueryTests.hpp"
#include "es31fIntegerStateQueryTests.hpp"
#include "es31fInternalFormatQueryTests.hpp"
+#include "es31fTextureFilteringTests.hpp"
#include "es31fTextureFormatTests.hpp"
#include "es31fTextureSpecificationTests.hpp"
#include "es31fTextureMultisampleTests.hpp"
#include "es31fTessellationGeometryInteractionTests.hpp"
#include "es31fUniformBlockTests.hpp"
#include "es31fDebugTests.hpp"
+#include "es31fFboColorbufferTests.hpp"
#include "es31fFboNoAttachmentTests.hpp"
#include "es31fProgramInterfaceQueryTests.hpp"
#include "es31fTextureGatherTests.hpp"
void init (void)
{
+ addChild(new TextureFilteringTests (m_context));
addChild(new TextureFormatTests (m_context));
addChild(new TextureSpecificationTests (m_context));
addChild(new TextureMultisampleTests (m_context));
void init (void)
{
+ addChild(new FboColorTests (m_context));
addChild(createFboNoAttachmentTests (m_context));
addChild(createFboNoAttachmentCompletenessTests (m_context));
}
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"
// 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";
}
// 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";
}
enum IndexExprType
{
INDEX_EXPR_TYPE_CONST_LITERAL = 0,
+ INDEX_EXPR_TYPE_CONST_EXPRESSION,
INDEX_EXPR_TYPE_UNIFORM,
INDEX_EXPR_TYPE_DYNAMIC_UNIFORM,
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";
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;
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)
, m_blockType (blockType)
, m_indexExprType (indexExprType)
, m_shaderType (shaderType)
+ , m_numInstances (4)
{
}
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
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"
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;
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);
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";
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;
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" }
};
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));
}
}
}
}
}
+ // 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;
}
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
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)
}
}
+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:
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)
}
}
+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:
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;
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;
}
}
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)
{
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)
// 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;
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);
}
}
}
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 (
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);
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);
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());
{
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;
}
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);
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;
{
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;
"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";
"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"
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"
"{\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"
// 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
{
Random rnd (seed);
TestParams params;
+ int tryNdx = 0;
do
{
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;
}
, m_status (log(), "// ")
, m_varyings (genVaryingInterface(params.varyings, m_rnd))
{
+ DE_ASSERT(paramsValid(params));
}
MovePtr<ProgramWrapper> SeparateShaderTest::createShaderProgram (const string* vtxSource,
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)
ostringstream name;
ostringstream desc;
+ DE_ASSERT(areCaseParamFlagsValid(flags));
+
name << namePrefix;
desc << descPrefix;
ostringstream name;
ostringstream desc;
+ if (!areCaseParamFlagsValid(ParamFlags(flags & PARAMFLAGS_MASK)))
+ continue;
+
if (flags & (PARAMFLAGS_LAST << 1))
{
params.useSameName = true;
{
TestParams params = defaultParams;
+ if (!areCaseParamFlagsValid(ParamFlags(flags)))
+ continue;
+
params.useUniform = true;
params.useProgramUniform = true;
{
TestParams params = defaultParams;
+ if (!areCaseParamFlagsValid(ParamFlags(flags)))
+ continue;
+
params.useCreateHelper = true;
addRenderTest(*createShaderProgramGroup, "", "", numIterations,
{
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";
}
{
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";
}
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;
}
}
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)
{
}
}
}
- 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;
}
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);
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)
"{\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"
// 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;
}
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:
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))
{
"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();
"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();
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"
<< " 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";
"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();
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"
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>
<< " 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"
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
#include "tcuStringTemplate.hpp"
#include "gluShaderProgram.hpp"
#include "gluRenderContext.hpp"
+#include "gluContextInfo.hpp"
#include "glwFunctions.hpp"
#include "glwEnums.hpp"
{
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(), "");
+ }
}
}
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[] =
{
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[] =
{
{
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);
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;
}
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);
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);
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";
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
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);
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
<< " 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"
<< " 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"
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"
" // 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")
" 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"
--- /dev/null
+/*-------------------------------------------------------------------------
+ * 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
--- /dev/null
+#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
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.
m_curLayerFace += 1;
- return m_curLayerFace < m_texture->getRefTexture().getNumLayers() ? CONTINUE : STOP;
+ return m_curLayerFace < m_texture->getRefTexture().getDepth() ? CONTINUE : STOP;
}
// TextureBufferFormatCase
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.
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
string getRequiredExtension (void) const
{
- return "GL_EXT_gpu_ shader5";
+ return "GL_EXT_gpu_shader5";
}
protected:
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 <>
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);
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();
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;
}
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;
}
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)
{
}
Context m_ctx;
ResultCollector m_status;
Random m_rnd;
+ const string m_extension;
};
IterateResult PrecisionCase::iterate (void)
}
spec.version = getContextTypeGLSLVersion(getRenderContext().getType());
+
+ if (!m_extension.empty())
+ spec.globalDeclarations = "#extension " + m_extension + " : require\n";
+
spec.inputs.resize(inCount);
switch (inCount)
template<typename In>
Inputs<In> generateInputs (const Samplings<In>& samplings,
const FloatFormat& floatFormat,
+ Precision intPrecision,
size_t numSamples,
Random& rnd)
{
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))
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)
{
const Inputs<In> inputs (generateInputs(getSamplings(),
m_ctx.floatFormat,
+ m_ctx.precision,
m_ctx.numRandoms,
m_rnd));
Variables<In, Out> variables;
{
const Inputs<In> inputs (generateInputs(getSamplings(),
m_ctx.floatFormat,
+ m_ctx.precision,
m_ctx.numRandoms,
m_rnd));
Variables<In, Out> variables;
#include "glsCalibration.hpp"
#include "tcuTestLog.hpp"
+#include "tcuVectorUtil.hpp"
#include "deStringUtil.hpp"
#include "deMath.h"
#include "deClock.h"
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;
// 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++)
// 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;
}
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;
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
{
#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
{
{
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)
{
}
{
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;
}
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[] =
{
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();
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
{
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
// 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
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);
}
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)
// TessEvaluationExecutor
-class TessEvaluationExecutor : public BufferIoExecutor
+class TessEvaluationExecutor : private CheckTessSupport, public BufferIoExecutor
{
public:
TessEvaluationExecutor (const glu::RenderContext& renderCtx, const ShaderSpec& shaderSpec);
}
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)
{
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);
}
{
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);
}
{
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++)
{
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;
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);
}
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)
{
}
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";
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;
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)
{
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
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,
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);
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,
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,