• 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__anonc60049ef0111::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__anonc60049ef0111::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     int32_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             if (mScreenshotFrame == kAllFrames)
906             {
907                 WARN() << "Capturing screenshots of all frames since requested frame was "
908                        << kAllFrames;
909             }
910         }
911     }
912 
913     if (isIntelWinANGLE && traceNameIs("manhattan_10"))
914     {
915         skipTest(
916             "TODO: http://anglebug.com/4533 This fails after the upgrade to the 26.20.100.7870 "
917             "driver");
918     }
919 
920     if (isIntelWinNative && traceNameIs("angry_birds_2_1500"))
921     {
922         skipTest("TODO: http://anglebug.com/4731 Fails on older Intel drivers. Passes in newer");
923     }
924 
925     if (traceNameIs("cod_mobile"))
926     {
927         // TODO: http://anglebug.com/4967 Vulkan: GL_EXT_color_buffer_float not supported on Pixel 2
928         // The COD:Mobile trace uses a framebuffer attachment with:
929         //   format = GL_RGB
930         //   type = GL_UNSIGNED_INT_10F_11F_11F_REV
931         // That combination is only renderable if GL_EXT_color_buffer_float is supported.
932         // It happens to not be supported on Pixel 2's Vulkan driver.
933         addExtensionPrerequisite("GL_EXT_color_buffer_float");
934 
935         // TODO: http://anglebug.com/4731 This extension is missing on older Intel drivers.
936         addExtensionPrerequisite("GL_OES_EGL_image_external");
937 
938         if (isIntelWin)
939         {
940             skipTest("http://anglebug.com/6568 Flaky on Intel/windows");
941         }
942     }
943 
944     if (isIntelWinANGLE && traceNameIs("black_desert_mobile"))
945     {
946         skipTest("TODO: http://anglebug.com/7879 Non-deterministic image on 31.0.101.2111 driver");
947     }
948 
949     if (isIntelWinANGLE && traceNameIs("the_gardens_between"))
950     {
951         skipTest("TODO: http://anglebug.com/7879 Non-deterministic image on 31.0.101.2111 driver");
952     }
953 
954     if (traceNameIs("brawl_stars"))
955     {
956         addExtensionPrerequisite("GL_EXT_shadow_samplers");
957     }
958 
959     if (traceNameIs("free_fire"))
960     {
961         addExtensionPrerequisite("GL_OES_EGL_image_external");
962     }
963 
964     if (traceNameIs("marvel_contest_of_champions"))
965     {
966         addExtensionPrerequisite("GL_EXT_color_buffer_half_float");
967     }
968 
969     if (traceNameIs("world_of_tanks_blitz"))
970     {
971         addExtensionPrerequisite("GL_EXT_disjoint_timer_query");
972     }
973 
974     if (traceNameIs("dragon_ball_legends"))
975     {
976         addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
977     }
978 
979     if (traceNameIs("lego_legacy"))
980     {
981         addExtensionPrerequisite("GL_EXT_shadow_samplers");
982     }
983 
984     if (traceNameIs("world_war_doh"))
985     {
986         // Linux+NVIDIA doesn't support GL_KHR_texture_compression_astc_ldr (possibly others also)
987         addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
988     }
989 
990     if (traceNameIs("saint_seiya_awakening"))
991     {
992         addExtensionPrerequisite("GL_EXT_shadow_samplers");
993 
994         if (isIntelLinuxANGLE)
995         {
996             skipTest(
997                 "TODO: https://anglebug.com/5517 Linux+Intel generates 'Framebuffer is incomplete' "
998                 "errors");
999         }
1000     }
1001 
1002     if (traceNameIs("magic_tiles_3"))
1003     {
1004         // Linux+NVIDIA doesn't support GL_KHR_texture_compression_astc_ldr (possibly others also)
1005         addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
1006     }
1007 
1008     if (traceNameIs("real_gangster_crime"))
1009     {
1010         // Linux+NVIDIA doesn't support GL_KHR_texture_compression_astc_ldr (possibly others also)
1011         addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
1012 
1013         // Intel doesn't support external images.
1014         addExtensionPrerequisite("GL_OES_EGL_image_external");
1015 
1016         if (isIntelLinuxNative || isAMDLinuxNative)
1017         {
1018             skipTest("http://anglebug.com/5822 Failing on Linux Intel and AMD due to invalid enum");
1019         }
1020     }
1021 
1022     if (traceNameIs("asphalt_8"))
1023     {
1024         addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
1025     }
1026 
1027     if (traceNameIs("hearthstone"))
1028     {
1029         addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
1030     }
1031 
1032     if (traceNameIs("efootball_pes_2021"))
1033     {
1034         if (isIntelLinuxANGLE)
1035         {
1036             skipTest(
1037                 "TODO: https://anglebug.com/5517 Linux+Intel generate 'Framebuffer is "
1038                 "incomplete' errors with the Vulkan backend");
1039         }
1040     }
1041 
1042     if (traceNameIs("shadow_fight_2"))
1043     {
1044         addExtensionPrerequisite("GL_OES_EGL_image_external");
1045         addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
1046     }
1047 
1048     if (traceNameIs("rise_of_kingdoms"))
1049     {
1050         addExtensionPrerequisite("GL_OES_EGL_image_external");
1051     }
1052 
1053     if (traceNameIs("happy_color"))
1054     {
1055         if (isAMDWinANGLE)
1056         {
1057             skipTest("http://anglebug.com/5623 Generates incorrect results on AMD Windows Vulkan");
1058         }
1059     }
1060 
1061     if (traceNameIs("bus_simulator_indonesia"))
1062     {
1063         if (isIntelLinuxNative || isAMDLinuxNative)
1064         {
1065             skipTest("TODO: https://anglebug.com/5629 native GLES generates GL_INVALID_OPERATION");
1066         }
1067     }
1068 
1069     if (traceNameIs("messenger_lite"))
1070     {
1071         if (isNVIDIAWinANGLE)
1072         {
1073             skipTest(
1074                 "https://anglebug.com/5663 Incorrect pixels on NVIDIA Windows for first frame");
1075         }
1076     }
1077 
1078     if (traceNameIs("among_us"))
1079     {
1080         addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
1081     }
1082 
1083     if (traceNameIs("car_parking_multiplayer"))
1084     {
1085         if (isNVIDIAWinNative || isNVIDIALinuxNative)
1086         {
1087             skipTest(
1088                 "TODO: https://anglebug.com/5613 NVIDIA native driver spews undefined behavior "
1089                 "warnings");
1090         }
1091         if (isIntelWinANGLE)
1092         {
1093             skipTest("https://anglebug.com/5724 Device lost on Win Intel");
1094         }
1095     }
1096 
1097     if (traceNameIs("fifa_mobile"))
1098     {
1099         if (isIntelWinANGLE)
1100         {
1101             skipTest(
1102                 "TODO: http://anglebug.com/5875 Intel Windows Vulkan flakily renders entirely "
1103                 "black");
1104         }
1105     }
1106 
1107     if (traceNameIs("extreme_car_driving_simulator"))
1108     {
1109         addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
1110     }
1111 
1112     if (traceNameIs("plants_vs_zombies_2"))
1113     {
1114         if (isAMDWinANGLE)
1115         {
1116             skipTest("TODO: http://crbug.com/1187752 Corrupted image");
1117         }
1118     }
1119 
1120     if (traceNameIs("junes_journey"))
1121     {
1122         addExtensionPrerequisite("GL_OES_EGL_image_external");
1123     }
1124 
1125     if (traceNameIs("ragnarok_m_eternal_love"))
1126     {
1127         addExtensionPrerequisite("GL_OES_EGL_image_external");
1128         addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
1129     }
1130 
1131     if (traceNameIs("league_of_legends_wild_rift"))
1132     {
1133         addExtensionPrerequisite("GL_OES_EGL_image_external");
1134         addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
1135 
1136         if (isIntelLinuxANGLE)
1137         {
1138             skipTest("TODO: http://anglebug.com/5815 Trace is crashing on Intel Linux");
1139         }
1140     }
1141 
1142     if (traceNameIs("aztec_ruins"))
1143     {
1144         addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
1145     }
1146 
1147     if (traceNameIs("dragon_raja"))
1148     {
1149         addExtensionPrerequisite("GL_OES_EGL_image_external");
1150 
1151         if (isIntelLinuxANGLE)
1152         {
1153             skipTest(
1154                 "TODO: http://anglebug.com/5807 Intel Linux errors with 'Framebuffer is "
1155                 "incomplete' on Vulkan");
1156         }
1157     }
1158 
1159     if (traceNameIs("hill_climb_racing") || traceNameIs("dead_trigger_2") ||
1160         traceNameIs("disney_mirrorverse") || traceNameIs("cut_the_rope") ||
1161         traceNameIs("geometry_dash"))
1162     {
1163         if (IsAndroid() && (IsPixel4() || IsPixel4XL()) && !mParams->isANGLE())
1164         {
1165             skipTest(
1166                 "http://anglebug.com/5823 Adreno gives a driver error with empty/small draw calls");
1167         }
1168     }
1169 
1170     if (traceNameIs("avakin_life"))
1171     {
1172         addExtensionPrerequisite("GL_OES_EGL_image_external");
1173     }
1174 
1175     if (traceNameIs("professional_baseball_spirits"))
1176     {
1177         if (isIntelLinuxANGLE || isAMDLinuxNative)
1178         {
1179             skipTest(
1180                 "TODO: https://anglebug.com/5827 Linux+Mesa/RADV Vulkan generates "
1181                 "GL_INVALID_FRAMEBUFFER_OPERATION. Mesa versions below 20.3.5 produce the same "
1182                 "issue on Linux+Mesa/Intel Vulkan");
1183         }
1184     }
1185 
1186     if (traceNameIs("call_break_offline_card_game"))
1187     {
1188         if (isIntelLinuxANGLE)
1189         {
1190             skipTest(
1191                 "TODO: http://anglebug.com/5837 Intel Linux Vulkan errors with 'Framebuffer is "
1192                 "incomplete'");
1193         }
1194     }
1195 
1196     if (traceNameIs("ludo_king"))
1197     {
1198         addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
1199     }
1200 
1201     if (traceNameIs("summoners_war"))
1202     {
1203         if (isIntelWinANGLE)
1204         {
1205             skipTest("TODO: http://anglebug.com/5943 GL_INVALID_ENUM on Windows/Intel");
1206         }
1207 
1208         if (isIntelLinuxNative)
1209         {
1210             skipTest("https://anglebug.com/8682 fails on newer OS/driver");
1211         }
1212     }
1213 
1214     if (traceNameIs("pokemon_go"))
1215     {
1216         addExtensionPrerequisite("GL_EXT_texture_cube_map_array");
1217         addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
1218 
1219         if (isIntelLinuxANGLE)
1220         {
1221             skipTest("TODO: http://anglebug.com/5989 Intel Linux crashing on teardown");
1222         }
1223 
1224         if (isIntelWinANGLE)
1225         {
1226             skipTest("TODO: http://anglebug.com/5994 Intel Windows timing out periodically");
1227         }
1228     }
1229 
1230     if (traceNameIs("cookie_run_kingdom"))
1231     {
1232         addExtensionPrerequisite("GL_EXT_texture_cube_map_array");
1233         addExtensionPrerequisite("GL_OES_EGL_image_external");
1234     }
1235 
1236     if (traceNameIs("genshin_impact"))
1237     {
1238         addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
1239 
1240         if (isNVIDIAWinANGLE || isNVIDIALinuxANGLE)
1241         {
1242             skipTest("http://anglebug.com/7496 Nondeterministic noise between runs");
1243         }
1244 
1245         if (isIntelLinuxANGLE)
1246         {
1247             skipTest("TODO: http://anglebug.com/6029 Crashes on Linux Intel Vulkan");
1248         }
1249 
1250         if (!Is64Bit())
1251         {
1252             skipTest("Genshin is too large to handle in 32-bit mode");
1253         }
1254     }
1255 
1256     if (traceNameIs("mario_kart_tour"))
1257     {
1258         if (isIntelLinuxNative)
1259         {
1260             skipTest("http://anglebug.com/6711 Fails on native Mesa");
1261         }
1262     }
1263 
1264     if (traceNameIs("pubg_mobile_skydive") || traceNameIs("pubg_mobile_battle_royale"))
1265     {
1266         addExtensionPrerequisite("GL_EXT_texture_buffer");
1267 
1268         if (isIntelWinNative || isNVIDIALinuxNative || isNVIDIAWinNative)
1269         {
1270             skipTest("TODO: http://anglebug.com/6240 Internal errors on Windows/Intel and NVIDIA");
1271         }
1272     }
1273 
1274     if (traceNameIs("sakura_school_simulator"))
1275     {
1276         if (isIntelWin)
1277         {
1278             skipTest("http://anglebug.com/6294 Flaky on Intel");
1279         }
1280     }
1281 
1282     if (traceNameIs("scrabble_go"))
1283     {
1284         addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
1285     }
1286 
1287     if (traceNameIs("world_of_kings"))
1288     {
1289         addExtensionPrerequisite("GL_OES_EGL_image_external");
1290         if (isIntelWin)
1291         {
1292             skipTest("http://anglebug.com/6372 Flaky on Intel");
1293         }
1294     }
1295 
1296     if (traceNameIs("nier_reincarnation"))
1297     {
1298         addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
1299     }
1300 
1301     if (traceNameIs("mini_world"))
1302     {
1303         if (IsQualcomm() && mParams->isVulkan())
1304         {
1305             skipTest(
1306                 "TODO: http://anglebug.com/6443 Vulkan Test failure on Pixel4XL due to vulkan "
1307                 "validation error VUID-vkDestroyBuffer-buffer-00922");
1308         }
1309         if (isIntelWinNative)
1310         {
1311             skipTest("https://anglebug.com/8440 Flaky on native Win Intel");
1312         }
1313     }
1314 
1315     if (traceNameIs("pokemon_unite"))
1316     {
1317         addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
1318 
1319         if (IsIntel())
1320         {
1321             skipTest(
1322                 "http://anglebug.com/6548 nondeterministic on Intel+Windows. Crashes on Linux "
1323                 "Intel");
1324         }
1325     }
1326 
1327     if (traceNameIs("world_cricket_championship_2"))
1328     {
1329         addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
1330 
1331         if (isIntelLinuxNative)
1332         {
1333             skipTest("http://anglebug.com/6657 Native test timing out on Intel Linux");
1334         }
1335     }
1336 
1337     if (traceNameIs("zillow"))
1338     {
1339         if (isNVIDIAWinANGLE || isNVIDIALinuxANGLE)
1340         {
1341             skipTest("http://anglebug.com/6658 Crashing in Vulkan backend");
1342         }
1343 
1344         if (isIntelLinuxNative)
1345         {
1346             skipTest("https://anglebug.com/8682 fails on newer OS/driver");
1347         }
1348     }
1349 
1350     if (traceNameIs("township"))
1351     {
1352         addExtensionPrerequisite("GL_OES_EGL_image_external");
1353     }
1354 
1355     if (traceNameIs("asphalt_9"))
1356     {
1357         addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
1358     }
1359 
1360     if (traceNameIs("pubg_mobile_launch"))
1361     {
1362         if (isNVIDIALinuxNative)
1363         {
1364             skipTest("http://anglebug.com/6850 Crashing in Nvidia GLES driver");
1365         }
1366     }
1367 
1368     if (traceNameIs("star_wars_kotor"))
1369     {
1370         if (IsLinux() && mParams->isSwiftshader())
1371         {
1372             skipTest("TODO: http://anglebug.com/7565 Flaky on Swiftshader");
1373         }
1374     }
1375 
1376     if (traceNameIs("dead_by_daylight"))
1377     {
1378         addExtensionPrerequisite("GL_EXT_shader_framebuffer_fetch");
1379     }
1380 
1381     if (traceNameIs("war_planet_online"))
1382     {
1383         addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
1384     }
1385 
1386     if (traceNameIs("lords_mobile"))
1387     {
1388         // http://anglebug.com/7000 - glTexStorage2DEXT is not exposed on Pixel 4 native
1389         addExtensionPrerequisite("GL_EXT_texture_storage");
1390     }
1391 
1392     if (traceNameIs("marvel_strike_force"))
1393     {
1394         if ((IsAndroid() && IsQualcomm()) && !mParams->isANGLE())
1395         {
1396             skipTest(
1397                 "http://anglebug.com/7017 Qualcomm native driver gets confused about the state of "
1398                 "a buffer that was recreated during the trace");
1399         }
1400     }
1401 
1402     if (traceNameIs("real_racing3"))
1403     {
1404         addExtensionPrerequisite("GL_EXT_shader_framebuffer_fetch");
1405     }
1406 
1407     if (traceNameIs("blade_and_soul_revolution"))
1408     {
1409         addExtensionPrerequisite("GL_EXT_texture_buffer");
1410         addExtensionPrerequisite("GL_EXT_shader_framebuffer_fetch");
1411         addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
1412     }
1413 
1414     if (traceNameIs("scary_teacher_3d"))
1415     {
1416         addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
1417     }
1418 
1419     if (traceNameIs("car_chase"))
1420     {
1421         if (isIntelWin)
1422         {
1423             skipTest("http://anglebug.com/7173 Fails on Intel HD 630 Mobile");
1424         }
1425 
1426         if (isIntelLinux)
1427         {
1428             skipTest("http://anglebug.com/7125#c8 Flaky hang on UHD630 Mesa 20.0.8");
1429         }
1430 
1431         if (isNVIDIAWinANGLE || isNVIDIALinuxANGLE)
1432         {
1433             skipTest("http://anglebug.com/7125 Renders incorrectly on NVIDIA");
1434         }
1435 
1436         addExtensionPrerequisite("GL_EXT_geometry_shader");
1437         addExtensionPrerequisite("GL_EXT_primitive_bounding_box");
1438         addExtensionPrerequisite("GL_EXT_tessellation_shader");
1439         addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
1440         addExtensionPrerequisite("GL_EXT_texture_cube_map_array");
1441     }
1442 
1443     if (traceNameIs("pokemon_masters_ex"))
1444     {
1445         if (isIntelLinux)
1446         {
1447             skipTest(
1448                 "https://issuetracker.google.com/u/2/issues/326199738#comment3 Renders incorrectly "
1449                 "on Intel Linux");
1450         }
1451     }
1452 
1453     if (traceNameIs("aztec_ruins_high"))
1454     {
1455         addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
1456     }
1457 
1458     if (traceNameIs("special_forces_group_2"))
1459     {
1460         addExtensionPrerequisite("GL_EXT_texture_buffer");
1461     }
1462 
1463     if (traceNameIs("tessellation"))
1464     {
1465         if (isNVIDIAWinANGLE || isNVIDIALinuxANGLE)
1466         {
1467             skipTest("http://anglebug.com/7240 Tessellation driver bugs on Nvidia");
1468         }
1469 
1470         addExtensionPrerequisite("GL_EXT_geometry_shader");
1471         addExtensionPrerequisite("GL_EXT_primitive_bounding_box");
1472         addExtensionPrerequisite("GL_EXT_tessellation_shader");
1473         addExtensionPrerequisite("GL_EXT_texture_cube_map_array");
1474     }
1475 
1476     if (traceNameIs("basemark_gpu"))
1477     {
1478         addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
1479     }
1480 
1481     if (traceNameIs("mortal_kombat"))
1482     {
1483         addExtensionPrerequisite("GL_EXT_texture_buffer");
1484     }
1485 
1486     if (traceNameIs("ni_no_kuni"))
1487     {
1488         addExtensionPrerequisite("GL_EXT_shader_framebuffer_fetch");
1489         addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
1490     }
1491 
1492     if (traceNameIs("octopath_traveler"))
1493     {
1494         addExtensionPrerequisite("GL_EXT_shader_framebuffer_fetch");
1495         addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
1496     }
1497 
1498     if (traceNameIs("antutu_refinery"))
1499     {
1500         if (isIntelLinuxANGLE || isAMDLinuxANGLE)
1501         {
1502             skipTest("https://anglebug.com/342545097 fails on Mesa 23.2.1");
1503         }
1504         addExtensionPrerequisite("GL_ANDROID_extension_pack_es31a");
1505     }
1506 
1507     if (traceNameIs("botworld_adventure"))
1508     {
1509         addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
1510     }
1511 
1512     if (traceNameIs("eve_echoes"))
1513     {
1514         if (IsQualcomm() && mParams->isVulkan())
1515         {
1516             skipTest("TODO: http://anglebug.com/7690 Test crashes in LLVM on Qualcomm (Pixel 4)");
1517         }
1518     }
1519 
1520     if (traceNameIs("life_is_strange"))
1521     {
1522         if (isNVIDIAWinANGLE)
1523         {
1524             skipTest("http://anglebug.com/7723 Renders incorrectly on Nvidia Windows");
1525         }
1526 
1527         addExtensionPrerequisite("GL_EXT_texture_buffer");
1528         addExtensionPrerequisite("GL_EXT_texture_cube_map_array");
1529     }
1530 
1531     if (traceNameIs("survivor_io"))
1532     {
1533         if (isNVIDIAWinANGLE)
1534         {
1535             skipTest("http://anglebug.com/7733 Renders incorrectly on Nvidia Windows");
1536         }
1537 
1538         if (isIntelWinNative)
1539         {
1540             skipTest(
1541                 "http://anglebug.com/7737 Programs fail to link on Intel Windows native driver, "
1542                 "citing MAX_UNIFORM_LOCATIONS exceeded");
1543         }
1544     }
1545 
1546     if (traceNameIs("minetest"))
1547     {
1548         if (isIntelLinuxNative)
1549         {
1550             skipTest("https://anglebug.com/8682 fails on newer OS/driver");
1551         }
1552         addExtensionPrerequisite("GL_EXT_texture_format_BGRA8888");
1553         addIntegerPrerequisite(GL_MAX_TEXTURE_UNITS, 4);
1554     }
1555 
1556     if (traceNameIs("diablo_immortal"))
1557     {
1558         addExtensionPrerequisite("GL_EXT_shader_framebuffer_fetch");
1559     }
1560 
1561     if (traceNameIs("mu_origin_3"))
1562     {
1563         addExtensionPrerequisite("GL_EXT_texture_buffer");
1564         addExtensionPrerequisite("GL_EXT_shader_framebuffer_fetch");
1565         addExtensionPrerequisite("GL_OES_EGL_image_external");
1566     }
1567 
1568     if (traceNameIs("catalyst_black"))
1569     {
1570         addExtensionPrerequisite("GL_EXT_shader_framebuffer_fetch");
1571     }
1572 
1573     if (traceNameIs("five_nights_at_freddys"))
1574     {
1575         if (isIntelWinANGLE)
1576         {
1577             skipTest("http://anglebug.com/7929 Too slow on Win Intel Vulkan");
1578         }
1579     }
1580 
1581     if (traceNameIs("pubg_mobile_launch"))
1582     {
1583         if (isIntelWinNative || isIntelWinANGLE)
1584         {
1585             skipTest("http://anglebug.com/7929 Too slow on Win Intel native and Vulkan");
1586         }
1587     }
1588 
1589     if (traceNameIs("beach_buggy_racing"))
1590     {
1591         if (isIntelWinANGLE)
1592         {
1593             skipTest("http://anglebug.com/7934 Flaky context lost on Win Intel Vulkan");
1594         }
1595     }
1596 
1597     if (traceNameIs("aliexpress"))
1598     {
1599         if (isIntelWinNative)
1600         {
1601             skipTest("http://anglebug.com/7934 Flaky failure on Win Intel native");
1602         }
1603     }
1604 
1605     if (traceNameIs("final_fantasy"))
1606     {
1607         if (IsAndroid() && IsPixel6() && !mParams->isANGLE())
1608         {
1609             skipTest("http://anglebug.com/7936 Crashes on Pixel 6 native");
1610         }
1611     }
1612 
1613     if (traceNameIs("limbo"))
1614     {
1615         addExtensionPrerequisite("GL_EXT_shader_framebuffer_fetch");
1616 
1617         // For LUMINANCE8_ALPHA8_EXT
1618         addExtensionPrerequisite("GL_EXT_texture_storage");
1619     }
1620 
1621     if (traceNameIs("into_the_dead_2"))
1622     {
1623         if (isNVIDIAWinANGLE)
1624         {
1625             skipTest("http://anglebug.com/8042 Non-deterministic trace");
1626         }
1627     }
1628 
1629     if (traceNameIs("arknights"))
1630     {
1631         // Intel doesn't support external images.
1632         addExtensionPrerequisite("GL_OES_EGL_image_external");
1633     }
1634 
1635     if (traceNameIs("street_fighter_duel"))
1636     {
1637         if (isNVIDIAWinANGLE)
1638         {
1639             skipTest("https://anglebug.com/8074 NVIDIA Windows flaky diffs");
1640         }
1641     }
1642 
1643     if (traceNameIs("honkai_star_rail"))
1644     {
1645         addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
1646         if (isIntelWin)
1647         {
1648             skipTest("https://anglebug.com/8175 Consistently stuck on Intel/windows");
1649         }
1650     }
1651 
1652     if (traceNameIs("gangstar_vegas"))
1653     {
1654         if (mParams->isSwiftshader())
1655         {
1656             skipTest("TODO: http://anglebug.com/8173 Missing shadows on Swiftshader");
1657         }
1658     }
1659 
1660     if (traceNameIs("respawnables"))
1661     {
1662         if (!mParams->isANGLE() && (IsWindows() || IsLinux()))
1663         {
1664             skipTest("TODO: https://anglebug.com/8191 Undefined behavior on native");
1665         }
1666     }
1667 
1668     if (traceNameIs("street_fighter_iv_ce"))
1669     {
1670         if (isIntelLinuxNative)
1671         {
1672             skipTest("https://anglebug.com/8682 fails on newer OS/driver");
1673         }
1674 
1675         if (mParams->isSwiftshader())
1676         {
1677             skipTest("https://anglebug.com/8243 Too slow on Swiftshader (large keyframe)");
1678         }
1679     }
1680 
1681     if (traceNameIs("monster_hunter_stories"))
1682     {
1683         if (isIntelWinANGLE)
1684         {
1685             skipTest("http://anglebug.com/7557 Flaky context lost on Win Intel Vulkan");
1686         }
1687     }
1688 
1689     if (traceNameIs("injustice_2"))
1690     {
1691         if (isNVIDIAWinANGLE)
1692         {
1693             skipTest("https://anglebug.com/8316 NVIDIA Windows flaky diffs");
1694         }
1695     }
1696 
1697     if (traceNameIs("toca_life_world"))
1698     {
1699         addExtensionPrerequisite("GL_OES_EGL_image_external");
1700     }
1701 
1702     if (traceNameIs("poppy_playtime"))
1703     {
1704         addExtensionPrerequisite("GL_OES_EGL_image_external");
1705         addIntegerPrerequisite(GL_MAX_TEXTURE_SIZE, 16383);
1706     }
1707 
1708     if (traceNameIs("dr_driving"))
1709     {
1710         if (isIntelLinuxNative)
1711         {
1712             skipTest("https://anglebug.com/8682 fails on newer OS/driver");
1713         }
1714     }
1715 
1716     if (traceNameIs("plague_inc"))
1717     {
1718         if (isIntelLinuxNative)
1719         {
1720             skipTest("https://anglebug.com/8682 fails on newer OS/driver");
1721         }
1722     }
1723 
1724     if (traceNameIs("sonic_the_hedgehog"))
1725     {
1726         if (isIntelLinuxNative)
1727         {
1728             skipTest("https://anglebug.com/8682 fails on newer OS/driver");
1729         }
1730     }
1731 
1732     if (traceNameIs("wayward_souls"))
1733     {
1734         if (isIntelLinuxNative)
1735         {
1736             skipTest("https://anglebug.com/8682 fails on newer OS/driver");
1737         }
1738     }
1739 
1740     if (traceNameIs("wordscapes"))
1741     {
1742         if (isIntelLinuxNative)
1743         {
1744             skipTest("https://anglebug.com/8682 fails on newer OS/driver");
1745         }
1746     }
1747 
1748     if (traceNameIs("zenonia_4"))
1749     {
1750         if (isIntelLinuxNative)
1751         {
1752             skipTest("https://anglebug.com/8682 fails on newer OS/driver");
1753         }
1754     }
1755 
1756     if (traceNameIs("zombie_smasher"))
1757     {
1758         if (isIntelLinuxNative)
1759         {
1760             skipTest("https://anglebug.com/8682 fails on newer OS/driver");
1761         }
1762     }
1763 
1764     if (traceNameIs("modern_combat_5"))
1765     {
1766         if (IsPixel6() && !IsAndroid14OrNewer())
1767         {
1768             skipTest(
1769                 "https://issuetracker.google.com/42267261 Causing thermal failures on Pixel 6 with "
1770                 "Android 13");
1771         }
1772     }
1773 
1774     if (IsGalaxyS22())
1775     {
1776         if (traceNameIs("cod_mobile") || traceNameIs("dota_underlords") ||
1777             traceNameIs("marvel_snap") || traceNameIs("nier_reincarnation") ||
1778             traceNameIs("pokemon_unite") || traceNameIs("slingshot_test1") ||
1779             traceNameIs("slingshot_test2") || traceNameIs("supertuxkart") ||
1780             traceNameIs("the_witcher_monster_slayer") || traceNameIs("warcraft_rumble"))
1781         {
1782             skipTest("https://issuetracker.google.com/267953710 Trace needs triage on Galaxy S22");
1783         }
1784     }
1785 
1786     // glDebugMessageControlKHR and glDebugMessageCallbackKHR crash on ARM GLES1.
1787     if (IsARM() && mParams->traceInfo.contextClientMajorVersion == 1)
1788     {
1789         mEnableDebugCallback = false;
1790     }
1791 
1792     // We already swap in TracePerfTest::drawBenchmark, no need to swap again in the harness.
1793     disableTestHarnessSwap();
1794 
1795     gCurrentTracePerfTest = this;
1796 
1797     if (gTraceTestValidation)
1798     {
1799         mStepsToRun = frameCount();
1800     }
1801 
1802     if (gRunToKeyFrame)
1803     {
1804         if (mParams->traceInfo.keyFrames.empty())
1805         {
1806             // If we don't have a keyFrame, run one step
1807             INFO() << "No keyframe available for trace, running to frame 1";
1808             mStepsToRun = 1;
1809         }
1810         else
1811         {
1812             int keyFrame = mParams->traceInfo.keyFrames[0];
1813             INFO() << "Running to keyframe: " << keyFrame;
1814             mStepsToRun = keyFrame;
1815         }
1816     }
1817 }
1818 
startTest()1819 void TracePerfTest::startTest()
1820 {
1821     // runTrial() must align to frameCount()
1822     ASSERT(mCurrentFrame == mStartFrame);
1823 }
1824 
FindTraceGzPath(const std::string & traceName)1825 std::string FindTraceGzPath(const std::string &traceName)
1826 {
1827     std::stringstream pathStream;
1828 
1829     char genDir[kMaxPath] = {};
1830     if (!angle::FindTestDataPath("gen", genDir, kMaxPath))
1831     {
1832         return "";
1833     }
1834     pathStream << genDir << angle::GetPathSeparator() << "tracegz_" << traceName << ".gz";
1835 
1836     return pathStream.str();
1837 }
1838 
initializeBenchmark()1839 void TracePerfTest::initializeBenchmark()
1840 {
1841     const TraceInfo &traceInfo = mParams->traceInfo;
1842 
1843     char testDataDir[kMaxPath] = {};
1844     if (!FindTraceTestDataPath(traceInfo.name, testDataDir, kMaxPath))
1845     {
1846         failTest("Could not find test data folder.");
1847         return;
1848     }
1849 
1850     if (gTraceInterpreter)
1851     {
1852         mTraceReplay.reset(new TraceLibrary("angle_trace_interpreter", traceInfo));
1853         if (strcmp(gTraceInterpreter, "gz") == 0)
1854         {
1855             std::string traceGzPath = FindTraceGzPath(traceInfo.name);
1856             if (traceGzPath.empty())
1857             {
1858                 failTest("Could not find trace gz.");
1859                 return;
1860             }
1861             mTraceReplay->setTraceGzPath(traceGzPath);
1862         }
1863     }
1864     else
1865     {
1866         std::stringstream traceNameStr;
1867         traceNameStr << "angle_restricted_traces_" << traceInfo.name;
1868         std::string traceName = traceNameStr.str();
1869         mTraceReplay.reset(new TraceLibrary(traceNameStr.str(), traceInfo));
1870     }
1871 
1872     LoadTraceEGL(TraceLoadProc);
1873     LoadTraceGLES(TraceLoadProc);
1874 
1875     if (!mTraceReplay->valid())
1876     {
1877         failTest("Could not load trace.");
1878         return;
1879     }
1880 
1881     mStartFrame = traceInfo.frameStart;
1882     mEndFrame   = traceInfo.frameEnd;
1883     mTraceReplay->setValidateSerializedStateCallback(ValidateSerializedState);
1884     mTraceReplay->setBinaryDataDir(testDataDir);
1885     mTraceReplay->setReplayResourceMode(gIncludeInactiveResources);
1886     if (gScreenshotDir)
1887     {
1888         mTraceReplay->setDebugOutputDir(gScreenshotDir);
1889     }
1890 
1891     if (gMinimizeGPUWork)
1892     {
1893         // Shrink the offscreen window to 1x1.
1894         mWindowWidth  = 1;
1895         mWindowHeight = 1;
1896     }
1897     else
1898     {
1899         mWindowWidth  = mTestParams.windowWidth;
1900         mWindowHeight = mTestParams.windowHeight;
1901     }
1902     mCurrentFrame     = mStartFrame;
1903     mCurrentIteration = mStartFrame;
1904 
1905     if (IsAndroid())
1906     {
1907         // On Android, set the orientation used by the app, based on width/height
1908         getWindow()->setOrientation(mTestParams.windowWidth, mTestParams.windowHeight);
1909     }
1910 
1911     // If we're rendering offscreen we set up a default back buffer.
1912     if (mParams->surfaceType == SurfaceType::Offscreen)
1913     {
1914         if (!IsAndroid())
1915         {
1916             mWindowWidth *= 4;
1917             mWindowHeight *= 4;
1918         }
1919 
1920         glGenRenderbuffers(1, &mOffscreenDepthStencil);
1921         glBindRenderbuffer(GL_RENDERBUFFER, mOffscreenDepthStencil);
1922         glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, mWindowWidth, mWindowHeight);
1923         glBindRenderbuffer(GL_RENDERBUFFER, 0);
1924 
1925         glGenFramebuffers(mMaxOffscreenBufferCount, mOffscreenFramebuffers.data());
1926         glGenTextures(mMaxOffscreenBufferCount, mOffscreenTextures.data());
1927         for (int i = 0; i < mMaxOffscreenBufferCount; i++)
1928         {
1929             glBindFramebuffer(GL_FRAMEBUFFER, mOffscreenFramebuffers[i]);
1930 
1931             // Hard-code RGBA8/D24S8. This should be specified in the trace info.
1932             glBindTexture(GL_TEXTURE_2D, mOffscreenTextures[i]);
1933             glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, mWindowWidth, mWindowHeight, 0, GL_RGBA,
1934                          GL_UNSIGNED_BYTE, nullptr);
1935 
1936             glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
1937                                    mOffscreenTextures[i], 0);
1938             glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER,
1939                                       mOffscreenDepthStencil);
1940             glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
1941                                       mOffscreenDepthStencil);
1942             glBindTexture(GL_TEXTURE_2D, 0);
1943         }
1944     }
1945 
1946     // Potentially slow. Can load a lot of resources.
1947     mTraceReplay->setupReplay();
1948 
1949     glFinish();
1950 
1951     ASSERT_GE(mEndFrame, mStartFrame);
1952 
1953     getWindow()->ignoreSizeEvents();
1954     getWindow()->setVisible(true);
1955 
1956     // If we're re-tracing, trigger capture start after setup. This ensures the Setup function gets
1957     // recaptured into another Setup function and not merged with the first frame.
1958     if (gRetraceMode)
1959     {
1960         getGLWindow()->swap();
1961     }
1962 }
1963 
1964 #undef TRACE_TEST_CASE
1965 
destroyBenchmark()1966 void TracePerfTest::destroyBenchmark()
1967 {
1968     if (mParams->surfaceType == SurfaceType::Offscreen)
1969     {
1970         glDeleteTextures(mMaxOffscreenBufferCount, mOffscreenTextures.data());
1971         mOffscreenTextures.fill(0);
1972 
1973         glDeleteRenderbuffers(1, &mOffscreenDepthStencil);
1974         mOffscreenDepthStencil = 0;
1975 
1976         glDeleteFramebuffers(mMaxOffscreenBufferCount, mOffscreenFramebuffers.data());
1977         mOffscreenFramebuffers.fill(0);
1978     }
1979 
1980     mTraceReplay->finishReplay();
1981     mTraceReplay.reset(nullptr);
1982 }
1983 
sampleTime()1984 void TracePerfTest::sampleTime()
1985 {
1986     if (mUseTimestampQueries)
1987     {
1988         GLint64 glTime;
1989         // glGetInteger64vEXT is exported by newer versions of the timer query extensions.
1990         // Unfortunately only the core EP is exposed by some desktop drivers (e.g. NVIDIA).
1991         if (glGetInteger64vEXT)
1992         {
1993             glGetInteger64vEXT(GL_TIMESTAMP_EXT, &glTime);
1994         }
1995         else
1996         {
1997             glGetInteger64v(GL_TIMESTAMP_EXT, &glTime);
1998         }
1999         mTimeline.push_back({glTime, angle::GetHostTimeSeconds()});
2000     }
2001 }
2002 
drawBenchmark()2003 void TracePerfTest::drawBenchmark()
2004 {
2005     constexpr uint32_t kFramesPerX  = 6;
2006     constexpr uint32_t kFramesPerY  = 4;
2007     constexpr uint32_t kFramesPerXY = kFramesPerY * kFramesPerX;
2008 
2009     const uint32_t kOffscreenOffsetX =
2010         static_cast<uint32_t>(static_cast<double>(mTestParams.windowWidth) / 3.0f);
2011     const uint32_t kOffscreenOffsetY =
2012         static_cast<uint32_t>(static_cast<double>(mTestParams.windowHeight) / 3.0f);
2013     const uint32_t kOffscreenWidth  = kOffscreenOffsetX;
2014     const uint32_t kOffscreenHeight = kOffscreenOffsetY;
2015 
2016     const uint32_t kOffscreenFrameWidth = static_cast<uint32_t>(
2017         static_cast<double>(kOffscreenWidth / static_cast<double>(kFramesPerX)));
2018     const uint32_t kOffscreenFrameHeight = static_cast<uint32_t>(
2019         static_cast<double>(kOffscreenHeight / static_cast<double>(kFramesPerY)));
2020 
2021     // Add a time sample from GL and the host.
2022     if (mCurrentFrame == mStartFrame)
2023     {
2024         sampleTime();
2025     }
2026 
2027     if (mParams->surfaceType == SurfaceType::Offscreen)
2028     {
2029         // Some driver (ARM and ANGLE) try to nop or defer the glFlush if it is called within the
2030         // renderpass to avoid breaking renderpass (performance reason). For app traces that does
2031         // not use any FBO, when we run in the offscreen mode, there is no frame boundary and
2032         // glFlush call we issued at end of frame will get skipped. To overcome this (and also
2033         // matches what onscreen double buffering behavior as well), we use two offscreen FBOs and
2034         // ping pong between them for each frame.
2035         glBindFramebuffer(GL_FRAMEBUFFER,
2036                           mOffscreenFramebuffers[mTotalFrameCount % mMaxOffscreenBufferCount]);
2037     }
2038 
2039     char frameName[32];
2040     snprintf(frameName, sizeof(frameName), "Frame %u", mCurrentFrame);
2041     beginInternalTraceEvent(frameName);
2042 
2043     startGpuTimer();
2044     mTraceReplay->replayFrame(mCurrentFrame);
2045     stopGpuTimer();
2046 
2047     updatePerfCounters();
2048 
2049     if (mParams->surfaceType == SurfaceType::Offscreen)
2050     {
2051         if (gMinimizeGPUWork)
2052         {
2053             // To keep GPU work minimum, we skip the blit.
2054             glFlush();
2055             mOffscreenFrameCount++;
2056         }
2057         else
2058         {
2059             GLint currentDrawFBO, currentReadFBO;
2060             glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &currentDrawFBO);
2061             glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &currentReadFBO);
2062 
2063             glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
2064             glBindFramebuffer(
2065                 GL_READ_FRAMEBUFFER,
2066                 mOffscreenFramebuffers[mOffscreenFrameCount % mMaxOffscreenBufferCount]);
2067 
2068             uint32_t frameX  = (mOffscreenFrameCount % kFramesPerXY) % kFramesPerX;
2069             uint32_t frameY  = (mOffscreenFrameCount % kFramesPerXY) / kFramesPerX;
2070             uint32_t windowX = kOffscreenOffsetX + frameX * kOffscreenFrameWidth;
2071             uint32_t windowY = kOffscreenOffsetY + frameY * kOffscreenFrameHeight;
2072 
2073             GLboolean scissorTest = GL_FALSE;
2074             glGetBooleanv(GL_SCISSOR_TEST, &scissorTest);
2075 
2076             if (scissorTest)
2077             {
2078                 glDisable(GL_SCISSOR_TEST);
2079             }
2080 
2081             glBlitFramebuffer(0, 0, mWindowWidth, mWindowHeight, windowX, windowY,
2082                               windowX + kOffscreenFrameWidth, windowY + kOffscreenFrameHeight,
2083                               GL_COLOR_BUFFER_BIT, GL_NEAREST);
2084 
2085             if (frameX == kFramesPerX - 1 && frameY == kFramesPerY - 1)
2086             {
2087                 swap();
2088                 glBindFramebuffer(GL_FRAMEBUFFER, 0);
2089                 glClear(GL_COLOR_BUFFER_BIT);
2090                 mOffscreenFrameCount = 0;
2091             }
2092             else
2093             {
2094                 glFlush();
2095                 mOffscreenFrameCount++;
2096             }
2097 
2098             if (scissorTest)
2099             {
2100                 glEnable(GL_SCISSOR_TEST);
2101             }
2102             glBindFramebuffer(GL_DRAW_FRAMEBUFFER, currentDrawFBO);
2103             glBindFramebuffer(GL_READ_FRAMEBUFFER, currentReadFBO);
2104         }
2105 
2106         mTotalFrameCount++;
2107     }
2108     else
2109     {
2110         swap();
2111     }
2112 
2113     endInternalTraceEvent(frameName);
2114 
2115     if (mCurrentFrame == mEndFrame)
2116     {
2117         mTraceReplay->resetReplay();
2118         mCurrentFrame = mStartFrame;
2119     }
2120     else
2121     {
2122         mCurrentFrame++;
2123     }
2124 
2125     // Always iterated for saving screenshots after reset
2126     mCurrentIteration++;
2127 
2128     // Process any running queries once per iteration.
2129     for (size_t queryIndex = 0; queryIndex < mRunningQueries.size();)
2130     {
2131         const QueryInfo &query = mRunningQueries[queryIndex];
2132 
2133         GLuint endResultAvailable = 0;
2134         glGetQueryObjectuivEXT(query.endTimestampQuery, GL_QUERY_RESULT_AVAILABLE,
2135                                &endResultAvailable);
2136 
2137         if (endResultAvailable == GL_TRUE)
2138         {
2139             char fboName[32];
2140             snprintf(fboName, sizeof(fboName), "FBO %u", query.framebuffer);
2141 
2142             GLint64 beginTimestamp = 0;
2143             glGetQueryObjecti64vEXT(query.beginTimestampQuery, GL_QUERY_RESULT, &beginTimestamp);
2144             glDeleteQueriesEXT(1, &query.beginTimestampQuery);
2145             double beginHostTime = getHostTimeFromGLTime(beginTimestamp);
2146             beginGLTraceEvent(fboName, beginHostTime);
2147 
2148             GLint64 endTimestamp = 0;
2149             glGetQueryObjecti64vEXT(query.endTimestampQuery, GL_QUERY_RESULT, &endTimestamp);
2150             glDeleteQueriesEXT(1, &query.endTimestampQuery);
2151             double endHostTime = getHostTimeFromGLTime(endTimestamp);
2152             endGLTraceEvent(fboName, endHostTime);
2153 
2154             mRunningQueries.erase(mRunningQueries.begin() + queryIndex);
2155         }
2156         else
2157         {
2158             queryIndex++;
2159         }
2160     }
2161 }
2162 
2163 // Converts a GL timestamp into a host-side CPU time aligned with "GetHostTimeSeconds".
2164 // This check is necessary to line up sampled trace events in a consistent timeline.
2165 // Uses a linear interpolation from a series of samples. We do a blocking call to sample
2166 // both host and GL time once per swap. We then find the two closest GL timestamps and
2167 // interpolate the host times between them to compute our result. If we are past the last
2168 // GL timestamp we sample a new data point pair.
getHostTimeFromGLTime(GLint64 glTime)2169 double TracePerfTest::getHostTimeFromGLTime(GLint64 glTime)
2170 {
2171     // Find two samples to do a lerp.
2172     size_t firstSampleIndex = mTimeline.size() - 1;
2173     while (firstSampleIndex > 0)
2174     {
2175         if (mTimeline[firstSampleIndex].glTime < glTime)
2176         {
2177             break;
2178         }
2179         firstSampleIndex--;
2180     }
2181 
2182     // Add an extra sample if we're missing an ending sample.
2183     if (firstSampleIndex == mTimeline.size() - 1)
2184     {
2185         sampleTime();
2186     }
2187 
2188     const TimeSample &start = mTimeline[firstSampleIndex];
2189     const TimeSample &end   = mTimeline[firstSampleIndex + 1];
2190 
2191     // Note: we have observed in some odd cases later timestamps producing values that are
2192     // smaller than preceding timestamps. This bears further investigation.
2193 
2194     // Compute the scaling factor for the lerp.
2195     double glDelta = static_cast<double>(glTime - start.glTime);
2196     double glRange = static_cast<double>(end.glTime - start.glTime);
2197     double t       = glDelta / glRange;
2198 
2199     // Lerp(t1, t2, t)
2200     double hostRange = end.hostTime - start.hostTime;
2201     return mTimeline[firstSampleIndex].hostTime + hostRange * t;
2202 }
2203 
onEglCreateContext(EGLDisplay display,EGLConfig config,EGLContext share_context,EGLint const * attrib_list)2204 EGLContext TracePerfTest::onEglCreateContext(EGLDisplay display,
2205                                              EGLConfig config,
2206                                              EGLContext share_context,
2207                                              EGLint const *attrib_list)
2208 {
2209     GLWindowContext newContext =
2210         getGLWindow()->createContextGeneric(reinterpret_cast<GLWindowContext>(share_context));
2211     return reinterpret_cast<EGLContext>(newContext);
2212 }
2213 
onEglMakeCurrent(EGLDisplay display,EGLSurface draw,EGLSurface read,EGLContext context)2214 void TracePerfTest::onEglMakeCurrent(EGLDisplay display,
2215                                      EGLSurface draw,
2216                                      EGLSurface read,
2217                                      EGLContext context)
2218 {
2219     getGLWindow()->makeCurrentGeneric(reinterpret_cast<GLWindowContext>(context));
2220 }
2221 
onEglGetCurrentContext()2222 EGLContext TracePerfTest::onEglGetCurrentContext()
2223 {
2224     return getGLWindow()->getCurrentContextGeneric();
2225 }
2226 
onEglCreateImage(EGLDisplay display,EGLContext context,EGLenum target,EGLClientBuffer buffer,const EGLAttrib * attrib_list)2227 EGLImage TracePerfTest::onEglCreateImage(EGLDisplay display,
2228                                          EGLContext context,
2229                                          EGLenum target,
2230                                          EGLClientBuffer buffer,
2231                                          const EGLAttrib *attrib_list)
2232 {
2233     GLWindowBase::Image image = getGLWindow()->createImage(
2234         reinterpret_cast<GLWindowContext>(context), target, buffer, attrib_list);
2235     return reinterpret_cast<EGLImage>(image);
2236 }
2237 
onEglCreateImageKHR(EGLDisplay display,EGLContext context,EGLenum target,EGLClientBuffer buffer,const EGLint * attrib_list)2238 EGLImageKHR TracePerfTest::onEglCreateImageKHR(EGLDisplay display,
2239                                                EGLContext context,
2240                                                EGLenum target,
2241                                                EGLClientBuffer buffer,
2242                                                const EGLint *attrib_list)
2243 {
2244     GLWindowBase::Image image = getGLWindow()->createImageKHR(
2245         reinterpret_cast<GLWindowContext>(context), target, buffer, attrib_list);
2246     return reinterpret_cast<EGLImage>(image);
2247 }
2248 
onEglDestroyImage(EGLDisplay display,EGLImage image)2249 EGLBoolean TracePerfTest::onEglDestroyImage(EGLDisplay display, EGLImage image)
2250 {
2251     return getGLWindow()->destroyImage(image);
2252 }
2253 
onEglDestroyImageKHR(EGLDisplay display,EGLImage image)2254 EGLBoolean TracePerfTest::onEglDestroyImageKHR(EGLDisplay display, EGLImage image)
2255 {
2256     return getGLWindow()->destroyImageKHR(image);
2257 }
2258 
onEglCreateSync(EGLDisplay dpy,EGLenum type,const EGLAttrib * attrib_list)2259 EGLSync TracePerfTest::onEglCreateSync(EGLDisplay dpy, EGLenum type, const EGLAttrib *attrib_list)
2260 {
2261     return getGLWindow()->createSync(dpy, type, attrib_list);
2262 }
2263 
onEglCreateSyncKHR(EGLDisplay dpy,EGLenum type,const EGLint * attrib_list)2264 EGLSync TracePerfTest::onEglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list)
2265 {
2266     return getGLWindow()->createSyncKHR(dpy, type, attrib_list);
2267 }
2268 
onEglDestroySync(EGLDisplay dpy,EGLSync sync)2269 EGLBoolean TracePerfTest::onEglDestroySync(EGLDisplay dpy, EGLSync sync)
2270 {
2271     return getGLWindow()->destroySync(dpy, sync);
2272 }
2273 
onEglDestroySyncKHR(EGLDisplay dpy,EGLSync sync)2274 EGLBoolean TracePerfTest::onEglDestroySyncKHR(EGLDisplay dpy, EGLSync sync)
2275 {
2276     return getGLWindow()->destroySyncKHR(dpy, sync);
2277 }
2278 
onEglClientWaitSync(EGLDisplay dpy,EGLSync sync,EGLint flags,EGLTimeKHR timeout)2279 EGLint TracePerfTest::onEglClientWaitSync(EGLDisplay dpy,
2280                                           EGLSync sync,
2281                                           EGLint flags,
2282                                           EGLTimeKHR timeout)
2283 {
2284     return getGLWindow()->clientWaitSync(dpy, sync, flags, timeout);
2285 }
2286 
onEglClientWaitSyncKHR(EGLDisplay dpy,EGLSync sync,EGLint flags,EGLTimeKHR timeout)2287 EGLint TracePerfTest::onEglClientWaitSyncKHR(EGLDisplay dpy,
2288                                              EGLSync sync,
2289                                              EGLint flags,
2290                                              EGLTimeKHR timeout)
2291 {
2292     return getGLWindow()->clientWaitSyncKHR(dpy, sync, flags, timeout);
2293 }
2294 
onEglGetError()2295 EGLint TracePerfTest::onEglGetError()
2296 {
2297     return getGLWindow()->getEGLError();
2298 }
2299 
onEglGetCurrentDisplay()2300 EGLDisplay TracePerfTest::onEglGetCurrentDisplay()
2301 {
2302     return getGLWindow()->getCurrentDisplay();
2303 }
2304 
2305 // Triggered when the replay calls glBindFramebuffer.
onReplayFramebufferChange(GLenum target,GLuint framebuffer)2306 void TracePerfTest::onReplayFramebufferChange(GLenum target, GLuint framebuffer)
2307 {
2308     if (framebuffer == 0 && mParams->surfaceType == SurfaceType::Offscreen)
2309     {
2310         glBindFramebuffer(target,
2311                           mOffscreenFramebuffers[mTotalFrameCount % mMaxOffscreenBufferCount]);
2312     }
2313     else
2314     {
2315         glBindFramebuffer(target, framebuffer);
2316     }
2317 
2318     switch (target)
2319     {
2320         case GL_FRAMEBUFFER:
2321             mDrawFramebufferBinding = framebuffer;
2322             mReadFramebufferBinding = framebuffer;
2323             break;
2324         case GL_DRAW_FRAMEBUFFER:
2325             mDrawFramebufferBinding = framebuffer;
2326             break;
2327         case GL_READ_FRAMEBUFFER:
2328             mReadFramebufferBinding = framebuffer;
2329             return;
2330 
2331         default:
2332             UNREACHABLE();
2333             break;
2334     }
2335 
2336     if (!mUseTimestampQueries)
2337         return;
2338 
2339     // We have at most one active timestamp query at a time. This code will end the current
2340     // query and immediately start a new one.
2341     if (mCurrentQuery.beginTimestampQuery != 0)
2342     {
2343         glGenQueriesEXT(1, &mCurrentQuery.endTimestampQuery);
2344         glQueryCounterEXT(mCurrentQuery.endTimestampQuery, GL_TIMESTAMP_EXT);
2345         mRunningQueries.push_back(mCurrentQuery);
2346         mCurrentQuery = {};
2347     }
2348 
2349     ASSERT(mCurrentQuery.beginTimestampQuery == 0);
2350 
2351     glGenQueriesEXT(1, &mCurrentQuery.beginTimestampQuery);
2352     glQueryCounterEXT(mCurrentQuery.beginTimestampQuery, GL_TIMESTAMP_EXT);
2353     mCurrentQuery.framebuffer = framebuffer;
2354 }
2355 
GetDiffPath()2356 std::string GetDiffPath()
2357 {
2358 #if defined(ANGLE_PLATFORM_WINDOWS)
2359     std::array<char, MAX_PATH> filenameBuffer = {};
2360     char *filenamePtr                         = nullptr;
2361     if (SearchPathA(NULL, "diff", ".exe", MAX_PATH, filenameBuffer.data(), &filenamePtr) == 0)
2362     {
2363         return "";
2364     }
2365     return std::string(filenameBuffer.data());
2366 #else
2367     return "/usr/bin/diff";
2368 #endif  // defined(ANGLE_PLATFORM_WINDOWS)
2369 }
2370 
PrintFileDiff(const char * aFilePath,const char * bFilePath)2371 void PrintFileDiff(const char *aFilePath, const char *bFilePath)
2372 {
2373     std::string pathToDiff = GetDiffPath();
2374     if (pathToDiff.empty())
2375     {
2376         printf("Could not find diff in the path.\n");
2377         return;
2378     }
2379 
2380     std::vector<const char *> args;
2381     args.push_back(pathToDiff.c_str());
2382     args.push_back(aFilePath);
2383     args.push_back(bFilePath);
2384     args.push_back("-u3");
2385 
2386     printf("Calling");
2387     for (const char *arg : args)
2388     {
2389         printf(" %s", arg);
2390     }
2391     printf("\n");
2392 
2393     ProcessHandle proc(LaunchProcess(args, ProcessOutputCapture::StdoutOnly));
2394     if (proc && proc->finish())
2395     {
2396         printf("\n%s\n", proc->getStdout().c_str());
2397     }
2398 }
2399 
validateSerializedState(const char * expectedCapturedSerializedState,const char * fileName,uint32_t line)2400 void TracePerfTest::validateSerializedState(const char *expectedCapturedSerializedState,
2401                                             const char *fileName,
2402                                             uint32_t line)
2403 {
2404     if (!gTraceTestValidation)
2405     {
2406         return;
2407     }
2408 
2409     printf("Serialization checkpoint %s:%u...\n", fileName, line);
2410 
2411     const GLubyte *bytes                      = glGetString(GL_SERIALIZED_CONTEXT_STRING_ANGLE);
2412     const char *actualReplayedSerializedState = reinterpret_cast<const char *>(bytes);
2413     if (strcmp(expectedCapturedSerializedState, actualReplayedSerializedState) == 0)
2414     {
2415         printf("Serialization match.\n");
2416         return;
2417     }
2418 
2419     GTEST_NONFATAL_FAILURE_("Serialization mismatch!");
2420 
2421     const Optional<std::string> aFilePath = CreateTemporaryFile();
2422     const char *aFilePathCStr             = aFilePath.value().c_str();
2423     if (aFilePath.valid())
2424     {
2425         printf("Saving \"expected\" capture serialization to \"%s\".\n", aFilePathCStr);
2426         FILE *fpA = fopen(aFilePathCStr, "wt");
2427         ASSERT(fpA);
2428         fprintf(fpA, "%s", expectedCapturedSerializedState);
2429         fclose(fpA);
2430     }
2431 
2432     const Optional<std::string> bFilePath = CreateTemporaryFile();
2433     const char *bFilePathCStr             = bFilePath.value().c_str();
2434     if (bFilePath.valid())
2435     {
2436         printf("Saving \"actual\" replay serialization to \"%s\".\n", bFilePathCStr);
2437         FILE *fpB = fopen(bFilePathCStr, "wt");
2438         ASSERT(fpB);
2439         fprintf(fpB, "%s", actualReplayedSerializedState);
2440         fclose(fpB);
2441     }
2442 
2443     PrintFileDiff(aFilePathCStr, bFilePathCStr);
2444 }
2445 
isDefaultFramebuffer(GLenum target) const2446 bool TracePerfTest::isDefaultFramebuffer(GLenum target) const
2447 {
2448     switch (target)
2449     {
2450         case GL_FRAMEBUFFER:
2451         case GL_DRAW_FRAMEBUFFER:
2452             return (mDrawFramebufferBinding == 0);
2453 
2454         case GL_READ_FRAMEBUFFER:
2455             return (mReadFramebufferBinding == 0);
2456 
2457         default:
2458             UNREACHABLE();
2459             return false;
2460     }
2461 }
2462 
ConvertDefaultFramebufferEnum(GLenum value)2463 GLenum ConvertDefaultFramebufferEnum(GLenum value)
2464 {
2465     switch (value)
2466     {
2467         case GL_NONE:
2468             return GL_NONE;
2469         case GL_BACK:
2470         case GL_COLOR:
2471             return GL_COLOR_ATTACHMENT0;
2472         case GL_DEPTH:
2473             return GL_DEPTH_ATTACHMENT;
2474         case GL_STENCIL:
2475             return GL_STENCIL_ATTACHMENT;
2476         case GL_DEPTH_STENCIL:
2477             return GL_DEPTH_STENCIL_ATTACHMENT;
2478         default:
2479             UNREACHABLE();
2480             return GL_NONE;
2481     }
2482 }
2483 
ConvertDefaultFramebufferEnums(GLsizei numAttachments,const GLenum * attachments)2484 std::vector<GLenum> ConvertDefaultFramebufferEnums(GLsizei numAttachments,
2485                                                    const GLenum *attachments)
2486 {
2487     std::vector<GLenum> translatedAttachments;
2488     for (GLsizei attachmentIndex = 0; attachmentIndex < numAttachments; ++attachmentIndex)
2489     {
2490         GLenum converted = ConvertDefaultFramebufferEnum(attachments[attachmentIndex]);
2491         translatedAttachments.push_back(converted);
2492     }
2493     return translatedAttachments;
2494 }
2495 
2496 // Needs special handling to treat the 0 framebuffer in offscreen mode.
onReplayInvalidateFramebuffer(GLenum target,GLsizei numAttachments,const GLenum * attachments)2497 void TracePerfTest::onReplayInvalidateFramebuffer(GLenum target,
2498                                                   GLsizei numAttachments,
2499                                                   const GLenum *attachments)
2500 {
2501     if (mParams->surfaceType != SurfaceType::Offscreen || !isDefaultFramebuffer(target))
2502     {
2503         glInvalidateFramebuffer(target, numAttachments, attachments);
2504     }
2505     else
2506     {
2507         std::vector<GLenum> translatedAttachments =
2508             ConvertDefaultFramebufferEnums(numAttachments, attachments);
2509         glInvalidateFramebuffer(target, numAttachments, translatedAttachments.data());
2510     }
2511 }
2512 
onReplayInvalidateSubFramebuffer(GLenum target,GLsizei numAttachments,const GLenum * attachments,GLint x,GLint y,GLsizei width,GLsizei height)2513 void TracePerfTest::onReplayInvalidateSubFramebuffer(GLenum target,
2514                                                      GLsizei numAttachments,
2515                                                      const GLenum *attachments,
2516                                                      GLint x,
2517                                                      GLint y,
2518                                                      GLsizei width,
2519                                                      GLsizei height)
2520 {
2521     if (mParams->surfaceType != SurfaceType::Offscreen || !isDefaultFramebuffer(target))
2522     {
2523         glInvalidateSubFramebuffer(target, numAttachments, attachments, x, y, width, height);
2524     }
2525     else
2526     {
2527         std::vector<GLenum> translatedAttachments =
2528             ConvertDefaultFramebufferEnums(numAttachments, attachments);
2529         glInvalidateSubFramebuffer(target, numAttachments, translatedAttachments.data(), x, y,
2530                                    width, height);
2531     }
2532 }
2533 
onReplayDrawBuffers(GLsizei n,const GLenum * bufs)2534 void TracePerfTest::onReplayDrawBuffers(GLsizei n, const GLenum *bufs)
2535 {
2536     if (mParams->surfaceType != SurfaceType::Offscreen ||
2537         !isDefaultFramebuffer(GL_DRAW_FRAMEBUFFER))
2538     {
2539         glDrawBuffers(n, bufs);
2540     }
2541     else
2542     {
2543         std::vector<GLenum> translatedBufs = ConvertDefaultFramebufferEnums(n, bufs);
2544         glDrawBuffers(n, translatedBufs.data());
2545     }
2546 }
2547 
onReplayReadBuffer(GLenum src)2548 void TracePerfTest::onReplayReadBuffer(GLenum src)
2549 {
2550     if (mParams->surfaceType != SurfaceType::Offscreen ||
2551         !isDefaultFramebuffer(GL_READ_FRAMEBUFFER))
2552     {
2553         glReadBuffer(src);
2554     }
2555     else
2556     {
2557         GLenum translated = ConvertDefaultFramebufferEnum(src);
2558         glReadBuffer(translated);
2559     }
2560 }
2561 
onReplayDiscardFramebufferEXT(GLenum target,GLsizei numAttachments,const GLenum * attachments)2562 void TracePerfTest::onReplayDiscardFramebufferEXT(GLenum target,
2563                                                   GLsizei numAttachments,
2564                                                   const GLenum *attachments)
2565 {
2566     if (mParams->surfaceType != SurfaceType::Offscreen || !isDefaultFramebuffer(target))
2567     {
2568         glDiscardFramebufferEXT(target, numAttachments, attachments);
2569     }
2570     else
2571     {
2572         std::vector<GLenum> translatedAttachments =
2573             ConvertDefaultFramebufferEnums(numAttachments, attachments);
2574         glDiscardFramebufferEXT(target, numAttachments, translatedAttachments.data());
2575     }
2576 }
2577 
swap()2578 void TracePerfTest::swap()
2579 {
2580     // Capture a screenshot if enabled.
2581     if (gScreenshotDir != nullptr && gSaveScreenshots && !mScreenshotSaved &&
2582         (static_cast<uint32_t>(mScreenshotFrame) == mCurrentIteration ||
2583          mScreenshotFrame == kAllFrames))
2584     {
2585         std::stringstream screenshotNameStr;
2586         screenshotNameStr << gScreenshotDir << GetPathSeparator() << "angle" << mBackend << "_"
2587                           << mStory;
2588 
2589         // Add a marker to the name for any screenshot that isn't start frame
2590         if (mStartFrame != static_cast<uint32_t>(mScreenshotFrame))
2591         {
2592             screenshotNameStr << "_frame" << mCurrentIteration;
2593         }
2594 
2595         screenshotNameStr << ".png";
2596 
2597         std::string screenshotName = screenshotNameStr.str();
2598         saveScreenshot(screenshotName);
2599 
2600         // Only set this value if we're capturing a single frame
2601         mScreenshotSaved = mScreenshotFrame != kAllFrames;
2602     }
2603 
2604     getGLWindow()->swap();
2605 }
2606 
saveScreenshot(const std::string & screenshotName)2607 void TracePerfTest::saveScreenshot(const std::string &screenshotName)
2608 {
2609     // The frame is already rendered and is waiting in the default framebuffer.
2610 
2611     // RGBA 4-byte data.
2612     uint32_t pixelCount = mTestParams.windowWidth * mTestParams.windowHeight;
2613     std::vector<uint8_t> pixelData(pixelCount * 4);
2614 
2615     // Only unbind the framebuffer on context versions where it's available.
2616     if (mParams->traceInfo.contextClientMajorVersion > 1)
2617     {
2618         glBindFramebuffer(GL_FRAMEBUFFER, 0);
2619     }
2620 
2621     glReadPixels(0, 0, mTestParams.windowWidth, mTestParams.windowHeight, GL_RGBA, GL_UNSIGNED_BYTE,
2622                  pixelData.data());
2623 
2624     // Convert to RGB and flip y.
2625     std::vector<uint8_t> rgbData(pixelCount * 3);
2626     for (EGLint y = 0; y < mTestParams.windowHeight; ++y)
2627     {
2628         for (EGLint x = 0; x < mTestParams.windowWidth; ++x)
2629         {
2630             EGLint srcPixel = x + y * mTestParams.windowWidth;
2631             EGLint dstPixel = x + (mTestParams.windowHeight - y - 1) * mTestParams.windowWidth;
2632             memcpy(&rgbData[dstPixel * 3], &pixelData[srcPixel * 4], 3);
2633         }
2634     }
2635 
2636     if (!angle::SavePNGRGB(screenshotName.c_str(), "ANGLE Screenshot", mTestParams.windowWidth,
2637                            mTestParams.windowHeight, rgbData))
2638     {
2639         failTest(std::string("Error saving screenshot: ") + screenshotName);
2640         return;
2641     }
2642     else
2643     {
2644         printf("Saved screenshot: '%s'\n", screenshotName.c_str());
2645     }
2646 }
2647 }  // anonymous namespace
2648 
2649 using namespace params;
2650 
RegisterTraceTests()2651 void RegisterTraceTests()
2652 {
2653     GLESDriverType driverType = GetDriverTypeFromString(gUseGL, GLESDriverType::AngleEGL);
2654     GLenum platformType       = EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE;
2655     GLenum deviceType         = EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE;
2656     if (IsANGLE(driverType))
2657     {
2658         platformType = GetPlatformANGLETypeFromArg(gUseANGLE, EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE);
2659         deviceType =
2660             GetANGLEDeviceTypeFromArg(gUseANGLE, EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE);
2661     }
2662 
2663     char rootTracePath[kMaxPath] = {};
2664     if (!FindRootTraceTestDataPath(rootTracePath, kMaxPath))
2665     {
2666         ERR() << "Unable to find trace folder.";
2667         return;
2668     }
2669 
2670     // Load JSON data.
2671     std::vector<std::string> traces;
2672     {
2673         std::stringstream tracesJsonStream;
2674         tracesJsonStream << rootTracePath << GetPathSeparator() << "restricted_traces.json";
2675         std::string tracesJsonPath = tracesJsonStream.str();
2676 
2677         if (!LoadTraceNamesFromJSON(tracesJsonPath, &traces))
2678         {
2679             ERR() << "Unable to load traces from JSON file: " << tracesJsonPath;
2680             return;
2681         }
2682     }
2683 
2684     std::vector<TraceInfo> traceInfos;
2685     for (const std::string &trace : traces)
2686     {
2687         std::stringstream traceJsonStream;
2688         traceJsonStream << rootTracePath << GetPathSeparator() << trace << GetPathSeparator()
2689                         << trace << ".json";
2690         std::string traceJsonPath = traceJsonStream.str();
2691 
2692         TraceInfo traceInfo = {};
2693         strncpy(traceInfo.name, trace.c_str(), kTraceInfoMaxNameLen);
2694         traceInfo.initialized = LoadTraceInfoFromJSON(trace, traceJsonPath, &traceInfo);
2695 
2696         traceInfos.push_back(traceInfo);
2697     }
2698 
2699     for (const TraceInfo &traceInfo : traceInfos)
2700     {
2701         const TracePerfParams params(traceInfo, driverType, platformType, deviceType);
2702 
2703         if (!IsPlatformAvailable(params))
2704         {
2705             continue;
2706         }
2707 
2708         auto factory = [params]() {
2709             return new TracePerfTest(std::make_unique<TracePerfParams>(params));
2710         };
2711         testing::RegisterTest("TraceTest", traceInfo.name, nullptr, nullptr, __FILE__, __LINE__,
2712                               factory);
2713     }
2714 }
2715