• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2020 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // TracePerf:
7 //   Performance test for ANGLE replaying traces.
8 //
9 
10 #include <gtest/gtest.h>
11 #include "common/PackedEnums.h"
12 #include "common/string_utils.h"
13 #include "common/system_utils.h"
14 #include "tests/perf_tests/ANGLEPerfTest.h"
15 #include "tests/perf_tests/ANGLEPerfTestArgs.h"
16 #include "tests/perf_tests/DrawCallPerfParams.h"
17 #include "util/capture/frame_capture_test_utils.h"
18 #include "util/capture/traces_export.h"
19 #include "util/egl_loader_autogen.h"
20 #include "util/png_utils.h"
21 #include "util/test_utils.h"
22 
23 #include <rapidjson/document.h>
24 #include <rapidjson/istreamwrapper.h>
25 
26 #include <cassert>
27 #include <fstream>
28 #include <functional>
29 #include <sstream>
30 
31 // When --minimize-gpu-work is specified, we want to reduce GPU work to minimum and lift up the CPU
32 // overhead to surface so that we can see how much CPU overhead each driver has for each app trace.
33 // On some driver(s) the bufferSubData/texSubImage calls end up dominating the frame time when the
34 // actual GPU work is minimized. Even reducing the texSubImage calls to only update 1x1 area is not
35 // enough. The driver may be implementing copy on write by cloning the entire texture to another
36 // memory storage for texSubImage call. While this information is also important for performance,
37 // they should be evaluated separately in real app usage scenario, or write stand alone tests for
38 // these. For the purpose of CPU overhead and avoid data copy to dominate the trace, I am using this
39 // flag to noop the texSubImage and bufferSubData call when --minimize-gpu-work is specified. Feel
40 // free to disable this when you have other needs. Or it can be turned to another run time option
41 // when desired.
42 #define NOOP_SUBDATA_SUBIMAGE_FOR_MINIMIZE_GPU_WORK
43 
44 using namespace angle;
45 using namespace egl_platform;
46 
47 namespace
48 {
49 constexpr size_t kMaxPath = 1024;
50 
51 struct TracePerfParams final : public RenderTestParams
52 {
53     // Common default options
TracePerfParams__anon04987c800111::TracePerfParams54     TracePerfParams(const TraceInfo &traceInfoIn,
55                     GLESDriverType driverType,
56                     EGLenum platformType,
57                     EGLenum deviceType)
58         : traceInfo(traceInfoIn)
59     {
60         majorVersion = traceInfo.contextClientMajorVersion;
61         minorVersion = traceInfo.contextClientMinorVersion;
62         windowWidth  = traceInfo.drawSurfaceWidth;
63         windowHeight = traceInfo.drawSurfaceHeight;
64         colorSpace   = traceInfo.drawSurfaceColorSpace;
65 
66         // Display the frame after every drawBenchmark invocation
67         iterationsPerStep = 1;
68 
69         driver                   = driverType;
70         eglParameters.renderer   = platformType;
71         eglParameters.deviceType = deviceType;
72 
73         ASSERT(!gOffscreen || !gVsync);
74 
75         if (gOffscreen)
76         {
77             surfaceType = SurfaceType::Offscreen;
78 
79             if (!IsAndroid())
80             {
81                 windowWidth /= 4;
82                 windowHeight /= 4;
83             }
84         }
85         if (gVsync)
86         {
87             surfaceType = SurfaceType::WindowWithVSync;
88         }
89 
90         // Force on features if we're validating serialization.
91         if (gTraceTestValidation)
92         {
93             // Enable limits when validating traces because we usually turn off capture.
94             eglParameters.enable(Feature::EnableCaptureLimits);
95 
96             // This feature should also be enabled in capture to mirror the replay.
97             eglParameters.enable(Feature::ForceInitShaderVariables);
98         }
99     }
100 
story__anon04987c800111::TracePerfParams101     std::string story() const override
102     {
103         std::stringstream strstr;
104         strstr << RenderTestParams::story() << "_" << traceInfo.name;
105         return strstr.str();
106     }
107 
108     TraceInfo traceInfo = {};
109 };
110 
111 class TracePerfTest : public ANGLERenderTest
112 {
113   public:
114     TracePerfTest(std::unique_ptr<const TracePerfParams> params);
115 
116     void startTest() override;
117     void initializeBenchmark() override;
118     void destroyBenchmark() override;
119     void drawBenchmark() override;
120 
121     // TODO(http://www.anglebug.com/5878): Add support for creating EGLSurface:
122     // - eglCreatePbufferSurface()
123     // - eglCreateWindowSurface()
124     EGLContext onEglCreateContext(EGLDisplay display,
125                                   EGLConfig config,
126                                   EGLContext share_context,
127                                   EGLint const *attrib_list);
128     void onEglMakeCurrent(EGLDisplay display, EGLSurface draw, EGLSurface read, EGLContext context);
129     EGLContext onEglGetCurrentContext();
130     EGLImage onEglCreateImage(EGLDisplay display,
131                               EGLContext context,
132                               EGLenum target,
133                               EGLClientBuffer buffer,
134                               const EGLAttrib *attrib_list);
135     EGLImageKHR onEglCreateImageKHR(EGLDisplay display,
136                                     EGLContext context,
137                                     EGLenum target,
138                                     EGLClientBuffer buffer,
139                                     const EGLint *attrib_list);
140     EGLBoolean onEglDestroyImage(EGLDisplay display, EGLImage image);
141     EGLBoolean onEglDestroyImageKHR(EGLDisplay display, EGLImage image);
142     EGLSync onEglCreateSync(EGLDisplay dpy, EGLenum type, const EGLAttrib *attrib_list);
143     EGLSync onEglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list);
144     EGLBoolean onEglDestroySync(EGLDisplay dpy, EGLSync sync);
145     EGLBoolean onEglDestroySyncKHR(EGLDisplay dpy, EGLSync sync);
146     EGLint onEglClientWaitSync(EGLDisplay dpy, EGLSync sync, EGLint flags, EGLTimeKHR timeout);
147     EGLint onEglClientWaitSyncKHR(EGLDisplay dpy, EGLSync sync, EGLint flags, EGLTimeKHR timeout);
148     EGLint onEglGetError();
149     EGLDisplay onEglGetCurrentDisplay();
150 
151     void onReplayFramebufferChange(GLenum target, GLuint framebuffer);
152     void onReplayInvalidateFramebuffer(GLenum target,
153                                        GLsizei numAttachments,
154                                        const GLenum *attachments);
155     void onReplayInvalidateSubFramebuffer(GLenum target,
156                                           GLsizei numAttachments,
157                                           const GLenum *attachments,
158                                           GLint x,
159                                           GLint y,
160                                           GLsizei width,
161                                           GLsizei height);
162     void onReplayDrawBuffers(GLsizei n, const GLenum *bufs);
163     void onReplayReadBuffer(GLenum src);
164     void onReplayDiscardFramebufferEXT(GLenum target,
165                                        GLsizei numAttachments,
166                                        const GLenum *attachments);
167 
168     void validateSerializedState(const char *serializedState, const char *fileName, uint32_t line);
169 
170     bool isDefaultFramebuffer(GLenum target) const;
171 
172     double getHostTimeFromGLTime(GLint64 glTime);
173 
frameCount() const174     uint32_t frameCount() const
175     {
176         const TraceInfo &traceInfo = mParams->traceInfo;
177         return traceInfo.frameEnd - traceInfo.frameStart + 1;
178     }
179 
getStepAlignment() const180     int getStepAlignment() const override
181     {
182         // Align step counts to the number of frames in a trace.
183         return static_cast<int>(frameCount());
184     }
185 
TestBody()186     void TestBody() override { run(); }
187 
traceNameIs(const char * name) const188     bool traceNameIs(const char *name) const
189     {
190         return strncmp(name, mParams->traceInfo.name, kTraceInfoMaxNameLen) == 0;
191     }
192 
193   private:
194     struct QueryInfo
195     {
196         GLuint beginTimestampQuery;
197         GLuint endTimestampQuery;
198         GLuint framebuffer;
199     };
200 
201     struct TimeSample
202     {
203         GLint64 glTime;
204         double hostTime;
205     };
206 
207     void sampleTime();
208     void saveScreenshot(const std::string &screenshotName) override;
209     void swap();
210 
211     std::unique_ptr<const TracePerfParams> mParams;
212 
213     uint32_t mStartFrame;
214     uint32_t mEndFrame;
215 
216     // For tracking RenderPass/FBO change timing.
217     QueryInfo mCurrentQuery = {};
218     std::vector<QueryInfo> mRunningQueries;
219     std::vector<TimeSample> mTimeline;
220 
221     bool mUseTimestampQueries                                           = false;
222     static constexpr int mMaxOffscreenBufferCount                       = 2;
223     std::array<GLuint, mMaxOffscreenBufferCount> mOffscreenFramebuffers = {0, 0};
224     std::array<GLuint, mMaxOffscreenBufferCount> mOffscreenTextures     = {0, 0};
225     GLuint mOffscreenDepthStencil                                       = 0;
226     int mWindowWidth                                                    = 0;
227     int mWindowHeight                                                   = 0;
228     GLuint mDrawFramebufferBinding                                      = 0;
229     GLuint mReadFramebufferBinding                                      = 0;
230     uint32_t mCurrentFrame                                              = 0;
231     uint32_t mCurrentIteration                                          = 0;
232     uint32_t mOffscreenFrameCount                                       = 0;
233     uint32_t mTotalFrameCount                                           = 0;
234     bool mScreenshotSaved                                               = false;
235     uint32_t mScreenshotFrame                                           = gScreenshotFrame;
236     std::unique_ptr<TraceLibrary> mTraceReplay;
237 };
238 
239 TracePerfTest *gCurrentTracePerfTest = nullptr;
240 
241 // Don't forget to include KHRONOS_APIENTRY in override methods. Necessary on Win/x86.
EglCreateContext(EGLDisplay display,EGLConfig config,EGLContext share_context,EGLint const * attrib_list)242 EGLContext KHRONOS_APIENTRY EglCreateContext(EGLDisplay display,
243                                              EGLConfig config,
244                                              EGLContext share_context,
245                                              EGLint const *attrib_list)
246 {
247     return gCurrentTracePerfTest->onEglCreateContext(display, config, share_context, attrib_list);
248 }
249 
EglMakeCurrent(EGLDisplay display,EGLSurface draw,EGLSurface read,EGLContext context)250 void KHRONOS_APIENTRY EglMakeCurrent(EGLDisplay display,
251                                      EGLSurface draw,
252                                      EGLSurface read,
253                                      EGLContext context)
254 {
255     gCurrentTracePerfTest->onEglMakeCurrent(display, draw, read, context);
256 }
257 
EglGetCurrentContext()258 EGLContext KHRONOS_APIENTRY EglGetCurrentContext()
259 {
260     return gCurrentTracePerfTest->onEglGetCurrentContext();
261 }
262 
EglCreateImage(EGLDisplay display,EGLContext context,EGLenum target,EGLClientBuffer buffer,const EGLAttrib * attrib_list)263 EGLImage KHRONOS_APIENTRY EglCreateImage(EGLDisplay display,
264                                          EGLContext context,
265                                          EGLenum target,
266                                          EGLClientBuffer buffer,
267                                          const EGLAttrib *attrib_list)
268 {
269     return gCurrentTracePerfTest->onEglCreateImage(display, context, target, buffer, attrib_list);
270 }
271 
EglCreateImageKHR(EGLDisplay display,EGLContext context,EGLenum target,EGLClientBuffer buffer,const EGLint * attrib_list)272 EGLImageKHR KHRONOS_APIENTRY EglCreateImageKHR(EGLDisplay display,
273                                                EGLContext context,
274                                                EGLenum target,
275                                                EGLClientBuffer buffer,
276                                                const EGLint *attrib_list)
277 {
278     return gCurrentTracePerfTest->onEglCreateImageKHR(display, context, target, buffer,
279                                                       attrib_list);
280 }
281 
EglDestroyImage(EGLDisplay display,EGLImage image)282 EGLBoolean KHRONOS_APIENTRY EglDestroyImage(EGLDisplay display, EGLImage image)
283 {
284     return gCurrentTracePerfTest->onEglDestroyImage(display, image);
285 }
286 
EglDestroyImageKHR(EGLDisplay display,EGLImage image)287 EGLBoolean KHRONOS_APIENTRY EglDestroyImageKHR(EGLDisplay display, EGLImage image)
288 {
289     return gCurrentTracePerfTest->onEglDestroyImageKHR(display, image);
290 }
291 
EglCreateSync(EGLDisplay dpy,EGLenum type,const EGLAttrib * attrib_list)292 EGLSync KHRONOS_APIENTRY EglCreateSync(EGLDisplay dpy, EGLenum type, const EGLAttrib *attrib_list)
293 {
294     return gCurrentTracePerfTest->onEglCreateSync(dpy, type, attrib_list);
295 }
296 
EglCreateSyncKHR(EGLDisplay dpy,EGLenum type,const EGLint * attrib_list)297 EGLSync KHRONOS_APIENTRY EglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list)
298 {
299     return gCurrentTracePerfTest->onEglCreateSyncKHR(dpy, type, attrib_list);
300 }
301 
EglDestroySync(EGLDisplay dpy,EGLSync sync)302 EGLBoolean KHRONOS_APIENTRY EglDestroySync(EGLDisplay dpy, EGLSync sync)
303 {
304     return gCurrentTracePerfTest->onEglDestroySync(dpy, sync);
305 }
306 
EglDestroySyncKHR(EGLDisplay dpy,EGLSync sync)307 EGLBoolean KHRONOS_APIENTRY EglDestroySyncKHR(EGLDisplay dpy, EGLSync sync)
308 {
309     return gCurrentTracePerfTest->onEglDestroySyncKHR(dpy, sync);
310 }
311 
EglClientWaitSync(EGLDisplay dpy,EGLSync sync,EGLint flags,EGLTimeKHR timeout)312 EGLint KHRONOS_APIENTRY EglClientWaitSync(EGLDisplay dpy,
313                                           EGLSync sync,
314                                           EGLint flags,
315                                           EGLTimeKHR timeout)
316 {
317     return gCurrentTracePerfTest->onEglClientWaitSync(dpy, sync, flags, timeout);
318 }
EglClientWaitSyncKHR(EGLDisplay dpy,EGLSync sync,EGLint flags,EGLTimeKHR timeout)319 EGLint KHRONOS_APIENTRY EglClientWaitSyncKHR(EGLDisplay dpy,
320                                              EGLSync sync,
321                                              EGLint flags,
322                                              EGLTimeKHR timeout)
323 {
324     return gCurrentTracePerfTest->onEglClientWaitSyncKHR(dpy, sync, flags, timeout);
325 }
326 
EglGetError()327 EGLint KHRONOS_APIENTRY EglGetError()
328 {
329     return gCurrentTracePerfTest->onEglGetError();
330 }
331 
EglGetCurrentDisplay()332 EGLDisplay KHRONOS_APIENTRY EglGetCurrentDisplay()
333 {
334     return gCurrentTracePerfTest->onEglGetCurrentDisplay();
335 }
336 
BindFramebufferProc(GLenum target,GLuint framebuffer)337 void KHRONOS_APIENTRY BindFramebufferProc(GLenum target, GLuint framebuffer)
338 {
339     gCurrentTracePerfTest->onReplayFramebufferChange(target, framebuffer);
340 }
341 
InvalidateFramebufferProc(GLenum target,GLsizei numAttachments,const GLenum * attachments)342 void KHRONOS_APIENTRY InvalidateFramebufferProc(GLenum target,
343                                                 GLsizei numAttachments,
344                                                 const GLenum *attachments)
345 {
346     gCurrentTracePerfTest->onReplayInvalidateFramebuffer(target, numAttachments, attachments);
347 }
348 
InvalidateSubFramebufferProc(GLenum target,GLsizei numAttachments,const GLenum * attachments,GLint x,GLint y,GLsizei width,GLsizei height)349 void KHRONOS_APIENTRY InvalidateSubFramebufferProc(GLenum target,
350                                                    GLsizei numAttachments,
351                                                    const GLenum *attachments,
352                                                    GLint x,
353                                                    GLint y,
354                                                    GLsizei width,
355                                                    GLsizei height)
356 {
357     gCurrentTracePerfTest->onReplayInvalidateSubFramebuffer(target, numAttachments, attachments, x,
358                                                             y, width, height);
359 }
360 
DrawBuffersProc(GLsizei n,const GLenum * bufs)361 void KHRONOS_APIENTRY DrawBuffersProc(GLsizei n, const GLenum *bufs)
362 {
363     gCurrentTracePerfTest->onReplayDrawBuffers(n, bufs);
364 }
365 
ReadBufferProc(GLenum src)366 void KHRONOS_APIENTRY ReadBufferProc(GLenum src)
367 {
368     gCurrentTracePerfTest->onReplayReadBuffer(src);
369 }
370 
DiscardFramebufferEXTProc(GLenum target,GLsizei numAttachments,const GLenum * attachments)371 void KHRONOS_APIENTRY DiscardFramebufferEXTProc(GLenum target,
372                                                 GLsizei numAttachments,
373                                                 const GLenum *attachments)
374 {
375     gCurrentTracePerfTest->onReplayDiscardFramebufferEXT(target, numAttachments, attachments);
376 }
377 
ViewportMinimizedProc(GLint x,GLint y,GLsizei width,GLsizei height)378 void KHRONOS_APIENTRY ViewportMinimizedProc(GLint x, GLint y, GLsizei width, GLsizei height)
379 {
380     glViewport(x, y, 1, 1);
381 }
382 
ScissorMinimizedProc(GLint x,GLint y,GLsizei width,GLsizei height)383 void KHRONOS_APIENTRY ScissorMinimizedProc(GLint x, GLint y, GLsizei width, GLsizei height)
384 {
385     glScissor(x, y, 1, 1);
386 }
387 
388 // Interpose the calls that generate actual GPU work
DrawElementsMinimizedProc(GLenum mode,GLsizei count,GLenum type,const void * indices)389 void KHRONOS_APIENTRY DrawElementsMinimizedProc(GLenum mode,
390                                                 GLsizei count,
391                                                 GLenum type,
392                                                 const void *indices)
393 {
394     glDrawElements(GL_POINTS, 1, type, indices);
395 }
396 
DrawElementsIndirectMinimizedProc(GLenum mode,GLenum type,const void * indirect)397 void KHRONOS_APIENTRY DrawElementsIndirectMinimizedProc(GLenum mode,
398                                                         GLenum type,
399                                                         const void *indirect)
400 {
401     glDrawElementsInstancedBaseVertex(GL_POINTS, 1, type, 0, 1, 0);
402 }
403 
DrawElementsInstancedMinimizedProc(GLenum mode,GLsizei count,GLenum type,const void * indices,GLsizei instancecount)404 void KHRONOS_APIENTRY DrawElementsInstancedMinimizedProc(GLenum mode,
405                                                          GLsizei count,
406                                                          GLenum type,
407                                                          const void *indices,
408                                                          GLsizei instancecount)
409 {
410     glDrawElementsInstanced(GL_POINTS, 1, type, indices, 1);
411 }
412 
DrawElementsBaseVertexMinimizedProc(GLenum mode,GLsizei count,GLenum type,const void * indices,GLint basevertex)413 void KHRONOS_APIENTRY DrawElementsBaseVertexMinimizedProc(GLenum mode,
414                                                           GLsizei count,
415                                                           GLenum type,
416                                                           const void *indices,
417                                                           GLint basevertex)
418 {
419     glDrawElementsBaseVertex(GL_POINTS, 1, type, indices, basevertex);
420 }
421 
DrawElementsInstancedBaseVertexMinimizedProc(GLenum mode,GLsizei count,GLenum type,const void * indices,GLsizei instancecount,GLint basevertex)422 void KHRONOS_APIENTRY DrawElementsInstancedBaseVertexMinimizedProc(GLenum mode,
423                                                                    GLsizei count,
424                                                                    GLenum type,
425                                                                    const void *indices,
426                                                                    GLsizei instancecount,
427                                                                    GLint basevertex)
428 {
429     glDrawElementsInstancedBaseVertex(GL_POINTS, 1, type, indices, 1, basevertex);
430 }
431 
DrawRangeElementsMinimizedProc(GLenum mode,GLuint start,GLuint end,GLsizei count,GLenum type,const void * indices)432 void KHRONOS_APIENTRY DrawRangeElementsMinimizedProc(GLenum mode,
433                                                      GLuint start,
434                                                      GLuint end,
435                                                      GLsizei count,
436                                                      GLenum type,
437                                                      const void *indices)
438 {
439     glDrawRangeElements(GL_POINTS, start, end, 1, type, indices);
440 }
441 
DrawArraysMinimizedProc(GLenum mode,GLint first,GLsizei count)442 void KHRONOS_APIENTRY DrawArraysMinimizedProc(GLenum mode, GLint first, GLsizei count)
443 {
444     glDrawArrays(GL_POINTS, first, 1);
445 }
446 
DrawArraysInstancedMinimizedProc(GLenum mode,GLint first,GLsizei count,GLsizei instancecount)447 void KHRONOS_APIENTRY DrawArraysInstancedMinimizedProc(GLenum mode,
448                                                        GLint first,
449                                                        GLsizei count,
450                                                        GLsizei instancecount)
451 {
452     glDrawArraysInstanced(GL_POINTS, first, 1, 1);
453 }
454 
DrawArraysIndirectMinimizedProc(GLenum mode,const void * indirect)455 void KHRONOS_APIENTRY DrawArraysIndirectMinimizedProc(GLenum mode, const void *indirect)
456 {
457     glDrawArraysInstanced(GL_POINTS, 0, 1, 1);
458 }
459 
DispatchComputeMinimizedProc(GLuint num_groups_x,GLuint num_groups_y,GLuint num_groups_z)460 void KHRONOS_APIENTRY DispatchComputeMinimizedProc(GLuint num_groups_x,
461                                                    GLuint num_groups_y,
462                                                    GLuint num_groups_z)
463 {
464     glDispatchCompute(1, 1, 1);
465 }
466 
DispatchComputeIndirectMinimizedProc(GLintptr indirect)467 void KHRONOS_APIENTRY DispatchComputeIndirectMinimizedProc(GLintptr indirect)
468 {
469     glDispatchCompute(1, 1, 1);
470 }
471 
472 // Interpose the calls that generate data copying work
BufferDataMinimizedProc(GLenum target,GLsizeiptr size,const void * data,GLenum usage)473 void KHRONOS_APIENTRY BufferDataMinimizedProc(GLenum target,
474                                               GLsizeiptr size,
475                                               const void *data,
476                                               GLenum usage)
477 {
478     glBufferData(target, size, nullptr, usage);
479 }
480 
BufferSubDataMinimizedProc(GLenum target,GLintptr offset,GLsizeiptr size,const void * data)481 void KHRONOS_APIENTRY BufferSubDataMinimizedProc(GLenum target,
482                                                  GLintptr offset,
483                                                  GLsizeiptr size,
484                                                  const void *data)
485 {
486 #if !defined(NOOP_SUBDATA_SUBIMAGE_FOR_MINIMIZE_GPU_WORK)
487     glBufferSubData(target, offset, 1, data);
488 #endif
489 }
490 
MapBufferRangeMinimizedProc(GLenum target,GLintptr offset,GLsizeiptr length,GLbitfield access)491 void *KHRONOS_APIENTRY MapBufferRangeMinimizedProc(GLenum target,
492                                                    GLintptr offset,
493                                                    GLsizeiptr length,
494                                                    GLbitfield access)
495 {
496     access |= GL_MAP_UNSYNCHRONIZED_BIT;
497     return glMapBufferRange(target, offset, length, access);
498 }
499 
TexImage2DMinimizedProc(GLenum target,GLint level,GLint internalformat,GLsizei width,GLsizei height,GLint border,GLenum format,GLenum type,const void * pixels)500 void KHRONOS_APIENTRY TexImage2DMinimizedProc(GLenum target,
501                                               GLint level,
502                                               GLint internalformat,
503                                               GLsizei width,
504                                               GLsizei height,
505                                               GLint border,
506                                               GLenum format,
507                                               GLenum type,
508                                               const void *pixels)
509 {
510     GLint unpackBuffer = 0;
511     glGetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING, &unpackBuffer);
512     if (unpackBuffer)
513     {
514         glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
515     }
516     glTexImage2D(target, level, internalformat, width, height, border, format, type, nullptr);
517     if (unpackBuffer)
518     {
519         glBindBuffer(GL_PIXEL_UNPACK_BUFFER, unpackBuffer);
520     }
521 }
522 
TexSubImage2DMinimizedProc(GLenum target,GLint level,GLint xoffset,GLint yoffset,GLsizei width,GLsizei height,GLenum format,GLenum type,const void * pixels)523 void KHRONOS_APIENTRY TexSubImage2DMinimizedProc(GLenum target,
524                                                  GLint level,
525                                                  GLint xoffset,
526                                                  GLint yoffset,
527                                                  GLsizei width,
528                                                  GLsizei height,
529                                                  GLenum format,
530                                                  GLenum type,
531                                                  const void *pixels)
532 {
533 #if !defined(NOOP_SUBDATA_SUBIMAGE_FOR_MINIMIZE_GPU_WORK)
534     glTexSubImage2D(target, level, xoffset, yoffset, 1, 1, format, type, pixels);
535 #endif
536 }
537 
TexImage3DMinimizedProc(GLenum target,GLint level,GLint internalformat,GLsizei width,GLsizei height,GLsizei depth,GLint border,GLenum format,GLenum type,const void * pixels)538 void KHRONOS_APIENTRY TexImage3DMinimizedProc(GLenum target,
539                                               GLint level,
540                                               GLint internalformat,
541                                               GLsizei width,
542                                               GLsizei height,
543                                               GLsizei depth,
544                                               GLint border,
545                                               GLenum format,
546                                               GLenum type,
547                                               const void *pixels)
548 {
549     GLint unpackBuffer = 0;
550     glGetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING, &unpackBuffer);
551     if (unpackBuffer)
552     {
553         glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
554     }
555     glTexImage3D(target, level, internalformat, width, height, depth, border, format, type,
556                  nullptr);
557     if (unpackBuffer)
558     {
559         glBindBuffer(GL_PIXEL_UNPACK_BUFFER, unpackBuffer);
560     }
561 }
562 
TexSubImage3DMinimizedProc(GLenum target,GLint level,GLint xoffset,GLint yoffset,GLint zoffset,GLsizei width,GLsizei height,GLsizei depth,GLenum format,GLenum type,const void * pixels)563 void KHRONOS_APIENTRY TexSubImage3DMinimizedProc(GLenum target,
564                                                  GLint level,
565                                                  GLint xoffset,
566                                                  GLint yoffset,
567                                                  GLint zoffset,
568                                                  GLsizei width,
569                                                  GLsizei height,
570                                                  GLsizei depth,
571                                                  GLenum format,
572                                                  GLenum type,
573                                                  const void *pixels)
574 {
575 #if !defined(NOOP_SUBDATA_SUBIMAGE_FOR_MINIMIZE_GPU_WORK)
576     glTexSubImage3D(target, level, xoffset, yoffset, zoffset, 1, 1, 1, format, type, pixels);
577 #endif
578 }
579 
GenerateMipmapMinimizedProc(GLenum target)580 void KHRONOS_APIENTRY GenerateMipmapMinimizedProc(GLenum target)
581 {
582     // Noop it for now. There is a risk that this will leave an incomplete mipmap chain and cause
583     // other issues. If this turns out to be a real issue with app traces, we can turn this into a
584     // glTexImage2D call for each generated level.
585 }
586 
BlitFramebufferMinimizedProc(GLint srcX0,GLint srcY0,GLint srcX1,GLint srcY1,GLint dstX0,GLint dstY0,GLint dstX1,GLint dstY1,GLbitfield mask,GLenum filter)587 void KHRONOS_APIENTRY BlitFramebufferMinimizedProc(GLint srcX0,
588                                                    GLint srcY0,
589                                                    GLint srcX1,
590                                                    GLint srcY1,
591                                                    GLint dstX0,
592                                                    GLint dstY0,
593                                                    GLint dstX1,
594                                                    GLint dstY1,
595                                                    GLbitfield mask,
596                                                    GLenum filter)
597 {
598     glBlitFramebuffer(srcX0, srcY0, srcX0 + 1, srcY0 + 1, dstX0, dstY0, dstX0 + 1, dstY0 + 1, mask,
599                       filter);
600 }
601 
ReadPixelsMinimizedProc(GLint x,GLint y,GLsizei width,GLsizei height,GLenum format,GLenum type,void * pixels)602 void KHRONOS_APIENTRY ReadPixelsMinimizedProc(GLint x,
603                                               GLint y,
604                                               GLsizei width,
605                                               GLsizei height,
606                                               GLenum format,
607                                               GLenum type,
608                                               void *pixels)
609 {
610     glReadPixels(x, y, 1, 1, format, type, pixels);
611 }
612 
BeginTransformFeedbackMinimizedProc(GLenum primitiveMode)613 void KHRONOS_APIENTRY BeginTransformFeedbackMinimizedProc(GLenum primitiveMode)
614 {
615     glBeginTransformFeedback(GL_POINTS);
616 }
617 
TraceLoadProc(const char * procName)618 angle::GenericProc KHRONOS_APIENTRY TraceLoadProc(const char *procName)
619 {
620     // EGL
621     if (strcmp(procName, "eglCreateContext") == 0)
622     {
623         return reinterpret_cast<angle::GenericProc>(EglCreateContext);
624     }
625     if (strcmp(procName, "eglMakeCurrent") == 0)
626     {
627         return reinterpret_cast<angle::GenericProc>(EglMakeCurrent);
628     }
629     if (strcmp(procName, "eglGetCurrentContext") == 0)
630     {
631         return reinterpret_cast<angle::GenericProc>(EglGetCurrentContext);
632     }
633     if (strcmp(procName, "eglCreateImage") == 0)
634     {
635         return reinterpret_cast<angle::GenericProc>(EglCreateImage);
636     }
637     if (strcmp(procName, "eglCreateImageKHR") == 0)
638     {
639         return reinterpret_cast<angle::GenericProc>(EglCreateImageKHR);
640     }
641     if (strcmp(procName, "eglDestroyImage") == 0)
642     {
643         return reinterpret_cast<angle::GenericProc>(EglDestroyImage);
644     }
645     if (strcmp(procName, "eglDestroyImageKHR") == 0)
646     {
647         return reinterpret_cast<angle::GenericProc>(EglDestroyImageKHR);
648     }
649     if (strcmp(procName, "eglCreateSync") == 0)
650     {
651         return reinterpret_cast<angle::GenericProc>(EglCreateSync);
652     }
653     if (strcmp(procName, "eglCreateSyncKHR") == 0)
654     {
655         return reinterpret_cast<angle::GenericProc>(EglCreateSyncKHR);
656     }
657     if (strcmp(procName, "eglDestroySync") == 0)
658     {
659         return reinterpret_cast<angle::GenericProc>(EglDestroySync);
660     }
661     if (strcmp(procName, "eglDestroySyncKHR") == 0)
662     {
663         return reinterpret_cast<angle::GenericProc>(EglDestroySyncKHR);
664     }
665     if (strcmp(procName, "eglClientWaitSync") == 0)
666     {
667         return reinterpret_cast<angle::GenericProc>(EglClientWaitSync);
668     }
669     if (strcmp(procName, "eglClientWaitSyncKHR") == 0)
670     {
671         return reinterpret_cast<angle::GenericProc>(EglClientWaitSyncKHR);
672     }
673     if (strcmp(procName, "eglGetError") == 0)
674     {
675         return reinterpret_cast<angle::GenericProc>(EglGetError);
676     }
677     if (strcmp(procName, "eglGetCurrentDisplay") == 0)
678     {
679         return reinterpret_cast<angle::GenericProc>(EglGetCurrentDisplay);
680     }
681 
682     // GLES
683     if (strcmp(procName, "glBindFramebuffer") == 0)
684     {
685         return reinterpret_cast<angle::GenericProc>(BindFramebufferProc);
686     }
687     if (strcmp(procName, "glInvalidateFramebuffer") == 0)
688     {
689         return reinterpret_cast<angle::GenericProc>(InvalidateFramebufferProc);
690     }
691     if (strcmp(procName, "glInvalidateSubFramebuffer") == 0)
692     {
693         return reinterpret_cast<angle::GenericProc>(InvalidateSubFramebufferProc);
694     }
695     if (strcmp(procName, "glDrawBuffers") == 0)
696     {
697         return reinterpret_cast<angle::GenericProc>(DrawBuffersProc);
698     }
699     if (strcmp(procName, "glReadBuffer") == 0)
700     {
701         return reinterpret_cast<angle::GenericProc>(ReadBufferProc);
702     }
703     if (strcmp(procName, "glDiscardFramebufferEXT") == 0)
704     {
705         return reinterpret_cast<angle::GenericProc>(DiscardFramebufferEXTProc);
706     }
707 
708     if (gMinimizeGPUWork)
709     {
710         if (strcmp(procName, "glViewport") == 0)
711         {
712             return reinterpret_cast<angle::GenericProc>(ViewportMinimizedProc);
713         }
714 
715         if (strcmp(procName, "glScissor") == 0)
716         {
717             return reinterpret_cast<angle::GenericProc>(ScissorMinimizedProc);
718         }
719 
720         // Interpose the calls that generate actual GPU work
721         if (strcmp(procName, "glDrawElements") == 0)
722         {
723             return reinterpret_cast<angle::GenericProc>(DrawElementsMinimizedProc);
724         }
725         if (strcmp(procName, "glDrawElementsIndirect") == 0)
726         {
727             return reinterpret_cast<angle::GenericProc>(DrawElementsIndirectMinimizedProc);
728         }
729         if (strcmp(procName, "glDrawElementsInstanced") == 0 ||
730             strcmp(procName, "glDrawElementsInstancedEXT") == 0)
731         {
732             return reinterpret_cast<angle::GenericProc>(DrawElementsInstancedMinimizedProc);
733         }
734         if (strcmp(procName, "glDrawElementsBaseVertex") == 0 ||
735             strcmp(procName, "glDrawElementsBaseVertexEXT") == 0 ||
736             strcmp(procName, "glDrawElementsBaseVertexOES") == 0)
737         {
738             return reinterpret_cast<angle::GenericProc>(DrawElementsBaseVertexMinimizedProc);
739         }
740         if (strcmp(procName, "glDrawElementsInstancedBaseVertex") == 0 ||
741             strcmp(procName, "glDrawElementsInstancedBaseVertexEXT") == 0 ||
742             strcmp(procName, "glDrawElementsInstancedBaseVertexOES") == 0)
743         {
744             return reinterpret_cast<angle::GenericProc>(
745                 DrawElementsInstancedBaseVertexMinimizedProc);
746         }
747         if (strcmp(procName, "glDrawRangeElements") == 0)
748         {
749             return reinterpret_cast<angle::GenericProc>(DrawRangeElementsMinimizedProc);
750         }
751         if (strcmp(procName, "glDrawArrays") == 0)
752         {
753             return reinterpret_cast<angle::GenericProc>(DrawArraysMinimizedProc);
754         }
755         if (strcmp(procName, "glDrawArraysInstanced") == 0 ||
756             strcmp(procName, "glDrawArraysInstancedEXT") == 0)
757         {
758             return reinterpret_cast<angle::GenericProc>(DrawArraysInstancedMinimizedProc);
759         }
760         if (strcmp(procName, "glDrawArraysIndirect") == 0)
761         {
762             return reinterpret_cast<angle::GenericProc>(DrawArraysIndirectMinimizedProc);
763         }
764         if (strcmp(procName, "glDispatchCompute") == 0)
765         {
766             return reinterpret_cast<angle::GenericProc>(DispatchComputeMinimizedProc);
767         }
768         if (strcmp(procName, "glDispatchComputeIndirect") == 0)
769         {
770             return reinterpret_cast<angle::GenericProc>(DispatchComputeIndirectMinimizedProc);
771         }
772 
773         // Interpose the calls that generate data copying work
774         if (strcmp(procName, "glBufferData") == 0)
775         {
776             return reinterpret_cast<angle::GenericProc>(BufferDataMinimizedProc);
777         }
778         if (strcmp(procName, "glBufferSubData") == 0)
779         {
780             return reinterpret_cast<angle::GenericProc>(BufferSubDataMinimizedProc);
781         }
782         if (strcmp(procName, "glMapBufferRange") == 0 ||
783             strcmp(procName, "glMapBufferRangeEXT") == 0)
784         {
785             return reinterpret_cast<angle::GenericProc>(MapBufferRangeMinimizedProc);
786         }
787         if (strcmp(procName, "glTexImage2D") == 0)
788         {
789             return reinterpret_cast<angle::GenericProc>(TexImage2DMinimizedProc);
790         }
791         if (strcmp(procName, "glTexImage3D") == 0)
792         {
793             return reinterpret_cast<angle::GenericProc>(TexImage3DMinimizedProc);
794         }
795         if (strcmp(procName, "glTexSubImage2D") == 0)
796         {
797             return reinterpret_cast<angle::GenericProc>(TexSubImage2DMinimizedProc);
798         }
799         if (strcmp(procName, "glTexSubImage3D") == 0)
800         {
801             return reinterpret_cast<angle::GenericProc>(TexSubImage3DMinimizedProc);
802         }
803         if (strcmp(procName, "glGenerateMipmap") == 0 ||
804             strcmp(procName, "glGenerateMipmapOES") == 0)
805         {
806             return reinterpret_cast<angle::GenericProc>(GenerateMipmapMinimizedProc);
807         }
808         if (strcmp(procName, "glBlitFramebuffer") == 0)
809         {
810             return reinterpret_cast<angle::GenericProc>(BlitFramebufferMinimizedProc);
811         }
812         if (strcmp(procName, "glReadPixels") == 0)
813         {
814             return reinterpret_cast<angle::GenericProc>(ReadPixelsMinimizedProc);
815         }
816         if (strcmp(procName, "glBeginTransformFeedback") == 0)
817         {
818             return reinterpret_cast<angle::GenericProc>(BeginTransformFeedbackMinimizedProc);
819         }
820     }
821 
822     return gCurrentTracePerfTest->getGLWindow()->getProcAddress(procName);
823 }
824 
ValidateSerializedState(const char * serializedState,const char * fileName,uint32_t line)825 void ValidateSerializedState(const char *serializedState, const char *fileName, uint32_t line)
826 {
827     gCurrentTracePerfTest->validateSerializedState(serializedState, fileName, line);
828 }
829 
830 constexpr char kTraceTestFolder[] = "src/tests/restricted_traces";
831 
FindTraceTestDataPath(const char * traceName,char * testDataDirOut,size_t maxDataDirLen)832 bool FindTraceTestDataPath(const char *traceName, char *testDataDirOut, size_t maxDataDirLen)
833 {
834     char relativeTestDataDir[kMaxPath] = {};
835     snprintf(relativeTestDataDir, kMaxPath, "%s%c%s", kTraceTestFolder, GetPathSeparator(),
836              traceName);
837     return angle::FindTestDataPath(relativeTestDataDir, testDataDirOut, maxDataDirLen);
838 }
839 
FindRootTraceTestDataPath(char * testDataDirOut,size_t maxDataDirLen)840 bool FindRootTraceTestDataPath(char *testDataDirOut, size_t maxDataDirLen)
841 {
842     return angle::FindTestDataPath(kTraceTestFolder, testDataDirOut, maxDataDirLen);
843 }
844 
TracePerfTest(std::unique_ptr<const TracePerfParams> params)845 TracePerfTest::TracePerfTest(std::unique_ptr<const TracePerfParams> params)
846     : ANGLERenderTest("TracePerf", *params.get(), "ms"),
847       mParams(std::move(params)),
848       mStartFrame(0),
849       mEndFrame(0)
850 {
851     bool isAMD      = IsAMD() && !mParams->isSwiftshader();
852     bool isAMDLinux = isAMD && IsLinux();
853     // bool isAMDLinuxANGLE  = isAMDLinux && mParams->isANGLE();
854     bool isAMDLinuxNative = isAMDLinux && !mParams->isANGLE();
855     bool isAMDWin         = isAMD && IsWindows();
856     bool isAMDWinANGLE    = isAMDWin && mParams->isANGLE();
857     // bool isAMDWinNative   = isAMDWin && !mParams->isANGLE();
858 
859     bool isIntel            = IsIntel() && !mParams->isSwiftshader();
860     bool isIntelLinux       = isIntel && IsLinux();
861     bool isIntelLinuxANGLE  = isIntelLinux && mParams->isANGLE();
862     bool isIntelLinuxNative = isIntelLinux && !mParams->isANGLE();
863     bool isIntelWin         = IsWindows() && isIntel;
864     bool isIntelWinANGLE    = isIntelWin && mParams->isANGLE();
865     bool isIntelWinNative   = isIntelWin && !mParams->isANGLE();
866 
867     bool isNVIDIA            = IsNVIDIA() && !mParams->isSwiftshader();
868     bool isNVIDIALinux       = isNVIDIA && IsLinux();
869     bool isNVIDIALinuxANGLE  = isNVIDIALinux && mParams->isANGLE();
870     bool isNVIDIALinuxNative = isNVIDIALinux && !mParams->isANGLE();
871     bool isNVIDIAWin         = isNVIDIA && IsWindows();
872     bool isNVIDIAWinANGLE    = isNVIDIAWin && mParams->isANGLE();
873     bool isNVIDIAWinNative   = isNVIDIAWin && !mParams->isANGLE();
874 
875     if (!mParams->traceInfo.initialized)
876     {
877         failTest("Failed to load trace json.");
878         return;
879     }
880 
881     for (std::string extension : mParams->traceInfo.requiredExtensions)
882     {
883         addExtensionPrerequisite(extension);
884     }
885 
886     if (!mParams->traceInfo.keyFrames.empty())
887     {
888         // Only support one keyFrame for now
889         if (mParams->traceInfo.keyFrames.size() != 1)
890         {
891             WARN() << "Multiple keyframes detected, only using the first";
892         }
893 
894         // Only use keyFrame if the user didn't specify a value.
895         if (gScreenshotFrame == kDefaultScreenshotFrame)
896         {
897             mScreenshotFrame = mParams->traceInfo.keyFrames[0];
898             INFO() << "Trace contains keyframe, using frame " << mScreenshotFrame
899                    << " for screenshot";
900         }
901         else
902         {
903             WARN() << "Ignoring keyframe, user requested frame " << mScreenshotFrame
904                    << " for screenshot";
905         }
906     }
907 
908     if (isIntelWinANGLE && traceNameIs("manhattan_10"))
909     {
910         skipTest(
911             "TODO: http://anglebug.com/4533 This fails after the upgrade to the 26.20.100.7870 "
912             "driver");
913     }
914 
915     if (isIntelWinNative && traceNameIs("angry_birds_2_1500"))
916     {
917         skipTest("TODO: http://anglebug.com/4731 Fails on older Intel drivers. Passes in newer");
918     }
919 
920     if (traceNameIs("cod_mobile"))
921     {
922         // TODO: http://anglebug.com/4967 Vulkan: GL_EXT_color_buffer_float not supported on Pixel 2
923         // The COD:Mobile trace uses a framebuffer attachment with:
924         //   format = GL_RGB
925         //   type = GL_UNSIGNED_INT_10F_11F_11F_REV
926         // That combination is only renderable if GL_EXT_color_buffer_float is supported.
927         // It happens to not be supported on Pixel 2's Vulkan driver.
928         addExtensionPrerequisite("GL_EXT_color_buffer_float");
929 
930         // TODO: http://anglebug.com/4731 This extension is missing on older Intel drivers.
931         addExtensionPrerequisite("GL_OES_EGL_image_external");
932 
933         if (isIntelWin)
934         {
935             skipTest("http://anglebug.com/6568 Flaky on Intel/windows");
936         }
937     }
938 
939     if (isIntelWinANGLE && traceNameIs("black_desert_mobile"))
940     {
941         skipTest("TODO: http://anglebug.com/7879 Non-deterministic image on 31.0.101.2111 driver");
942     }
943 
944     if (isIntelWinANGLE && traceNameIs("the_gardens_between"))
945     {
946         skipTest("TODO: http://anglebug.com/7879 Non-deterministic image on 31.0.101.2111 driver");
947     }
948 
949     if (traceNameIs("brawl_stars"))
950     {
951         addExtensionPrerequisite("GL_EXT_shadow_samplers");
952     }
953 
954     if (traceNameIs("free_fire"))
955     {
956         addExtensionPrerequisite("GL_OES_EGL_image_external");
957     }
958 
959     if (traceNameIs("marvel_contest_of_champions"))
960     {
961         addExtensionPrerequisite("GL_EXT_color_buffer_half_float");
962     }
963 
964     if (traceNameIs("world_of_tanks_blitz"))
965     {
966         addExtensionPrerequisite("GL_EXT_disjoint_timer_query");
967     }
968 
969     if (traceNameIs("dragon_ball_legends"))
970     {
971         addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
972     }
973 
974     if (traceNameIs("lego_legacy"))
975     {
976         addExtensionPrerequisite("GL_EXT_shadow_samplers");
977     }
978 
979     if (traceNameIs("world_war_doh"))
980     {
981         // Linux+NVIDIA doesn't support GL_KHR_texture_compression_astc_ldr (possibly others also)
982         addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
983     }
984 
985     if (traceNameIs("saint_seiya_awakening"))
986     {
987         addExtensionPrerequisite("GL_EXT_shadow_samplers");
988 
989         if (isIntelLinuxANGLE)
990         {
991             skipTest(
992                 "TODO: https://anglebug.com/5517 Linux+Intel generates 'Framebuffer is incomplete' "
993                 "errors");
994         }
995     }
996 
997     if (traceNameIs("magic_tiles_3"))
998     {
999         // Linux+NVIDIA doesn't support GL_KHR_texture_compression_astc_ldr (possibly others also)
1000         addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
1001     }
1002 
1003     if (traceNameIs("real_gangster_crime"))
1004     {
1005         // Linux+NVIDIA doesn't support GL_KHR_texture_compression_astc_ldr (possibly others also)
1006         addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
1007 
1008         // Intel doesn't support external images.
1009         addExtensionPrerequisite("GL_OES_EGL_image_external");
1010 
1011         if (isIntelLinuxNative || isAMDLinuxNative)
1012         {
1013             skipTest("http://anglebug.com/5822 Failing on Linux Intel and AMD due to invalid enum");
1014         }
1015     }
1016 
1017     if (traceNameIs("asphalt_8"))
1018     {
1019         addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
1020     }
1021 
1022     if (traceNameIs("hearthstone"))
1023     {
1024         addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
1025     }
1026 
1027     if (traceNameIs("efootball_pes_2021"))
1028     {
1029         if (isIntelLinuxANGLE)
1030         {
1031             skipTest(
1032                 "TODO: https://anglebug.com/5517 Linux+Intel generate 'Framebuffer is "
1033                 "incomplete' errors with the Vulkan backend");
1034         }
1035     }
1036 
1037     if (traceNameIs("shadow_fight_2"))
1038     {
1039         addExtensionPrerequisite("GL_OES_EGL_image_external");
1040         addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
1041     }
1042 
1043     if (traceNameIs("rise_of_kingdoms"))
1044     {
1045         addExtensionPrerequisite("GL_OES_EGL_image_external");
1046     }
1047 
1048     if (traceNameIs("happy_color"))
1049     {
1050         if (isAMDWinANGLE)
1051         {
1052             skipTest("http://anglebug.com/5623 Generates incorrect results on AMD Windows Vulkan");
1053         }
1054     }
1055 
1056     if (traceNameIs("bus_simulator_indonesia"))
1057     {
1058         if (isIntelLinuxNative || isAMDLinuxNative)
1059         {
1060             skipTest("TODO: https://anglebug.com/5629 native GLES generates GL_INVALID_OPERATION");
1061         }
1062     }
1063 
1064     if (traceNameIs("messenger_lite"))
1065     {
1066         if (isNVIDIAWinANGLE)
1067         {
1068             skipTest(
1069                 "https://anglebug.com/5663 Incorrect pixels on NVIDIA Windows for first frame");
1070         }
1071     }
1072 
1073     if (traceNameIs("among_us"))
1074     {
1075         addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
1076     }
1077 
1078     if (traceNameIs("car_parking_multiplayer"))
1079     {
1080         if (isNVIDIAWinNative || isNVIDIALinuxNative)
1081         {
1082             skipTest(
1083                 "TODO: https://anglebug.com/5613 NVIDIA native driver spews undefined behavior "
1084                 "warnings");
1085         }
1086         if (isIntelWinANGLE)
1087         {
1088             skipTest("https://anglebug.com/5724 Device lost on Win Intel");
1089         }
1090     }
1091 
1092     if (traceNameIs("fifa_mobile"))
1093     {
1094         if (isIntelWinANGLE)
1095         {
1096             skipTest(
1097                 "TODO: http://anglebug.com/5875 Intel Windows Vulkan flakily renders entirely "
1098                 "black");
1099         }
1100     }
1101 
1102     if (traceNameIs("extreme_car_driving_simulator"))
1103     {
1104         addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
1105     }
1106 
1107     if (traceNameIs("plants_vs_zombies_2"))
1108     {
1109         if (isAMDWinANGLE)
1110         {
1111             skipTest("TODO: http://crbug.com/1187752 Corrupted image");
1112         }
1113     }
1114 
1115     if (traceNameIs("junes_journey"))
1116     {
1117         addExtensionPrerequisite("GL_OES_EGL_image_external");
1118     }
1119 
1120     if (traceNameIs("ragnarok_m_eternal_love"))
1121     {
1122         addExtensionPrerequisite("GL_OES_EGL_image_external");
1123         addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
1124     }
1125 
1126     if (traceNameIs("league_of_legends_wild_rift"))
1127     {
1128         addExtensionPrerequisite("GL_OES_EGL_image_external");
1129         addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
1130 
1131         if (isIntelLinuxANGLE)
1132         {
1133             skipTest("TODO: http://anglebug.com/5815 Trace is crashing on Intel Linux");
1134         }
1135     }
1136 
1137     if (traceNameIs("aztec_ruins"))
1138     {
1139         addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
1140     }
1141 
1142     if (traceNameIs("dragon_raja"))
1143     {
1144         addExtensionPrerequisite("GL_OES_EGL_image_external");
1145 
1146         if (isIntelLinuxANGLE)
1147         {
1148             skipTest(
1149                 "TODO: http://anglebug.com/5807 Intel Linux errors with 'Framebuffer is "
1150                 "incomplete' on Vulkan");
1151         }
1152     }
1153 
1154     if (traceNameIs("hill_climb_racing") || traceNameIs("dead_trigger_2") ||
1155         traceNameIs("disney_mirrorverse") || traceNameIs("cut_the_rope") ||
1156         traceNameIs("geometry_dash"))
1157     {
1158         if (IsAndroid() && (IsPixel4() || IsPixel4XL()) && !mParams->isANGLE())
1159         {
1160             skipTest(
1161                 "http://anglebug.com/5823 Adreno gives a driver error with empty/small draw calls");
1162         }
1163     }
1164 
1165     if (traceNameIs("avakin_life"))
1166     {
1167         addExtensionPrerequisite("GL_OES_EGL_image_external");
1168     }
1169 
1170     if (traceNameIs("professional_baseball_spirits"))
1171     {
1172         if (isIntelLinuxANGLE || isAMDLinuxNative)
1173         {
1174             skipTest(
1175                 "TODO: https://anglebug.com/5827 Linux+Mesa/RADV Vulkan generates "
1176                 "GL_INVALID_FRAMEBUFFER_OPERATION. Mesa versions below 20.3.5 produce the same "
1177                 "issue on Linux+Mesa/Intel Vulkan");
1178         }
1179     }
1180 
1181     if (traceNameIs("call_break_offline_card_game"))
1182     {
1183         if (isIntelLinuxANGLE)
1184         {
1185             skipTest(
1186                 "TODO: http://anglebug.com/5837 Intel Linux Vulkan errors with 'Framebuffer is "
1187                 "incomplete'");
1188         }
1189     }
1190 
1191     if (traceNameIs("ludo_king"))
1192     {
1193         addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
1194     }
1195 
1196     if (traceNameIs("summoners_war"))
1197     {
1198         if (isIntelWinANGLE)
1199         {
1200             skipTest("TODO: http://anglebug.com/5943 GL_INVALID_ENUM on Windows/Intel");
1201         }
1202     }
1203 
1204     if (traceNameIs("pokemon_go"))
1205     {
1206         addExtensionPrerequisite("GL_EXT_texture_cube_map_array");
1207         addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
1208 
1209         if (isIntelLinuxANGLE)
1210         {
1211             skipTest("TODO: http://anglebug.com/5989 Intel Linux crashing on teardown");
1212         }
1213 
1214         if (isIntelWinANGLE)
1215         {
1216             skipTest("TODO: http://anglebug.com/5994 Intel Windows timing out periodically");
1217         }
1218     }
1219 
1220     if (traceNameIs("cookie_run_kingdom"))
1221     {
1222         addExtensionPrerequisite("GL_EXT_texture_cube_map_array");
1223         addExtensionPrerequisite("GL_OES_EGL_image_external");
1224     }
1225 
1226     if (traceNameIs("genshin_impact"))
1227     {
1228         addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
1229 
1230         if (isNVIDIAWinANGLE || isNVIDIALinuxANGLE)
1231         {
1232             skipTest("http://anglebug.com/7496 Nondeterministic noise between runs");
1233         }
1234 
1235         if (isIntelLinuxANGLE)
1236         {
1237             skipTest("TODO: http://anglebug.com/6029 Crashes on Linux Intel Vulkan");
1238         }
1239 
1240         if (!Is64Bit())
1241         {
1242             skipTest("Genshin is too large to handle in 32-bit mode");
1243         }
1244     }
1245 
1246     if (traceNameIs("mario_kart_tour"))
1247     {
1248         if (isIntelLinuxNative)
1249         {
1250             skipTest("http://anglebug.com/6711 Fails on native Mesa");
1251         }
1252     }
1253 
1254     if (traceNameIs("pubg_mobile_skydive") || traceNameIs("pubg_mobile_battle_royale"))
1255     {
1256         addExtensionPrerequisite("GL_EXT_texture_buffer");
1257 
1258         if (isIntelWinNative || isNVIDIALinuxNative || isNVIDIAWinNative)
1259         {
1260             skipTest("TODO: http://anglebug.com/6240 Internal errors on Windows/Intel and NVIDIA");
1261         }
1262     }
1263 
1264     if (traceNameIs("sakura_school_simulator"))
1265     {
1266         if (isIntelWin)
1267         {
1268             skipTest("http://anglebug.com/6294 Flaky on Intel");
1269         }
1270     }
1271 
1272     if (traceNameIs("scrabble_go"))
1273     {
1274         addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
1275     }
1276 
1277     if (traceNameIs("world_of_kings"))
1278     {
1279         addExtensionPrerequisite("GL_OES_EGL_image_external");
1280         if (isIntelWin)
1281         {
1282             skipTest("http://anglebug.com/6372 Flaky on Intel");
1283         }
1284     }
1285 
1286     if (traceNameIs("nier_reincarnation"))
1287     {
1288         addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
1289     }
1290 
1291     if (traceNameIs("mini_world"))
1292     {
1293         if (IsQualcomm() && mParams->isVulkan())
1294         {
1295             skipTest(
1296                 "TODO: http://anglebug.com/6443 Vulkan Test failure on Pixel4XL due to vulkan "
1297                 "validation error VUID-vkDestroyBuffer-buffer-00922");
1298         }
1299     }
1300 
1301     if (traceNameIs("pokemon_unite"))
1302     {
1303         addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
1304 
1305         if (IsIntel())
1306         {
1307             skipTest(
1308                 "http://anglebug.com/6548 nondeterministic on Intel+Windows. Crashes on Linux "
1309                 "Intel");
1310         }
1311     }
1312 
1313     if (traceNameIs("world_cricket_championship_2"))
1314     {
1315         addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
1316 
1317         if (isIntelLinuxNative)
1318         {
1319             skipTest("http://anglebug.com/6657 Native test timing out on Intel Linux");
1320         }
1321     }
1322 
1323     if (traceNameIs("zillow"))
1324     {
1325         if (isNVIDIAWinANGLE || isNVIDIALinuxANGLE)
1326         {
1327             skipTest("http://anglebug.com/6658 Crashing in Vulkan backend");
1328         }
1329     }
1330 
1331     if (traceNameIs("township"))
1332     {
1333         addExtensionPrerequisite("GL_OES_EGL_image_external");
1334     }
1335 
1336     if (traceNameIs("asphalt_9"))
1337     {
1338         addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
1339     }
1340 
1341     if (traceNameIs("pubg_mobile_launch"))
1342     {
1343         if (isNVIDIALinuxNative)
1344         {
1345             skipTest("http://anglebug.com/6850 Crashing in Nvidia GLES driver");
1346         }
1347     }
1348 
1349     if (traceNameIs("star_wars_kotor"))
1350     {
1351         if (IsLinux() && mParams->isSwiftshader())
1352         {
1353             skipTest("TODO: http://anglebug.com/7565 Flaky on Swiftshader");
1354         }
1355     }
1356 
1357     if (traceNameIs("dead_by_daylight"))
1358     {
1359         addExtensionPrerequisite("GL_EXT_shader_framebuffer_fetch");
1360     }
1361 
1362     if (traceNameIs("war_planet_online"))
1363     {
1364         addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
1365     }
1366 
1367     if (traceNameIs("lords_mobile"))
1368     {
1369         // http://anglebug.com/7000 - glTexStorage2DEXT is not exposed on Pixel 4 native
1370         addExtensionPrerequisite("GL_EXT_texture_storage");
1371     }
1372 
1373     if (traceNameIs("marvel_strike_force"))
1374     {
1375         if ((IsAndroid() && IsQualcomm()) && !mParams->isANGLE())
1376         {
1377             skipTest(
1378                 "http://anglebug.com/7017 Qualcomm native driver gets confused about the state of "
1379                 "a buffer that was recreated during the trace");
1380         }
1381     }
1382 
1383     if (traceNameIs("real_racing3"))
1384     {
1385         addExtensionPrerequisite("GL_EXT_shader_framebuffer_fetch");
1386     }
1387 
1388     if (traceNameIs("blade_and_soul_revolution"))
1389     {
1390         addExtensionPrerequisite("GL_EXT_texture_buffer");
1391         addExtensionPrerequisite("GL_EXT_shader_framebuffer_fetch");
1392         addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
1393     }
1394 
1395     if (traceNameIs("scary_teacher_3d"))
1396     {
1397         addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
1398     }
1399 
1400     if (traceNameIs("car_chase"))
1401     {
1402         if (isIntelWin)
1403         {
1404             skipTest("http://anglebug.com/7173 Fails on Intel HD 630 Mobile");
1405         }
1406 
1407         if (isIntelLinux)
1408         {
1409             skipTest("http://anglebug.com/7125#c8 Flaky hang on UHD630 Mesa 20.0.8");
1410         }
1411 
1412         if (isNVIDIAWinANGLE || isNVIDIALinuxANGLE)
1413         {
1414             skipTest("http://anglebug.com/7125 Renders incorrectly on NVIDIA");
1415         }
1416 
1417         addExtensionPrerequisite("GL_EXT_geometry_shader");
1418         addExtensionPrerequisite("GL_EXT_primitive_bounding_box");
1419         addExtensionPrerequisite("GL_EXT_tessellation_shader");
1420         addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
1421         addExtensionPrerequisite("GL_EXT_texture_cube_map_array");
1422     }
1423 
1424     if (traceNameIs("aztec_ruins_high"))
1425     {
1426         addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
1427     }
1428 
1429     if (traceNameIs("special_forces_group_2"))
1430     {
1431         addExtensionPrerequisite("GL_EXT_texture_buffer");
1432     }
1433 
1434     if (traceNameIs("tessellation"))
1435     {
1436         if (isNVIDIAWinANGLE || isNVIDIALinuxANGLE)
1437         {
1438             skipTest("http://anglebug.com/7240 Tessellation driver bugs on Nvidia");
1439         }
1440 
1441         addExtensionPrerequisite("GL_EXT_geometry_shader");
1442         addExtensionPrerequisite("GL_EXT_primitive_bounding_box");
1443         addExtensionPrerequisite("GL_EXT_tessellation_shader");
1444         addExtensionPrerequisite("GL_EXT_texture_cube_map_array");
1445     }
1446 
1447     if (traceNameIs("basemark_gpu"))
1448     {
1449         addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
1450     }
1451 
1452     if (traceNameIs("mortal_kombat"))
1453     {
1454         addExtensionPrerequisite("GL_EXT_texture_buffer");
1455     }
1456 
1457     if (traceNameIs("ni_no_kuni"))
1458     {
1459         addExtensionPrerequisite("GL_EXT_shader_framebuffer_fetch");
1460         addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
1461     }
1462 
1463     if (traceNameIs("octopath_traveler"))
1464     {
1465         addExtensionPrerequisite("GL_EXT_shader_framebuffer_fetch");
1466         addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
1467     }
1468 
1469     if (traceNameIs("antutu_refinery"))
1470     {
1471         addExtensionPrerequisite("GL_ANDROID_extension_pack_es31a");
1472     }
1473 
1474     if (traceNameIs("botworld_adventure"))
1475     {
1476         addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
1477     }
1478 
1479     if (traceNameIs("eve_echoes"))
1480     {
1481         if (IsQualcomm() && mParams->isVulkan())
1482         {
1483             skipTest("TODO: http://anglebug.com/7690 Test crashes in LLVM on Qualcomm (Pixel 4)");
1484         }
1485     }
1486 
1487     if (traceNameIs("life_is_strange"))
1488     {
1489         if (isNVIDIAWinANGLE)
1490         {
1491             skipTest("http://anglebug.com/7723 Renders incorrectly on Nvidia Windows");
1492         }
1493 
1494         addExtensionPrerequisite("GL_EXT_texture_buffer");
1495         addExtensionPrerequisite("GL_EXT_texture_cube_map_array");
1496     }
1497 
1498     if (traceNameIs("survivor_io"))
1499     {
1500         if (isNVIDIAWinANGLE)
1501         {
1502             skipTest("http://anglebug.com/7733 Renders incorrectly on Nvidia Windows");
1503         }
1504 
1505         if (isIntelWinNative)
1506         {
1507             skipTest(
1508                 "http://anglebug.com/7737 Programs fail to link on Intel Windows native driver, "
1509                 "citing MAX_UNIFORM_LOCATIONS exceeded");
1510         }
1511     }
1512 
1513     if (traceNameIs("minetest"))
1514     {
1515         addExtensionPrerequisite("GL_EXT_texture_format_BGRA8888");
1516         addIntegerPrerequisite(GL_MAX_TEXTURE_UNITS, 4);
1517     }
1518 
1519     if (traceNameIs("diablo_immortal"))
1520     {
1521         addExtensionPrerequisite("GL_EXT_shader_framebuffer_fetch");
1522     }
1523 
1524     if (traceNameIs("mu_origin_3"))
1525     {
1526         addExtensionPrerequisite("GL_EXT_texture_buffer");
1527         addExtensionPrerequisite("GL_EXT_shader_framebuffer_fetch");
1528         addExtensionPrerequisite("GL_OES_EGL_image_external");
1529     }
1530 
1531     if (traceNameIs("catalyst_black"))
1532     {
1533         addExtensionPrerequisite("GL_EXT_shader_framebuffer_fetch");
1534     }
1535 
1536     if (traceNameIs("five_nights_at_freddys"))
1537     {
1538         if (isIntelWinANGLE)
1539         {
1540             skipTest("http://anglebug.com/7929 Too slow on Win Intel Vulkan");
1541         }
1542     }
1543 
1544     if (traceNameIs("pubg_mobile_launch"))
1545     {
1546         if (isIntelWinNative || isIntelWinANGLE)
1547         {
1548             skipTest("http://anglebug.com/7929 Too slow on Win Intel native and Vulkan");
1549         }
1550     }
1551 
1552     if (traceNameIs("beach_buggy_racing"))
1553     {
1554         if (isIntelWinANGLE)
1555         {
1556             skipTest("http://anglebug.com/7934 Flaky context lost on Win Intel Vulkan");
1557         }
1558     }
1559 
1560     if (traceNameIs("aliexpress"))
1561     {
1562         if (isIntelWinNative)
1563         {
1564             skipTest("http://anglebug.com/7934 Flaky failure on Win Intel native");
1565         }
1566     }
1567 
1568     if (traceNameIs("final_fantasy"))
1569     {
1570         if (IsAndroid() && IsPixel6() && !mParams->isANGLE())
1571         {
1572             skipTest("http://anglebug.com/7936 Crashes on Pixel 6 native");
1573         }
1574     }
1575 
1576     if (traceNameIs("limbo"))
1577     {
1578         addExtensionPrerequisite("GL_EXT_shader_framebuffer_fetch");
1579 
1580         // For LUMINANCE8_ALPHA8_EXT
1581         addExtensionPrerequisite("GL_EXT_texture_storage");
1582     }
1583 
1584     if (traceNameIs("into_the_dead_2"))
1585     {
1586         if (isNVIDIAWinANGLE)
1587         {
1588             skipTest("http://anglebug.com/8042 Non-deterministic trace");
1589         }
1590     }
1591 
1592     if (traceNameIs("arknights"))
1593     {
1594         // Intel doesn't support external images.
1595         addExtensionPrerequisite("GL_OES_EGL_image_external");
1596     }
1597 
1598     if (traceNameIs("street_fighter_duel"))
1599     {
1600         if (isNVIDIAWinANGLE)
1601         {
1602             skipTest("https://anglebug.com/8074 NVIDIA Windows flaky diffs");
1603         }
1604     }
1605 
1606     if (traceNameIs("honkai_star_rail"))
1607     {
1608         addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
1609         if (isIntelWin)
1610         {
1611             skipTest("https://anglebug.com/8175 Consistently stuck on Intel/windows");
1612         }
1613     }
1614 
1615     if (traceNameIs("gangstar_vegas"))
1616     {
1617         if (mParams->isSwiftshader())
1618         {
1619             skipTest("TODO: http://anglebug.com/8173 Missing shadows on Swiftshader");
1620         }
1621     }
1622 
1623     if (traceNameIs("respawnables"))
1624     {
1625         if (!mParams->isANGLE() && (IsWindows() || IsLinux()))
1626         {
1627             skipTest("TODO: https://anglebug.com/8191 Undefined behavior on native");
1628         }
1629     }
1630 
1631     if (traceNameIs("street_fighter_iv_ce"))
1632     {
1633         if (mParams->isSwiftshader())
1634         {
1635             skipTest("https://anglebug.com/8243 Too slow on Swiftshader (large keyframe)");
1636         }
1637     }
1638 
1639     if (traceNameIs("monster_hunter_stories"))
1640     {
1641         if (isIntelWinANGLE)
1642         {
1643             skipTest("http://anglebug.com/7557 Flaky context lost on Win Intel Vulkan");
1644         }
1645     }
1646 
1647     // glDebugMessageControlKHR and glDebugMessageCallbackKHR crash on ARM GLES1.
1648     if (IsARM() && mParams->traceInfo.contextClientMajorVersion == 1)
1649     {
1650         mEnableDebugCallback = false;
1651     }
1652 
1653     // We already swap in TracePerfTest::drawBenchmark, no need to swap again in the harness.
1654     disableTestHarnessSwap();
1655 
1656     gCurrentTracePerfTest = this;
1657 
1658     if (gTraceTestValidation)
1659     {
1660         mStepsToRun = frameCount();
1661     }
1662 
1663     if (gWarmupSteps == kAllFrames)
1664     {
1665         mWarmupSteps = frameCount();
1666     }
1667 
1668     if (gRunToKeyFrame)
1669     {
1670         if (mParams->traceInfo.keyFrames.empty())
1671         {
1672             // If we don't have a keyFrame, run one step
1673             INFO() << "No keyframe available for trace, running to frame 1";
1674             mStepsToRun = 1;
1675         }
1676         else
1677         {
1678             int keyFrame = mParams->traceInfo.keyFrames[0];
1679             INFO() << "Running to keyframe: " << keyFrame;
1680             mStepsToRun = keyFrame;
1681         }
1682     }
1683 }
1684 
startTest()1685 void TracePerfTest::startTest()
1686 {
1687     // runTrial() must align to frameCount()
1688     ASSERT(mCurrentFrame == mStartFrame);
1689 }
1690 
FindTraceGzPath(const std::string & traceName)1691 std::string FindTraceGzPath(const std::string &traceName)
1692 {
1693     std::stringstream pathStream;
1694 
1695     char genDir[kMaxPath] = {};
1696     if (!angle::FindTestDataPath("gen", genDir, kMaxPath))
1697     {
1698         return "";
1699     }
1700     pathStream << genDir << angle::GetPathSeparator() << "tracegz_" << traceName << ".gz";
1701 
1702     return pathStream.str();
1703 }
1704 
initializeBenchmark()1705 void TracePerfTest::initializeBenchmark()
1706 {
1707     const TraceInfo &traceInfo = mParams->traceInfo;
1708 
1709     char testDataDir[kMaxPath] = {};
1710     if (!FindTraceTestDataPath(traceInfo.name, testDataDir, kMaxPath))
1711     {
1712         failTest("Could not find test data folder.");
1713         return;
1714     }
1715 
1716     if (gTraceInterpreter)
1717     {
1718         mTraceReplay.reset(new TraceLibrary("angle_trace_interpreter", traceInfo));
1719         if (strcmp(gTraceInterpreter, "gz") == 0)
1720         {
1721             std::string traceGzPath = FindTraceGzPath(traceInfo.name);
1722             if (traceGzPath.empty())
1723             {
1724                 failTest("Could not find trace gz.");
1725                 return;
1726             }
1727             mTraceReplay->setTraceGzPath(traceGzPath);
1728         }
1729     }
1730     else
1731     {
1732         std::stringstream traceNameStr;
1733         traceNameStr << "angle_restricted_traces_" << traceInfo.name;
1734         std::string traceName = traceNameStr.str();
1735         mTraceReplay.reset(new TraceLibrary(traceNameStr.str(), traceInfo));
1736     }
1737 
1738     LoadTraceEGL(TraceLoadProc);
1739     LoadTraceGLES(TraceLoadProc);
1740 
1741     if (!mTraceReplay->valid())
1742     {
1743         failTest("Could not load trace.");
1744         return;
1745     }
1746 
1747     mStartFrame = traceInfo.frameStart;
1748     mEndFrame   = traceInfo.frameEnd;
1749     mTraceReplay->setValidateSerializedStateCallback(ValidateSerializedState);
1750     mTraceReplay->setBinaryDataDir(testDataDir);
1751 
1752     if (gMinimizeGPUWork)
1753     {
1754         // Shrink the offscreen window to 1x1.
1755         mWindowWidth  = 1;
1756         mWindowHeight = 1;
1757     }
1758     else
1759     {
1760         mWindowWidth  = mTestParams.windowWidth;
1761         mWindowHeight = mTestParams.windowHeight;
1762     }
1763     mCurrentFrame     = mStartFrame;
1764     mCurrentIteration = mStartFrame;
1765 
1766     if (IsAndroid())
1767     {
1768         // On Android, set the orientation used by the app, based on width/height
1769         getWindow()->setOrientation(mTestParams.windowWidth, mTestParams.windowHeight);
1770     }
1771 
1772     // If we're rendering offscreen we set up a default back buffer.
1773     if (mParams->surfaceType == SurfaceType::Offscreen)
1774     {
1775         if (!IsAndroid())
1776         {
1777             mWindowWidth *= 4;
1778             mWindowHeight *= 4;
1779         }
1780 
1781         glGenRenderbuffers(1, &mOffscreenDepthStencil);
1782         glBindRenderbuffer(GL_RENDERBUFFER, mOffscreenDepthStencil);
1783         glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, mWindowWidth, mWindowHeight);
1784         glBindRenderbuffer(GL_RENDERBUFFER, 0);
1785 
1786         glGenFramebuffers(mMaxOffscreenBufferCount, mOffscreenFramebuffers.data());
1787         glGenTextures(mMaxOffscreenBufferCount, mOffscreenTextures.data());
1788         for (int i = 0; i < mMaxOffscreenBufferCount; i++)
1789         {
1790             glBindFramebuffer(GL_FRAMEBUFFER, mOffscreenFramebuffers[i]);
1791 
1792             // Hard-code RGBA8/D24S8. This should be specified in the trace info.
1793             glBindTexture(GL_TEXTURE_2D, mOffscreenTextures[i]);
1794             glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, mWindowWidth, mWindowHeight, 0, GL_RGBA,
1795                          GL_UNSIGNED_BYTE, nullptr);
1796 
1797             glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
1798                                    mOffscreenTextures[i], 0);
1799             glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER,
1800                                       mOffscreenDepthStencil);
1801             glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
1802                                       mOffscreenDepthStencil);
1803             glBindTexture(GL_TEXTURE_2D, 0);
1804         }
1805     }
1806 
1807     // Potentially slow. Can load a lot of resources.
1808     mTraceReplay->setupReplay();
1809 
1810     glFinish();
1811 
1812     ASSERT_GE(mEndFrame, mStartFrame);
1813 
1814     getWindow()->ignoreSizeEvents();
1815     getWindow()->setVisible(true);
1816 
1817     // If we're re-tracing, trigger capture start after setup. This ensures the Setup function gets
1818     // recaptured into another Setup function and not merged with the first frame.
1819     if (gRetraceMode)
1820     {
1821         getGLWindow()->swap();
1822     }
1823 }
1824 
1825 #undef TRACE_TEST_CASE
1826 
destroyBenchmark()1827 void TracePerfTest::destroyBenchmark()
1828 {
1829     if (mParams->surfaceType == SurfaceType::Offscreen)
1830     {
1831         glDeleteTextures(mMaxOffscreenBufferCount, mOffscreenTextures.data());
1832         mOffscreenTextures.fill(0);
1833 
1834         glDeleteRenderbuffers(1, &mOffscreenDepthStencil);
1835         mOffscreenDepthStencil = 0;
1836 
1837         glDeleteFramebuffers(mMaxOffscreenBufferCount, mOffscreenFramebuffers.data());
1838         mOffscreenFramebuffers.fill(0);
1839     }
1840 
1841     mTraceReplay->finishReplay();
1842     mTraceReplay.reset(nullptr);
1843 }
1844 
sampleTime()1845 void TracePerfTest::sampleTime()
1846 {
1847     if (mUseTimestampQueries)
1848     {
1849         GLint64 glTime;
1850         // glGetInteger64vEXT is exported by newer versions of the timer query extensions.
1851         // Unfortunately only the core EP is exposed by some desktop drivers (e.g. NVIDIA).
1852         if (glGetInteger64vEXT)
1853         {
1854             glGetInteger64vEXT(GL_TIMESTAMP_EXT, &glTime);
1855         }
1856         else
1857         {
1858             glGetInteger64v(GL_TIMESTAMP_EXT, &glTime);
1859         }
1860         mTimeline.push_back({glTime, angle::GetHostTimeSeconds()});
1861     }
1862 }
1863 
drawBenchmark()1864 void TracePerfTest::drawBenchmark()
1865 {
1866     constexpr uint32_t kFramesPerX  = 6;
1867     constexpr uint32_t kFramesPerY  = 4;
1868     constexpr uint32_t kFramesPerXY = kFramesPerY * kFramesPerX;
1869 
1870     const uint32_t kOffscreenOffsetX =
1871         static_cast<uint32_t>(static_cast<double>(mTestParams.windowWidth) / 3.0f);
1872     const uint32_t kOffscreenOffsetY =
1873         static_cast<uint32_t>(static_cast<double>(mTestParams.windowHeight) / 3.0f);
1874     const uint32_t kOffscreenWidth  = kOffscreenOffsetX;
1875     const uint32_t kOffscreenHeight = kOffscreenOffsetY;
1876 
1877     const uint32_t kOffscreenFrameWidth = static_cast<uint32_t>(
1878         static_cast<double>(kOffscreenWidth / static_cast<double>(kFramesPerX)));
1879     const uint32_t kOffscreenFrameHeight = static_cast<uint32_t>(
1880         static_cast<double>(kOffscreenHeight / static_cast<double>(kFramesPerY)));
1881 
1882     // Add a time sample from GL and the host.
1883     if (mCurrentFrame == mStartFrame)
1884     {
1885         sampleTime();
1886     }
1887 
1888     if (mParams->surfaceType == SurfaceType::Offscreen)
1889     {
1890         // Some driver (ARM and ANGLE) try to nop or defer the glFlush if it is called within the
1891         // renderpass to avoid breaking renderpass (performance reason). For app traces that does
1892         // not use any FBO, when we run in the offscreen mode, there is no frame boundary and
1893         // glFlush call we issued at end of frame will get skipped. To overcome this (and also
1894         // matches what onscreen double buffering behavior as well), we use two offscreen FBOs and
1895         // ping pong between them for each frame.
1896         glBindFramebuffer(GL_FRAMEBUFFER,
1897                           mOffscreenFramebuffers[mTotalFrameCount % mMaxOffscreenBufferCount]);
1898     }
1899 
1900     char frameName[32];
1901     snprintf(frameName, sizeof(frameName), "Frame %u", mCurrentFrame);
1902     beginInternalTraceEvent(frameName);
1903 
1904     startGpuTimer();
1905     mTraceReplay->replayFrame(mCurrentFrame);
1906     stopGpuTimer();
1907 
1908     updatePerfCounters();
1909 
1910     if (mParams->surfaceType == SurfaceType::Offscreen)
1911     {
1912         if (gMinimizeGPUWork)
1913         {
1914             // To keep GPU work minimum, we skip the blit.
1915             glFlush();
1916             mOffscreenFrameCount++;
1917         }
1918         else
1919         {
1920             GLint currentDrawFBO, currentReadFBO;
1921             glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &currentDrawFBO);
1922             glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &currentReadFBO);
1923 
1924             glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
1925             glBindFramebuffer(
1926                 GL_READ_FRAMEBUFFER,
1927                 mOffscreenFramebuffers[mOffscreenFrameCount % mMaxOffscreenBufferCount]);
1928 
1929             uint32_t frameX  = (mOffscreenFrameCount % kFramesPerXY) % kFramesPerX;
1930             uint32_t frameY  = (mOffscreenFrameCount % kFramesPerXY) / kFramesPerX;
1931             uint32_t windowX = kOffscreenOffsetX + frameX * kOffscreenFrameWidth;
1932             uint32_t windowY = kOffscreenOffsetY + frameY * kOffscreenFrameHeight;
1933 
1934             GLboolean scissorTest = GL_FALSE;
1935             glGetBooleanv(GL_SCISSOR_TEST, &scissorTest);
1936 
1937             if (scissorTest)
1938             {
1939                 glDisable(GL_SCISSOR_TEST);
1940             }
1941 
1942             glBlitFramebuffer(0, 0, mWindowWidth, mWindowHeight, windowX, windowY,
1943                               windowX + kOffscreenFrameWidth, windowY + kOffscreenFrameHeight,
1944                               GL_COLOR_BUFFER_BIT, GL_NEAREST);
1945 
1946             if (frameX == kFramesPerX - 1 && frameY == kFramesPerY - 1)
1947             {
1948                 swap();
1949                 glBindFramebuffer(GL_FRAMEBUFFER, 0);
1950                 glClear(GL_COLOR_BUFFER_BIT);
1951                 mOffscreenFrameCount = 0;
1952             }
1953             else
1954             {
1955                 glFlush();
1956                 mOffscreenFrameCount++;
1957             }
1958 
1959             if (scissorTest)
1960             {
1961                 glEnable(GL_SCISSOR_TEST);
1962             }
1963             glBindFramebuffer(GL_DRAW_FRAMEBUFFER, currentDrawFBO);
1964             glBindFramebuffer(GL_READ_FRAMEBUFFER, currentReadFBO);
1965         }
1966 
1967         mTotalFrameCount++;
1968     }
1969     else
1970     {
1971         swap();
1972     }
1973 
1974     endInternalTraceEvent(frameName);
1975 
1976     if (mCurrentFrame == mEndFrame)
1977     {
1978         mTraceReplay->resetReplay();
1979         mCurrentFrame = mStartFrame;
1980     }
1981     else
1982     {
1983         mCurrentFrame++;
1984     }
1985 
1986     // Always iterated for saving screenshots after reset
1987     mCurrentIteration++;
1988 
1989     // Process any running queries once per iteration.
1990     for (size_t queryIndex = 0; queryIndex < mRunningQueries.size();)
1991     {
1992         const QueryInfo &query = mRunningQueries[queryIndex];
1993 
1994         GLuint endResultAvailable = 0;
1995         glGetQueryObjectuivEXT(query.endTimestampQuery, GL_QUERY_RESULT_AVAILABLE,
1996                                &endResultAvailable);
1997 
1998         if (endResultAvailable == GL_TRUE)
1999         {
2000             char fboName[32];
2001             snprintf(fboName, sizeof(fboName), "FBO %u", query.framebuffer);
2002 
2003             GLint64 beginTimestamp = 0;
2004             glGetQueryObjecti64vEXT(query.beginTimestampQuery, GL_QUERY_RESULT, &beginTimestamp);
2005             glDeleteQueriesEXT(1, &query.beginTimestampQuery);
2006             double beginHostTime = getHostTimeFromGLTime(beginTimestamp);
2007             beginGLTraceEvent(fboName, beginHostTime);
2008 
2009             GLint64 endTimestamp = 0;
2010             glGetQueryObjecti64vEXT(query.endTimestampQuery, GL_QUERY_RESULT, &endTimestamp);
2011             glDeleteQueriesEXT(1, &query.endTimestampQuery);
2012             double endHostTime = getHostTimeFromGLTime(endTimestamp);
2013             endGLTraceEvent(fboName, endHostTime);
2014 
2015             mRunningQueries.erase(mRunningQueries.begin() + queryIndex);
2016         }
2017         else
2018         {
2019             queryIndex++;
2020         }
2021     }
2022 }
2023 
2024 // Converts a GL timestamp into a host-side CPU time aligned with "GetHostTimeSeconds".
2025 // This check is necessary to line up sampled trace events in a consistent timeline.
2026 // Uses a linear interpolation from a series of samples. We do a blocking call to sample
2027 // both host and GL time once per swap. We then find the two closest GL timestamps and
2028 // interpolate the host times between them to compute our result. If we are past the last
2029 // GL timestamp we sample a new data point pair.
getHostTimeFromGLTime(GLint64 glTime)2030 double TracePerfTest::getHostTimeFromGLTime(GLint64 glTime)
2031 {
2032     // Find two samples to do a lerp.
2033     size_t firstSampleIndex = mTimeline.size() - 1;
2034     while (firstSampleIndex > 0)
2035     {
2036         if (mTimeline[firstSampleIndex].glTime < glTime)
2037         {
2038             break;
2039         }
2040         firstSampleIndex--;
2041     }
2042 
2043     // Add an extra sample if we're missing an ending sample.
2044     if (firstSampleIndex == mTimeline.size() - 1)
2045     {
2046         sampleTime();
2047     }
2048 
2049     const TimeSample &start = mTimeline[firstSampleIndex];
2050     const TimeSample &end   = mTimeline[firstSampleIndex + 1];
2051 
2052     // Note: we have observed in some odd cases later timestamps producing values that are
2053     // smaller than preceding timestamps. This bears further investigation.
2054 
2055     // Compute the scaling factor for the lerp.
2056     double glDelta = static_cast<double>(glTime - start.glTime);
2057     double glRange = static_cast<double>(end.glTime - start.glTime);
2058     double t       = glDelta / glRange;
2059 
2060     // Lerp(t1, t2, t)
2061     double hostRange = end.hostTime - start.hostTime;
2062     return mTimeline[firstSampleIndex].hostTime + hostRange * t;
2063 }
2064 
onEglCreateContext(EGLDisplay display,EGLConfig config,EGLContext share_context,EGLint const * attrib_list)2065 EGLContext TracePerfTest::onEglCreateContext(EGLDisplay display,
2066                                              EGLConfig config,
2067                                              EGLContext share_context,
2068                                              EGLint const *attrib_list)
2069 {
2070     GLWindowContext newContext =
2071         getGLWindow()->createContextGeneric(reinterpret_cast<GLWindowContext>(share_context));
2072     return reinterpret_cast<EGLContext>(newContext);
2073 }
2074 
onEglMakeCurrent(EGLDisplay display,EGLSurface draw,EGLSurface read,EGLContext context)2075 void TracePerfTest::onEglMakeCurrent(EGLDisplay display,
2076                                      EGLSurface draw,
2077                                      EGLSurface read,
2078                                      EGLContext context)
2079 {
2080     getGLWindow()->makeCurrentGeneric(reinterpret_cast<GLWindowContext>(context));
2081 }
2082 
onEglGetCurrentContext()2083 EGLContext TracePerfTest::onEglGetCurrentContext()
2084 {
2085     return getGLWindow()->getCurrentContextGeneric();
2086 }
2087 
onEglCreateImage(EGLDisplay display,EGLContext context,EGLenum target,EGLClientBuffer buffer,const EGLAttrib * attrib_list)2088 EGLImage TracePerfTest::onEglCreateImage(EGLDisplay display,
2089                                          EGLContext context,
2090                                          EGLenum target,
2091                                          EGLClientBuffer buffer,
2092                                          const EGLAttrib *attrib_list)
2093 {
2094     GLWindowBase::Image image = getGLWindow()->createImage(
2095         reinterpret_cast<GLWindowContext>(context), target, buffer, attrib_list);
2096     return reinterpret_cast<EGLImage>(image);
2097 }
2098 
onEglCreateImageKHR(EGLDisplay display,EGLContext context,EGLenum target,EGLClientBuffer buffer,const EGLint * attrib_list)2099 EGLImageKHR TracePerfTest::onEglCreateImageKHR(EGLDisplay display,
2100                                                EGLContext context,
2101                                                EGLenum target,
2102                                                EGLClientBuffer buffer,
2103                                                const EGLint *attrib_list)
2104 {
2105     GLWindowBase::Image image = getGLWindow()->createImageKHR(
2106         reinterpret_cast<GLWindowContext>(context), target, buffer, attrib_list);
2107     return reinterpret_cast<EGLImage>(image);
2108 }
2109 
onEglDestroyImage(EGLDisplay display,EGLImage image)2110 EGLBoolean TracePerfTest::onEglDestroyImage(EGLDisplay display, EGLImage image)
2111 {
2112     return getGLWindow()->destroyImage(image);
2113 }
2114 
onEglDestroyImageKHR(EGLDisplay display,EGLImage image)2115 EGLBoolean TracePerfTest::onEglDestroyImageKHR(EGLDisplay display, EGLImage image)
2116 {
2117     return getGLWindow()->destroyImageKHR(image);
2118 }
2119 
onEglCreateSync(EGLDisplay dpy,EGLenum type,const EGLAttrib * attrib_list)2120 EGLSync TracePerfTest::onEglCreateSync(EGLDisplay dpy, EGLenum type, const EGLAttrib *attrib_list)
2121 {
2122     return getGLWindow()->createSync(dpy, type, attrib_list);
2123 }
2124 
onEglCreateSyncKHR(EGLDisplay dpy,EGLenum type,const EGLint * attrib_list)2125 EGLSync TracePerfTest::onEglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list)
2126 {
2127     return getGLWindow()->createSyncKHR(dpy, type, attrib_list);
2128 }
2129 
onEglDestroySync(EGLDisplay dpy,EGLSync sync)2130 EGLBoolean TracePerfTest::onEglDestroySync(EGLDisplay dpy, EGLSync sync)
2131 {
2132     return getGLWindow()->destroySync(dpy, sync);
2133 }
2134 
onEglDestroySyncKHR(EGLDisplay dpy,EGLSync sync)2135 EGLBoolean TracePerfTest::onEglDestroySyncKHR(EGLDisplay dpy, EGLSync sync)
2136 {
2137     return getGLWindow()->destroySyncKHR(dpy, sync);
2138 }
2139 
onEglClientWaitSync(EGLDisplay dpy,EGLSync sync,EGLint flags,EGLTimeKHR timeout)2140 EGLint TracePerfTest::onEglClientWaitSync(EGLDisplay dpy,
2141                                           EGLSync sync,
2142                                           EGLint flags,
2143                                           EGLTimeKHR timeout)
2144 {
2145     return getGLWindow()->clientWaitSync(dpy, sync, flags, timeout);
2146 }
2147 
onEglClientWaitSyncKHR(EGLDisplay dpy,EGLSync sync,EGLint flags,EGLTimeKHR timeout)2148 EGLint TracePerfTest::onEglClientWaitSyncKHR(EGLDisplay dpy,
2149                                              EGLSync sync,
2150                                              EGLint flags,
2151                                              EGLTimeKHR timeout)
2152 {
2153     return getGLWindow()->clientWaitSyncKHR(dpy, sync, flags, timeout);
2154 }
2155 
onEglGetError()2156 EGLint TracePerfTest::onEglGetError()
2157 {
2158     return getGLWindow()->getEGLError();
2159 }
2160 
onEglGetCurrentDisplay()2161 EGLDisplay TracePerfTest::onEglGetCurrentDisplay()
2162 {
2163     return getGLWindow()->getCurrentDisplay();
2164 }
2165 
2166 // Triggered when the replay calls glBindFramebuffer.
onReplayFramebufferChange(GLenum target,GLuint framebuffer)2167 void TracePerfTest::onReplayFramebufferChange(GLenum target, GLuint framebuffer)
2168 {
2169     if (framebuffer == 0 && mParams->surfaceType == SurfaceType::Offscreen)
2170     {
2171         glBindFramebuffer(target,
2172                           mOffscreenFramebuffers[mTotalFrameCount % mMaxOffscreenBufferCount]);
2173     }
2174     else
2175     {
2176         glBindFramebuffer(target, framebuffer);
2177     }
2178 
2179     switch (target)
2180     {
2181         case GL_FRAMEBUFFER:
2182             mDrawFramebufferBinding = framebuffer;
2183             mReadFramebufferBinding = framebuffer;
2184             break;
2185         case GL_DRAW_FRAMEBUFFER:
2186             mDrawFramebufferBinding = framebuffer;
2187             break;
2188         case GL_READ_FRAMEBUFFER:
2189             mReadFramebufferBinding = framebuffer;
2190             return;
2191 
2192         default:
2193             UNREACHABLE();
2194             break;
2195     }
2196 
2197     if (!mUseTimestampQueries)
2198         return;
2199 
2200     // We have at most one active timestamp query at a time. This code will end the current
2201     // query and immediately start a new one.
2202     if (mCurrentQuery.beginTimestampQuery != 0)
2203     {
2204         glGenQueriesEXT(1, &mCurrentQuery.endTimestampQuery);
2205         glQueryCounterEXT(mCurrentQuery.endTimestampQuery, GL_TIMESTAMP_EXT);
2206         mRunningQueries.push_back(mCurrentQuery);
2207         mCurrentQuery = {};
2208     }
2209 
2210     ASSERT(mCurrentQuery.beginTimestampQuery == 0);
2211 
2212     glGenQueriesEXT(1, &mCurrentQuery.beginTimestampQuery);
2213     glQueryCounterEXT(mCurrentQuery.beginTimestampQuery, GL_TIMESTAMP_EXT);
2214     mCurrentQuery.framebuffer = framebuffer;
2215 }
2216 
GetDiffPath()2217 std::string GetDiffPath()
2218 {
2219 #if defined(ANGLE_PLATFORM_WINDOWS)
2220     std::array<char, MAX_PATH> filenameBuffer = {};
2221     char *filenamePtr                         = nullptr;
2222     if (SearchPathA(NULL, "diff", ".exe", MAX_PATH, filenameBuffer.data(), &filenamePtr) == 0)
2223     {
2224         return "";
2225     }
2226     return std::string(filenameBuffer.data());
2227 #else
2228     return "/usr/bin/diff";
2229 #endif  // defined(ANGLE_PLATFORM_WINDOWS)
2230 }
2231 
PrintFileDiff(const char * aFilePath,const char * bFilePath)2232 void PrintFileDiff(const char *aFilePath, const char *bFilePath)
2233 {
2234     std::string pathToDiff = GetDiffPath();
2235     if (pathToDiff.empty())
2236     {
2237         printf("Could not find diff in the path.\n");
2238         return;
2239     }
2240 
2241     std::vector<const char *> args;
2242     args.push_back(pathToDiff.c_str());
2243     args.push_back(aFilePath);
2244     args.push_back(bFilePath);
2245     args.push_back("-u3");
2246 
2247     printf("Calling");
2248     for (const char *arg : args)
2249     {
2250         printf(" %s", arg);
2251     }
2252     printf("\n");
2253 
2254     ProcessHandle proc(LaunchProcess(args, ProcessOutputCapture::StdoutOnly));
2255     if (proc && proc->finish())
2256     {
2257         printf("\n%s\n", proc->getStdout().c_str());
2258     }
2259 }
2260 
validateSerializedState(const char * expectedCapturedSerializedState,const char * fileName,uint32_t line)2261 void TracePerfTest::validateSerializedState(const char *expectedCapturedSerializedState,
2262                                             const char *fileName,
2263                                             uint32_t line)
2264 {
2265     if (!gTraceTestValidation)
2266     {
2267         return;
2268     }
2269 
2270     printf("Serialization checkpoint %s:%u...\n", fileName, line);
2271 
2272     const GLubyte *bytes                      = glGetString(GL_SERIALIZED_CONTEXT_STRING_ANGLE);
2273     const char *actualReplayedSerializedState = reinterpret_cast<const char *>(bytes);
2274     if (strcmp(expectedCapturedSerializedState, actualReplayedSerializedState) == 0)
2275     {
2276         printf("Serialization match.\n");
2277         return;
2278     }
2279 
2280     GTEST_NONFATAL_FAILURE_("Serialization mismatch!");
2281 
2282     const Optional<std::string> aFilePath = CreateTemporaryFile();
2283     const char *aFilePathCStr             = aFilePath.value().c_str();
2284     if (aFilePath.valid())
2285     {
2286         printf("Saving \"expected\" capture serialization to \"%s\".\n", aFilePathCStr);
2287         FILE *fpA = fopen(aFilePathCStr, "wt");
2288         ASSERT(fpA);
2289         fprintf(fpA, "%s", expectedCapturedSerializedState);
2290         fclose(fpA);
2291     }
2292 
2293     const Optional<std::string> bFilePath = CreateTemporaryFile();
2294     const char *bFilePathCStr             = bFilePath.value().c_str();
2295     if (bFilePath.valid())
2296     {
2297         printf("Saving \"actual\" replay serialization to \"%s\".\n", bFilePathCStr);
2298         FILE *fpB = fopen(bFilePathCStr, "wt");
2299         ASSERT(fpB);
2300         fprintf(fpB, "%s", actualReplayedSerializedState);
2301         fclose(fpB);
2302     }
2303 
2304     PrintFileDiff(aFilePathCStr, bFilePathCStr);
2305 }
2306 
isDefaultFramebuffer(GLenum target) const2307 bool TracePerfTest::isDefaultFramebuffer(GLenum target) const
2308 {
2309     switch (target)
2310     {
2311         case GL_FRAMEBUFFER:
2312         case GL_DRAW_FRAMEBUFFER:
2313             return (mDrawFramebufferBinding == 0);
2314 
2315         case GL_READ_FRAMEBUFFER:
2316             return (mReadFramebufferBinding == 0);
2317 
2318         default:
2319             UNREACHABLE();
2320             return false;
2321     }
2322 }
2323 
ConvertDefaultFramebufferEnum(GLenum value)2324 GLenum ConvertDefaultFramebufferEnum(GLenum value)
2325 {
2326     switch (value)
2327     {
2328         case GL_NONE:
2329             return GL_NONE;
2330         case GL_BACK:
2331         case GL_COLOR:
2332             return GL_COLOR_ATTACHMENT0;
2333         case GL_DEPTH:
2334             return GL_DEPTH_ATTACHMENT;
2335         case GL_STENCIL:
2336             return GL_STENCIL_ATTACHMENT;
2337         case GL_DEPTH_STENCIL:
2338             return GL_DEPTH_STENCIL_ATTACHMENT;
2339         default:
2340             UNREACHABLE();
2341             return GL_NONE;
2342     }
2343 }
2344 
ConvertDefaultFramebufferEnums(GLsizei numAttachments,const GLenum * attachments)2345 std::vector<GLenum> ConvertDefaultFramebufferEnums(GLsizei numAttachments,
2346                                                    const GLenum *attachments)
2347 {
2348     std::vector<GLenum> translatedAttachments;
2349     for (GLsizei attachmentIndex = 0; attachmentIndex < numAttachments; ++attachmentIndex)
2350     {
2351         GLenum converted = ConvertDefaultFramebufferEnum(attachments[attachmentIndex]);
2352         translatedAttachments.push_back(converted);
2353     }
2354     return translatedAttachments;
2355 }
2356 
2357 // Needs special handling to treat the 0 framebuffer in offscreen mode.
onReplayInvalidateFramebuffer(GLenum target,GLsizei numAttachments,const GLenum * attachments)2358 void TracePerfTest::onReplayInvalidateFramebuffer(GLenum target,
2359                                                   GLsizei numAttachments,
2360                                                   const GLenum *attachments)
2361 {
2362     if (mParams->surfaceType != SurfaceType::Offscreen || !isDefaultFramebuffer(target))
2363     {
2364         glInvalidateFramebuffer(target, numAttachments, attachments);
2365     }
2366     else
2367     {
2368         std::vector<GLenum> translatedAttachments =
2369             ConvertDefaultFramebufferEnums(numAttachments, attachments);
2370         glInvalidateFramebuffer(target, numAttachments, translatedAttachments.data());
2371     }
2372 }
2373 
onReplayInvalidateSubFramebuffer(GLenum target,GLsizei numAttachments,const GLenum * attachments,GLint x,GLint y,GLsizei width,GLsizei height)2374 void TracePerfTest::onReplayInvalidateSubFramebuffer(GLenum target,
2375                                                      GLsizei numAttachments,
2376                                                      const GLenum *attachments,
2377                                                      GLint x,
2378                                                      GLint y,
2379                                                      GLsizei width,
2380                                                      GLsizei height)
2381 {
2382     if (mParams->surfaceType != SurfaceType::Offscreen || !isDefaultFramebuffer(target))
2383     {
2384         glInvalidateSubFramebuffer(target, numAttachments, attachments, x, y, width, height);
2385     }
2386     else
2387     {
2388         std::vector<GLenum> translatedAttachments =
2389             ConvertDefaultFramebufferEnums(numAttachments, attachments);
2390         glInvalidateSubFramebuffer(target, numAttachments, translatedAttachments.data(), x, y,
2391                                    width, height);
2392     }
2393 }
2394 
onReplayDrawBuffers(GLsizei n,const GLenum * bufs)2395 void TracePerfTest::onReplayDrawBuffers(GLsizei n, const GLenum *bufs)
2396 {
2397     if (mParams->surfaceType != SurfaceType::Offscreen ||
2398         !isDefaultFramebuffer(GL_DRAW_FRAMEBUFFER))
2399     {
2400         glDrawBuffers(n, bufs);
2401     }
2402     else
2403     {
2404         std::vector<GLenum> translatedBufs = ConvertDefaultFramebufferEnums(n, bufs);
2405         glDrawBuffers(n, translatedBufs.data());
2406     }
2407 }
2408 
onReplayReadBuffer(GLenum src)2409 void TracePerfTest::onReplayReadBuffer(GLenum src)
2410 {
2411     if (mParams->surfaceType != SurfaceType::Offscreen ||
2412         !isDefaultFramebuffer(GL_READ_FRAMEBUFFER))
2413     {
2414         glReadBuffer(src);
2415     }
2416     else
2417     {
2418         GLenum translated = ConvertDefaultFramebufferEnum(src);
2419         glReadBuffer(translated);
2420     }
2421 }
2422 
onReplayDiscardFramebufferEXT(GLenum target,GLsizei numAttachments,const GLenum * attachments)2423 void TracePerfTest::onReplayDiscardFramebufferEXT(GLenum target,
2424                                                   GLsizei numAttachments,
2425                                                   const GLenum *attachments)
2426 {
2427     if (mParams->surfaceType != SurfaceType::Offscreen || !isDefaultFramebuffer(target))
2428     {
2429         glDiscardFramebufferEXT(target, numAttachments, attachments);
2430     }
2431     else
2432     {
2433         std::vector<GLenum> translatedAttachments =
2434             ConvertDefaultFramebufferEnums(numAttachments, attachments);
2435         glDiscardFramebufferEXT(target, numAttachments, translatedAttachments.data());
2436     }
2437 }
2438 
swap()2439 void TracePerfTest::swap()
2440 {
2441     // Capture a screenshot if enabled.
2442     if (gScreenshotDir != nullptr && gSaveScreenshots && !mScreenshotSaved &&
2443         mScreenshotFrame == mCurrentIteration)
2444     {
2445         std::stringstream screenshotNameStr;
2446         screenshotNameStr << gScreenshotDir << GetPathSeparator() << "angle" << mBackend << "_"
2447                           << mStory;
2448 
2449         // Add a marker to the name for any screenshot that isn't start frame
2450         if (mStartFrame != mScreenshotFrame)
2451         {
2452             screenshotNameStr << "_frame" << mScreenshotFrame;
2453         }
2454 
2455         screenshotNameStr << ".png";
2456 
2457         std::string screenshotName = screenshotNameStr.str();
2458         saveScreenshot(screenshotName);
2459         mScreenshotSaved = true;
2460     }
2461 
2462     getGLWindow()->swap();
2463 }
2464 
saveScreenshot(const std::string & screenshotName)2465 void TracePerfTest::saveScreenshot(const std::string &screenshotName)
2466 {
2467     // The frame is already rendered and is waiting in the default framebuffer.
2468 
2469     // RGBA 4-byte data.
2470     uint32_t pixelCount = mTestParams.windowWidth * mTestParams.windowHeight;
2471     std::vector<uint8_t> pixelData(pixelCount * 4);
2472 
2473     // Only unbind the framebuffer on context versions where it's available.
2474     if (mParams->traceInfo.contextClientMajorVersion > 1)
2475     {
2476         glBindFramebuffer(GL_FRAMEBUFFER, 0);
2477     }
2478 
2479     glReadPixels(0, 0, mTestParams.windowWidth, mTestParams.windowHeight, GL_RGBA, GL_UNSIGNED_BYTE,
2480                  pixelData.data());
2481 
2482     // Convert to RGB and flip y.
2483     std::vector<uint8_t> rgbData(pixelCount * 3);
2484     for (EGLint y = 0; y < mTestParams.windowHeight; ++y)
2485     {
2486         for (EGLint x = 0; x < mTestParams.windowWidth; ++x)
2487         {
2488             EGLint srcPixel = x + y * mTestParams.windowWidth;
2489             EGLint dstPixel = x + (mTestParams.windowHeight - y - 1) * mTestParams.windowWidth;
2490             memcpy(&rgbData[dstPixel * 3], &pixelData[srcPixel * 4], 3);
2491         }
2492     }
2493 
2494     if (!angle::SavePNGRGB(screenshotName.c_str(), "ANGLE Screenshot", mTestParams.windowWidth,
2495                            mTestParams.windowHeight, rgbData))
2496     {
2497         failTest(std::string("Error saving screenshot: ") + screenshotName);
2498         return;
2499     }
2500     else
2501     {
2502         printf("Saved screenshot: '%s'\n", screenshotName.c_str());
2503     }
2504 }
2505 }  // anonymous namespace
2506 
2507 using namespace params;
2508 
RegisterTraceTests()2509 void RegisterTraceTests()
2510 {
2511     GLESDriverType driverType = GetDriverTypeFromString(gUseGL, GLESDriverType::AngleEGL);
2512     GLenum platformType       = EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE;
2513     GLenum deviceType         = EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE;
2514     if (IsANGLE(driverType))
2515     {
2516         platformType = GetPlatformANGLETypeFromArg(gUseANGLE, EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE);
2517         deviceType =
2518             GetANGLEDeviceTypeFromArg(gUseANGLE, EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE);
2519     }
2520 
2521     char rootTracePath[kMaxPath] = {};
2522     if (!FindRootTraceTestDataPath(rootTracePath, kMaxPath))
2523     {
2524         ERR() << "Unable to find trace folder.";
2525         return;
2526     }
2527 
2528     // Load JSON data.
2529     std::vector<std::string> traces;
2530     {
2531         std::stringstream tracesJsonStream;
2532         tracesJsonStream << rootTracePath << GetPathSeparator() << "restricted_traces.json";
2533         std::string tracesJsonPath = tracesJsonStream.str();
2534 
2535         if (!LoadTraceNamesFromJSON(tracesJsonPath, &traces))
2536         {
2537             ERR() << "Unable to load traces from JSON file: " << tracesJsonPath;
2538             return;
2539         }
2540     }
2541 
2542     std::vector<TraceInfo> traceInfos;
2543     for (const std::string &trace : traces)
2544     {
2545         std::stringstream traceJsonStream;
2546         traceJsonStream << rootTracePath << GetPathSeparator() << trace << GetPathSeparator()
2547                         << trace << ".json";
2548         std::string traceJsonPath = traceJsonStream.str();
2549 
2550         TraceInfo traceInfo = {};
2551         strncpy(traceInfo.name, trace.c_str(), kTraceInfoMaxNameLen);
2552         traceInfo.initialized = LoadTraceInfoFromJSON(trace, traceJsonPath, &traceInfo);
2553 
2554         traceInfos.push_back(traceInfo);
2555     }
2556 
2557     for (const TraceInfo &traceInfo : traceInfos)
2558     {
2559         const TracePerfParams params(traceInfo, driverType, platformType, deviceType);
2560 
2561         if (!IsPlatformAvailable(params))
2562         {
2563             continue;
2564         }
2565 
2566         auto factory = [params]() {
2567             return new TracePerfTest(std::make_unique<TracePerfParams>(params));
2568         };
2569         testing::RegisterTest("TraceTest", traceInfo.name, nullptr, nullptr, __FILE__, __LINE__,
2570                               factory);
2571     }
2572 }
2573