Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/angle
Path: blob/main_old/src/tests/perf_tests/TracePerfTest.cpp
1693 views
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/system_utils.h"
13
#include "tests/perf_tests/ANGLEPerfTest.h"
14
#include "tests/perf_tests/ANGLEPerfTestArgs.h"
15
#include "tests/perf_tests/DrawCallPerfParams.h"
16
#include "util/egl_loader_autogen.h"
17
#include "util/frame_capture_test_utils.h"
18
#include "util/png_utils.h"
19
#include "util/test_utils.h"
20
21
#include "restricted_traces/restricted_traces_autogen.h"
22
23
#include <cassert>
24
#include <functional>
25
#include <sstream>
26
27
// When --minimize-gpu-work is specified, we want to reduce GPU work to minimum and lift up the CPU
28
// overhead to surface so that we can see how much CPU overhead each driver has for each app trace.
29
// On some driver(s) the bufferSubData/texSubImage calls end up dominating the frame time when the
30
// actual GPU work is minimized. Even reducing the texSubImage calls to only update 1x1 area is not
31
// enough. The driver may be implementing copy on write by cloning the entire texture to another
32
// memory storage for texSubImage call. While this information is also important for performance,
33
// they should be evaluated separately in real app usage scenario, or write stand alone tests for
34
// these. For the purpose of CPU overhead and avoid data copy to dominate the trace, I am using this
35
// flag to noop the texSubImage and bufferSubData call when --minimize-gpu-work is specified. Feel
36
// free to disable this when you have other needs. Or it can be turned to another run time option
37
// when desired.
38
#define NOOP_SUBDATA_SUBIMAGE_FOR_MINIMIZE_GPU_WORK
39
40
using namespace angle;
41
using namespace egl_platform;
42
43
namespace
44
{
45
struct TracePerfParams final : public RenderTestParams
46
{
47
// Common default options
48
TracePerfParams()
49
{
50
// Display the frame after every drawBenchmark invocation
51
iterationsPerStep = 1;
52
}
53
54
std::string story() const override
55
{
56
std::stringstream strstr;
57
strstr << RenderTestParams::story() << "_" << GetTraceInfo(testID).name;
58
return strstr.str();
59
}
60
61
RestrictedTraceID testID;
62
};
63
64
std::ostream &operator<<(std::ostream &os, const TracePerfParams &params)
65
{
66
os << params.backendAndStory().substr(1);
67
return os;
68
}
69
70
class TracePerfTest : public ANGLERenderTest
71
{
72
public:
73
TracePerfTest(const TracePerfParams &params);
74
75
void initializeBenchmark() override;
76
void destroyBenchmark() override;
77
void drawBenchmark() override;
78
79
// TODO(http://www.anglebug.com/5878): Add support for creating EGLSurface:
80
// - eglCreatePbufferSurface()
81
// - eglCreateWindowSurface()
82
EGLContext onEglCreateContext(EGLDisplay display,
83
EGLConfig config,
84
EGLContext share_context,
85
EGLint const *attrib_list);
86
void onEglMakeCurrent(EGLDisplay display, EGLSurface draw, EGLSurface read, EGLContext context);
87
EGLContext onEglGetCurrentContext();
88
void onReplayFramebufferChange(GLenum target, GLuint framebuffer);
89
void onReplayInvalidateFramebuffer(GLenum target,
90
GLsizei numAttachments,
91
const GLenum *attachments);
92
void onReplayInvalidateSubFramebuffer(GLenum target,
93
GLsizei numAttachments,
94
const GLenum *attachments,
95
GLint x,
96
GLint y,
97
GLsizei width,
98
GLsizei height);
99
void onReplayDrawBuffers(GLsizei n, const GLenum *bufs);
100
void onReplayReadBuffer(GLenum src);
101
void onReplayDiscardFramebufferEXT(GLenum target,
102
GLsizei numAttachments,
103
const GLenum *attachments);
104
105
void validateSerializedState(const char *serializedState, const char *fileName, uint32_t line);
106
107
bool isDefaultFramebuffer(GLenum target) const;
108
109
double getHostTimeFromGLTime(GLint64 glTime);
110
111
int getStepAlignment() const override
112
{
113
// Align step counts to the number of frames in a trace.
114
const TraceInfo &traceInfo = GetTraceInfo(mParams.testID);
115
return static_cast<int>(traceInfo.endFrame - traceInfo.startFrame + 1);
116
}
117
118
void TestBody() override { run(); }
119
120
private:
121
struct QueryInfo
122
{
123
GLuint beginTimestampQuery;
124
GLuint endTimestampQuery;
125
GLuint framebuffer;
126
};
127
128
struct TimeSample
129
{
130
GLint64 glTime;
131
double hostTime;
132
};
133
134
void sampleTime();
135
void saveScreenshot(const std::string &screenshotName) override;
136
void swap();
137
138
const TracePerfParams mParams;
139
140
uint32_t mStartFrame;
141
uint32_t mEndFrame;
142
143
// For tracking RenderPass/FBO change timing.
144
QueryInfo mCurrentQuery = {};
145
std::vector<QueryInfo> mRunningQueries;
146
std::vector<TimeSample> mTimeline;
147
148
std::string mStartingDirectory;
149
bool mUseTimestampQueries = false;
150
static constexpr int mMaxOffscreenBufferCount = 2;
151
std::array<GLuint, mMaxOffscreenBufferCount> mOffscreenFramebuffers = {0, 0};
152
std::array<GLuint, mMaxOffscreenBufferCount> mOffscreenTextures = {0, 0};
153
GLuint mOffscreenDepthStencil = 0;
154
int mWindowWidth = 0;
155
int mWindowHeight = 0;
156
GLuint mDrawFramebufferBinding = 0;
157
GLuint mReadFramebufferBinding = 0;
158
uint32_t mCurrentFrame = 0;
159
uint32_t mOffscreenFrameCount = 0;
160
uint32_t mTotalFrameCount = 0;
161
bool mScreenshotSaved = false;
162
std::unique_ptr<TraceLibrary> mTraceLibrary;
163
};
164
165
TracePerfTest *gCurrentTracePerfTest = nullptr;
166
167
// Don't forget to include KHRONOS_APIENTRY in override methods. Necessary on Win/x86.
168
EGLContext KHRONOS_APIENTRY EglCreateContext(EGLDisplay display,
169
EGLConfig config,
170
EGLContext share_context,
171
EGLint const *attrib_list)
172
{
173
return gCurrentTracePerfTest->onEglCreateContext(display, config, share_context, attrib_list);
174
}
175
176
void KHRONOS_APIENTRY EglMakeCurrent(EGLDisplay display,
177
EGLSurface draw,
178
EGLSurface read,
179
EGLContext context)
180
{
181
gCurrentTracePerfTest->onEglMakeCurrent(display, draw, read, context);
182
}
183
184
EGLContext KHRONOS_APIENTRY EglGetCurrentContext()
185
{
186
return gCurrentTracePerfTest->onEglGetCurrentContext();
187
}
188
189
void KHRONOS_APIENTRY BindFramebufferProc(GLenum target, GLuint framebuffer)
190
{
191
gCurrentTracePerfTest->onReplayFramebufferChange(target, framebuffer);
192
}
193
194
void KHRONOS_APIENTRY InvalidateFramebufferProc(GLenum target,
195
GLsizei numAttachments,
196
const GLenum *attachments)
197
{
198
gCurrentTracePerfTest->onReplayInvalidateFramebuffer(target, numAttachments, attachments);
199
}
200
201
void KHRONOS_APIENTRY InvalidateSubFramebufferProc(GLenum target,
202
GLsizei numAttachments,
203
const GLenum *attachments,
204
GLint x,
205
GLint y,
206
GLsizei width,
207
GLsizei height)
208
{
209
gCurrentTracePerfTest->onReplayInvalidateSubFramebuffer(target, numAttachments, attachments, x,
210
y, width, height);
211
}
212
213
void KHRONOS_APIENTRY DrawBuffersProc(GLsizei n, const GLenum *bufs)
214
{
215
gCurrentTracePerfTest->onReplayDrawBuffers(n, bufs);
216
}
217
218
void KHRONOS_APIENTRY ReadBufferProc(GLenum src)
219
{
220
gCurrentTracePerfTest->onReplayReadBuffer(src);
221
}
222
223
void KHRONOS_APIENTRY DiscardFramebufferEXTProc(GLenum target,
224
GLsizei numAttachments,
225
const GLenum *attachments)
226
{
227
gCurrentTracePerfTest->onReplayDiscardFramebufferEXT(target, numAttachments, attachments);
228
}
229
230
void KHRONOS_APIENTRY ViewportMinimizedProc(GLint x, GLint y, GLsizei width, GLsizei height)
231
{
232
glViewport(x, y, 1, 1);
233
}
234
235
void KHRONOS_APIENTRY ScissorMinimizedProc(GLint x, GLint y, GLsizei width, GLsizei height)
236
{
237
glScissor(x, y, 1, 1);
238
}
239
240
// Interpose the calls that generate actual GPU work
241
void KHRONOS_APIENTRY DrawElementsMinimizedProc(GLenum mode,
242
GLsizei count,
243
GLenum type,
244
const void *indices)
245
{
246
glDrawElements(GL_POINTS, 1, type, indices);
247
}
248
249
void KHRONOS_APIENTRY DrawElementsIndirectMinimizedProc(GLenum mode,
250
GLenum type,
251
const void *indirect)
252
{
253
glDrawElementsInstancedBaseVertex(GL_POINTS, 1, type, 0, 1, 0);
254
}
255
256
void KHRONOS_APIENTRY DrawElementsInstancedMinimizedProc(GLenum mode,
257
GLsizei count,
258
GLenum type,
259
const void *indices,
260
GLsizei instancecount)
261
{
262
glDrawElementsInstanced(GL_POINTS, 1, type, indices, 1);
263
}
264
265
void KHRONOS_APIENTRY DrawElementsBaseVertexMinimizedProc(GLenum mode,
266
GLsizei count,
267
GLenum type,
268
const void *indices,
269
GLint basevertex)
270
{
271
glDrawElementsBaseVertex(GL_POINTS, 1, type, indices, basevertex);
272
}
273
274
void KHRONOS_APIENTRY DrawElementsInstancedBaseVertexMinimizedProc(GLenum mode,
275
GLsizei count,
276
GLenum type,
277
const void *indices,
278
GLsizei instancecount,
279
GLint basevertex)
280
{
281
glDrawElementsInstancedBaseVertex(GL_POINTS, 1, type, indices, 1, basevertex);
282
}
283
284
void KHRONOS_APIENTRY DrawRangeElementsMinimizedProc(GLenum mode,
285
GLuint start,
286
GLuint end,
287
GLsizei count,
288
GLenum type,
289
const void *indices)
290
{
291
glDrawRangeElements(GL_POINTS, start, end, 1, type, indices);
292
}
293
294
void KHRONOS_APIENTRY DrawArraysMinimizedProc(GLenum mode, GLint first, GLsizei count)
295
{
296
glDrawArrays(GL_POINTS, first, 1);
297
}
298
299
void KHRONOS_APIENTRY DrawArraysInstancedMinimizedProc(GLenum mode,
300
GLint first,
301
GLsizei count,
302
GLsizei instancecount)
303
{
304
glDrawArraysInstanced(GL_POINTS, first, 1, 1);
305
}
306
307
void KHRONOS_APIENTRY DrawArraysIndirectMinimizedProc(GLenum mode, const void *indirect)
308
{
309
glDrawArraysInstanced(GL_POINTS, 0, 1, 1);
310
}
311
312
void KHRONOS_APIENTRY DispatchComputeMinimizedProc(GLuint num_groups_x,
313
GLuint num_groups_y,
314
GLuint num_groups_z)
315
{
316
glDispatchCompute(1, 1, 1);
317
}
318
319
void KHRONOS_APIENTRY DispatchComputeIndirectMinimizedProc(GLintptr indirect)
320
{
321
glDispatchCompute(1, 1, 1);
322
}
323
324
// Interpose the calls that generate data copying work
325
void KHRONOS_APIENTRY BufferDataMinimizedProc(GLenum target,
326
GLsizeiptr size,
327
const void *data,
328
GLenum usage)
329
{
330
glBufferData(target, size, nullptr, usage);
331
}
332
333
void KHRONOS_APIENTRY BufferSubDataMinimizedProc(GLenum target,
334
GLintptr offset,
335
GLsizeiptr size,
336
const void *data)
337
{
338
#if !defined(NOOP_SUBDATA_SUBIMAGE_FOR_MINIMIZE_GPU_WORK)
339
glBufferSubData(target, offset, 1, data);
340
#endif
341
}
342
343
void *KHRONOS_APIENTRY MapBufferRangeMinimizedProc(GLenum target,
344
GLintptr offset,
345
GLsizeiptr length,
346
GLbitfield access)
347
{
348
access |= GL_MAP_UNSYNCHRONIZED_BIT;
349
return glMapBufferRange(target, offset, length, access);
350
}
351
352
void KHRONOS_APIENTRY TexImage2DMinimizedProc(GLenum target,
353
GLint level,
354
GLint internalformat,
355
GLsizei width,
356
GLsizei height,
357
GLint border,
358
GLenum format,
359
GLenum type,
360
const void *pixels)
361
{
362
GLint unpackBuffer = 0;
363
glGetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING, &unpackBuffer);
364
if (unpackBuffer)
365
{
366
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
367
}
368
glTexImage2D(target, level, internalformat, width, height, border, format, type, nullptr);
369
if (unpackBuffer)
370
{
371
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, unpackBuffer);
372
}
373
}
374
375
void KHRONOS_APIENTRY TexSubImage2DMinimizedProc(GLenum target,
376
GLint level,
377
GLint xoffset,
378
GLint yoffset,
379
GLsizei width,
380
GLsizei height,
381
GLenum format,
382
GLenum type,
383
const void *pixels)
384
{
385
#if !defined(NOOP_SUBDATA_SUBIMAGE_FOR_MINIMIZE_GPU_WORK)
386
glTexSubImage2D(target, level, xoffset, yoffset, 1, 1, format, type, pixels);
387
#endif
388
}
389
390
void KHRONOS_APIENTRY TexImage3DMinimizedProc(GLenum target,
391
GLint level,
392
GLint internalformat,
393
GLsizei width,
394
GLsizei height,
395
GLsizei depth,
396
GLint border,
397
GLenum format,
398
GLenum type,
399
const void *pixels)
400
{
401
GLint unpackBuffer = 0;
402
glGetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING, &unpackBuffer);
403
if (unpackBuffer)
404
{
405
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
406
}
407
glTexImage3D(target, level, internalformat, width, height, depth, border, format, type,
408
nullptr);
409
if (unpackBuffer)
410
{
411
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, unpackBuffer);
412
}
413
}
414
415
void KHRONOS_APIENTRY TexSubImage3DMinimizedProc(GLenum target,
416
GLint level,
417
GLint xoffset,
418
GLint yoffset,
419
GLint zoffset,
420
GLsizei width,
421
GLsizei height,
422
GLsizei depth,
423
GLenum format,
424
GLenum type,
425
const void *pixels)
426
{
427
#if !defined(NOOP_SUBDATA_SUBIMAGE_FOR_MINIMIZE_GPU_WORK)
428
glTexSubImage3D(target, level, xoffset, yoffset, zoffset, 1, 1, 1, format, type, pixels);
429
#endif
430
}
431
432
void KHRONOS_APIENTRY GenerateMipmapMinimizedProc(GLenum target)
433
{
434
// Noop it for now. There is a risk that this will leave an incomplete mipmap chain and cause
435
// other issues. If this turns out to be a real issue with app traces, we can turn this into a
436
// glTexImage2D call for each generated level.
437
}
438
439
void KHRONOS_APIENTRY BlitFramebufferMinimizedProc(GLint srcX0,
440
GLint srcY0,
441
GLint srcX1,
442
GLint srcY1,
443
GLint dstX0,
444
GLint dstY0,
445
GLint dstX1,
446
GLint dstY1,
447
GLbitfield mask,
448
GLenum filter)
449
{
450
glBlitFramebuffer(srcX0, srcY0, srcX0 + 1, srcY0 + 1, dstX0, dstY0, dstX0 + 1, dstY0 + 1, mask,
451
filter);
452
}
453
454
void KHRONOS_APIENTRY ReadPixelsMinimizedProc(GLint x,
455
GLint y,
456
GLsizei width,
457
GLsizei height,
458
GLenum format,
459
GLenum type,
460
void *pixels)
461
{
462
glReadPixels(x, y, 1, 1, format, type, pixels);
463
}
464
465
void KHRONOS_APIENTRY BeginTransformFeedbackMinimizedProc(GLenum primitiveMode)
466
{
467
glBeginTransformFeedback(GL_POINTS);
468
}
469
470
angle::GenericProc KHRONOS_APIENTRY TraceLoadProc(const char *procName)
471
{
472
// EGL
473
if (strcmp(procName, "eglCreateContext") == 0)
474
{
475
return reinterpret_cast<angle::GenericProc>(EglCreateContext);
476
}
477
if (strcmp(procName, "eglMakeCurrent") == 0)
478
{
479
return reinterpret_cast<angle::GenericProc>(EglMakeCurrent);
480
}
481
if (strcmp(procName, "eglGetCurrentContext") == 0)
482
{
483
return reinterpret_cast<angle::GenericProc>(EglGetCurrentContext);
484
}
485
486
// GLES
487
if (strcmp(procName, "glBindFramebuffer") == 0)
488
{
489
return reinterpret_cast<angle::GenericProc>(BindFramebufferProc);
490
}
491
if (strcmp(procName, "glInvalidateFramebuffer") == 0)
492
{
493
return reinterpret_cast<angle::GenericProc>(InvalidateFramebufferProc);
494
}
495
if (strcmp(procName, "glInvalidateSubFramebuffer") == 0)
496
{
497
return reinterpret_cast<angle::GenericProc>(InvalidateSubFramebufferProc);
498
}
499
if (strcmp(procName, "glDrawBuffers") == 0)
500
{
501
return reinterpret_cast<angle::GenericProc>(DrawBuffersProc);
502
}
503
if (strcmp(procName, "glReadBuffer") == 0)
504
{
505
return reinterpret_cast<angle::GenericProc>(ReadBufferProc);
506
}
507
if (strcmp(procName, "glDiscardFramebufferEXT") == 0)
508
{
509
return reinterpret_cast<angle::GenericProc>(DiscardFramebufferEXTProc);
510
}
511
512
if (gMinimizeGPUWork)
513
{
514
if (strcmp(procName, "glViewport") == 0)
515
{
516
return reinterpret_cast<angle::GenericProc>(ViewportMinimizedProc);
517
}
518
519
if (strcmp(procName, "glScissor") == 0)
520
{
521
return reinterpret_cast<angle::GenericProc>(ScissorMinimizedProc);
522
}
523
524
// Interpose the calls that generate actual GPU work
525
if (strcmp(procName, "glDrawElements") == 0)
526
{
527
return reinterpret_cast<angle::GenericProc>(DrawElementsMinimizedProc);
528
}
529
if (strcmp(procName, "glDrawElementsIndirect") == 0)
530
{
531
return reinterpret_cast<angle::GenericProc>(DrawElementsIndirectMinimizedProc);
532
}
533
if (strcmp(procName, "glDrawElementsInstanced") == 0 ||
534
strcmp(procName, "glDrawElementsInstancedEXT") == 0)
535
{
536
return reinterpret_cast<angle::GenericProc>(DrawElementsInstancedMinimizedProc);
537
}
538
if (strcmp(procName, "glDrawElementsBaseVertex") == 0 ||
539
strcmp(procName, "glDrawElementsBaseVertexEXT") == 0 ||
540
strcmp(procName, "glDrawElementsBaseVertexOES") == 0)
541
{
542
return reinterpret_cast<angle::GenericProc>(DrawElementsBaseVertexMinimizedProc);
543
}
544
if (strcmp(procName, "glDrawElementsInstancedBaseVertex") == 0 ||
545
strcmp(procName, "glDrawElementsInstancedBaseVertexEXT") == 0 ||
546
strcmp(procName, "glDrawElementsInstancedBaseVertexOES") == 0)
547
{
548
return reinterpret_cast<angle::GenericProc>(
549
DrawElementsInstancedBaseVertexMinimizedProc);
550
}
551
if (strcmp(procName, "glDrawRangeElements") == 0)
552
{
553
return reinterpret_cast<angle::GenericProc>(DrawRangeElementsMinimizedProc);
554
}
555
if (strcmp(procName, "glDrawArrays") == 0)
556
{
557
return reinterpret_cast<angle::GenericProc>(DrawArraysMinimizedProc);
558
}
559
if (strcmp(procName, "glDrawArraysInstanced") == 0 ||
560
strcmp(procName, "glDrawArraysInstancedEXT") == 0)
561
{
562
return reinterpret_cast<angle::GenericProc>(DrawArraysInstancedMinimizedProc);
563
}
564
if (strcmp(procName, "glDrawArraysIndirect") == 0)
565
{
566
return reinterpret_cast<angle::GenericProc>(DrawArraysIndirectMinimizedProc);
567
}
568
if (strcmp(procName, "glDispatchCompute") == 0)
569
{
570
return reinterpret_cast<angle::GenericProc>(DispatchComputeMinimizedProc);
571
}
572
if (strcmp(procName, "glDispatchComputeIndirect") == 0)
573
{
574
return reinterpret_cast<angle::GenericProc>(DispatchComputeIndirectMinimizedProc);
575
}
576
577
// Interpose the calls that generate data copying work
578
if (strcmp(procName, "glBufferData") == 0)
579
{
580
return reinterpret_cast<angle::GenericProc>(BufferDataMinimizedProc);
581
}
582
if (strcmp(procName, "glBufferSubData") == 0)
583
{
584
return reinterpret_cast<angle::GenericProc>(BufferSubDataMinimizedProc);
585
}
586
if (strcmp(procName, "glMapBufferRange") == 0 ||
587
strcmp(procName, "glMapBufferRangeEXT") == 0)
588
{
589
return reinterpret_cast<angle::GenericProc>(MapBufferRangeMinimizedProc);
590
}
591
if (strcmp(procName, "glTexImage2D") == 0)
592
{
593
return reinterpret_cast<angle::GenericProc>(TexImage2DMinimizedProc);
594
}
595
if (strcmp(procName, "glTexImage3D") == 0)
596
{
597
return reinterpret_cast<angle::GenericProc>(TexImage3DMinimizedProc);
598
}
599
if (strcmp(procName, "glTexSubImage2D") == 0)
600
{
601
return reinterpret_cast<angle::GenericProc>(TexSubImage2DMinimizedProc);
602
}
603
if (strcmp(procName, "glTexSubImage3D") == 0)
604
{
605
return reinterpret_cast<angle::GenericProc>(TexSubImage3DMinimizedProc);
606
}
607
if (strcmp(procName, "glGenerateMipmap") == 0 ||
608
strcmp(procName, "glGenerateMipmapOES") == 0)
609
{
610
return reinterpret_cast<angle::GenericProc>(GenerateMipmapMinimizedProc);
611
}
612
if (strcmp(procName, "glBlitFramebuffer") == 0)
613
{
614
return reinterpret_cast<angle::GenericProc>(BlitFramebufferMinimizedProc);
615
}
616
if (strcmp(procName, "glReadPixels") == 0)
617
{
618
return reinterpret_cast<angle::GenericProc>(ReadPixelsMinimizedProc);
619
}
620
if (strcmp(procName, "glBeginTransformFeedback") == 0)
621
{
622
return reinterpret_cast<angle::GenericProc>(BeginTransformFeedbackMinimizedProc);
623
}
624
}
625
626
return gCurrentTracePerfTest->getGLWindow()->getProcAddress(procName);
627
}
628
629
void ValidateSerializedState(const char *serializedState, const char *fileName, uint32_t line)
630
{
631
gCurrentTracePerfTest->validateSerializedState(serializedState, fileName, line);
632
}
633
634
TracePerfTest::TracePerfTest(const TracePerfParams &params)
635
: ANGLERenderTest("TracePerf", params, "ms"), mParams(params), mStartFrame(0), mEndFrame(0)
636
{
637
// TODO: http://anglebug.com/4533 This fails after the upgrade to the 26.20.100.7870 driver.
638
if (IsWindows() && IsIntel() && mParams.getRenderer() == EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE &&
639
mParams.testID == RestrictedTraceID::manhattan_10)
640
{
641
mSkipTest = true;
642
}
643
644
// TODO: http://anglebug.com/4731 Fails on older Intel drivers. Passes in newer.
645
if (IsWindows() && IsIntel() && mParams.driver != GLESDriverType::AngleEGL &&
646
mParams.testID == RestrictedTraceID::angry_birds_2_1500)
647
{
648
mSkipTest = true;
649
}
650
651
if (mParams.surfaceType != SurfaceType::Window && !gEnableAllTraceTests)
652
{
653
printf("Test skipped. Use --enable-all-trace-tests to run.\n");
654
mSkipTest = true;
655
}
656
657
if (mParams.eglParameters.deviceType != EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE &&
658
!gEnableAllTraceTests)
659
{
660
printf("Test skipped. Use --enable-all-trace-tests to run.\n");
661
mSkipTest = true;
662
}
663
664
if (mParams.testID == RestrictedTraceID::cod_mobile)
665
{
666
// TODO: http://anglebug.com/4967 Vulkan: GL_EXT_color_buffer_float not supported on Pixel 2
667
// The COD:Mobile trace uses a framebuffer attachment with:
668
// format = GL_RGB
669
// type = GL_UNSIGNED_INT_10F_11F_11F_REV
670
// That combination is only renderable if GL_EXT_color_buffer_float is supported.
671
// It happens to not be supported on Pixel 2's Vulkan driver.
672
addExtensionPrerequisite("GL_EXT_color_buffer_float");
673
674
// TODO: http://anglebug.com/4731 This extension is missing on older Intel drivers.
675
addExtensionPrerequisite("GL_OES_EGL_image_external");
676
}
677
678
if (mParams.testID == RestrictedTraceID::brawl_stars)
679
{
680
addExtensionPrerequisite("GL_EXT_shadow_samplers");
681
}
682
683
if (mParams.testID == RestrictedTraceID::free_fire)
684
{
685
addExtensionPrerequisite("GL_OES_EGL_image_external");
686
}
687
688
if (mParams.testID == RestrictedTraceID::marvel_contest_of_champions)
689
{
690
addExtensionPrerequisite("GL_EXT_color_buffer_half_float");
691
}
692
693
if (mParams.testID == RestrictedTraceID::world_of_tanks_blitz)
694
{
695
addExtensionPrerequisite("GL_EXT_disjoint_timer_query");
696
}
697
698
if (mParams.testID == RestrictedTraceID::dragon_ball_legends)
699
{
700
addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
701
}
702
703
if (mParams.testID == RestrictedTraceID::lego_legacy)
704
{
705
addExtensionPrerequisite("GL_EXT_shadow_samplers");
706
}
707
708
if (mParams.testID == RestrictedTraceID::world_war_doh)
709
{
710
// Linux+Nvidia doesn't support GL_KHR_texture_compression_astc_ldr (possibly others also)
711
addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
712
}
713
714
if (mParams.testID == RestrictedTraceID::saint_seiya_awakening)
715
{
716
addExtensionPrerequisite("GL_EXT_shadow_samplers");
717
718
// TODO(https://anglebug.com/5517) Linux+Intel generates "Framebuffer is incomplete" errors.
719
if (IsLinux() && IsIntel() && mParams.getRenderer() == EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE)
720
{
721
mSkipTest = true;
722
}
723
}
724
725
if (mParams.testID == RestrictedTraceID::magic_tiles_3)
726
{
727
// Linux+Nvidia doesn't support GL_KHR_texture_compression_astc_ldr (possibly others also)
728
addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
729
}
730
731
if (mParams.testID == RestrictedTraceID::real_gangster_crime)
732
{
733
// Linux+Nvidia doesn't support GL_KHR_texture_compression_astc_ldr (possibly others also)
734
addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
735
736
// Intel doesn't support external images.
737
addExtensionPrerequisite("GL_OES_EGL_image_external");
738
739
// Failing on Linux Intel and AMD due to invalid enum. http://anglebug.com/5822
740
if (IsLinux() && (IsIntel() || IsAMD()) && mParams.driver != GLESDriverType::AngleEGL)
741
{
742
mSkipTest = true;
743
}
744
}
745
746
if (mParams.testID == RestrictedTraceID::asphalt_8)
747
{
748
addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
749
}
750
751
if (mParams.testID == RestrictedTraceID::hearthstone)
752
{
753
addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
754
}
755
756
if (mParams.testID == RestrictedTraceID::efootball_pes_2021)
757
{
758
// TODO(https://anglebug.com/5517) Linux+Intel and Pixel 2 generate "Framebuffer is
759
// incomplete" errors with the Vulkan backend.
760
if (mParams.getRenderer() == EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE &&
761
((IsLinux() && IsIntel()) || IsPixel2()))
762
{
763
mSkipTest = true;
764
}
765
}
766
767
if (mParams.testID == RestrictedTraceID::manhattan_31)
768
{
769
// TODO: http://anglebug.com/5591 Trace crashes on Pixel 2 in vulkan driver
770
if (IsPixel2() && mParams.getRenderer() == EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE)
771
{
772
mSkipTest = true;
773
}
774
}
775
776
if (mParams.testID == RestrictedTraceID::idle_heroes)
777
{
778
// TODO: http://anglebug.com/5591 Trace crashes on Pixel 2
779
if (IsPixel2())
780
{
781
mSkipTest = true;
782
}
783
}
784
785
if (mParams.testID == RestrictedTraceID::shadow_fight_2)
786
{
787
addExtensionPrerequisite("GL_OES_EGL_image_external");
788
addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
789
}
790
791
if (mParams.testID == RestrictedTraceID::rise_of_kingdoms)
792
{
793
addExtensionPrerequisite("GL_OES_EGL_image_external");
794
}
795
796
if (mParams.testID == RestrictedTraceID::happy_color)
797
{
798
if (IsWindows() && IsAMD() && mParams.getRenderer() == EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE)
799
{
800
mSkipTest = true;
801
}
802
}
803
804
if (mParams.testID == RestrictedTraceID::bus_simulator_indonesia)
805
{
806
// TODO(https://anglebug.com/5629) Linux+(Intel|AMD) native GLES generates
807
// GL_INVALID_OPERATION
808
if (IsLinux() && (IsIntel() || IsAMD()) &&
809
mParams.getRenderer() != EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE)
810
{
811
mSkipTest = true;
812
}
813
}
814
815
if (mParams.testID == RestrictedTraceID::messenger_lite)
816
{
817
// TODO: https://anglebug.com/5663 Incorrect pixels on Nvidia Windows for first frame
818
if (IsWindows() && IsNVIDIA() &&
819
mParams.getRenderer() == EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE &&
820
mParams.getDeviceType() != EGL_PLATFORM_ANGLE_DEVICE_TYPE_SWIFTSHADER_ANGLE)
821
{
822
mSkipTest = true;
823
}
824
}
825
826
if (mParams.testID == RestrictedTraceID::among_us)
827
{
828
addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
829
}
830
831
if (mParams.testID == RestrictedTraceID::car_parking_multiplayer)
832
{
833
// TODO: https://anglebug.com/5613 Nvidia native driver spews undefined behavior warnings
834
if (IsNVIDIA() && mParams.getRenderer() != EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE)
835
{
836
mSkipTest = true;
837
}
838
// TODO: https://anglebug.com/5724 Device lost on Win Intel
839
if (IsWindows() && IsIntel() &&
840
mParams.getRenderer() == EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE)
841
{
842
mSkipTest = true;
843
}
844
}
845
846
if (mParams.testID == RestrictedTraceID::fifa_mobile)
847
{
848
// TODO: http://anglebug.com/5875 Intel Windows Vulkan flakily renders entirely black
849
if (IsWindows() && IsIntel() &&
850
mParams.getRenderer() == EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE)
851
{
852
mSkipTest = true;
853
}
854
}
855
856
if (mParams.testID == RestrictedTraceID::rope_hero_vice_town)
857
{
858
// TODO: http://anglebug.com/5716 Trace crashes on Pixel 2 in vulkan driver
859
if (IsPixel2() && mParams.getRenderer() == EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE)
860
{
861
mSkipTest = true;
862
}
863
}
864
865
if (mParams.testID == RestrictedTraceID::extreme_car_driving_simulator)
866
{
867
addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
868
}
869
870
if (mParams.testID == RestrictedTraceID::plants_vs_zombies_2)
871
{
872
// TODO: http://crbug.com/1187752 Corrupted image
873
if (IsWindows() && IsAMD() && mParams.getRenderer() == EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE)
874
{
875
mSkipTest = true;
876
}
877
}
878
879
if (mParams.testID == RestrictedTraceID::junes_journey)
880
{
881
addExtensionPrerequisite("GL_OES_EGL_image_external");
882
}
883
884
if (mParams.testID == RestrictedTraceID::ragnarok_m_eternal_love)
885
{
886
addExtensionPrerequisite("GL_OES_EGL_image_external");
887
addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
888
889
// TODO: http://anglebug.com/5772 Pixel 2 errors with "Framebuffer is incomplete" on Vulkan
890
if (IsPixel2() && mParams.getRenderer() == EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE)
891
{
892
mSkipTest = true;
893
}
894
}
895
896
if (mParams.testID == RestrictedTraceID::real_cricket_20)
897
{
898
// TODO: http://anglebug.com/5777 ARM doesn't have enough VS storage blocks
899
if (IsAndroid() && IsARM())
900
{
901
mSkipTest = true;
902
}
903
}
904
905
if (mParams.testID == RestrictedTraceID::league_of_legends_wild_rift)
906
{
907
addExtensionPrerequisite("GL_OES_EGL_image_external");
908
addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
909
910
// TODO: http://anglebug.com/5815 Trace is crashing on Intel Linux
911
if (IsLinux() && IsIntel() && mParams.getRenderer() == EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE)
912
{
913
mSkipTest = true;
914
}
915
}
916
917
if (mParams.testID == RestrictedTraceID::aztec_ruins)
918
{
919
addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
920
921
// TODO: http://anglebug.com/5553 Pixel 2 errors with "Framebuffer is incomplete" on Vulkan
922
if (IsPixel2() && mParams.getRenderer() == EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE)
923
{
924
mSkipTest = true;
925
}
926
}
927
928
if (mParams.testID == RestrictedTraceID::dragon_raja)
929
{
930
addExtensionPrerequisite("GL_OES_EGL_image_external");
931
932
// TODO: http://anglebug.com/5807 Intel Linux and Pixel 2 error with "Framebuffer is
933
// incomplete" on Vulkan
934
if (((IsLinux() && IsIntel()) || IsPixel2()) &&
935
mParams.getRenderer() == EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE)
936
{
937
mSkipTest = true;
938
}
939
}
940
941
// Adreno gives a driver error with empty/small draw calls. http://anglebug.com/5823
942
if (mParams.testID == RestrictedTraceID::hill_climb_racing)
943
{
944
if (IsAndroid() && (IsPixel2() || IsPixel4()) &&
945
mParams.driver == GLESDriverType::SystemEGL)
946
{
947
mSkipTest = true;
948
}
949
}
950
951
if (mParams.testID == RestrictedTraceID::avakin_life)
952
{
953
addExtensionPrerequisite("GL_OES_EGL_image_external");
954
}
955
956
if (mParams.testID == RestrictedTraceID::professional_baseball_spirits)
957
{
958
// TODO(https://anglebug.com/5827) Linux+Mesa/RADV Vulkan generates
959
// GL_INVALID_FRAMEBUFFER_OPERATION.
960
// Mesa versions below 20.3.5 produce the same issue on Linux+Mesa/Intel Vulkan
961
if (IsLinux() && (IsAMD() || IsIntel()) &&
962
mParams.getRenderer() == EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE &&
963
mParams.eglParameters.deviceType != EGL_PLATFORM_ANGLE_DEVICE_TYPE_SWIFTSHADER_ANGLE)
964
{
965
mSkipTest = true;
966
}
967
}
968
969
if (mParams.testID == RestrictedTraceID::call_break_offline_card_game)
970
{
971
// TODO: http://anglebug.com/5837 Intel Linux Vulkan errors with "Framebuffer is incomplete"
972
if ((IsLinux() && IsIntel()) &&
973
mParams.getRenderer() == EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE)
974
{
975
mSkipTest = true;
976
}
977
}
978
979
if (mParams.testID == RestrictedTraceID::slingshot_test1 ||
980
mParams.testID == RestrictedTraceID::slingshot_test2)
981
{
982
// TODO: http://anglebug.com/5877 Trace crashes on Pixel 2 in vulkan driver
983
if (IsPixel2() && mParams.getRenderer() == EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE)
984
{
985
mSkipTest = true;
986
}
987
}
988
989
if (mParams.testID == RestrictedTraceID::ludo_king)
990
{
991
addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
992
}
993
994
// TODO: http://anglebug.com/5943 GL_INVALID_ENUM on Windows/Intel.
995
if (mParams.testID == RestrictedTraceID::summoners_war)
996
{
997
if (IsWindows() && IsIntel() && mParams.driver != GLESDriverType::AngleEGL)
998
{
999
mSkipTest = true;
1000
}
1001
}
1002
1003
if (mParams.testID == RestrictedTraceID::pokemon_go)
1004
{
1005
addExtensionPrerequisite("GL_EXT_texture_cube_map_array");
1006
addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
1007
1008
// TODO: http://anglebug.com/5989 Intel Linux crashing on teardown
1009
// TODO: http://anglebug.com/5994 Intel Windows timing out periodically
1010
if ((IsLinux() || IsWindows()) && IsIntel() &&
1011
mParams.getRenderer() == EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE)
1012
{
1013
mSkipTest = true;
1014
}
1015
}
1016
1017
if (mParams.testID == RestrictedTraceID::cookie_run_kingdom)
1018
{
1019
addExtensionPrerequisite("GL_EXT_texture_cube_map_array");
1020
addExtensionPrerequisite("GL_OES_EGL_image_external");
1021
1022
// TODO: http://anglebug.com/6017 ARM doesn't have enough VS storage blocks
1023
if (IsAndroid() && IsARM())
1024
{
1025
mSkipTest = true;
1026
}
1027
}
1028
1029
if (mParams.testID == RestrictedTraceID::genshin_impact)
1030
{
1031
addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
1032
1033
// TODO: http://anglebug.com/6023 Crashes on Pixel 2 in vulkan driver
1034
// TODO: http://anglebug.com/6029 Crashes on Linux Intel Vulkan
1035
if (((IsLinux() && IsIntel()) || IsPixel2()) &&
1036
mParams.getRenderer() == EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE)
1037
{
1038
mSkipTest = true;
1039
}
1040
}
1041
1042
if (mParams.testID == RestrictedTraceID::pubg_mobile_skydive ||
1043
mParams.testID == RestrictedTraceID::pubg_mobile_battle_royale)
1044
{
1045
addExtensionPrerequisite("GL_EXT_texture_buffer");
1046
1047
// TODO: http://anglebug.com/6240 Internal errors on Windows using Intel or Nvida
1048
if (IsWindows() && (IsIntel() || IsNVIDIA()) && mParams.driver == GLESDriverType::SystemWGL)
1049
{
1050
mSkipTest = true;
1051
}
1052
}
1053
1054
if (mParams.testID == RestrictedTraceID::sakura_school_simulator)
1055
{
1056
// Flaky on Intel. http://anglebug.com/6294
1057
if (IsWindows() && IsIntel())
1058
{
1059
mSkipTest = true;
1060
}
1061
}
1062
1063
if (mParams.testID == RestrictedTraceID::scrabble_go)
1064
{
1065
addExtensionPrerequisite("GL_KHR_texture_compression_astc_ldr");
1066
}
1067
1068
if (mParams.testID == RestrictedTraceID::world_of_kings)
1069
{
1070
addExtensionPrerequisite("GL_OES_EGL_image_external");
1071
}
1072
1073
// We already swap in TracePerfTest::drawBenchmark, no need to swap again in the harness.
1074
disableTestHarnessSwap();
1075
1076
gCurrentTracePerfTest = this;
1077
1078
if (gTraceTestValidation)
1079
{
1080
const TraceInfo &traceInfo = GetTraceInfo(mParams.testID);
1081
mStepsToRun = (traceInfo.endFrame - traceInfo.startFrame + 1);
1082
}
1083
}
1084
1085
void TracePerfTest::initializeBenchmark()
1086
{
1087
const TraceInfo &traceInfo = GetTraceInfo(mParams.testID);
1088
1089
mStartingDirectory = angle::GetCWD().value();
1090
1091
std::stringstream traceNameStr;
1092
traceNameStr << "angle_restricted_trace_" << traceInfo.name;
1093
std::string traceName = traceNameStr.str();
1094
mTraceLibrary.reset(new TraceLibrary(traceName.c_str()));
1095
1096
// To load the trace data path correctly we set the CWD to the executable dir.
1097
if (!IsAndroid())
1098
{
1099
std::string exeDir = angle::GetExecutableDirectory();
1100
angle::SetCWD(exeDir.c_str());
1101
}
1102
1103
trace_angle::LoadEGL(TraceLoadProc);
1104
trace_angle::LoadGLES(TraceLoadProc);
1105
1106
if (!mTraceLibrary->valid())
1107
{
1108
ERR() << "Could not load trace library.";
1109
mSkipTest = true;
1110
return;
1111
}
1112
1113
mStartFrame = traceInfo.startFrame;
1114
mEndFrame = traceInfo.endFrame;
1115
mTraceLibrary->setBinaryDataDecompressCallback(DecompressBinaryData);
1116
1117
mTraceLibrary->setValidateSerializedStateCallback(ValidateSerializedState);
1118
1119
std::string relativeTestDataDir = std::string("src/tests/restricted_traces/") + traceInfo.name;
1120
1121
constexpr size_t kMaxDataDirLen = 1000;
1122
char testDataDir[kMaxDataDirLen];
1123
if (!angle::FindTestDataPath(relativeTestDataDir.c_str(), testDataDir, kMaxDataDirLen))
1124
{
1125
ERR() << "Could not find test data folder.";
1126
mSkipTest = true;
1127
return;
1128
}
1129
1130
mTraceLibrary->setBinaryDataDir(testDataDir);
1131
1132
if (gMinimizeGPUWork)
1133
{
1134
// Shrink the offscreen window to 1x1.
1135
mWindowWidth = 1;
1136
mWindowHeight = 1;
1137
}
1138
else
1139
{
1140
mWindowWidth = mTestParams.windowWidth;
1141
mWindowHeight = mTestParams.windowHeight;
1142
}
1143
mCurrentFrame = mStartFrame;
1144
1145
if (IsAndroid())
1146
{
1147
// On Android, set the orientation used by the app, based on width/height
1148
getWindow()->setOrientation(mTestParams.windowWidth, mTestParams.windowHeight);
1149
}
1150
1151
// If we're rendering offscreen we set up a default back buffer.
1152
if (mParams.surfaceType == SurfaceType::Offscreen)
1153
{
1154
if (!IsAndroid())
1155
{
1156
mWindowWidth *= 4;
1157
mWindowHeight *= 4;
1158
}
1159
1160
glGenRenderbuffers(1, &mOffscreenDepthStencil);
1161
glBindRenderbuffer(GL_RENDERBUFFER, mOffscreenDepthStencil);
1162
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, mWindowWidth, mWindowHeight);
1163
glBindRenderbuffer(GL_RENDERBUFFER, 0);
1164
1165
glGenFramebuffers(mMaxOffscreenBufferCount, mOffscreenFramebuffers.data());
1166
glGenTextures(mMaxOffscreenBufferCount, mOffscreenTextures.data());
1167
for (int i = 0; i < mMaxOffscreenBufferCount; i++)
1168
{
1169
glBindFramebuffer(GL_FRAMEBUFFER, mOffscreenFramebuffers[i]);
1170
1171
// Hard-code RGBA8/D24S8. This should be specified in the trace info.
1172
glBindTexture(GL_TEXTURE_2D, mOffscreenTextures[i]);
1173
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, mWindowWidth, mWindowHeight, 0, GL_RGBA,
1174
GL_UNSIGNED_BYTE, nullptr);
1175
1176
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
1177
mOffscreenTextures[i], 0);
1178
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER,
1179
mOffscreenDepthStencil);
1180
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
1181
mOffscreenDepthStencil);
1182
glBindTexture(GL_TEXTURE_2D, 0);
1183
}
1184
}
1185
1186
// Potentially slow. Can load a lot of resources.
1187
mTraceLibrary->setupReplay();
1188
1189
glFinish();
1190
1191
ASSERT_GE(mEndFrame, mStartFrame);
1192
1193
getWindow()->ignoreSizeEvents();
1194
getWindow()->setVisible(true);
1195
1196
// If we're re-tracing, trigger capture start after setup. This ensures the Setup function gets
1197
// recaptured into another Setup function and not merged with the first frame.
1198
if (gRetraceMode)
1199
{
1200
getGLWindow()->swap();
1201
}
1202
}
1203
1204
#undef TRACE_TEST_CASE
1205
1206
void TracePerfTest::destroyBenchmark()
1207
{
1208
if (mParams.surfaceType == SurfaceType::Offscreen)
1209
{
1210
glDeleteTextures(mMaxOffscreenBufferCount, mOffscreenTextures.data());
1211
mOffscreenTextures.fill(0);
1212
1213
glDeleteRenderbuffers(1, &mOffscreenDepthStencil);
1214
mOffscreenDepthStencil = 0;
1215
1216
glDeleteFramebuffers(mMaxOffscreenBufferCount, mOffscreenFramebuffers.data());
1217
mOffscreenFramebuffers.fill(0);
1218
}
1219
1220
mTraceLibrary->finishReplay();
1221
mTraceLibrary.reset(nullptr);
1222
1223
// In order for the next test to load, restore the working directory
1224
angle::SetCWD(mStartingDirectory.c_str());
1225
}
1226
1227
void TracePerfTest::sampleTime()
1228
{
1229
if (mUseTimestampQueries)
1230
{
1231
GLint64 glTime;
1232
// glGetInteger64vEXT is exported by newer versions of the timer query extensions.
1233
// Unfortunately only the core EP is exposed by some desktop drivers (e.g. NVIDIA).
1234
if (glGetInteger64vEXT)
1235
{
1236
glGetInteger64vEXT(GL_TIMESTAMP_EXT, &glTime);
1237
}
1238
else
1239
{
1240
glGetInteger64v(GL_TIMESTAMP_EXT, &glTime);
1241
}
1242
mTimeline.push_back({glTime, angle::GetHostTimeSeconds()});
1243
}
1244
}
1245
1246
void TracePerfTest::drawBenchmark()
1247
{
1248
constexpr uint32_t kFramesPerX = 6;
1249
constexpr uint32_t kFramesPerY = 4;
1250
constexpr uint32_t kFramesPerXY = kFramesPerY * kFramesPerX;
1251
1252
const uint32_t kOffscreenOffsetX =
1253
static_cast<uint32_t>(static_cast<double>(mTestParams.windowWidth) / 3.0f);
1254
const uint32_t kOffscreenOffsetY =
1255
static_cast<uint32_t>(static_cast<double>(mTestParams.windowHeight) / 3.0f);
1256
const uint32_t kOffscreenWidth = kOffscreenOffsetX;
1257
const uint32_t kOffscreenHeight = kOffscreenOffsetY;
1258
1259
const uint32_t kOffscreenFrameWidth = static_cast<uint32_t>(
1260
static_cast<double>(kOffscreenWidth / static_cast<double>(kFramesPerX)));
1261
const uint32_t kOffscreenFrameHeight = static_cast<uint32_t>(
1262
static_cast<double>(kOffscreenHeight / static_cast<double>(kFramesPerY)));
1263
1264
// Add a time sample from GL and the host.
1265
if (mCurrentFrame == mStartFrame)
1266
{
1267
sampleTime();
1268
}
1269
1270
if (mParams.surfaceType == SurfaceType::Offscreen)
1271
{
1272
// Some driver (ARM and ANGLE) try to nop or defer the glFlush if it is called within the
1273
// renderpass to avoid breaking renderpass (performance reason). For app traces that does
1274
// not use any FBO, when we run in the offscreen mode, there is no frame boundary and
1275
// glFlush call we issued at end of frame will get skipped. To overcome this (and also
1276
// matches what onscreen double buffering behavior as well), we use two offscreen FBOs and
1277
// ping pong between them for each frame.
1278
glBindFramebuffer(GL_FRAMEBUFFER,
1279
mOffscreenFramebuffers[mTotalFrameCount % mMaxOffscreenBufferCount]);
1280
}
1281
1282
char frameName[32];
1283
sprintf(frameName, "Frame %u", mCurrentFrame);
1284
beginInternalTraceEvent(frameName);
1285
1286
startGpuTimer();
1287
mTraceLibrary->replayFrame(mCurrentFrame);
1288
stopGpuTimer();
1289
1290
if (mParams.surfaceType == SurfaceType::Offscreen)
1291
{
1292
if (gMinimizeGPUWork)
1293
{
1294
// To keep GPU work minimum, we skip the blit.
1295
glFlush();
1296
mOffscreenFrameCount++;
1297
}
1298
else
1299
{
1300
GLint currentDrawFBO, currentReadFBO;
1301
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &currentDrawFBO);
1302
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &currentReadFBO);
1303
1304
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
1305
glBindFramebuffer(
1306
GL_READ_FRAMEBUFFER,
1307
mOffscreenFramebuffers[mOffscreenFrameCount % mMaxOffscreenBufferCount]);
1308
1309
uint32_t frameX = (mOffscreenFrameCount % kFramesPerXY) % kFramesPerX;
1310
uint32_t frameY = (mOffscreenFrameCount % kFramesPerXY) / kFramesPerX;
1311
uint32_t windowX = kOffscreenOffsetX + frameX * kOffscreenFrameWidth;
1312
uint32_t windowY = kOffscreenOffsetY + frameY * kOffscreenFrameHeight;
1313
1314
if (gVerboseLogging)
1315
{
1316
printf("Frame %d: x %d y %d (screen x %d, screen y %d)\n", mOffscreenFrameCount,
1317
frameX, frameY, windowX, windowY);
1318
}
1319
1320
GLboolean scissorTest = GL_FALSE;
1321
glGetBooleanv(GL_SCISSOR_TEST, &scissorTest);
1322
1323
if (scissorTest)
1324
{
1325
glDisable(GL_SCISSOR_TEST);
1326
}
1327
1328
glBlitFramebuffer(0, 0, mWindowWidth, mWindowHeight, windowX, windowY,
1329
windowX + kOffscreenFrameWidth, windowY + kOffscreenFrameHeight,
1330
GL_COLOR_BUFFER_BIT, GL_NEAREST);
1331
1332
if (frameX == kFramesPerX - 1 && frameY == kFramesPerY - 1)
1333
{
1334
swap();
1335
glBindFramebuffer(GL_FRAMEBUFFER, 0);
1336
glClear(GL_COLOR_BUFFER_BIT);
1337
mOffscreenFrameCount = 0;
1338
}
1339
else
1340
{
1341
glFlush();
1342
mOffscreenFrameCount++;
1343
}
1344
1345
if (scissorTest)
1346
{
1347
glEnable(GL_SCISSOR_TEST);
1348
}
1349
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, currentDrawFBO);
1350
glBindFramebuffer(GL_READ_FRAMEBUFFER, currentReadFBO);
1351
}
1352
1353
mTotalFrameCount++;
1354
}
1355
else
1356
{
1357
swap();
1358
}
1359
1360
endInternalTraceEvent(frameName);
1361
1362
if (mCurrentFrame == mEndFrame)
1363
{
1364
mTraceLibrary->resetReplay();
1365
mCurrentFrame = mStartFrame;
1366
}
1367
else
1368
{
1369
mCurrentFrame++;
1370
}
1371
1372
// Process any running queries once per iteration.
1373
for (size_t queryIndex = 0; queryIndex < mRunningQueries.size();)
1374
{
1375
const QueryInfo &query = mRunningQueries[queryIndex];
1376
1377
GLuint endResultAvailable = 0;
1378
glGetQueryObjectuivEXT(query.endTimestampQuery, GL_QUERY_RESULT_AVAILABLE,
1379
&endResultAvailable);
1380
1381
if (endResultAvailable == GL_TRUE)
1382
{
1383
char fboName[32];
1384
sprintf(fboName, "FBO %u", query.framebuffer);
1385
1386
GLint64 beginTimestamp = 0;
1387
glGetQueryObjecti64vEXT(query.beginTimestampQuery, GL_QUERY_RESULT, &beginTimestamp);
1388
glDeleteQueriesEXT(1, &query.beginTimestampQuery);
1389
double beginHostTime = getHostTimeFromGLTime(beginTimestamp);
1390
beginGLTraceEvent(fboName, beginHostTime);
1391
1392
GLint64 endTimestamp = 0;
1393
glGetQueryObjecti64vEXT(query.endTimestampQuery, GL_QUERY_RESULT, &endTimestamp);
1394
glDeleteQueriesEXT(1, &query.endTimestampQuery);
1395
double endHostTime = getHostTimeFromGLTime(endTimestamp);
1396
endGLTraceEvent(fboName, endHostTime);
1397
1398
mRunningQueries.erase(mRunningQueries.begin() + queryIndex);
1399
}
1400
else
1401
{
1402
queryIndex++;
1403
}
1404
}
1405
}
1406
1407
// Converts a GL timestamp into a host-side CPU time aligned with "GetHostTimeSeconds".
1408
// This check is necessary to line up sampled trace events in a consistent timeline.
1409
// Uses a linear interpolation from a series of samples. We do a blocking call to sample
1410
// both host and GL time once per swap. We then find the two closest GL timestamps and
1411
// interpolate the host times between them to compute our result. If we are past the last
1412
// GL timestamp we sample a new data point pair.
1413
double TracePerfTest::getHostTimeFromGLTime(GLint64 glTime)
1414
{
1415
// Find two samples to do a lerp.
1416
size_t firstSampleIndex = mTimeline.size() - 1;
1417
while (firstSampleIndex > 0)
1418
{
1419
if (mTimeline[firstSampleIndex].glTime < glTime)
1420
{
1421
break;
1422
}
1423
firstSampleIndex--;
1424
}
1425
1426
// Add an extra sample if we're missing an ending sample.
1427
if (firstSampleIndex == mTimeline.size() - 1)
1428
{
1429
sampleTime();
1430
}
1431
1432
const TimeSample &start = mTimeline[firstSampleIndex];
1433
const TimeSample &end = mTimeline[firstSampleIndex + 1];
1434
1435
// Note: we have observed in some odd cases later timestamps producing values that are
1436
// smaller than preceding timestamps. This bears further investigation.
1437
1438
// Compute the scaling factor for the lerp.
1439
double glDelta = static_cast<double>(glTime - start.glTime);
1440
double glRange = static_cast<double>(end.glTime - start.glTime);
1441
double t = glDelta / glRange;
1442
1443
// Lerp(t1, t2, t)
1444
double hostRange = end.hostTime - start.hostTime;
1445
return mTimeline[firstSampleIndex].hostTime + hostRange * t;
1446
}
1447
1448
EGLContext TracePerfTest::onEglCreateContext(EGLDisplay display,
1449
EGLConfig config,
1450
EGLContext share_context,
1451
EGLint const *attrib_list)
1452
{
1453
GLWindowContext newContext =
1454
getGLWindow()->createContextGeneric(reinterpret_cast<GLWindowContext>(share_context));
1455
return reinterpret_cast<EGLContext>(newContext);
1456
}
1457
1458
void TracePerfTest::onEglMakeCurrent(EGLDisplay display,
1459
EGLSurface draw,
1460
EGLSurface read,
1461
EGLContext context)
1462
{
1463
getGLWindow()->makeCurrentGeneric(reinterpret_cast<GLWindowContext>(context));
1464
}
1465
1466
EGLContext TracePerfTest::onEglGetCurrentContext()
1467
{
1468
return getGLWindow()->getCurrentContextGeneric();
1469
}
1470
1471
// Triggered when the replay calls glBindFramebuffer.
1472
void TracePerfTest::onReplayFramebufferChange(GLenum target, GLuint framebuffer)
1473
{
1474
if (framebuffer == 0 && mParams.surfaceType == SurfaceType::Offscreen)
1475
{
1476
glBindFramebuffer(target,
1477
mOffscreenFramebuffers[mTotalFrameCount % mMaxOffscreenBufferCount]);
1478
}
1479
else
1480
{
1481
glBindFramebuffer(target, framebuffer);
1482
}
1483
1484
switch (target)
1485
{
1486
case GL_FRAMEBUFFER:
1487
mDrawFramebufferBinding = framebuffer;
1488
mReadFramebufferBinding = framebuffer;
1489
break;
1490
case GL_DRAW_FRAMEBUFFER:
1491
mDrawFramebufferBinding = framebuffer;
1492
break;
1493
case GL_READ_FRAMEBUFFER:
1494
mReadFramebufferBinding = framebuffer;
1495
return;
1496
1497
default:
1498
UNREACHABLE();
1499
break;
1500
}
1501
1502
if (!mUseTimestampQueries)
1503
return;
1504
1505
// We have at most one active timestamp query at a time. This code will end the current
1506
// query and immediately start a new one.
1507
if (mCurrentQuery.beginTimestampQuery != 0)
1508
{
1509
glGenQueriesEXT(1, &mCurrentQuery.endTimestampQuery);
1510
glQueryCounterEXT(mCurrentQuery.endTimestampQuery, GL_TIMESTAMP_EXT);
1511
mRunningQueries.push_back(mCurrentQuery);
1512
mCurrentQuery = {};
1513
}
1514
1515
ASSERT(mCurrentQuery.beginTimestampQuery == 0);
1516
1517
glGenQueriesEXT(1, &mCurrentQuery.beginTimestampQuery);
1518
glQueryCounterEXT(mCurrentQuery.beginTimestampQuery, GL_TIMESTAMP_EXT);
1519
mCurrentQuery.framebuffer = framebuffer;
1520
}
1521
1522
std::string GetDiffPath()
1523
{
1524
#if defined(ANGLE_PLATFORM_WINDOWS)
1525
std::array<char, MAX_PATH> filenameBuffer = {};
1526
char *filenamePtr = nullptr;
1527
if (SearchPathA(NULL, "diff", ".exe", MAX_PATH, filenameBuffer.data(), &filenamePtr) == 0)
1528
{
1529
return "";
1530
}
1531
return std::string(filenameBuffer.data());
1532
#else
1533
return "/usr/bin/diff";
1534
#endif // defined(ANGLE_PLATFORM_WINDOWS)
1535
}
1536
1537
void PrintFileDiff(const char *aFilePath, const char *bFilePath)
1538
{
1539
std::string pathToDiff = GetDiffPath();
1540
if (pathToDiff.empty())
1541
{
1542
printf("Could not find diff in the path.\n");
1543
return;
1544
}
1545
1546
std::vector<const char *> args;
1547
args.push_back(pathToDiff.c_str());
1548
args.push_back(aFilePath);
1549
args.push_back(bFilePath);
1550
args.push_back("-u3");
1551
1552
printf("Calling");
1553
for (const char *arg : args)
1554
{
1555
printf(" %s", arg);
1556
}
1557
printf("\n");
1558
1559
ProcessHandle proc(LaunchProcess(args, ProcessOutputCapture::StdoutOnly));
1560
if (proc && proc->finish())
1561
{
1562
printf("\n%s\n", proc->getStdout().c_str());
1563
}
1564
}
1565
1566
void TracePerfTest::validateSerializedState(const char *expectedCapturedSerializedState,
1567
const char *fileName,
1568
uint32_t line)
1569
{
1570
if (!gTraceTestValidation)
1571
{
1572
return;
1573
}
1574
1575
printf("Serialization checkpoint %s:%u...\n", fileName, line);
1576
1577
const GLubyte *bytes = glGetString(GL_SERIALIZED_CONTEXT_STRING_ANGLE);
1578
const char *actualReplayedSerializedState = reinterpret_cast<const char *>(bytes);
1579
if (strcmp(expectedCapturedSerializedState, actualReplayedSerializedState) == 0)
1580
{
1581
printf("Serialization match.\n");
1582
return;
1583
}
1584
1585
printf("Serialization mismatch!\n");
1586
1587
constexpr size_t kMaxPath = 1024;
1588
char aFilePath[kMaxPath] = {};
1589
if (CreateTemporaryFile(aFilePath, kMaxPath))
1590
{
1591
printf("Saving \"expected\" capture serialization to \"%s\".\n", aFilePath);
1592
FILE *fpA = fopen(aFilePath, "wt");
1593
ASSERT(fpA);
1594
fprintf(fpA, "%s", expectedCapturedSerializedState);
1595
fclose(fpA);
1596
}
1597
1598
char bFilePath[kMaxPath] = {};
1599
if (CreateTemporaryFile(bFilePath, kMaxPath))
1600
{
1601
printf("Saving \"actual\" replay serialization to \"%s\".\n", bFilePath);
1602
FILE *fpB = fopen(bFilePath, "wt");
1603
ASSERT(fpB);
1604
fprintf(fpB, "%s", actualReplayedSerializedState);
1605
fclose(fpB);
1606
}
1607
1608
PrintFileDiff(aFilePath, bFilePath);
1609
}
1610
1611
bool TracePerfTest::isDefaultFramebuffer(GLenum target) const
1612
{
1613
switch (target)
1614
{
1615
case GL_FRAMEBUFFER:
1616
case GL_DRAW_FRAMEBUFFER:
1617
return (mDrawFramebufferBinding == 0);
1618
1619
case GL_READ_FRAMEBUFFER:
1620
return (mReadFramebufferBinding == 0);
1621
1622
default:
1623
UNREACHABLE();
1624
return false;
1625
}
1626
}
1627
1628
GLenum ConvertDefaultFramebufferEnum(GLenum value)
1629
{
1630
switch (value)
1631
{
1632
case GL_NONE:
1633
return GL_NONE;
1634
case GL_BACK:
1635
case GL_COLOR:
1636
return GL_COLOR_ATTACHMENT0;
1637
case GL_DEPTH:
1638
return GL_DEPTH_ATTACHMENT;
1639
case GL_STENCIL:
1640
return GL_STENCIL_ATTACHMENT;
1641
case GL_DEPTH_STENCIL:
1642
return GL_DEPTH_STENCIL_ATTACHMENT;
1643
default:
1644
UNREACHABLE();
1645
return GL_NONE;
1646
}
1647
}
1648
1649
std::vector<GLenum> ConvertDefaultFramebufferEnums(GLsizei numAttachments,
1650
const GLenum *attachments)
1651
{
1652
std::vector<GLenum> translatedAttachments;
1653
for (GLsizei attachmentIndex = 0; attachmentIndex < numAttachments; ++attachmentIndex)
1654
{
1655
GLenum converted = ConvertDefaultFramebufferEnum(attachments[attachmentIndex]);
1656
translatedAttachments.push_back(converted);
1657
}
1658
return translatedAttachments;
1659
}
1660
1661
// Needs special handling to treat the 0 framebuffer in offscreen mode.
1662
void TracePerfTest::onReplayInvalidateFramebuffer(GLenum target,
1663
GLsizei numAttachments,
1664
const GLenum *attachments)
1665
{
1666
if (mParams.surfaceType != SurfaceType::Offscreen || !isDefaultFramebuffer(target))
1667
{
1668
glInvalidateFramebuffer(target, numAttachments, attachments);
1669
}
1670
else
1671
{
1672
std::vector<GLenum> translatedAttachments =
1673
ConvertDefaultFramebufferEnums(numAttachments, attachments);
1674
glInvalidateFramebuffer(target, numAttachments, translatedAttachments.data());
1675
}
1676
}
1677
1678
void TracePerfTest::onReplayInvalidateSubFramebuffer(GLenum target,
1679
GLsizei numAttachments,
1680
const GLenum *attachments,
1681
GLint x,
1682
GLint y,
1683
GLsizei width,
1684
GLsizei height)
1685
{
1686
if (mParams.surfaceType != SurfaceType::Offscreen || !isDefaultFramebuffer(target))
1687
{
1688
glInvalidateSubFramebuffer(target, numAttachments, attachments, x, y, width, height);
1689
}
1690
else
1691
{
1692
std::vector<GLenum> translatedAttachments =
1693
ConvertDefaultFramebufferEnums(numAttachments, attachments);
1694
glInvalidateSubFramebuffer(target, numAttachments, translatedAttachments.data(), x, y,
1695
width, height);
1696
}
1697
}
1698
1699
void TracePerfTest::onReplayDrawBuffers(GLsizei n, const GLenum *bufs)
1700
{
1701
if (mParams.surfaceType != SurfaceType::Offscreen || !isDefaultFramebuffer(GL_DRAW_FRAMEBUFFER))
1702
{
1703
glDrawBuffers(n, bufs);
1704
}
1705
else
1706
{
1707
std::vector<GLenum> translatedBufs = ConvertDefaultFramebufferEnums(n, bufs);
1708
glDrawBuffers(n, translatedBufs.data());
1709
}
1710
}
1711
1712
void TracePerfTest::onReplayReadBuffer(GLenum src)
1713
{
1714
if (mParams.surfaceType != SurfaceType::Offscreen || !isDefaultFramebuffer(GL_READ_FRAMEBUFFER))
1715
{
1716
glReadBuffer(src);
1717
}
1718
else
1719
{
1720
GLenum translated = ConvertDefaultFramebufferEnum(src);
1721
glReadBuffer(translated);
1722
}
1723
}
1724
1725
void TracePerfTest::onReplayDiscardFramebufferEXT(GLenum target,
1726
GLsizei numAttachments,
1727
const GLenum *attachments)
1728
{
1729
if (mParams.surfaceType != SurfaceType::Offscreen || !isDefaultFramebuffer(target))
1730
{
1731
glDiscardFramebufferEXT(target, numAttachments, attachments);
1732
}
1733
else
1734
{
1735
std::vector<GLenum> translatedAttachments =
1736
ConvertDefaultFramebufferEnums(numAttachments, attachments);
1737
glDiscardFramebufferEXT(target, numAttachments, translatedAttachments.data());
1738
}
1739
}
1740
1741
void TracePerfTest::swap()
1742
{
1743
// Capture a screenshot if enabled.
1744
if (gScreenShotDir != nullptr && !mScreenshotSaved &&
1745
static_cast<uint32_t>(gScreenShotFrame) == mCurrentFrame)
1746
{
1747
std::stringstream screenshotNameStr;
1748
screenshotNameStr << gScreenShotDir << GetPathSeparator() << "angle" << mBackend << "_"
1749
<< mStory;
1750
1751
// Add a marker to the name for any screenshot that isn't start frame
1752
if (mStartFrame != static_cast<uint32_t>(gScreenShotFrame))
1753
{
1754
screenshotNameStr << "_frame" << gScreenShotFrame;
1755
}
1756
1757
screenshotNameStr << ".png";
1758
1759
std::string screenshotName = screenshotNameStr.str();
1760
saveScreenshot(screenshotName);
1761
mScreenshotSaved = true;
1762
}
1763
1764
getGLWindow()->swap();
1765
}
1766
1767
void TracePerfTest::saveScreenshot(const std::string &screenshotName)
1768
{
1769
// The frame is already rendered and is waiting in the default framebuffer.
1770
1771
// RGBA 4-byte data.
1772
uint32_t pixelCount = mTestParams.windowWidth * mTestParams.windowHeight;
1773
std::vector<uint8_t> pixelData(pixelCount * 4);
1774
1775
// Only unbind the framebuffer on context versions where it's available.
1776
const TraceInfo &traceInfo = GetTraceInfo(mParams.testID);
1777
if (traceInfo.contextClientMajorVersion > 1)
1778
{
1779
glBindFramebuffer(GL_FRAMEBUFFER, 0);
1780
}
1781
1782
glReadPixels(0, 0, mTestParams.windowWidth, mTestParams.windowHeight, GL_RGBA, GL_UNSIGNED_BYTE,
1783
pixelData.data());
1784
1785
// Convert to RGB and flip y.
1786
std::vector<uint8_t> rgbData(pixelCount * 3);
1787
for (EGLint y = 0; y < mTestParams.windowHeight; ++y)
1788
{
1789
for (EGLint x = 0; x < mTestParams.windowWidth; ++x)
1790
{
1791
EGLint srcPixel = x + y * mTestParams.windowWidth;
1792
EGLint dstPixel = x + (mTestParams.windowHeight - y - 1) * mTestParams.windowWidth;
1793
memcpy(&rgbData[dstPixel * 3], &pixelData[srcPixel * 4], 3);
1794
}
1795
}
1796
1797
if (!angle::SavePNGRGB(screenshotName.c_str(), "ANGLE Screenshot", mTestParams.windowWidth,
1798
mTestParams.windowHeight, rgbData))
1799
{
1800
FAIL() << "Error saving screenshot: " << screenshotName;
1801
}
1802
else
1803
{
1804
printf("Saved screenshot: '%s'\n", screenshotName.c_str());
1805
}
1806
}
1807
1808
TracePerfParams CombineTestID(const TracePerfParams &in, RestrictedTraceID id)
1809
{
1810
const TraceInfo &traceInfo = GetTraceInfo(id);
1811
1812
TracePerfParams out = in;
1813
out.testID = id;
1814
out.majorVersion = traceInfo.contextClientMajorVersion;
1815
out.minorVersion = traceInfo.contextClientMinorVersion;
1816
out.windowWidth = traceInfo.drawSurfaceWidth;
1817
out.windowHeight = traceInfo.drawSurfaceHeight;
1818
out.colorSpace = traceInfo.drawSurfaceColorSpace;
1819
return out;
1820
}
1821
1822
TracePerfParams CombineWithSurfaceType(const TracePerfParams &in, SurfaceType surfaceType)
1823
{
1824
TracePerfParams out = in;
1825
out.surfaceType = surfaceType;
1826
1827
if (!IsAndroid() && surfaceType == SurfaceType::Offscreen)
1828
{
1829
out.windowWidth /= 4;
1830
out.windowHeight /= 4;
1831
}
1832
1833
// We track GPU time only in frame-rate-limited cases.
1834
out.trackGpuTime = surfaceType == SurfaceType::WindowWithVSync;
1835
1836
return out;
1837
}
1838
1839
} // anonymous namespace
1840
1841
using namespace params;
1842
using P = TracePerfParams;
1843
using PV = std::vector<P>;
1844
1845
void RegisterTraceTests()
1846
{
1847
std::vector<SurfaceType> surfaceTypes = {SurfaceType::Window};
1848
if (gEnableAllTraceTests)
1849
{
1850
surfaceTypes.push_back(SurfaceType::Offscreen);
1851
surfaceTypes.push_back(SurfaceType::WindowWithVSync);
1852
}
1853
1854
std::vector<ModifierFunc<P>> renderers = {Vulkan<P>, Native<P>};
1855
if (gEnableAllTraceTests)
1856
{
1857
if (!IsAndroid())
1858
{
1859
renderers.push_back(VulkanMockICD<P>);
1860
}
1861
renderers.push_back(VulkanSwiftShader<P>);
1862
}
1863
1864
PV testsWithID = CombineWithValues({P()}, AllEnums<RestrictedTraceID>(), CombineTestID);
1865
PV testsWithSurfaceType = CombineWithValues(testsWithID, surfaceTypes, CombineWithSurfaceType);
1866
PV testsWithRenderer = CombineWithFuncs(testsWithSurfaceType, renderers);
1867
PV filteredTests = FilterTestParams(testsWithRenderer);
1868
1869
for (const TracePerfParams &params : filteredTests)
1870
{
1871
// Force on features if we're validating serialization.
1872
TracePerfParams overrideParams = params;
1873
if (gTraceTestValidation)
1874
{
1875
// Enable limits when validating traces because we usually turn off capture.
1876
overrideParams.eglParameters.captureLimits = EGL_TRUE;
1877
1878
// This feature should also be enabled in capture to mirror the replay.
1879
overrideParams.eglParameters.forceInitShaderVariables = EGL_TRUE;
1880
}
1881
1882
auto factory = [overrideParams]() { return new TracePerfTest(overrideParams); };
1883
std::string paramName = testing::PrintToString(params);
1884
std::stringstream testNameStr;
1885
testNameStr << "Run/" << paramName;
1886
std::string testName = testNameStr.str();
1887
testing::RegisterTest("TracePerfTest", testName.c_str(), nullptr, paramName.c_str(),
1888
__FILE__, __LINE__, factory);
1889
}
1890
}
1891
1892