1e5c31af7Sopenharmony_ci/*------------------------------------------------------------------------- 2e5c31af7Sopenharmony_ci * drawElements Quality Program OpenGL ES 2.0 Module 3e5c31af7Sopenharmony_ci * ------------------------------------------------- 4e5c31af7Sopenharmony_ci * 5e5c31af7Sopenharmony_ci * Copyright 2014 The Android Open Source Project 6e5c31af7Sopenharmony_ci * 7e5c31af7Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 8e5c31af7Sopenharmony_ci * you may not use this file except in compliance with the License. 9e5c31af7Sopenharmony_ci * You may obtain a copy of the License at 10e5c31af7Sopenharmony_ci * 11e5c31af7Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 12e5c31af7Sopenharmony_ci * 13e5c31af7Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 14e5c31af7Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 15e5c31af7Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16e5c31af7Sopenharmony_ci * See the License for the specific language governing permissions and 17e5c31af7Sopenharmony_ci * limitations under the License. 18e5c31af7Sopenharmony_ci * 19e5c31af7Sopenharmony_ci *//*! 20e5c31af7Sopenharmony_ci * \file 21e5c31af7Sopenharmony_ci * \brief Shader operator performance tests. 22e5c31af7Sopenharmony_ci *//*--------------------------------------------------------------------*/ 23e5c31af7Sopenharmony_ci 24e5c31af7Sopenharmony_ci#include "es2pShaderOperatorTests.hpp" 25e5c31af7Sopenharmony_ci#include "glsCalibration.hpp" 26e5c31af7Sopenharmony_ci#include "gluShaderUtil.hpp" 27e5c31af7Sopenharmony_ci#include "gluShaderProgram.hpp" 28e5c31af7Sopenharmony_ci#include "gluPixelTransfer.hpp" 29e5c31af7Sopenharmony_ci#include "tcuTestLog.hpp" 30e5c31af7Sopenharmony_ci#include "tcuRenderTarget.hpp" 31e5c31af7Sopenharmony_ci#include "tcuCommandLine.hpp" 32e5c31af7Sopenharmony_ci#include "tcuSurface.hpp" 33e5c31af7Sopenharmony_ci#include "deStringUtil.hpp" 34e5c31af7Sopenharmony_ci#include "deSharedPtr.hpp" 35e5c31af7Sopenharmony_ci#include "deClock.h" 36e5c31af7Sopenharmony_ci#include "deMath.h" 37e5c31af7Sopenharmony_ci 38e5c31af7Sopenharmony_ci#include "glwEnums.hpp" 39e5c31af7Sopenharmony_ci#include "glwFunctions.hpp" 40e5c31af7Sopenharmony_ci 41e5c31af7Sopenharmony_ci#include <map> 42e5c31af7Sopenharmony_ci#include <algorithm> 43e5c31af7Sopenharmony_ci#include <limits> 44e5c31af7Sopenharmony_ci#include <set> 45e5c31af7Sopenharmony_ci 46e5c31af7Sopenharmony_cinamespace deqp 47e5c31af7Sopenharmony_ci{ 48e5c31af7Sopenharmony_cinamespace gles2 49e5c31af7Sopenharmony_ci{ 50e5c31af7Sopenharmony_cinamespace Performance 51e5c31af7Sopenharmony_ci{ 52e5c31af7Sopenharmony_ci 53e5c31af7Sopenharmony_ciusing namespace gls; 54e5c31af7Sopenharmony_ciusing namespace glu; 55e5c31af7Sopenharmony_ciusing tcu::Vec2; 56e5c31af7Sopenharmony_ciusing tcu::Vec4; 57e5c31af7Sopenharmony_ciusing tcu::TestLog; 58e5c31af7Sopenharmony_ciusing de::SharedPtr; 59e5c31af7Sopenharmony_ci 60e5c31af7Sopenharmony_ciusing std::string; 61e5c31af7Sopenharmony_ciusing std::vector; 62e5c31af7Sopenharmony_ci 63e5c31af7Sopenharmony_ci#define MEASUREMENT_FAIL() throw tcu::InternalError("Unable to get sensible measurements for estimation", DE_NULL, __FILE__, __LINE__) 64e5c31af7Sopenharmony_ci 65e5c31af7Sopenharmony_ci// Number of measurements in OperatorPerformanceCase for each workload size, unless specified otherwise by a command line argument. 66e5c31af7Sopenharmony_cistatic const int DEFAULT_NUM_MEASUREMENTS_PER_WORKLOAD = 3; 67e5c31af7Sopenharmony_ci// How many different workload sizes are used by OperatorPerformanceCase. 68e5c31af7Sopenharmony_cistatic const int NUM_WORKLOADS = 8; 69e5c31af7Sopenharmony_ci// Maximum workload size that can be attempted. In a sensible case, this most likely won't be reached. 70e5c31af7Sopenharmony_cistatic const int MAX_WORKLOAD_SIZE = 1<<29; 71e5c31af7Sopenharmony_ci 72e5c31af7Sopenharmony_ci// BinaryOpCase-specific constants for shader generation. 73e5c31af7Sopenharmony_cistatic const int BINARY_OPERATOR_CASE_NUM_INDEPENDENT_CALCULATIONS = 4; 74e5c31af7Sopenharmony_cistatic const int BINARY_OPERATOR_CASE_SMALL_PROGRAM_UNROLL_AMOUNT = 2; 75e5c31af7Sopenharmony_cistatic const int BINARY_OPERATOR_CASE_BIG_PROGRAM_UNROLL_AMOUNT = 4; 76e5c31af7Sopenharmony_ci 77e5c31af7Sopenharmony_ci// FunctionCase-specific constants for shader generation. 78e5c31af7Sopenharmony_cistatic const int FUNCTION_CASE_NUM_INDEPENDENT_CALCULATIONS = 4; 79e5c31af7Sopenharmony_ci 80e5c31af7Sopenharmony_cistatic const char* const s_swizzles[][4] = 81e5c31af7Sopenharmony_ci{ 82e5c31af7Sopenharmony_ci { "x", "yx", "yzx", "wzyx" }, 83e5c31af7Sopenharmony_ci { "y", "zy", "wyz", "xwzy" }, 84e5c31af7Sopenharmony_ci { "z", "wy", "zxy", "yzwx" }, 85e5c31af7Sopenharmony_ci { "w", "xw", "yxw", "zyxw" } 86e5c31af7Sopenharmony_ci}; 87e5c31af7Sopenharmony_ci 88e5c31af7Sopenharmony_citemplate <int N> 89e5c31af7Sopenharmony_cistatic tcu::Vector<float, N> mean (const vector<tcu::Vector<float, N> >& data) 90e5c31af7Sopenharmony_ci{ 91e5c31af7Sopenharmony_ci tcu::Vector<float, N> sum(0.0f); 92e5c31af7Sopenharmony_ci for (int i = 0; i < (int)data.size(); i++) 93e5c31af7Sopenharmony_ci sum += data[i]; 94e5c31af7Sopenharmony_ci return sum / tcu::Vector<float, N>((float)data.size()); 95e5c31af7Sopenharmony_ci} 96e5c31af7Sopenharmony_ci 97e5c31af7Sopenharmony_cistatic void uniformNfv (const glw::Functions& gl, int n, int location, int count, const float* data) 98e5c31af7Sopenharmony_ci{ 99e5c31af7Sopenharmony_ci switch (n) 100e5c31af7Sopenharmony_ci { 101e5c31af7Sopenharmony_ci case 1: gl.uniform1fv(location, count, data); break; 102e5c31af7Sopenharmony_ci case 2: gl.uniform2fv(location, count, data); break; 103e5c31af7Sopenharmony_ci case 3: gl.uniform3fv(location, count, data); break; 104e5c31af7Sopenharmony_ci case 4: gl.uniform4fv(location, count, data); break; 105e5c31af7Sopenharmony_ci default: DE_ASSERT(false); 106e5c31af7Sopenharmony_ci } 107e5c31af7Sopenharmony_ci} 108e5c31af7Sopenharmony_ci 109e5c31af7Sopenharmony_cistatic void uniformNiv (const glw::Functions& gl, int n, int location, int count, const int* data) 110e5c31af7Sopenharmony_ci{ 111e5c31af7Sopenharmony_ci switch (n) 112e5c31af7Sopenharmony_ci { 113e5c31af7Sopenharmony_ci case 1: gl.uniform1iv(location, count, data); break; 114e5c31af7Sopenharmony_ci case 2: gl.uniform2iv(location, count, data); break; 115e5c31af7Sopenharmony_ci case 3: gl.uniform3iv(location, count, data); break; 116e5c31af7Sopenharmony_ci case 4: gl.uniform4iv(location, count, data); break; 117e5c31af7Sopenharmony_ci default: DE_ASSERT(false); 118e5c31af7Sopenharmony_ci } 119e5c31af7Sopenharmony_ci} 120e5c31af7Sopenharmony_ci 121e5c31af7Sopenharmony_cistatic void uniformMatrixNfv (const glw::Functions& gl, int n, int location, int count, const float* data) 122e5c31af7Sopenharmony_ci{ 123e5c31af7Sopenharmony_ci switch (n) 124e5c31af7Sopenharmony_ci { 125e5c31af7Sopenharmony_ci case 2: gl.uniformMatrix2fv(location, count, GL_FALSE, &data[0]); break; 126e5c31af7Sopenharmony_ci case 3: gl.uniformMatrix3fv(location, count, GL_FALSE, &data[0]); break; 127e5c31af7Sopenharmony_ci case 4: gl.uniformMatrix4fv(location, count, GL_FALSE, &data[0]); break; 128e5c31af7Sopenharmony_ci default: DE_ASSERT(false); 129e5c31af7Sopenharmony_ci } 130e5c31af7Sopenharmony_ci} 131e5c31af7Sopenharmony_ci 132e5c31af7Sopenharmony_cistatic glu::DataType getDataTypeFloatOrVec (int size) 133e5c31af7Sopenharmony_ci{ 134e5c31af7Sopenharmony_ci return size == 1 ? glu::TYPE_FLOAT : glu::getDataTypeFloatVec(size); 135e5c31af7Sopenharmony_ci} 136e5c31af7Sopenharmony_ci 137e5c31af7Sopenharmony_cistatic int getIterationCountOrDefault (const tcu::CommandLine& cmdLine, int def) 138e5c31af7Sopenharmony_ci{ 139e5c31af7Sopenharmony_ci const int cmdLineVal = cmdLine.getTestIterationCount(); 140e5c31af7Sopenharmony_ci return cmdLineVal > 0 ? cmdLineVal : def; 141e5c31af7Sopenharmony_ci} 142e5c31af7Sopenharmony_ci 143e5c31af7Sopenharmony_cistatic string lineParamsString (const LineParameters& params) 144e5c31af7Sopenharmony_ci{ 145e5c31af7Sopenharmony_ci return "y = " + de::toString(params.offset) + " + " + de::toString(params.coefficient) + "*x"; 146e5c31af7Sopenharmony_ci} 147e5c31af7Sopenharmony_ci 148e5c31af7Sopenharmony_cinamespace 149e5c31af7Sopenharmony_ci{ 150e5c31af7Sopenharmony_ci 151e5c31af7Sopenharmony_ci/*--------------------------------------------------------------------*//*! 152e5c31af7Sopenharmony_ci * \brief Abstract class for measuring shader operator performance. 153e5c31af7Sopenharmony_ci * 154e5c31af7Sopenharmony_ci * This class draws multiple times with different workload sizes (set 155e5c31af7Sopenharmony_ci * via a uniform, by subclass). Time for each frame is measured, and the 156e5c31af7Sopenharmony_ci * slope of the workload size vs frame time data is estimated. This slope 157e5c31af7Sopenharmony_ci * tells us the estimated increase in frame time caused by a workload 158e5c31af7Sopenharmony_ci * increase of 1 unit (what 1 workload unit means is up to subclass). 159e5c31af7Sopenharmony_ci * 160e5c31af7Sopenharmony_ci * Generally, the shaders contain not just the operation we're interested 161e5c31af7Sopenharmony_ci * in (e.g. addition) but also some other stuff (e.g. loop overhead). To 162e5c31af7Sopenharmony_ci * eliminate this cost, we actually do the stuff described in the above 163e5c31af7Sopenharmony_ci * paragraph with multiple programs (usually two), which contain different 164e5c31af7Sopenharmony_ci * kinds of workload (e.g. different loop contents). Then we can (in 165e5c31af7Sopenharmony_ci * theory) compute the cost of just one operation in a subclass-dependent 166e5c31af7Sopenharmony_ci * manner. 167e5c31af7Sopenharmony_ci * 168e5c31af7Sopenharmony_ci * At this point, the result tells us the increase in frame time caused 169e5c31af7Sopenharmony_ci * by the addition of one operation. Dividing this by the amount of 170e5c31af7Sopenharmony_ci * draw calls in a frame, and further by the amount of vertices or 171e5c31af7Sopenharmony_ci * fragments in a draw call, we get the time cost of one operation. 172e5c31af7Sopenharmony_ci * 173e5c31af7Sopenharmony_ci * In reality, there sometimes isn't just a trivial linear dependence 174e5c31af7Sopenharmony_ci * between workload size and frame time. Instead, there tends to be some 175e5c31af7Sopenharmony_ci * amount of initial "free" operations. That is, it may be that all 176e5c31af7Sopenharmony_ci * workload sizes below some positive integer C yield the same frame time, 177e5c31af7Sopenharmony_ci * and only workload sizes beyond C increase the frame time in a supposedly 178e5c31af7Sopenharmony_ci * linear manner. Graphically, this means that there graph consists of two 179e5c31af7Sopenharmony_ci * parts: a horizontal left part, and a linearly increasing right part; the 180e5c31af7Sopenharmony_ci * right part starts where the left parts ends. The principal task of these 181e5c31af7Sopenharmony_ci * tests is to look at the slope of the increasing right part. Additionally 182e5c31af7Sopenharmony_ci * an estimate for the amount of initial free operations is calculated. 183e5c31af7Sopenharmony_ci * Note that it is also normal to get graphs where the horizontal left part 184e5c31af7Sopenharmony_ci * is of zero width, i.e. there are no free operations. 185e5c31af7Sopenharmony_ci *//*--------------------------------------------------------------------*/ 186e5c31af7Sopenharmony_ciclass OperatorPerformanceCase : public tcu::TestCase 187e5c31af7Sopenharmony_ci{ 188e5c31af7Sopenharmony_cipublic: 189e5c31af7Sopenharmony_ci enum CaseType 190e5c31af7Sopenharmony_ci { 191e5c31af7Sopenharmony_ci CASETYPE_VERTEX = 0, 192e5c31af7Sopenharmony_ci CASETYPE_FRAGMENT, 193e5c31af7Sopenharmony_ci 194e5c31af7Sopenharmony_ci CASETYPE_LAST 195e5c31af7Sopenharmony_ci }; 196e5c31af7Sopenharmony_ci 197e5c31af7Sopenharmony_ci struct InitialCalibration 198e5c31af7Sopenharmony_ci { 199e5c31af7Sopenharmony_ci int initialNumCalls; 200e5c31af7Sopenharmony_ci InitialCalibration (void) : initialNumCalls(1) {} 201e5c31af7Sopenharmony_ci }; 202e5c31af7Sopenharmony_ci 203e5c31af7Sopenharmony_ci typedef SharedPtr<InitialCalibration> InitialCalibrationStorage; 204e5c31af7Sopenharmony_ci 205e5c31af7Sopenharmony_ci OperatorPerformanceCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* description, 206e5c31af7Sopenharmony_ci CaseType caseType, int numWorkloads, const InitialCalibrationStorage& initialCalibrationStorage); 207e5c31af7Sopenharmony_ci ~OperatorPerformanceCase (void); 208e5c31af7Sopenharmony_ci 209e5c31af7Sopenharmony_ci void init (void); 210e5c31af7Sopenharmony_ci void deinit (void); 211e5c31af7Sopenharmony_ci 212e5c31af7Sopenharmony_ci IterateResult iterate (void); 213e5c31af7Sopenharmony_ci 214e5c31af7Sopenharmony_ci struct AttribSpec 215e5c31af7Sopenharmony_ci { 216e5c31af7Sopenharmony_ci AttribSpec (const char* name_, const tcu::Vec4& p00_, const tcu::Vec4& p01_, const tcu::Vec4& p10_, const tcu::Vec4& p11_) 217e5c31af7Sopenharmony_ci : name (name_) 218e5c31af7Sopenharmony_ci , p00 (p00_) 219e5c31af7Sopenharmony_ci , p01 (p01_) 220e5c31af7Sopenharmony_ci , p10 (p10_) 221e5c31af7Sopenharmony_ci , p11 (p11_) 222e5c31af7Sopenharmony_ci { 223e5c31af7Sopenharmony_ci } 224e5c31af7Sopenharmony_ci 225e5c31af7Sopenharmony_ci AttribSpec (void) {} 226e5c31af7Sopenharmony_ci 227e5c31af7Sopenharmony_ci std::string name; 228e5c31af7Sopenharmony_ci tcu::Vec4 p00; //!< Bottom left. 229e5c31af7Sopenharmony_ci tcu::Vec4 p01; //!< Bottom right. 230e5c31af7Sopenharmony_ci tcu::Vec4 p10; //!< Top left. 231e5c31af7Sopenharmony_ci tcu::Vec4 p11; //!< Top right. 232e5c31af7Sopenharmony_ci }; 233e5c31af7Sopenharmony_ci 234e5c31af7Sopenharmony_ciprotected: 235e5c31af7Sopenharmony_ci struct ProgramContext 236e5c31af7Sopenharmony_ci { 237e5c31af7Sopenharmony_ci string vertShaderSource; 238e5c31af7Sopenharmony_ci string fragShaderSource; 239e5c31af7Sopenharmony_ci vector<AttribSpec> attributes; 240e5c31af7Sopenharmony_ci 241e5c31af7Sopenharmony_ci string description; 242e5c31af7Sopenharmony_ci 243e5c31af7Sopenharmony_ci ProgramContext (void) {} 244e5c31af7Sopenharmony_ci ProgramContext (const string& vs, const string& fs, const vector<AttribSpec>& attrs, const string& desc) 245e5c31af7Sopenharmony_ci : vertShaderSource(vs), fragShaderSource(fs), attributes(attrs), description(desc) {} 246e5c31af7Sopenharmony_ci }; 247e5c31af7Sopenharmony_ci 248e5c31af7Sopenharmony_ci virtual vector<ProgramContext> generateProgramData (void) const = 0; 249e5c31af7Sopenharmony_ci //! Sets program-specific uniforms that don't depend on the workload size. 250e5c31af7Sopenharmony_ci virtual void setGeneralUniforms (deUint32 program) const = 0; 251e5c31af7Sopenharmony_ci //! Sets the uniform(s) that specifies the workload size in the shader. 252e5c31af7Sopenharmony_ci virtual void setWorkloadSizeUniform (deUint32 program, int workload) const = 0; 253e5c31af7Sopenharmony_ci //! Computes the cost of a single operation, given the workload costs per program. 254e5c31af7Sopenharmony_ci virtual float computeSingleOperationTime (const vector<float>& perProgramWorkloadCosts) const = 0; 255e5c31af7Sopenharmony_ci //! Logs a human-readable description of what computeSingleOperationTime does. 256e5c31af7Sopenharmony_ci virtual void logSingleOperationCalculationInfo (void) const = 0; 257e5c31af7Sopenharmony_ci 258e5c31af7Sopenharmony_ci glu::RenderContext& m_renderCtx; 259e5c31af7Sopenharmony_ci 260e5c31af7Sopenharmony_ci CaseType m_caseType; 261e5c31af7Sopenharmony_ci 262e5c31af7Sopenharmony_ciprivate: 263e5c31af7Sopenharmony_ci enum State 264e5c31af7Sopenharmony_ci { 265e5c31af7Sopenharmony_ci STATE_CALIBRATING = 0, //!< Calibrate draw call count, using first program in m_programs, with workload size 1. 266e5c31af7Sopenharmony_ci STATE_FIND_HIGH_WORKLOAD, //!< Find an appropriate lower bound for the highest workload size we intend to use (one with high-enough frame time compared to workload size 1) for each program. 267e5c31af7Sopenharmony_ci STATE_MEASURING, //!< Do actual measurements, for each program in m_programs. 268e5c31af7Sopenharmony_ci STATE_REPORTING, //!< Measurements are done; calculate results and log. 269e5c31af7Sopenharmony_ci STATE_FINISHED, //!< All done. 270e5c31af7Sopenharmony_ci 271e5c31af7Sopenharmony_ci STATE_LAST 272e5c31af7Sopenharmony_ci }; 273e5c31af7Sopenharmony_ci 274e5c31af7Sopenharmony_ci struct WorkloadRecord 275e5c31af7Sopenharmony_ci { 276e5c31af7Sopenharmony_ci int workloadSize; 277e5c31af7Sopenharmony_ci vector<float> frameTimes; //!< In microseconds. 278e5c31af7Sopenharmony_ci 279e5c31af7Sopenharmony_ci WorkloadRecord (int workloadSize_) : workloadSize(workloadSize_) {} 280e5c31af7Sopenharmony_ci bool operator< (const WorkloadRecord& other) const { return this->workloadSize < other.workloadSize; } 281e5c31af7Sopenharmony_ci void addFrameTime (float time) { frameTimes.push_back(time); } 282e5c31af7Sopenharmony_ci float getMedianTime (void) const 283e5c31af7Sopenharmony_ci { 284e5c31af7Sopenharmony_ci vector<float> times = frameTimes; 285e5c31af7Sopenharmony_ci std::sort(times.begin(), times.end()); 286e5c31af7Sopenharmony_ci return times.size() % 2 == 0 ? 287e5c31af7Sopenharmony_ci (times[times.size()/2-1] + times[times.size()/2])*0.5f : 288e5c31af7Sopenharmony_ci times[times.size()/2]; 289e5c31af7Sopenharmony_ci } 290e5c31af7Sopenharmony_ci }; 291e5c31af7Sopenharmony_ci 292e5c31af7Sopenharmony_ci void prepareProgram (int progNdx); //!< Sets attributes and uniforms for m_programs[progNdx]. 293e5c31af7Sopenharmony_ci void prepareWorkload (int progNdx, int workload); //!< Calls setWorkloadSizeUniform and draws, in case the implementation does some draw-time compilation. 294e5c31af7Sopenharmony_ci void prepareNextRound (void); //!< Increases workload and/or updates m_state. 295e5c31af7Sopenharmony_ci void render (int numDrawCalls); 296e5c31af7Sopenharmony_ci deUint64 renderAndMeasure (int numDrawCalls); 297e5c31af7Sopenharmony_ci void adjustAndLogGridAndViewport (void); //!< Log grid and viewport sizes, after possibly reducing them to reduce draw time. 298e5c31af7Sopenharmony_ci 299e5c31af7Sopenharmony_ci vector<Vec2> getWorkloadMedianDataPoints (int progNdx) const; //!< [ Vec2(r.workloadSize, r.getMedianTime()) for r in m_workloadRecords[progNdx] ] 300e5c31af7Sopenharmony_ci 301e5c31af7Sopenharmony_ci const int m_numMeasurementsPerWorkload; 302e5c31af7Sopenharmony_ci const int m_numWorkloads; //!< How many different workload sizes are used for measurement for each program. 303e5c31af7Sopenharmony_ci 304e5c31af7Sopenharmony_ci int m_workloadNdx; //!< Runs from 0 to m_numWorkloads-1. 305e5c31af7Sopenharmony_ci 306e5c31af7Sopenharmony_ci int m_workloadMeasurementNdx; 307e5c31af7Sopenharmony_ci vector<vector<WorkloadRecord> > m_workloadRecordsFindHigh; //!< The measurements done during STATE_FIND_HIGH_WORKLOAD. 308e5c31af7Sopenharmony_ci vector<vector<WorkloadRecord> > m_workloadRecords; //!< The measurements of each program in m_programs. Generated during STATE_MEASURING, into index specified by m_measureProgramNdx. 309e5c31af7Sopenharmony_ci 310e5c31af7Sopenharmony_ci State m_state; 311e5c31af7Sopenharmony_ci int m_measureProgramNdx; //!< When m_state is STATE_FIND_HIGH_WORKLOAD or STATE_MEASURING, this tells which program in m_programs is being measured. 312e5c31af7Sopenharmony_ci 313e5c31af7Sopenharmony_ci vector<int> m_highWorkloadSizes; //!< The first workload size encountered during STATE_FIND_HIGH_WORKLOAD that was determined suitable, for each program. 314e5c31af7Sopenharmony_ci 315e5c31af7Sopenharmony_ci TheilSenCalibrator m_calibrator; 316e5c31af7Sopenharmony_ci InitialCalibrationStorage m_initialCalibrationStorage; 317e5c31af7Sopenharmony_ci 318e5c31af7Sopenharmony_ci int m_viewportWidth; 319e5c31af7Sopenharmony_ci int m_viewportHeight; 320e5c31af7Sopenharmony_ci int m_gridSizeX; 321e5c31af7Sopenharmony_ci int m_gridSizeY; 322e5c31af7Sopenharmony_ci 323e5c31af7Sopenharmony_ci vector<ProgramContext> m_programData; 324e5c31af7Sopenharmony_ci vector<SharedPtr<ShaderProgram> > m_programs; 325e5c31af7Sopenharmony_ci 326e5c31af7Sopenharmony_ci std::vector<deUint32> m_attribBuffers; 327e5c31af7Sopenharmony_ci}; 328e5c31af7Sopenharmony_ci 329e5c31af7Sopenharmony_cistatic inline float triangleInterpolate (float v0, float v1, float v2, float x, float y) 330e5c31af7Sopenharmony_ci{ 331e5c31af7Sopenharmony_ci return v0 + (v2-v0)*x + (v1-v0)*y; 332e5c31af7Sopenharmony_ci} 333e5c31af7Sopenharmony_ci 334e5c31af7Sopenharmony_cistatic inline float triQuadInterpolate (float x, float y, const tcu::Vec4& quad) 335e5c31af7Sopenharmony_ci{ 336e5c31af7Sopenharmony_ci // \note Top left fill rule. 337e5c31af7Sopenharmony_ci if (x + y < 1.0f) 338e5c31af7Sopenharmony_ci return triangleInterpolate(quad.x(), quad.y(), quad.z(), x, y); 339e5c31af7Sopenharmony_ci else 340e5c31af7Sopenharmony_ci return triangleInterpolate(quad.w(), quad.z(), quad.y(), 1.0f-x, 1.0f-y); 341e5c31af7Sopenharmony_ci} 342e5c31af7Sopenharmony_ci 343e5c31af7Sopenharmony_cistatic inline int getNumVertices (int gridSizeX, int gridSizeY) 344e5c31af7Sopenharmony_ci{ 345e5c31af7Sopenharmony_ci return gridSizeX * gridSizeY * 2 * 3; 346e5c31af7Sopenharmony_ci} 347e5c31af7Sopenharmony_ci 348e5c31af7Sopenharmony_cistatic void generateVertices (std::vector<float>& dst, int gridSizeX, int gridSizeY, const OperatorPerformanceCase::AttribSpec& spec) 349e5c31af7Sopenharmony_ci{ 350e5c31af7Sopenharmony_ci const int numComponents = 4; 351e5c31af7Sopenharmony_ci 352e5c31af7Sopenharmony_ci DE_ASSERT(gridSizeX >= 1 && gridSizeY >= 1); 353e5c31af7Sopenharmony_ci dst.resize(getNumVertices(gridSizeX, gridSizeY) * numComponents); 354e5c31af7Sopenharmony_ci 355e5c31af7Sopenharmony_ci { 356e5c31af7Sopenharmony_ci int dstNdx = 0; 357e5c31af7Sopenharmony_ci 358e5c31af7Sopenharmony_ci for (int baseY = 0; baseY < gridSizeY; baseY++) 359e5c31af7Sopenharmony_ci for (int baseX = 0; baseX < gridSizeX; baseX++) 360e5c31af7Sopenharmony_ci { 361e5c31af7Sopenharmony_ci const float xf0 = (float)(baseX + 0) / (float)gridSizeX; 362e5c31af7Sopenharmony_ci const float yf0 = (float)(baseY + 0) / (float)gridSizeY; 363e5c31af7Sopenharmony_ci const float xf1 = (float)(baseX + 1) / (float)gridSizeX; 364e5c31af7Sopenharmony_ci const float yf1 = (float)(baseY + 1) / (float)gridSizeY; 365e5c31af7Sopenharmony_ci 366e5c31af7Sopenharmony_ci#define ADD_VERTEX(XF, YF) \ 367e5c31af7Sopenharmony_ci for (int compNdx = 0; compNdx < numComponents; compNdx++) \ 368e5c31af7Sopenharmony_ci dst[dstNdx++] = triQuadInterpolate((XF), (YF), tcu::Vec4(spec.p00[compNdx], spec.p01[compNdx], spec.p10[compNdx], spec.p11[compNdx])) 369e5c31af7Sopenharmony_ci 370e5c31af7Sopenharmony_ci ADD_VERTEX(xf0, yf0); 371e5c31af7Sopenharmony_ci ADD_VERTEX(xf1, yf0); 372e5c31af7Sopenharmony_ci ADD_VERTEX(xf0, yf1); 373e5c31af7Sopenharmony_ci 374e5c31af7Sopenharmony_ci ADD_VERTEX(xf1, yf0); 375e5c31af7Sopenharmony_ci ADD_VERTEX(xf1, yf1); 376e5c31af7Sopenharmony_ci ADD_VERTEX(xf0, yf1); 377e5c31af7Sopenharmony_ci 378e5c31af7Sopenharmony_ci#undef ADD_VERTEX 379e5c31af7Sopenharmony_ci } 380e5c31af7Sopenharmony_ci } 381e5c31af7Sopenharmony_ci} 382e5c31af7Sopenharmony_ci 383e5c31af7Sopenharmony_cistatic float intersectionX (const gls::LineParameters& a, const gls::LineParameters& b) 384e5c31af7Sopenharmony_ci{ 385e5c31af7Sopenharmony_ci return (a.offset - b.offset) / (b.coefficient - a.coefficient); 386e5c31af7Sopenharmony_ci} 387e5c31af7Sopenharmony_ci 388e5c31af7Sopenharmony_cistatic int numDistinctX (const vector<Vec2>& data) 389e5c31af7Sopenharmony_ci{ 390e5c31af7Sopenharmony_ci std::set<float> xs; 391e5c31af7Sopenharmony_ci for (int i = 0; i < (int)data.size(); i++) 392e5c31af7Sopenharmony_ci xs.insert(data[i].x()); 393e5c31af7Sopenharmony_ci return (int)xs.size(); 394e5c31af7Sopenharmony_ci} 395e5c31af7Sopenharmony_ci 396e5c31af7Sopenharmony_cistatic gls::LineParameters simpleLinearRegression (const vector<Vec2>& data) 397e5c31af7Sopenharmony_ci{ 398e5c31af7Sopenharmony_ci const Vec2 mid = mean(data); 399e5c31af7Sopenharmony_ci 400e5c31af7Sopenharmony_ci float slopeNumerator = 0.0f; 401e5c31af7Sopenharmony_ci float slopeDenominator = 0.0f; 402e5c31af7Sopenharmony_ci 403e5c31af7Sopenharmony_ci for (int i = 0; i < (int)data.size(); i++) 404e5c31af7Sopenharmony_ci { 405e5c31af7Sopenharmony_ci const Vec2 diff = data[i] - mid; 406e5c31af7Sopenharmony_ci 407e5c31af7Sopenharmony_ci slopeNumerator += diff.x()*diff.y(); 408e5c31af7Sopenharmony_ci slopeDenominator += diff.x()*diff.x(); 409e5c31af7Sopenharmony_ci } 410e5c31af7Sopenharmony_ci 411e5c31af7Sopenharmony_ci const float slope = slopeNumerator / slopeDenominator; 412e5c31af7Sopenharmony_ci const float offset = mid.y() - slope*mid.x(); 413e5c31af7Sopenharmony_ci 414e5c31af7Sopenharmony_ci return gls::LineParameters(offset, slope); 415e5c31af7Sopenharmony_ci} 416e5c31af7Sopenharmony_ci 417e5c31af7Sopenharmony_cistatic float simpleLinearRegressionError (const vector<Vec2>& data) 418e5c31af7Sopenharmony_ci{ 419e5c31af7Sopenharmony_ci if (numDistinctX(data) <= 2) 420e5c31af7Sopenharmony_ci return 0.0f; 421e5c31af7Sopenharmony_ci else 422e5c31af7Sopenharmony_ci { 423e5c31af7Sopenharmony_ci const gls::LineParameters estimator = simpleLinearRegression(data); 424e5c31af7Sopenharmony_ci float error = 0.0f; 425e5c31af7Sopenharmony_ci 426e5c31af7Sopenharmony_ci for (int i = 0; i < (int)data.size(); i++) 427e5c31af7Sopenharmony_ci { 428e5c31af7Sopenharmony_ci const float estY = estimator.offset + estimator.coefficient*data[i].x(); 429e5c31af7Sopenharmony_ci const float diff = estY - data[i].y(); 430e5c31af7Sopenharmony_ci error += diff*diff; 431e5c31af7Sopenharmony_ci } 432e5c31af7Sopenharmony_ci 433e5c31af7Sopenharmony_ci return error / (float)data.size(); 434e5c31af7Sopenharmony_ci } 435e5c31af7Sopenharmony_ci} 436e5c31af7Sopenharmony_ci 437e5c31af7Sopenharmony_cistatic float verticalVariance (const vector<Vec2>& data) 438e5c31af7Sopenharmony_ci{ 439e5c31af7Sopenharmony_ci if (numDistinctX(data) <= 2) 440e5c31af7Sopenharmony_ci return 0.0f; 441e5c31af7Sopenharmony_ci else 442e5c31af7Sopenharmony_ci { 443e5c31af7Sopenharmony_ci const float meanY = mean(data).y(); 444e5c31af7Sopenharmony_ci float error = 0.0f; 445e5c31af7Sopenharmony_ci 446e5c31af7Sopenharmony_ci for (int i = 0; i < (int)data.size(); i++) 447e5c31af7Sopenharmony_ci { 448e5c31af7Sopenharmony_ci const float diff = meanY - data[i].y(); 449e5c31af7Sopenharmony_ci error += diff*diff; 450e5c31af7Sopenharmony_ci } 451e5c31af7Sopenharmony_ci 452e5c31af7Sopenharmony_ci return error / (float)data.size(); 453e5c31af7Sopenharmony_ci } 454e5c31af7Sopenharmony_ci} 455e5c31af7Sopenharmony_ci 456e5c31af7Sopenharmony_ci/*--------------------------------------------------------------------*//*! 457e5c31af7Sopenharmony_ci * \brief Find the x coord that divides the input data into two slopes. 458e5c31af7Sopenharmony_ci * 459e5c31af7Sopenharmony_ci * The operator performance measurements tend to produce results where 460e5c31af7Sopenharmony_ci * we get small operation counts "for free" (e.g. because the operations 461e5c31af7Sopenharmony_ci * are performed during some memory transfer overhead or something), 462e5c31af7Sopenharmony_ci * resulting in a curve with two parts: an initial horizontal line segment, 463e5c31af7Sopenharmony_ci * and a rising line. 464e5c31af7Sopenharmony_ci * 465e5c31af7Sopenharmony_ci * This function finds the x coordinate that divides the input data into 466e5c31af7Sopenharmony_ci * two parts such that the sum of the mean square errors for the 467e5c31af7Sopenharmony_ci * least-squares estimated lines for the two parts is minimized, under the 468e5c31af7Sopenharmony_ci * additional condition that the left line is horizontal. 469e5c31af7Sopenharmony_ci * 470e5c31af7Sopenharmony_ci * This function returns a number X s.t. { pt | pt is in data, pt.x >= X } 471e5c31af7Sopenharmony_ci * is the right line, and the rest of data is the left line. 472e5c31af7Sopenharmony_ci *//*--------------------------------------------------------------------*/ 473e5c31af7Sopenharmony_cistatic float findSlopePivotX (const vector<Vec2>& data) 474e5c31af7Sopenharmony_ci{ 475e5c31af7Sopenharmony_ci std::set<float> xCoords; 476e5c31af7Sopenharmony_ci for (int i = 0; i < (int)data.size(); i++) 477e5c31af7Sopenharmony_ci xCoords.insert(data[i].x()); 478e5c31af7Sopenharmony_ci 479e5c31af7Sopenharmony_ci float lowestError = std::numeric_limits<float>::infinity(); 480e5c31af7Sopenharmony_ci float bestPivotX = -std::numeric_limits<float>::infinity(); 481e5c31af7Sopenharmony_ci 482e5c31af7Sopenharmony_ci for (std::set<float>::const_iterator pivotX = xCoords.begin(); pivotX != xCoords.end(); ++pivotX) 483e5c31af7Sopenharmony_ci { 484e5c31af7Sopenharmony_ci vector<Vec2> leftData; 485e5c31af7Sopenharmony_ci vector<Vec2> rightData; 486e5c31af7Sopenharmony_ci for (int i = 0; i < (int)data.size(); i++) 487e5c31af7Sopenharmony_ci { 488e5c31af7Sopenharmony_ci if (data[i].x() < *pivotX) 489e5c31af7Sopenharmony_ci leftData.push_back(data[i]); 490e5c31af7Sopenharmony_ci else 491e5c31af7Sopenharmony_ci rightData.push_back(data[i]); 492e5c31af7Sopenharmony_ci } 493e5c31af7Sopenharmony_ci 494e5c31af7Sopenharmony_ci if (numDistinctX(rightData) < 3) // We don't trust the right data if there's too little of it. 495e5c31af7Sopenharmony_ci break; 496e5c31af7Sopenharmony_ci 497e5c31af7Sopenharmony_ci { 498e5c31af7Sopenharmony_ci const float totalError = verticalVariance(leftData) + simpleLinearRegressionError(rightData); 499e5c31af7Sopenharmony_ci 500e5c31af7Sopenharmony_ci if (totalError < lowestError) 501e5c31af7Sopenharmony_ci { 502e5c31af7Sopenharmony_ci lowestError = totalError; 503e5c31af7Sopenharmony_ci bestPivotX = *pivotX; 504e5c31af7Sopenharmony_ci } 505e5c31af7Sopenharmony_ci } 506e5c31af7Sopenharmony_ci } 507e5c31af7Sopenharmony_ci 508e5c31af7Sopenharmony_ci DE_ASSERT(lowestError < std::numeric_limits<float>::infinity()); 509e5c31af7Sopenharmony_ci 510e5c31af7Sopenharmony_ci return bestPivotX; 511e5c31af7Sopenharmony_ci} 512e5c31af7Sopenharmony_ci 513e5c31af7Sopenharmony_cistruct SegmentedEstimator 514e5c31af7Sopenharmony_ci{ 515e5c31af7Sopenharmony_ci float pivotX; //!< Value returned by findSlopePivotX, or -infinity if only single line. 516e5c31af7Sopenharmony_ci gls::LineParameters left; 517e5c31af7Sopenharmony_ci gls::LineParameters right; 518e5c31af7Sopenharmony_ci SegmentedEstimator (const gls::LineParameters& l, const gls::LineParameters& r, float pivotX_) : pivotX(pivotX_), left(l), right(r) {} 519e5c31af7Sopenharmony_ci}; 520e5c31af7Sopenharmony_ci 521e5c31af7Sopenharmony_ci/*--------------------------------------------------------------------*//*! 522e5c31af7Sopenharmony_ci * \brief Compute line estimators for (potentially) two-segment data. 523e5c31af7Sopenharmony_ci * 524e5c31af7Sopenharmony_ci * Splits the given data into left and right parts (using findSlopePivotX) 525e5c31af7Sopenharmony_ci * and returns the line estimates for them. 526e5c31af7Sopenharmony_ci * 527e5c31af7Sopenharmony_ci * Sometimes, however (especially in fragment shader cases) the data is 528e5c31af7Sopenharmony_ci * in fact not segmented, but a straight line. This function attempts to 529e5c31af7Sopenharmony_ci * detect if this the case, and if so, sets left.offset = right.offset and 530e5c31af7Sopenharmony_ci * left.slope = 0, meaning essentially that the initial "flat" part of the 531e5c31af7Sopenharmony_ci * data has zero width. 532e5c31af7Sopenharmony_ci *//*--------------------------------------------------------------------*/ 533e5c31af7Sopenharmony_cistatic SegmentedEstimator computeSegmentedEstimator (const vector<Vec2>& data) 534e5c31af7Sopenharmony_ci{ 535e5c31af7Sopenharmony_ci const float pivotX = findSlopePivotX(data); 536e5c31af7Sopenharmony_ci vector<Vec2> leftData; 537e5c31af7Sopenharmony_ci vector<Vec2> rightData; 538e5c31af7Sopenharmony_ci 539e5c31af7Sopenharmony_ci for (int i = 0; i < (int)data.size(); i++) 540e5c31af7Sopenharmony_ci { 541e5c31af7Sopenharmony_ci if (data[i].x() < pivotX) 542e5c31af7Sopenharmony_ci leftData.push_back(data[i]); 543e5c31af7Sopenharmony_ci else 544e5c31af7Sopenharmony_ci rightData.push_back(data[i]); 545e5c31af7Sopenharmony_ci } 546e5c31af7Sopenharmony_ci 547e5c31af7Sopenharmony_ci { 548e5c31af7Sopenharmony_ci const gls::LineParameters leftLine = gls::theilSenLinearRegression(leftData); 549e5c31af7Sopenharmony_ci const gls::LineParameters rightLine = gls::theilSenLinearRegression(rightData); 550e5c31af7Sopenharmony_ci 551e5c31af7Sopenharmony_ci if (numDistinctX(leftData) < 2 || leftLine.coefficient > rightLine.coefficient*0.5f) 552e5c31af7Sopenharmony_ci { 553e5c31af7Sopenharmony_ci // Left data doesn't seem credible; assume the data is just a single line. 554e5c31af7Sopenharmony_ci const gls::LineParameters entireLine = gls::theilSenLinearRegression(data); 555e5c31af7Sopenharmony_ci return SegmentedEstimator(gls::LineParameters(entireLine.offset, 0.0f), entireLine, -std::numeric_limits<float>::infinity()); 556e5c31af7Sopenharmony_ci } 557e5c31af7Sopenharmony_ci else 558e5c31af7Sopenharmony_ci return SegmentedEstimator(leftLine, rightLine, pivotX); 559e5c31af7Sopenharmony_ci } 560e5c31af7Sopenharmony_ci} 561e5c31af7Sopenharmony_ci 562e5c31af7Sopenharmony_ciOperatorPerformanceCase::OperatorPerformanceCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* description, 563e5c31af7Sopenharmony_ci CaseType caseType, int numWorkloads, const InitialCalibrationStorage& initialCalibrationStorage) 564e5c31af7Sopenharmony_ci : tcu::TestCase (testCtx, tcu::NODETYPE_PERFORMANCE, name, description) 565e5c31af7Sopenharmony_ci , m_renderCtx (renderCtx) 566e5c31af7Sopenharmony_ci , m_caseType (caseType) 567e5c31af7Sopenharmony_ci , m_numMeasurementsPerWorkload (getIterationCountOrDefault(m_testCtx.getCommandLine(), DEFAULT_NUM_MEASUREMENTS_PER_WORKLOAD)) 568e5c31af7Sopenharmony_ci , m_numWorkloads (numWorkloads) 569e5c31af7Sopenharmony_ci , m_workloadNdx (-1) 570e5c31af7Sopenharmony_ci , m_workloadMeasurementNdx (-1) 571e5c31af7Sopenharmony_ci , m_state (STATE_LAST) 572e5c31af7Sopenharmony_ci , m_measureProgramNdx (-1) 573e5c31af7Sopenharmony_ci , m_initialCalibrationStorage (initialCalibrationStorage) 574e5c31af7Sopenharmony_ci , m_viewportWidth (caseType == CASETYPE_VERTEX ? 32 : renderCtx.getRenderTarget().getWidth()) 575e5c31af7Sopenharmony_ci , m_viewportHeight (caseType == CASETYPE_VERTEX ? 32 : renderCtx.getRenderTarget().getHeight()) 576e5c31af7Sopenharmony_ci , m_gridSizeX (caseType == CASETYPE_FRAGMENT ? 1 : 100) 577e5c31af7Sopenharmony_ci , m_gridSizeY (caseType == CASETYPE_FRAGMENT ? 1 : 100) 578e5c31af7Sopenharmony_ci{ 579e5c31af7Sopenharmony_ci DE_ASSERT(m_numWorkloads > 0); 580e5c31af7Sopenharmony_ci} 581e5c31af7Sopenharmony_ci 582e5c31af7Sopenharmony_ciOperatorPerformanceCase::~OperatorPerformanceCase (void) 583e5c31af7Sopenharmony_ci{ 584e5c31af7Sopenharmony_ci if (!m_attribBuffers.empty()) 585e5c31af7Sopenharmony_ci { 586e5c31af7Sopenharmony_ci m_renderCtx.getFunctions().deleteBuffers((glw::GLsizei)m_attribBuffers.size(), &m_attribBuffers[0]); 587e5c31af7Sopenharmony_ci m_attribBuffers.clear(); 588e5c31af7Sopenharmony_ci } 589e5c31af7Sopenharmony_ci} 590e5c31af7Sopenharmony_ci 591e5c31af7Sopenharmony_cistatic void logRenderTargetInfo (TestLog& log, const tcu::RenderTarget& renderTarget) 592e5c31af7Sopenharmony_ci{ 593e5c31af7Sopenharmony_ci log << TestLog::Section("RenderTarget", "Render target") 594e5c31af7Sopenharmony_ci << TestLog::Message << "size: " << renderTarget.getWidth() << "x" << renderTarget.getHeight() << TestLog::EndMessage 595e5c31af7Sopenharmony_ci << TestLog::Message << "bits:" 596e5c31af7Sopenharmony_ci << " R" << renderTarget.getPixelFormat().redBits 597e5c31af7Sopenharmony_ci << " G" << renderTarget.getPixelFormat().greenBits 598e5c31af7Sopenharmony_ci << " B" << renderTarget.getPixelFormat().blueBits 599e5c31af7Sopenharmony_ci << " A" << renderTarget.getPixelFormat().alphaBits 600e5c31af7Sopenharmony_ci << " D" << renderTarget.getDepthBits() 601e5c31af7Sopenharmony_ci << " S" << renderTarget.getStencilBits() 602e5c31af7Sopenharmony_ci << TestLog::EndMessage; 603e5c31af7Sopenharmony_ci 604e5c31af7Sopenharmony_ci if (renderTarget.getNumSamples() != 0) 605e5c31af7Sopenharmony_ci log << TestLog::Message << renderTarget.getNumSamples() << "x MSAA" << TestLog::EndMessage; 606e5c31af7Sopenharmony_ci else 607e5c31af7Sopenharmony_ci log << TestLog::Message << "No MSAA" << TestLog::EndMessage; 608e5c31af7Sopenharmony_ci 609e5c31af7Sopenharmony_ci log << TestLog::EndSection; 610e5c31af7Sopenharmony_ci} 611e5c31af7Sopenharmony_ci 612e5c31af7Sopenharmony_civector<Vec2> OperatorPerformanceCase::getWorkloadMedianDataPoints (int progNdx) const 613e5c31af7Sopenharmony_ci{ 614e5c31af7Sopenharmony_ci const vector<WorkloadRecord>& records = m_workloadRecords[progNdx]; 615e5c31af7Sopenharmony_ci vector<Vec2> result; 616e5c31af7Sopenharmony_ci 617e5c31af7Sopenharmony_ci for (int i = 0; i < (int)records.size(); i++) 618e5c31af7Sopenharmony_ci result.push_back(Vec2((float)records[i].workloadSize, records[i].getMedianTime())); 619e5c31af7Sopenharmony_ci 620e5c31af7Sopenharmony_ci return result; 621e5c31af7Sopenharmony_ci} 622e5c31af7Sopenharmony_ci 623e5c31af7Sopenharmony_civoid OperatorPerformanceCase::prepareProgram (int progNdx) 624e5c31af7Sopenharmony_ci{ 625e5c31af7Sopenharmony_ci DE_ASSERT(progNdx < (int)m_programs.size()); 626e5c31af7Sopenharmony_ci DE_ASSERT(m_programData.size() == m_programs.size()); 627e5c31af7Sopenharmony_ci 628e5c31af7Sopenharmony_ci const glw::Functions& gl = m_renderCtx.getFunctions(); 629e5c31af7Sopenharmony_ci const ShaderProgram& program = *m_programs[progNdx]; 630e5c31af7Sopenharmony_ci 631e5c31af7Sopenharmony_ci vector<AttribSpec> attributes = m_programData[progNdx].attributes; 632e5c31af7Sopenharmony_ci 633e5c31af7Sopenharmony_ci attributes.push_back(AttribSpec("a_position", 634e5c31af7Sopenharmony_ci Vec4(-1.0f, -1.0f, 0.0f, 1.0f), 635e5c31af7Sopenharmony_ci Vec4( 1.0f, -1.0f, 0.0f, 1.0f), 636e5c31af7Sopenharmony_ci Vec4(-1.0f, 1.0f, 0.0f, 1.0f), 637e5c31af7Sopenharmony_ci Vec4( 1.0f, 1.0f, 0.0f, 1.0f))); 638e5c31af7Sopenharmony_ci 639e5c31af7Sopenharmony_ci DE_ASSERT(program.isOk()); 640e5c31af7Sopenharmony_ci 641e5c31af7Sopenharmony_ci // Generate vertices. 642e5c31af7Sopenharmony_ci if (!m_attribBuffers.empty()) 643e5c31af7Sopenharmony_ci gl.deleteBuffers((glw::GLsizei)m_attribBuffers.size(), &m_attribBuffers[0]); 644e5c31af7Sopenharmony_ci m_attribBuffers.resize(attributes.size(), 0); 645e5c31af7Sopenharmony_ci gl.genBuffers((glw::GLsizei)m_attribBuffers.size(), &m_attribBuffers[0]); 646e5c31af7Sopenharmony_ci GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers()"); 647e5c31af7Sopenharmony_ci 648e5c31af7Sopenharmony_ci for (int attribNdx = 0; attribNdx < (int)attributes.size(); attribNdx++) 649e5c31af7Sopenharmony_ci { 650e5c31af7Sopenharmony_ci std::vector<float> vertices; 651e5c31af7Sopenharmony_ci generateVertices(vertices, m_gridSizeX, m_gridSizeY, attributes[attribNdx]); 652e5c31af7Sopenharmony_ci 653e5c31af7Sopenharmony_ci gl.bindBuffer(GL_ARRAY_BUFFER, m_attribBuffers[attribNdx]); 654e5c31af7Sopenharmony_ci gl.bufferData(GL_ARRAY_BUFFER, (glw::GLsizeiptr)(vertices.size()*sizeof(float)), &vertices[0], GL_STATIC_DRAW); 655e5c31af7Sopenharmony_ci GLU_EXPECT_NO_ERROR(gl.getError(), "Upload buffer data"); 656e5c31af7Sopenharmony_ci } 657e5c31af7Sopenharmony_ci 658e5c31af7Sopenharmony_ci // Setup attribute bindings. 659e5c31af7Sopenharmony_ci for (int attribNdx = 0; attribNdx < (int)attributes.size(); attribNdx++) 660e5c31af7Sopenharmony_ci { 661e5c31af7Sopenharmony_ci int location = gl.getAttribLocation(program.getProgram(), attributes[attribNdx].name.c_str()); 662e5c31af7Sopenharmony_ci 663e5c31af7Sopenharmony_ci if (location >= 0) 664e5c31af7Sopenharmony_ci { 665e5c31af7Sopenharmony_ci gl.enableVertexAttribArray(location); 666e5c31af7Sopenharmony_ci gl.bindBuffer(GL_ARRAY_BUFFER, m_attribBuffers[attribNdx]); 667e5c31af7Sopenharmony_ci gl.vertexAttribPointer(location, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL); 668e5c31af7Sopenharmony_ci } 669e5c31af7Sopenharmony_ci } 670e5c31af7Sopenharmony_ci GLU_EXPECT_NO_ERROR(gl.getError(), "Setup vertex input state"); 671e5c31af7Sopenharmony_ci 672e5c31af7Sopenharmony_ci gl.useProgram(program.getProgram()); 673e5c31af7Sopenharmony_ci setGeneralUniforms(program.getProgram()); 674e5c31af7Sopenharmony_ci gl.viewport(0, 0, m_viewportWidth, m_viewportHeight); 675e5c31af7Sopenharmony_ci} 676e5c31af7Sopenharmony_ci 677e5c31af7Sopenharmony_civoid OperatorPerformanceCase::prepareWorkload (int progNdx, int workload) 678e5c31af7Sopenharmony_ci{ 679e5c31af7Sopenharmony_ci setWorkloadSizeUniform(m_programs[progNdx]->getProgram(), workload); 680e5c31af7Sopenharmony_ci render(m_calibrator.getCallCount()); 681e5c31af7Sopenharmony_ci} 682e5c31af7Sopenharmony_ci 683e5c31af7Sopenharmony_civoid OperatorPerformanceCase::prepareNextRound (void) 684e5c31af7Sopenharmony_ci{ 685e5c31af7Sopenharmony_ci DE_ASSERT(m_state == STATE_CALIBRATING || 686e5c31af7Sopenharmony_ci m_state == STATE_FIND_HIGH_WORKLOAD || 687e5c31af7Sopenharmony_ci m_state == STATE_MEASURING); 688e5c31af7Sopenharmony_ci 689e5c31af7Sopenharmony_ci TestLog& log = m_testCtx.getLog(); 690e5c31af7Sopenharmony_ci 691e5c31af7Sopenharmony_ci if (m_state == STATE_CALIBRATING && m_calibrator.getState() == TheilSenCalibrator::STATE_FINISHED) 692e5c31af7Sopenharmony_ci { 693e5c31af7Sopenharmony_ci m_measureProgramNdx = 0; 694e5c31af7Sopenharmony_ci m_state = STATE_FIND_HIGH_WORKLOAD; 695e5c31af7Sopenharmony_ci } 696e5c31af7Sopenharmony_ci 697e5c31af7Sopenharmony_ci if (m_state == STATE_CALIBRATING) 698e5c31af7Sopenharmony_ci prepareWorkload(0, 1); 699e5c31af7Sopenharmony_ci else if (m_state == STATE_FIND_HIGH_WORKLOAD) 700e5c31af7Sopenharmony_ci { 701e5c31af7Sopenharmony_ci vector<WorkloadRecord>& records = m_workloadRecordsFindHigh[m_measureProgramNdx]; 702e5c31af7Sopenharmony_ci 703e5c31af7Sopenharmony_ci if (records.empty() || records.back().getMedianTime() < 2.0f*records[0].getMedianTime()) 704e5c31af7Sopenharmony_ci { 705e5c31af7Sopenharmony_ci int workloadSize; 706e5c31af7Sopenharmony_ci 707e5c31af7Sopenharmony_ci if (records.empty()) 708e5c31af7Sopenharmony_ci workloadSize = 1; 709e5c31af7Sopenharmony_ci else 710e5c31af7Sopenharmony_ci { 711e5c31af7Sopenharmony_ci workloadSize = records.back().workloadSize*2; 712e5c31af7Sopenharmony_ci 713e5c31af7Sopenharmony_ci if (workloadSize > MAX_WORKLOAD_SIZE) 714e5c31af7Sopenharmony_ci { 715e5c31af7Sopenharmony_ci log << TestLog::Message << "Even workload size " << records.back().workloadSize 716e5c31af7Sopenharmony_ci << " doesn't give high enough frame time for program " << m_measureProgramNdx 717e5c31af7Sopenharmony_ci << ". Can't get sensible result." << TestLog::EndMessage; 718e5c31af7Sopenharmony_ci MEASUREMENT_FAIL(); 719e5c31af7Sopenharmony_ci } 720e5c31af7Sopenharmony_ci } 721e5c31af7Sopenharmony_ci 722e5c31af7Sopenharmony_ci records.push_back(WorkloadRecord(workloadSize)); 723e5c31af7Sopenharmony_ci prepareWorkload(0, workloadSize); 724e5c31af7Sopenharmony_ci m_workloadMeasurementNdx = 0; 725e5c31af7Sopenharmony_ci } 726e5c31af7Sopenharmony_ci else 727e5c31af7Sopenharmony_ci { 728e5c31af7Sopenharmony_ci m_highWorkloadSizes[m_measureProgramNdx] = records.back().workloadSize; 729e5c31af7Sopenharmony_ci m_measureProgramNdx++; 730e5c31af7Sopenharmony_ci 731e5c31af7Sopenharmony_ci if (m_measureProgramNdx >= (int)m_programs.size()) 732e5c31af7Sopenharmony_ci { 733e5c31af7Sopenharmony_ci m_state = STATE_MEASURING; 734e5c31af7Sopenharmony_ci m_workloadNdx = -1; 735e5c31af7Sopenharmony_ci m_measureProgramNdx = 0; 736e5c31af7Sopenharmony_ci } 737e5c31af7Sopenharmony_ci 738e5c31af7Sopenharmony_ci prepareProgram(m_measureProgramNdx); 739e5c31af7Sopenharmony_ci prepareNextRound(); 740e5c31af7Sopenharmony_ci } 741e5c31af7Sopenharmony_ci } 742e5c31af7Sopenharmony_ci else 743e5c31af7Sopenharmony_ci { 744e5c31af7Sopenharmony_ci m_workloadNdx++; 745e5c31af7Sopenharmony_ci 746e5c31af7Sopenharmony_ci if (m_workloadNdx < m_numWorkloads) 747e5c31af7Sopenharmony_ci { 748e5c31af7Sopenharmony_ci DE_ASSERT(m_numWorkloads > 1); 749e5c31af7Sopenharmony_ci const int highWorkload = m_highWorkloadSizes[m_measureProgramNdx]; 750e5c31af7Sopenharmony_ci const int workload = highWorkload > m_numWorkloads ? 751e5c31af7Sopenharmony_ci 1 + m_workloadNdx*(highWorkload-1)/(m_numWorkloads-1) : 752e5c31af7Sopenharmony_ci 1 + m_workloadNdx; 753e5c31af7Sopenharmony_ci 754e5c31af7Sopenharmony_ci prepareWorkload(m_measureProgramNdx, workload); 755e5c31af7Sopenharmony_ci 756e5c31af7Sopenharmony_ci m_workloadMeasurementNdx = 0; 757e5c31af7Sopenharmony_ci 758e5c31af7Sopenharmony_ci m_workloadRecords[m_measureProgramNdx].push_back(WorkloadRecord(workload)); 759e5c31af7Sopenharmony_ci } 760e5c31af7Sopenharmony_ci else 761e5c31af7Sopenharmony_ci { 762e5c31af7Sopenharmony_ci m_measureProgramNdx++; 763e5c31af7Sopenharmony_ci 764e5c31af7Sopenharmony_ci if (m_measureProgramNdx < (int)m_programs.size()) 765e5c31af7Sopenharmony_ci { 766e5c31af7Sopenharmony_ci m_workloadNdx = -1; 767e5c31af7Sopenharmony_ci m_workloadMeasurementNdx = 0; 768e5c31af7Sopenharmony_ci prepareProgram(m_measureProgramNdx); 769e5c31af7Sopenharmony_ci prepareNextRound(); 770e5c31af7Sopenharmony_ci } 771e5c31af7Sopenharmony_ci else 772e5c31af7Sopenharmony_ci m_state = STATE_REPORTING; 773e5c31af7Sopenharmony_ci } 774e5c31af7Sopenharmony_ci } 775e5c31af7Sopenharmony_ci} 776e5c31af7Sopenharmony_ci 777e5c31af7Sopenharmony_civoid OperatorPerformanceCase::init (void) 778e5c31af7Sopenharmony_ci{ 779e5c31af7Sopenharmony_ci TestLog& log = m_testCtx.getLog(); 780e5c31af7Sopenharmony_ci const glw::Functions& gl = m_renderCtx.getFunctions(); 781e5c31af7Sopenharmony_ci 782e5c31af7Sopenharmony_ci // Validate that we have sane grid and viewport setup. 783e5c31af7Sopenharmony_ci DE_ASSERT(de::inBounds(m_gridSizeX, 1, 256) && de::inBounds(m_gridSizeY, 1, 256)); 784e5c31af7Sopenharmony_ci TCU_CHECK(de::inRange(m_viewportWidth, 1, m_renderCtx.getRenderTarget().getWidth()) && 785e5c31af7Sopenharmony_ci de::inRange(m_viewportHeight, 1, m_renderCtx.getRenderTarget().getHeight())); 786e5c31af7Sopenharmony_ci 787e5c31af7Sopenharmony_ci logRenderTargetInfo(log, m_renderCtx.getRenderTarget()); 788e5c31af7Sopenharmony_ci 789e5c31af7Sopenharmony_ci log << TestLog::Message << "Using additive blending." << TestLog::EndMessage; 790e5c31af7Sopenharmony_ci gl.enable(GL_BLEND); 791e5c31af7Sopenharmony_ci gl.blendEquation(GL_FUNC_ADD); 792e5c31af7Sopenharmony_ci gl.blendFunc(GL_ONE, GL_ONE); 793e5c31af7Sopenharmony_ci 794e5c31af7Sopenharmony_ci // Generate programs. 795e5c31af7Sopenharmony_ci DE_ASSERT(m_programs.empty()); 796e5c31af7Sopenharmony_ci m_programData = generateProgramData(); 797e5c31af7Sopenharmony_ci DE_ASSERT(!m_programData.empty()); 798e5c31af7Sopenharmony_ci 799e5c31af7Sopenharmony_ci for (int progNdx = 0; progNdx < (int)m_programData.size(); progNdx++) 800e5c31af7Sopenharmony_ci { 801e5c31af7Sopenharmony_ci const string& vert = m_programData[progNdx].vertShaderSource; 802e5c31af7Sopenharmony_ci const string& frag = m_programData[progNdx].fragShaderSource; 803e5c31af7Sopenharmony_ci 804e5c31af7Sopenharmony_ci m_programs.push_back(SharedPtr<ShaderProgram>(new ShaderProgram(m_renderCtx, glu::makeVtxFragSources(vert, frag)))); 805e5c31af7Sopenharmony_ci 806e5c31af7Sopenharmony_ci if (!m_programs.back()->isOk()) 807e5c31af7Sopenharmony_ci { 808e5c31af7Sopenharmony_ci log << *m_programs.back(); 809e5c31af7Sopenharmony_ci TCU_FAIL("Compile failed"); 810e5c31af7Sopenharmony_ci } 811e5c31af7Sopenharmony_ci } 812e5c31af7Sopenharmony_ci 813e5c31af7Sopenharmony_ci // Log all programs. 814e5c31af7Sopenharmony_ci for (int progNdx = 0; progNdx < (int)m_programs.size(); progNdx++) 815e5c31af7Sopenharmony_ci log << TestLog::Section("Program" + de::toString(progNdx), "Program " + de::toString(progNdx)) 816e5c31af7Sopenharmony_ci << TestLog::Message << m_programData[progNdx].description << TestLog::EndMessage 817e5c31af7Sopenharmony_ci << *m_programs[progNdx] 818e5c31af7Sopenharmony_ci << TestLog::EndSection; 819e5c31af7Sopenharmony_ci 820e5c31af7Sopenharmony_ci m_highWorkloadSizes.resize(m_programData.size()); 821e5c31af7Sopenharmony_ci m_workloadRecordsFindHigh.resize(m_programData.size()); 822e5c31af7Sopenharmony_ci m_workloadRecords.resize(m_programData.size()); 823e5c31af7Sopenharmony_ci 824e5c31af7Sopenharmony_ci m_calibrator.clear(CalibratorParameters(m_initialCalibrationStorage->initialNumCalls, 10 /* calibrate iteration frames */, 2000.0f /* calibrate iteration shortcut threshold (ms) */, 16 /* max calibrate iterations */, 825e5c31af7Sopenharmony_ci 1000.0f/30.0f /* frame time (ms) */, 1000.0f/60.0f /* frame time cap (ms) */, 1000.0f /* target measure duration (ms) */)); 826e5c31af7Sopenharmony_ci m_state = STATE_CALIBRATING; 827e5c31af7Sopenharmony_ci 828e5c31af7Sopenharmony_ci prepareProgram(0); 829e5c31af7Sopenharmony_ci prepareNextRound(); 830e5c31af7Sopenharmony_ci} 831e5c31af7Sopenharmony_ci 832e5c31af7Sopenharmony_civoid OperatorPerformanceCase::deinit (void) 833e5c31af7Sopenharmony_ci{ 834e5c31af7Sopenharmony_ci if (!m_attribBuffers.empty()) 835e5c31af7Sopenharmony_ci { 836e5c31af7Sopenharmony_ci m_renderCtx.getFunctions().deleteBuffers((glw::GLsizei)m_attribBuffers.size(), &m_attribBuffers[0]); 837e5c31af7Sopenharmony_ci m_attribBuffers.clear(); 838e5c31af7Sopenharmony_ci } 839e5c31af7Sopenharmony_ci 840e5c31af7Sopenharmony_ci m_programs.clear(); 841e5c31af7Sopenharmony_ci} 842e5c31af7Sopenharmony_ci 843e5c31af7Sopenharmony_civoid OperatorPerformanceCase::render (int numDrawCalls) 844e5c31af7Sopenharmony_ci{ 845e5c31af7Sopenharmony_ci const glw::Functions& gl = m_renderCtx.getFunctions(); 846e5c31af7Sopenharmony_ci const int numVertices = getNumVertices(m_gridSizeX, m_gridSizeY); 847e5c31af7Sopenharmony_ci 848e5c31af7Sopenharmony_ci for (int callNdx = 0; callNdx < numDrawCalls; callNdx++) 849e5c31af7Sopenharmony_ci gl.drawArrays(GL_TRIANGLES, 0, numVertices); 850e5c31af7Sopenharmony_ci 851e5c31af7Sopenharmony_ci glu::readPixels(m_renderCtx, 0, 0, tcu::Surface(1, 1).getAccess()); // \note Serves as a more reliable replacement for glFinish(). 852e5c31af7Sopenharmony_ci} 853e5c31af7Sopenharmony_ci 854e5c31af7Sopenharmony_cideUint64 OperatorPerformanceCase::renderAndMeasure (int numDrawCalls) 855e5c31af7Sopenharmony_ci{ 856e5c31af7Sopenharmony_ci const deUint64 startTime = deGetMicroseconds(); 857e5c31af7Sopenharmony_ci render(numDrawCalls); 858e5c31af7Sopenharmony_ci return deGetMicroseconds() - startTime; 859e5c31af7Sopenharmony_ci} 860e5c31af7Sopenharmony_ci 861e5c31af7Sopenharmony_civoid OperatorPerformanceCase::adjustAndLogGridAndViewport (void) 862e5c31af7Sopenharmony_ci{ 863e5c31af7Sopenharmony_ci TestLog& log = m_testCtx.getLog(); 864e5c31af7Sopenharmony_ci 865e5c31af7Sopenharmony_ci // If call count is just 1, and the target frame time still wasn't reached, reduce grid or viewport size. 866e5c31af7Sopenharmony_ci if (m_calibrator.getCallCount() == 1) 867e5c31af7Sopenharmony_ci { 868e5c31af7Sopenharmony_ci const gls::MeasureState& calibratorMeasure = m_calibrator.getMeasureState(); 869e5c31af7Sopenharmony_ci const float drawCallTime = (float)calibratorMeasure.getTotalTime() / (float)calibratorMeasure.frameTimes.size(); 870e5c31af7Sopenharmony_ci const float targetDrawCallTime = m_calibrator.getParameters().targetFrameTimeUs; 871e5c31af7Sopenharmony_ci const float targetRatio = targetDrawCallTime / drawCallTime; 872e5c31af7Sopenharmony_ci 873e5c31af7Sopenharmony_ci if (targetRatio < 0.95f) 874e5c31af7Sopenharmony_ci { 875e5c31af7Sopenharmony_ci // Reduce grid or viewport size assuming draw call time scales proportionally. 876e5c31af7Sopenharmony_ci if (m_caseType == CASETYPE_VERTEX) 877e5c31af7Sopenharmony_ci { 878e5c31af7Sopenharmony_ci const float targetRatioSqrt = deFloatSqrt(targetRatio); 879e5c31af7Sopenharmony_ci m_gridSizeX = (int)(targetRatioSqrt * (float)m_gridSizeX); 880e5c31af7Sopenharmony_ci m_gridSizeY = (int)(targetRatioSqrt * (float)m_gridSizeY); 881e5c31af7Sopenharmony_ci TCU_CHECK_MSG(m_gridSizeX >= 1 && m_gridSizeY >= 1, "Can't decrease grid size enough to achieve low-enough draw times"); 882e5c31af7Sopenharmony_ci log << TestLog::Message << "Note: triangle grid size reduced from original; it's now smaller than during calibration." << TestLog::EndMessage; 883e5c31af7Sopenharmony_ci } 884e5c31af7Sopenharmony_ci else 885e5c31af7Sopenharmony_ci { 886e5c31af7Sopenharmony_ci const float targetRatioSqrt = deFloatSqrt(targetRatio); 887e5c31af7Sopenharmony_ci m_viewportWidth = (int)(targetRatioSqrt * (float)m_viewportWidth); 888e5c31af7Sopenharmony_ci m_viewportHeight = (int)(targetRatioSqrt * (float)m_viewportHeight); 889e5c31af7Sopenharmony_ci TCU_CHECK_MSG(m_viewportWidth >= 1 && m_viewportHeight >= 1, "Can't decrease viewport size enough to achieve low-enough draw times"); 890e5c31af7Sopenharmony_ci log << TestLog::Message << "Note: viewport size reduced from original; it's now smaller than during calibration." << TestLog::EndMessage; 891e5c31af7Sopenharmony_ci } 892e5c31af7Sopenharmony_ci } 893e5c31af7Sopenharmony_ci } 894e5c31af7Sopenharmony_ci 895e5c31af7Sopenharmony_ci prepareProgram(0); 896e5c31af7Sopenharmony_ci 897e5c31af7Sopenharmony_ci // Log grid and viewport sizes. 898e5c31af7Sopenharmony_ci log << TestLog::Message << "Grid size: " << m_gridSizeX << "x" << m_gridSizeY << TestLog::EndMessage; 899e5c31af7Sopenharmony_ci log << TestLog::Message << "Viewport: " << m_viewportWidth << "x" << m_viewportHeight << TestLog::EndMessage; 900e5c31af7Sopenharmony_ci} 901e5c31af7Sopenharmony_ci 902e5c31af7Sopenharmony_ciOperatorPerformanceCase::IterateResult OperatorPerformanceCase::iterate (void) 903e5c31af7Sopenharmony_ci{ 904e5c31af7Sopenharmony_ci const TheilSenCalibrator::State calibratorState = m_calibrator.getState(); 905e5c31af7Sopenharmony_ci 906e5c31af7Sopenharmony_ci if (calibratorState != TheilSenCalibrator::STATE_FINISHED) 907e5c31af7Sopenharmony_ci { 908e5c31af7Sopenharmony_ci if (calibratorState == TheilSenCalibrator::STATE_RECOMPUTE_PARAMS) 909e5c31af7Sopenharmony_ci m_calibrator.recomputeParameters(); 910e5c31af7Sopenharmony_ci else if (calibratorState == TheilSenCalibrator::STATE_MEASURE) 911e5c31af7Sopenharmony_ci m_calibrator.recordIteration(renderAndMeasure(m_calibrator.getCallCount())); 912e5c31af7Sopenharmony_ci else 913e5c31af7Sopenharmony_ci DE_ASSERT(false); 914e5c31af7Sopenharmony_ci 915e5c31af7Sopenharmony_ci if (m_calibrator.getState() == TheilSenCalibrator::STATE_FINISHED) 916e5c31af7Sopenharmony_ci { 917e5c31af7Sopenharmony_ci logCalibrationInfo(m_testCtx.getLog(), m_calibrator); 918e5c31af7Sopenharmony_ci adjustAndLogGridAndViewport(); 919e5c31af7Sopenharmony_ci prepareNextRound(); 920e5c31af7Sopenharmony_ci m_initialCalibrationStorage->initialNumCalls = m_calibrator.getCallCount(); 921e5c31af7Sopenharmony_ci } 922e5c31af7Sopenharmony_ci } 923e5c31af7Sopenharmony_ci else if (m_state == STATE_FIND_HIGH_WORKLOAD || m_state == STATE_MEASURING) 924e5c31af7Sopenharmony_ci { 925e5c31af7Sopenharmony_ci if (m_workloadMeasurementNdx < m_numMeasurementsPerWorkload) 926e5c31af7Sopenharmony_ci { 927e5c31af7Sopenharmony_ci vector<WorkloadRecord>& records = m_state == STATE_FIND_HIGH_WORKLOAD ? m_workloadRecordsFindHigh[m_measureProgramNdx] : m_workloadRecords[m_measureProgramNdx]; 928e5c31af7Sopenharmony_ci records.back().addFrameTime((float)renderAndMeasure(m_calibrator.getCallCount())); 929e5c31af7Sopenharmony_ci m_workloadMeasurementNdx++; 930e5c31af7Sopenharmony_ci } 931e5c31af7Sopenharmony_ci else 932e5c31af7Sopenharmony_ci prepareNextRound(); 933e5c31af7Sopenharmony_ci } 934e5c31af7Sopenharmony_ci else 935e5c31af7Sopenharmony_ci { 936e5c31af7Sopenharmony_ci DE_ASSERT(m_state == STATE_REPORTING); 937e5c31af7Sopenharmony_ci 938e5c31af7Sopenharmony_ci TestLog& log = m_testCtx.getLog(); 939e5c31af7Sopenharmony_ci const int drawCallCount = m_calibrator.getCallCount(); 940e5c31af7Sopenharmony_ci 941e5c31af7Sopenharmony_ci { 942e5c31af7Sopenharmony_ci // Compute per-program estimators for measurements. 943e5c31af7Sopenharmony_ci vector<SegmentedEstimator> estimators; 944e5c31af7Sopenharmony_ci for (int progNdx = 0; progNdx < (int)m_programs.size(); progNdx++) 945e5c31af7Sopenharmony_ci estimators.push_back(computeSegmentedEstimator(getWorkloadMedianDataPoints(progNdx))); 946e5c31af7Sopenharmony_ci 947e5c31af7Sopenharmony_ci // Log measurements and their estimators for all programs. 948e5c31af7Sopenharmony_ci for (int progNdx = 0; progNdx < (int)m_programs.size(); progNdx++) 949e5c31af7Sopenharmony_ci { 950e5c31af7Sopenharmony_ci const SegmentedEstimator& estimator = estimators[progNdx]; 951e5c31af7Sopenharmony_ci const string progNdxStr = de::toString(progNdx); 952e5c31af7Sopenharmony_ci vector<WorkloadRecord> records = m_workloadRecords[progNdx]; 953e5c31af7Sopenharmony_ci std::sort(records.begin(), records.end()); 954e5c31af7Sopenharmony_ci 955e5c31af7Sopenharmony_ci { 956e5c31af7Sopenharmony_ci const tcu::ScopedLogSection section(log, 957e5c31af7Sopenharmony_ci "Program" + progNdxStr + "Measurements", 958e5c31af7Sopenharmony_ci "Measurements for program " + progNdxStr); 959e5c31af7Sopenharmony_ci 960e5c31af7Sopenharmony_ci // Sample list of individual frame times. 961e5c31af7Sopenharmony_ci 962e5c31af7Sopenharmony_ci log << TestLog::SampleList("Program" + progNdxStr + "IndividualFrameTimes", "Individual frame times") 963e5c31af7Sopenharmony_ci << TestLog::SampleInfo << TestLog::ValueInfo("Workload", "Workload", "", QP_SAMPLE_VALUE_TAG_PREDICTOR) 964e5c31af7Sopenharmony_ci << TestLog::ValueInfo("FrameTime", "Frame time", "us", QP_SAMPLE_VALUE_TAG_RESPONSE) 965e5c31af7Sopenharmony_ci << TestLog::EndSampleInfo; 966e5c31af7Sopenharmony_ci 967e5c31af7Sopenharmony_ci for (int i = 0; i < (int)records.size(); i++) 968e5c31af7Sopenharmony_ci for (int j = 0; j < (int)records[i].frameTimes.size(); j++) 969e5c31af7Sopenharmony_ci log << TestLog::Sample << records[i].workloadSize << records[i].frameTimes[j] << TestLog::EndSample; 970e5c31af7Sopenharmony_ci 971e5c31af7Sopenharmony_ci log << TestLog::EndSampleList; 972e5c31af7Sopenharmony_ci 973e5c31af7Sopenharmony_ci // Sample list of median frame times. 974e5c31af7Sopenharmony_ci 975e5c31af7Sopenharmony_ci log << TestLog::SampleList("Program" + progNdxStr + "MedianFrameTimes", "Median frame times") 976e5c31af7Sopenharmony_ci << TestLog::SampleInfo << TestLog::ValueInfo("Workload", "Workload", "", QP_SAMPLE_VALUE_TAG_PREDICTOR) 977e5c31af7Sopenharmony_ci << TestLog::ValueInfo("MedianFrameTime", "Median frame time", "us", QP_SAMPLE_VALUE_TAG_RESPONSE) 978e5c31af7Sopenharmony_ci << TestLog::EndSampleInfo; 979e5c31af7Sopenharmony_ci 980e5c31af7Sopenharmony_ci for (int i = 0; i < (int)records.size(); i++) 981e5c31af7Sopenharmony_ci log << TestLog::Sample << records[i].workloadSize << records[i].getMedianTime() << TestLog::EndSample; 982e5c31af7Sopenharmony_ci 983e5c31af7Sopenharmony_ci log << TestLog::EndSampleList; 984e5c31af7Sopenharmony_ci 985e5c31af7Sopenharmony_ci log << TestLog::Float("Program" + progNdxStr + "WorkloadCostEstimate", "Workload cost estimate", "us / workload", QP_KEY_TAG_TIME, estimator.right.coefficient); 986e5c31af7Sopenharmony_ci 987e5c31af7Sopenharmony_ci if (estimator.pivotX > -std::numeric_limits<float>::infinity()) 988e5c31af7Sopenharmony_ci log << TestLog::Message << "Note: the data points with x coordinate greater than or equal to " << estimator.pivotX 989e5c31af7Sopenharmony_ci << " seem to form a rising line, and the rest of data points seem to form a near-horizontal line" << TestLog::EndMessage 990e5c31af7Sopenharmony_ci << TestLog::Message << "Note: the left line is estimated to be " << lineParamsString(estimator.left) 991e5c31af7Sopenharmony_ci << " and the right line " << lineParamsString(estimator.right) << TestLog::EndMessage; 992e5c31af7Sopenharmony_ci else 993e5c31af7Sopenharmony_ci log << TestLog::Message << "Note: the data seem to form a single line: " << lineParamsString(estimator.right) << TestLog::EndMessage; 994e5c31af7Sopenharmony_ci } 995e5c31af7Sopenharmony_ci } 996e5c31af7Sopenharmony_ci 997e5c31af7Sopenharmony_ci for (int progNdx = 0; progNdx < (int)m_programs.size(); progNdx++) 998e5c31af7Sopenharmony_ci { 999e5c31af7Sopenharmony_ci if (estimators[progNdx].right.coefficient <= 0.0f) 1000e5c31af7Sopenharmony_ci { 1001e5c31af7Sopenharmony_ci log << TestLog::Message << "Slope of measurements for program " << progNdx << " isn't positive. Can't get sensible result." << TestLog::EndMessage; 1002e5c31af7Sopenharmony_ci MEASUREMENT_FAIL(); 1003e5c31af7Sopenharmony_ci } 1004e5c31af7Sopenharmony_ci } 1005e5c31af7Sopenharmony_ci 1006e5c31af7Sopenharmony_ci // \note For each estimator, .right.coefficient is the increase in draw time (in microseconds) when 1007e5c31af7Sopenharmony_ci // incrementing shader workload size by 1, when D draw calls are done, with a vertex/fragment count 1008e5c31af7Sopenharmony_ci // of R. 1009e5c31af7Sopenharmony_ci // 1010e5c31af7Sopenharmony_ci // The measurements of any single program can't tell us the final result (time of single operation), 1011e5c31af7Sopenharmony_ci // so we use computeSingleOperationTime to compute it from multiple programs' measurements in a 1012e5c31af7Sopenharmony_ci // subclass-defined manner. 1013e5c31af7Sopenharmony_ci // 1014e5c31af7Sopenharmony_ci // After that, microseconds per operation can be calculated as singleOperationTime / (D * R). 1015e5c31af7Sopenharmony_ci 1016e5c31af7Sopenharmony_ci { 1017e5c31af7Sopenharmony_ci vector<float> perProgramSlopes; 1018e5c31af7Sopenharmony_ci for (int i = 0; i < (int)m_programs.size(); i++) 1019e5c31af7Sopenharmony_ci perProgramSlopes.push_back(estimators[i].right.coefficient); 1020e5c31af7Sopenharmony_ci 1021e5c31af7Sopenharmony_ci logSingleOperationCalculationInfo(); 1022e5c31af7Sopenharmony_ci 1023e5c31af7Sopenharmony_ci const float maxSlope = *std::max_element(perProgramSlopes.begin(), perProgramSlopes.end()); 1024e5c31af7Sopenharmony_ci const float usecsPerFramePerOp = computeSingleOperationTime(perProgramSlopes); 1025e5c31af7Sopenharmony_ci const int vertexOrFragmentCount = m_caseType == CASETYPE_VERTEX ? 1026e5c31af7Sopenharmony_ci getNumVertices(m_gridSizeX, m_gridSizeY) : 1027e5c31af7Sopenharmony_ci m_viewportWidth*m_viewportHeight; 1028e5c31af7Sopenharmony_ci const double usecsPerDrawCallPerOp = usecsPerFramePerOp / (double)drawCallCount; 1029e5c31af7Sopenharmony_ci const double usecsPerSingleOp = usecsPerDrawCallPerOp / (double)vertexOrFragmentCount; 1030e5c31af7Sopenharmony_ci const double megaOpsPerSecond = (double)(drawCallCount*vertexOrFragmentCount) / usecsPerFramePerOp; 1031e5c31af7Sopenharmony_ci const int numFreeOps = de::max(0, (int)deFloatFloor(intersectionX(estimators[0].left, 1032e5c31af7Sopenharmony_ci LineParameters(estimators[0].right.offset, 1033e5c31af7Sopenharmony_ci usecsPerFramePerOp)))); 1034e5c31af7Sopenharmony_ci 1035e5c31af7Sopenharmony_ci log << TestLog::Integer("VertexOrFragmentCount", 1036e5c31af7Sopenharmony_ci "R = " + string(m_caseType == CASETYPE_VERTEX ? "Vertex" : "Fragment") + " count", 1037e5c31af7Sopenharmony_ci "", QP_KEY_TAG_NONE, vertexOrFragmentCount) 1038e5c31af7Sopenharmony_ci 1039e5c31af7Sopenharmony_ci << TestLog::Integer("DrawCallsPerFrame", "D = Draw calls per frame", "", QP_KEY_TAG_NONE, drawCallCount) 1040e5c31af7Sopenharmony_ci 1041e5c31af7Sopenharmony_ci << TestLog::Integer("VerticesOrFragmentsPerFrame", 1042e5c31af7Sopenharmony_ci "R*D = " + string(m_caseType == CASETYPE_VERTEX ? "Vertices" : "Fragments") + " per frame", 1043e5c31af7Sopenharmony_ci "", QP_KEY_TAG_NONE, vertexOrFragmentCount*drawCallCount) 1044e5c31af7Sopenharmony_ci 1045e5c31af7Sopenharmony_ci << TestLog::Float("TimePerFramePerOp", 1046e5c31af7Sopenharmony_ci "Estimated cost of R*D " + string(m_caseType == CASETYPE_VERTEX ? "vertices" : "fragments") 1047e5c31af7Sopenharmony_ci + " (i.e. one frame) with one shader operation", 1048e5c31af7Sopenharmony_ci "us", QP_KEY_TAG_TIME, (float)usecsPerFramePerOp) 1049e5c31af7Sopenharmony_ci 1050e5c31af7Sopenharmony_ci << TestLog::Float("TimePerDrawcallPerOp", 1051e5c31af7Sopenharmony_ci "Estimated cost of one draw call with one shader operation", 1052e5c31af7Sopenharmony_ci "us", QP_KEY_TAG_TIME, (float)usecsPerDrawCallPerOp) 1053e5c31af7Sopenharmony_ci 1054e5c31af7Sopenharmony_ci << TestLog::Float("TimePerSingleOp", 1055e5c31af7Sopenharmony_ci "Estimated cost of a single shader operation", 1056e5c31af7Sopenharmony_ci "us", QP_KEY_TAG_TIME, (float)usecsPerSingleOp); 1057e5c31af7Sopenharmony_ci 1058e5c31af7Sopenharmony_ci // \note Sometimes, when the operation is free or very cheap, it can happen that the shader with the operation runs, 1059e5c31af7Sopenharmony_ci // for some reason, a bit faster than the shader without the operation, and thus we get a negative result. The 1060e5c31af7Sopenharmony_ci // following threshold values for accepting a negative or almost-zero result are rather quick and dirty. 1061e5c31af7Sopenharmony_ci if (usecsPerFramePerOp <= -0.1f*maxSlope) 1062e5c31af7Sopenharmony_ci { 1063e5c31af7Sopenharmony_ci log << TestLog::Message << "Got strongly negative result." << TestLog::EndMessage; 1064e5c31af7Sopenharmony_ci MEASUREMENT_FAIL(); 1065e5c31af7Sopenharmony_ci } 1066e5c31af7Sopenharmony_ci else if (usecsPerFramePerOp <= 0.001*maxSlope) 1067e5c31af7Sopenharmony_ci { 1068e5c31af7Sopenharmony_ci log << TestLog::Message << "Cost of operation seems to be approximately zero." << TestLog::EndMessage; 1069e5c31af7Sopenharmony_ci m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 1070e5c31af7Sopenharmony_ci } 1071e5c31af7Sopenharmony_ci else 1072e5c31af7Sopenharmony_ci { 1073e5c31af7Sopenharmony_ci log << TestLog::Float("OpsPerSecond", 1074e5c31af7Sopenharmony_ci "Operations per second", 1075e5c31af7Sopenharmony_ci "Million/s", QP_KEY_TAG_PERFORMANCE, (float)megaOpsPerSecond) 1076e5c31af7Sopenharmony_ci 1077e5c31af7Sopenharmony_ci << TestLog::Integer("NumFreeOps", 1078e5c31af7Sopenharmony_ci "Estimated number of \"free\" operations", 1079e5c31af7Sopenharmony_ci "", QP_KEY_TAG_PERFORMANCE, numFreeOps); 1080e5c31af7Sopenharmony_ci 1081e5c31af7Sopenharmony_ci m_testCtx.setTestResult(QP_TEST_RESULT_PASS, de::floatToString((float)megaOpsPerSecond, 2).c_str()); 1082e5c31af7Sopenharmony_ci } 1083e5c31af7Sopenharmony_ci 1084e5c31af7Sopenharmony_ci m_state = STATE_FINISHED; 1085e5c31af7Sopenharmony_ci } 1086e5c31af7Sopenharmony_ci } 1087e5c31af7Sopenharmony_ci 1088e5c31af7Sopenharmony_ci return STOP; 1089e5c31af7Sopenharmony_ci } 1090e5c31af7Sopenharmony_ci 1091e5c31af7Sopenharmony_ci return CONTINUE; 1092e5c31af7Sopenharmony_ci} 1093e5c31af7Sopenharmony_ci 1094e5c31af7Sopenharmony_ci// Binary operator case. 1095e5c31af7Sopenharmony_ciclass BinaryOpCase : public OperatorPerformanceCase 1096e5c31af7Sopenharmony_ci{ 1097e5c31af7Sopenharmony_cipublic: 1098e5c31af7Sopenharmony_ci BinaryOpCase (Context& context, const char* name, const char* description, const char* op, 1099e5c31af7Sopenharmony_ci glu::DataType type, glu::Precision precision, bool useSwizzle, bool isVertex, const InitialCalibrationStorage& initialCalibration); 1100e5c31af7Sopenharmony_ci 1101e5c31af7Sopenharmony_ciprotected: 1102e5c31af7Sopenharmony_ci vector<ProgramContext> generateProgramData (void) const; 1103e5c31af7Sopenharmony_ci void setGeneralUniforms (deUint32 program) const; 1104e5c31af7Sopenharmony_ci void setWorkloadSizeUniform (deUint32 program, int numOperations) const; 1105e5c31af7Sopenharmony_ci float computeSingleOperationTime (const vector<float>& perProgramOperationCosts) const; 1106e5c31af7Sopenharmony_ci void logSingleOperationCalculationInfo (void) const; 1107e5c31af7Sopenharmony_ci 1108e5c31af7Sopenharmony_ciprivate: 1109e5c31af7Sopenharmony_ci enum ProgramID 1110e5c31af7Sopenharmony_ci { 1111e5c31af7Sopenharmony_ci // \note 0-based sequential numbering is relevant, because these are also used as vector indices. 1112e5c31af7Sopenharmony_ci // \note The first program should be the heaviest, because OperatorPerformanceCase uses it to reduce grid/viewport size when going too slow. 1113e5c31af7Sopenharmony_ci PROGRAM_WITH_BIGGER_LOOP = 0, 1114e5c31af7Sopenharmony_ci PROGRAM_WITH_SMALLER_LOOP, 1115e5c31af7Sopenharmony_ci 1116e5c31af7Sopenharmony_ci PROGRAM_LAST 1117e5c31af7Sopenharmony_ci }; 1118e5c31af7Sopenharmony_ci 1119e5c31af7Sopenharmony_ci ProgramContext generateSingleProgramData (ProgramID) const; 1120e5c31af7Sopenharmony_ci 1121e5c31af7Sopenharmony_ci const string m_op; 1122e5c31af7Sopenharmony_ci const glu::DataType m_type; 1123e5c31af7Sopenharmony_ci const glu::Precision m_precision; 1124e5c31af7Sopenharmony_ci const bool m_useSwizzle; 1125e5c31af7Sopenharmony_ci}; 1126e5c31af7Sopenharmony_ci 1127e5c31af7Sopenharmony_ciBinaryOpCase::BinaryOpCase (Context& context, const char* name, const char* description, const char* op, 1128e5c31af7Sopenharmony_ci glu::DataType type, glu::Precision precision, bool useSwizzle, bool isVertex, const InitialCalibrationStorage& initialCalibration) 1129e5c31af7Sopenharmony_ci : OperatorPerformanceCase (context.getTestContext(), context.getRenderContext(), name, description, 1130e5c31af7Sopenharmony_ci isVertex ? CASETYPE_VERTEX : CASETYPE_FRAGMENT, NUM_WORKLOADS, initialCalibration) 1131e5c31af7Sopenharmony_ci , m_op (op) 1132e5c31af7Sopenharmony_ci , m_type (type) 1133e5c31af7Sopenharmony_ci , m_precision (precision) 1134e5c31af7Sopenharmony_ci , m_useSwizzle (useSwizzle) 1135e5c31af7Sopenharmony_ci{ 1136e5c31af7Sopenharmony_ci} 1137e5c31af7Sopenharmony_ci 1138e5c31af7Sopenharmony_ciBinaryOpCase::ProgramContext BinaryOpCase::generateSingleProgramData (ProgramID programID) const 1139e5c31af7Sopenharmony_ci{ 1140e5c31af7Sopenharmony_ci DE_ASSERT(glu::isDataTypeFloatOrVec(m_type) || glu::isDataTypeIntOrIVec(m_type)); 1141e5c31af7Sopenharmony_ci 1142e5c31af7Sopenharmony_ci const bool isVertexCase = m_caseType == CASETYPE_VERTEX; 1143e5c31af7Sopenharmony_ci const char* const precision = glu::getPrecisionName(m_precision); 1144e5c31af7Sopenharmony_ci const char* const inputPrecision = glu::isDataTypeIntOrIVec(m_type) && m_precision == glu::PRECISION_LOWP ? "mediump" : precision; 1145e5c31af7Sopenharmony_ci const char* const typeName = getDataTypeName(m_type); 1146e5c31af7Sopenharmony_ci 1147e5c31af7Sopenharmony_ci std::ostringstream vtx; 1148e5c31af7Sopenharmony_ci std::ostringstream frag; 1149e5c31af7Sopenharmony_ci std::ostringstream& op = isVertexCase ? vtx : frag; 1150e5c31af7Sopenharmony_ci 1151e5c31af7Sopenharmony_ci // Attributes. 1152e5c31af7Sopenharmony_ci vtx << "attribute highp vec4 a_position;\n"; 1153e5c31af7Sopenharmony_ci for (int i = 0; i < BINARY_OPERATOR_CASE_NUM_INDEPENDENT_CALCULATIONS+1; i++) 1154e5c31af7Sopenharmony_ci vtx << "attribute " << inputPrecision << " vec4 a_in" << i << ";\n"; 1155e5c31af7Sopenharmony_ci 1156e5c31af7Sopenharmony_ci if (isVertexCase) 1157e5c31af7Sopenharmony_ci { 1158e5c31af7Sopenharmony_ci vtx << "varying mediump vec4 v_color;\n"; 1159e5c31af7Sopenharmony_ci frag << "varying mediump vec4 v_color;\n"; 1160e5c31af7Sopenharmony_ci } 1161e5c31af7Sopenharmony_ci else 1162e5c31af7Sopenharmony_ci { 1163e5c31af7Sopenharmony_ci for (int i = 0; i < BINARY_OPERATOR_CASE_NUM_INDEPENDENT_CALCULATIONS+1; i++) 1164e5c31af7Sopenharmony_ci { 1165e5c31af7Sopenharmony_ci vtx << "varying " << inputPrecision << " vec4 v_in" << i << ";\n"; 1166e5c31af7Sopenharmony_ci frag << "varying " << inputPrecision << " vec4 v_in" << i << ";\n"; 1167e5c31af7Sopenharmony_ci } 1168e5c31af7Sopenharmony_ci } 1169e5c31af7Sopenharmony_ci 1170e5c31af7Sopenharmony_ci op << "uniform mediump int u_numLoopIterations;\n"; 1171e5c31af7Sopenharmony_ci if (isVertexCase) 1172e5c31af7Sopenharmony_ci op << "uniform mediump float u_zero;\n"; 1173e5c31af7Sopenharmony_ci 1174e5c31af7Sopenharmony_ci vtx << "\n"; 1175e5c31af7Sopenharmony_ci vtx << "void main()\n"; 1176e5c31af7Sopenharmony_ci vtx << "{\n"; 1177e5c31af7Sopenharmony_ci 1178e5c31af7Sopenharmony_ci if (!isVertexCase) 1179e5c31af7Sopenharmony_ci vtx << "\tgl_Position = a_position;\n"; 1180e5c31af7Sopenharmony_ci 1181e5c31af7Sopenharmony_ci frag << "\n"; 1182e5c31af7Sopenharmony_ci frag << "void main()\n"; 1183e5c31af7Sopenharmony_ci frag << "{\n"; 1184e5c31af7Sopenharmony_ci 1185e5c31af7Sopenharmony_ci // Expression inputs. 1186e5c31af7Sopenharmony_ci const char* const prefix = isVertexCase ? "a_" : "v_"; 1187e5c31af7Sopenharmony_ci for (int i = 0; i < BINARY_OPERATOR_CASE_NUM_INDEPENDENT_CALCULATIONS+1; i++) 1188e5c31af7Sopenharmony_ci { 1189e5c31af7Sopenharmony_ci const int inSize = getDataTypeScalarSize(m_type); 1190e5c31af7Sopenharmony_ci const bool isInt = de::inRange<int>(m_type, TYPE_INT, TYPE_INT_VEC4); 1191e5c31af7Sopenharmony_ci const bool cast = isInt || (!m_useSwizzle && m_type != TYPE_FLOAT_VEC4); 1192e5c31af7Sopenharmony_ci 1193e5c31af7Sopenharmony_ci op << "\t" << precision << " " << typeName << " in" << i << " = "; 1194e5c31af7Sopenharmony_ci 1195e5c31af7Sopenharmony_ci if (cast) 1196e5c31af7Sopenharmony_ci op << typeName << "("; 1197e5c31af7Sopenharmony_ci 1198e5c31af7Sopenharmony_ci op << prefix << "in" << i; 1199e5c31af7Sopenharmony_ci 1200e5c31af7Sopenharmony_ci if (m_useSwizzle) 1201e5c31af7Sopenharmony_ci op << "." << s_swizzles[i % DE_LENGTH_OF_ARRAY(s_swizzles)][inSize-1]; 1202e5c31af7Sopenharmony_ci 1203e5c31af7Sopenharmony_ci if (cast) 1204e5c31af7Sopenharmony_ci op << ")"; 1205e5c31af7Sopenharmony_ci 1206e5c31af7Sopenharmony_ci op << ";\n"; 1207e5c31af7Sopenharmony_ci } 1208e5c31af7Sopenharmony_ci 1209e5c31af7Sopenharmony_ci // Operation accumulation variables. 1210e5c31af7Sopenharmony_ci for (int i = 0; i < BINARY_OPERATOR_CASE_NUM_INDEPENDENT_CALCULATIONS; i++) 1211e5c31af7Sopenharmony_ci { 1212e5c31af7Sopenharmony_ci op << "\t" << precision << " " << typeName << " acc" << i << "a" << " = in" << i+0 << ";\n"; 1213e5c31af7Sopenharmony_ci op << "\t" << precision << " " << typeName << " acc" << i << "b" << " = in" << i+1 << ";\n"; 1214e5c31af7Sopenharmony_ci } 1215e5c31af7Sopenharmony_ci 1216e5c31af7Sopenharmony_ci // Loop, with expressions in it. 1217e5c31af7Sopenharmony_ci op << "\tfor (int i = 0; i < u_numLoopIterations; i++)\n"; 1218e5c31af7Sopenharmony_ci op << "\t{\n"; 1219e5c31af7Sopenharmony_ci { 1220e5c31af7Sopenharmony_ci const int unrollAmount = programID == PROGRAM_WITH_SMALLER_LOOP ? BINARY_OPERATOR_CASE_SMALL_PROGRAM_UNROLL_AMOUNT : BINARY_OPERATOR_CASE_BIG_PROGRAM_UNROLL_AMOUNT; 1221e5c31af7Sopenharmony_ci for (int unrollNdx = 0; unrollNdx < unrollAmount; unrollNdx++) 1222e5c31af7Sopenharmony_ci { 1223e5c31af7Sopenharmony_ci for (int i = 0; i < BINARY_OPERATOR_CASE_NUM_INDEPENDENT_CALCULATIONS; i++) 1224e5c31af7Sopenharmony_ci { 1225e5c31af7Sopenharmony_ci if (i > 0 || unrollNdx > 0) 1226e5c31af7Sopenharmony_ci op << "\n"; 1227e5c31af7Sopenharmony_ci op << "\t\tacc" << i << "a = acc" << i << "b " << m_op << " acc" << i << "a" << ";\n"; 1228e5c31af7Sopenharmony_ci op << "\t\tacc" << i << "b = acc" << i << "a " << m_op << " acc" << i << "b" << ";\n"; 1229e5c31af7Sopenharmony_ci } 1230e5c31af7Sopenharmony_ci } 1231e5c31af7Sopenharmony_ci } 1232e5c31af7Sopenharmony_ci op << "\t}\n"; 1233e5c31af7Sopenharmony_ci op << "\n"; 1234e5c31af7Sopenharmony_ci 1235e5c31af7Sopenharmony_ci // Result variable (sum of accumulation variables). 1236e5c31af7Sopenharmony_ci op << "\t" << precision << " " << typeName << " res ="; 1237e5c31af7Sopenharmony_ci for (int i = 0; i < BINARY_OPERATOR_CASE_NUM_INDEPENDENT_CALCULATIONS; i++) 1238e5c31af7Sopenharmony_ci op << (i > 0 ? " "+m_op : "") << " acc" << i << "b"; 1239e5c31af7Sopenharmony_ci op << ";\n"; 1240e5c31af7Sopenharmony_ci 1241e5c31af7Sopenharmony_ci // Convert to color. 1242e5c31af7Sopenharmony_ci op << "\tmediump vec4 color = "; 1243e5c31af7Sopenharmony_ci if (m_type == TYPE_FLOAT_VEC4) 1244e5c31af7Sopenharmony_ci op << "res"; 1245e5c31af7Sopenharmony_ci else 1246e5c31af7Sopenharmony_ci { 1247e5c31af7Sopenharmony_ci int size = getDataTypeScalarSize(m_type); 1248e5c31af7Sopenharmony_ci op << "vec4(res"; 1249e5c31af7Sopenharmony_ci 1250e5c31af7Sopenharmony_ci for (int i = size; i < 4; i++) 1251e5c31af7Sopenharmony_ci op << ", " << (i == 3 ? "1.0" : "0.0"); 1252e5c31af7Sopenharmony_ci 1253e5c31af7Sopenharmony_ci op << ")"; 1254e5c31af7Sopenharmony_ci } 1255e5c31af7Sopenharmony_ci op << ";\n"; 1256e5c31af7Sopenharmony_ci op << "\t" << (isVertexCase ? "v_color" : "gl_FragColor") << " = color;\n"; 1257e5c31af7Sopenharmony_ci 1258e5c31af7Sopenharmony_ci if (isVertexCase) 1259e5c31af7Sopenharmony_ci { 1260e5c31af7Sopenharmony_ci vtx << " gl_Position = a_position + u_zero*color;\n"; 1261e5c31af7Sopenharmony_ci frag << " gl_FragColor = v_color;\n"; 1262e5c31af7Sopenharmony_ci } 1263e5c31af7Sopenharmony_ci else 1264e5c31af7Sopenharmony_ci { 1265e5c31af7Sopenharmony_ci for (int i = 0; i < BINARY_OPERATOR_CASE_NUM_INDEPENDENT_CALCULATIONS+1; i++) 1266e5c31af7Sopenharmony_ci vtx << " v_in" << i << " = a_in" << i << ";\n"; 1267e5c31af7Sopenharmony_ci } 1268e5c31af7Sopenharmony_ci 1269e5c31af7Sopenharmony_ci vtx << "}\n"; 1270e5c31af7Sopenharmony_ci frag << "}\n"; 1271e5c31af7Sopenharmony_ci 1272e5c31af7Sopenharmony_ci { 1273e5c31af7Sopenharmony_ci vector<AttribSpec> attributes; 1274e5c31af7Sopenharmony_ci for (int i = 0; i < BINARY_OPERATOR_CASE_NUM_INDEPENDENT_CALCULATIONS+1; i++) 1275e5c31af7Sopenharmony_ci attributes.push_back(AttribSpec(("a_in" + de::toString(i)).c_str(), 1276e5c31af7Sopenharmony_ci Vec4(2.0f, 2.0f, 2.0f, 1.0f).swizzle((i+0)%4, (i+1)%4, (i+2)%4, (i+3)%4), 1277e5c31af7Sopenharmony_ci Vec4(1.0f, 2.0f, 1.0f, 2.0f).swizzle((i+0)%4, (i+1)%4, (i+2)%4, (i+3)%4), 1278e5c31af7Sopenharmony_ci Vec4(2.0f, 1.0f, 2.0f, 2.0f).swizzle((i+0)%4, (i+1)%4, (i+2)%4, (i+3)%4), 1279e5c31af7Sopenharmony_ci Vec4(1.0f, 1.0f, 2.0f, 1.0f).swizzle((i+0)%4, (i+1)%4, (i+2)%4, (i+3)%4))); 1280e5c31af7Sopenharmony_ci 1281e5c31af7Sopenharmony_ci { 1282e5c31af7Sopenharmony_ci string description = "This is the program with the "; 1283e5c31af7Sopenharmony_ci 1284e5c31af7Sopenharmony_ci description += programID == PROGRAM_WITH_SMALLER_LOOP ? "smaller" 1285e5c31af7Sopenharmony_ci : programID == PROGRAM_WITH_BIGGER_LOOP ? "bigger" 1286e5c31af7Sopenharmony_ci : DE_NULL; 1287e5c31af7Sopenharmony_ci 1288e5c31af7Sopenharmony_ci description += " loop.\n" 1289e5c31af7Sopenharmony_ci "Note: workload size for this program means the number of loop iterations."; 1290e5c31af7Sopenharmony_ci 1291e5c31af7Sopenharmony_ci return ProgramContext(vtx.str(), frag.str(), attributes, description); 1292e5c31af7Sopenharmony_ci } 1293e5c31af7Sopenharmony_ci } 1294e5c31af7Sopenharmony_ci} 1295e5c31af7Sopenharmony_ci 1296e5c31af7Sopenharmony_civector<BinaryOpCase::ProgramContext> BinaryOpCase::generateProgramData (void) const 1297e5c31af7Sopenharmony_ci{ 1298e5c31af7Sopenharmony_ci vector<ProgramContext> progData; 1299e5c31af7Sopenharmony_ci for (int i = 0; i < PROGRAM_LAST; i++) 1300e5c31af7Sopenharmony_ci progData.push_back(generateSingleProgramData((ProgramID)i)); 1301e5c31af7Sopenharmony_ci return progData; 1302e5c31af7Sopenharmony_ci} 1303e5c31af7Sopenharmony_ci 1304e5c31af7Sopenharmony_civoid BinaryOpCase::setGeneralUniforms (deUint32 program) const 1305e5c31af7Sopenharmony_ci{ 1306e5c31af7Sopenharmony_ci const glw::Functions& gl = m_renderCtx.getFunctions(); 1307e5c31af7Sopenharmony_ci gl.uniform1f(gl.getUniformLocation(program, "u_zero"), 0.0f); 1308e5c31af7Sopenharmony_ci} 1309e5c31af7Sopenharmony_ci 1310e5c31af7Sopenharmony_civoid BinaryOpCase::setWorkloadSizeUniform (deUint32 program, int numLoopIterations) const 1311e5c31af7Sopenharmony_ci{ 1312e5c31af7Sopenharmony_ci const glw::Functions& gl = m_renderCtx.getFunctions(); 1313e5c31af7Sopenharmony_ci gl.uniform1i(gl.getUniformLocation(program, "u_numLoopIterations"), numLoopIterations); 1314e5c31af7Sopenharmony_ci} 1315e5c31af7Sopenharmony_ci 1316e5c31af7Sopenharmony_cifloat BinaryOpCase::computeSingleOperationTime (const vector<float>& perProgramOperationCosts) const 1317e5c31af7Sopenharmony_ci{ 1318e5c31af7Sopenharmony_ci DE_ASSERT(perProgramOperationCosts.size() == PROGRAM_LAST); 1319e5c31af7Sopenharmony_ci 1320e5c31af7Sopenharmony_ci const int baseNumOpsInsideLoop = 2 * BINARY_OPERATOR_CASE_NUM_INDEPENDENT_CALCULATIONS; 1321e5c31af7Sopenharmony_ci const int numOpsInsideLoopInSmallProgram = baseNumOpsInsideLoop * BINARY_OPERATOR_CASE_SMALL_PROGRAM_UNROLL_AMOUNT; 1322e5c31af7Sopenharmony_ci const int numOpsInsideLoopInBigProgram = baseNumOpsInsideLoop * BINARY_OPERATOR_CASE_BIG_PROGRAM_UNROLL_AMOUNT; 1323e5c31af7Sopenharmony_ci DE_STATIC_ASSERT(numOpsInsideLoopInBigProgram > numOpsInsideLoopInSmallProgram); 1324e5c31af7Sopenharmony_ci const int opDiff = numOpsInsideLoopInBigProgram - numOpsInsideLoopInSmallProgram; 1325e5c31af7Sopenharmony_ci const float programOperationCostDiff = perProgramOperationCosts[PROGRAM_WITH_BIGGER_LOOP] - perProgramOperationCosts[PROGRAM_WITH_SMALLER_LOOP]; 1326e5c31af7Sopenharmony_ci 1327e5c31af7Sopenharmony_ci return programOperationCostDiff / (float)opDiff; 1328e5c31af7Sopenharmony_ci} 1329e5c31af7Sopenharmony_ci 1330e5c31af7Sopenharmony_civoid BinaryOpCase::logSingleOperationCalculationInfo (void) const 1331e5c31af7Sopenharmony_ci{ 1332e5c31af7Sopenharmony_ci const int baseNumOpsInsideLoop = 2 * BINARY_OPERATOR_CASE_NUM_INDEPENDENT_CALCULATIONS; 1333e5c31af7Sopenharmony_ci const int numOpsInsideLoopInSmallProgram = baseNumOpsInsideLoop * BINARY_OPERATOR_CASE_SMALL_PROGRAM_UNROLL_AMOUNT; 1334e5c31af7Sopenharmony_ci const int numOpsInsideLoopInBigProgram = baseNumOpsInsideLoop * BINARY_OPERATOR_CASE_BIG_PROGRAM_UNROLL_AMOUNT; 1335e5c31af7Sopenharmony_ci const int opDiff = numOpsInsideLoopInBigProgram - numOpsInsideLoopInSmallProgram; 1336e5c31af7Sopenharmony_ci const char* const opName = m_op == "+" ? "addition" 1337e5c31af7Sopenharmony_ci : m_op == "-" ? "subtraction" 1338e5c31af7Sopenharmony_ci : m_op == "*" ? "multiplication" 1339e5c31af7Sopenharmony_ci : m_op == "/" ? "division" 1340e5c31af7Sopenharmony_ci : DE_NULL; 1341e5c31af7Sopenharmony_ci DE_ASSERT(opName != DE_NULL); 1342e5c31af7Sopenharmony_ci 1343e5c31af7Sopenharmony_ci m_testCtx.getLog() << TestLog::Message << "Note: the bigger program contains " << opDiff << " more " 1344e5c31af7Sopenharmony_ci << opName << " operations in one loop iteration than the small program; " 1345e5c31af7Sopenharmony_ci << "cost of one operation is calculated as (cost_of_bigger_workload - cost_of_smaller_workload) / " << opDiff 1346e5c31af7Sopenharmony_ci << TestLog::EndMessage; 1347e5c31af7Sopenharmony_ci} 1348e5c31af7Sopenharmony_ci 1349e5c31af7Sopenharmony_ci// Built-in function case. 1350e5c31af7Sopenharmony_ciclass FunctionCase : public OperatorPerformanceCase 1351e5c31af7Sopenharmony_ci{ 1352e5c31af7Sopenharmony_cipublic: 1353e5c31af7Sopenharmony_ci enum 1354e5c31af7Sopenharmony_ci { 1355e5c31af7Sopenharmony_ci MAX_PARAMS = 3 1356e5c31af7Sopenharmony_ci }; 1357e5c31af7Sopenharmony_ci 1358e5c31af7Sopenharmony_ci FunctionCase (Context& context, 1359e5c31af7Sopenharmony_ci const char* name, 1360e5c31af7Sopenharmony_ci const char* description, 1361e5c31af7Sopenharmony_ci const char* func, 1362e5c31af7Sopenharmony_ci glu::DataType returnType, 1363e5c31af7Sopenharmony_ci const glu::DataType paramTypes[MAX_PARAMS], 1364e5c31af7Sopenharmony_ci const Vec4& attribute, 1365e5c31af7Sopenharmony_ci int modifyParamNdx, //!< Add a compile-time constant (2.0) to the parameter at this index. This is ignored if negative. 1366e5c31af7Sopenharmony_ci bool useNearlyConstantINputs, //!< Function inputs shouldn't be much bigger than 'attribute'. 1367e5c31af7Sopenharmony_ci glu::Precision precision, 1368e5c31af7Sopenharmony_ci bool isVertex, 1369e5c31af7Sopenharmony_ci const InitialCalibrationStorage& initialCalibration); 1370e5c31af7Sopenharmony_ci 1371e5c31af7Sopenharmony_ciprotected: 1372e5c31af7Sopenharmony_ci vector<ProgramContext> generateProgramData (void) const; 1373e5c31af7Sopenharmony_ci void setGeneralUniforms (deUint32 program) const; 1374e5c31af7Sopenharmony_ci void setWorkloadSizeUniform (deUint32 program, int numOperations) const; 1375e5c31af7Sopenharmony_ci float computeSingleOperationTime (const vector<float>& perProgramOperationCosts) const; 1376e5c31af7Sopenharmony_ci void logSingleOperationCalculationInfo (void) const; 1377e5c31af7Sopenharmony_ci 1378e5c31af7Sopenharmony_ciprivate: 1379e5c31af7Sopenharmony_ci enum ProgramID 1380e5c31af7Sopenharmony_ci { 1381e5c31af7Sopenharmony_ci // \note 0-based sequential numbering is relevant, because these are also used as vector indices. 1382e5c31af7Sopenharmony_ci // \note The first program should be the heaviest, because OperatorPerformanceCase uses it to reduce grid/viewport size when going too slow. 1383e5c31af7Sopenharmony_ci PROGRAM_WITH_FUNCTION_CALLS = 0, 1384e5c31af7Sopenharmony_ci PROGRAM_WITHOUT_FUNCTION_CALLS, 1385e5c31af7Sopenharmony_ci 1386e5c31af7Sopenharmony_ci PROGRAM_LAST 1387e5c31af7Sopenharmony_ci }; 1388e5c31af7Sopenharmony_ci 1389e5c31af7Sopenharmony_ci //! Forms a "sum" expression from aExpr and bExpr; for booleans, this is "equal(a,b)", otherwise actual sum. 1390e5c31af7Sopenharmony_ci static string sumExpr (const string& aExpr, const string& bExpr, glu::DataType type); 1391e5c31af7Sopenharmony_ci //! Forms an expression used to increment an input value in the shader. If type is boolean, this is just 1392e5c31af7Sopenharmony_ci //! baseExpr; otherwise, baseExpr is modified by multiplication or division by a loop index, 1393e5c31af7Sopenharmony_ci //! to prevent simple compiler optimizations. See m_useNearlyConstantInputs for more explanation. 1394e5c31af7Sopenharmony_ci static string incrementExpr (const string& baseExpr, glu::DataType type, bool divide); 1395e5c31af7Sopenharmony_ci 1396e5c31af7Sopenharmony_ci ProgramContext generateSingleProgramData (ProgramID) const; 1397e5c31af7Sopenharmony_ci 1398e5c31af7Sopenharmony_ci const string m_func; 1399e5c31af7Sopenharmony_ci const glu::DataType m_returnType; 1400e5c31af7Sopenharmony_ci glu::DataType m_paramTypes[MAX_PARAMS]; 1401e5c31af7Sopenharmony_ci // \note m_modifyParamNdx, if not negative, specifies the index of the parameter to which a 1402e5c31af7Sopenharmony_ci // compile-time constant (2.0) is added. This is a quick and dirty way to deal with 1403e5c31af7Sopenharmony_ci // functions like clamp or smoothstep that require that a certain parameter is 1404e5c31af7Sopenharmony_ci // greater than a certain other parameter. 1405e5c31af7Sopenharmony_ci const int m_modifyParamNdx; 1406e5c31af7Sopenharmony_ci // \note m_useNearlyConstantInputs determines whether the inputs given to the function 1407e5c31af7Sopenharmony_ci // should increase (w.r.t m_attribute) only by very small amounts. This is relevant 1408e5c31af7Sopenharmony_ci // for functions like asin, which requires its inputs to be in a specific range. 1409e5c31af7Sopenharmony_ci // In practice, this affects whether expressions used to increment the input 1410e5c31af7Sopenharmony_ci // variables use division instead of multiplication; normally, multiplication is used, 1411e5c31af7Sopenharmony_ci // but it's hard to keep the increments very small that way, and division shouldn't 1412e5c31af7Sopenharmony_ci // be the default, since for many functions (probably not asin, luckily), division 1413e5c31af7Sopenharmony_ci // is too heavy and dominates time-wise. 1414e5c31af7Sopenharmony_ci const bool m_useNearlyConstantInputs; 1415e5c31af7Sopenharmony_ci const Vec4 m_attribute; 1416e5c31af7Sopenharmony_ci const glu::Precision m_precision; 1417e5c31af7Sopenharmony_ci}; 1418e5c31af7Sopenharmony_ci 1419e5c31af7Sopenharmony_ciFunctionCase::FunctionCase (Context& context, 1420e5c31af7Sopenharmony_ci const char* name, 1421e5c31af7Sopenharmony_ci const char* description, 1422e5c31af7Sopenharmony_ci const char* func, 1423e5c31af7Sopenharmony_ci glu::DataType returnType, 1424e5c31af7Sopenharmony_ci const glu::DataType paramTypes[MAX_PARAMS], 1425e5c31af7Sopenharmony_ci const Vec4& attribute, 1426e5c31af7Sopenharmony_ci int modifyParamNdx, 1427e5c31af7Sopenharmony_ci bool useNearlyConstantInputs, 1428e5c31af7Sopenharmony_ci glu::Precision precision, 1429e5c31af7Sopenharmony_ci bool isVertex, 1430e5c31af7Sopenharmony_ci const InitialCalibrationStorage& initialCalibration) 1431e5c31af7Sopenharmony_ci : OperatorPerformanceCase (context.getTestContext(), context.getRenderContext(), name, description, 1432e5c31af7Sopenharmony_ci isVertex ? CASETYPE_VERTEX : CASETYPE_FRAGMENT, NUM_WORKLOADS, initialCalibration) 1433e5c31af7Sopenharmony_ci , m_func (func) 1434e5c31af7Sopenharmony_ci , m_returnType (returnType) 1435e5c31af7Sopenharmony_ci , m_modifyParamNdx (modifyParamNdx) 1436e5c31af7Sopenharmony_ci , m_useNearlyConstantInputs (useNearlyConstantInputs) 1437e5c31af7Sopenharmony_ci , m_attribute (attribute) 1438e5c31af7Sopenharmony_ci , m_precision (precision) 1439e5c31af7Sopenharmony_ci{ 1440e5c31af7Sopenharmony_ci for (int i = 0; i < MAX_PARAMS; i++) 1441e5c31af7Sopenharmony_ci m_paramTypes[i] = paramTypes[i]; 1442e5c31af7Sopenharmony_ci} 1443e5c31af7Sopenharmony_ci 1444e5c31af7Sopenharmony_cistring FunctionCase::sumExpr (const string& aExpr, const string& bExpr, glu::DataType type) 1445e5c31af7Sopenharmony_ci{ 1446e5c31af7Sopenharmony_ci if (glu::isDataTypeBoolOrBVec(type)) 1447e5c31af7Sopenharmony_ci { 1448e5c31af7Sopenharmony_ci if (type == glu::TYPE_BOOL) 1449e5c31af7Sopenharmony_ci return "(" + aExpr + " == " + bExpr + ")"; 1450e5c31af7Sopenharmony_ci else 1451e5c31af7Sopenharmony_ci return "equal(" + aExpr + ", " + bExpr + ")"; 1452e5c31af7Sopenharmony_ci } 1453e5c31af7Sopenharmony_ci else 1454e5c31af7Sopenharmony_ci return "(" + aExpr + " + " + bExpr + ")"; 1455e5c31af7Sopenharmony_ci} 1456e5c31af7Sopenharmony_ci 1457e5c31af7Sopenharmony_cistring FunctionCase::incrementExpr (const string& baseExpr, glu::DataType type, bool divide) 1458e5c31af7Sopenharmony_ci{ 1459e5c31af7Sopenharmony_ci const string mulOrDiv = divide ? "/" : "*"; 1460e5c31af7Sopenharmony_ci 1461e5c31af7Sopenharmony_ci return glu::isDataTypeBoolOrBVec(type) ? baseExpr 1462e5c31af7Sopenharmony_ci : glu::isDataTypeIntOrIVec(type) ? "(" + baseExpr + mulOrDiv + "(i+1))" 1463e5c31af7Sopenharmony_ci : "(" + baseExpr + mulOrDiv + "float(i+1))"; 1464e5c31af7Sopenharmony_ci} 1465e5c31af7Sopenharmony_ci 1466e5c31af7Sopenharmony_ciFunctionCase::ProgramContext FunctionCase::generateSingleProgramData (ProgramID programID) const 1467e5c31af7Sopenharmony_ci{ 1468e5c31af7Sopenharmony_ci const bool isVertexCase = m_caseType == CASETYPE_VERTEX; 1469e5c31af7Sopenharmony_ci const char* const precision = glu::getPrecisionName(m_precision); 1470e5c31af7Sopenharmony_ci const char* const returnTypeName = getDataTypeName(m_returnType); 1471e5c31af7Sopenharmony_ci const string returnPrecisionMaybe = glu::isDataTypeBoolOrBVec(m_returnType) ? "" : string() + precision + " "; 1472e5c31af7Sopenharmony_ci const char* inputPrecision = DE_NULL; 1473e5c31af7Sopenharmony_ci const bool isMatrixReturn = isDataTypeMatrix(m_returnType); 1474e5c31af7Sopenharmony_ci int numParams = 0; 1475e5c31af7Sopenharmony_ci const char* paramTypeNames[MAX_PARAMS]; 1476e5c31af7Sopenharmony_ci string paramPrecisionsMaybe[MAX_PARAMS]; 1477e5c31af7Sopenharmony_ci 1478e5c31af7Sopenharmony_ci for (int i = 0; i < MAX_PARAMS; i++) 1479e5c31af7Sopenharmony_ci { 1480e5c31af7Sopenharmony_ci paramTypeNames[i] = getDataTypeName(m_paramTypes[i]); 1481e5c31af7Sopenharmony_ci paramPrecisionsMaybe[i] = glu::isDataTypeBoolOrBVec(m_paramTypes[i]) ? "" : string() + precision + " "; 1482e5c31af7Sopenharmony_ci 1483e5c31af7Sopenharmony_ci if (inputPrecision == DE_NULL && isDataTypeIntOrIVec(m_paramTypes[i]) && m_precision == glu::PRECISION_LOWP) 1484e5c31af7Sopenharmony_ci inputPrecision = "mediump"; 1485e5c31af7Sopenharmony_ci 1486e5c31af7Sopenharmony_ci if (m_paramTypes[i] != TYPE_INVALID) 1487e5c31af7Sopenharmony_ci numParams = i+1; 1488e5c31af7Sopenharmony_ci } 1489e5c31af7Sopenharmony_ci 1490e5c31af7Sopenharmony_ci DE_ASSERT(numParams > 0); 1491e5c31af7Sopenharmony_ci 1492e5c31af7Sopenharmony_ci if (inputPrecision == DE_NULL) 1493e5c31af7Sopenharmony_ci inputPrecision = precision; 1494e5c31af7Sopenharmony_ci 1495e5c31af7Sopenharmony_ci int numAttributes = FUNCTION_CASE_NUM_INDEPENDENT_CALCULATIONS + numParams - 1; 1496e5c31af7Sopenharmony_ci std::ostringstream vtx; 1497e5c31af7Sopenharmony_ci std::ostringstream frag; 1498e5c31af7Sopenharmony_ci std::ostringstream& op = isVertexCase ? vtx : frag; 1499e5c31af7Sopenharmony_ci 1500e5c31af7Sopenharmony_ci // Attributes. 1501e5c31af7Sopenharmony_ci vtx << "attribute highp vec4 a_position;\n"; 1502e5c31af7Sopenharmony_ci for (int i = 0; i < numAttributes; i++) 1503e5c31af7Sopenharmony_ci vtx << "attribute " << inputPrecision << " vec4 a_in" << i << ";\n"; 1504e5c31af7Sopenharmony_ci 1505e5c31af7Sopenharmony_ci if (isVertexCase) 1506e5c31af7Sopenharmony_ci { 1507e5c31af7Sopenharmony_ci vtx << "varying mediump vec4 v_color;\n"; 1508e5c31af7Sopenharmony_ci frag << "varying mediump vec4 v_color;\n"; 1509e5c31af7Sopenharmony_ci } 1510e5c31af7Sopenharmony_ci else 1511e5c31af7Sopenharmony_ci { 1512e5c31af7Sopenharmony_ci for (int i = 0; i < numAttributes; i++) 1513e5c31af7Sopenharmony_ci { 1514e5c31af7Sopenharmony_ci vtx << "varying " << inputPrecision << " vec4 v_in" << i << ";\n"; 1515e5c31af7Sopenharmony_ci frag << "varying " << inputPrecision << " vec4 v_in" << i << ";\n"; 1516e5c31af7Sopenharmony_ci } 1517e5c31af7Sopenharmony_ci } 1518e5c31af7Sopenharmony_ci 1519e5c31af7Sopenharmony_ci op << "uniform mediump int u_numLoopIterations;\n"; 1520e5c31af7Sopenharmony_ci if (isVertexCase) 1521e5c31af7Sopenharmony_ci op << "uniform mediump float u_zero;\n"; 1522e5c31af7Sopenharmony_ci 1523e5c31af7Sopenharmony_ci for (int paramNdx = 0; paramNdx < numParams; paramNdx++) 1524e5c31af7Sopenharmony_ci op << "uniform " << paramPrecisionsMaybe[paramNdx] << paramTypeNames[paramNdx] << " u_inc" << (char)('A'+paramNdx) << ";\n"; 1525e5c31af7Sopenharmony_ci 1526e5c31af7Sopenharmony_ci vtx << "\n"; 1527e5c31af7Sopenharmony_ci vtx << "void main()\n"; 1528e5c31af7Sopenharmony_ci vtx << "{\n"; 1529e5c31af7Sopenharmony_ci 1530e5c31af7Sopenharmony_ci if (!isVertexCase) 1531e5c31af7Sopenharmony_ci vtx << "\tgl_Position = a_position;\n"; 1532e5c31af7Sopenharmony_ci 1533e5c31af7Sopenharmony_ci frag << "\n"; 1534e5c31af7Sopenharmony_ci frag << "void main()\n"; 1535e5c31af7Sopenharmony_ci frag << "{\n"; 1536e5c31af7Sopenharmony_ci 1537e5c31af7Sopenharmony_ci // Function call input and return value accumulation variables. 1538e5c31af7Sopenharmony_ci { 1539e5c31af7Sopenharmony_ci const char* const inPrefix = isVertexCase ? "a_" : "v_"; 1540e5c31af7Sopenharmony_ci 1541e5c31af7Sopenharmony_ci for (int calcNdx = 0; calcNdx < FUNCTION_CASE_NUM_INDEPENDENT_CALCULATIONS; calcNdx++) 1542e5c31af7Sopenharmony_ci { 1543e5c31af7Sopenharmony_ci for (int paramNdx = 0; paramNdx < numParams; paramNdx++) 1544e5c31af7Sopenharmony_ci { 1545e5c31af7Sopenharmony_ci const glu::DataType paramType = m_paramTypes[paramNdx]; 1546e5c31af7Sopenharmony_ci const bool mustCast = paramType != glu::TYPE_FLOAT_VEC4; 1547e5c31af7Sopenharmony_ci 1548e5c31af7Sopenharmony_ci op << "\t" << paramPrecisionsMaybe[paramNdx] << paramTypeNames[paramNdx] << " in" << calcNdx << (char)('a'+paramNdx) << " = "; 1549e5c31af7Sopenharmony_ci 1550e5c31af7Sopenharmony_ci if (mustCast) 1551e5c31af7Sopenharmony_ci op << paramTypeNames[paramNdx] << "("; 1552e5c31af7Sopenharmony_ci 1553e5c31af7Sopenharmony_ci if (glu::isDataTypeMatrix(paramType)) 1554e5c31af7Sopenharmony_ci { 1555e5c31af7Sopenharmony_ci static const char* const swizzles[3] = { "x", "xy", "xyz" }; 1556e5c31af7Sopenharmony_ci const int numRows = glu::getDataTypeMatrixNumRows(paramType); 1557e5c31af7Sopenharmony_ci const int numCols = glu::getDataTypeMatrixNumColumns(paramType); 1558e5c31af7Sopenharmony_ci const string swizzle = numRows < 4 ? string() + "." + swizzles[numRows-1] : ""; 1559e5c31af7Sopenharmony_ci 1560e5c31af7Sopenharmony_ci for (int i = 0; i < numCols; i++) 1561e5c31af7Sopenharmony_ci op << (i > 0 ? ", " : "") << inPrefix << "in" << calcNdx+paramNdx << swizzle; 1562e5c31af7Sopenharmony_ci } 1563e5c31af7Sopenharmony_ci else 1564e5c31af7Sopenharmony_ci { 1565e5c31af7Sopenharmony_ci op << inPrefix << "in" << calcNdx+paramNdx; 1566e5c31af7Sopenharmony_ci 1567e5c31af7Sopenharmony_ci if (paramNdx == m_modifyParamNdx) 1568e5c31af7Sopenharmony_ci { 1569e5c31af7Sopenharmony_ci DE_ASSERT(glu::isDataTypeFloatOrVec(paramType)); 1570e5c31af7Sopenharmony_ci op << " + 2.0"; 1571e5c31af7Sopenharmony_ci } 1572e5c31af7Sopenharmony_ci } 1573e5c31af7Sopenharmony_ci 1574e5c31af7Sopenharmony_ci if (mustCast) 1575e5c31af7Sopenharmony_ci op << ")"; 1576e5c31af7Sopenharmony_ci 1577e5c31af7Sopenharmony_ci op << ";\n"; 1578e5c31af7Sopenharmony_ci } 1579e5c31af7Sopenharmony_ci 1580e5c31af7Sopenharmony_ci op << "\t" << returnPrecisionMaybe << returnTypeName << " res" << calcNdx << " = " << returnTypeName << "(0);\n"; 1581e5c31af7Sopenharmony_ci } 1582e5c31af7Sopenharmony_ci } 1583e5c31af7Sopenharmony_ci 1584e5c31af7Sopenharmony_ci // Loop with expressions in it. 1585e5c31af7Sopenharmony_ci op << "\tfor (int i = 0; i < u_numLoopIterations; i++)\n"; 1586e5c31af7Sopenharmony_ci op << "\t{\n"; 1587e5c31af7Sopenharmony_ci for (int calcNdx = 0; calcNdx < FUNCTION_CASE_NUM_INDEPENDENT_CALCULATIONS; calcNdx++) 1588e5c31af7Sopenharmony_ci { 1589e5c31af7Sopenharmony_ci if (calcNdx > 0) 1590e5c31af7Sopenharmony_ci op << "\n"; 1591e5c31af7Sopenharmony_ci 1592e5c31af7Sopenharmony_ci op << "\t\t{\n"; 1593e5c31af7Sopenharmony_ci 1594e5c31af7Sopenharmony_ci for (int inputNdx = 0; inputNdx < numParams; inputNdx++) 1595e5c31af7Sopenharmony_ci { 1596e5c31af7Sopenharmony_ci const string inputName = "in" + de::toString(calcNdx) + (char)('a'+inputNdx); 1597e5c31af7Sopenharmony_ci const string incName = string() + "u_inc" + (char)('A'+inputNdx); 1598e5c31af7Sopenharmony_ci const string incExpr = incrementExpr(incName, m_paramTypes[inputNdx], m_useNearlyConstantInputs); 1599e5c31af7Sopenharmony_ci 1600e5c31af7Sopenharmony_ci op << "\t\t\t" << inputName << " = " << sumExpr(inputName, incExpr, m_paramTypes[inputNdx]) << ";\n"; 1601e5c31af7Sopenharmony_ci } 1602e5c31af7Sopenharmony_ci 1603e5c31af7Sopenharmony_ci op << "\t\t\t" << returnPrecisionMaybe << returnTypeName << " eval" << calcNdx << " = "; 1604e5c31af7Sopenharmony_ci 1605e5c31af7Sopenharmony_ci if (programID == PROGRAM_WITH_FUNCTION_CALLS) 1606e5c31af7Sopenharmony_ci { 1607e5c31af7Sopenharmony_ci op << m_func << "("; 1608e5c31af7Sopenharmony_ci 1609e5c31af7Sopenharmony_ci for (int paramNdx = 0; paramNdx < numParams; paramNdx++) 1610e5c31af7Sopenharmony_ci { 1611e5c31af7Sopenharmony_ci if (paramNdx > 0) 1612e5c31af7Sopenharmony_ci op << ", "; 1613e5c31af7Sopenharmony_ci 1614e5c31af7Sopenharmony_ci op << "in" << calcNdx << (char)('a'+paramNdx); 1615e5c31af7Sopenharmony_ci } 1616e5c31af7Sopenharmony_ci 1617e5c31af7Sopenharmony_ci op << ")"; 1618e5c31af7Sopenharmony_ci } 1619e5c31af7Sopenharmony_ci else 1620e5c31af7Sopenharmony_ci { 1621e5c31af7Sopenharmony_ci DE_ASSERT(programID == PROGRAM_WITHOUT_FUNCTION_CALLS); 1622e5c31af7Sopenharmony_ci op << returnTypeName << "(1)"; 1623e5c31af7Sopenharmony_ci } 1624e5c31af7Sopenharmony_ci 1625e5c31af7Sopenharmony_ci op << ";\n"; 1626e5c31af7Sopenharmony_ci 1627e5c31af7Sopenharmony_ci { 1628e5c31af7Sopenharmony_ci const string resName = "res" + de::toString(calcNdx); 1629e5c31af7Sopenharmony_ci const string evalName = "eval" + de::toString(calcNdx); 1630e5c31af7Sopenharmony_ci const string incExpr = incrementExpr(evalName, m_returnType, m_useNearlyConstantInputs); 1631e5c31af7Sopenharmony_ci 1632e5c31af7Sopenharmony_ci op << "\t\t\tres" << calcNdx << " = " << sumExpr(resName, incExpr, m_returnType) << ";\n"; 1633e5c31af7Sopenharmony_ci } 1634e5c31af7Sopenharmony_ci 1635e5c31af7Sopenharmony_ci op << "\t\t}\n"; 1636e5c31af7Sopenharmony_ci } 1637e5c31af7Sopenharmony_ci op << "\t}\n"; 1638e5c31af7Sopenharmony_ci op << "\n"; 1639e5c31af7Sopenharmony_ci 1640e5c31af7Sopenharmony_ci // Result variables. 1641e5c31af7Sopenharmony_ci for (int inputNdx = 0; inputNdx < numParams; inputNdx++) 1642e5c31af7Sopenharmony_ci { 1643e5c31af7Sopenharmony_ci op << "\t" << paramPrecisionsMaybe[inputNdx] << paramTypeNames[inputNdx] << " sumIn" << (char)('A'+inputNdx) << " = "; 1644e5c31af7Sopenharmony_ci { 1645e5c31af7Sopenharmony_ci string expr = string() + "in0" + (char)('a'+inputNdx); 1646e5c31af7Sopenharmony_ci for (int i = 1; i < FUNCTION_CASE_NUM_INDEPENDENT_CALCULATIONS; i++) 1647e5c31af7Sopenharmony_ci expr = sumExpr(expr, string() + "in" + de::toString(i) + (char)('a'+inputNdx), m_paramTypes[inputNdx]); 1648e5c31af7Sopenharmony_ci op << expr; 1649e5c31af7Sopenharmony_ci } 1650e5c31af7Sopenharmony_ci op << ";\n"; 1651e5c31af7Sopenharmony_ci } 1652e5c31af7Sopenharmony_ci 1653e5c31af7Sopenharmony_ci op << "\t" << returnPrecisionMaybe << returnTypeName << " sumRes = "; 1654e5c31af7Sopenharmony_ci { 1655e5c31af7Sopenharmony_ci string expr = "res0"; 1656e5c31af7Sopenharmony_ci for (int i = 1; i < FUNCTION_CASE_NUM_INDEPENDENT_CALCULATIONS; i++) 1657e5c31af7Sopenharmony_ci expr = sumExpr(expr, "res" + de::toString(i), m_returnType); 1658e5c31af7Sopenharmony_ci op << expr; 1659e5c31af7Sopenharmony_ci } 1660e5c31af7Sopenharmony_ci op << ";\n"; 1661e5c31af7Sopenharmony_ci 1662e5c31af7Sopenharmony_ci { 1663e5c31af7Sopenharmony_ci glu::DataType finalResultDataType = glu::TYPE_LAST; 1664e5c31af7Sopenharmony_ci 1665e5c31af7Sopenharmony_ci if (glu::isDataTypeMatrix(m_returnType)) 1666e5c31af7Sopenharmony_ci { 1667e5c31af7Sopenharmony_ci finalResultDataType = m_returnType; 1668e5c31af7Sopenharmony_ci 1669e5c31af7Sopenharmony_ci op << "\t" << precision << " " << returnTypeName << " finalRes = "; 1670e5c31af7Sopenharmony_ci 1671e5c31af7Sopenharmony_ci for (int inputNdx = 0; inputNdx < numParams; inputNdx++) 1672e5c31af7Sopenharmony_ci { 1673e5c31af7Sopenharmony_ci DE_ASSERT(m_paramTypes[inputNdx] == m_returnType); 1674e5c31af7Sopenharmony_ci op << "sumIn" << (char)('A'+inputNdx) << " + "; 1675e5c31af7Sopenharmony_ci } 1676e5c31af7Sopenharmony_ci op << "sumRes;\n"; 1677e5c31af7Sopenharmony_ci } 1678e5c31af7Sopenharmony_ci else 1679e5c31af7Sopenharmony_ci { 1680e5c31af7Sopenharmony_ci int numFinalResComponents = glu::getDataTypeScalarSize(m_returnType); 1681e5c31af7Sopenharmony_ci for (int inputNdx = 0; inputNdx < numParams; inputNdx++) 1682e5c31af7Sopenharmony_ci numFinalResComponents = de::max(numFinalResComponents, glu::getDataTypeScalarSize(m_paramTypes[inputNdx])); 1683e5c31af7Sopenharmony_ci 1684e5c31af7Sopenharmony_ci finalResultDataType = getDataTypeFloatOrVec(numFinalResComponents); 1685e5c31af7Sopenharmony_ci 1686e5c31af7Sopenharmony_ci { 1687e5c31af7Sopenharmony_ci const string finalResType = glu::getDataTypeName(finalResultDataType); 1688e5c31af7Sopenharmony_ci op << "\t" << precision << " " << finalResType << " finalRes = "; 1689e5c31af7Sopenharmony_ci for (int inputNdx = 0; inputNdx < numParams; inputNdx++) 1690e5c31af7Sopenharmony_ci op << finalResType << "(sumIn" << (char)('A'+inputNdx) << ") + "; 1691e5c31af7Sopenharmony_ci op << finalResType << "(sumRes);\n"; 1692e5c31af7Sopenharmony_ci } 1693e5c31af7Sopenharmony_ci } 1694e5c31af7Sopenharmony_ci 1695e5c31af7Sopenharmony_ci // Convert to color. 1696e5c31af7Sopenharmony_ci op << "\tmediump vec4 color = "; 1697e5c31af7Sopenharmony_ci if (finalResultDataType == TYPE_FLOAT_VEC4) 1698e5c31af7Sopenharmony_ci op << "finalRes"; 1699e5c31af7Sopenharmony_ci else 1700e5c31af7Sopenharmony_ci { 1701e5c31af7Sopenharmony_ci int size = isMatrixReturn ? getDataTypeMatrixNumRows(finalResultDataType) : getDataTypeScalarSize(finalResultDataType); 1702e5c31af7Sopenharmony_ci 1703e5c31af7Sopenharmony_ci op << "vec4("; 1704e5c31af7Sopenharmony_ci 1705e5c31af7Sopenharmony_ci if (isMatrixReturn) 1706e5c31af7Sopenharmony_ci { 1707e5c31af7Sopenharmony_ci for (int i = 0; i < getDataTypeMatrixNumColumns(finalResultDataType); i++) 1708e5c31af7Sopenharmony_ci { 1709e5c31af7Sopenharmony_ci if (i > 0) 1710e5c31af7Sopenharmony_ci op << " + "; 1711e5c31af7Sopenharmony_ci op << "finalRes[" << i << "]"; 1712e5c31af7Sopenharmony_ci } 1713e5c31af7Sopenharmony_ci } 1714e5c31af7Sopenharmony_ci else 1715e5c31af7Sopenharmony_ci op << "finalRes"; 1716e5c31af7Sopenharmony_ci 1717e5c31af7Sopenharmony_ci for (int i = size; i < 4; i++) 1718e5c31af7Sopenharmony_ci op << ", " << (i == 3 ? "1.0" : "0.0"); 1719e5c31af7Sopenharmony_ci 1720e5c31af7Sopenharmony_ci op << ")"; 1721e5c31af7Sopenharmony_ci } 1722e5c31af7Sopenharmony_ci op << ";\n"; 1723e5c31af7Sopenharmony_ci op << "\t" << (isVertexCase ? "v_color" : "gl_FragColor") << " = color;\n"; 1724e5c31af7Sopenharmony_ci 1725e5c31af7Sopenharmony_ci if (isVertexCase) 1726e5c31af7Sopenharmony_ci { 1727e5c31af7Sopenharmony_ci vtx << " gl_Position = a_position + u_zero*color;\n"; 1728e5c31af7Sopenharmony_ci frag << " gl_FragColor = v_color;\n"; 1729e5c31af7Sopenharmony_ci } 1730e5c31af7Sopenharmony_ci else 1731e5c31af7Sopenharmony_ci { 1732e5c31af7Sopenharmony_ci for (int i = 0; i < numAttributes; i++) 1733e5c31af7Sopenharmony_ci vtx << " v_in" << i << " = a_in" << i << ";\n"; 1734e5c31af7Sopenharmony_ci } 1735e5c31af7Sopenharmony_ci 1736e5c31af7Sopenharmony_ci vtx << "}\n"; 1737e5c31af7Sopenharmony_ci frag << "}\n"; 1738e5c31af7Sopenharmony_ci } 1739e5c31af7Sopenharmony_ci 1740e5c31af7Sopenharmony_ci { 1741e5c31af7Sopenharmony_ci vector<AttribSpec> attributes; 1742e5c31af7Sopenharmony_ci for (int i = 0; i < numAttributes; i++) 1743e5c31af7Sopenharmony_ci attributes.push_back(AttribSpec(("a_in" + de::toString(i)).c_str(), 1744e5c31af7Sopenharmony_ci m_attribute.swizzle((i+0)%4, (i+1)%4, (i+2)%4, (i+3)%4), 1745e5c31af7Sopenharmony_ci m_attribute.swizzle((i+1)%4, (i+2)%4, (i+3)%4, (i+0)%4), 1746e5c31af7Sopenharmony_ci m_attribute.swizzle((i+2)%4, (i+3)%4, (i+0)%4, (i+1)%4), 1747e5c31af7Sopenharmony_ci m_attribute.swizzle((i+3)%4, (i+0)%4, (i+1)%4, (i+2)%4))); 1748e5c31af7Sopenharmony_ci 1749e5c31af7Sopenharmony_ci { 1750e5c31af7Sopenharmony_ci string description = "This is the program "; 1751e5c31af7Sopenharmony_ci 1752e5c31af7Sopenharmony_ci description += programID == PROGRAM_WITHOUT_FUNCTION_CALLS ? "without" 1753e5c31af7Sopenharmony_ci : programID == PROGRAM_WITH_FUNCTION_CALLS ? "with" 1754e5c31af7Sopenharmony_ci : DE_NULL; 1755e5c31af7Sopenharmony_ci 1756e5c31af7Sopenharmony_ci description += " '" + m_func + "' function calls.\n" 1757e5c31af7Sopenharmony_ci "Note: workload size for this program means the number of loop iterations."; 1758e5c31af7Sopenharmony_ci 1759e5c31af7Sopenharmony_ci return ProgramContext(vtx.str(), frag.str(), attributes, description); 1760e5c31af7Sopenharmony_ci } 1761e5c31af7Sopenharmony_ci } 1762e5c31af7Sopenharmony_ci} 1763e5c31af7Sopenharmony_ci 1764e5c31af7Sopenharmony_civector<FunctionCase::ProgramContext> FunctionCase::generateProgramData (void) const 1765e5c31af7Sopenharmony_ci{ 1766e5c31af7Sopenharmony_ci vector<ProgramContext> progData; 1767e5c31af7Sopenharmony_ci for (int i = 0; i < PROGRAM_LAST; i++) 1768e5c31af7Sopenharmony_ci progData.push_back(generateSingleProgramData((ProgramID)i)); 1769e5c31af7Sopenharmony_ci return progData; 1770e5c31af7Sopenharmony_ci} 1771e5c31af7Sopenharmony_ci 1772e5c31af7Sopenharmony_civoid FunctionCase::setGeneralUniforms (deUint32 program) const 1773e5c31af7Sopenharmony_ci{ 1774e5c31af7Sopenharmony_ci const glw::Functions& gl = m_renderCtx.getFunctions(); 1775e5c31af7Sopenharmony_ci 1776e5c31af7Sopenharmony_ci gl.uniform1f(gl.getUniformLocation(program, "u_zero"), 0.0f); 1777e5c31af7Sopenharmony_ci 1778e5c31af7Sopenharmony_ci for (int paramNdx = 0; paramNdx < MAX_PARAMS; paramNdx++) 1779e5c31af7Sopenharmony_ci { 1780e5c31af7Sopenharmony_ci if (m_paramTypes[paramNdx] != glu::TYPE_INVALID) 1781e5c31af7Sopenharmony_ci { 1782e5c31af7Sopenharmony_ci const glu::DataType paramType = m_paramTypes[paramNdx]; 1783e5c31af7Sopenharmony_ci const int scalarSize = glu::getDataTypeScalarSize(paramType); 1784e5c31af7Sopenharmony_ci const int location = gl.getUniformLocation(program, (string() + "u_inc" + (char)('A'+paramNdx)).c_str()); 1785e5c31af7Sopenharmony_ci 1786e5c31af7Sopenharmony_ci if (glu::isDataTypeFloatOrVec(paramType)) 1787e5c31af7Sopenharmony_ci { 1788e5c31af7Sopenharmony_ci float values[4]; 1789e5c31af7Sopenharmony_ci for (int i = 0; i < DE_LENGTH_OF_ARRAY(values); i++) 1790e5c31af7Sopenharmony_ci values[i] = (float)paramNdx*0.01f + (float)i*0.001f; // Arbitrary small values. 1791e5c31af7Sopenharmony_ci uniformNfv(gl, scalarSize, location, 1, &values[0]); 1792e5c31af7Sopenharmony_ci } 1793e5c31af7Sopenharmony_ci else if (glu::isDataTypeIntOrIVec(paramType)) 1794e5c31af7Sopenharmony_ci { 1795e5c31af7Sopenharmony_ci int values[4]; 1796e5c31af7Sopenharmony_ci for (int i = 0; i < DE_LENGTH_OF_ARRAY(values); i++) 1797e5c31af7Sopenharmony_ci values[i] = paramNdx*100 + i; // Arbitrary values. 1798e5c31af7Sopenharmony_ci uniformNiv(gl, scalarSize, location, 1, &values[0]); 1799e5c31af7Sopenharmony_ci } 1800e5c31af7Sopenharmony_ci else if (glu::isDataTypeBoolOrBVec(paramType)) 1801e5c31af7Sopenharmony_ci { 1802e5c31af7Sopenharmony_ci int values[4]; 1803e5c31af7Sopenharmony_ci for (int i = 0; i < DE_LENGTH_OF_ARRAY(values); i++) 1804e5c31af7Sopenharmony_ci values[i] = (paramNdx >> i) & 1; // Arbitrary values. 1805e5c31af7Sopenharmony_ci uniformNiv(gl, scalarSize, location, 1, &values[0]); 1806e5c31af7Sopenharmony_ci } 1807e5c31af7Sopenharmony_ci else if (glu::isDataTypeMatrix(paramType)) 1808e5c31af7Sopenharmony_ci { 1809e5c31af7Sopenharmony_ci const int size = glu::getDataTypeMatrixNumRows(paramType); 1810e5c31af7Sopenharmony_ci DE_ASSERT(size == glu::getDataTypeMatrixNumColumns(paramType)); 1811e5c31af7Sopenharmony_ci float values[4*4]; 1812e5c31af7Sopenharmony_ci for (int i = 0; i < DE_LENGTH_OF_ARRAY(values); i++) 1813e5c31af7Sopenharmony_ci values[i] = (float)paramNdx*0.01f + (float)i*0.001f; // Arbitrary values. 1814e5c31af7Sopenharmony_ci uniformMatrixNfv(gl, size, location, 1, &values[0]); 1815e5c31af7Sopenharmony_ci } 1816e5c31af7Sopenharmony_ci else 1817e5c31af7Sopenharmony_ci DE_ASSERT(false); 1818e5c31af7Sopenharmony_ci } 1819e5c31af7Sopenharmony_ci } 1820e5c31af7Sopenharmony_ci} 1821e5c31af7Sopenharmony_ci 1822e5c31af7Sopenharmony_civoid FunctionCase::setWorkloadSizeUniform (deUint32 program, int numLoopIterations) const 1823e5c31af7Sopenharmony_ci{ 1824e5c31af7Sopenharmony_ci const glw::Functions& gl = m_renderCtx.getFunctions(); 1825e5c31af7Sopenharmony_ci const int loc = gl.getUniformLocation(program, "u_numLoopIterations"); 1826e5c31af7Sopenharmony_ci 1827e5c31af7Sopenharmony_ci gl.uniform1i(loc, numLoopIterations); 1828e5c31af7Sopenharmony_ci} 1829e5c31af7Sopenharmony_ci 1830e5c31af7Sopenharmony_cifloat FunctionCase::computeSingleOperationTime (const vector<float>& perProgramOperationCosts) const 1831e5c31af7Sopenharmony_ci{ 1832e5c31af7Sopenharmony_ci DE_ASSERT(perProgramOperationCosts.size() == PROGRAM_LAST); 1833e5c31af7Sopenharmony_ci const int numFunctionCalls = FUNCTION_CASE_NUM_INDEPENDENT_CALCULATIONS; 1834e5c31af7Sopenharmony_ci const float programOperationCostDiff = perProgramOperationCosts[PROGRAM_WITH_FUNCTION_CALLS] - perProgramOperationCosts[PROGRAM_WITHOUT_FUNCTION_CALLS]; 1835e5c31af7Sopenharmony_ci 1836e5c31af7Sopenharmony_ci return programOperationCostDiff / (float)numFunctionCalls; 1837e5c31af7Sopenharmony_ci} 1838e5c31af7Sopenharmony_ci 1839e5c31af7Sopenharmony_civoid FunctionCase::logSingleOperationCalculationInfo (void) const 1840e5c31af7Sopenharmony_ci{ 1841e5c31af7Sopenharmony_ci const int numFunctionCalls = FUNCTION_CASE_NUM_INDEPENDENT_CALCULATIONS; 1842e5c31af7Sopenharmony_ci 1843e5c31af7Sopenharmony_ci m_testCtx.getLog() << TestLog::Message << "Note: program " << (int)PROGRAM_WITH_FUNCTION_CALLS << " contains " 1844e5c31af7Sopenharmony_ci << numFunctionCalls << " calls to '" << m_func << "' in one loop iteration; " 1845e5c31af7Sopenharmony_ci << "cost of one operation is calculated as " 1846e5c31af7Sopenharmony_ci << "(cost_of_workload_with_calls - cost_of_workload_without_calls) / " << numFunctionCalls << TestLog::EndMessage; 1847e5c31af7Sopenharmony_ci} 1848e5c31af7Sopenharmony_ci 1849e5c31af7Sopenharmony_ci} // anonymous 1850e5c31af7Sopenharmony_ci 1851e5c31af7Sopenharmony_ciShaderOperatorTests::ShaderOperatorTests (Context& context) 1852e5c31af7Sopenharmony_ci : TestCaseGroup(context, "operator", "Operator Performance Tests") 1853e5c31af7Sopenharmony_ci{ 1854e5c31af7Sopenharmony_ci} 1855e5c31af7Sopenharmony_ci 1856e5c31af7Sopenharmony_ciShaderOperatorTests::~ShaderOperatorTests (void) 1857e5c31af7Sopenharmony_ci{ 1858e5c31af7Sopenharmony_ci} 1859e5c31af7Sopenharmony_ci 1860e5c31af7Sopenharmony_civoid ShaderOperatorTests::init (void) 1861e5c31af7Sopenharmony_ci{ 1862e5c31af7Sopenharmony_ci // Binary operator cases 1863e5c31af7Sopenharmony_ci 1864e5c31af7Sopenharmony_ci static const DataType binaryOpTypes[] = 1865e5c31af7Sopenharmony_ci { 1866e5c31af7Sopenharmony_ci TYPE_FLOAT, 1867e5c31af7Sopenharmony_ci TYPE_FLOAT_VEC2, 1868e5c31af7Sopenharmony_ci TYPE_FLOAT_VEC3, 1869e5c31af7Sopenharmony_ci TYPE_FLOAT_VEC4, 1870e5c31af7Sopenharmony_ci TYPE_INT, 1871e5c31af7Sopenharmony_ci TYPE_INT_VEC2, 1872e5c31af7Sopenharmony_ci TYPE_INT_VEC3, 1873e5c31af7Sopenharmony_ci TYPE_INT_VEC4, 1874e5c31af7Sopenharmony_ci }; 1875e5c31af7Sopenharmony_ci static const Precision precisions[] = 1876e5c31af7Sopenharmony_ci { 1877e5c31af7Sopenharmony_ci PRECISION_LOWP, 1878e5c31af7Sopenharmony_ci PRECISION_MEDIUMP, 1879e5c31af7Sopenharmony_ci PRECISION_HIGHP 1880e5c31af7Sopenharmony_ci }; 1881e5c31af7Sopenharmony_ci static const struct 1882e5c31af7Sopenharmony_ci { 1883e5c31af7Sopenharmony_ci const char* name; 1884e5c31af7Sopenharmony_ci const char* op; 1885e5c31af7Sopenharmony_ci bool swizzle; 1886e5c31af7Sopenharmony_ci } binaryOps[] = 1887e5c31af7Sopenharmony_ci { 1888e5c31af7Sopenharmony_ci { "add", "+", false }, 1889e5c31af7Sopenharmony_ci { "sub", "-", true }, 1890e5c31af7Sopenharmony_ci { "mul", "*", false }, 1891e5c31af7Sopenharmony_ci { "div", "/", true } 1892e5c31af7Sopenharmony_ci }; 1893e5c31af7Sopenharmony_ci 1894e5c31af7Sopenharmony_ci tcu::TestCaseGroup* const binaryOpsGroup = new tcu::TestCaseGroup(m_testCtx, "binary_operator", "Binary Operator Performance Tests"); 1895e5c31af7Sopenharmony_ci addChild(binaryOpsGroup); 1896e5c31af7Sopenharmony_ci 1897e5c31af7Sopenharmony_ci for (int opNdx = 0; opNdx < DE_LENGTH_OF_ARRAY(binaryOps); opNdx++) 1898e5c31af7Sopenharmony_ci { 1899e5c31af7Sopenharmony_ci tcu::TestCaseGroup* const opGroup = new tcu::TestCaseGroup(m_testCtx, binaryOps[opNdx].name, ""); 1900e5c31af7Sopenharmony_ci binaryOpsGroup->addChild(opGroup); 1901e5c31af7Sopenharmony_ci 1902e5c31af7Sopenharmony_ci for (int isFrag = 0; isFrag <= 1; isFrag++) 1903e5c31af7Sopenharmony_ci { 1904e5c31af7Sopenharmony_ci const BinaryOpCase::InitialCalibrationStorage shaderGroupCalibrationStorage (new BinaryOpCase::InitialCalibration); 1905e5c31af7Sopenharmony_ci const bool isVertex = isFrag == 0; 1906e5c31af7Sopenharmony_ci tcu::TestCaseGroup* const shaderGroup = new tcu::TestCaseGroup(m_testCtx, isVertex ? "vertex" : "fragment", ""); 1907e5c31af7Sopenharmony_ci opGroup->addChild(shaderGroup); 1908e5c31af7Sopenharmony_ci 1909e5c31af7Sopenharmony_ci for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(binaryOpTypes); typeNdx++) 1910e5c31af7Sopenharmony_ci { 1911e5c31af7Sopenharmony_ci for (int precNdx = 0; precNdx < DE_LENGTH_OF_ARRAY(precisions); precNdx++) 1912e5c31af7Sopenharmony_ci { 1913e5c31af7Sopenharmony_ci const DataType type = binaryOpTypes[typeNdx]; 1914e5c31af7Sopenharmony_ci const Precision precision = precisions[precNdx]; 1915e5c31af7Sopenharmony_ci const char* const op = binaryOps[opNdx].op; 1916e5c31af7Sopenharmony_ci const bool useSwizzle = binaryOps[opNdx].swizzle; 1917e5c31af7Sopenharmony_ci std::ostringstream name; 1918e5c31af7Sopenharmony_ci 1919e5c31af7Sopenharmony_ci name << getPrecisionName(precision) << "_" << getDataTypeName(type); 1920e5c31af7Sopenharmony_ci 1921e5c31af7Sopenharmony_ci shaderGroup->addChild(new BinaryOpCase(m_context, name.str().c_str(), "", op, type, precision, useSwizzle, isVertex, shaderGroupCalibrationStorage)); 1922e5c31af7Sopenharmony_ci } 1923e5c31af7Sopenharmony_ci } 1924e5c31af7Sopenharmony_ci } 1925e5c31af7Sopenharmony_ci } 1926e5c31af7Sopenharmony_ci 1927e5c31af7Sopenharmony_ci // Built-in function cases. 1928e5c31af7Sopenharmony_ci 1929e5c31af7Sopenharmony_ci // Non-specific (i.e. includes gentypes) parameter types for the functions. 1930e5c31af7Sopenharmony_ci enum ValueType 1931e5c31af7Sopenharmony_ci { 1932e5c31af7Sopenharmony_ci VALUE_NONE = 0, 1933e5c31af7Sopenharmony_ci VALUE_FLOAT = (1<<0), // float scalar 1934e5c31af7Sopenharmony_ci VALUE_FLOAT_VEC = (1<<1), // float vector 1935e5c31af7Sopenharmony_ci VALUE_FLOAT_VEC34 = (1<<2), // float vector of size 3 or 4 1936e5c31af7Sopenharmony_ci VALUE_FLOAT_GENTYPE = (1<<3), // float scalar/vector 1937e5c31af7Sopenharmony_ci VALUE_VEC3 = (1<<4), // vec3 only 1938e5c31af7Sopenharmony_ci VALUE_VEC4 = (1<<5), // vec4 only 1939e5c31af7Sopenharmony_ci VALUE_MATRIX = (1<<6), // matrix 1940e5c31af7Sopenharmony_ci VALUE_BOOL = (1<<7), // boolean scalar 1941e5c31af7Sopenharmony_ci VALUE_BOOL_VEC = (1<<8), // boolean vector 1942e5c31af7Sopenharmony_ci VALUE_BOOL_GENTYPE = (1<<9), // boolean scalar/vector 1943e5c31af7Sopenharmony_ci VALUE_INT = (1<<10), // int scalar 1944e5c31af7Sopenharmony_ci VALUE_INT_VEC = (1<<11), // int vector 1945e5c31af7Sopenharmony_ci VALUE_INT_GENTYPE = (1<<12), // int scalar/vector 1946e5c31af7Sopenharmony_ci 1947e5c31af7Sopenharmony_ci // Shorthands. 1948e5c31af7Sopenharmony_ci N = VALUE_NONE, 1949e5c31af7Sopenharmony_ci F = VALUE_FLOAT, 1950e5c31af7Sopenharmony_ci FV = VALUE_FLOAT_VEC, 1951e5c31af7Sopenharmony_ci VL = VALUE_FLOAT_VEC34, // L for "large" 1952e5c31af7Sopenharmony_ci GT = VALUE_FLOAT_GENTYPE, 1953e5c31af7Sopenharmony_ci V3 = VALUE_VEC3, 1954e5c31af7Sopenharmony_ci V4 = VALUE_VEC4, 1955e5c31af7Sopenharmony_ci M = VALUE_MATRIX, 1956e5c31af7Sopenharmony_ci B = VALUE_BOOL, 1957e5c31af7Sopenharmony_ci BV = VALUE_BOOL_VEC, 1958e5c31af7Sopenharmony_ci BGT = VALUE_BOOL_GENTYPE, 1959e5c31af7Sopenharmony_ci I = VALUE_INT, 1960e5c31af7Sopenharmony_ci IV = VALUE_INT_VEC, 1961e5c31af7Sopenharmony_ci IGT = VALUE_INT_GENTYPE, 1962e5c31af7Sopenharmony_ci 1963e5c31af7Sopenharmony_ci VALUE_ANY_FLOAT = VALUE_FLOAT | VALUE_FLOAT_VEC | VALUE_FLOAT_GENTYPE | VALUE_VEC3 | VALUE_VEC4 | VALUE_FLOAT_VEC34, 1964e5c31af7Sopenharmony_ci VALUE_ANY_INT = VALUE_INT | VALUE_INT_VEC | VALUE_INT_GENTYPE, 1965e5c31af7Sopenharmony_ci VALUE_ANY_BOOL = VALUE_BOOL | VALUE_BOOL_VEC | VALUE_BOOL_GENTYPE, 1966e5c31af7Sopenharmony_ci 1967e5c31af7Sopenharmony_ci VALUE_ANY_GENTYPE = VALUE_FLOAT_VEC | VALUE_FLOAT_GENTYPE | VALUE_FLOAT_VEC34 | 1968e5c31af7Sopenharmony_ci VALUE_BOOL_VEC | VALUE_BOOL_GENTYPE | 1969e5c31af7Sopenharmony_ci VALUE_INT_VEC | VALUE_INT_GENTYPE | 1970e5c31af7Sopenharmony_ci VALUE_MATRIX 1971e5c31af7Sopenharmony_ci }; 1972e5c31af7Sopenharmony_ci enum PrecisionMask 1973e5c31af7Sopenharmony_ci { 1974e5c31af7Sopenharmony_ci PRECMASK_NA = 0, //!< Precision not applicable (booleans) 1975e5c31af7Sopenharmony_ci PRECMASK_LOWP = (1<<PRECISION_LOWP), 1976e5c31af7Sopenharmony_ci PRECMASK_MEDIUMP = (1<<PRECISION_MEDIUMP), 1977e5c31af7Sopenharmony_ci PRECMASK_HIGHP = (1<<PRECISION_HIGHP), 1978e5c31af7Sopenharmony_ci 1979e5c31af7Sopenharmony_ci PRECMASK_MEDIUMP_HIGHP = (1<<PRECISION_MEDIUMP) | (1<<PRECISION_HIGHP), 1980e5c31af7Sopenharmony_ci PRECMASK_ALL = (1<<PRECISION_LOWP) | (1<<PRECISION_MEDIUMP) | (1<<PRECISION_HIGHP) 1981e5c31af7Sopenharmony_ci }; 1982e5c31af7Sopenharmony_ci 1983e5c31af7Sopenharmony_ci static const DataType floatTypes[] = 1984e5c31af7Sopenharmony_ci { 1985e5c31af7Sopenharmony_ci TYPE_FLOAT, 1986e5c31af7Sopenharmony_ci TYPE_FLOAT_VEC2, 1987e5c31af7Sopenharmony_ci TYPE_FLOAT_VEC3, 1988e5c31af7Sopenharmony_ci TYPE_FLOAT_VEC4 1989e5c31af7Sopenharmony_ci }; 1990e5c31af7Sopenharmony_ci static const DataType intTypes[] = 1991e5c31af7Sopenharmony_ci { 1992e5c31af7Sopenharmony_ci TYPE_INT, 1993e5c31af7Sopenharmony_ci TYPE_INT_VEC2, 1994e5c31af7Sopenharmony_ci TYPE_INT_VEC3, 1995e5c31af7Sopenharmony_ci TYPE_INT_VEC4 1996e5c31af7Sopenharmony_ci }; 1997e5c31af7Sopenharmony_ci static const DataType boolTypes[] = 1998e5c31af7Sopenharmony_ci { 1999e5c31af7Sopenharmony_ci TYPE_BOOL, 2000e5c31af7Sopenharmony_ci TYPE_BOOL_VEC2, 2001e5c31af7Sopenharmony_ci TYPE_BOOL_VEC3, 2002e5c31af7Sopenharmony_ci TYPE_BOOL_VEC4 2003e5c31af7Sopenharmony_ci }; 2004e5c31af7Sopenharmony_ci static const DataType matrixTypes[] = 2005e5c31af7Sopenharmony_ci { 2006e5c31af7Sopenharmony_ci TYPE_FLOAT_MAT2, 2007e5c31af7Sopenharmony_ci TYPE_FLOAT_MAT3, 2008e5c31af7Sopenharmony_ci TYPE_FLOAT_MAT4 2009e5c31af7Sopenharmony_ci }; 2010e5c31af7Sopenharmony_ci 2011e5c31af7Sopenharmony_ci tcu::TestCaseGroup* const angleAndTrigonometryGroup = new tcu::TestCaseGroup(m_testCtx, "angle_and_trigonometry", "Built-In Angle and Trigonometry Function Performance Tests"); 2012e5c31af7Sopenharmony_ci tcu::TestCaseGroup* const exponentialGroup = new tcu::TestCaseGroup(m_testCtx, "exponential", "Built-In Exponential Function Performance Tests"); 2013e5c31af7Sopenharmony_ci tcu::TestCaseGroup* const commonFunctionsGroup = new tcu::TestCaseGroup(m_testCtx, "common_functions", "Built-In Common Function Performance Tests"); 2014e5c31af7Sopenharmony_ci tcu::TestCaseGroup* const geometricFunctionsGroup = new tcu::TestCaseGroup(m_testCtx, "geometric", "Built-In Geometric Function Performance Tests"); 2015e5c31af7Sopenharmony_ci tcu::TestCaseGroup* const matrixFunctionsGroup = new tcu::TestCaseGroup(m_testCtx, "matrix", "Built-In Matrix Function Performance Tests"); 2016e5c31af7Sopenharmony_ci tcu::TestCaseGroup* const floatCompareGroup = new tcu::TestCaseGroup(m_testCtx, "float_compare", "Built-In Floating Point Comparison Function Performance Tests"); 2017e5c31af7Sopenharmony_ci tcu::TestCaseGroup* const intCompareGroup = new tcu::TestCaseGroup(m_testCtx, "int_compare", "Built-In Integer Comparison Function Performance Tests"); 2018e5c31af7Sopenharmony_ci tcu::TestCaseGroup* const boolCompareGroup = new tcu::TestCaseGroup(m_testCtx, "bool_compare", "Built-In Boolean Comparison Function Performance Tests"); 2019e5c31af7Sopenharmony_ci 2020e5c31af7Sopenharmony_ci addChild(angleAndTrigonometryGroup); 2021e5c31af7Sopenharmony_ci addChild(exponentialGroup); 2022e5c31af7Sopenharmony_ci addChild(commonFunctionsGroup); 2023e5c31af7Sopenharmony_ci addChild(geometricFunctionsGroup); 2024e5c31af7Sopenharmony_ci addChild(matrixFunctionsGroup); 2025e5c31af7Sopenharmony_ci addChild(floatCompareGroup); 2026e5c31af7Sopenharmony_ci addChild(intCompareGroup); 2027e5c31af7Sopenharmony_ci addChild(boolCompareGroup); 2028e5c31af7Sopenharmony_ci 2029e5c31af7Sopenharmony_ci // Some attributes to be used as parameters for the functions. 2030e5c31af7Sopenharmony_ci const Vec4 attrPos = Vec4( 2.3f, 1.9f, 0.8f, 0.7f); 2031e5c31af7Sopenharmony_ci const Vec4 attrNegPos = Vec4(-1.3f, 2.5f, -3.5f, 4.3f); 2032e5c31af7Sopenharmony_ci const Vec4 attrSmall = Vec4(-0.9f, 0.8f, -0.4f, 0.2f); 2033e5c31af7Sopenharmony_ci 2034e5c31af7Sopenharmony_ci // Function name, return type and parameter type information; also, what attribute should be used in the test. 2035e5c31af7Sopenharmony_ci // \note Different versions of the same function (i.e. with the same group name) can be defined by putting them successively in this array. 2036e5c31af7Sopenharmony_ci // \note In order to reduce case count and thus total execution time, we don't test all input type combinations for every function. 2037e5c31af7Sopenharmony_ci static const struct 2038e5c31af7Sopenharmony_ci { 2039e5c31af7Sopenharmony_ci tcu::TestCaseGroup* parentGroup; 2040e5c31af7Sopenharmony_ci const char* groupName; 2041e5c31af7Sopenharmony_ci const char* func; 2042e5c31af7Sopenharmony_ci const ValueType types[FunctionCase::MAX_PARAMS + 1]; // Return type and parameter types, in that order. 2043e5c31af7Sopenharmony_ci const Vec4& attribute; 2044e5c31af7Sopenharmony_ci int modifyParamNdx; 2045e5c31af7Sopenharmony_ci bool useNearlyConstantInputs; 2046e5c31af7Sopenharmony_ci bool booleanCase; 2047e5c31af7Sopenharmony_ci PrecisionMask precMask; 2048e5c31af7Sopenharmony_ci } functionCaseGroups[] = 2049e5c31af7Sopenharmony_ci { 2050e5c31af7Sopenharmony_ci { angleAndTrigonometryGroup, "radians", "radians", { F, F, N, N }, attrNegPos, -1, false, false, PRECMASK_ALL }, 2051e5c31af7Sopenharmony_ci { angleAndTrigonometryGroup, "degrees", "degrees", { F, F, N, N }, attrNegPos, -1, false, false, PRECMASK_ALL }, 2052e5c31af7Sopenharmony_ci { angleAndTrigonometryGroup, "sin", "sin", { F, F, N, N }, attrNegPos, -1, false, false, PRECMASK_ALL }, 2053e5c31af7Sopenharmony_ci { angleAndTrigonometryGroup, "cos", "cos", { F, F, N, N }, attrNegPos, -1, false, false, PRECMASK_ALL }, 2054e5c31af7Sopenharmony_ci { angleAndTrigonometryGroup, "tan", "tan", { F, F, N, N }, attrNegPos, -1, false, false, PRECMASK_ALL }, 2055e5c31af7Sopenharmony_ci { angleAndTrigonometryGroup, "asin", "asin", { F, F, N, N }, attrSmall, -1, true, false, PRECMASK_ALL }, 2056e5c31af7Sopenharmony_ci { angleAndTrigonometryGroup, "acos", "acos", { F, F, N, N }, attrSmall, -1, true, false, PRECMASK_ALL }, 2057e5c31af7Sopenharmony_ci { angleAndTrigonometryGroup, "atan2", "atan", { F, F, F, N }, attrNegPos, -1, false, false, PRECMASK_ALL }, 2058e5c31af7Sopenharmony_ci { angleAndTrigonometryGroup, "atan", "atan", { F, F, N, N }, attrNegPos, -1, false, false, PRECMASK_ALL }, 2059e5c31af7Sopenharmony_ci 2060e5c31af7Sopenharmony_ci { exponentialGroup, "pow", "pow", { F, F, F, N }, attrPos, -1, false, false, PRECMASK_ALL }, 2061e5c31af7Sopenharmony_ci { exponentialGroup, "exp", "exp", { F, F, N, N }, attrNegPos, -1, false, false, PRECMASK_ALL }, 2062e5c31af7Sopenharmony_ci { exponentialGroup, "log", "log", { F, F, N, N }, attrPos, -1, false, false, PRECMASK_ALL }, 2063e5c31af7Sopenharmony_ci { exponentialGroup, "exp2", "exp2", { F, F, N, N }, attrNegPos, -1, false, false, PRECMASK_ALL }, 2064e5c31af7Sopenharmony_ci { exponentialGroup, "log2", "log2", { F, F, N, N }, attrPos, -1, false, false, PRECMASK_ALL }, 2065e5c31af7Sopenharmony_ci { exponentialGroup, "sqrt", "sqrt", { F, F, N, N }, attrPos, -1, false, false, PRECMASK_ALL }, 2066e5c31af7Sopenharmony_ci { exponentialGroup, "inversesqrt", "inversesqrt", { F, F, N, N }, attrPos, -1, false, false, PRECMASK_ALL }, 2067e5c31af7Sopenharmony_ci 2068e5c31af7Sopenharmony_ci { commonFunctionsGroup, "abs", "abs", { F, F, N, N }, attrNegPos, -1, false, false, PRECMASK_MEDIUMP_HIGHP }, 2069e5c31af7Sopenharmony_ci { commonFunctionsGroup, "abs", "abs", { V4, V4, N, N }, attrNegPos, -1, false, false, PRECMASK_ALL }, 2070e5c31af7Sopenharmony_ci { commonFunctionsGroup, "sign", "sign", { F, F, N, N }, attrNegPos, -1, false, false, PRECMASK_MEDIUMP_HIGHP }, 2071e5c31af7Sopenharmony_ci { commonFunctionsGroup, "sign", "sign", { V4, V4, N, N }, attrNegPos, -1, false, false, PRECMASK_ALL }, 2072e5c31af7Sopenharmony_ci { commonFunctionsGroup, "floor", "floor", { F, F, N, N }, attrNegPos, -1, false, false, PRECMASK_MEDIUMP_HIGHP }, 2073e5c31af7Sopenharmony_ci { commonFunctionsGroup, "floor", "floor", { V4, V4, N, N }, attrNegPos, -1, false, false, PRECMASK_ALL }, 2074e5c31af7Sopenharmony_ci { commonFunctionsGroup, "ceil", "ceil", { F, F, N, N }, attrNegPos, -1, false, false, PRECMASK_MEDIUMP_HIGHP }, 2075e5c31af7Sopenharmony_ci { commonFunctionsGroup, "ceil", "ceil", { V4, V4, N, N }, attrNegPos, -1, false, false, PRECMASK_ALL }, 2076e5c31af7Sopenharmony_ci { commonFunctionsGroup, "fract", "fract", { F, F, N, N }, attrNegPos, -1, false, false, PRECMASK_MEDIUMP_HIGHP }, 2077e5c31af7Sopenharmony_ci { commonFunctionsGroup, "fract", "fract", { V4, V4, N, N }, attrNegPos, -1, false, false, PRECMASK_ALL }, 2078e5c31af7Sopenharmony_ci { commonFunctionsGroup, "mod", "mod", { GT, GT, GT, N }, attrNegPos, -1, false, false, PRECMASK_ALL }, 2079e5c31af7Sopenharmony_ci { commonFunctionsGroup, "min", "min", { F, F, F, N }, attrNegPos, -1, false, false, PRECMASK_MEDIUMP_HIGHP }, 2080e5c31af7Sopenharmony_ci { commonFunctionsGroup, "min", "min", { V4, V4, V4, N }, attrNegPos, -1, false, false, PRECMASK_ALL }, 2081e5c31af7Sopenharmony_ci { commonFunctionsGroup, "max", "max", { F, F, F, N }, attrNegPos, -1, false, false, PRECMASK_MEDIUMP_HIGHP }, 2082e5c31af7Sopenharmony_ci { commonFunctionsGroup, "max", "max", { V4, V4, V4, N }, attrNegPos, -1, false, false, PRECMASK_ALL }, 2083e5c31af7Sopenharmony_ci { commonFunctionsGroup, "clamp", "clamp", { F, F, F, F }, attrSmall, 2, false, false, PRECMASK_MEDIUMP_HIGHP }, 2084e5c31af7Sopenharmony_ci { commonFunctionsGroup, "clamp", "clamp", { V4, V4, V4, V4 }, attrSmall, 2, false, false, PRECMASK_ALL }, 2085e5c31af7Sopenharmony_ci { commonFunctionsGroup, "mix", "mix", { F, F, F, F }, attrNegPos, -1, false, false, PRECMASK_MEDIUMP_HIGHP }, 2086e5c31af7Sopenharmony_ci { commonFunctionsGroup, "mix", "mix", { V4, V4, V4, V4 }, attrNegPos, -1, false, false, PRECMASK_ALL }, 2087e5c31af7Sopenharmony_ci { commonFunctionsGroup, "step", "step", { F, F, F, N }, attrNegPos, -1, false, false, PRECMASK_MEDIUMP_HIGHP }, 2088e5c31af7Sopenharmony_ci { commonFunctionsGroup, "step", "step", { V4, V4, V4, N }, attrNegPos, -1, false, false, PRECMASK_ALL }, 2089e5c31af7Sopenharmony_ci { commonFunctionsGroup, "smoothstep", "smoothstep", { F, F, F, F }, attrSmall, 1, false, false, PRECMASK_MEDIUMP_HIGHP }, 2090e5c31af7Sopenharmony_ci { commonFunctionsGroup, "smoothstep", "smoothstep", { V4, V4, V4, V4 }, attrSmall, 1, false, false, PRECMASK_ALL }, 2091e5c31af7Sopenharmony_ci 2092e5c31af7Sopenharmony_ci { geometricFunctionsGroup, "length", "length", { F, VL, N, N }, attrNegPos, -1, false, false, PRECMASK_ALL }, 2093e5c31af7Sopenharmony_ci { geometricFunctionsGroup, "distance", "distance", { F, VL, VL, N }, attrNegPos, -1, false, false, PRECMASK_ALL }, 2094e5c31af7Sopenharmony_ci { geometricFunctionsGroup, "dot", "dot", { F, VL, VL, N }, attrNegPos, -1, false, false, PRECMASK_ALL }, 2095e5c31af7Sopenharmony_ci { geometricFunctionsGroup, "cross", "cross", { V3, V3, V3, N }, attrNegPos, -1, false, false, PRECMASK_ALL }, 2096e5c31af7Sopenharmony_ci { geometricFunctionsGroup, "normalize", "normalize", { VL, VL, N, N }, attrNegPos, -1, false, false, PRECMASK_ALL }, 2097e5c31af7Sopenharmony_ci { geometricFunctionsGroup, "faceforward", "faceforward", { VL, VL, VL, VL }, attrNegPos, -1, false, false, PRECMASK_ALL }, 2098e5c31af7Sopenharmony_ci { geometricFunctionsGroup, "reflect", "reflect", { VL, VL, VL, N }, attrNegPos, -1, false, false, PRECMASK_ALL }, 2099e5c31af7Sopenharmony_ci { geometricFunctionsGroup, "refract", "refract", { VL, VL, VL, F }, attrNegPos, -1, false, false, PRECMASK_ALL }, 2100e5c31af7Sopenharmony_ci 2101e5c31af7Sopenharmony_ci { matrixFunctionsGroup, "matrixCompMult", "matrixCompMult", { M, M, M, N }, attrNegPos, -1, false, false, PRECMASK_ALL }, 2102e5c31af7Sopenharmony_ci 2103e5c31af7Sopenharmony_ci { floatCompareGroup, "lessThan", "lessThan", { BV, FV, FV, N }, attrNegPos, -1, false, false, PRECMASK_ALL }, 2104e5c31af7Sopenharmony_ci { floatCompareGroup, "lessThanEqual", "lessThanEqual", { BV, FV, FV, N }, attrNegPos, -1, false, false, PRECMASK_ALL }, 2105e5c31af7Sopenharmony_ci { floatCompareGroup, "greaterThan", "greaterThan", { BV, FV, FV, N }, attrNegPos, -1, false, false, PRECMASK_ALL }, 2106e5c31af7Sopenharmony_ci { floatCompareGroup, "greaterThanEqual", "greaterThanEqual", { BV, FV, FV, N }, attrNegPos, -1, false, false, PRECMASK_ALL }, 2107e5c31af7Sopenharmony_ci { floatCompareGroup, "equal", "equal", { BV, FV, FV, N }, attrNegPos, -1, false, false, PRECMASK_ALL }, 2108e5c31af7Sopenharmony_ci { floatCompareGroup, "notEqual", "notEqual", { BV, FV, FV, N }, attrNegPos, -1, false, false, PRECMASK_ALL }, 2109e5c31af7Sopenharmony_ci 2110e5c31af7Sopenharmony_ci { intCompareGroup, "lessThan", "lessThan", { BV, IV, IV, N }, attrNegPos, -1, false, false, PRECMASK_ALL }, 2111e5c31af7Sopenharmony_ci { intCompareGroup, "lessThanEqual", "lessThanEqual", { BV, IV, IV, N }, attrNegPos, -1, false, false, PRECMASK_ALL }, 2112e5c31af7Sopenharmony_ci { intCompareGroup, "greaterThan", "greaterThan", { BV, IV, IV, N }, attrNegPos, -1, false, false, PRECMASK_ALL }, 2113e5c31af7Sopenharmony_ci { intCompareGroup, "greaterThanEqual", "greaterThanEqual", { BV, IV, IV, N }, attrNegPos, -1, false, false, PRECMASK_ALL }, 2114e5c31af7Sopenharmony_ci { intCompareGroup, "equal", "equal", { BV, IV, IV, N }, attrNegPos, -1, false, false, PRECMASK_ALL }, 2115e5c31af7Sopenharmony_ci { intCompareGroup, "notEqual", "notEqual", { BV, IV, IV, N }, attrNegPos, -1, false, false, PRECMASK_ALL }, 2116e5c31af7Sopenharmony_ci 2117e5c31af7Sopenharmony_ci { boolCompareGroup, "equal", "equal", { BV, BV, BV, N }, attrNegPos, -1, false, true, PRECMASK_MEDIUMP }, 2118e5c31af7Sopenharmony_ci { boolCompareGroup, "notEqual", "notEqual", { BV, BV, BV, N }, attrNegPos, -1, false, true, PRECMASK_MEDIUMP }, 2119e5c31af7Sopenharmony_ci { boolCompareGroup, "any", "any", { B, BV, N, N }, attrNegPos, -1, false, true, PRECMASK_MEDIUMP }, 2120e5c31af7Sopenharmony_ci { boolCompareGroup, "all", "all", { B, BV, N, N }, attrNegPos, -1, false, true, PRECMASK_MEDIUMP }, 2121e5c31af7Sopenharmony_ci { boolCompareGroup, "not", "not", { BV, BV, N, N }, attrNegPos, -1, false, true, PRECMASK_MEDIUMP } 2122e5c31af7Sopenharmony_ci }; 2123e5c31af7Sopenharmony_ci 2124e5c31af7Sopenharmony_ci // vertexSubGroup and fragmentSubGroup are the groups where the various vertex/fragment cases of a single function are added. 2125e5c31af7Sopenharmony_ci // \note These are defined here so that different versions (different entries in the functionCaseGroups array) of the same function can be put in the same group. 2126e5c31af7Sopenharmony_ci tcu::TestCaseGroup* vertexSubGroup = DE_NULL; 2127e5c31af7Sopenharmony_ci tcu::TestCaseGroup* fragmentSubGroup = DE_NULL; 2128e5c31af7Sopenharmony_ci FunctionCase::InitialCalibrationStorage vertexSubGroupCalibrationStorage; 2129e5c31af7Sopenharmony_ci FunctionCase::InitialCalibrationStorage fragmentSubGroupCalibrationStorage; 2130e5c31af7Sopenharmony_ci for (int funcNdx = 0; funcNdx < DE_LENGTH_OF_ARRAY(functionCaseGroups); funcNdx++) 2131e5c31af7Sopenharmony_ci { 2132e5c31af7Sopenharmony_ci tcu::TestCaseGroup* const parentGroup = functionCaseGroups[funcNdx].parentGroup; 2133e5c31af7Sopenharmony_ci const char* const groupName = functionCaseGroups[funcNdx].groupName; 2134e5c31af7Sopenharmony_ci const char* const groupFunc = functionCaseGroups[funcNdx].func; 2135e5c31af7Sopenharmony_ci const ValueType* const funcTypes = functionCaseGroups[funcNdx].types; 2136e5c31af7Sopenharmony_ci const Vec4& groupAttribute = functionCaseGroups[funcNdx].attribute; 2137e5c31af7Sopenharmony_ci const int modifyParamNdx = functionCaseGroups[funcNdx].modifyParamNdx; 2138e5c31af7Sopenharmony_ci const bool useNearlyConstantInputs = functionCaseGroups[funcNdx].useNearlyConstantInputs; 2139e5c31af7Sopenharmony_ci const bool booleanCase = functionCaseGroups[funcNdx].booleanCase; 2140e5c31af7Sopenharmony_ci const PrecisionMask precMask = functionCaseGroups[funcNdx].precMask; 2141e5c31af7Sopenharmony_ci 2142e5c31af7Sopenharmony_ci // If this is a new function and not just a different version of the previously defined function, create a new group. 2143e5c31af7Sopenharmony_ci if (funcNdx == 0 || parentGroup != functionCaseGroups[funcNdx-1].parentGroup || string(groupName) != functionCaseGroups[funcNdx-1].groupName) 2144e5c31af7Sopenharmony_ci { 2145e5c31af7Sopenharmony_ci tcu::TestCaseGroup* const funcGroup = new tcu::TestCaseGroup(m_testCtx, groupName, ""); 2146e5c31af7Sopenharmony_ci functionCaseGroups[funcNdx].parentGroup->addChild(funcGroup); 2147e5c31af7Sopenharmony_ci 2148e5c31af7Sopenharmony_ci vertexSubGroup = new tcu::TestCaseGroup(m_testCtx, "vertex", ""); 2149e5c31af7Sopenharmony_ci fragmentSubGroup = new tcu::TestCaseGroup(m_testCtx, "fragment", ""); 2150e5c31af7Sopenharmony_ci 2151e5c31af7Sopenharmony_ci funcGroup->addChild(vertexSubGroup); 2152e5c31af7Sopenharmony_ci funcGroup->addChild(fragmentSubGroup); 2153e5c31af7Sopenharmony_ci 2154e5c31af7Sopenharmony_ci vertexSubGroupCalibrationStorage = FunctionCase::InitialCalibrationStorage(new FunctionCase::InitialCalibration); 2155e5c31af7Sopenharmony_ci fragmentSubGroupCalibrationStorage = FunctionCase::InitialCalibrationStorage(new FunctionCase::InitialCalibration); 2156e5c31af7Sopenharmony_ci } 2157e5c31af7Sopenharmony_ci 2158e5c31af7Sopenharmony_ci DE_ASSERT(vertexSubGroup != DE_NULL); 2159e5c31af7Sopenharmony_ci DE_ASSERT(fragmentSubGroup != DE_NULL); 2160e5c31af7Sopenharmony_ci 2161e5c31af7Sopenharmony_ci // Find the type size range of parameters (e.g. from 2 to 4 in case of vectors). 2162e5c31af7Sopenharmony_ci int genTypeFirstSize = 1; 2163e5c31af7Sopenharmony_ci int genTypeLastSize = 1; 2164e5c31af7Sopenharmony_ci 2165e5c31af7Sopenharmony_ci // Find the first return value or parameter with a gentype (if any) and set sizes accordingly. 2166e5c31af7Sopenharmony_ci // \note Assumes only matching sizes gentypes are to be found, e.g. no "genType func (vec param)" 2167e5c31af7Sopenharmony_ci for (int i = 0; i < FunctionCase::MAX_PARAMS + 1 && genTypeLastSize == 1; i++) 2168e5c31af7Sopenharmony_ci { 2169e5c31af7Sopenharmony_ci switch (funcTypes[i]) 2170e5c31af7Sopenharmony_ci { 2171e5c31af7Sopenharmony_ci case VALUE_FLOAT_VEC: 2172e5c31af7Sopenharmony_ci case VALUE_BOOL_VEC: 2173e5c31af7Sopenharmony_ci case VALUE_INT_VEC: // \note Fall-through. 2174e5c31af7Sopenharmony_ci genTypeFirstSize = 2; 2175e5c31af7Sopenharmony_ci genTypeLastSize = 4; 2176e5c31af7Sopenharmony_ci break; 2177e5c31af7Sopenharmony_ci case VALUE_FLOAT_VEC34: 2178e5c31af7Sopenharmony_ci genTypeFirstSize = 3; 2179e5c31af7Sopenharmony_ci genTypeLastSize = 4; 2180e5c31af7Sopenharmony_ci break; 2181e5c31af7Sopenharmony_ci case VALUE_FLOAT_GENTYPE: 2182e5c31af7Sopenharmony_ci case VALUE_BOOL_GENTYPE: 2183e5c31af7Sopenharmony_ci case VALUE_INT_GENTYPE: // \note Fall-through. 2184e5c31af7Sopenharmony_ci genTypeFirstSize = 1; 2185e5c31af7Sopenharmony_ci genTypeLastSize = 4; 2186e5c31af7Sopenharmony_ci break; 2187e5c31af7Sopenharmony_ci case VALUE_MATRIX: 2188e5c31af7Sopenharmony_ci genTypeFirstSize = 2; 2189e5c31af7Sopenharmony_ci genTypeLastSize = 4; 2190e5c31af7Sopenharmony_ci break; 2191e5c31af7Sopenharmony_ci // If none of the above, keep looping. 2192e5c31af7Sopenharmony_ci default: 2193e5c31af7Sopenharmony_ci break; 2194e5c31af7Sopenharmony_ci } 2195e5c31af7Sopenharmony_ci } 2196e5c31af7Sopenharmony_ci 2197e5c31af7Sopenharmony_ci // Create a case for each possible size of the gentype. 2198e5c31af7Sopenharmony_ci for (int curSize = genTypeFirstSize; curSize <= genTypeLastSize; curSize++) 2199e5c31af7Sopenharmony_ci { 2200e5c31af7Sopenharmony_ci // Determine specific types for return value and the parameters, according to curSize. Non-gentypes not affected by curSize. 2201e5c31af7Sopenharmony_ci DataType types[FunctionCase::MAX_PARAMS + 1]; 2202e5c31af7Sopenharmony_ci for (int i = 0; i < FunctionCase::MAX_PARAMS + 1; i++) 2203e5c31af7Sopenharmony_ci { 2204e5c31af7Sopenharmony_ci if (funcTypes[i] == VALUE_NONE) 2205e5c31af7Sopenharmony_ci types[i] = TYPE_INVALID; 2206e5c31af7Sopenharmony_ci else 2207e5c31af7Sopenharmony_ci { 2208e5c31af7Sopenharmony_ci int isFloat = funcTypes[i] & VALUE_ANY_FLOAT; 2209e5c31af7Sopenharmony_ci int isBool = funcTypes[i] & VALUE_ANY_BOOL; 2210e5c31af7Sopenharmony_ci int isInt = funcTypes[i] & VALUE_ANY_INT; 2211e5c31af7Sopenharmony_ci int isMat = funcTypes[i] == VALUE_MATRIX; 2212e5c31af7Sopenharmony_ci int inSize = (funcTypes[i] & VALUE_ANY_GENTYPE) ? curSize 2213e5c31af7Sopenharmony_ci : funcTypes[i] == VALUE_VEC3 ? 3 2214e5c31af7Sopenharmony_ci : funcTypes[i] == VALUE_VEC4 ? 4 2215e5c31af7Sopenharmony_ci : 1; 2216e5c31af7Sopenharmony_ci int typeArrayNdx = isMat ? inSize - 2 : inSize - 1; // \note No matrices of size 1. 2217e5c31af7Sopenharmony_ci 2218e5c31af7Sopenharmony_ci types[i] = isFloat ? floatTypes[typeArrayNdx] 2219e5c31af7Sopenharmony_ci : isBool ? boolTypes[typeArrayNdx] 2220e5c31af7Sopenharmony_ci : isInt ? intTypes[typeArrayNdx] 2221e5c31af7Sopenharmony_ci : isMat ? matrixTypes[typeArrayNdx] 2222e5c31af7Sopenharmony_ci : TYPE_LAST; 2223e5c31af7Sopenharmony_ci } 2224e5c31af7Sopenharmony_ci 2225e5c31af7Sopenharmony_ci DE_ASSERT(types[i] != TYPE_LAST); 2226e5c31af7Sopenharmony_ci } 2227e5c31af7Sopenharmony_ci 2228e5c31af7Sopenharmony_ci // Array for just the parameter types. 2229e5c31af7Sopenharmony_ci DataType paramTypes[FunctionCase::MAX_PARAMS]; 2230e5c31af7Sopenharmony_ci for (int i = 0; i < FunctionCase::MAX_PARAMS; i++) 2231e5c31af7Sopenharmony_ci paramTypes[i] = types[i+1]; 2232e5c31af7Sopenharmony_ci 2233e5c31af7Sopenharmony_ci for (int prec = (int)PRECISION_LOWP; prec < (int)PRECISION_LAST; prec++) 2234e5c31af7Sopenharmony_ci { 2235e5c31af7Sopenharmony_ci if ((precMask & (1 << prec)) == 0) 2236e5c31af7Sopenharmony_ci continue; 2237e5c31af7Sopenharmony_ci 2238e5c31af7Sopenharmony_ci const string precisionPrefix = booleanCase ? "" : (string(getPrecisionName((Precision)prec)) + "_"); 2239e5c31af7Sopenharmony_ci std::ostringstream caseName; 2240e5c31af7Sopenharmony_ci 2241e5c31af7Sopenharmony_ci caseName << precisionPrefix; 2242e5c31af7Sopenharmony_ci 2243e5c31af7Sopenharmony_ci // Write the name of each distinct parameter data type into the test case name. 2244e5c31af7Sopenharmony_ci for (int i = 1; i < FunctionCase::MAX_PARAMS + 1 && types[i] != TYPE_INVALID; i++) 2245e5c31af7Sopenharmony_ci { 2246e5c31af7Sopenharmony_ci if (i == 1 || types[i] != types[i-1]) 2247e5c31af7Sopenharmony_ci { 2248e5c31af7Sopenharmony_ci if (i > 1) 2249e5c31af7Sopenharmony_ci caseName << "_"; 2250e5c31af7Sopenharmony_ci 2251e5c31af7Sopenharmony_ci caseName << getDataTypeName(types[i]); 2252e5c31af7Sopenharmony_ci } 2253e5c31af7Sopenharmony_ci } 2254e5c31af7Sopenharmony_ci 2255e5c31af7Sopenharmony_ci for (int fragI = 0; fragI <= 1; fragI++) 2256e5c31af7Sopenharmony_ci { 2257e5c31af7Sopenharmony_ci const bool vert = fragI == 0; 2258e5c31af7Sopenharmony_ci tcu::TestCaseGroup* const group = vert ? vertexSubGroup : fragmentSubGroup; 2259e5c31af7Sopenharmony_ci group->addChild (new FunctionCase(m_context, 2260e5c31af7Sopenharmony_ci caseName.str().c_str(), "", 2261e5c31af7Sopenharmony_ci groupFunc, 2262e5c31af7Sopenharmony_ci types[0], paramTypes, 2263e5c31af7Sopenharmony_ci groupAttribute, modifyParamNdx, useNearlyConstantInputs, 2264e5c31af7Sopenharmony_ci (Precision)prec, vert, 2265e5c31af7Sopenharmony_ci vert ? vertexSubGroupCalibrationStorage : fragmentSubGroupCalibrationStorage)); 2266e5c31af7Sopenharmony_ci } 2267e5c31af7Sopenharmony_ci } 2268e5c31af7Sopenharmony_ci } 2269e5c31af7Sopenharmony_ci } 2270e5c31af7Sopenharmony_ci} 2271e5c31af7Sopenharmony_ci 2272e5c31af7Sopenharmony_ci} // Performance 2273e5c31af7Sopenharmony_ci} // gles2 2274e5c31af7Sopenharmony_ci} // deqp 2275