Merge "Allow alternative form for refract()." into nyc-dev am: f492a25
[platform/upstream/VK-GL-CTS.git] / modules / glshared / glsShaderPerformanceMeasurer.cpp
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL (ES) Module
3  * -----------------------------------------------
4  *
5  * Copyright 2014 The Android Open Source Project
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Shader performance measurer; handles calibration and measurement
22  *//*--------------------------------------------------------------------*/
23
24 #include "glsShaderPerformanceMeasurer.hpp"
25 #include "gluDefs.hpp"
26 #include "tcuTestLog.hpp"
27 #include "tcuRenderTarget.hpp"
28 #include "deStringUtil.hpp"
29 #include "deMath.h"
30 #include "deClock.h"
31
32 #include "glwFunctions.hpp"
33 #include "glwEnums.hpp"
34
35 #include <algorithm>
36
37 using tcu::Vec4;
38 using std::string;
39 using std::vector;
40 using tcu::TestLog;
41 using namespace glw; // GL types
42
43 namespace deqp
44 {
45 namespace gls
46 {
47
48 static inline float triangleInterpolate (float v0, float v1, float v2, float x, float y)
49 {
50         return v0 + (v2-v0)*x + (v1-v0)*y;
51 }
52
53 static inline float triQuadInterpolate (float x, float y, const tcu::Vec4& quad)
54 {
55         // \note Top left fill rule.
56         if (x + y < 1.0f)
57                 return triangleInterpolate(quad.x(), quad.y(), quad.z(), x, y);
58         else
59                 return triangleInterpolate(quad.w(), quad.z(), quad.y(), 1.0f-x, 1.0f-y);
60 }
61
62 static inline int getNumVertices (int gridSizeX, int gridSizeY)
63 {
64         return (gridSizeX + 1) * (gridSizeY + 1);
65 }
66
67 static inline int getNumIndices (int gridSizeX, int gridSizeY)
68 {
69         return gridSizeX*gridSizeY*6;
70 }
71
72 static inline deUint16 getVtxIndex (int x, int y, int gridSizeX)
73 {
74         return (deUint16)(y*(gridSizeX+1) + x);
75 }
76
77 static void generateVertices (std::vector<float>& dst, int gridSizeX, int gridSizeY, const AttribSpec& spec)
78 {
79         const int numComponents = 4;
80
81         DE_ASSERT((gridSizeX + 1)*(gridSizeY + 1) <= (1<<16)); // Must fit into 16-bit indices.
82         DE_ASSERT(gridSizeX >= 1 && gridSizeY >= 1);
83         dst.resize((gridSizeX + 1) * (gridSizeY + 1) * 4);
84
85         for (int y = 0; y <= gridSizeY; y++)
86         {
87                 for (int x = 0; x <= gridSizeX; x++)
88                 {
89                         float   xf      = (float)x / (float)gridSizeX;
90                         float   yf      = (float)y / (float)gridSizeY;
91
92                         for (int compNdx = 0; compNdx < numComponents; compNdx++)
93                                 dst[getVtxIndex(x, y, gridSizeX)*numComponents + compNdx] = triQuadInterpolate(xf, yf, tcu::Vec4(spec.p00[compNdx], spec.p01[compNdx], spec.p10[compNdx], spec.p11[compNdx]));
94                 }
95         }
96 }
97
98 static void generateIndices (std::vector<deUint16>& dst, int gridSizeX, int gridSizeY)
99 {
100         const int       numIndicesPerQuad       = 6;
101         int                     numIndices                      = gridSizeX * gridSizeY * numIndicesPerQuad;
102         dst.resize(numIndices);
103
104         for (int y = 0; y < gridSizeY; y++)
105         {
106                 for (int x = 0; x < gridSizeX; x++)
107                 {
108                         int quadNdx = y*gridSizeX + x;
109
110                         dst[quadNdx*numIndicesPerQuad + 0] = getVtxIndex(x+0, y+0, gridSizeX);
111                         dst[quadNdx*numIndicesPerQuad + 1] = getVtxIndex(x+1, y+0, gridSizeX);
112                         dst[quadNdx*numIndicesPerQuad + 2] = getVtxIndex(x+0, y+1, gridSizeX);
113
114                         dst[quadNdx*numIndicesPerQuad + 3] = getVtxIndex(x+0, y+1, gridSizeX);
115                         dst[quadNdx*numIndicesPerQuad + 4] = getVtxIndex(x+1, y+0, gridSizeX);
116                         dst[quadNdx*numIndicesPerQuad + 5] = getVtxIndex(x+1, y+1, gridSizeX);
117                 }
118         }
119 }
120
121 ShaderPerformanceMeasurer::ShaderPerformanceMeasurer (const glu::RenderContext& renderCtx, PerfCaseType measureType)
122         : m_renderCtx           (renderCtx)
123         , m_gridSizeX           (measureType == CASETYPE_FRAGMENT       ? 1             : 255)
124         , m_gridSizeY           (measureType == CASETYPE_FRAGMENT       ? 1             : 255)
125         , m_viewportWidth       (measureType == CASETYPE_VERTEX         ? 32    : renderCtx.getRenderTarget().getWidth())
126         , m_viewportHeight      (measureType == CASETYPE_VERTEX         ? 32    : renderCtx.getRenderTarget().getHeight())
127         , m_state                       (STATE_UNINITIALIZED)
128         , m_result                      (-1.0f, -1.0f)
129         , m_indexBuffer         (0)
130         , m_vao                         (0)
131 {
132 }
133
134 void ShaderPerformanceMeasurer::logParameters (TestLog& log) const
135 {
136         log << TestLog::Message << "Grid size: " << m_gridSizeX << "x" << m_gridSizeY << TestLog::EndMessage
137                 << TestLog::Message << "Viewport: " << m_viewportWidth << "x" << m_viewportHeight << TestLog::EndMessage;
138 }
139
140 void ShaderPerformanceMeasurer::init (deUint32 program, const vector<AttribSpec>& attributes, int calibratorInitialNumCalls)
141 {
142         DE_ASSERT(m_state == STATE_UNINITIALIZED);
143
144         const glw::Functions&   gl              = m_renderCtx.getFunctions();
145         const bool                              useVAO  = glu::isContextTypeGLCore(m_renderCtx.getType());
146
147         if (useVAO)
148         {
149                 DE_ASSERT(!m_vao);
150                 gl.genVertexArrays(1, &m_vao);
151                 gl.bindVertexArray(m_vao);
152                 GLU_EXPECT_NO_ERROR(gl.getError(), "Create VAO");
153         }
154
155         // Validate that we have sane grid and viewport setup.
156
157         DE_ASSERT(de::inBounds(m_gridSizeX, 1, 256) && de::inBounds(m_gridSizeY, 1, 256));
158
159         {
160                 bool widthTooSmall              = m_renderCtx.getRenderTarget().getWidth() < m_viewportWidth;
161                 bool heightTooSmall             = m_renderCtx.getRenderTarget().getHeight() < m_viewportHeight;
162
163                 if (widthTooSmall || heightTooSmall)
164                         throw tcu::NotSupportedError("Render target too small (" +
165                                                                                          (widthTooSmall  ?                                                                         "width must be at least "  + de::toString(m_viewportWidth)  : "") +
166                                                                                          (heightTooSmall ? string(widthTooSmall ? ", " : "") + "height must be at least " + de::toString(m_viewportHeight) : "") +
167                                                                                          ")");
168         }
169
170         TCU_CHECK_INTERNAL(de::inRange(m_viewportWidth,         1, m_renderCtx.getRenderTarget().getWidth()) &&
171                                            de::inRange(m_viewportHeight,        1, m_renderCtx.getRenderTarget().getHeight()));
172
173         // Insert a_position to attributes.
174         m_attributes = attributes;
175         m_attributes.push_back(AttribSpec("a_position",
176                                                                           Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
177                                                                           Vec4( 1.0f, -1.0f, 0.0f, 1.0f),
178                                                                           Vec4(-1.0f,  1.0f, 0.0f, 1.0f),
179                                                                           Vec4( 1.0f,  1.0f, 0.0f, 1.0f)));
180
181         // Generate indices.
182         {
183                 std::vector<deUint16> indices;
184                 generateIndices(indices, m_gridSizeX, m_gridSizeY);
185
186                 gl.genBuffers(1, &m_indexBuffer);
187                 gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_indexBuffer);
188                 gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, (GLsizeiptr)(indices.size()*sizeof(deUint16)), &indices[0], GL_STATIC_DRAW);
189
190                 GLU_EXPECT_NO_ERROR(gl.getError(), "Upload index data");
191         }
192
193         // Generate vertices.
194         m_attribBuffers.resize(m_attributes.size(), 0);
195         gl.genBuffers((GLsizei)m_attribBuffers.size(), &m_attribBuffers[0]);
196
197         for (int attribNdx = 0; attribNdx < (int)m_attributes.size(); attribNdx++)
198         {
199                 std::vector<float> vertices;
200                 generateVertices(vertices, m_gridSizeX, m_gridSizeY, m_attributes[attribNdx]);
201
202                 gl.bindBuffer(GL_ARRAY_BUFFER, m_attribBuffers[attribNdx]);
203                 gl.bufferData(GL_ARRAY_BUFFER, (GLsizeiptr)(vertices.size()*sizeof(float)), &vertices[0], GL_STATIC_DRAW);
204         }
205
206         GLU_EXPECT_NO_ERROR(gl.getError(), "Upload vertex data");
207
208         // Setup attribute bindings.
209         for (int attribNdx = 0; attribNdx < (int)m_attributes.size(); attribNdx++)
210         {
211                 int location = gl.getAttribLocation(program, m_attributes[attribNdx].name.c_str());
212
213                 if (location >= 0)
214                 {
215                         gl.enableVertexAttribArray(location);
216                         gl.bindBuffer(GL_ARRAY_BUFFER, m_attribBuffers[attribNdx]);
217                         gl.vertexAttribPointer(location, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
218                 }
219
220                 GLU_EXPECT_NO_ERROR(gl.getError(), "Setup vertex attribute state");
221         }
222
223         gl.useProgram(program);
224         GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram()");
225
226         m_state = STATE_MEASURING;
227         m_isFirstIteration = true;
228
229         m_calibrator.clear(CalibratorParameters(calibratorInitialNumCalls, 10 /* calibrate iteration frames */, 2000.0f /* calibrate iteration shortcut threshold (ms) */, 16 /* max calibrate iterations */,
230                                                                                         1000.0f/30.0f /* frame time (ms) */, 1000.0f/60.0f /* frame time cap (ms) */, 1000.0f /* target measure duration (ms) */));
231 }
232
233 void ShaderPerformanceMeasurer::deinit (void)
234 {
235         const glw::Functions& gl = m_renderCtx.getFunctions();
236
237         if (m_indexBuffer)
238         {
239                 gl.deleteBuffers(1, &m_indexBuffer);
240                 m_indexBuffer = 0;
241         }
242
243         if (m_vao)
244         {
245                 gl.deleteVertexArrays(1, &m_vao);
246                 m_vao = 0;
247         }
248
249         if (!m_attribBuffers.empty())
250         {
251                 gl.deleteBuffers((GLsizei)m_attribBuffers.size(), &m_attribBuffers[0]);
252                 m_attribBuffers.clear();
253         }
254
255         m_state = STATE_UNINITIALIZED;
256 }
257
258 void ShaderPerformanceMeasurer::render (int numDrawCalls)
259 {
260         const glw::Functions&   gl                      = m_renderCtx.getFunctions();
261         GLsizei                                 numIndices      = (GLsizei)getNumIndices(m_gridSizeX, m_gridSizeY);
262
263         gl.viewport(0, 0, m_viewportWidth, m_viewportHeight);
264
265         for (int callNdx = 0; callNdx < numDrawCalls; callNdx++)
266                 gl.drawElements(GL_TRIANGLES, numIndices, GL_UNSIGNED_SHORT, DE_NULL);
267 }
268
269 void ShaderPerformanceMeasurer::iterate (void)
270 {
271         DE_ASSERT(m_state == STATE_MEASURING);
272
273         deUint64 renderStartTime = deGetMicroseconds();
274         render(m_calibrator.getCallCount()); // Always render. This gives more stable performance behavior.
275
276         TheilSenCalibrator::State calibratorState = m_calibrator.getState();
277
278         if (calibratorState == TheilSenCalibrator::STATE_RECOMPUTE_PARAMS)
279         {
280                 m_calibrator.recomputeParameters();
281
282                 m_isFirstIteration = true;
283                 m_prevRenderStartTime = renderStartTime;
284         }
285         else if (calibratorState == TheilSenCalibrator::STATE_MEASURE)
286         {
287                 if (!m_isFirstIteration)
288                         m_calibrator.recordIteration(renderStartTime - m_prevRenderStartTime);
289
290                 m_isFirstIteration = false;
291                 m_prevRenderStartTime = renderStartTime;
292         }
293         else
294         {
295                 DE_ASSERT(calibratorState == TheilSenCalibrator::STATE_FINISHED);
296
297                 GLU_EXPECT_NO_ERROR(m_renderCtx.getFunctions().getError(), "End of rendering");
298
299                 const MeasureState& measureState = m_calibrator.getMeasureState();
300
301                 // Compute result.
302                 deUint64        totalTime                       = measureState.getTotalTime();
303                 int                     numFrames                       = (int)measureState.frameTimes.size();
304                 deInt64         numQuadGrids            = measureState.numDrawCalls * numFrames;
305                 deInt64         numPixels                       = (deInt64)m_viewportWidth * (deInt64)m_viewportHeight * numQuadGrids;
306                 deInt64         numVertices                     = (deInt64)getNumVertices(m_gridSizeX, m_gridSizeY) * numQuadGrids;
307                 double          mfragPerSecond          = (double)numPixels / (double)totalTime;
308                 double          mvertPerSecond          = (double)numVertices / (double)totalTime;
309
310                 m_result = Result((float)mvertPerSecond, (float)mfragPerSecond);
311                 m_state = STATE_FINISHED;
312         }
313 }
314
315 void ShaderPerformanceMeasurer::logMeasurementInfo (TestLog& log) const
316 {
317         DE_ASSERT(m_state == STATE_FINISHED);
318
319         const MeasureState& measureState(m_calibrator.getMeasureState());
320
321         // Compute totals.
322         deUint64        totalTime                       = measureState.getTotalTime();
323         int                     numFrames                       = (int)measureState.frameTimes.size();
324         deInt64         numQuadGrids            = measureState.numDrawCalls * numFrames;
325         deInt64         numPixels                       = (deInt64)m_viewportWidth * (deInt64)m_viewportHeight * numQuadGrids;
326         deInt64         numVertices                     = (deInt64)getNumVertices(m_gridSizeX, m_gridSizeY) * numQuadGrids;
327         double          mfragPerSecond          = (double)numPixels / (double)totalTime;
328         double          mvertPerSecond          = (double)numVertices / (double)totalTime;
329         double          framesPerSecond         = (double)numFrames / ((double)totalTime / 1000000.0);
330
331         logCalibrationInfo(log, m_calibrator);
332
333         log << TestLog::Float("FramesPerSecond",                "Frames per second in measurement",     "Frames/s",                             QP_KEY_TAG_PERFORMANCE, (float)framesPerSecond)
334                 << TestLog::Float("FragmentsPerVertices",       "Vertex-fragment ratio",                        "Fragments/Vertices",   QP_KEY_TAG_NONE,                (float)numPixels / (float)numVertices)
335                 << TestLog::Float("FragmentPerf",                       "Fragment performance",                         "MPix/s",                               QP_KEY_TAG_PERFORMANCE, (float)mfragPerSecond)
336                 << TestLog::Float("VertexPerf",                         "Vertex performance",                           "MVert/s",                              QP_KEY_TAG_PERFORMANCE, (float)mvertPerSecond);
337 }
338
339 void ShaderPerformanceMeasurer::setGridSize (int gridW, int gridH)
340 {
341         DE_ASSERT(m_state == STATE_UNINITIALIZED);
342         DE_ASSERT(de::inBounds(gridW, 1, 256) && de::inBounds(gridH, 1, 256));
343         m_gridSizeX             = gridW;
344         m_gridSizeY             = gridH;
345 }
346
347 void ShaderPerformanceMeasurer::setViewportSize (int width, int height)
348 {
349         DE_ASSERT(m_state == STATE_UNINITIALIZED);
350         DE_ASSERT(de::inRange(width,    1, m_renderCtx.getRenderTarget().getWidth()) &&
351                           de::inRange(height,   1, m_renderCtx.getRenderTarget().getHeight()));
352         m_viewportWidth         = width;
353         m_viewportHeight        = height;
354 }
355
356 } // gls
357 } // deqp