diff options
Diffstat (limited to 'modules/gles3')
-rw-r--r-- | modules/gles3/functional/es3fBlendTests.cpp | 2 | ||||
-rw-r--r-- | modules/gles3/functional/es3fFboCompletenessTests.cpp | 12 | ||||
-rw-r--r-- | modules/gles3/functional/es3fFboInvalidateTests.cpp | 4 | ||||
-rw-r--r-- | modules/gles3/functional/es3fFlushFinishTests.cpp | 6 | ||||
-rw-r--r-- | modules/gles3/functional/es3fScissorTests.cpp | 400 | ||||
-rw-r--r-- | modules/gles3/functional/es3fShaderPrecisionTests.cpp | 6 | ||||
-rw-r--r-- | modules/gles3/functional/es3fShaderTextureFunctionTests.cpp | 14 | ||||
-rw-r--r-- | modules/gles3/performance/CMakeLists.txt | 2 | ||||
-rw-r--r-- | modules/gles3/performance/es3pBufferDataUploadTests.cpp | 187 | ||||
-rw-r--r-- | modules/gles3/performance/es3pDepthTests.cpp | 1911 | ||||
-rw-r--r-- | modules/gles3/performance/es3pDepthTests.hpp | 53 | ||||
-rw-r--r-- | modules/gles3/performance/es3pPerformanceTests.cpp | 2 | ||||
-rw-r--r-- | modules/gles3/performance/es3pShaderOperatorTests.cpp | 6 |
13 files changed, 2111 insertions, 494 deletions
diff --git a/modules/gles3/functional/es3fBlendTests.cpp b/modules/gles3/functional/es3fBlendTests.cpp index f91573ae6..c17ff9b2d 100644 --- a/modules/gles3/functional/es3fBlendTests.cpp +++ b/modules/gles3/functional/es3fBlendTests.cpp @@ -319,7 +319,7 @@ BlendCase::IterateResult BlendCase::iterate (void) // \note In sRGB cases, convert to linear space for comparison. UVec4 compareThreshold = (m_useSrgbFbo ? tcu::PixelFormat(8, 8, 8, 8) : m_context.getRenderTarget().getPixelFormat()).getColorThreshold().toIVec().asUint() - * UVec4(5) / UVec4(2) + UVec4(m_useSrgbFbo ? 4 : 2); // \note Non-scientific ad hoc formula. Need big threshold when few color bits; blending brings extra inaccuracy. + * UVec4(5) / UVec4(2) + UVec4(m_useSrgbFbo ? 5 : 2); // \note Non-scientific ad hoc formula. Need big threshold when few color bits; blending brings extra inaccuracy. bool comparePass = tcu::intThresholdCompare(m_testCtx.getLog(), "CompareResult", "Image Comparison Result", (m_useSrgbFbo ? sRGBATextureLevelToLinear(*m_refColorBuffer) : *m_refColorBuffer).getAccess(), diff --git a/modules/gles3/functional/es3fFboCompletenessTests.cpp b/modules/gles3/functional/es3fFboCompletenessTests.cpp index e3239d210..c594e4cd1 100644 --- a/modules/gles3/functional/es3fFboCompletenessTests.cpp +++ b/modules/gles3/functional/es3fFboCompletenessTests.cpp @@ -120,6 +120,13 @@ static const FormatKey s_extColorBufferFloatFormats[] = GL_RGBA32F, GL_RGBA16F, GL_R11F_G11F_B10F, GL_RG32F, GL_RG16F, GL_R32F, GL_R16F, }; +// GL_OES_texture_stencil8 +static const FormatKey s_extOESTextureStencil8[] = +{ + GL_STENCIL_INDEX8, +}; + + static const FormatExtEntry s_es3ExtFormats[] = { { "GL_EXT_color_buffer_float", @@ -127,6 +134,11 @@ static const FormatExtEntry s_es3ExtFormats[] = // support and makes them color-renderable. REQUIRED_RENDERABLE | COLOR_RENDERABLE | RENDERBUFFER_VALID, GLS_ARRAY_RANGE(s_extColorBufferFloatFormats) }, + { "GL_OES_texture_stencil8", + // Note: es3 RBO tests actually cover the first two requirements + // - kept here for completeness + REQUIRED_RENDERABLE | STENCIL_RENDERABLE | TEXTURE_VALID, + GLS_ARRAY_RANGE(s_extOESTextureStencil8) } }; class ES3Checker : public Checker diff --git a/modules/gles3/functional/es3fFboInvalidateTests.cpp b/modules/gles3/functional/es3fFboInvalidateTests.cpp index 4a02c29b8..7fc9f2652 100644 --- a/modules/gles3/functional/es3fFboInvalidateTests.cpp +++ b/modules/gles3/functional/es3fFboInvalidateTests.cpp @@ -1211,7 +1211,9 @@ protected: const tcu::TextureFormatInfo colorFmtInfo = tcu::getTextureFormatInfo(colorFmt); const tcu::Vec4& cBias = colorFmtInfo.valueMin; const tcu::Vec4 cScale = colorFmtInfo.valueMax-colorFmtInfo.valueMin; - const bool isDiscarded = (m_invalidateTarget == GL_FRAMEBUFFER && m_boundTarget == GL_DRAW_FRAMEBUFFER) || (m_invalidateTarget == m_boundTarget); + const bool isDiscarded = (m_boundTarget == GL_FRAMEBUFFER) || + (m_invalidateTarget == GL_FRAMEBUFFER && m_boundTarget == GL_DRAW_FRAMEBUFFER) || + (m_invalidateTarget == m_boundTarget); const bool isColorDiscarded = isDiscarded && hasAttachment(m_invalidateAttachments, GL_COLOR_ATTACHMENT0); const bool isDepthDiscarded = isDiscarded && (hasAttachment(m_invalidateAttachments, GL_DEPTH_ATTACHMENT) || hasAttachment(m_invalidateAttachments, GL_DEPTH_STENCIL_ATTACHMENT)); const bool isStencilDiscarded = isDiscarded && (hasAttachment(m_invalidateAttachments, GL_STENCIL_ATTACHMENT) || hasAttachment(m_invalidateAttachments, GL_DEPTH_STENCIL_ATTACHMENT)); diff --git a/modules/gles3/functional/es3fFlushFinishTests.cpp b/modules/gles3/functional/es3fFlushFinishTests.cpp index 16ea85478..19da1c19b 100644 --- a/modules/gles3/functional/es3fFlushFinishTests.cpp +++ b/modules/gles3/functional/es3fFlushFinishTests.cpp @@ -54,7 +54,7 @@ using std::vector; using std::string; using tcu::TestLog; using tcu::Vec2; -using deqp::gls::theilSenEstimator; +using deqp::gls::theilSenLinearRegression; using deqp::gls::LineParameters; namespace @@ -427,8 +427,8 @@ void FlushFinishCase::analyzeResults (const std::vector<Sample>& samples, const { const vector<Vec2> waitTimes = getPointsFromSamples(samples, &Sample::waitTime); const vector<Vec2> readTimes = getPointsFromSamples(samples, &Sample::readPixelsTime); - const LineParameters waitLine = theilSenEstimator(waitTimes); - const LineParameters readLine = theilSenEstimator(readTimes); + const LineParameters waitLine = theilSenLinearRegression(waitTimes); + const LineParameters readLine = theilSenLinearRegression(readTimes); const float normWaitCoef = waitLine.coefficient * float(calibrationParams.maxDrawCalls) / float(MAX_SAMPLE_DURATION_US); const float normReadCoef = readLine.coefficient * float(calibrationParams.maxDrawCalls) / float(MAX_SAMPLE_DURATION_US); bool allOk = true; diff --git a/modules/gles3/functional/es3fScissorTests.cpp b/modules/gles3/functional/es3fScissorTests.cpp index 3ef5bc666..a3b16f278 100644 --- a/modules/gles3/functional/es3fScissorTests.cpp +++ b/modules/gles3/functional/es3fScissorTests.cpp @@ -45,320 +45,6 @@ namespace gles3 { namespace Functional { -namespace -{ - -using tcu::ConstPixelBufferAccess; - -class FramebufferCase : public tcu::TestCase -{ -public: - FramebufferCase (glu::RenderContext& context, tcu::TestContext& testContext, const char* name, const char* description); - virtual ~FramebufferCase (void) {} - - virtual IterateResult iterate (void); - -protected: - // Must do its own 'readPixels', wrapper does not need to care about formats this way - virtual ConstPixelBufferAccess render (sglr::Context& context, std::vector<deUint8>& pixelBuffer) = DE_NULL; - - glu::RenderContext& m_renderContext; -}; - -FramebufferCase::FramebufferCase (glu::RenderContext& context, tcu::TestContext& testContext, const char* name, const char* description) - : tcu::TestCase (testContext, name, description) - , m_renderContext (context) -{ -} - -FramebufferCase::IterateResult FramebufferCase::iterate (void) -{ - const tcu::Vec4 clearColor (0.0f, 0.0f, 0.0f, 1.0f); - const tcu::RenderTarget& renderTarget = m_renderContext.getRenderTarget(); - const char* failReason = DE_NULL; - - const int width = 64; - const int height = 64; - - tcu::TestLog& log = m_testCtx.getLog(); - glu::RenderContext& renderCtx = m_renderContext; - - tcu::ConstPixelBufferAccess glesAccess; - tcu::ConstPixelBufferAccess refAccess; - - std::vector<deUint8> glesFrame; - std::vector<deUint8> refFrame; - deUint32 glesError; - - { - // Render using GLES - sglr::GLContext context(renderCtx, log, sglr::GLCONTEXT_LOG_CALLS, tcu::IVec4(0, 0, width, height)); - - context.clearColor(clearColor.x(), clearColor.y(), clearColor.z(), clearColor.w()); - context.clear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT); - - glesAccess = render(context, glesFrame); // Call actual render func - glesError = context.getError(); - } - - // Render reference image - { - sglr::ReferenceContextBuffers buffers (tcu::PixelFormat(8,8,8,renderTarget.getPixelFormat().alphaBits?8:0), renderTarget.getDepthBits(), renderTarget.getStencilBits(), width, height); - sglr::ReferenceContext context (sglr::ReferenceContextLimits(renderCtx), buffers.getColorbuffer(), buffers.getDepthbuffer(), buffers.getStencilbuffer()); - - context.clearColor(clearColor.x(), clearColor.y(), clearColor.z(), clearColor.w()); - context.clear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT); - - refAccess = render(context, refFrame); - DE_ASSERT(context.getError() == GL_NO_ERROR); - } - - if (glesError != GL_NO_ERROR) - { - log << tcu::TestLog::Message << "Unexpected error: got " << glu::getErrorStr(glesError) << tcu::TestLog::EndMessage; - m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got unexpected error"); - } - else - { - // Compare images - const tcu::Vec4 threshold (0.02f, 0.02f, 0.02f, 0.02f); - const bool imagesOk = tcu::floatThresholdCompare(log, "ComparisonResult", "Image comparison result", refAccess, glesAccess, threshold, tcu::COMPARE_LOG_RESULT); - - if (!imagesOk && !failReason) - failReason = "Image comparison failed"; - - // Store test result - m_testCtx.setTestResult(imagesOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, - imagesOk ? "Pass" : failReason); - } - - return STOP; -} - -class FramebufferClearCase : public FramebufferCase -{ -public: - enum ClearType - { - COLOR_FIXED = 0, - COLOR_FLOAT, - COLOR_INT, - COLOR_UINT, - DEPTH, - STENCIL, - DEPTH_STENCIL, - - CLEAR_TYPE_LAST - }; - - FramebufferClearCase (glu::RenderContext& context, tcu::TestContext& testContext, ClearType clearType, const char* name, const char* description); - virtual ~FramebufferClearCase (void) {} - - tcu::ConstPixelBufferAccess render (sglr::Context& context, std::vector<deUint8>& pixelBuffer); - -private: - const ClearType m_clearType; -}; - -FramebufferClearCase::FramebufferClearCase (glu::RenderContext& context, tcu::TestContext& testContext, ClearType clearType, const char* name, const char* description) - : FramebufferCase (context, testContext, name, description) - , m_clearType (clearType) -{ -} - -ConstPixelBufferAccess FramebufferClearCase::render (sglr::Context& context, std::vector<deUint8>& pixelBuffer) -{ - using gls::Functional::ScissorTestShader; - - ScissorTestShader shader; - const deUint32 shaderID = context.createProgram(&shader); - - const int width = 64; - const int height = 64; - - const tcu::Vec4 clearColor (1.0f, 1.0f, 0.5f, 1.0f); - const tcu::IVec4 clearInt (127, -127, 0, 127); - const tcu::UVec4 clearUint (255, 255, 0, 255); - - const tcu::Vec4 baseColor (0.0f, 0.0f, 0.0f, 1.0f); - const tcu::IVec4 baseIntColor (0, 0, 0, 0); - const tcu::UVec4 baseUintColor (0, 0, 0, 0); - - const int clearStencil = 123; - const float clearDepth = 1.0f; - - deUint32 framebuf, colorbuf, dsbuf; - - deUint32 colorBufferFormat = GL_RGBA8; - deUint32 readFormat = GL_RGBA; - deUint32 readType = GL_UNSIGNED_BYTE; - tcu::TextureFormat textureFormat (tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8); - - context.genFramebuffers(1, &framebuf); - context.bindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuf); - - switch (m_clearType) - { - case COLOR_FLOAT: - colorBufferFormat = GL_RGBA16F; - textureFormat = tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::HALF_FLOAT); - DE_ASSERT(!"Floating point clear not implemented");// \todo [2014-1-23 otto] pixel read format & type, nothing guaranteed, need extension... - break; - - case COLOR_INT: - colorBufferFormat = GL_RGBA8I; - readFormat = GL_RGBA_INTEGER; - readType = GL_INT; - textureFormat = tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::SIGNED_INT32); - pixelBuffer.resize(width*height*4*4); - break; - - case COLOR_UINT: - colorBufferFormat = GL_RGBA8UI; - readFormat = GL_RGBA_INTEGER; - readType = GL_UNSIGNED_INT; - textureFormat = tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNSIGNED_INT32); - pixelBuffer.resize(width*height*4*4); - break; - - default: - pixelBuffer.resize(width*height*1*4); - break; - } - - // Color - context.genRenderbuffers(1, &colorbuf); - context.bindRenderbuffer(GL_RENDERBUFFER, colorbuf); - context.renderbufferStorage(GL_RENDERBUFFER, colorBufferFormat, width, height); - context.framebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorbuf); - - // Depth/stencil - context.genRenderbuffers(1, &dsbuf); - context.bindRenderbuffer(GL_RENDERBUFFER, dsbuf); - context.renderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height); - context.framebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, dsbuf); - - context.clearBufferfi(GL_DEPTH_STENCIL, 0, 1.0f-clearDepth, ~clearStencil); - switch (m_clearType) - { - case COLOR_INT: context.clearBufferiv(GL_COLOR, 0, baseIntColor.getPtr()); break; - case COLOR_UINT: context.clearBufferuiv(GL_COLOR, 0, baseUintColor.getPtr()); break; - default: context.clearBufferfv(GL_COLOR, 0, baseColor.getPtr()); - } - - context.enable(GL_SCISSOR_TEST); - context.scissor(8, 8, 48, 48); - - switch (m_clearType) - { - case COLOR_FIXED: context.clearBufferfv(GL_COLOR, 0, clearColor.getPtr()); break; - case COLOR_FLOAT: context.clearBufferfv(GL_COLOR, 0, clearColor.getPtr()); break; - case COLOR_INT: context.clearBufferiv(GL_COLOR, 0, clearInt.getPtr()); break; - case COLOR_UINT: context.clearBufferuiv(GL_COLOR, 0, clearUint.getPtr()); break; - case DEPTH: context.clearBufferfv(GL_DEPTH, 0, &clearDepth); break; - case STENCIL: context.clearBufferiv(GL_STENCIL, 0, &clearStencil); break; - case DEPTH_STENCIL: context.clearBufferfi(GL_DEPTH_STENCIL, 0, clearDepth, clearStencil); break; - - default: DE_ASSERT(false); break; - } - - context.disable(GL_SCISSOR_TEST); - - const bool useDepth = (m_clearType==DEPTH || m_clearType==DEPTH_STENCIL); - const bool useStencil = (m_clearType==STENCIL || m_clearType==DEPTH_STENCIL); - - if (useDepth) - context.enable(GL_DEPTH_TEST); - - if (useStencil) - { - context.enable(GL_STENCIL_TEST); - context.stencilFunc(GL_EQUAL, clearStencil, ~0u); - } - - if (useDepth || useStencil) - { - shader.setColor(context, shaderID, clearColor); - sglr::drawQuad(context, shaderID, tcu::Vec3(-1.0f, -1.0f, 0.2f), tcu::Vec3(1.0f, 1.0f, 0.2f)); - } - - context.bindFramebuffer(GL_READ_FRAMEBUFFER, framebuf); - context.readPixels(0, 0, width, height, readFormat, readType, &pixelBuffer[0]); - - context.deleteFramebuffers(1, &framebuf); - context.deleteRenderbuffers(1, &colorbuf); - context.deleteRenderbuffers(1, &dsbuf); - - return tcu::PixelBufferAccess(textureFormat, width, height, 1, &pixelBuffer[0]); -} - -class FramebufferBlitCase : public gls::Functional::ScissorCase -{ -public: - FramebufferBlitCase (glu::RenderContext& context, tcu::TestContext& testContext, const tcu::Vec4& scissorArea, const char* name, const char* description); - virtual ~FramebufferBlitCase (void) {} - - virtual void init (void); - -protected: - virtual void render (sglr::Context& context, const tcu::IVec4& viewport); -}; - -FramebufferBlitCase::FramebufferBlitCase (glu::RenderContext& context, tcu::TestContext& testContext, const tcu::Vec4& scissorArea, const char* name, const char* description): - ScissorCase(context, testContext, scissorArea, name, description) -{ -} - -void FramebufferBlitCase::init (void) -{ - if (m_renderContext.getRenderTarget().getNumSamples()) - throw tcu::NotSupportedError("Cannot blit to multisampled render buffer", "", __FILE__, __LINE__); -} - -void FramebufferBlitCase::render (sglr::Context& context, const tcu::IVec4& viewport) -{ - deUint32 framebuf; - deUint32 colorbuf; - - const int fboWidth = 64; - const int fboHeight = 64; - const tcu::Vec4 clearColor (1.0f, 1.0f, 0.5f, 1.0f); - const int width = viewport.z(); - const int height = viewport.w(); - const tcu::IVec4 scissorArea (int(m_scissorArea.x()*width) + viewport.x(), - int(m_scissorArea.y()*height) + viewport.y(), - int(m_scissorArea.z()*width), - int(m_scissorArea.w()*height)); - const deInt32 defaultFramebuffer = m_renderContext.getDefaultFramebuffer(); - - context.genFramebuffers(1, &framebuf); - context.bindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuf); - - context.genRenderbuffers(1, &colorbuf); - context.bindRenderbuffer(GL_RENDERBUFFER, colorbuf); - context.renderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, fboWidth, fboHeight); - context.framebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorbuf); - - context.clearBufferfv(GL_COLOR, 0, clearColor.getPtr()); - - context.enable(GL_SCISSOR_TEST); - context.scissor(scissorArea.x(), scissorArea.y(), scissorArea.z(), scissorArea.w()); - - // blit to default framebuffer - context.bindFramebuffer(GL_READ_FRAMEBUFFER, framebuf); - context.bindFramebuffer(GL_DRAW_FRAMEBUFFER, defaultFramebuffer); - - context.blitFramebuffer(0, 0, fboWidth, fboHeight, viewport.x(), viewport.y(), viewport.x() + width, viewport.y() + height, GL_COLOR_BUFFER_BIT, GL_NEAREST); - - context.bindFramebuffer(GL_READ_FRAMEBUFFER, defaultFramebuffer); - - context.disable(GL_SCISSOR_TEST); - - context.deleteFramebuffers(1, &framebuf); - context.deleteRenderbuffers(1, &colorbuf); -} - -} // Anonymous ScissorTests::ScissorTests (Context& context): TestCaseGroup (context, "scissor", "Scissor Tests") @@ -372,63 +58,63 @@ ScissorTests::~ScissorTests (void) void ScissorTests::init (void) { using tcu::Vec4; - typedef gls::Functional::ScissorCase SC; + using namespace gls::Functional::ScissorTestInternal; - glu::RenderContext& rc = m_context.getRenderContext(); tcu::TestContext& tc = m_context.getTestContext(); + glu::RenderContext& rc = m_context.getRenderContext(); - static const struct + const struct { - const char* name; - const char* description; - const tcu::Vec4 scissor; - const tcu::Vec4 render; - const SC::PrimitiveType type; - const int primitives; + const char* name; + const char* desc; + const tcu::Vec4 scissor; + const tcu::Vec4 render; + const PrimitiveType type; + const int primitives; } cases[] = { - { "contained_quads", "Triangles fully inside scissor area (single call)", Vec4(0.1f, 0.1f, 0.8f, 0.8f), Vec4(0.2f, 0.2f, 0.6f, 0.6f), SC::TRIANGLE, 30 }, - { "partial_quads", "Triangles partially inside scissor area (single call)", Vec4(0.3f, 0.3f, 0.4f, 0.4f), Vec4(0.2f, 0.2f, 0.6f, 0.6f), SC::TRIANGLE, 30 }, - { "contained_tri", "Triangle fully inside scissor area", Vec4(0.1f, 0.1f, 0.8f, 0.8f), Vec4(0.2f, 0.2f, 0.6f, 0.6f), SC::TRIANGLE, 1 }, - { "enclosing_tri", "Triangle fully covering scissor area", Vec4(0.4f, 0.4f, 0.2f, 0.2f), Vec4(0.2f, 0.2f, 0.6f, 0.6f), SC::TRIANGLE, 1 }, - { "partial_tri", "Triangle partially inside scissor area", Vec4(0.4f, 0.4f, 0.6f, 0.6f), Vec4(0.0f, 0.0f, 1.0f, 1.0f), SC::TRIANGLE, 1 }, - { "outside_render_tri", "Triangle with scissor area outside render target", Vec4(1.4f, 1.4f, 0.6f, 0.6f), Vec4(0.0f, 0.0f, 0.6f, 0.6f), SC::TRIANGLE, 1 }, - { "partial_lines", "Linse partially inside scissor area", Vec4(0.4f, 0.4f, 0.6f, 0.6f), Vec4(0.0f, 0.0f, 1.0f, 1.0f), SC::LINE, 30 }, - { "contained_line", "Line fully inside scissor area", Vec4(0.1f, 0.1f, 0.8f, 0.8f), Vec4(0.2f, 0.2f, 0.6f, 0.6f), SC::LINE, 1 }, - { "partial_line", "Line partially inside scissor area", Vec4(0.4f, 0.4f, 0.6f, 0.6f), Vec4(0.0f, 0.0f, 1.0f, 1.0f), SC::LINE, 1 }, - { "outside_render_line", "Line with scissor area outside render target", Vec4(1.4f, 1.4f, 0.6f, 0.6f), Vec4(0.0f, 0.0f, 0.6f, 0.6f), SC::LINE, 1 }, - { "contained_point", "Point fully inside scissor area", Vec4(0.1f, 0.1f, 0.8f, 0.8f), Vec4(0.5f, 0.5f, 0.0f, 0.0f), SC::POINT, 1 }, - { "partial_points", "Points partially inside scissor area", Vec4(0.4f, 0.4f, 0.6f, 0.6f), Vec4(0.0f, 0.0f, 1.0f, 1.0f), SC::POINT, 30 }, - { "outside_point", "Point fully outside scissor area", Vec4(0.4f, 0.4f, 0.6f, 0.6f), Vec4(0.0f, 0.0f, 0.0f, 0.0f), SC::POINT, 1 }, - { "outside_render_point", "Point with scissor area outside render target", Vec4(1.4f, 1.4f, 0.6f, 0.6f), Vec4(0.5f, 0.5f, 0.0f, 0.0f), SC::POINT, 1 } + { "contained_quads", "Triangles fully inside scissor area (single call)", Vec4(0.1f, 0.1f, 0.8f, 0.8f), Vec4(0.2f, 0.2f, 0.6f, 0.6f), TRIANGLE, 30 }, + { "partial_quads", "Triangles partially inside scissor area (single call)", Vec4(0.3f, 0.3f, 0.4f, 0.4f), Vec4(0.2f, 0.2f, 0.6f, 0.6f), TRIANGLE, 30 }, + { "contained_tri", "Triangle fully inside scissor area", Vec4(0.1f, 0.1f, 0.8f, 0.8f), Vec4(0.2f, 0.2f, 0.6f, 0.6f), TRIANGLE, 1 }, + { "enclosing_tri", "Triangle fully covering scissor area", Vec4(0.4f, 0.4f, 0.2f, 0.2f), Vec4(0.2f, 0.2f, 0.6f, 0.6f), TRIANGLE, 1 }, + { "partial_tri", "Triangle partially inside scissor area", Vec4(0.4f, 0.4f, 0.6f, 0.6f), Vec4(0.0f, 0.0f, 1.0f, 1.0f), TRIANGLE, 1 }, + { "outside_render_tri", "Triangle with scissor area outside render target", Vec4(1.4f, 1.4f, 0.6f, 0.6f), Vec4(0.0f, 0.0f, 0.6f, 0.6f), TRIANGLE, 1 }, + { "partial_lines", "Linse partially inside scissor area", Vec4(0.4f, 0.4f, 0.6f, 0.6f), Vec4(0.0f, 0.0f, 1.0f, 1.0f), LINE, 30 }, + { "contained_line", "Line fully inside scissor area", Vec4(0.1f, 0.1f, 0.8f, 0.8f), Vec4(0.2f, 0.2f, 0.6f, 0.6f), LINE, 1 }, + { "partial_line", "Line partially inside scissor area", Vec4(0.4f, 0.4f, 0.6f, 0.6f), Vec4(0.0f, 0.0f, 1.0f, 1.0f), LINE, 1 }, + { "outside_render_line", "Line with scissor area outside render target", Vec4(1.4f, 1.4f, 0.6f, 0.6f), Vec4(0.0f, 0.0f, 0.6f, 0.6f), LINE, 1 }, + { "contained_point", "Point fully inside scissor area", Vec4(0.1f, 0.1f, 0.8f, 0.8f), Vec4(0.5f, 0.5f, 0.0f, 0.0f), POINT, 1 }, + { "partial_points", "Points partially inside scissor area", Vec4(0.4f, 0.4f, 0.6f, 0.6f), Vec4(0.0f, 0.0f, 1.0f, 1.0f), POINT, 30 }, + { "outside_point", "Point fully outside scissor area", Vec4(0.4f, 0.4f, 0.6f, 0.6f), Vec4(0.0f, 0.0f, 0.0f, 0.0f), POINT, 1 }, + { "outside_render_point", "Point with scissor area outside render target", Vec4(1.4f, 1.4f, 0.6f, 0.6f), Vec4(0.5f, 0.5f, 0.0f, 0.0f), POINT, 1 } }; for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(cases); caseNdx++) { - addChild(SC::createPrimitiveTest(rc, - tc, - cases[caseNdx].scissor, - cases[caseNdx].render, - cases[caseNdx].type, - cases[caseNdx].primitives, - cases[caseNdx].name, - cases[caseNdx].description)); + addChild(createPrimitiveTest(tc, + rc, + cases[caseNdx].name, + cases[caseNdx].desc, + cases[caseNdx].scissor, + cases[caseNdx].render, + cases[caseNdx].type, + cases[caseNdx].primitives)); } - addChild(SC::createClearTest(rc, tc, Vec4(0.1f, 0.1f, 0.8f, 0.8f), GL_DEPTH_BUFFER_BIT, "clear_depth", "Depth buffer clear")); - addChild(SC::createClearTest(rc, tc, Vec4(0.1f, 0.1f, 0.8f, 0.8f), GL_STENCIL_BUFFER_BIT, "clear_stencil", "Stencil buffer clear")); - addChild(SC::createClearTest(rc, tc, Vec4(0.1f, 0.1f, 0.8f, 0.8f), GL_COLOR_BUFFER_BIT, "clear_color", "Color buffer clear")); + addChild(createClearTest(tc, rc, "clear_depth", "Depth buffer clear", Vec4(0.1f, 0.1f, 0.8f, 0.8f), GL_DEPTH_BUFFER_BIT)); + addChild(createClearTest(tc, rc, "clear_stencil", "Stencil buffer clear", Vec4(0.1f, 0.1f, 0.8f, 0.8f), GL_STENCIL_BUFFER_BIT)); + addChild(createClearTest(tc, rc, "clear_color", "Color buffer clear", Vec4(0.1f, 0.1f, 0.8f, 0.8f), GL_COLOR_BUFFER_BIT)); - addChild(new FramebufferClearCase(rc, tc, FramebufferClearCase::COLOR_FIXED, "clear_fixed_buffer", "Fixed point color clear")); - addChild(new FramebufferClearCase(rc, tc, FramebufferClearCase::COLOR_INT, "clear_int_buffer", "Integer color clear")); - addChild(new FramebufferClearCase(rc, tc, FramebufferClearCase::COLOR_UINT, "clear_uint_buffer", "Unsigned integer buffer clear")); - addChild(new FramebufferClearCase(rc, tc, FramebufferClearCase::DEPTH, "clear_depth_buffer", "Depth buffer clear")); - addChild(new FramebufferClearCase(rc, tc, FramebufferClearCase::STENCIL, "clear_stencil_buffer", "Stencil buffer clear")); - addChild(new FramebufferClearCase(rc, tc, FramebufferClearCase::DEPTH_STENCIL, "clear_depth_stencil_buffer", "Fixed point color buffer clear")); + addChild(createFramebufferClearTest(tc, rc, "clear_fixed_buffer", "Fixed point color clear", CLEAR_COLOR_FIXED)); + addChild(createFramebufferClearTest(tc, rc, "clear_int_buffer", "Integer color clear", CLEAR_COLOR_INT)); + addChild(createFramebufferClearTest(tc, rc, "clear_uint_buffer", "Unsigned integer buffer clear", CLEAR_COLOR_UINT)); + addChild(createFramebufferClearTest(tc, rc, "clear_depth_buffer", "Depth buffer clear", CLEAR_DEPTH)); + addChild(createFramebufferClearTest(tc, rc, "clear_stencil_buffer", "Stencil buffer clear", CLEAR_STENCIL)); + addChild(createFramebufferClearTest(tc, rc, "clear_depth_stencil_buffer", "Fixed point color buffer clear", CLEAR_DEPTH_STENCIL)); - addChild(new FramebufferBlitCase(rc, tc, Vec4(0.1f, 0.1f, 0.8f, 0.8f), "framebuffer_blit_center", "Blit to default framebuffer, scissor away edges")); - addChild(new FramebufferBlitCase(rc, tc, Vec4(0.6f, 0.6f, 0.5f, 0.5f), "framebuffer_blit_corner", "Blit to default framebuffer, scissor all but a corner")); - addChild(new FramebufferBlitCase(rc, tc, Vec4(1.6f, 0.6f, 0.5f, 0.5f), "framebuffer_blit_none", "Blit to default framebuffer, scissor area outside screen")); + addChild(createFramebufferBlitTest(tc, rc, "framebuffer_blit_center", "Blit to default framebuffer, scissor away edges", Vec4(0.1f, 0.1f, 0.8f, 0.8f))); + addChild(createFramebufferBlitTest(tc, rc, "framebuffer_blit_corner", "Blit to default framebuffer, scissor all but a corner", Vec4(0.6f, 0.6f, 0.5f, 0.5f))); + addChild(createFramebufferBlitTest(tc, rc, "framebuffer_blit_none", "Blit to default framebuffer, scissor area outside screen", Vec4(1.6f, 0.6f, 0.5f, 0.5f))); } } // Functional diff --git a/modules/gles3/functional/es3fShaderPrecisionTests.cpp b/modules/gles3/functional/es3fShaderPrecisionTests.cpp index 0b405fef9..c05b7636d 100644 --- a/modules/gles3/functional/es3fShaderPrecisionTests.cpp +++ b/modules/gles3/functional/es3fShaderPrecisionTests.cpp @@ -288,8 +288,8 @@ bool ShaderFloatPrecisionCase::compare (float in0, float in1, double reference, // Comparison is done using 64-bit reference value to accurately evaluate rounding mode error. // If 32-bit reference value is used, 2 bits of rounding error must be allowed. - // For mediump and lowp types the comparison currently allows 2 bits of rounding error: - // one bit from conversion and another from actual operation. + // For mediump and lowp types the comparison currently allows 3 bits of rounding error: + // two bits from conversions and one from actual operation. // \todo [2013-09-30 pyry] Make this more strict: determine if rounding can actually happen. @@ -301,7 +301,7 @@ bool ShaderFloatPrecisionCase::compare (float in0, float in1, double reference, const int resExp = tcu::Float32(result).exponent(); const int numLostBits = de::max(de::max(in0Exp-resExp, in1Exp-resExp), 0); // Lost due to mantissa shift. - const int roundingUlpError = m_precision == glu::PRECISION_HIGHP ? 1 : 2; + const int roundingUlpError = m_precision == glu::PRECISION_HIGHP ? 1 : 3; const int maskBits = numLostBits + numPrecBits; m_testCtx.getLog() << TestLog::Message << "Assuming " << mantissaBits << " mantissa bits, " << numLostBits << " bits lost in operation, and " << roundingUlpError << " ULP rounding error." diff --git a/modules/gles3/functional/es3fShaderTextureFunctionTests.cpp b/modules/gles3/functional/es3fShaderTextureFunctionTests.cpp index 7c9d4361f..a72950b11 100644 --- a/modules/gles3/functional/es3fShaderTextureFunctionTests.cpp +++ b/modules/gles3/functional/es3fShaderTextureFunctionTests.cpp @@ -690,7 +690,19 @@ void ShaderTextureFunctionCase::initTexture (void) Vec4 colorB = cBias + cScale*f.swizzle(swzB[0], swzB[1], swzB[2], swzB[3]); m_textureCube->getRefTexture().allocLevel((tcu::CubeFace)face, level); - tcu::fillWithGrid(m_textureCube->getRefTexture().getLevelFace(level, (tcu::CubeFace)face), de::max(1, baseCellSize>>level), colorA, colorB); + + { + const tcu::PixelBufferAccess access = m_textureCube->getRefTexture().getLevelFace(level, (tcu::CubeFace)face); + const int lastPix = access.getWidth()-1; + + tcu::fillWithGrid(access, de::max(1, baseCellSize>>level), colorA, colorB); + + // Ensure all corners have identical colors in order to avoid dealing with ambiguous corner texel filtering + access.setPixel(colorA, 0, 0); + access.setPixel(colorA, 0, lastPix); + access.setPixel(colorA, lastPix, 0); + access.setPixel(colorA, lastPix, lastPix); + } } } m_textureCube->upload(); diff --git a/modules/gles3/performance/CMakeLists.txt b/modules/gles3/performance/CMakeLists.txt index 896954eda..8840b3feb 100644 --- a/modules/gles3/performance/CMakeLists.txt +++ b/modules/gles3/performance/CMakeLists.txt @@ -31,6 +31,8 @@ set(DEQP_GLES3_PERFORMANCE_SRCS es3pBufferDataUploadTests.hpp es3pShaderOperatorTests.cpp es3pShaderOperatorTests.hpp + es3pDepthTests.hpp + es3pDepthTests.cpp ) add_library(deqp-gles3-performance STATIC ${DEQP_GLES3_PERFORMANCE_SRCS}) diff --git a/modules/gles3/performance/es3pBufferDataUploadTests.cpp b/modules/gles3/performance/es3pBufferDataUploadTests.cpp index c9758c4f4..45bd25fb2 100644 --- a/modules/gles3/performance/es3pBufferDataUploadTests.cpp +++ b/modules/gles3/performance/es3pBufferDataUploadTests.cpp @@ -22,6 +22,7 @@ *//*--------------------------------------------------------------------*/ #include "es3pBufferDataUploadTests.hpp" +#include "glsCalibration.hpp" #include "tcuTestLog.hpp" #include "tcuVectorUtil.hpp" #include "tcuSurface.hpp" @@ -54,6 +55,9 @@ namespace Performance namespace { +using gls::theilSenSiegelLinearRegression; +using gls::LineParametersWithConfidence; + static const char* const s_dummyVertexShader = "#version 300 es\n" "in highp vec4 a_position;\n" "void main (void)\n" @@ -497,16 +501,6 @@ struct SampleTypeTraits<RenderUploadRenderReadDuration> enum { LOG_UNRELATED_UPLOAD_SIZE = 1 }; }; -struct TheilSenLineFit -{ - float coefficient; - float coefficient60ConfidenceUpper; - float coefficient60ConfidenceLower; - float offset; - float offset60ConfidenceUpper; - float offset60ConfidenceLower; -}; - struct UploadSampleAnalyzeResult { float transferRateMedian; @@ -689,63 +683,6 @@ static float linearSample (const std::vector<T>& values, float position) return tcu::mix((float)values[lowerNdx], (float)values[higherNdx], interpolationFactor); } -static TheilSenLineFit theilSenLinearRegression (const std::vector<tcu::Vec2>& dataPoints) -{ - DE_ASSERT(!dataPoints.empty()); - - // \note Based on gls::theilSenEstimator() - // Siegel's variation - - const float epsilon = 1e-6f; - int numDataPoints = (int)dataPoints.size(); - std::vector<float> medianSlopes; - std::vector<float> pointwiseOffsets; - TheilSenLineFit result; - - // Compute the median slope via each element - for (int i = 0; i < numDataPoints; i++) - { - const tcu::Vec2& ptA = dataPoints[i]; - std::vector<float> slopes; - - for (int j = 0; j < numDataPoints; j++) - { - const tcu::Vec2& ptB = dataPoints[j]; - - if (de::abs(ptA.x() - ptB.x()) > epsilon) - slopes.push_back((ptA.y() - ptB.y()) / (ptA.x() - ptB.x())); - } - - std::sort(slopes.begin(), slopes.end()); - medianSlopes.push_back(linearSample(slopes, 0.5f)); - } - - DE_ASSERT(!medianSlopes.empty()); - - // Find the median of the pairwise coefficients. - std::sort(medianSlopes.begin(), medianSlopes.end()); - result.coefficient = linearSample(medianSlopes, 0.5f); - - // Compute the offsets corresponding to the median coefficient, for all data points. - for (int i = 0; i < numDataPoints; i++) - pointwiseOffsets.push_back(dataPoints[i].y() - result.coefficient*dataPoints[i].x()); - - // Find the median of the offsets. - std::sort(pointwiseOffsets.begin(), pointwiseOffsets.end()); - result.offset = linearSample(pointwiseOffsets, 0.5f); - - // calculate 60% confidence intervals - { - result.coefficient60ConfidenceLower = linearSample(medianSlopes, 0.2f); - result.coefficient60ConfidenceUpper = linearSample(medianSlopes, 0.8f); - - result.offset60ConfidenceLower = linearSample(pointwiseOffsets, 0.2f); - result.offset60ConfidenceUpper = linearSample(pointwiseOffsets, 0.8f); - } - - return result; -} - template <typename T> SingleOperationStatistics calculateSingleOperationStatistics (const std::vector<T>& samples, deUint64 T::SampleType::*target) { @@ -767,7 +704,7 @@ SingleOperationStatistics calculateSingleOperationStatistics (const std::vector< } template <typename StatisticsType, typename SampleType> -void calculateBasicStatistics (StatisticsType& stats, const TheilSenLineFit& fit, const std::vector<SampleType>& samples, int SampleType::*predictor) +void calculateBasicStatistics (StatisticsType& stats, const LineParametersWithConfidence& fit, const std::vector<SampleType>& samples, int SampleType::*predictor) { std::vector<deUint64> values(samples.size()); @@ -842,18 +779,18 @@ void calculateBasicStatistics (StatisticsType& stats, const TheilSenLineFit& fit } template <typename StatisticsType, typename SampleType> -void calculateBasicTransferStatistics (StatisticsType& stats, const TheilSenLineFit& fit, const std::vector<SampleType>& samples) +void calculateBasicTransferStatistics (StatisticsType& stats, const LineParametersWithConfidence& fit, const std::vector<SampleType>& samples) { calculateBasicStatistics(stats, fit, samples, &SampleType::writtenSize); } template <typename StatisticsType, typename SampleType> -void calculateBasicRenderStatistics (StatisticsType& stats, const TheilSenLineFit& fit, const std::vector<SampleType>& samples) +void calculateBasicRenderStatistics (StatisticsType& stats, const LineParametersWithConfidence& fit, const std::vector<SampleType>& samples) { calculateBasicStatistics(stats, fit, samples, &SampleType::renderDataSize); } -static SingleCallStatistics calculateSampleStatistics (const TheilSenLineFit& fit, const std::vector<UploadSampleResult<SingleOperationDuration> >& samples) +static SingleCallStatistics calculateSampleStatistics (const LineParametersWithConfidence& fit, const std::vector<UploadSampleResult<SingleOperationDuration> >& samples) { SingleCallStatistics stats; @@ -862,7 +799,7 @@ static SingleCallStatistics calculateSampleStatistics (const TheilSenLineFit& fi return stats; } -static MapCallStatistics calculateSampleStatistics (const TheilSenLineFit& fit, const std::vector<UploadSampleResult<MapBufferRangeDuration> >& samples) +static MapCallStatistics calculateSampleStatistics (const LineParametersWithConfidence& fit, const std::vector<UploadSampleResult<MapBufferRangeDuration> >& samples) { MapCallStatistics stats; @@ -876,7 +813,7 @@ static MapCallStatistics calculateSampleStatistics (const TheilSenLineFit& fit, return stats; } -static MapFlushCallStatistics calculateSampleStatistics (const TheilSenLineFit& fit, const std::vector<UploadSampleResult<MapBufferRangeFlushDuration> >& samples) +static MapFlushCallStatistics calculateSampleStatistics (const LineParametersWithConfidence& fit, const std::vector<UploadSampleResult<MapBufferRangeFlushDuration> >& samples) { MapFlushCallStatistics stats; @@ -891,7 +828,7 @@ static MapFlushCallStatistics calculateSampleStatistics (const TheilSenLineFit& return stats; } -static MapCallStatistics calculateSampleStatistics (const TheilSenLineFit& fit, const std::vector<UploadSampleResult<MapBufferRangeDurationNoAlloc> >& samples) +static MapCallStatistics calculateSampleStatistics (const LineParametersWithConfidence& fit, const std::vector<UploadSampleResult<MapBufferRangeDurationNoAlloc> >& samples) { MapCallStatistics stats; @@ -904,7 +841,7 @@ static MapCallStatistics calculateSampleStatistics (const TheilSenLineFit& fit, return stats; } -static MapFlushCallStatistics calculateSampleStatistics (const TheilSenLineFit& fit, const std::vector<UploadSampleResult<MapBufferRangeFlushDurationNoAlloc> >& samples) +static MapFlushCallStatistics calculateSampleStatistics (const LineParametersWithConfidence& fit, const std::vector<UploadSampleResult<MapBufferRangeFlushDurationNoAlloc> >& samples) { MapFlushCallStatistics stats; @@ -918,7 +855,7 @@ static MapFlushCallStatistics calculateSampleStatistics (const TheilSenLineFit& return stats; } -static RenderReadStatistics calculateSampleStatistics (const TheilSenLineFit& fit, const std::vector<RenderSampleResult<RenderReadDuration> >& samples) +static RenderReadStatistics calculateSampleStatistics (const LineParametersWithConfidence& fit, const std::vector<RenderSampleResult<RenderReadDuration> >& samples) { RenderReadStatistics stats; @@ -931,7 +868,7 @@ static RenderReadStatistics calculateSampleStatistics (const TheilSenLineFit& fi return stats; } -static RenderReadStatistics calculateSampleStatistics (const TheilSenLineFit& fit, const std::vector<RenderSampleResult<UnrelatedUploadRenderReadDuration> >& samples) +static RenderReadStatistics calculateSampleStatistics (const LineParametersWithConfidence& fit, const std::vector<RenderSampleResult<UnrelatedUploadRenderReadDuration> >& samples) { RenderReadStatistics stats; @@ -944,7 +881,7 @@ static RenderReadStatistics calculateSampleStatistics (const TheilSenLineFit& fi return stats; } -static UploadRenderReadStatistics calculateSampleStatistics (const TheilSenLineFit& fit, const std::vector<RenderSampleResult<UploadRenderReadDuration> >& samples) +static UploadRenderReadStatistics calculateSampleStatistics (const LineParametersWithConfidence& fit, const std::vector<RenderSampleResult<UploadRenderReadDuration> >& samples) { UploadRenderReadStatistics stats; @@ -958,7 +895,7 @@ static UploadRenderReadStatistics calculateSampleStatistics (const TheilSenLineF return stats; } -static UploadRenderReadStatistics calculateSampleStatistics (const TheilSenLineFit& fit, const std::vector<RenderSampleResult<UploadRenderReadDurationWithUnrelatedUploadSize> >& samples) +static UploadRenderReadStatistics calculateSampleStatistics (const LineParametersWithConfidence& fit, const std::vector<RenderSampleResult<UploadRenderReadDurationWithUnrelatedUploadSize> >& samples) { UploadRenderReadStatistics stats; @@ -972,7 +909,7 @@ static UploadRenderReadStatistics calculateSampleStatistics (const TheilSenLineF return stats; } -static RenderUploadRenderReadStatistics calculateSampleStatistics (const TheilSenLineFit& fit, const std::vector<RenderSampleResult<RenderUploadRenderReadDuration> >& samples) +static RenderUploadRenderReadStatistics calculateSampleStatistics (const LineParametersWithConfidence& fit, const std::vector<RenderSampleResult<RenderUploadRenderReadDuration> >& samples) { RenderUploadRenderReadStatistics stats; @@ -988,7 +925,7 @@ static RenderUploadRenderReadStatistics calculateSampleStatistics (const TheilSe } template <typename DurationType> -static TheilSenLineFit fitLineToSamples (const std::vector<UploadSampleResult<DurationType> >& samples, int beginNdx, int endNdx, int step, deUint64 DurationType::*target = &DurationType::fitResponseDuration) +static LineParametersWithConfidence fitLineToSamples (const std::vector<UploadSampleResult<DurationType> >& samples, int beginNdx, int endNdx, int step, deUint64 DurationType::*target = &DurationType::fitResponseDuration) { std::vector<tcu::Vec2> samplePoints; @@ -1002,11 +939,11 @@ static TheilSenLineFit fitLineToSamples (const std::vector<UploadSampleResult<Du samplePoints.push_back(point); } - return theilSenLinearRegression(samplePoints); + return theilSenSiegelLinearRegression(samplePoints, 0.6f); } template <typename DurationType> -static TheilSenLineFit fitLineToSamples (const std::vector<RenderSampleResult<DurationType> >& samples, int beginNdx, int endNdx, int step, deUint64 DurationType::*target = &DurationType::fitResponseDuration) +static LineParametersWithConfidence fitLineToSamples (const std::vector<RenderSampleResult<DurationType> >& samples, int beginNdx, int endNdx, int step, deUint64 DurationType::*target = &DurationType::fitResponseDuration) { std::vector<tcu::Vec2> samplePoints; @@ -1020,17 +957,17 @@ static TheilSenLineFit fitLineToSamples (const std::vector<RenderSampleResult<Du samplePoints.push_back(point); } - return theilSenLinearRegression(samplePoints); + return theilSenSiegelLinearRegression(samplePoints, 0.6f); } template <typename T> -static TheilSenLineFit fitLineToSamples (const std::vector<T>& samples, int beginNdx, int endNdx, deUint64 T::SampleType::*target = &T::SampleType::fitResponseDuration) +static LineParametersWithConfidence fitLineToSamples (const std::vector<T>& samples, int beginNdx, int endNdx, deUint64 T::SampleType::*target = &T::SampleType::fitResponseDuration) { return fitLineToSamples(samples, beginNdx, endNdx, 1, target); } template <typename T> -static TheilSenLineFit fitLineToSamples (const std::vector<T>& samples, deUint64 T::SampleType::*target = &T::SampleType::fitResponseDuration) +static LineParametersWithConfidence fitLineToSamples (const std::vector<T>& samples, deUint64 T::SampleType::*target = &T::SampleType::fitResponseDuration) { return fitLineToSamples(samples, 0, (int)samples.size(), target); } @@ -1083,8 +1020,8 @@ static float calculateSampleFitLinearity (const std::vector<T>& samples, int T:: const float epsilon = 1.e-6f; const int midPoint = (int)samples.size() / 2; - const TheilSenLineFit startApproximation = fitLineToSamples(samples, 0, midPoint, &T::SampleType::fitResponseDuration); - const TheilSenLineFit endApproximation = fitLineToSamples(samples, midPoint, (int)samples.size(), &T::SampleType::fitResponseDuration); + const LineParametersWithConfidence startApproximation = fitLineToSamples(samples, 0, midPoint, &T::SampleType::fitResponseDuration); + const LineParametersWithConfidence endApproximation = fitLineToSamples(samples, midPoint, (int)samples.size(), &T::SampleType::fitResponseDuration); const float aabbMinX = (float)(samples.front().*predictor); const float aabbMinY = de::min(startApproximation.offset + startApproximation.coefficient*aabbMinX, endApproximation.offset + endApproximation.coefficient*aabbMinX); @@ -1119,8 +1056,8 @@ static float calculateSampleTemporalStability (const std::vector<T>& samples, in // the lines and the AABB. const float epsilon = 1.e-6f; - const TheilSenLineFit evenApproximation = fitLineToSamples(samples, 0, (int)samples.size(), 2, &T::SampleType::fitResponseDuration); - const TheilSenLineFit oddApproximation = fitLineToSamples(samples, 1, (int)samples.size(), 2, &T::SampleType::fitResponseDuration); + const LineParametersWithConfidence evenApproximation = fitLineToSamples(samples, 0, (int)samples.size(), 2, &T::SampleType::fitResponseDuration); + const LineParametersWithConfidence oddApproximation = fitLineToSamples(samples, 1, (int)samples.size(), 2, &T::SampleType::fitResponseDuration); const float aabbMinX = (float)(samples.front().*predictor); const float aabbMinY = de::min(evenApproximation.offset + evenApproximation.coefficient*aabbMinX, oddApproximation.offset + oddApproximation.coefficient*aabbMinX); @@ -1259,7 +1196,7 @@ static typename EnableIfNot<void, SampleTypeTraits<SampleType>::HAS_ALLOC_STATS> template <typename SampleType> static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_MAP_STATS>::Type logMapContribution (tcu::TestLog& log, const std::vector<UploadSampleResult<SampleType> >& samples, const typename SampleTypeTraits<SampleType>::StatsType& stats) { - const TheilSenLineFit contributionFitting = fitLineToSamples(samples, &SampleType::mapDuration); + const LineParametersWithConfidence contributionFitting = fitLineToSamples(samples, &SampleType::mapDuration); log << tcu::TestLog::Float("MapConstantCost", "Map: Approximated contant cost", "us", QP_KEY_TAG_TIME, contributionFitting.offset) << tcu::TestLog::Float("MapLinearCost", "Map: Approximated linear cost", "us / MB", QP_KEY_TAG_TIME, contributionFitting.coefficient * 1024.0f * 1024.0f) << tcu::TestLog::Float("MapMedianCost", "Map: Median cost", "us", QP_KEY_TAG_TIME, stats.map.medianTime); @@ -1268,7 +1205,7 @@ static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_MAP_STATS>::Typ template <typename SampleType> static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_UNMAP_STATS>::Type logUnmapContribution (tcu::TestLog& log, const std::vector<UploadSampleResult<SampleType> >& samples, const typename SampleTypeTraits<SampleType>::StatsType& stats) { - const TheilSenLineFit contributionFitting = fitLineToSamples(samples, &SampleType::unmapDuration); + const LineParametersWithConfidence contributionFitting = fitLineToSamples(samples, &SampleType::unmapDuration); log << tcu::TestLog::Float("UnmapConstantCost", "Unmap: Approximated contant cost", "us", QP_KEY_TAG_TIME, contributionFitting.offset) << tcu::TestLog::Float("UnmapLinearCost", "Unmap: Approximated linear cost", "us / MB", QP_KEY_TAG_TIME, contributionFitting.coefficient * 1024.0f * 1024.0f) << tcu::TestLog::Float("UnmapMedianCost", "Unmap: Median cost", "us", QP_KEY_TAG_TIME, stats.unmap.medianTime); @@ -1277,7 +1214,7 @@ static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_UNMAP_STATS>::T template <typename SampleType> static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_WRITE_STATS>::Type logWriteContribution (tcu::TestLog& log, const std::vector<UploadSampleResult<SampleType> >& samples, const typename SampleTypeTraits<SampleType>::StatsType& stats) { - const TheilSenLineFit contributionFitting = fitLineToSamples(samples, &SampleType::writeDuration); + const LineParametersWithConfidence contributionFitting = fitLineToSamples(samples, &SampleType::writeDuration); log << tcu::TestLog::Float("WriteConstantCost", "Write: Approximated contant cost", "us", QP_KEY_TAG_TIME, contributionFitting.offset) << tcu::TestLog::Float("WriteLinearCost", "Write: Approximated linear cost", "us / MB", QP_KEY_TAG_TIME, contributionFitting.coefficient * 1024.0f * 1024.0f) << tcu::TestLog::Float("WriteMedianCost", "Write: Median cost", "us", QP_KEY_TAG_TIME, stats.write.medianTime); @@ -1286,7 +1223,7 @@ static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_WRITE_STATS>::T template <typename SampleType> static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_FLUSH_STATS>::Type logFlushContribution (tcu::TestLog& log, const std::vector<UploadSampleResult<SampleType> >& samples, const typename SampleTypeTraits<SampleType>::StatsType& stats) { - const TheilSenLineFit contributionFitting = fitLineToSamples(samples, &SampleType::flushDuration); + const LineParametersWithConfidence contributionFitting = fitLineToSamples(samples, &SampleType::flushDuration); log << tcu::TestLog::Float("FlushConstantCost", "Flush: Approximated contant cost", "us", QP_KEY_TAG_TIME, contributionFitting.offset) << tcu::TestLog::Float("FlushLinearCost", "Flush: Approximated linear cost", "us / MB", QP_KEY_TAG_TIME, contributionFitting.coefficient * 1024.0f * 1024.0f) << tcu::TestLog::Float("FlushMedianCost", "Flush: Median cost", "us", QP_KEY_TAG_TIME, stats.flush.medianTime); @@ -1295,7 +1232,7 @@ static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_FLUSH_STATS>::T template <typename SampleType> static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_ALLOC_STATS>::Type logAllocContribution (tcu::TestLog& log, const std::vector<UploadSampleResult<SampleType> >& samples, const typename SampleTypeTraits<SampleType>::StatsType& stats) { - const TheilSenLineFit contributionFitting = fitLineToSamples(samples, &SampleType::allocDuration); + const LineParametersWithConfidence contributionFitting = fitLineToSamples(samples, &SampleType::allocDuration); log << tcu::TestLog::Float("AllocConstantCost", "Alloc: Approximated contant cost", "us", QP_KEY_TAG_TIME, contributionFitting.offset) << tcu::TestLog::Float("AllocLinearCost", "Alloc: Approximated linear cost", "us / MB", QP_KEY_TAG_TIME, contributionFitting.coefficient * 1024.0f * 1024.0f) << tcu::TestLog::Float("AllocMedianCost", "Alloc: Median cost", "us", QP_KEY_TAG_TIME, stats.alloc.medianTime); @@ -1304,7 +1241,7 @@ static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_ALLOC_STATS>::T template <typename SampleType> static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_RENDER_STATS>::Type logRenderContribution (tcu::TestLog& log, const std::vector<RenderSampleResult<SampleType> >& samples, const typename SampleTypeTraits<SampleType>::StatsType& stats) { - const TheilSenLineFit contributionFitting = fitLineToSamples(samples, &SampleType::renderDuration); + const LineParametersWithConfidence contributionFitting = fitLineToSamples(samples, &SampleType::renderDuration); log << tcu::TestLog::Float("DrawCallConstantCost", "DrawCall: Approximated contant cost", "us", QP_KEY_TAG_TIME, contributionFitting.offset) << tcu::TestLog::Float("DrawCallLinearCost", "DrawCall: Approximated linear cost", "us / MB", QP_KEY_TAG_TIME, contributionFitting.coefficient * 1024.0f * 1024.0f) << tcu::TestLog::Float("DrawCallMedianCost", "DrawCall: Median cost", "us", QP_KEY_TAG_TIME, stats.render.medianTime); @@ -1313,7 +1250,7 @@ static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_RENDER_STATS>:: template <typename SampleType> static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_READ_STATS>::Type logReadContribution (tcu::TestLog& log, const std::vector<RenderSampleResult<SampleType> >& samples, const typename SampleTypeTraits<SampleType>::StatsType& stats) { - const TheilSenLineFit contributionFitting = fitLineToSamples(samples, &SampleType::readDuration); + const LineParametersWithConfidence contributionFitting = fitLineToSamples(samples, &SampleType::readDuration); log << tcu::TestLog::Float("ReadConstantCost", "Read: Approximated contant cost", "us", QP_KEY_TAG_TIME, contributionFitting.offset) << tcu::TestLog::Float("ReadLinearCost", "Read: Approximated linear cost", "us / MB", QP_KEY_TAG_TIME, contributionFitting.coefficient * 1024.0f * 1024.0f) << tcu::TestLog::Float("ReadMedianCost", "Read: Median cost", "us", QP_KEY_TAG_TIME, stats.read.medianTime); @@ -1322,7 +1259,7 @@ static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_READ_STATS>::Ty template <typename SampleType> static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_UPLOAD_STATS>::Type logUploadContribution (tcu::TestLog& log, const std::vector<RenderSampleResult<SampleType> >& samples, const typename SampleTypeTraits<SampleType>::StatsType& stats) { - const TheilSenLineFit contributionFitting = fitLineToSamples(samples, &SampleType::uploadDuration); + const LineParametersWithConfidence contributionFitting = fitLineToSamples(samples, &SampleType::uploadDuration); log << tcu::TestLog::Float("UploadConstantCost", "Upload: Approximated contant cost", "us", QP_KEY_TAG_TIME, contributionFitting.offset) << tcu::TestLog::Float("UploadLinearCost", "Upload: Approximated linear cost", "us / MB", QP_KEY_TAG_TIME, contributionFitting.coefficient * 1024.0f * 1024.0f) << tcu::TestLog::Float("UploadMedianCost", "Upload: Median cost", "us", QP_KEY_TAG_TIME, stats.upload.medianTime); @@ -1331,7 +1268,7 @@ static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_UPLOAD_STATS>:: template <typename SampleType> static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_TOTAL_STATS>::Type logTotalContribution (tcu::TestLog& log, const std::vector<RenderSampleResult<SampleType> >& samples, const typename SampleTypeTraits<SampleType>::StatsType& stats) { - const TheilSenLineFit contributionFitting = fitLineToSamples(samples, &SampleType::totalDuration); + const LineParametersWithConfidence contributionFitting = fitLineToSamples(samples, &SampleType::totalDuration); log << tcu::TestLog::Float("TotalConstantCost", "Total: Approximated contant cost", "us", QP_KEY_TAG_TIME, contributionFitting.offset) << tcu::TestLog::Float("TotalLinearCost", "Total: Approximated linear cost", "us / MB", QP_KEY_TAG_TIME, contributionFitting.coefficient * 1024.0f * 1024.0f) << tcu::TestLog::Float("TotalMedianCost", "Total: Median cost", "us", QP_KEY_TAG_TIME, stats.total.medianTime); @@ -1340,7 +1277,7 @@ static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_TOTAL_STATS>::T template <typename SampleType> static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_FIRST_RENDER_STATS>::Type logFirstRenderContribution (tcu::TestLog& log, const std::vector<RenderSampleResult<SampleType> >& samples, const typename SampleTypeTraits<SampleType>::StatsType& stats) { - const TheilSenLineFit contributionFitting = fitLineToSamples(samples, &SampleType::firstRenderDuration); + const LineParametersWithConfidence contributionFitting = fitLineToSamples(samples, &SampleType::firstRenderDuration); log << tcu::TestLog::Float("FirstDrawCallConstantCost", "First DrawCall: Approximated contant cost", "us", QP_KEY_TAG_TIME, contributionFitting.offset) << tcu::TestLog::Float("FirstDrawCallLinearCost", "First DrawCall: Approximated linear cost", "us / MB", QP_KEY_TAG_TIME, contributionFitting.coefficient * 1024.0f * 1024.0f) << tcu::TestLog::Float("FirstDrawCallMedianCost", "First DrawCall: Median cost", "us", QP_KEY_TAG_TIME, stats.firstRender.medianTime); @@ -1349,7 +1286,7 @@ static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_FIRST_RENDER_ST template <typename SampleType> static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_SECOND_RENDER_STATS>::Type logSecondRenderContribution (tcu::TestLog& log, const std::vector<RenderSampleResult<SampleType> >& samples, const typename SampleTypeTraits<SampleType>::StatsType& stats) { - const TheilSenLineFit contributionFitting = fitLineToSamples(samples, &SampleType::secondRenderDuration); + const LineParametersWithConfidence contributionFitting = fitLineToSamples(samples, &SampleType::secondRenderDuration); log << tcu::TestLog::Float("SecondDrawCallConstantCost", "Second DrawCall: Approximated contant cost", "us", QP_KEY_TAG_TIME, contributionFitting.offset) << tcu::TestLog::Float("SecondDrawCallLinearCost", "Second DrawCall: Approximated linear cost", "us / MB", QP_KEY_TAG_TIME, contributionFitting.coefficient * 1024.0f * 1024.0f) << tcu::TestLog::Float("SecondDrawCallMedianCost", "Second DrawCall: Median cost", "us", QP_KEY_TAG_TIME, stats.secondRender.medianTime); @@ -1443,7 +1380,7 @@ static typename EnableIfNot<void, SampleTypeTraits<SampleType>::HAS_SECOND_RENDE DE_UNREF(stats); } -void logSampleList (tcu::TestLog& log, const TheilSenLineFit& theilSenFitting, const std::vector<UploadSampleResult<SingleOperationDuration> >& samples) +void logSampleList (tcu::TestLog& log, const LineParametersWithConfidence& theilSenFitting, const std::vector<UploadSampleResult<SingleOperationDuration> >& samples) { log << tcu::TestLog::SampleList("Samples", "Samples") << tcu::TestLog::SampleInfo @@ -1467,7 +1404,7 @@ void logSampleList (tcu::TestLog& log, const TheilSenLineFit& theilSenFitting, c log << tcu::TestLog::EndSampleList; } -void logSampleList (tcu::TestLog& log, const TheilSenLineFit& theilSenFitting, const std::vector<UploadSampleResult<MapBufferRangeDuration> >& samples) +void logSampleList (tcu::TestLog& log, const LineParametersWithConfidence& theilSenFitting, const std::vector<UploadSampleResult<MapBufferRangeDuration> >& samples) { log << tcu::TestLog::SampleList("Samples", "Samples") << tcu::TestLog::SampleInfo @@ -1499,7 +1436,7 @@ void logSampleList (tcu::TestLog& log, const TheilSenLineFit& theilSenFitting, c log << tcu::TestLog::EndSampleList; } -void logSampleList (tcu::TestLog& log, const TheilSenLineFit& theilSenFitting, const std::vector<UploadSampleResult<MapBufferRangeDurationNoAlloc> >& samples) +void logSampleList (tcu::TestLog& log, const LineParametersWithConfidence& theilSenFitting, const std::vector<UploadSampleResult<MapBufferRangeDurationNoAlloc> >& samples) { log << tcu::TestLog::SampleList("Samples", "Samples") << tcu::TestLog::SampleInfo @@ -1529,7 +1466,7 @@ void logSampleList (tcu::TestLog& log, const TheilSenLineFit& theilSenFitting, c log << tcu::TestLog::EndSampleList; } -void logSampleList (tcu::TestLog& log, const TheilSenLineFit& theilSenFitting, const std::vector<UploadSampleResult<MapBufferRangeFlushDuration> >& samples) +void logSampleList (tcu::TestLog& log, const LineParametersWithConfidence& theilSenFitting, const std::vector<UploadSampleResult<MapBufferRangeFlushDuration> >& samples) { log << tcu::TestLog::SampleList("Samples", "Samples") << tcu::TestLog::SampleInfo @@ -1563,7 +1500,7 @@ void logSampleList (tcu::TestLog& log, const TheilSenLineFit& theilSenFitting, c log << tcu::TestLog::EndSampleList; } -void logSampleList (tcu::TestLog& log, const TheilSenLineFit& theilSenFitting, const std::vector<UploadSampleResult<MapBufferRangeFlushDurationNoAlloc> >& samples) +void logSampleList (tcu::TestLog& log, const LineParametersWithConfidence& theilSenFitting, const std::vector<UploadSampleResult<MapBufferRangeFlushDurationNoAlloc> >& samples) { log << tcu::TestLog::SampleList("Samples", "Samples") << tcu::TestLog::SampleInfo @@ -1595,7 +1532,7 @@ void logSampleList (tcu::TestLog& log, const TheilSenLineFit& theilSenFitting, c log << tcu::TestLog::EndSampleList; } -void logSampleList (tcu::TestLog& log, const TheilSenLineFit& theilSenFitting, const std::vector<RenderSampleResult<RenderReadDuration> >& samples) +void logSampleList (tcu::TestLog& log, const LineParametersWithConfidence& theilSenFitting, const std::vector<RenderSampleResult<RenderReadDuration> >& samples) { log << tcu::TestLog::SampleList("Samples", "Samples") << tcu::TestLog::SampleInfo @@ -1623,7 +1560,7 @@ void logSampleList (tcu::TestLog& log, const TheilSenLineFit& theilSenFitting, c log << tcu::TestLog::EndSampleList; } -void logSampleList (tcu::TestLog& log, const TheilSenLineFit& theilSenFitting, const std::vector<RenderSampleResult<UnrelatedUploadRenderReadDuration> >& samples) +void logSampleList (tcu::TestLog& log, const LineParametersWithConfidence& theilSenFitting, const std::vector<RenderSampleResult<UnrelatedUploadRenderReadDuration> >& samples) { log << tcu::TestLog::SampleList("Samples", "Samples") << tcu::TestLog::SampleInfo @@ -1653,7 +1590,7 @@ void logSampleList (tcu::TestLog& log, const TheilSenLineFit& theilSenFitting, c log << tcu::TestLog::EndSampleList; } -void logSampleList (tcu::TestLog& log, const TheilSenLineFit& theilSenFitting, const std::vector<RenderSampleResult<UploadRenderReadDuration> >& samples) +void logSampleList (tcu::TestLog& log, const LineParametersWithConfidence& theilSenFitting, const std::vector<RenderSampleResult<UploadRenderReadDuration> >& samples) { log << tcu::TestLog::SampleList("Samples", "Samples") << tcu::TestLog::SampleInfo @@ -1687,7 +1624,7 @@ void logSampleList (tcu::TestLog& log, const TheilSenLineFit& theilSenFitting, c log << tcu::TestLog::EndSampleList; } -void logSampleList (tcu::TestLog& log, const TheilSenLineFit& theilSenFitting, const std::vector<RenderSampleResult<UploadRenderReadDurationWithUnrelatedUploadSize> >& samples) +void logSampleList (tcu::TestLog& log, const LineParametersWithConfidence& theilSenFitting, const std::vector<RenderSampleResult<UploadRenderReadDurationWithUnrelatedUploadSize> >& samples) { log << tcu::TestLog::SampleList("Samples", "Samples") << tcu::TestLog::SampleInfo @@ -1723,7 +1660,7 @@ void logSampleList (tcu::TestLog& log, const TheilSenLineFit& theilSenFitting, c log << tcu::TestLog::EndSampleList; } -void logSampleList (tcu::TestLog& log, const TheilSenLineFit& theilSenFitting, const std::vector<RenderSampleResult<RenderUploadRenderReadDuration> >& samples) +void logSampleList (tcu::TestLog& log, const LineParametersWithConfidence& theilSenFitting, const std::vector<RenderSampleResult<RenderUploadRenderReadDuration> >& samples) { log << tcu::TestLog::SampleList("Samples", "Samples") << tcu::TestLog::SampleInfo @@ -1763,7 +1700,7 @@ template <typename SampleType> static UploadSampleAnalyzeResult analyzeSampleResults (tcu::TestLog& log, const std::vector<UploadSampleResult<SampleType> >& samples, bool logBucketPerformance) { // Assume data is linear with some outliers, fit a line - const TheilSenLineFit theilSenFitting = fitLineToSamples(samples); + const LineParametersWithConfidence theilSenFitting = fitLineToSamples(samples); const typename SampleTypeTraits<SampleType>::StatsType resultStats = calculateSampleStatistics(theilSenFitting, samples); float approximatedTransferRate; float approximatedTransferRateNoConstant; @@ -1845,11 +1782,11 @@ static UploadSampleAnalyzeResult analyzeSampleResults (tcu::TestLog& log, const log << tcu::TestLog::Float("ResultLinearity", "Sample linearity", "%", QP_KEY_TAG_QUALITY, sampleLinearity * 100.0f) << tcu::TestLog::Float("SampleTemporalStability", "Sample temporal stability", "%", QP_KEY_TAG_QUALITY, sampleTemporalStability * 100.0f) << tcu::TestLog::Float("ApproximatedConstantCost", "Approximated contant cost", "us", QP_KEY_TAG_TIME, theilSenFitting.offset) - << tcu::TestLog::Float("ApproximatedConstantCostConfidence60Lower", "Approximated contant cost 60% confidence lower limit", "us", QP_KEY_TAG_TIME, theilSenFitting.offset60ConfidenceLower) - << tcu::TestLog::Float("ApproximatedConstantCostConfidence60Upper", "Approximated contant cost 60% confidence upper limit", "us", QP_KEY_TAG_TIME, theilSenFitting.offset60ConfidenceUpper) + << tcu::TestLog::Float("ApproximatedConstantCostConfidence60Lower", "Approximated contant cost 60% confidence lower limit", "us", QP_KEY_TAG_TIME, theilSenFitting.offsetConfidenceLower) + << tcu::TestLog::Float("ApproximatedConstantCostConfidence60Upper", "Approximated contant cost 60% confidence upper limit", "us", QP_KEY_TAG_TIME, theilSenFitting.offsetConfidenceUpper) << tcu::TestLog::Float("ApproximatedLinearCost", "Approximated linear cost", "us / MB", QP_KEY_TAG_TIME, theilSenFitting.coefficient * 1024.0f * 1024.0f) - << tcu::TestLog::Float("ApproximatedLinearCostConfidence60Lower", "Approximated linear cost 60% confidence lower limit", "us / MB", QP_KEY_TAG_TIME, theilSenFitting.coefficient60ConfidenceLower * 1024.0f * 1024.0f) - << tcu::TestLog::Float("ApproximatedLinearCostConfidence60Upper", "Approximated linear cost 60% confidence upper limit", "us / MB", QP_KEY_TAG_TIME, theilSenFitting.coefficient60ConfidenceUpper * 1024.0f * 1024.0f) + << tcu::TestLog::Float("ApproximatedLinearCostConfidence60Lower", "Approximated linear cost 60% confidence lower limit", "us / MB", QP_KEY_TAG_TIME, theilSenFitting.coefficientConfidenceLower * 1024.0f * 1024.0f) + << tcu::TestLog::Float("ApproximatedLinearCostConfidence60Upper", "Approximated linear cost 60% confidence upper limit", "us / MB", QP_KEY_TAG_TIME, theilSenFitting.coefficientConfidenceUpper * 1024.0f * 1024.0f) << tcu::TestLog::Float("ApproximatedTransferRate", "Approximated transfer rate", "MB / s", QP_KEY_TAG_PERFORMANCE, approximatedTransferRate / 1024.0f / 1024.0f) << tcu::TestLog::Float("ApproximatedTransferRateNoConstant", "Approximated transfer rate without constant cost", "MB / s", QP_KEY_TAG_PERFORMANCE, approximatedTransferRateNoConstant / 1024.0f / 1024.0f) << tcu::TestLog::Float("SampleMedianTime", "Median sample time", "us", QP_KEY_TAG_TIME, resultStats.result.medianTime) @@ -1872,7 +1809,7 @@ template <typename SampleType> static RenderSampleAnalyzeResult analyzeSampleResults (tcu::TestLog& log, const std::vector<RenderSampleResult<SampleType> >& samples) { // Assume data is linear with some outliers, fit a line - const TheilSenLineFit theilSenFitting = fitLineToSamples(samples); + const LineParametersWithConfidence theilSenFitting = fitLineToSamples(samples); const typename SampleTypeTraits<SampleType>::StatsType resultStats = calculateSampleStatistics(theilSenFitting, samples); float approximatedProcessingRate; float approximatedProcessingRateNoConstant; @@ -1912,11 +1849,11 @@ static RenderSampleAnalyzeResult analyzeSampleResults (tcu::TestLog& log, const log << tcu::TestLog::Float("ResultLinearity", "Sample linearity", "%", QP_KEY_TAG_QUALITY, sampleLinearity * 100.0f) << tcu::TestLog::Float("SampleTemporalStability", "Sample temporal stability", "%", QP_KEY_TAG_QUALITY, sampleTemporalStability * 100.0f) << tcu::TestLog::Float("ApproximatedConstantCost", "Approximated contant cost", "us", QP_KEY_TAG_TIME, theilSenFitting.offset) - << tcu::TestLog::Float("ApproximatedConstantCostConfidence60Lower", "Approximated contant cost 60% confidence lower limit", "us", QP_KEY_TAG_TIME, theilSenFitting.offset60ConfidenceLower) - << tcu::TestLog::Float("ApproximatedConstantCostConfidence60Upper", "Approximated contant cost 60% confidence upper limit", "us", QP_KEY_TAG_TIME, theilSenFitting.offset60ConfidenceUpper) + << tcu::TestLog::Float("ApproximatedConstantCostConfidence60Lower", "Approximated contant cost 60% confidence lower limit", "us", QP_KEY_TAG_TIME, theilSenFitting.offsetConfidenceLower) + << tcu::TestLog::Float("ApproximatedConstantCostConfidence60Upper", "Approximated contant cost 60% confidence upper limit", "us", QP_KEY_TAG_TIME, theilSenFitting.offsetConfidenceUpper) << tcu::TestLog::Float("ApproximatedLinearCost", "Approximated linear cost", "us / MB", QP_KEY_TAG_TIME, theilSenFitting.coefficient * 1024.0f * 1024.0f) - << tcu::TestLog::Float("ApproximatedLinearCostConfidence60Lower", "Approximated linear cost 60% confidence lower limit", "us / MB", QP_KEY_TAG_TIME, theilSenFitting.coefficient60ConfidenceLower * 1024.0f * 1024.0f) - << tcu::TestLog::Float("ApproximatedLinearCostConfidence60Upper", "Approximated linear cost 60% confidence upper limit", "us / MB", QP_KEY_TAG_TIME, theilSenFitting.coefficient60ConfidenceUpper * 1024.0f * 1024.0f) + << tcu::TestLog::Float("ApproximatedLinearCostConfidence60Lower", "Approximated linear cost 60% confidence lower limit", "us / MB", QP_KEY_TAG_TIME, theilSenFitting.coefficientConfidenceLower * 1024.0f * 1024.0f) + << tcu::TestLog::Float("ApproximatedLinearCostConfidence60Upper", "Approximated linear cost 60% confidence upper limit", "us / MB", QP_KEY_TAG_TIME, theilSenFitting.coefficientConfidenceUpper * 1024.0f * 1024.0f) << tcu::TestLog::Float("ApproximatedProcessRate", "Approximated processing rate", "MB / s", QP_KEY_TAG_PERFORMANCE, approximatedProcessingRate / 1024.0f / 1024.0f) << tcu::TestLog::Float("ApproximatedProcessRateNoConstant", "Approximated processing rate without constant cost", "MB / s", QP_KEY_TAG_PERFORMANCE, approximatedProcessingRateNoConstant / 1024.0f / 1024.0f) << tcu::TestLog::Float("SampleMedianTime", "Median sample time", "us", QP_KEY_TAG_TIME, resultStats.result.medianTime) @@ -6233,9 +6170,9 @@ bool UploadWaitDrawCase::checkSampleTemporalStability (deUint64 (UploadWaitDrawC { // Try to find correlation with sample order and sample times - const int numDataPoints = (int)m_iterationOrder.size(); - std::vector<tcu::Vec2> dataPoints (m_iterationOrder.size()); - TheilSenLineFit lineFit; + const int numDataPoints = (int)m_iterationOrder.size(); + std::vector<tcu::Vec2> dataPoints (m_iterationOrder.size()); + LineParametersWithConfidence lineFit; for (int ndx = 0; ndx < (int)m_iterationOrder.size(); ++ndx) { @@ -6243,7 +6180,7 @@ bool UploadWaitDrawCase::checkSampleTemporalStability (deUint64 (UploadWaitDrawC dataPoints[m_iterationOrder[ndx]].y() = (float)(m_results[m_iterationOrder[ndx]].*target); } - lineFit = theilSenLinearRegression(dataPoints); + lineFit = theilSenSiegelLinearRegression(dataPoints, 0.6f); // Difference of more than 25% of the offset along the whole sample range if (de::abs(lineFit.coefficient) * numDataPoints > de::abs(lineFit.offset) * 0.25f) diff --git a/modules/gles3/performance/es3pDepthTests.cpp b/modules/gles3/performance/es3pDepthTests.cpp new file mode 100644 index 000000000..2638a1eba --- /dev/null +++ b/modules/gles3/performance/es3pDepthTests.cpp @@ -0,0 +1,1911 @@ +/*------------------------------------------------------------------------- + * drawElements Quality Program OpenGL ES 3.0 Module + * ------------------------------------------------- + * + * Copyright 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *//*! + * \file + * \brief Depth buffer performance tests. + *//*--------------------------------------------------------------------*/ + +#include "es3pDepthTests.hpp" + +#include "glsCalibration.hpp" + +#include "gluShaderProgram.hpp" +#include "gluObjectWrapper.hpp" +#include "gluPixelTransfer.hpp" + +#include "glwFunctions.hpp" +#include "glwEnums.hpp" + +#include "tcuTestLog.hpp" +#include "tcuStringTemplate.hpp" +#include "tcuCPUWarmup.hpp" +#include "tcuCommandLine.hpp" + +#include "deClock.h" +#include "deString.h" +#include "deMath.h" +#include "deStringUtil.hpp" +#include "deRandom.hpp" +#include "deUniquePtr.hpp" + +#include <vector> +#include <algorithm> + +namespace deqp +{ +namespace gles3 +{ +namespace Performance +{ +namespace +{ +using namespace glw; +using de::MovePtr; +using tcu::TestContext; +using tcu::TestLog; +using tcu::Vec4; +using tcu::Vec3; +using tcu::Vec2; +using glu::RenderContext; +using glu::ProgramSources; +using glu::ShaderSource; +using std::vector; +using std::string; +using std::map; + +struct Sample +{ + deInt64 nullTime; + deInt64 baseTime; + deInt64 testTime; + int order; + int workload; +}; + +struct SampleParams +{ + int step; + int measurement; + + SampleParams(int step_, int measurement_) : step(step_), measurement(measurement_) {} +}; + +typedef vector<float> Geometry; + +struct ObjectData +{ + ProgramSources shader; + Geometry geometry; + + ObjectData (const ProgramSources& shader_, const Geometry& geometry_) : shader(shader_), geometry(geometry_) {} +}; + +class RenderData +{ +public: + RenderData (const ObjectData& object, const glu::RenderContext& renderCtx, TestLog& log); + ~RenderData (void) {}; + + const glu::ShaderProgram m_program; + const glu::VertexArray m_vao; + const glu::Buffer m_vbo; + + const int m_numVertices; +}; + +RenderData::RenderData (const ObjectData& object, const glu::RenderContext& renderCtx, TestLog& log) + : m_program (renderCtx, object.shader) + , m_vao (renderCtx.getFunctions()) + , m_vbo (renderCtx.getFunctions()) + , m_numVertices (int(object.geometry.size())/4) +{ + const glw::Functions& gl = renderCtx.getFunctions(); + + if (!m_program.isOk()) + log << m_program; + + gl.bindBuffer(GL_ARRAY_BUFFER, *m_vbo); + gl.bufferData(GL_ARRAY_BUFFER, object.geometry.size() * sizeof(float), &object.geometry[0], GL_STATIC_DRAW); + gl.bindAttribLocation(m_program.getProgram(), 0, "a_position"); + + gl.bindVertexArray(*m_vao); + gl.vertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL); + gl.enableVertexAttribArray(0); + gl.bindVertexArray(0); +} + +namespace Utils +{ + vector<float> getFullscreenQuad (float depth) + { + const float data[] = + { + +1.0f, +1.0f, depth, 0.0f, // .w is gl_VertexId%3 since Nexus 4&5 can't handle that on their own + +1.0f, -1.0f, depth, 1.0f, + -1.0f, -1.0f, depth, 2.0f, + -1.0f, -1.0f, depth, 0.0f, + -1.0f, +1.0f, depth, 1.0f, + +1.0f, +1.0f, depth, 2.0f, + }; + + return vector<float>(DE_ARRAY_BEGIN(data), DE_ARRAY_END(data)); + } + + vector<float> getFullscreenQuadWithGradient (float depth0, float depth1) + { + const float data[] = + { + +1.0f, +1.0f, depth0, 0.0f, + +1.0f, -1.0f, depth0, 1.0f, + -1.0f, -1.0f, depth1, 2.0f, + -1.0f, -1.0f, depth1, 0.0f, + -1.0f, +1.0f, depth1, 1.0f, + +1.0f, +1.0f, depth0, 2.0f, + }; + + return vector<float>(DE_ARRAY_BEGIN(data), DE_ARRAY_END(data)); + } + + vector<float> getPartScreenQuad (float coverage, float depth) + { + const float xMax = -1.0f + 2.0f*coverage; + const float data[] = + { + xMax, +1.0f, depth, 0.0f, + xMax, -1.0f, depth, 1.0f, + -1.0f, -1.0f, depth, 2.0f, + -1.0f, -1.0f, depth, 0.0f, + -1.0f, +1.0f, depth, 1.0f, + xMax, +1.0f, depth, 2.0f, + }; + + return vector<float>(DE_ARRAY_BEGIN(data), DE_ARRAY_END(data)); + } + + // Axis aligned grid. Depth of vertices is baseDepth +/- depthNoise + vector<float> getFullScreenGrid (int resolution, deUint32 seed, float baseDepth, float depthNoise, float xyNoise) + { + const int gridsize = resolution+1; + vector<Vec3> vertices (gridsize*gridsize); + vector<float> retval; + de::Random rng (seed); + + for (int y = 0; y < gridsize; y++) + for (int x = 0; x < gridsize; x++) + { + const bool isEdge = x == 0 || y == 0 || x == resolution || y == resolution; + const float x_ = float(x)/float(resolution)*2.0f - 1.0f + (isEdge ? 0.0f : rng.getFloat(-xyNoise, +xyNoise)); + const float y_ = float(y)/float(resolution)*2.0f - 1.0f + (isEdge ? 0.0f : rng.getFloat(-xyNoise, +xyNoise)); + const float z_ = baseDepth + rng.getFloat(-depthNoise, +depthNoise); + + vertices[y*gridsize + x] = Vec3(x_, y_, z_); + } + + retval.reserve(resolution*resolution*6); + + for (int y = 0; y < resolution; y++) + for (int x = 0; x < resolution; x++) + { + const Vec3& p0 = vertices[(y+0)*gridsize + (x+0)]; + const Vec3& p1 = vertices[(y+0)*gridsize + (x+1)]; + const Vec3& p2 = vertices[(y+1)*gridsize + (x+0)]; + const Vec3& p3 = vertices[(y+1)*gridsize + (x+1)]; + + const float temp[6*4] = + { + p0.x(), p0.y(), p0.z(), 0.0f, + p2.x(), p2.y(), p2.z(), 1.0f, + p1.x(), p1.y(), p1.z(), 2.0f, + + p3.x(), p3.y(), p3.z(), 0.0f, + p1.x(), p1.y(), p1.z(), 1.0f, + p2.x(), p2.y(), p2.z(), 2.0f, + }; + + retval.insert(retval.end(), DE_ARRAY_BEGIN(temp), DE_ARRAY_END(temp)); + } + + return retval; + } + + // Outputs barycentric coordinates as v_bcoords. Otherwise a passthrough shader + string getBaseVertexShader (void) + { + return "#version 300 es\n" + "in highp vec4 a_position;\n" + "out mediump vec3 v_bcoords;\n" + "void main()\n" + "{\n" + " v_bcoords = vec3(0, 0, 0);\n" + " v_bcoords[int(a_position.w)] = 1.0;\n" + " gl_Position = vec4(a_position.xyz, 1.0);\n" + "}\n"; + } + + // Adds noise to coordinates based on InstanceID Outputs barycentric coordinates as v_bcoords + string getInstanceNoiseVertexShader (void) + { + return "#version 300 es\n" + "in highp vec4 a_position;\n" + "out mediump vec3 v_bcoords;\n" + "void main()\n" + "{\n" + " v_bcoords = vec3(0, 0, 0);\n" + " v_bcoords[int(a_position.w)] = 1.0;\n" + " vec3 noise = vec3(sin(float(gl_InstanceID)*1.05), sin(float(gl_InstanceID)*1.23), sin(float(gl_InstanceID)*1.71));\n" + " gl_Position = vec4(a_position.xyz + noise * 0.005, 1.0);\n" + "}\n"; + } + + // Renders green triangles with edges highlighted. Exact shade depends on depth. + string getDepthAsGreenFragmentShader (void) + { + return "#version 300 es\n" + "in mediump vec3 v_bcoords;\n" + "out mediump vec4 fragColor;\n" + "void main()\n" + "{\n" + " mediump float d = gl_FragCoord.z;\n" + " if (v_bcoords.x < 0.02 || v_bcoords.y < 0.02 || v_bcoords.z < 0.02)\n" + " fragColor = vec4(d,1,d,1);\n" + " else\n" + " fragColor = vec4(0,d,0,1);\n" + "}\n"; + } + + // Renders green triangles with edges highlighted. Exact shade depends on depth. + string getDepthAsRedFragmentShader (void) + { + return "#version 300 es\n" + "in mediump vec3 v_bcoords;\n" + "out mediump vec4 fragColor;\n" + "void main()\n" + "{\n" + " mediump float d = gl_FragCoord.z;\n" + " if (v_bcoords.x < 0.02 || v_bcoords.y < 0.02 || v_bcoords.z < 0.02)\n" + " fragColor = vec4(1,d,d,1);\n" + " else\n" + " fragColor = vec4(d,0,0,1);\n" + "}\n"; + } + + // Basic time waster. Renders red triangles with edges highlighted. Exact shade depends on depth. + string getArithmeticWorkloadFragmentShader (void) + { + + return "#version 300 es\n" + "in mediump vec3 v_bcoords;\n" + "out mediump vec4 fragColor;\n" + "uniform mediump int u_iterations;\n" + "void main()\n" + "{\n" + " mediump float d = gl_FragCoord.z;\n" + " for (int i = 0; i<u_iterations; i++)\n" + // cos(a)^2 + sin(a)^2 == 1. since d is in range [0,1] this will lose a few ULP's of precision per iteration but should not significantly change the value of d without extreme iteration counts + " d = d*sin(d)*sin(d) + d*cos(d)*cos(d);\n" + " if (v_bcoords.x < 0.02 || v_bcoords.y < 0.02 || v_bcoords.z < 0.02)\n" + " fragColor = vec4(1,d,d,1);\n" + " else\n" + " fragColor = vec4(d,0,0,1);\n" + "}\n"; + } + + // Arithmetic workload shader but contains discard + string getArithmeticWorkloadDiscardFragmentShader (void) + { + return "#version 300 es\n" + "in mediump vec3 v_bcoords;\n" + "out mediump vec4 fragColor;\n" + "uniform mediump int u_iterations;\n" + "void main()\n" + "{\n" + " mediump float d = gl_FragCoord.z;\n" + " for (int i = 0; i<u_iterations; i++)\n" + " d = d*sin(d)*sin(d) + d*cos(d)*cos(d);\n" + " if (d < 0.5) discard;\n" + " if (v_bcoords.x < 0.02 || v_bcoords.y < 0.02 || v_bcoords.z < 0.02)\n" + " fragColor = vec4(1,d,d,1);\n" + " else\n" + " fragColor = vec4(d,0,0,1);\n" + "}\n"; + } + + // Texture fetch based time waster. Renders red triangles with edges highlighted. Exact shade depends on depth. + string getTextureWorkloadFragmentShader (void) + { + return "#version 300 es\n" + "in mediump vec3 v_bcoords;\n" + "out mediump vec4 fragColor;\n" + "uniform mediump int u_iterations;\n" + "uniform sampler2D u_texture;\n" + "void main()\n" + "{\n" + " mediump float d = gl_FragCoord.z;\n" + " for (int i = 0; i<u_iterations; i++)\n" + " d *= texture(u_texture, (gl_FragCoord.xy+vec2(i))/512.0).r;\n" // Texture is expected to be fully white + " if (v_bcoords.x < 0.02 || v_bcoords.y < 0.02 || v_bcoords.z < 0.02)\n" + " fragColor = vec4(1,1,1,1);\n" + " else\n" + " fragColor = vec4(d,0,0,1);\n" + "}\n"; + } + + // Discard fragments in a grid pattern + string getGridDiscardFragmentShader (int gridsize) + { + const string fragSrc = "#version 300 es\n" + "in mediump vec3 v_bcoords;\n" + "out mediump vec4 fragColor;\n" + "void main()\n" + "{\n" + " mediump float d = gl_FragCoord.z;\n" + " if ((int(gl_FragCoord.x)/${GRIDRENDER_SIZE} + int(gl_FragCoord.y)/${GRIDRENDER_SIZE})%2 == 0)\n" + " discard;\n" + " if (v_bcoords.x < 0.02 || v_bcoords.y < 0.02 || v_bcoords.z < 0.02)\n" + " fragColor = vec4(d,1,d,1);\n" + " else\n" + " fragColor = vec4(0,d,0,1);\n" + "}\n"; + map<string, string> params; + + params["GRIDRENDER_SIZE"] = de::toString(gridsize); + + return tcu::StringTemplate(fragSrc).specialize(params); + } + + // A static increment to frag depth + string getStaticFragDepthFragmentShader (void) + { + return "#version 300 es\n" + "in mediump vec3 v_bcoords;\n" + "out mediump vec4 fragColor;\n" + "void main()\n" + "{\n" + " mediump float d = gl_FragCoord.z;\n" + " gl_FragDepth = gl_FragCoord.z + 0.1;\n" + " if (v_bcoords.x < 0.02 || v_bcoords.y < 0.02 || v_bcoords.z < 0.02)\n" + " fragColor = vec4(d,1,d,1);\n" + " else\n" + " fragColor = vec4(0,d,0,1);\n" + "}\n"; + } + + // A trivial dynamic change to frag depth + string getDynamicFragDepthFragmentShader (void) + { + return "#version 300 es\n" + "in mediump vec3 v_bcoords;\n" + "out mediump vec4 fragColor;\n" + "void main()\n" + "{\n" + " mediump float d = gl_FragCoord.z;\n" + " gl_FragDepth = gl_FragCoord.z + (v_bcoords.x + v_bcoords.y + v_bcoords.z)*0.05;\n" // Sum of v_bcoords components is allways 1 + " if (v_bcoords.x < 0.02 || v_bcoords.y < 0.02 || v_bcoords.z < 0.02)\n" + " fragColor = vec4(d,1,d,1);\n" + " else\n" + " fragColor = vec4(0,d,0,1);\n" + "}\n"; + } + + // A static increment to frag depth + string getStaticFragDepthArithmeticWorkloadFragmentShader (void) + { + return "#version 300 es\n" + "in mediump vec3 v_bcoords;\n" + "out mediump vec4 fragColor;\n" + "uniform mediump int u_iterations;\n" + "void main()\n" + "{\n" + " mediump float d = gl_FragCoord.z;\n" + " gl_FragDepth = gl_FragCoord.z + 0.1;\n" + " for (int i = 0; i<u_iterations; i++)\n" + " d = d*sin(d)*sin(d) + d*cos(d)*cos(d);\n" + " if (v_bcoords.x < 0.02 || v_bcoords.y < 0.02 || v_bcoords.z < 0.02)\n" + " fragColor = vec4(1,d,d,1);\n" + " else\n" + " fragColor = vec4(d,0,0,1);\n" + "}\n"; + } + + // A trivial dynamic change to frag depth + string getDynamicFragDepthArithmeticWorkloadFragmentShader (void) + { + return "#version 300 es\n" + "in mediump vec3 v_bcoords;\n" + "out mediump vec4 fragColor;\n" + "uniform mediump int u_iterations;\n" + "void main()\n" + "{\n" + " mediump float d = gl_FragCoord.z;\n" + " gl_FragDepth = gl_FragCoord.z + (v_bcoords.x + v_bcoords.y + v_bcoords.z)*0.05;\n" // Sum of v_bcoords components is allways 1 + " for (int i = 0; i<u_iterations; i++)\n" + " d = d*sin(d)*sin(d) + d*cos(d)*cos(d);\n" + " if (v_bcoords.x < 0.02 || v_bcoords.y < 0.02 || v_bcoords.z < 0.02)\n" + " fragColor = vec4(1,d,d,1);\n" + " else\n" + " fragColor = vec4(d,0,0,1);\n" + "}\n"; + } + + glu::ProgramSources getBaseShader (void) + { + return glu::makeVtxFragSources(getBaseVertexShader(), getDepthAsGreenFragmentShader()); + } + + glu::ProgramSources getArithmeticWorkloadShader (void) + { + return glu::makeVtxFragSources(getBaseVertexShader(), getArithmeticWorkloadFragmentShader()); + } + + glu::ProgramSources getArithmeticWorkloadDiscardShader (void) + { + return glu::makeVtxFragSources(getBaseVertexShader(), getArithmeticWorkloadDiscardFragmentShader()); + } + + glu::ProgramSources getTextureWorkloadShader (void) + { + return glu::makeVtxFragSources(getBaseVertexShader(), getTextureWorkloadFragmentShader()); + } + + glu::ProgramSources getGridDiscardShader (int gridsize) + { + return glu::makeVtxFragSources(getBaseVertexShader(), getGridDiscardFragmentShader(gridsize)); + } + + inline ObjectData quadWith (const glu::ProgramSources& shader, float depth) + { + return ObjectData(shader, getFullscreenQuad(depth)); + } + + inline ObjectData quadWith (const string& fragShader, float depth) + { + return ObjectData(glu::makeVtxFragSources(getBaseVertexShader(), fragShader), getFullscreenQuad(depth)); + } + + inline ObjectData variableQuad (float depth) + { + return ObjectData(glu::makeVtxFragSources(getInstanceNoiseVertexShader(), getDepthAsRedFragmentShader()), getFullscreenQuad(depth)); + } + + inline ObjectData fastQuad (float depth) + { + return ObjectData(getBaseShader(), getFullscreenQuad(depth)); + } + + inline ObjectData slowQuad (float depth) + { + return ObjectData(getArithmeticWorkloadShader(), getFullscreenQuad(depth)); + } + + inline ObjectData fastQuadWithGradient (float depth0, float depth1) + { + return ObjectData(getBaseShader(), getFullscreenQuadWithGradient(depth0, depth1)); + } +} // Utils + +// Shared base +class BaseCase : public tcu::TestCase +{ +public: + enum {RENDER_SIZE = 512}; + + BaseCase (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc); + virtual ~BaseCase (void) {} + + virtual IterateResult iterate (void); + +protected: + void logSamples (const vector<Sample>& samples, const string& name, const string& desc); + void logGeometry (const tcu::ConstPixelBufferAccess& sample, const glu::ShaderProgram& occluderProg, const glu::ShaderProgram& occludedProg); + virtual void logAnalysis (const vector<Sample>& samples) = 0; + virtual void logDescription (void) = 0; + + virtual ObjectData genOccluderGeometry (void) const = 0; + virtual ObjectData genOccludedGeometry (void) const = 0; + + virtual int calibrate (void) const = 0; + virtual Sample renderSample (const RenderData& occluder, const RenderData& occluded, int workload) const = 0; + + void render (const RenderData& data) const; + void render (const RenderData& data, int instances) const; + + const RenderContext& m_renderCtx; + tcu::ResultCollector m_results; + + enum {ITERATION_STEPS = 10, ITERATION_SAMPLES = 16}; +}; + +BaseCase::BaseCase (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc) + : TestCase (testCtx, tcu::NODETYPE_PERFORMANCE, name, desc) + , m_renderCtx (renderCtx) +{ +} + +BaseCase::IterateResult BaseCase::iterate (void) +{ + typedef de::MovePtr<RenderData> RenderDataP; + + const glw::Functions& gl = m_renderCtx.getFunctions(); + TestLog& log = m_testCtx.getLog(); + + const glu::Framebuffer framebuffer (gl); + const glu::Renderbuffer renderbuffer (gl); + const glu::Renderbuffer depthbuffer (gl); + + vector<Sample> results; + vector<int> params; + RenderDataP occluderData; + RenderDataP occludedData; + tcu::TextureLevel resultTex (tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), RENDER_SIZE, RENDER_SIZE); + int maxWorkload = 0; + de::Random rng (deInt32Hash(deStringHash(getName())) ^ m_testCtx.getCommandLine().getBaseSeed()); + + logDescription(); + + gl.bindRenderbuffer(GL_RENDERBUFFER, *renderbuffer); + gl.renderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, RENDER_SIZE, RENDER_SIZE); + gl.bindRenderbuffer(GL_RENDERBUFFER, *depthbuffer); + gl.renderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, RENDER_SIZE, RENDER_SIZE); + + gl.bindFramebuffer(GL_FRAMEBUFFER, *framebuffer); + gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, *renderbuffer); + gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, *depthbuffer); + gl.viewport(0, 0, RENDER_SIZE, RENDER_SIZE); + gl.clearColor(0.125f, 0.25f, 0.5f, 1.0f); + + maxWorkload = calibrate(); + + // Setup data + occluderData = RenderDataP(new RenderData (genOccluderGeometry(), m_renderCtx, log)); + occludedData = RenderDataP(new RenderData (genOccludedGeometry(), m_renderCtx, log)); + + TCU_CHECK(occluderData->m_program.isOk()); + TCU_CHECK(occludedData->m_program.isOk()); + + // Force initialization of GPU resources + gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + gl.enable(GL_DEPTH_TEST); + + render(*occluderData); + render(*occludedData); + glu::readPixels(m_renderCtx, 0, 0, resultTex.getAccess()); + + logGeometry(resultTex.getAccess(), occluderData->m_program, occludedData->m_program); + + params.reserve(ITERATION_STEPS*ITERATION_SAMPLES); + + // Setup parameters + for (int step = 0; step < ITERATION_STEPS; step++) + { + const int workload = maxWorkload*step/ITERATION_STEPS; + + for (int count = 0; count < ITERATION_SAMPLES; count++) + params.push_back(workload); + } + + rng.shuffle(params.begin(), params.end()); + + // Render samples + for (size_t ndx = 0; ndx < params.size(); ndx++) + { + const int workload = params[ndx]; + Sample sample = renderSample(*occluderData, *occludedData, workload); + + sample.workload = workload; + sample.order = int(ndx); + + results.push_back(sample); + } + + logSamples(results, "Samples", "Samples"); + logAnalysis(results); + + m_results.setTestContextResult(m_testCtx); + + return STOP; +} + +void BaseCase::logSamples (const vector<Sample>& samples, const string& name, const string& desc) +{ + TestLog& log = m_testCtx.getLog(); + + bool testOnly = true; + + for (size_t ndx = 0; ndx < samples.size(); ndx++) + { + if (samples[ndx].baseTime != 0 || samples[ndx].nullTime != 0) + { + testOnly = false; + break; + } + } + + log << TestLog::SampleList(name, desc); + + if (testOnly) + { + log << TestLog::SampleInfo + << TestLog::ValueInfo("Workload", "Workload", "", QP_SAMPLE_VALUE_TAG_PREDICTOR) + << TestLog::ValueInfo("Order", "Order of sample", "", QP_SAMPLE_VALUE_TAG_PREDICTOR) + << TestLog::ValueInfo("TestTime", "Test render time", "us", QP_SAMPLE_VALUE_TAG_RESPONSE) + << TestLog::EndSampleInfo; + + for (size_t sampleNdx = 0; sampleNdx < samples.size(); sampleNdx++) + { + const Sample& sample = samples[sampleNdx]; + + log << TestLog::Sample << sample.workload << sample.order << sample.testTime << TestLog::EndSample; + } + } + else + { + log << TestLog::SampleInfo + << TestLog::ValueInfo("Workload", "Workload", "", QP_SAMPLE_VALUE_TAG_PREDICTOR) + << TestLog::ValueInfo("Order", "Order of sample", "", QP_SAMPLE_VALUE_TAG_PREDICTOR) + << TestLog::ValueInfo("TestTime", "Test render time", "us", QP_SAMPLE_VALUE_TAG_RESPONSE) + << TestLog::ValueInfo("NullTime", "Read pixels time", "us", QP_SAMPLE_VALUE_TAG_RESPONSE) + << TestLog::ValueInfo("BaseTime", "Base render time", "us", QP_SAMPLE_VALUE_TAG_RESPONSE) + << TestLog::EndSampleInfo; + + for (size_t sampleNdx = 0; sampleNdx < samples.size(); sampleNdx++) + { + const Sample& sample = samples[sampleNdx]; + + log << TestLog::Sample << sample.workload << sample.order << sample.testTime << sample.nullTime << sample.baseTime << TestLog::EndSample; + } + } + + log << TestLog::EndSampleList; +} + +void BaseCase::logGeometry (const tcu::ConstPixelBufferAccess& sample, const glu::ShaderProgram& occluderProg, const glu::ShaderProgram& occludedProg) +{ + TestLog& log = m_testCtx.getLog(); + + log << TestLog::Section("Geometry", "Geometry"); + log << TestLog::Message << "Occluding geometry is green with shade dependent on depth (rgb == 0, depth, 0)" << TestLog::EndMessage; + log << TestLog::Message << "Occluded geometry is red with shade dependent on depth (rgb == depth, 0, 0)" << TestLog::EndMessage; + log << TestLog::Message << "Primitive edges are a lighter shade of red/green" << TestLog::EndMessage; + + log << TestLog::Image("Test Geometry", "Test Geometry", sample); + log << TestLog::EndSection; + + log << TestLog::Section("Occluder", "Occluder"); + log << occluderProg; + log << TestLog::EndSection; + + log << TestLog::Section("Occluded", "Occluded"); + log << occludedProg; + log << TestLog::EndSection; +} + +void BaseCase::render (const RenderData& data) const +{ + const glw::Functions& gl = m_renderCtx.getFunctions(); + + gl.useProgram(data.m_program.getProgram()); + + gl.bindVertexArray(*data.m_vao); + gl.drawArrays(GL_TRIANGLES, 0, data.m_numVertices); + gl.bindVertexArray(0); +} + +void BaseCase::render (const RenderData& data, int instances) const +{ + const glw::Functions& gl = m_renderCtx.getFunctions(); + + gl.useProgram(data.m_program.getProgram()); + + gl.bindVertexArray(*data.m_vao); + gl.drawArraysInstanced(GL_TRIANGLES, 0, data.m_numVertices, instances); + gl.bindVertexArray(0); +} + +// Render occluder once, then repeatedly render occluded geometry. Sample with multiple repetition counts & establish time per call with linear regression +class RenderCountCase : public BaseCase +{ +public: + RenderCountCase (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc); + ~RenderCountCase (void) {} + +protected: + virtual void logAnalysis (const vector<Sample>& samples); + +private: + virtual int calibrate (void) const; + virtual Sample renderSample (const RenderData& occluder, const RenderData& occluded, int callcount) const; +}; + +RenderCountCase::RenderCountCase (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc) + : BaseCase (testCtx, renderCtx, name, desc) +{ +} + +void RenderCountCase::logAnalysis (const vector<Sample>& samples) +{ + using namespace gls; + + TestLog& log = m_testCtx.getLog(); + int maxWorkload = 0; + vector<Vec2> testSamples (samples.size()); + + for (size_t ndx = 0; ndx < samples.size(); ndx++) + { + const Sample& sample = samples[ndx]; + + testSamples[ndx] = Vec2((float)sample.workload, (float)sample.testTime); + + maxWorkload = de::max(maxWorkload, sample.workload); + } + + { + const float confidence = 0.60f; + const LineParametersWithConfidence testParam = theilSenSiegelLinearRegression(testSamples, confidence); + const float usPerCall = testParam.coefficient; + const float pxPerCall = RENDER_SIZE*RENDER_SIZE; + const float pxPerUs = pxPerCall/usPerCall; + const float mpxPerS = pxPerUs; + + log << TestLog::Section("Linear Regression", "Linear Regression"); + log << TestLog::Message << "Offset & coefficient presented as [confidence interval min, estimate, confidence interval max]. Reported confidence interval for this test is " << confidence << TestLog::EndMessage; + log << TestLog::Message << "Render time for scene with depth test was\n\t" + << "[" << testParam.offsetConfidenceLower << ", " << testParam.offset << ", " << testParam.offsetConfidenceUpper << "]us +" + << "[" << testParam.coefficientConfidenceLower << ", " << testParam.coefficient << ", " << testParam.coefficientConfidenceUpper << "]" + << "us/workload" << TestLog::EndMessage; + log << TestLog::EndSection; + + log << TestLog::Section("Result", "Result"); + + if (testParam.coefficientConfidenceLower < 0.0f) + { + log << TestLog::Message << "Coefficient confidence bounds include values below 0.0, the operation likely has neglible per-pixel cost" << TestLog::EndMessage; + m_results.addResult(QP_TEST_RESULT_PASS, "Pass"); + } + else if (testParam.coefficientConfidenceLower < testParam.coefficientConfidenceUpper*0.25) + { + log << TestLog::Message << "Coefficient confidence range is extremely large, cannot give reliable result" << TestLog::EndMessage; + m_results.addResult(QP_TEST_RESULT_PASS, "Result confidence extremely low"); + } + else + { + log << TestLog::Message << "Culled hidden pixels @ " << mpxPerS << "Mpx/s" << TestLog::EndMessage; + m_results.addResult(QP_TEST_RESULT_PASS, de::floatToString(mpxPerS, 2)); + } + + log << TestLog::EndSection; + } +} + +Sample RenderCountCase::renderSample (const RenderData& occluder, const RenderData& occluded, int callcount) const +{ + const glw::Functions& gl = m_renderCtx.getFunctions(); + Sample sample; + deUint64 now = 0; + deUint64 prev = 0; + deUint8 buffer[4]; + + // Stabilize + { + gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + gl.enable(GL_DEPTH_TEST); + gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, buffer); + } + + prev = deGetMicroseconds(); + + gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + gl.enable(GL_DEPTH_TEST); + + render(occluder); + render(occluded, callcount); + + gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, buffer); + + now = deGetMicroseconds(); + + sample.testTime = now - prev; + sample.baseTime = 0; + sample.nullTime = 0; + sample.workload = callcount; + + return sample; +} + +int RenderCountCase::calibrate (void) const +{ + using namespace gls; + + const glw::Functions& gl = m_renderCtx.getFunctions(); + TestLog& log = m_testCtx.getLog(); + + const RenderData occluderGeometry (genOccluderGeometry(), m_renderCtx, log); + const RenderData occludedGeometry (genOccludedGeometry(), m_renderCtx, log); + + TheilSenCalibrator calibrator (CalibratorParameters(20, // Initial workload + 10, // Max iteration frames + 20.0f, // Iteration shortcut threshold ms + 20, // Max iterations + 33.0f, // Target frame time + 40.0f, // Frame time cap + 1000.0f // Target measurement duration + )); + + while (true) + { + switch(calibrator.getState()) + { + case TheilSenCalibrator::STATE_FINISHED: + logCalibrationInfo(m_testCtx.getLog(), calibrator); + return calibrator.getCallCount(); + + case TheilSenCalibrator::STATE_MEASURE: + { + deUint8 buffer[4]; + deInt64 now; + deInt64 prev; + + prev = deGetMicroseconds(); + + gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + gl.disable(GL_DEPTH_TEST); + + render(occluderGeometry); + render(occludedGeometry, calibrator.getCallCount()); + + gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, buffer); + + now = deGetMicroseconds(); + + calibrator.recordIteration(now - prev); + break; + } + + case TheilSenCalibrator::STATE_RECOMPUTE_PARAMS: + calibrator.recomputeParameters(); + break; + default: + DE_ASSERT(false); + return 1; + } + } +} + +// Compares time/workload gradients of same geometry with and without depth testing +class RelativeChangeCase : public BaseCase +{ +public: + RelativeChangeCase (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc); + virtual ~RelativeChangeCase (void) {} + +protected: + Sample renderSample (const RenderData& occluder, const RenderData& occluded, int workload) const; + + virtual void logAnalysis (const vector<Sample>& samples); + +private: + int calibrate (void) const; +}; + +RelativeChangeCase::RelativeChangeCase (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc) + : BaseCase (testCtx, renderCtx, name, desc) +{ +} + +int RelativeChangeCase::calibrate (void) const +{ + using namespace gls; + + const glw::Functions& gl = m_renderCtx.getFunctions(); + TestLog& log = m_testCtx.getLog(); + + const RenderData geom (genOccludedGeometry(), m_renderCtx, log); + + TheilSenCalibrator calibrator(CalibratorParameters( 20, // Initial workload + 10, // Max iteration frames + 20.0f, // Iteration shortcut threshold ms + 20, // Max iterations + 10.0f, // Target frame time + 15.0f, // Frame time cap + 1000.0f // Target measurement duration + )); + + while (true) + { + switch(calibrator.getState()) + { + case TheilSenCalibrator::STATE_FINISHED: + logCalibrationInfo(m_testCtx.getLog(), calibrator); + return calibrator.getCallCount(); + + case TheilSenCalibrator::STATE_MEASURE: + { + deUint8 buffer[4]; + const GLuint program = geom.m_program.getProgram(); + + gl.useProgram(program); + gl.uniform1i(gl.getUniformLocation(program, "u_iterations"), calibrator.getCallCount()); + + const deInt64 prev = deGetMicroseconds(); + + gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + gl.disable(GL_DEPTH_TEST); + + render(geom); + + gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, buffer); + + const deInt64 now = deGetMicroseconds(); + + calibrator.recordIteration(now - prev); + break; + } + + case TheilSenCalibrator::STATE_RECOMPUTE_PARAMS: + calibrator.recomputeParameters(); + break; + default: + DE_ASSERT(false); + return 1; + } + } +} + +Sample RelativeChangeCase::renderSample (const RenderData& occluder, const RenderData& occluded, int workload) const +{ + const glw::Functions& gl = m_renderCtx.getFunctions(); + const GLuint program = occluded.m_program.getProgram(); + Sample sample; + deUint64 now = 0; + deUint64 prev = 0; + deUint8 buffer[4]; + + gl.useProgram(program); + gl.uniform1i(gl.getUniformLocation(program, "u_iterations"), workload); + + // Warmup (this workload seems to reduce variation in following workloads) + { + gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + gl.disable(GL_DEPTH_TEST); + + gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, buffer); + } + + // Null time + { + prev = deGetMicroseconds(); + + gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + gl.disable(GL_DEPTH_TEST); + + gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, buffer); + + now = deGetMicroseconds(); + + sample.nullTime = now - prev; + } + + // Test time + { + prev = deGetMicroseconds(); + + gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + gl.enable(GL_DEPTH_TEST); + + render(occluder); + render(occluded); + + gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, buffer); + + now = deGetMicroseconds(); + + sample.testTime = now - prev; + } + + // Base time + { + prev = deGetMicroseconds(); + + gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + gl.disable(GL_DEPTH_TEST); + + render(occluder); + render(occluded); + + gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, buffer); + + now = deGetMicroseconds(); + + sample.baseTime = now - prev; + } + + sample.workload = 0; + + return sample; +} + +void RelativeChangeCase::logAnalysis (const vector<Sample>& samples) +{ + using namespace gls; + + TestLog& log = m_testCtx.getLog(); + + int maxWorkload = 0; + + vector<Vec2> nullSamples (samples.size()); + vector<Vec2> baseSamples (samples.size()); + vector<Vec2> testSamples (samples.size()); + + for (size_t ndx = 0; ndx < samples.size(); ndx++) + { + const Sample& sample = samples[ndx]; + + nullSamples[ndx] = Vec2((float)sample.workload, (float)sample.nullTime); + baseSamples[ndx] = Vec2((float)sample.workload, (float)sample.baseTime); + testSamples[ndx] = Vec2((float)sample.workload, (float)sample.testTime); + + maxWorkload = de::max(maxWorkload, sample.workload); + } + + { + const float confidence = 0.60f; + + const LineParametersWithConfidence nullParam = theilSenSiegelLinearRegression(nullSamples, confidence); + const LineParametersWithConfidence baseParam = theilSenSiegelLinearRegression(baseSamples, confidence); + const LineParametersWithConfidence testParam = theilSenSiegelLinearRegression(testSamples, confidence); + + if (!de::inRange(0.0f, nullParam.coefficientConfidenceLower, nullParam.coefficientConfidenceUpper)) + { + m_results.addResult(QP_TEST_RESULT_FAIL, "Constant operation sequence duration not constant"); + log << TestLog::Message << "Constant operation sequence timing may vary as a function of workload. Result quality extremely low" << TestLog::EndMessage; + } + + if (de::inRange(0.0f, baseParam.coefficientConfidenceLower, baseParam.coefficientConfidenceUpper)) + { + m_results.addResult(QP_TEST_RESULT_FAIL, "Workload has no effect on duration"); + log << TestLog::Message << "Workload factor has no effect on duration of sample (smart optimizer?)" << TestLog::EndMessage; + } + + log << TestLog::Section("Linear Regression", "Linear Regression"); + log << TestLog::Message << "Offset & coefficient presented as [confidence interval min, estimate, confidence interval max]. Reported confidence interval for this test is " << confidence << TestLog::EndMessage; + + log << TestLog::Message << "Render time for empty scene was\n\t" + << "[" << nullParam.offsetConfidenceLower << ", " << nullParam.offset << ", " << nullParam.offsetConfidenceUpper << "]us +" + << "[" << nullParam.coefficientConfidenceLower << ", " << nullParam.coefficient << ", " << nullParam.coefficientConfidenceUpper << "]" + << "us/workload" << TestLog::EndMessage; + + log << TestLog::Message << "Render time for scene without depth test was\n\t" + << "[" << baseParam.offsetConfidenceLower << ", " << baseParam.offset << ", " << baseParam.offsetConfidenceUpper << "]us +" + << "[" << baseParam.coefficientConfidenceLower << ", " << baseParam.coefficient << ", " << baseParam.coefficientConfidenceUpper << "]" + << "us/workload" << TestLog::EndMessage; + + log << TestLog::Message << "Render time for scene with depth test was\n\t" + << "[" << testParam.offsetConfidenceLower << ", " << testParam.offset << ", " << testParam.offsetConfidenceUpper << "]us +" + << "[" << testParam.coefficientConfidenceLower << ", " << testParam.coefficient << ", " << testParam.coefficientConfidenceUpper << "]" + << "us/workload" << TestLog::EndMessage; + + log << TestLog::EndSection; + + if (de::inRange(0.0f, testParam.coefficientConfidenceLower, testParam.coefficientConfidenceUpper)) + { + log << TestLog::Message << "Test duration not dependent on culled workload" << TestLog::EndMessage; + m_results.addResult(QP_TEST_RESULT_PASS, "0.0"); + } + else if (testParam.coefficientConfidenceLower < testParam.coefficientConfidenceUpper*0.25) + { + log << TestLog::Message << "Coefficient confidence range is extremely large, cannot give reliable result" << TestLog::EndMessage; + m_results.addResult(QP_TEST_RESULT_PASS, "Result confidence extremely low"); + } + else if (baseParam.coefficientConfidenceLower < baseParam.coefficientConfidenceUpper*0.25) + { + log << TestLog::Message << "Coefficient confidence range for base render time is extremely large, cannot give reliable result" << TestLog::EndMessage; + m_results.addResult(QP_TEST_RESULT_PASS, "Result confidence extremely low"); + } + else + { + log << TestLog::Message << "Test duration is dependent on culled workload" << TestLog::EndMessage; + m_results.addResult(QP_TEST_RESULT_PASS, de::floatToString(de::abs(testParam.coefficient)/de::abs(baseParam.coefficient), 2)); + } + } +} + +// Speed of trivial culling +class BaseCostCase : public RenderCountCase +{ +public: + BaseCostCase (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc) + : RenderCountCase (testCtx, renderCtx, name, desc) {} + + ~BaseCostCase (void) {} + +private: + virtual ObjectData genOccluderGeometry (void) const { return Utils::fastQuad(0.2f); } + virtual ObjectData genOccludedGeometry (void) const { return Utils::variableQuad(0.8f); } + + virtual void logDescription (void) + { + TestLog& log = m_testCtx.getLog(); + + log << TestLog::Section("Description", "Test description"); + log << TestLog::Message << "Testing hidden fragment culling speed" << TestLog::EndMessage; + log << TestLog::Message << "Geometry consists of two fullsceen quads. The first (occluding) is rendered once, the second (occluded) is rendered repeatedly" << TestLog::EndMessage; + log << TestLog::Message << "Workload indicates the number of times the occluded quad is rendered" << TestLog::EndMessage; + log << TestLog::Message << "The time per culled pixel is estimated from the rate of change of rendering time as a function of workload" << TestLog::EndMessage; + log << TestLog::EndSection; + } +}; + +// Gradient +class GradientCostCase : public RenderCountCase +{ +public: + GradientCostCase (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc, float gradientDistance) + : RenderCountCase (testCtx, renderCtx, name, desc) + , m_gradientDistance (gradientDistance) + { + } + + ~GradientCostCase (void) {} + +private: + virtual ObjectData genOccluderGeometry (void) const { return Utils::fastQuadWithGradient(0.0f, 1.0f - m_gradientDistance); } + virtual ObjectData genOccludedGeometry (void) const + { + return ObjectData(glu::makeVtxFragSources(Utils::getInstanceNoiseVertexShader(), Utils::getDepthAsRedFragmentShader()), Utils::getFullscreenQuadWithGradient(m_gradientDistance, 1.0f)); + } + + virtual void logDescription (void) + { + TestLog& log = m_testCtx.getLog(); + + log << TestLog::Section("Description", "Test description"); + log << TestLog::Message << "Testing hidden fragment culling speed" << TestLog::EndMessage; + log << TestLog::Message << "Geometry consists of two fullsceen quads. The first (occluding) is rendered once, the second (occluded) is rendered repeatedly" << TestLog::EndMessage; + log << TestLog::Message << "Workload indicates the number of times the occluded quad is rendered" << TestLog::EndMessage; + log << TestLog::Message << "The quads are tilted so that the left edge of the occluded quad has a depth of 1.0 and the right edge of the occluding quad has a depth of 0.0." << TestLog::EndMessage; + log << TestLog::Message << "The quads are spaced to have a depth difference of " << m_gradientDistance << " at all points." << TestLog::EndMessage; + log << TestLog::Message << "The time per culled pixel is estimated from the rate of change of rendering time as a function of workload" << TestLog::EndMessage; + log << TestLog::EndSection; + } + + const float m_gradientDistance; +}; + +// Constant offset to frag depth in occluder +class OccluderStaticFragDepthCostCase : public RenderCountCase +{ +public: + OccluderStaticFragDepthCostCase (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc) + : RenderCountCase(testCtx, renderCtx, name, desc) + { + } + + ~OccluderStaticFragDepthCostCase (void) {} + +private: + virtual ObjectData genOccluderGeometry (void) const { return Utils::quadWith(Utils::getStaticFragDepthFragmentShader(), 0.2f); } + virtual ObjectData genOccludedGeometry (void) const { return Utils::fastQuad(0.8f); } + + virtual void logDescription (void) + { + TestLog& log = m_testCtx.getLog(); + + log << TestLog::Section("Description", "Test description"); + log << TestLog::Message << "Testing hidden fragment culling speed" << TestLog::EndMessage; + log << TestLog::Message << "Geometry consists of two fullsceen quads. The first (occluding) is rendered once, the second (occluded) is rendered repeatedly" << TestLog::EndMessage; + log << TestLog::Message << "Workload indicates the number of times the occluded quad is rendered" << TestLog::EndMessage; + log << TestLog::Message << "The occluder quad has a static offset applied to gl_FragDepth" << TestLog::EndMessage; + log << TestLog::Message << "The time per culled pixel is estimated from the rate of change of rendering time as a function of workload" << TestLog::EndMessage; + log << TestLog::EndSection; + } +}; + +// Dynamic offset to frag depth in occluder +class OccluderDynamicFragDepthCostCase : public RenderCountCase +{ +public: + OccluderDynamicFragDepthCostCase (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc) + : RenderCountCase(testCtx, renderCtx, name, desc) + { + } + + ~OccluderDynamicFragDepthCostCase (void) {} + +private: + virtual ObjectData genOccluderGeometry (void) const { return Utils::quadWith(Utils::getDynamicFragDepthFragmentShader(), 0.2f); } + virtual ObjectData genOccludedGeometry (void) const { return Utils::fastQuad(0.8f); } + + virtual void logDescription (void) + { + TestLog& log = m_testCtx.getLog(); + + log << TestLog::Section("Description", "Test description"); + log << TestLog::Message << "Testing hidden fragment culling speed" << TestLog::EndMessage; + log << TestLog::Message << "Geometry consists of two fullsceen quads. The first (occluding) is rendered once, the second (occluded) is rendered repeatedly" << TestLog::EndMessage; + log << TestLog::Message << "Workload indicates the number of times the occluded quad is rendered" << TestLog::EndMessage; + log << TestLog::Message << "The occluder quad has a dynamic offset applied to gl_FragDepth" << TestLog::EndMessage; + log << TestLog::Message << "The time per culled pixel is estimated from the rate of change of rendering time as a function of workload" << TestLog::EndMessage; + log << TestLog::EndSection; + } +}; + +// Constant offset to frag depth in occluder +class OccludedStaticFragDepthCostCase : public RenderCountCase +{ +public: + OccludedStaticFragDepthCostCase (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc) + : RenderCountCase(testCtx, renderCtx, name, desc) + { + } + + ~OccludedStaticFragDepthCostCase (void) {} + +private: + virtual ObjectData genOccluderGeometry (void) const { return Utils::fastQuad(0.2f); } + virtual ObjectData genOccludedGeometry (void) const { return Utils::quadWith(Utils::getStaticFragDepthFragmentShader(), 0.2f); } + + virtual void logDescription (void) + { + TestLog& log = m_testCtx.getLog(); + + log << TestLog::Section("Description", "Test description"); + log << TestLog::Message << "Testing hidden fragment culling speed" << TestLog::EndMessage; + log << TestLog::Message << "Geometry consists of two fullsceen quads. The first (occluding) is rendered once, the second (occluded) is rendered repeatedly" << TestLog::EndMessage; + log << TestLog::Message << "Workload indicates the number of times the occluded quad is rendered" << TestLog::EndMessage; + log << TestLog::Message << "The occluded quad has a static offset applied to gl_FragDepth" << TestLog::EndMessage; + log << TestLog::Message << "The time per culled pixel is estimated from the rate of change of rendering time as a function of workload" << TestLog::EndMessage; + log << TestLog::EndSection; + } +}; + +// Dynamic offset to frag depth in occluder +class OccludedDynamicFragDepthCostCase : public RenderCountCase +{ +public: + OccludedDynamicFragDepthCostCase (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc) + : RenderCountCase(testCtx, renderCtx, name, desc) + { + } + + ~OccludedDynamicFragDepthCostCase (void) {} + +private: + virtual ObjectData genOccluderGeometry (void) const { return Utils::fastQuad(0.2f); } + virtual ObjectData genOccludedGeometry (void) const { return Utils::quadWith(Utils::getDynamicFragDepthFragmentShader(), 0.2f); } + + virtual void logDescription (void) + { + TestLog& log = m_testCtx.getLog(); + + log << TestLog::Section("Description", "Test description"); + log << TestLog::Message << "Testing hidden fragment culling speed" << TestLog::EndMessage; + log << TestLog::Message << "Geometry consists of two fullsceen quads. The first (occluding) is rendered once, the second (occluded) is rendered repeatedly" << TestLog::EndMessage; + log << TestLog::Message << "Workload indicates the number of times the occluded quad is rendered" << TestLog::EndMessage; + log << TestLog::Message << "The occluded quad has a dynamic offset applied to gl_FragDepth" << TestLog::EndMessage; + log << TestLog::Message << "The time per culled pixel is estimated from the rate of change of rendering time as a function of workload" << TestLog::EndMessage; + log << TestLog::EndSection; + } +}; + +// Culling speed with slightly less trivial geometry +class OccludingGeometryComplexityCostCase : public RenderCountCase +{ +public: + OccludingGeometryComplexityCostCase (TestContext& testCtx, + const RenderContext& renderCtx, + const char* name, + const char* desc, + int resolution, + float xyNoise, + float zNoise) + : RenderCountCase (testCtx, renderCtx, name, desc) + , m_resolution (resolution) + , m_xyNoise (xyNoise) + , m_zNoise (zNoise) + { + } + + ~OccludingGeometryComplexityCostCase (void) {} + +private: + virtual ObjectData genOccluderGeometry (void) const + { + return ObjectData(Utils::getBaseShader(), + Utils::getFullScreenGrid(m_resolution, + deInt32Hash(deStringHash(getName())) ^ m_testCtx.getCommandLine().getBaseSeed(), + 0.2f, + m_zNoise, + m_xyNoise)); + } + + virtual ObjectData genOccludedGeometry (void) const { return Utils::variableQuad(0.8f); } + + virtual void logDescription (void) + { + TestLog& log = m_testCtx.getLog(); + + log << TestLog::Section("Description", "Test description"); + log << TestLog::Message << "Testing hidden fragment culling speed" << TestLog::EndMessage; + log << TestLog::Message << "Geometry consists of an occluding grid and an occluded fullsceen quad. The occluding geometry is rendered once, the occluded one is rendered repeatedly" << TestLog::EndMessage; + log << TestLog::Message << "Workload indicates the number of times the occluded quad is rendered" << TestLog::EndMessage; + log << TestLog::Message << "The time per culled pixel is estimated from the rate of change of rendering time as a function of workload" << TestLog::EndMessage; + log << TestLog::EndSection; + } + + const int m_resolution; + const float m_xyNoise; + const float m_zNoise; +}; + + +// Cases with varying workloads in the fragment shader +class FragmentWorkloadCullCase : public RelativeChangeCase +{ +public: + FragmentWorkloadCullCase (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc); + virtual ~FragmentWorkloadCullCase (void) {} + +private: + virtual ObjectData genOccluderGeometry (void) const { return Utils::fastQuad(0.2f); } + + virtual void logDescription (void); +}; + +FragmentWorkloadCullCase::FragmentWorkloadCullCase (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc) + : RelativeChangeCase (testCtx, renderCtx, name, desc) +{ +} + +void FragmentWorkloadCullCase::logDescription (void) +{ + TestLog& log = m_testCtx.getLog(); + + log << TestLog::Section("Description", "Test description"); + log << TestLog::Message << "Testing effects of culled fragment workload on render time" << TestLog::EndMessage; + log << TestLog::Message << "Geometry consists of two fullsceen quads. The first (occluding) quad uses a trivial shader," + "the second (occluded) contains significant fragment shader work" << TestLog::EndMessage; + log << TestLog::Message << "Workload indicates the number of iterations of dummy work done in the occluded quad's fragment shader" << TestLog::EndMessage; + log << TestLog::Message << "The ratio of rendering times of this scene with/without depth testing are compared" << TestLog::EndMessage; + log << TestLog::Message << "Successfull early Z-testing should result in no correlation between workload and render time" << TestLog::EndMessage; + log << TestLog::EndSection; +} + +// Additional workload consists of texture lookups +class FragmentTextureWorkloadCullCase : public FragmentWorkloadCullCase +{ +public: + FragmentTextureWorkloadCullCase (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc); + virtual ~FragmentTextureWorkloadCullCase (void) {} + + virtual void init (void); + virtual void deinit (void); + +private: + typedef MovePtr<glu::Texture> TexPtr; + + virtual ObjectData genOccludedGeometry (void) const + { + return ObjectData(Utils::getTextureWorkloadShader(), Utils::getFullscreenQuad(0.8f)); + } + + TexPtr m_texture; +}; + +FragmentTextureWorkloadCullCase::FragmentTextureWorkloadCullCase (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc) + : FragmentWorkloadCullCase (testCtx, renderCtx, name, desc) +{ +} + +void FragmentTextureWorkloadCullCase::init (void) +{ + const glw::Functions& gl = m_renderCtx.getFunctions(); + const int size = 128; + const vector<deUint8> data (size*size*4, 255); + + m_texture = MovePtr<glu::Texture>(new glu::Texture(gl)); + + gl.bindTexture(GL_TEXTURE_2D, m_texture); + gl.texImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, size, size, 0, GL_RGBA, GL_UNSIGNED_BYTE, &data[0]); + gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); +} + +void FragmentTextureWorkloadCullCase::deinit (void) +{ + m_texture.clear(); +} + +// Additional workload consists of arithmetic +class FragmentArithmeticWorkloadCullCase : public FragmentWorkloadCullCase +{ +public: + FragmentArithmeticWorkloadCullCase (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc) + : FragmentWorkloadCullCase (testCtx, renderCtx, name, desc) + { + } + virtual ~FragmentArithmeticWorkloadCullCase (void) {} + +private: + virtual ObjectData genOccludedGeometry (void) const + { + return ObjectData(Utils::getArithmeticWorkloadShader(), Utils::getFullscreenQuad(0.8f)); + } +}; + +// Contains dynamicly unused discard after a series of calculations +class FragmentDiscardArithmeticWorkloadCullCase : public FragmentWorkloadCullCase +{ +public: + FragmentDiscardArithmeticWorkloadCullCase (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc) + : FragmentWorkloadCullCase (testCtx, renderCtx, name, desc) + { + } + + virtual ~FragmentDiscardArithmeticWorkloadCullCase (void) {} + +private: + virtual ObjectData genOccludedGeometry (void) const + { + return ObjectData(Utils::getArithmeticWorkloadDiscardShader(), Utils::getFullscreenQuad(0.8f)); + } + + virtual void logDescription (void) + { + TestLog& log = m_testCtx.getLog(); + + log << TestLog::Section("Description", "Test description"); + log << TestLog::Message << "Testing effects of culled fragment workload on render time" << TestLog::EndMessage; + log << TestLog::Message << "Geometry consists of two fullsceen quads. The first (occluding) quad uses a trivial shader," + "the second (occluded) contains significant fragment shader work and a discard that is never triggers but has a dynamic condition" << TestLog::EndMessage; + log << TestLog::Message << "Workload indicates the number of iterations of dummy work done in the occluded quad's fragment shader" << TestLog::EndMessage; + log << TestLog::Message << "The ratio of rendering times of this scene with/without depth testing are compared" << TestLog::EndMessage; + log << TestLog::Message << "Successfull early Z-testing should result in no correlation between workload and render time" << TestLog::EndMessage; + log << TestLog::EndSection; + } +}; + +// Discards fragments from the occluder in a grid pattern +class PartialOccluderDiscardCullCase : public RelativeChangeCase +{ +public: + PartialOccluderDiscardCullCase (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc, int gridsize) + : RelativeChangeCase (testCtx, renderCtx, name, desc) + , m_gridsize (gridsize) + { + } + virtual ~PartialOccluderDiscardCullCase (void) {} + +private: + virtual ObjectData genOccluderGeometry (void) const { return Utils::quadWith(Utils::getGridDiscardShader(m_gridsize), 0.2f); } + virtual ObjectData genOccludedGeometry (void) const { return Utils::slowQuad(0.8f); } + + virtual void logDescription (void) + { + TestLog& log = m_testCtx.getLog(); + + log << TestLog::Section("Description", "Test description"); + log << TestLog::Message << "Testing effects of partially discarded occluder on rendering time" << TestLog::EndMessage; + log << TestLog::Message << "Geometry consists of two fullsceen quads. The first (occluding) quad discards half the " + "fragments in a grid pattern, the second (partially occluded) contains significant fragment shader work" << TestLog::EndMessage; + log << TestLog::Message << "Workload indicates the number of iterations of dummy work done in the occluded quad's fragment shader" << TestLog::EndMessage; + log << TestLog::Message << "The ratio of rendering times of this scene with/without depth testing are compared" << TestLog::EndMessage; + log << TestLog::Message << "Successfull early Z-testing should result in depth testing halving the render time" << TestLog::EndMessage; + log << TestLog::EndSection; + } + + const int m_gridsize; +}; + +// Trivial occluder covering part of screen +class PartialOccluderCullCase : public RelativeChangeCase +{ +public: + PartialOccluderCullCase (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc, float coverage) + : RelativeChangeCase (testCtx, renderCtx, name, desc) + , m_coverage (coverage) + { + } + ~PartialOccluderCullCase (void) {} + +private: + virtual ObjectData genOccluderGeometry (void) const { return ObjectData(Utils::getBaseShader(), Utils::getPartScreenQuad(m_coverage, 0.2f)); } + virtual ObjectData genOccludedGeometry (void) const {return Utils::slowQuad(0.8f); } + + virtual void logDescription (void) + { + TestLog& log = m_testCtx.getLog(); + + log << TestLog::Section("Description", "Test description"); + log << TestLog::Message << "Testing effects of partial occluder on rendering time" << TestLog::EndMessage; + log << TestLog::Message << "Geometry consists of two quads. The first (occluding) quad covers " << m_coverage*100.0f + << "% of the screen, while the second (partially occluded, fullscreen) contains significant fragment shader work" << TestLog::EndMessage; + log << TestLog::Message << "Workload indicates the number of iterations of dummy work done in the occluded quad's fragment shader" << TestLog::EndMessage; + log << TestLog::Message << "The ratio of rendering times of this scene with/without depth testing are compared" << TestLog::EndMessage; + log << TestLog::Message << "Successfull early Z-testing should result in render time increasing proportionally with unoccluded area" << TestLog::EndMessage; + log << TestLog::EndSection; + } + + const float m_coverage; +}; + +// Constant offset to frag depth in occluder +class StaticOccluderFragDepthCullCase : public RelativeChangeCase +{ +public: + StaticOccluderFragDepthCullCase (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc) + : RelativeChangeCase(testCtx, renderCtx, name, desc) + { + } + + ~StaticOccluderFragDepthCullCase (void) {} + +private: + virtual ObjectData genOccluderGeometry (void) const { return Utils::quadWith(Utils::getStaticFragDepthFragmentShader(), 0.2f); } + virtual ObjectData genOccludedGeometry (void) const { return Utils::slowQuad(0.8f); } + + virtual void logDescription (void) + { + TestLog& log = m_testCtx.getLog(); + + log << TestLog::Section("Description", "Test description"); + log << TestLog::Message << "Testing effects of non-default frag depth on culling efficiency" << TestLog::EndMessage; + log << TestLog::Message << "Geometry consists of two fullscreen quads. The first (occluding) quad is trivial, while the second (occluded) contains significant fragment shader work" << TestLog::EndMessage; + log << TestLog::Message << "Workload indicates the number of iterations of dummy work done in the occluded quad's fragment shader" << TestLog::EndMessage; + log << TestLog::Message << "The occluder quad has a static offset applied to gl_FragDepth" << TestLog::EndMessage; + log << TestLog::Message << "The ratio of rendering times of this scene with/without depth testing are compared" << TestLog::EndMessage; + log << TestLog::Message << "Successfull early Z-testing should result in no correlation between workload and render time" << TestLog::EndMessage; + log << TestLog::EndSection; + } +}; + +// Dynamic offset to frag depth in occluder +class DynamicOccluderFragDepthCullCase : public RelativeChangeCase +{ +public: + DynamicOccluderFragDepthCullCase (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc) + : RelativeChangeCase(testCtx, renderCtx, name, desc) + { + } + + ~DynamicOccluderFragDepthCullCase (void) {} + +private: + virtual ObjectData genOccluderGeometry (void) const { return Utils::quadWith(Utils::getDynamicFragDepthFragmentShader(), 0.2f); } + virtual ObjectData genOccludedGeometry (void) const { return Utils::slowQuad(0.8f); } + + virtual void logDescription (void) + { + TestLog& log = m_testCtx.getLog(); + + log << TestLog::Section("Description", "Test description"); + log << TestLog::Message << "Testing effects of non-default frag depth on culling efficiency" << TestLog::EndMessage; + log << TestLog::Message << "Geometry consists of two fullscreen quads. The first (occluding) quad is trivial, while the second (occluded) contains significant fragment shader work" << TestLog::EndMessage; + log << TestLog::Message << "Workload indicates the number of iterations of dummy work done in the occluded quad's fragment shader" << TestLog::EndMessage; + log << TestLog::Message << "The occluder quad has a dynamic offset applied to gl_FragDepth" << TestLog::EndMessage; + log << TestLog::Message << "The ratio of rendering times of this scene with/without depth testing are compared" << TestLog::EndMessage; + log << TestLog::Message << "Successfull early Z-testing should result in no correlation between workload and render time" << TestLog::EndMessage; + log << TestLog::EndSection; + } +}; + +// Constant offset to frag depth in occluded +class StaticOccludedFragDepthCullCase : public RelativeChangeCase +{ +public: + StaticOccludedFragDepthCullCase (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc) + : RelativeChangeCase(testCtx, renderCtx, name, desc) + { + } + + ~StaticOccludedFragDepthCullCase (void) {} + +private: + virtual ObjectData genOccluderGeometry (void) const { return Utils::fastQuad(0.2f); } + virtual ObjectData genOccludedGeometry (void) const { return Utils::quadWith(Utils::getStaticFragDepthArithmeticWorkloadFragmentShader(), 0.2f); } + + virtual void logDescription (void) + { + TestLog& log = m_testCtx.getLog(); + + log << TestLog::Section("Description", "Test description"); + log << TestLog::Message << "Testing effects of non-default frag depth on rendering time" << TestLog::EndMessage; + log << TestLog::Message << "Geometry consists of two fullscreen quads. The first (occluding) quad is trivial, while the second (occluded) contains significant fragment shader work" << TestLog::EndMessage; + log << TestLog::Message << "Workload indicates the number of iterations of dummy work done in the occluded quad's fragment shader" << TestLog::EndMessage; + log << TestLog::Message << "The occluded quad has a static offset applied to gl_FragDepth" << TestLog::EndMessage; + log << TestLog::Message << "The ratio of rendering times of this scene with/without depth testing are compared" << TestLog::EndMessage; + log << TestLog::Message << "Successfull early Z-testing should result in no correlation between workload and render time" << TestLog::EndMessage; + log << TestLog::EndSection; + } +}; + +// Dynamic offset to frag depth in occluded +class DynamicOccludedFragDepthCullCase : public RelativeChangeCase +{ +public: + DynamicOccludedFragDepthCullCase (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc) + : RelativeChangeCase(testCtx, renderCtx, name, desc) + { + } + + ~DynamicOccludedFragDepthCullCase (void) {} + +private: + virtual ObjectData genOccluderGeometry (void) const { return Utils::fastQuad(0.2f); } + virtual ObjectData genOccludedGeometry (void) const { return Utils::quadWith(Utils::getDynamicFragDepthArithmeticWorkloadFragmentShader(), 0.2f); } + + virtual void logDescription (void) + { + TestLog& log = m_testCtx.getLog(); + + log << TestLog::Section("Description", "Test description"); + log << TestLog::Message << "Testing effects of non-default frag depth on rendering time" << TestLog::EndMessage; + log << TestLog::Message << "Geometry consists of two fullscreen quads. The first (occluding) quad is trivial, while the second (occluded) contains significant fragment shader work" << TestLog::EndMessage; + log << TestLog::Message << "Workload indicates the number of iterations of dummy work done in the occluded quad's fragment shader" << TestLog::EndMessage; + log << TestLog::Message << "The occluded quad has a dynamic offset applied to gl_FragDepth" << TestLog::EndMessage; + log << TestLog::Message << "The ratio of rendering times of this scene with/without depth testing are compared" << TestLog::EndMessage; + log << TestLog::Message << "Successfull early Z-testing should result in no correlation between workload and render time" << TestLog::EndMessage; + log << TestLog::EndSection; + } +}; + +// Dynamic offset to frag depth in occluded +class ReversedDepthOrderCullCase : public RelativeChangeCase +{ +public: + ReversedDepthOrderCullCase (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc) + : RelativeChangeCase(testCtx, renderCtx, name, desc) + { + } + + ~ReversedDepthOrderCullCase (void) {} + +private: + virtual ObjectData genOccluderGeometry (void) const { return Utils::fastQuad(0.2f); } + virtual ObjectData genOccludedGeometry (void) const { return Utils::slowQuad(0.8f); } + + virtual void logDescription (void) + { + TestLog& log = m_testCtx.getLog(); + + log << TestLog::Section("Description", "Test description"); + log << TestLog::Message << "Testing effects of of back first rendering order on culling efficiency" << TestLog::EndMessage; + log << TestLog::Message << "Geometry consists of two fullscreen quads. The second (occluding) quad is trivial, while the first (occluded) contains significant fragment shader work" << TestLog::EndMessage; + log << TestLog::Message << "Workload indicates the number of iterations of dummy work done in the occluded quad's fragment shader" << TestLog::EndMessage; + log << TestLog::Message << "The ratio of rendering times of this scene with/without depth testing are compared" << TestLog::EndMessage; + log << TestLog::Message << "Successfull early Z-testing should result in no correlation between workload and render time" << TestLog::EndMessage; + log << TestLog::EndSection; + } + + // Rendering order of occluder & occluded is reversed, otherwise identical to parent version + Sample renderSample (const RenderData& occluder, const RenderData& occluded, int workload) const + { + const glw::Functions& gl = m_renderCtx.getFunctions(); + const GLuint program = occluded.m_program.getProgram(); + Sample sample; + deUint64 now = 0; + deUint64 prev = 0; + deUint8 buffer[4]; + + gl.useProgram(program); + gl.uniform1i(gl.getUniformLocation(program, "u_iterations"), workload); + + // Warmup (this workload seems to reduce variation in following workloads) + { + gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + gl.disable(GL_DEPTH_TEST); + + gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, buffer); + } + + // Null time + { + prev = deGetMicroseconds(); + + gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + gl.disable(GL_DEPTH_TEST); + + gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, buffer); + + now = deGetMicroseconds(); + + sample.nullTime = now - prev; + } + + // Test time + { + prev = deGetMicroseconds(); + + gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + gl.enable(GL_DEPTH_TEST); + + render(occluded); + render(occluder); + + gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, buffer); + + now = deGetMicroseconds(); + + sample.testTime = now - prev; + } + + // Base time + { + prev = deGetMicroseconds(); + + gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + gl.disable(GL_DEPTH_TEST); + + render(occluded); + render(occluder); + + gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, buffer); + + now = deGetMicroseconds(); + + sample.baseTime = now - prev; + } + + sample.workload = 0; + + return sample; + } +}; + +} // Anonymous + +DepthTests::DepthTests (Context& context) + : TestCaseGroup (context, "depth", "Depth culling performance") +{ +} + +void DepthTests::init (void) +{ + TestContext& testCtx = m_context.getTestContext(); + const RenderContext& renderCtx = m_context.getRenderContext(); + + { + tcu::TestCaseGroup* const cullEfficiencyGroup = new tcu::TestCaseGroup(m_testCtx, "cull_efficiency", "Fragment cull efficiency"); + + addChild(cullEfficiencyGroup); + + { + tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "workload", "Workload"); + + cullEfficiencyGroup->addChild(group); + + group->addChild(new FragmentTextureWorkloadCullCase( testCtx, renderCtx, "workload_texture", "Fragment shader with texture lookup workload")); + group->addChild(new FragmentArithmeticWorkloadCullCase( testCtx, renderCtx, "workload_arithmetic", "Fragment shader with arithmetic workload")); + group->addChild(new FragmentDiscardArithmeticWorkloadCullCase( testCtx, renderCtx, "workload_arithmetic_discard", "Fragment shader that may discard with arithmetic workload")); + } + + { + tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "occluder_discard", "Discard"); + + cullEfficiencyGroup->addChild(group); + + group->addChild(new PartialOccluderDiscardCullCase(testCtx, renderCtx, "grid_256", "Parts of occluder geometry discarded", 256)); + group->addChild(new PartialOccluderDiscardCullCase(testCtx, renderCtx, "grid_128", "Parts of occluder geometry discarded", 128)); + group->addChild(new PartialOccluderDiscardCullCase(testCtx, renderCtx, "grid_64", "Parts of occluder geometry discarded", 64)); + group->addChild(new PartialOccluderDiscardCullCase(testCtx, renderCtx, "grid_32", "Parts of occluder geometry discarded", 32)); + group->addChild(new PartialOccluderDiscardCullCase(testCtx, renderCtx, "grid_16", "Parts of occluder geometry discarded", 16)); + group->addChild(new PartialOccluderDiscardCullCase(testCtx, renderCtx, "grid_8", "Parts of occluder geometry discarded", 8)); + group->addChild(new PartialOccluderDiscardCullCase(testCtx, renderCtx, "grid_4", "Parts of occluder geometry discarded", 4)); + group->addChild(new PartialOccluderDiscardCullCase(testCtx, renderCtx, "grid_2", "Parts of occluder geometry discarded", 2)); + group->addChild(new PartialOccluderDiscardCullCase(testCtx, renderCtx, "grid_1", "Parts of occluder geometry discarded", 1)); + } + + { + tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "partial_coverage", "Partial Coverage"); + + cullEfficiencyGroup->addChild(group); + + group->addChild(new PartialOccluderCullCase(testCtx, renderCtx, "100", "Occluder covering only part of occluded geometry", 1.00f)); + group->addChild(new PartialOccluderCullCase(testCtx, renderCtx, "099", "Occluder covering only part of occluded geometry", 0.99f)); + group->addChild(new PartialOccluderCullCase(testCtx, renderCtx, "095", "Occluder covering only part of occluded geometry", 0.95f)); + group->addChild(new PartialOccluderCullCase(testCtx, renderCtx, "090", "Occluder covering only part of occluded geometry", 0.90f)); + group->addChild(new PartialOccluderCullCase(testCtx, renderCtx, "080", "Occluder covering only part of occluded geometry", 0.80f)); + group->addChild(new PartialOccluderCullCase(testCtx, renderCtx, "070", "Occluder covering only part of occluded geometry", 0.70f)); + group->addChild(new PartialOccluderCullCase(testCtx, renderCtx, "050", "Occluder covering only part of occluded geometry", 0.50f)); + group->addChild(new PartialOccluderCullCase(testCtx, renderCtx, "025", "Occluder covering only part of occluded geometry", 0.25f)); + group->addChild(new PartialOccluderCullCase(testCtx, renderCtx, "010", "Occluder covering only part of occluded geometry", 0.10f)); + } + + { + tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "frag_depth", "Partial Coverage"); + + cullEfficiencyGroup->addChild(group); + + group->addChild(new StaticOccluderFragDepthCullCase( testCtx, renderCtx, "occluder_static", "")); + group->addChild(new DynamicOccluderFragDepthCullCase(testCtx, renderCtx, "occluder_dynamic", "")); + group->addChild(new StaticOccludedFragDepthCullCase( testCtx, renderCtx, "occluded_static", "")); + group->addChild(new DynamicOccludedFragDepthCullCase(testCtx, renderCtx, "occluded_dynamic", "")); + } + + { + tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "order", "Rendering order"); + + cullEfficiencyGroup->addChild(group); + + group->addChild(new ReversedDepthOrderCullCase(testCtx, renderCtx, "reversed", "Back to front rendering order")); + } + } + + { + tcu::TestCaseGroup* const testCostGroup = new tcu::TestCaseGroup(m_testCtx, "culled_pixel_cost", "Fragment cull efficiency"); + + addChild(testCostGroup); + + { + tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "gradient", "Gradients with small depth differences"); + + testCostGroup->addChild(group); + + group->addChild(new BaseCostCase(testCtx, renderCtx, "flat", "")); + group->addChild(new GradientCostCase(testCtx, renderCtx, "gradient_050", "", 0.50f)); + group->addChild(new GradientCostCase(testCtx, renderCtx, "gradient_010", "", 0.10f)); + group->addChild(new GradientCostCase(testCtx, renderCtx, "gradient_005", "", 0.05f)); + group->addChild(new GradientCostCase(testCtx, renderCtx, "gradient_002", "", 0.02f)); + group->addChild(new GradientCostCase(testCtx, renderCtx, "gradient_001", "", 0.01f)); + } + + { + tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "occluder_geometry", "Occluders with varying geometry complexity"); + + testCostGroup->addChild(group); + + group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "flat_uniform_grid_5", "", 5, 0.0f, 0.0f)); + group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "flat_uniform_grid_15", "", 15, 0.0f, 0.0f)); + group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "flat_uniform_grid_25", "", 25, 0.0f, 0.0f)); + group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "flat_uniform_grid_50", "", 50, 0.0f, 0.0f)); + group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "flat_uniform_grid_100", "", 100, 0.0f, 0.0f)); + + group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "flat_noisy_grid_5", "", 5, 1.0f/5.0f, 0.0f)); + group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "flat_noisy_grid_15", "", 15, 1.0f/15.0f, 0.0f)); + group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "flat_noisy_grid_25", "", 25, 1.0f/25.0f, 0.0f)); + group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "flat_noisy_grid_50", "", 50, 1.0f/50.0f, 0.0f)); + group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "flat_noisy_grid_100", "", 100, 1.0f/100.0f, 0.0f)); + + group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "uneven_uniform_grid_5", "", 5, 0.0f, 0.2f)); + group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "uneven_uniform_grid_15", "", 15, 0.0f, 0.2f)); + group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "uneven_uniform_grid_25", "", 25, 0.0f, 0.2f)); + group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "uneven_uniform_grid_50", "", 50, 0.0f, 0.2f)); + group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "uneven_uniform_grid_100", "", 100, 0.0f, 0.2f)); + + group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "uneven_noisy_grid_5", "", 5, 1.0f/5.0f, 0.2f)); + group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "uneven_noisy_grid_15", "", 15, 1.0f/15.0f, 0.2f)); + group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "uneven_noisy_grid_25", "", 25, 1.0f/25.0f, 0.2f)); + group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "uneven_noisy_grid_50", "", 50, 1.0f/50.0f, 0.2f)); + group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "uneven_noisy_grid_100", "", 100, 1.0f/100.0f, 0.2f)); + } + + { + tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "frag_depth", "Modifying gl_FragDepth"); + + testCostGroup->addChild(group); + + group->addChild(new OccluderStaticFragDepthCostCase( testCtx, renderCtx, "occluder_static", "")); + group->addChild(new OccluderDynamicFragDepthCostCase(testCtx, renderCtx, "occluder_dynamic", "")); + group->addChild(new OccludedStaticFragDepthCostCase( testCtx, renderCtx, "occluded_static", "")); + group->addChild(new OccludedDynamicFragDepthCostCase(testCtx, renderCtx, "occluded_dynamic", "")); + } + } +} + +} // Performance +} // gles3 +} // deqp diff --git a/modules/gles3/performance/es3pDepthTests.hpp b/modules/gles3/performance/es3pDepthTests.hpp new file mode 100644 index 000000000..5b861b5bd --- /dev/null +++ b/modules/gles3/performance/es3pDepthTests.hpp @@ -0,0 +1,53 @@ +#ifndef _ES3PDEPTHTESTS_HPP +#define _ES3PDEPTHTESTS_HPP +/*------------------------------------------------------------------------- + * drawElements Quality Program OpenGL ES 3.0 Module + * ------------------------------------------------- + * + * Copyright 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *//*! + * \file + * \brief Depth buffer performance tests. + *//*--------------------------------------------------------------------*/ + +#include "tcuDefs.hpp" +#include "tes3TestCase.hpp" + +namespace deqp +{ +namespace gles3 +{ +namespace Performance +{ + +class DepthTests : public TestCaseGroup +{ +public: + DepthTests (Context& context); + ~DepthTests (void) {} + + virtual void init (void); + +private: + DepthTests (const DepthTests& other); + DepthTests& operator= (const DepthTests& other); +}; + +} // Performance +} // gles3 +} // deqp + +#endif // _ES3PDEPTHTESTS_HPP diff --git a/modules/gles3/performance/es3pPerformanceTests.cpp b/modules/gles3/performance/es3pPerformanceTests.cpp index f7377cc75..7c05a035d 100644 --- a/modules/gles3/performance/es3pPerformanceTests.cpp +++ b/modules/gles3/performance/es3pPerformanceTests.cpp @@ -35,6 +35,7 @@ #include "es3pStateChangeCallTests.hpp" #include "es3pStateChangeTests.hpp" #include "es3pBufferDataUploadTests.hpp" +#include "es3pDepthTests.hpp" namespace deqp { @@ -131,6 +132,7 @@ void PerformanceTests::init (void) addChild(new ShaderCompilerTests (m_context)); addChild(new APITests (m_context)); addChild(new BufferTestGroup (m_context)); + addChild(new DepthTests (m_context)); } } // Performance diff --git a/modules/gles3/performance/es3pShaderOperatorTests.cpp b/modules/gles3/performance/es3pShaderOperatorTests.cpp index f4254b141..ac502bed6 100644 --- a/modules/gles3/performance/es3pShaderOperatorTests.cpp +++ b/modules/gles3/performance/es3pShaderOperatorTests.cpp @@ -545,13 +545,13 @@ static SegmentedEstimator computeSegmentedEstimator (const vector<Vec2>& data) } { - const gls::LineParameters leftLine = gls::theilSenEstimator(leftData); - const gls::LineParameters rightLine = gls::theilSenEstimator(rightData); + const gls::LineParameters leftLine = gls::theilSenLinearRegression(leftData); + const gls::LineParameters rightLine = gls::theilSenLinearRegression(rightData); if (numDistinctX(leftData) < 2 || leftLine.coefficient > rightLine.coefficient*0.5f) { // Left data doesn't seem credible; assume the data is just a single line. - const gls::LineParameters entireLine = gls::theilSenEstimator(data); + const gls::LineParameters entireLine = gls::theilSenLinearRegression(data); return SegmentedEstimator(gls::LineParameters(entireLine.offset, 0.0f), entireLine, -std::numeric_limits<float>::infinity()); } else |