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