| /*------------------------------------------------------------------------- |
| * drawElements Quality Program OpenGL (ES) 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 Single-program test case wrapper for ShaderPerformanceMeasurer. |
| *//*--------------------------------------------------------------------*/ |
| |
| #include "glsShaderPerformanceCase.hpp" |
| #include "tcuRenderTarget.hpp" |
| #include "deStringUtil.hpp" |
| #include "deMath.h" |
| |
| #include "glwFunctions.hpp" |
| #include "glwEnums.hpp" |
| |
| using tcu::TestLog; |
| using tcu::Vec4; |
| using namespace glw; // GL types |
| |
| namespace deqp |
| { |
| namespace gls |
| { |
| |
| ShaderPerformanceCase::ShaderPerformanceCase(tcu::TestContext &testCtx, glu::RenderContext &renderCtx, const char *name, |
| const char *description, PerfCaseType caseType) |
| : tcu::TestCase(testCtx, tcu::NODETYPE_PERFORMANCE, name, description) |
| , m_renderCtx(renderCtx) |
| , m_caseType(caseType) |
| , m_program(DE_NULL) |
| , m_measurer(renderCtx, caseType) |
| { |
| } |
| |
| ShaderPerformanceCase::~ShaderPerformanceCase(void) |
| { |
| ShaderPerformanceCase::deinit(); |
| } |
| |
| void ShaderPerformanceCase::setGridSize(int gridW, int gridH) |
| { |
| m_measurer.setGridSize(gridW, gridH); |
| } |
| |
| void ShaderPerformanceCase::setViewportSize(int width, int height) |
| { |
| m_measurer.setViewportSize(width, height); |
| } |
| |
| void ShaderPerformanceCase::setVertexFragmentRatio(float fragmentsPerVertices) |
| { |
| const float eps = 0.01f; |
| int gridW = 255; |
| int gridH = 255; |
| int viewportW = m_renderCtx.getRenderTarget().getWidth(); |
| int viewportH = m_renderCtx.getRenderTarget().getHeight(); |
| |
| for (int i = 0; i < 10; i++) |
| { |
| int numVert = (gridW + 1) * (gridH + 1); |
| int numFrag = viewportW * viewportH; |
| float ratio = (float)numFrag / (float)numVert; |
| |
| if (de::abs(ratio - fragmentsPerVertices) < eps) |
| break; |
| else if (ratio < fragmentsPerVertices) |
| { |
| // Not enough fragments. |
| numVert = deRoundFloatToInt32((float)numFrag / fragmentsPerVertices); |
| |
| while ((gridW + 1) * (gridH + 1) > numVert) |
| { |
| if (gridW > gridH) |
| gridW -= 1; |
| else |
| gridH -= 1; |
| } |
| } |
| else |
| { |
| // Not enough vertices. |
| numFrag = deRoundFloatToInt32((float)numVert * fragmentsPerVertices); |
| |
| while (viewportW * viewportH > numFrag) |
| { |
| if (viewportW > viewportH) |
| viewportW -= 1; |
| else |
| viewportH -= 1; |
| } |
| } |
| } |
| |
| float finalRatio = (float)(viewportW * viewportH) / (float)((gridW + 1) * (gridH + 1)); |
| m_testCtx.getLog() << TestLog::Message |
| << "Requested fragment/vertex-ratio: " << de::floatToString(fragmentsPerVertices, 2) << "\n" |
| << "Computed fragment/vertex-ratio: " << de::floatToString(finalRatio, 2) << TestLog::EndMessage; |
| |
| setGridSize(gridW, gridH); |
| setViewportSize(viewportW, viewportH); |
| } |
| |
| static void logRenderTargetInfo(TestLog &log, const tcu::RenderTarget &renderTarget) |
| { |
| log << TestLog::Section("RenderTarget", "Render target") << TestLog::Message << "size: " << renderTarget.getWidth() |
| << "x" << renderTarget.getHeight() << TestLog::EndMessage << TestLog::Message << "bits:" |
| << " R" << renderTarget.getPixelFormat().redBits << " G" << renderTarget.getPixelFormat().greenBits << " B" |
| << renderTarget.getPixelFormat().blueBits << " A" << renderTarget.getPixelFormat().alphaBits << " D" |
| << renderTarget.getDepthBits() << " S" << renderTarget.getStencilBits() << TestLog::EndMessage; |
| |
| if (renderTarget.getNumSamples() != 0) |
| log << TestLog::Message << renderTarget.getNumSamples() << "x MSAA" << TestLog::EndMessage; |
| else |
| log << TestLog::Message << "No MSAA" << TestLog::EndMessage; |
| |
| log << TestLog::EndSection; |
| } |
| |
| void ShaderPerformanceCase::init(void) |
| { |
| tcu::TestLog &log = m_testCtx.getLog(); |
| |
| m_program = new glu::ShaderProgram(m_renderCtx, glu::makeVtxFragSources(m_vertShaderSource, m_fragShaderSource)); |
| |
| if (m_program->isOk()) |
| { |
| const int initialCallCount = m_initialCalibration ? m_initialCalibration->initialNumCalls : 1; |
| logRenderTargetInfo(log, m_renderCtx.getRenderTarget()); |
| m_measurer.init(m_program->getProgram(), m_attributes, initialCallCount); |
| m_measurer.logParameters(log); |
| log << *m_program; |
| } |
| else |
| { |
| log << *m_program; |
| m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Compile failed"); |
| return; // Skip rest of init. |
| } |
| |
| setupProgram(m_program->getProgram()); |
| setupRenderState(); |
| } |
| |
| void ShaderPerformanceCase::deinit(void) |
| { |
| delete m_program; |
| m_program = DE_NULL; |
| |
| m_measurer.deinit(); |
| } |
| |
| void ShaderPerformanceCase::setupProgram(uint32_t program) |
| { |
| DE_UNREF(program); |
| } |
| |
| void ShaderPerformanceCase::setupRenderState(void) |
| { |
| } |
| |
| ShaderPerformanceCase::IterateResult ShaderPerformanceCase::iterate(void) |
| { |
| DE_ASSERT(m_program); |
| |
| if (!m_program->isOk()) // This happens when compilation failed in init(). |
| return STOP; |
| |
| m_measurer.iterate(); |
| |
| if (m_measurer.isFinished()) |
| { |
| m_measurer.logMeasurementInfo(m_testCtx.getLog()); |
| |
| if (m_initialCalibration) |
| m_initialCalibration->initialNumCalls = de::max(1, m_measurer.getFinalCallCount()); |
| |
| const ShaderPerformanceMeasurer::Result result = m_measurer.getResult(); |
| reportResult(result.megaVertPerSec, result.megaFragPerSec); |
| return STOP; |
| } |
| else |
| return CONTINUE; |
| } |
| |
| void ShaderPerformanceCase::reportResult(float mvertPerSecond, float mfragPerSecond) |
| { |
| float result = 0.0f; |
| switch (m_caseType) |
| { |
| case CASETYPE_VERTEX: |
| result = mvertPerSecond; |
| break; |
| case CASETYPE_FRAGMENT: |
| result = mfragPerSecond; |
| break; |
| case CASETYPE_BALANCED: |
| result = mfragPerSecond; |
| break; |
| default: |
| DE_ASSERT(false); |
| } |
| |
| m_testCtx.setTestResult(QP_TEST_RESULT_PASS, de::floatToString(result, 2).c_str()); |
| } |
| |
| ShaderPerformanceCaseGroup::ShaderPerformanceCaseGroup(tcu::TestContext &testCtx, const char *name, |
| const char *description) |
| : TestCaseGroup(testCtx, name, description) |
| , m_initialCalibrationStorage(new ShaderPerformanceCase::InitialCalibration) |
| { |
| } |
| |
| void ShaderPerformanceCaseGroup::addChild(ShaderPerformanceCase *perfCase) |
| { |
| perfCase->setCalibrationInitialParamStorage(m_initialCalibrationStorage); |
| TestCaseGroup::addChild(perfCase); |
| } |
| |
| } // namespace gls |
| } // namespace deqp |