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