xref: /aosp_15_r20/external/angle/src/libANGLE/capture/FrameCapture.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1*8975f5c5SAndroid Build Coastguard Worker //
2*8975f5c5SAndroid Build Coastguard Worker // Copyright 2019 The ANGLE Project Authors. All rights reserved.
3*8975f5c5SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
4*8975f5c5SAndroid Build Coastguard Worker // found in the LICENSE file.
5*8975f5c5SAndroid Build Coastguard Worker //
6*8975f5c5SAndroid Build Coastguard Worker // FrameCapture.cpp:
7*8975f5c5SAndroid Build Coastguard Worker //   ANGLE Frame capture implementation.
8*8975f5c5SAndroid Build Coastguard Worker //
9*8975f5c5SAndroid Build Coastguard Worker 
10*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/capture/FrameCapture.h"
11*8975f5c5SAndroid Build Coastguard Worker 
12*8975f5c5SAndroid Build Coastguard Worker #include <cerrno>
13*8975f5c5SAndroid Build Coastguard Worker #include <cstring>
14*8975f5c5SAndroid Build Coastguard Worker #include <fstream>
15*8975f5c5SAndroid Build Coastguard Worker #include <queue>
16*8975f5c5SAndroid Build Coastguard Worker #include <string>
17*8975f5c5SAndroid Build Coastguard Worker 
18*8975f5c5SAndroid Build Coastguard Worker #include "sys/stat.h"
19*8975f5c5SAndroid Build Coastguard Worker 
20*8975f5c5SAndroid Build Coastguard Worker #include "common/aligned_memory.h"
21*8975f5c5SAndroid Build Coastguard Worker #include "common/angle_version_info.h"
22*8975f5c5SAndroid Build Coastguard Worker #include "common/frame_capture_utils.h"
23*8975f5c5SAndroid Build Coastguard Worker #include "common/gl_enum_utils.h"
24*8975f5c5SAndroid Build Coastguard Worker #include "common/mathutil.h"
25*8975f5c5SAndroid Build Coastguard Worker #include "common/serializer/JsonSerializer.h"
26*8975f5c5SAndroid Build Coastguard Worker #include "common/string_utils.h"
27*8975f5c5SAndroid Build Coastguard Worker #include "common/system_utils.h"
28*8975f5c5SAndroid Build Coastguard Worker #include "gpu_info_util/SystemInfo.h"
29*8975f5c5SAndroid Build Coastguard Worker #include "image_util/storeimage.h"
30*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/Config.h"
31*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/Context.h"
32*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/Context.inl.h"
33*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/Display.h"
34*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/EGLSync.h"
35*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/Fence.h"
36*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/Framebuffer.h"
37*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/GLES1Renderer.h"
38*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/Query.h"
39*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/ResourceMap.h"
40*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/Shader.h"
41*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/Surface.h"
42*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/VertexArray.h"
43*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/capture/capture_egl_autogen.h"
44*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/capture/capture_gles_1_0_autogen.h"
45*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/capture/capture_gles_2_0_autogen.h"
46*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/capture/capture_gles_3_0_autogen.h"
47*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/capture/capture_gles_3_1_autogen.h"
48*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/capture/capture_gles_3_2_autogen.h"
49*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/capture/capture_gles_ext_autogen.h"
50*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/capture/serialize.h"
51*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/entry_points_utils.h"
52*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/queryconversions.h"
53*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/queryutils.h"
54*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/renderer/driver_utils.h"
55*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/validationEGL.h"
56*8975f5c5SAndroid Build Coastguard Worker #include "third_party/ceval/ceval.h"
57*8975f5c5SAndroid Build Coastguard Worker 
58*8975f5c5SAndroid Build Coastguard Worker #define USE_SYSTEM_ZLIB
59*8975f5c5SAndroid Build Coastguard Worker #include "compression_utils_portable.h"
60*8975f5c5SAndroid Build Coastguard Worker 
61*8975f5c5SAndroid Build Coastguard Worker #if !ANGLE_CAPTURE_ENABLED
62*8975f5c5SAndroid Build Coastguard Worker #    error Frame capture must be enabled to include this file.
63*8975f5c5SAndroid Build Coastguard Worker #endif  // !ANGLE_CAPTURE_ENABLED
64*8975f5c5SAndroid Build Coastguard Worker 
65*8975f5c5SAndroid Build Coastguard Worker namespace angle
66*8975f5c5SAndroid Build Coastguard Worker {
67*8975f5c5SAndroid Build Coastguard Worker namespace
68*8975f5c5SAndroid Build Coastguard Worker {
69*8975f5c5SAndroid Build Coastguard Worker 
70*8975f5c5SAndroid Build Coastguard Worker // TODO: Consolidate to C output and remove option. http://anglebug.com/42266223
71*8975f5c5SAndroid Build Coastguard Worker 
72*8975f5c5SAndroid Build Coastguard Worker constexpr char kEnabledVarName[]        = "ANGLE_CAPTURE_ENABLED";
73*8975f5c5SAndroid Build Coastguard Worker constexpr char kOutDirectoryVarName[]   = "ANGLE_CAPTURE_OUT_DIR";
74*8975f5c5SAndroid Build Coastguard Worker constexpr char kFrameStartVarName[]     = "ANGLE_CAPTURE_FRAME_START";
75*8975f5c5SAndroid Build Coastguard Worker constexpr char kFrameEndVarName[]       = "ANGLE_CAPTURE_FRAME_END";
76*8975f5c5SAndroid Build Coastguard Worker constexpr char kTriggerVarName[]        = "ANGLE_CAPTURE_TRIGGER";
77*8975f5c5SAndroid Build Coastguard Worker constexpr char kCaptureLabelVarName[]   = "ANGLE_CAPTURE_LABEL";
78*8975f5c5SAndroid Build Coastguard Worker constexpr char kCompressionVarName[]    = "ANGLE_CAPTURE_COMPRESSION";
79*8975f5c5SAndroid Build Coastguard Worker constexpr char kSerializeStateVarName[] = "ANGLE_CAPTURE_SERIALIZE_STATE";
80*8975f5c5SAndroid Build Coastguard Worker constexpr char kValidationVarName[]     = "ANGLE_CAPTURE_VALIDATION";
81*8975f5c5SAndroid Build Coastguard Worker constexpr char kValidationExprVarName[] = "ANGLE_CAPTURE_VALIDATION_EXPR";
82*8975f5c5SAndroid Build Coastguard Worker constexpr char kSourceExtVarName[]      = "ANGLE_CAPTURE_SOURCE_EXT";
83*8975f5c5SAndroid Build Coastguard Worker constexpr char kSourceSizeVarName[]     = "ANGLE_CAPTURE_SOURCE_SIZE";
84*8975f5c5SAndroid Build Coastguard Worker constexpr char kForceShadowVarName[]    = "ANGLE_CAPTURE_FORCE_SHADOW";
85*8975f5c5SAndroid Build Coastguard Worker 
86*8975f5c5SAndroid Build Coastguard Worker constexpr size_t kBinaryAlignment   = 16;
87*8975f5c5SAndroid Build Coastguard Worker constexpr size_t kFunctionSizeLimit = 5000;
88*8975f5c5SAndroid Build Coastguard Worker 
89*8975f5c5SAndroid Build Coastguard Worker // Limit based on MSVC Compiler Error C2026
90*8975f5c5SAndroid Build Coastguard Worker constexpr size_t kStringLengthLimit = 16380;
91*8975f5c5SAndroid Build Coastguard Worker 
92*8975f5c5SAndroid Build Coastguard Worker // Default limit to number of bytes in a capture source files.
93*8975f5c5SAndroid Build Coastguard Worker constexpr char kDefaultSourceFileExt[]           = "cpp";
94*8975f5c5SAndroid Build Coastguard Worker constexpr size_t kDefaultSourceFileSizeThreshold = 400000;
95*8975f5c5SAndroid Build Coastguard Worker 
96*8975f5c5SAndroid Build Coastguard Worker // Android debug properties that correspond to the above environment variables
97*8975f5c5SAndroid Build Coastguard Worker constexpr char kAndroidEnabled[]        = "debug.angle.capture.enabled";
98*8975f5c5SAndroid Build Coastguard Worker constexpr char kAndroidOutDir[]         = "debug.angle.capture.out_dir";
99*8975f5c5SAndroid Build Coastguard Worker constexpr char kAndroidFrameStart[]     = "debug.angle.capture.frame_start";
100*8975f5c5SAndroid Build Coastguard Worker constexpr char kAndroidFrameEnd[]       = "debug.angle.capture.frame_end";
101*8975f5c5SAndroid Build Coastguard Worker constexpr char kAndroidTrigger[]        = "debug.angle.capture.trigger";
102*8975f5c5SAndroid Build Coastguard Worker constexpr char kAndroidCaptureLabel[]   = "debug.angle.capture.label";
103*8975f5c5SAndroid Build Coastguard Worker constexpr char kAndroidCompression[]    = "debug.angle.capture.compression";
104*8975f5c5SAndroid Build Coastguard Worker constexpr char kAndroidValidation[]     = "debug.angle.capture.validation";
105*8975f5c5SAndroid Build Coastguard Worker constexpr char kAndroidValidationExpr[] = "debug.angle.capture.validation_expr";
106*8975f5c5SAndroid Build Coastguard Worker constexpr char kAndroidSourceExt[]      = "debug.angle.capture.source_ext";
107*8975f5c5SAndroid Build Coastguard Worker constexpr char kAndroidSourceSize[]     = "debug.angle.capture.source_size";
108*8975f5c5SAndroid Build Coastguard Worker constexpr char kAndroidForceShadow[]    = "debug.angle.capture.force_shadow";
109*8975f5c5SAndroid Build Coastguard Worker 
110*8975f5c5SAndroid Build Coastguard Worker struct FramebufferCaptureFuncs
111*8975f5c5SAndroid Build Coastguard Worker {
FramebufferCaptureFuncsangle::__anoncf31a3f40111::FramebufferCaptureFuncs112*8975f5c5SAndroid Build Coastguard Worker     FramebufferCaptureFuncs(bool isGLES1)
113*8975f5c5SAndroid Build Coastguard Worker     {
114*8975f5c5SAndroid Build Coastguard Worker         if (isGLES1)
115*8975f5c5SAndroid Build Coastguard Worker         {
116*8975f5c5SAndroid Build Coastguard Worker             // From GL_OES_framebuffer_object
117*8975f5c5SAndroid Build Coastguard Worker             framebufferTexture2D    = &gl::CaptureFramebufferTexture2DOES;
118*8975f5c5SAndroid Build Coastguard Worker             framebufferRenderbuffer = &gl::CaptureFramebufferRenderbufferOES;
119*8975f5c5SAndroid Build Coastguard Worker             bindFramebuffer         = &gl::CaptureBindFramebufferOES;
120*8975f5c5SAndroid Build Coastguard Worker             genFramebuffers         = &gl::CaptureGenFramebuffersOES;
121*8975f5c5SAndroid Build Coastguard Worker             bindRenderbuffer        = &gl::CaptureBindRenderbufferOES;
122*8975f5c5SAndroid Build Coastguard Worker             genRenderbuffers        = &gl::CaptureGenRenderbuffersOES;
123*8975f5c5SAndroid Build Coastguard Worker             renderbufferStorage     = &gl::CaptureRenderbufferStorageOES;
124*8975f5c5SAndroid Build Coastguard Worker         }
125*8975f5c5SAndroid Build Coastguard Worker         else
126*8975f5c5SAndroid Build Coastguard Worker         {
127*8975f5c5SAndroid Build Coastguard Worker             framebufferTexture2D    = &gl::CaptureFramebufferTexture2D;
128*8975f5c5SAndroid Build Coastguard Worker             framebufferRenderbuffer = &gl::CaptureFramebufferRenderbuffer;
129*8975f5c5SAndroid Build Coastguard Worker             bindFramebuffer         = &gl::CaptureBindFramebuffer;
130*8975f5c5SAndroid Build Coastguard Worker             genFramebuffers         = &gl::CaptureGenFramebuffers;
131*8975f5c5SAndroid Build Coastguard Worker             bindRenderbuffer        = &gl::CaptureBindRenderbuffer;
132*8975f5c5SAndroid Build Coastguard Worker             genRenderbuffers        = &gl::CaptureGenRenderbuffers;
133*8975f5c5SAndroid Build Coastguard Worker             renderbufferStorage     = &gl::CaptureRenderbufferStorage;
134*8975f5c5SAndroid Build Coastguard Worker         }
135*8975f5c5SAndroid Build Coastguard Worker     }
136*8975f5c5SAndroid Build Coastguard Worker 
137*8975f5c5SAndroid Build Coastguard Worker     decltype(&gl::CaptureFramebufferTexture2D) framebufferTexture2D;
138*8975f5c5SAndroid Build Coastguard Worker     decltype(&gl::CaptureFramebufferRenderbuffer) framebufferRenderbuffer;
139*8975f5c5SAndroid Build Coastguard Worker     decltype(&gl::CaptureBindFramebuffer) bindFramebuffer;
140*8975f5c5SAndroid Build Coastguard Worker     decltype(&gl::CaptureGenFramebuffers) genFramebuffers;
141*8975f5c5SAndroid Build Coastguard Worker     decltype(&gl::CaptureBindRenderbuffer) bindRenderbuffer;
142*8975f5c5SAndroid Build Coastguard Worker     decltype(&gl::CaptureGenRenderbuffers) genRenderbuffers;
143*8975f5c5SAndroid Build Coastguard Worker     decltype(&gl::CaptureRenderbufferStorage) renderbufferStorage;
144*8975f5c5SAndroid Build Coastguard Worker };
145*8975f5c5SAndroid Build Coastguard Worker 
146*8975f5c5SAndroid Build Coastguard Worker struct VertexArrayCaptureFuncs
147*8975f5c5SAndroid Build Coastguard Worker {
VertexArrayCaptureFuncsangle::__anoncf31a3f40111::VertexArrayCaptureFuncs148*8975f5c5SAndroid Build Coastguard Worker     VertexArrayCaptureFuncs(bool isGLES1)
149*8975f5c5SAndroid Build Coastguard Worker     {
150*8975f5c5SAndroid Build Coastguard Worker         if (isGLES1)
151*8975f5c5SAndroid Build Coastguard Worker         {
152*8975f5c5SAndroid Build Coastguard Worker             // From GL_OES_vertex_array_object
153*8975f5c5SAndroid Build Coastguard Worker             bindVertexArray    = &gl::CaptureBindVertexArrayOES;
154*8975f5c5SAndroid Build Coastguard Worker             deleteVertexArrays = &gl::CaptureDeleteVertexArraysOES;
155*8975f5c5SAndroid Build Coastguard Worker             genVertexArrays    = &gl::CaptureGenVertexArraysOES;
156*8975f5c5SAndroid Build Coastguard Worker             isVertexArray      = &gl::CaptureIsVertexArrayOES;
157*8975f5c5SAndroid Build Coastguard Worker         }
158*8975f5c5SAndroid Build Coastguard Worker         else
159*8975f5c5SAndroid Build Coastguard Worker         {
160*8975f5c5SAndroid Build Coastguard Worker             bindVertexArray    = &gl::CaptureBindVertexArray;
161*8975f5c5SAndroid Build Coastguard Worker             deleteVertexArrays = &gl::CaptureDeleteVertexArrays;
162*8975f5c5SAndroid Build Coastguard Worker             genVertexArrays    = &gl::CaptureGenVertexArrays;
163*8975f5c5SAndroid Build Coastguard Worker             isVertexArray      = &gl::CaptureIsVertexArray;
164*8975f5c5SAndroid Build Coastguard Worker         }
165*8975f5c5SAndroid Build Coastguard Worker     }
166*8975f5c5SAndroid Build Coastguard Worker 
167*8975f5c5SAndroid Build Coastguard Worker     decltype(&gl::CaptureBindVertexArray) bindVertexArray;
168*8975f5c5SAndroid Build Coastguard Worker     decltype(&gl::CaptureDeleteVertexArrays) deleteVertexArrays;
169*8975f5c5SAndroid Build Coastguard Worker     decltype(&gl::CaptureGenVertexArrays) genVertexArrays;
170*8975f5c5SAndroid Build Coastguard Worker     decltype(&gl::CaptureIsVertexArray) isVertexArray;
171*8975f5c5SAndroid Build Coastguard Worker };
172*8975f5c5SAndroid Build Coastguard Worker 
GetDefaultOutDirectory()173*8975f5c5SAndroid Build Coastguard Worker std::string GetDefaultOutDirectory()
174*8975f5c5SAndroid Build Coastguard Worker {
175*8975f5c5SAndroid Build Coastguard Worker #if defined(ANGLE_PLATFORM_ANDROID)
176*8975f5c5SAndroid Build Coastguard Worker     std::string path = "/sdcard/Android/data/";
177*8975f5c5SAndroid Build Coastguard Worker 
178*8975f5c5SAndroid Build Coastguard Worker     // Linux interface to get application id of the running process
179*8975f5c5SAndroid Build Coastguard Worker     FILE *cmdline = fopen("/proc/self/cmdline", "r");
180*8975f5c5SAndroid Build Coastguard Worker     char applicationId[512];
181*8975f5c5SAndroid Build Coastguard Worker     if (cmdline)
182*8975f5c5SAndroid Build Coastguard Worker     {
183*8975f5c5SAndroid Build Coastguard Worker         fread(applicationId, 1, sizeof(applicationId), cmdline);
184*8975f5c5SAndroid Build Coastguard Worker         fclose(cmdline);
185*8975f5c5SAndroid Build Coastguard Worker 
186*8975f5c5SAndroid Build Coastguard Worker         // Some package may have application id as <app_name>:<cmd_name>
187*8975f5c5SAndroid Build Coastguard Worker         char *colonSep = strchr(applicationId, ':');
188*8975f5c5SAndroid Build Coastguard Worker         if (colonSep)
189*8975f5c5SAndroid Build Coastguard Worker         {
190*8975f5c5SAndroid Build Coastguard Worker             *colonSep = '\0';
191*8975f5c5SAndroid Build Coastguard Worker         }
192*8975f5c5SAndroid Build Coastguard Worker     }
193*8975f5c5SAndroid Build Coastguard Worker     else
194*8975f5c5SAndroid Build Coastguard Worker     {
195*8975f5c5SAndroid Build Coastguard Worker         ERR() << "not able to lookup application id";
196*8975f5c5SAndroid Build Coastguard Worker     }
197*8975f5c5SAndroid Build Coastguard Worker 
198*8975f5c5SAndroid Build Coastguard Worker     constexpr char kAndroidOutputSubdir[] = "/angle_capture/";
199*8975f5c5SAndroid Build Coastguard Worker     path += std::string(applicationId) + kAndroidOutputSubdir;
200*8975f5c5SAndroid Build Coastguard Worker 
201*8975f5c5SAndroid Build Coastguard Worker     // Check for existence of output path
202*8975f5c5SAndroid Build Coastguard Worker     struct stat dir_stat;
203*8975f5c5SAndroid Build Coastguard Worker     if (stat(path.c_str(), &dir_stat) == -1)
204*8975f5c5SAndroid Build Coastguard Worker     {
205*8975f5c5SAndroid Build Coastguard Worker         ERR() << "Output directory '" << path
206*8975f5c5SAndroid Build Coastguard Worker               << "' does not exist.  Create it over adb using mkdir.";
207*8975f5c5SAndroid Build Coastguard Worker     }
208*8975f5c5SAndroid Build Coastguard Worker 
209*8975f5c5SAndroid Build Coastguard Worker     return path;
210*8975f5c5SAndroid Build Coastguard Worker #else
211*8975f5c5SAndroid Build Coastguard Worker     return std::string("./");
212*8975f5c5SAndroid Build Coastguard Worker #endif  // defined(ANGLE_PLATFORM_ANDROID)
213*8975f5c5SAndroid Build Coastguard Worker }
214*8975f5c5SAndroid Build Coastguard Worker 
GetCaptureTrigger()215*8975f5c5SAndroid Build Coastguard Worker std::string GetCaptureTrigger()
216*8975f5c5SAndroid Build Coastguard Worker {
217*8975f5c5SAndroid Build Coastguard Worker     // Use the GetAndSet variant to improve future lookup times
218*8975f5c5SAndroid Build Coastguard Worker     return GetAndSetEnvironmentVarOrUnCachedAndroidProperty(kTriggerVarName, kAndroidTrigger);
219*8975f5c5SAndroid Build Coastguard Worker }
220*8975f5c5SAndroid Build Coastguard Worker 
operator <<(std::ostream & os,gl::ContextID contextId)221*8975f5c5SAndroid Build Coastguard Worker std::ostream &operator<<(std::ostream &os, gl::ContextID contextId)
222*8975f5c5SAndroid Build Coastguard Worker {
223*8975f5c5SAndroid Build Coastguard Worker     os << static_cast<int>(contextId.value);
224*8975f5c5SAndroid Build Coastguard Worker     return os;
225*8975f5c5SAndroid Build Coastguard Worker }
226*8975f5c5SAndroid Build Coastguard Worker 
227*8975f5c5SAndroid Build Coastguard Worker // Used to indicate that "shared" should be used to identify the files.
228*8975f5c5SAndroid Build Coastguard Worker constexpr gl::ContextID kSharedContextId = {0};
229*8975f5c5SAndroid Build Coastguard Worker // Used to indicate no context ID should be output.
230*8975f5c5SAndroid Build Coastguard Worker constexpr gl::ContextID kNoContextId = {std::numeric_limits<uint32_t>::max()};
231*8975f5c5SAndroid Build Coastguard Worker 
232*8975f5c5SAndroid Build Coastguard Worker struct FmtCapturePrefix
233*8975f5c5SAndroid Build Coastguard Worker {
FmtCapturePrefixangle::__anoncf31a3f40111::FmtCapturePrefix234*8975f5c5SAndroid Build Coastguard Worker     FmtCapturePrefix(gl::ContextID contextIdIn, const std::string &captureLabelIn)
235*8975f5c5SAndroid Build Coastguard Worker         : contextId(contextIdIn), captureLabel(captureLabelIn)
236*8975f5c5SAndroid Build Coastguard Worker     {}
237*8975f5c5SAndroid Build Coastguard Worker     gl::ContextID contextId;
238*8975f5c5SAndroid Build Coastguard Worker     const std::string &captureLabel;
239*8975f5c5SAndroid Build Coastguard Worker };
240*8975f5c5SAndroid Build Coastguard Worker 
operator <<(std::ostream & os,const FmtCapturePrefix & fmt)241*8975f5c5SAndroid Build Coastguard Worker std::ostream &operator<<(std::ostream &os, const FmtCapturePrefix &fmt)
242*8975f5c5SAndroid Build Coastguard Worker {
243*8975f5c5SAndroid Build Coastguard Worker     if (fmt.captureLabel.empty())
244*8975f5c5SAndroid Build Coastguard Worker     {
245*8975f5c5SAndroid Build Coastguard Worker         os << "angle_capture";
246*8975f5c5SAndroid Build Coastguard Worker     }
247*8975f5c5SAndroid Build Coastguard Worker     else
248*8975f5c5SAndroid Build Coastguard Worker     {
249*8975f5c5SAndroid Build Coastguard Worker         os << fmt.captureLabel;
250*8975f5c5SAndroid Build Coastguard Worker     }
251*8975f5c5SAndroid Build Coastguard Worker 
252*8975f5c5SAndroid Build Coastguard Worker     if (fmt.contextId == kSharedContextId)
253*8975f5c5SAndroid Build Coastguard Worker     {
254*8975f5c5SAndroid Build Coastguard Worker         os << "_shared";
255*8975f5c5SAndroid Build Coastguard Worker     }
256*8975f5c5SAndroid Build Coastguard Worker 
257*8975f5c5SAndroid Build Coastguard Worker     return os;
258*8975f5c5SAndroid Build Coastguard Worker }
259*8975f5c5SAndroid Build Coastguard Worker 
260*8975f5c5SAndroid Build Coastguard Worker enum class ReplayFunc
261*8975f5c5SAndroid Build Coastguard Worker {
262*8975f5c5SAndroid Build Coastguard Worker     Replay,
263*8975f5c5SAndroid Build Coastguard Worker     Setup,
264*8975f5c5SAndroid Build Coastguard Worker     SetupInactive,
265*8975f5c5SAndroid Build Coastguard Worker     Reset,
266*8975f5c5SAndroid Build Coastguard Worker };
267*8975f5c5SAndroid Build Coastguard Worker 
268*8975f5c5SAndroid Build Coastguard Worker constexpr uint32_t kNoPartId = std::numeric_limits<uint32_t>::max();
269*8975f5c5SAndroid Build Coastguard Worker 
270*8975f5c5SAndroid Build Coastguard Worker // In C, when you declare or define a function that takes no parameters, you must explicitly say the
271*8975f5c5SAndroid Build Coastguard Worker // function takes "void" parameters. When you're calling the function you omit this void. It's
272*8975f5c5SAndroid Build Coastguard Worker // therefore necessary to know how we're using a function to know if we should emi the "void".
273*8975f5c5SAndroid Build Coastguard Worker enum FuncUsage
274*8975f5c5SAndroid Build Coastguard Worker {
275*8975f5c5SAndroid Build Coastguard Worker     Prototype,
276*8975f5c5SAndroid Build Coastguard Worker     Definition,
277*8975f5c5SAndroid Build Coastguard Worker     Call,
278*8975f5c5SAndroid Build Coastguard Worker };
279*8975f5c5SAndroid Build Coastguard Worker 
operator <<(std::ostream & os,FuncUsage usage)280*8975f5c5SAndroid Build Coastguard Worker std::ostream &operator<<(std::ostream &os, FuncUsage usage)
281*8975f5c5SAndroid Build Coastguard Worker {
282*8975f5c5SAndroid Build Coastguard Worker     os << "(";
283*8975f5c5SAndroid Build Coastguard Worker     if (usage != FuncUsage::Call)
284*8975f5c5SAndroid Build Coastguard Worker     {
285*8975f5c5SAndroid Build Coastguard Worker         os << "void";
286*8975f5c5SAndroid Build Coastguard Worker     }
287*8975f5c5SAndroid Build Coastguard Worker     os << ")";
288*8975f5c5SAndroid Build Coastguard Worker     return os;
289*8975f5c5SAndroid Build Coastguard Worker }
290*8975f5c5SAndroid Build Coastguard Worker 
291*8975f5c5SAndroid Build Coastguard Worker struct FmtReplayFunction
292*8975f5c5SAndroid Build Coastguard Worker {
FmtReplayFunctionangle::__anoncf31a3f40111::FmtReplayFunction293*8975f5c5SAndroid Build Coastguard Worker     FmtReplayFunction(gl::ContextID contextIdIn,
294*8975f5c5SAndroid Build Coastguard Worker                       FuncUsage usageIn,
295*8975f5c5SAndroid Build Coastguard Worker                       uint32_t frameIndexIn,
296*8975f5c5SAndroid Build Coastguard Worker                       uint32_t partIdIn = kNoPartId)
297*8975f5c5SAndroid Build Coastguard Worker         : contextId(contextIdIn), usage(usageIn), frameIndex(frameIndexIn), partId(partIdIn)
298*8975f5c5SAndroid Build Coastguard Worker     {}
299*8975f5c5SAndroid Build Coastguard Worker     gl::ContextID contextId;
300*8975f5c5SAndroid Build Coastguard Worker     FuncUsage usage;
301*8975f5c5SAndroid Build Coastguard Worker     uint32_t frameIndex;
302*8975f5c5SAndroid Build Coastguard Worker     uint32_t partId;
303*8975f5c5SAndroid Build Coastguard Worker };
304*8975f5c5SAndroid Build Coastguard Worker 
operator <<(std::ostream & os,const FmtReplayFunction & fmt)305*8975f5c5SAndroid Build Coastguard Worker std::ostream &operator<<(std::ostream &os, const FmtReplayFunction &fmt)
306*8975f5c5SAndroid Build Coastguard Worker {
307*8975f5c5SAndroid Build Coastguard Worker     os << "Replay";
308*8975f5c5SAndroid Build Coastguard Worker 
309*8975f5c5SAndroid Build Coastguard Worker     if (fmt.contextId == kSharedContextId)
310*8975f5c5SAndroid Build Coastguard Worker     {
311*8975f5c5SAndroid Build Coastguard Worker         os << "Shared";
312*8975f5c5SAndroid Build Coastguard Worker     }
313*8975f5c5SAndroid Build Coastguard Worker 
314*8975f5c5SAndroid Build Coastguard Worker     os << "Frame" << fmt.frameIndex;
315*8975f5c5SAndroid Build Coastguard Worker 
316*8975f5c5SAndroid Build Coastguard Worker     if (fmt.partId != kNoPartId)
317*8975f5c5SAndroid Build Coastguard Worker     {
318*8975f5c5SAndroid Build Coastguard Worker         os << "Part" << fmt.partId;
319*8975f5c5SAndroid Build Coastguard Worker     }
320*8975f5c5SAndroid Build Coastguard Worker     os << fmt.usage;
321*8975f5c5SAndroid Build Coastguard Worker     return os;
322*8975f5c5SAndroid Build Coastguard Worker }
323*8975f5c5SAndroid Build Coastguard Worker 
324*8975f5c5SAndroid Build Coastguard Worker struct FmtSetupFunction
325*8975f5c5SAndroid Build Coastguard Worker {
FmtSetupFunctionangle::__anoncf31a3f40111::FmtSetupFunction326*8975f5c5SAndroid Build Coastguard Worker     FmtSetupFunction(uint32_t partIdIn, gl::ContextID contextIdIn, FuncUsage usageIn)
327*8975f5c5SAndroid Build Coastguard Worker         : partId(partIdIn), contextId(contextIdIn), usage(usageIn)
328*8975f5c5SAndroid Build Coastguard Worker     {}
329*8975f5c5SAndroid Build Coastguard Worker 
330*8975f5c5SAndroid Build Coastguard Worker     uint32_t partId;
331*8975f5c5SAndroid Build Coastguard Worker     gl::ContextID contextId;
332*8975f5c5SAndroid Build Coastguard Worker     FuncUsage usage;
333*8975f5c5SAndroid Build Coastguard Worker };
334*8975f5c5SAndroid Build Coastguard Worker 
operator <<(std::ostream & os,const FmtSetupFunction & fmt)335*8975f5c5SAndroid Build Coastguard Worker std::ostream &operator<<(std::ostream &os, const FmtSetupFunction &fmt)
336*8975f5c5SAndroid Build Coastguard Worker {
337*8975f5c5SAndroid Build Coastguard Worker     os << "SetupReplayContext";
338*8975f5c5SAndroid Build Coastguard Worker 
339*8975f5c5SAndroid Build Coastguard Worker     if (fmt.contextId == kSharedContextId)
340*8975f5c5SAndroid Build Coastguard Worker     {
341*8975f5c5SAndroid Build Coastguard Worker         os << "Shared";
342*8975f5c5SAndroid Build Coastguard Worker     }
343*8975f5c5SAndroid Build Coastguard Worker     else
344*8975f5c5SAndroid Build Coastguard Worker     {
345*8975f5c5SAndroid Build Coastguard Worker         os << fmt.contextId;
346*8975f5c5SAndroid Build Coastguard Worker     }
347*8975f5c5SAndroid Build Coastguard Worker 
348*8975f5c5SAndroid Build Coastguard Worker     if (fmt.partId != kNoPartId)
349*8975f5c5SAndroid Build Coastguard Worker     {
350*8975f5c5SAndroid Build Coastguard Worker         os << "Part" << fmt.partId;
351*8975f5c5SAndroid Build Coastguard Worker     }
352*8975f5c5SAndroid Build Coastguard Worker     os << fmt.usage;
353*8975f5c5SAndroid Build Coastguard Worker     return os;
354*8975f5c5SAndroid Build Coastguard Worker }
355*8975f5c5SAndroid Build Coastguard Worker 
356*8975f5c5SAndroid Build Coastguard Worker struct FmtSetupInactiveFunction
357*8975f5c5SAndroid Build Coastguard Worker {
FmtSetupInactiveFunctionangle::__anoncf31a3f40111::FmtSetupInactiveFunction358*8975f5c5SAndroid Build Coastguard Worker     FmtSetupInactiveFunction(uint32_t partIdIn, gl::ContextID contextIdIn, FuncUsage usageIn)
359*8975f5c5SAndroid Build Coastguard Worker         : partId(partIdIn), contextId(contextIdIn), usage(usageIn)
360*8975f5c5SAndroid Build Coastguard Worker     {}
361*8975f5c5SAndroid Build Coastguard Worker 
362*8975f5c5SAndroid Build Coastguard Worker     uint32_t partId;
363*8975f5c5SAndroid Build Coastguard Worker     gl::ContextID contextId;
364*8975f5c5SAndroid Build Coastguard Worker     FuncUsage usage;
365*8975f5c5SAndroid Build Coastguard Worker };
366*8975f5c5SAndroid Build Coastguard Worker 
operator <<(std::ostream & os,const FmtSetupInactiveFunction & fmt)367*8975f5c5SAndroid Build Coastguard Worker std::ostream &operator<<(std::ostream &os, const FmtSetupInactiveFunction &fmt)
368*8975f5c5SAndroid Build Coastguard Worker {
369*8975f5c5SAndroid Build Coastguard Worker     if ((fmt.usage == FuncUsage::Call) && (fmt.partId == kNoPartId))
370*8975f5c5SAndroid Build Coastguard Worker     {
371*8975f5c5SAndroid Build Coastguard Worker         os << "if (gReplayResourceMode == angle::ReplayResourceMode::All)\n    {\n        ";
372*8975f5c5SAndroid Build Coastguard Worker     }
373*8975f5c5SAndroid Build Coastguard Worker     os << "SetupReplayContext";
374*8975f5c5SAndroid Build Coastguard Worker 
375*8975f5c5SAndroid Build Coastguard Worker     if (fmt.contextId == kSharedContextId)
376*8975f5c5SAndroid Build Coastguard Worker     {
377*8975f5c5SAndroid Build Coastguard Worker         os << "Shared";
378*8975f5c5SAndroid Build Coastguard Worker     }
379*8975f5c5SAndroid Build Coastguard Worker     else
380*8975f5c5SAndroid Build Coastguard Worker     {
381*8975f5c5SAndroid Build Coastguard Worker         os << fmt.contextId;
382*8975f5c5SAndroid Build Coastguard Worker     }
383*8975f5c5SAndroid Build Coastguard Worker 
384*8975f5c5SAndroid Build Coastguard Worker     os << "Inactive";
385*8975f5c5SAndroid Build Coastguard Worker 
386*8975f5c5SAndroid Build Coastguard Worker     if (fmt.partId != kNoPartId)
387*8975f5c5SAndroid Build Coastguard Worker     {
388*8975f5c5SAndroid Build Coastguard Worker         os << "Part" << fmt.partId;
389*8975f5c5SAndroid Build Coastguard Worker     }
390*8975f5c5SAndroid Build Coastguard Worker 
391*8975f5c5SAndroid Build Coastguard Worker     os << fmt.usage;
392*8975f5c5SAndroid Build Coastguard Worker 
393*8975f5c5SAndroid Build Coastguard Worker     if ((fmt.usage == FuncUsage::Call) && (fmt.partId == kNoPartId))
394*8975f5c5SAndroid Build Coastguard Worker     {
395*8975f5c5SAndroid Build Coastguard Worker         os << ";\n    }";
396*8975f5c5SAndroid Build Coastguard Worker     }
397*8975f5c5SAndroid Build Coastguard Worker     return os;
398*8975f5c5SAndroid Build Coastguard Worker }
399*8975f5c5SAndroid Build Coastguard Worker 
400*8975f5c5SAndroid Build Coastguard Worker struct FmtResetFunction
401*8975f5c5SAndroid Build Coastguard Worker {
FmtResetFunctionangle::__anoncf31a3f40111::FmtResetFunction402*8975f5c5SAndroid Build Coastguard Worker     FmtResetFunction(uint32_t partIdIn, gl::ContextID contextIdIn, FuncUsage usageIn)
403*8975f5c5SAndroid Build Coastguard Worker         : partId(partIdIn), contextId(contextIdIn), usage(usageIn)
404*8975f5c5SAndroid Build Coastguard Worker     {}
405*8975f5c5SAndroid Build Coastguard Worker 
406*8975f5c5SAndroid Build Coastguard Worker     uint32_t partId;
407*8975f5c5SAndroid Build Coastguard Worker     gl::ContextID contextId;
408*8975f5c5SAndroid Build Coastguard Worker     FuncUsage usage;
409*8975f5c5SAndroid Build Coastguard Worker };
410*8975f5c5SAndroid Build Coastguard Worker 
operator <<(std::ostream & os,const FmtResetFunction & fmt)411*8975f5c5SAndroid Build Coastguard Worker std::ostream &operator<<(std::ostream &os, const FmtResetFunction &fmt)
412*8975f5c5SAndroid Build Coastguard Worker {
413*8975f5c5SAndroid Build Coastguard Worker     os << "ResetReplayContext";
414*8975f5c5SAndroid Build Coastguard Worker 
415*8975f5c5SAndroid Build Coastguard Worker     if (fmt.contextId == kSharedContextId)
416*8975f5c5SAndroid Build Coastguard Worker     {
417*8975f5c5SAndroid Build Coastguard Worker         os << "Shared";
418*8975f5c5SAndroid Build Coastguard Worker     }
419*8975f5c5SAndroid Build Coastguard Worker     else
420*8975f5c5SAndroid Build Coastguard Worker     {
421*8975f5c5SAndroid Build Coastguard Worker         os << fmt.contextId;
422*8975f5c5SAndroid Build Coastguard Worker     }
423*8975f5c5SAndroid Build Coastguard Worker 
424*8975f5c5SAndroid Build Coastguard Worker     if (fmt.partId != kNoPartId)
425*8975f5c5SAndroid Build Coastguard Worker     {
426*8975f5c5SAndroid Build Coastguard Worker         os << "Part" << fmt.partId;
427*8975f5c5SAndroid Build Coastguard Worker     }
428*8975f5c5SAndroid Build Coastguard Worker     os << fmt.usage;
429*8975f5c5SAndroid Build Coastguard Worker     return os;
430*8975f5c5SAndroid Build Coastguard Worker }
431*8975f5c5SAndroid Build Coastguard Worker 
432*8975f5c5SAndroid Build Coastguard Worker struct FmtFunction
433*8975f5c5SAndroid Build Coastguard Worker {
FmtFunctionangle::__anoncf31a3f40111::FmtFunction434*8975f5c5SAndroid Build Coastguard Worker     FmtFunction(ReplayFunc funcTypeIn,
435*8975f5c5SAndroid Build Coastguard Worker                 gl::ContextID contextIdIn,
436*8975f5c5SAndroid Build Coastguard Worker                 FuncUsage usageIn,
437*8975f5c5SAndroid Build Coastguard Worker                 uint32_t frameIndexIn,
438*8975f5c5SAndroid Build Coastguard Worker                 uint32_t partIdIn)
439*8975f5c5SAndroid Build Coastguard Worker         : funcType(funcTypeIn),
440*8975f5c5SAndroid Build Coastguard Worker           contextId(contextIdIn),
441*8975f5c5SAndroid Build Coastguard Worker           usage(usageIn),
442*8975f5c5SAndroid Build Coastguard Worker           frameIndex(frameIndexIn),
443*8975f5c5SAndroid Build Coastguard Worker           partId(partIdIn)
444*8975f5c5SAndroid Build Coastguard Worker     {}
445*8975f5c5SAndroid Build Coastguard Worker 
446*8975f5c5SAndroid Build Coastguard Worker     ReplayFunc funcType;
447*8975f5c5SAndroid Build Coastguard Worker     gl::ContextID contextId;
448*8975f5c5SAndroid Build Coastguard Worker     FuncUsage usage;
449*8975f5c5SAndroid Build Coastguard Worker     uint32_t frameIndex;
450*8975f5c5SAndroid Build Coastguard Worker     uint32_t partId;
451*8975f5c5SAndroid Build Coastguard Worker };
452*8975f5c5SAndroid Build Coastguard Worker 
operator <<(std::ostream & os,const FmtFunction & fmt)453*8975f5c5SAndroid Build Coastguard Worker std::ostream &operator<<(std::ostream &os, const FmtFunction &fmt)
454*8975f5c5SAndroid Build Coastguard Worker {
455*8975f5c5SAndroid Build Coastguard Worker     switch (fmt.funcType)
456*8975f5c5SAndroid Build Coastguard Worker     {
457*8975f5c5SAndroid Build Coastguard Worker         case ReplayFunc::Replay:
458*8975f5c5SAndroid Build Coastguard Worker             os << FmtReplayFunction(fmt.contextId, fmt.usage, fmt.frameIndex, fmt.partId);
459*8975f5c5SAndroid Build Coastguard Worker             break;
460*8975f5c5SAndroid Build Coastguard Worker 
461*8975f5c5SAndroid Build Coastguard Worker         case ReplayFunc::Setup:
462*8975f5c5SAndroid Build Coastguard Worker             os << FmtSetupFunction(fmt.partId, fmt.contextId, fmt.usage);
463*8975f5c5SAndroid Build Coastguard Worker             break;
464*8975f5c5SAndroid Build Coastguard Worker 
465*8975f5c5SAndroid Build Coastguard Worker         case ReplayFunc::SetupInactive:
466*8975f5c5SAndroid Build Coastguard Worker             os << FmtSetupInactiveFunction(fmt.partId, fmt.contextId, fmt.usage);
467*8975f5c5SAndroid Build Coastguard Worker             break;
468*8975f5c5SAndroid Build Coastguard Worker 
469*8975f5c5SAndroid Build Coastguard Worker         case ReplayFunc::Reset:
470*8975f5c5SAndroid Build Coastguard Worker             os << FmtResetFunction(fmt.partId, fmt.contextId, fmt.usage);
471*8975f5c5SAndroid Build Coastguard Worker             break;
472*8975f5c5SAndroid Build Coastguard Worker 
473*8975f5c5SAndroid Build Coastguard Worker         default:
474*8975f5c5SAndroid Build Coastguard Worker             UNREACHABLE();
475*8975f5c5SAndroid Build Coastguard Worker             break;
476*8975f5c5SAndroid Build Coastguard Worker     }
477*8975f5c5SAndroid Build Coastguard Worker 
478*8975f5c5SAndroid Build Coastguard Worker     return os;
479*8975f5c5SAndroid Build Coastguard Worker }
480*8975f5c5SAndroid Build Coastguard Worker 
481*8975f5c5SAndroid Build Coastguard Worker struct FmtGetSerializedContextStateFunction
482*8975f5c5SAndroid Build Coastguard Worker {
FmtGetSerializedContextStateFunctionangle::__anoncf31a3f40111::FmtGetSerializedContextStateFunction483*8975f5c5SAndroid Build Coastguard Worker     FmtGetSerializedContextStateFunction(gl::ContextID contextIdIn,
484*8975f5c5SAndroid Build Coastguard Worker                                          FuncUsage usageIn,
485*8975f5c5SAndroid Build Coastguard Worker                                          uint32_t frameIndexIn)
486*8975f5c5SAndroid Build Coastguard Worker         : contextId(contextIdIn), usage(usageIn), frameIndex(frameIndexIn)
487*8975f5c5SAndroid Build Coastguard Worker     {}
488*8975f5c5SAndroid Build Coastguard Worker     gl::ContextID contextId;
489*8975f5c5SAndroid Build Coastguard Worker     FuncUsage usage;
490*8975f5c5SAndroid Build Coastguard Worker     uint32_t frameIndex;
491*8975f5c5SAndroid Build Coastguard Worker };
492*8975f5c5SAndroid Build Coastguard Worker 
operator <<(std::ostream & os,const FmtGetSerializedContextStateFunction & fmt)493*8975f5c5SAndroid Build Coastguard Worker std::ostream &operator<<(std::ostream &os, const FmtGetSerializedContextStateFunction &fmt)
494*8975f5c5SAndroid Build Coastguard Worker {
495*8975f5c5SAndroid Build Coastguard Worker     os << "GetSerializedContext" << fmt.contextId << "StateFrame" << fmt.frameIndex << "Data"
496*8975f5c5SAndroid Build Coastguard Worker        << fmt.usage;
497*8975f5c5SAndroid Build Coastguard Worker     return os;
498*8975f5c5SAndroid Build Coastguard Worker }
499*8975f5c5SAndroid Build Coastguard Worker 
WriteGLFloatValue(std::ostream & out,GLfloat value)500*8975f5c5SAndroid Build Coastguard Worker void WriteGLFloatValue(std::ostream &out, GLfloat value)
501*8975f5c5SAndroid Build Coastguard Worker {
502*8975f5c5SAndroid Build Coastguard Worker     // Check for non-representable values
503*8975f5c5SAndroid Build Coastguard Worker     ASSERT(std::numeric_limits<float>::has_infinity);
504*8975f5c5SAndroid Build Coastguard Worker     ASSERT(std::numeric_limits<float>::has_quiet_NaN);
505*8975f5c5SAndroid Build Coastguard Worker 
506*8975f5c5SAndroid Build Coastguard Worker     if (std::isinf(value))
507*8975f5c5SAndroid Build Coastguard Worker     {
508*8975f5c5SAndroid Build Coastguard Worker         float negativeInf = -std::numeric_limits<float>::infinity();
509*8975f5c5SAndroid Build Coastguard Worker         if (value == negativeInf)
510*8975f5c5SAndroid Build Coastguard Worker         {
511*8975f5c5SAndroid Build Coastguard Worker             out << "-";
512*8975f5c5SAndroid Build Coastguard Worker         }
513*8975f5c5SAndroid Build Coastguard Worker         out << "INFINITY";
514*8975f5c5SAndroid Build Coastguard Worker     }
515*8975f5c5SAndroid Build Coastguard Worker     else if (std::isnan(value))
516*8975f5c5SAndroid Build Coastguard Worker     {
517*8975f5c5SAndroid Build Coastguard Worker         out << "NAN";
518*8975f5c5SAndroid Build Coastguard Worker     }
519*8975f5c5SAndroid Build Coastguard Worker     else
520*8975f5c5SAndroid Build Coastguard Worker     {
521*8975f5c5SAndroid Build Coastguard Worker         // Write a decimal point to preserve the zero sign on replay
522*8975f5c5SAndroid Build Coastguard Worker         out << (value == 0.0 ? std::showpoint : std::noshowpoint);
523*8975f5c5SAndroid Build Coastguard Worker         out << std::setprecision(16);
524*8975f5c5SAndroid Build Coastguard Worker         out << value;
525*8975f5c5SAndroid Build Coastguard Worker     }
526*8975f5c5SAndroid Build Coastguard Worker }
527*8975f5c5SAndroid Build Coastguard Worker 
528*8975f5c5SAndroid Build Coastguard Worker template <typename T, typename CastT = T>
WriteInlineData(const std::vector<uint8_t> & vec,std::ostream & out)529*8975f5c5SAndroid Build Coastguard Worker void WriteInlineData(const std::vector<uint8_t> &vec, std::ostream &out)
530*8975f5c5SAndroid Build Coastguard Worker {
531*8975f5c5SAndroid Build Coastguard Worker     const T *data = reinterpret_cast<const T *>(vec.data());
532*8975f5c5SAndroid Build Coastguard Worker     size_t count  = vec.size() / sizeof(T);
533*8975f5c5SAndroid Build Coastguard Worker 
534*8975f5c5SAndroid Build Coastguard Worker     if (data == nullptr)
535*8975f5c5SAndroid Build Coastguard Worker     {
536*8975f5c5SAndroid Build Coastguard Worker         return;
537*8975f5c5SAndroid Build Coastguard Worker     }
538*8975f5c5SAndroid Build Coastguard Worker 
539*8975f5c5SAndroid Build Coastguard Worker     out << static_cast<CastT>(data[0]);
540*8975f5c5SAndroid Build Coastguard Worker 
541*8975f5c5SAndroid Build Coastguard Worker     for (size_t dataIndex = 1; dataIndex < count; ++dataIndex)
542*8975f5c5SAndroid Build Coastguard Worker     {
543*8975f5c5SAndroid Build Coastguard Worker         out << ", " << static_cast<CastT>(data[dataIndex]);
544*8975f5c5SAndroid Build Coastguard Worker     }
545*8975f5c5SAndroid Build Coastguard Worker }
546*8975f5c5SAndroid Build Coastguard Worker 
547*8975f5c5SAndroid Build Coastguard Worker template <>
WriteInlineData(const std::vector<uint8_t> & vec,std::ostream & out)548*8975f5c5SAndroid Build Coastguard Worker void WriteInlineData<GLchar>(const std::vector<uint8_t> &vec, std::ostream &out)
549*8975f5c5SAndroid Build Coastguard Worker {
550*8975f5c5SAndroid Build Coastguard Worker     const GLchar *data = reinterpret_cast<const GLchar *>(vec.data());
551*8975f5c5SAndroid Build Coastguard Worker     size_t count       = vec.size() / sizeof(GLchar);
552*8975f5c5SAndroid Build Coastguard Worker 
553*8975f5c5SAndroid Build Coastguard Worker     if (data == nullptr || data[0] == '\0')
554*8975f5c5SAndroid Build Coastguard Worker     {
555*8975f5c5SAndroid Build Coastguard Worker         return;
556*8975f5c5SAndroid Build Coastguard Worker     }
557*8975f5c5SAndroid Build Coastguard Worker 
558*8975f5c5SAndroid Build Coastguard Worker     out << "\"";
559*8975f5c5SAndroid Build Coastguard Worker 
560*8975f5c5SAndroid Build Coastguard Worker     for (size_t dataIndex = 0; dataIndex < count; ++dataIndex)
561*8975f5c5SAndroid Build Coastguard Worker     {
562*8975f5c5SAndroid Build Coastguard Worker         if (data[dataIndex] == '\0')
563*8975f5c5SAndroid Build Coastguard Worker             break;
564*8975f5c5SAndroid Build Coastguard Worker 
565*8975f5c5SAndroid Build Coastguard Worker         out << static_cast<GLchar>(data[dataIndex]);
566*8975f5c5SAndroid Build Coastguard Worker     }
567*8975f5c5SAndroid Build Coastguard Worker 
568*8975f5c5SAndroid Build Coastguard Worker     out << "\"";
569*8975f5c5SAndroid Build Coastguard Worker }
570*8975f5c5SAndroid Build Coastguard Worker 
571*8975f5c5SAndroid Build Coastguard Worker // For compatibility with C, which does not have multi-line string literals, we break strings up
572*8975f5c5SAndroid Build Coastguard Worker // into multiple lines like:
573*8975f5c5SAndroid Build Coastguard Worker //
574*8975f5c5SAndroid Build Coastguard Worker //   const char *str[] = {
575*8975f5c5SAndroid Build Coastguard Worker //   "multiple\n"
576*8975f5c5SAndroid Build Coastguard Worker //   "line\n"
577*8975f5c5SAndroid Build Coastguard Worker //   "strings may have \"quotes\"\n"
578*8975f5c5SAndroid Build Coastguard Worker //   "and \\slashes\\\n",
579*8975f5c5SAndroid Build Coastguard Worker //   };
580*8975f5c5SAndroid Build Coastguard Worker //
581*8975f5c5SAndroid Build Coastguard Worker // Note we need to emit extra escapes to ensure quotes and other special characters are preserved.
582*8975f5c5SAndroid Build Coastguard Worker struct FmtMultiLineString
583*8975f5c5SAndroid Build Coastguard Worker {
FmtMultiLineStringangle::__anoncf31a3f40111::FmtMultiLineString584*8975f5c5SAndroid Build Coastguard Worker     FmtMultiLineString(const std::string &str) : strings()
585*8975f5c5SAndroid Build Coastguard Worker     {
586*8975f5c5SAndroid Build Coastguard Worker         std::string str2;
587*8975f5c5SAndroid Build Coastguard Worker 
588*8975f5c5SAndroid Build Coastguard Worker         // Strip any carriage returns before splitting, for consistency
589*8975f5c5SAndroid Build Coastguard Worker         if (str.find("\r") != std::string::npos)
590*8975f5c5SAndroid Build Coastguard Worker         {
591*8975f5c5SAndroid Build Coastguard Worker             // str is const, so have to make a copy of it first
592*8975f5c5SAndroid Build Coastguard Worker             str2 = str;
593*8975f5c5SAndroid Build Coastguard Worker             ReplaceAllSubstrings(&str2, "\r", "");
594*8975f5c5SAndroid Build Coastguard Worker         }
595*8975f5c5SAndroid Build Coastguard Worker 
596*8975f5c5SAndroid Build Coastguard Worker         strings =
597*8975f5c5SAndroid Build Coastguard Worker             angle::SplitString(str2.empty() ? str : str2, "\n", WhitespaceHandling::KEEP_WHITESPACE,
598*8975f5c5SAndroid Build Coastguard Worker                                SplitResult::SPLIT_WANT_ALL);
599*8975f5c5SAndroid Build Coastguard Worker     }
600*8975f5c5SAndroid Build Coastguard Worker 
601*8975f5c5SAndroid Build Coastguard Worker     std::vector<std::string> strings;
602*8975f5c5SAndroid Build Coastguard Worker };
603*8975f5c5SAndroid Build Coastguard Worker 
EscapeString(const std::string & string)604*8975f5c5SAndroid Build Coastguard Worker std::string EscapeString(const std::string &string)
605*8975f5c5SAndroid Build Coastguard Worker {
606*8975f5c5SAndroid Build Coastguard Worker     std::stringstream strstr;
607*8975f5c5SAndroid Build Coastguard Worker 
608*8975f5c5SAndroid Build Coastguard Worker     for (char c : string)
609*8975f5c5SAndroid Build Coastguard Worker     {
610*8975f5c5SAndroid Build Coastguard Worker         if (c == '\"' || c == '\\')
611*8975f5c5SAndroid Build Coastguard Worker         {
612*8975f5c5SAndroid Build Coastguard Worker             strstr << "\\";
613*8975f5c5SAndroid Build Coastguard Worker         }
614*8975f5c5SAndroid Build Coastguard Worker         strstr << c;
615*8975f5c5SAndroid Build Coastguard Worker     }
616*8975f5c5SAndroid Build Coastguard Worker 
617*8975f5c5SAndroid Build Coastguard Worker     return strstr.str();
618*8975f5c5SAndroid Build Coastguard Worker }
619*8975f5c5SAndroid Build Coastguard Worker 
operator <<(std::ostream & ostr,const FmtMultiLineString & fmt)620*8975f5c5SAndroid Build Coastguard Worker std::ostream &operator<<(std::ostream &ostr, const FmtMultiLineString &fmt)
621*8975f5c5SAndroid Build Coastguard Worker {
622*8975f5c5SAndroid Build Coastguard Worker     ASSERT(!fmt.strings.empty());
623*8975f5c5SAndroid Build Coastguard Worker     bool first = true;
624*8975f5c5SAndroid Build Coastguard Worker     for (const std::string &string : fmt.strings)
625*8975f5c5SAndroid Build Coastguard Worker     {
626*8975f5c5SAndroid Build Coastguard Worker         if (first)
627*8975f5c5SAndroid Build Coastguard Worker         {
628*8975f5c5SAndroid Build Coastguard Worker             first = false;
629*8975f5c5SAndroid Build Coastguard Worker         }
630*8975f5c5SAndroid Build Coastguard Worker         else
631*8975f5c5SAndroid Build Coastguard Worker         {
632*8975f5c5SAndroid Build Coastguard Worker             ostr << "\\n\"\n";
633*8975f5c5SAndroid Build Coastguard Worker         }
634*8975f5c5SAndroid Build Coastguard Worker 
635*8975f5c5SAndroid Build Coastguard Worker         ostr << "\"" << EscapeString(string);
636*8975f5c5SAndroid Build Coastguard Worker     }
637*8975f5c5SAndroid Build Coastguard Worker 
638*8975f5c5SAndroid Build Coastguard Worker     ostr << "\"";
639*8975f5c5SAndroid Build Coastguard Worker 
640*8975f5c5SAndroid Build Coastguard Worker     return ostr;
641*8975f5c5SAndroid Build Coastguard Worker }
642*8975f5c5SAndroid Build Coastguard Worker 
WriteStringParamReplay(ReplayWriter & replayWriter,std::ostream & out,std::ostream & header,const CallCapture & call,const ParamCapture & param,std::vector<uint8_t> * binaryData)643*8975f5c5SAndroid Build Coastguard Worker void WriteStringParamReplay(ReplayWriter &replayWriter,
644*8975f5c5SAndroid Build Coastguard Worker                             std::ostream &out,
645*8975f5c5SAndroid Build Coastguard Worker                             std::ostream &header,
646*8975f5c5SAndroid Build Coastguard Worker                             const CallCapture &call,
647*8975f5c5SAndroid Build Coastguard Worker                             const ParamCapture &param,
648*8975f5c5SAndroid Build Coastguard Worker                             std::vector<uint8_t> *binaryData)
649*8975f5c5SAndroid Build Coastguard Worker {
650*8975f5c5SAndroid Build Coastguard Worker     const std::vector<uint8_t> &data = param.data[0];
651*8975f5c5SAndroid Build Coastguard Worker     // null terminate C style string
652*8975f5c5SAndroid Build Coastguard Worker     ASSERT(data.size() > 0 && data.back() == '\0');
653*8975f5c5SAndroid Build Coastguard Worker     std::string str(data.begin(), data.end() - 1);
654*8975f5c5SAndroid Build Coastguard Worker 
655*8975f5c5SAndroid Build Coastguard Worker     constexpr size_t kMaxInlineStringLength = 20000;
656*8975f5c5SAndroid Build Coastguard Worker     if (str.size() > kMaxInlineStringLength)
657*8975f5c5SAndroid Build Coastguard Worker     {
658*8975f5c5SAndroid Build Coastguard Worker         // Store in binary file if the string is too long.
659*8975f5c5SAndroid Build Coastguard Worker         // Round up to 16-byte boundary for cross ABI safety.
660*8975f5c5SAndroid Build Coastguard Worker         size_t offset = rx::roundUpPow2(binaryData->size(), kBinaryAlignment);
661*8975f5c5SAndroid Build Coastguard Worker         binaryData->resize(offset + str.size() + 1);
662*8975f5c5SAndroid Build Coastguard Worker         memcpy(binaryData->data() + offset, str.data(), str.size() + 1);
663*8975f5c5SAndroid Build Coastguard Worker         out << "(const char *)&gBinaryData[" << offset << "]";
664*8975f5c5SAndroid Build Coastguard Worker     }
665*8975f5c5SAndroid Build Coastguard Worker     else if (str.find('\n') != std::string::npos)
666*8975f5c5SAndroid Build Coastguard Worker     {
667*8975f5c5SAndroid Build Coastguard Worker         std::string varName = replayWriter.getInlineVariableName(call.entryPoint, param.name);
668*8975f5c5SAndroid Build Coastguard Worker         header << "const char " << varName << "[] = \n" << FmtMultiLineString(str) << ";";
669*8975f5c5SAndroid Build Coastguard Worker         out << varName;
670*8975f5c5SAndroid Build Coastguard Worker     }
671*8975f5c5SAndroid Build Coastguard Worker     else
672*8975f5c5SAndroid Build Coastguard Worker     {
673*8975f5c5SAndroid Build Coastguard Worker         out << "\"" << str << "\"";
674*8975f5c5SAndroid Build Coastguard Worker     }
675*8975f5c5SAndroid Build Coastguard Worker }
676*8975f5c5SAndroid Build Coastguard Worker 
WriteStringPointerParamReplay(ReplayWriter & replayWriter,std::ostream & out,std::ostream & header,const CallCapture & call,const ParamCapture & param)677*8975f5c5SAndroid Build Coastguard Worker void WriteStringPointerParamReplay(ReplayWriter &replayWriter,
678*8975f5c5SAndroid Build Coastguard Worker                                    std::ostream &out,
679*8975f5c5SAndroid Build Coastguard Worker                                    std::ostream &header,
680*8975f5c5SAndroid Build Coastguard Worker                                    const CallCapture &call,
681*8975f5c5SAndroid Build Coastguard Worker                                    const ParamCapture &param)
682*8975f5c5SAndroid Build Coastguard Worker {
683*8975f5c5SAndroid Build Coastguard Worker     // Concatenate the strings to ensure we get an accurate counter
684*8975f5c5SAndroid Build Coastguard Worker     std::vector<std::string> strings;
685*8975f5c5SAndroid Build Coastguard Worker     for (const std::vector<uint8_t> &data : param.data)
686*8975f5c5SAndroid Build Coastguard Worker     {
687*8975f5c5SAndroid Build Coastguard Worker         // null terminate C style string
688*8975f5c5SAndroid Build Coastguard Worker         ASSERT(data.size() > 0 && data.back() == '\0');
689*8975f5c5SAndroid Build Coastguard Worker         strings.emplace_back(data.begin(), data.end() - 1);
690*8975f5c5SAndroid Build Coastguard Worker     }
691*8975f5c5SAndroid Build Coastguard Worker 
692*8975f5c5SAndroid Build Coastguard Worker     bool isNewEntry     = false;
693*8975f5c5SAndroid Build Coastguard Worker     std::string varName = replayWriter.getInlineStringSetVariableName(call.entryPoint, param.name,
694*8975f5c5SAndroid Build Coastguard Worker                                                                       strings, &isNewEntry);
695*8975f5c5SAndroid Build Coastguard Worker 
696*8975f5c5SAndroid Build Coastguard Worker     if (isNewEntry)
697*8975f5c5SAndroid Build Coastguard Worker     {
698*8975f5c5SAndroid Build Coastguard Worker         header << "const char *const " << varName << "[] = { \n";
699*8975f5c5SAndroid Build Coastguard Worker 
700*8975f5c5SAndroid Build Coastguard Worker         for (const std::string &str : strings)
701*8975f5c5SAndroid Build Coastguard Worker         {
702*8975f5c5SAndroid Build Coastguard Worker             // Break up long strings for MSVC
703*8975f5c5SAndroid Build Coastguard Worker             size_t copyLength = 0;
704*8975f5c5SAndroid Build Coastguard Worker             std::string separator;
705*8975f5c5SAndroid Build Coastguard Worker             for (size_t i = 0; i < str.length(); i += kStringLengthLimit)
706*8975f5c5SAndroid Build Coastguard Worker             {
707*8975f5c5SAndroid Build Coastguard Worker                 if ((str.length() - i) <= kStringLengthLimit)
708*8975f5c5SAndroid Build Coastguard Worker                 {
709*8975f5c5SAndroid Build Coastguard Worker                     copyLength = str.length() - i;
710*8975f5c5SAndroid Build Coastguard Worker                     separator  = ",";
711*8975f5c5SAndroid Build Coastguard Worker                 }
712*8975f5c5SAndroid Build Coastguard Worker                 else
713*8975f5c5SAndroid Build Coastguard Worker                 {
714*8975f5c5SAndroid Build Coastguard Worker                     copyLength = kStringLengthLimit;
715*8975f5c5SAndroid Build Coastguard Worker                     separator  = "";
716*8975f5c5SAndroid Build Coastguard Worker                 }
717*8975f5c5SAndroid Build Coastguard Worker 
718*8975f5c5SAndroid Build Coastguard Worker                 header << FmtMultiLineString(str.substr(i, copyLength)) << separator << "\n";
719*8975f5c5SAndroid Build Coastguard Worker             }
720*8975f5c5SAndroid Build Coastguard Worker         }
721*8975f5c5SAndroid Build Coastguard Worker 
722*8975f5c5SAndroid Build Coastguard Worker         header << "};\n";
723*8975f5c5SAndroid Build Coastguard Worker     }
724*8975f5c5SAndroid Build Coastguard Worker 
725*8975f5c5SAndroid Build Coastguard Worker     out << varName;
726*8975f5c5SAndroid Build Coastguard Worker }
727*8975f5c5SAndroid Build Coastguard Worker 
728*8975f5c5SAndroid Build Coastguard Worker enum class Indent
729*8975f5c5SAndroid Build Coastguard Worker {
730*8975f5c5SAndroid Build Coastguard Worker     Indent,
731*8975f5c5SAndroid Build Coastguard Worker     NoIdent,
732*8975f5c5SAndroid Build Coastguard Worker };
733*8975f5c5SAndroid Build Coastguard Worker 
UpdateResourceIDBuffer(std::ostream & out,Indent indent,size_t bufferIndex,ResourceIDType resourceIDType,gl::ContextID contextID,GLuint resourceID)734*8975f5c5SAndroid Build Coastguard Worker void UpdateResourceIDBuffer(std::ostream &out,
735*8975f5c5SAndroid Build Coastguard Worker                             Indent indent,
736*8975f5c5SAndroid Build Coastguard Worker                             size_t bufferIndex,
737*8975f5c5SAndroid Build Coastguard Worker                             ResourceIDType resourceIDType,
738*8975f5c5SAndroid Build Coastguard Worker                             gl::ContextID contextID,
739*8975f5c5SAndroid Build Coastguard Worker                             GLuint resourceID)
740*8975f5c5SAndroid Build Coastguard Worker {
741*8975f5c5SAndroid Build Coastguard Worker     if (indent == Indent::Indent)
742*8975f5c5SAndroid Build Coastguard Worker     {
743*8975f5c5SAndroid Build Coastguard Worker         out << "    ";
744*8975f5c5SAndroid Build Coastguard Worker     }
745*8975f5c5SAndroid Build Coastguard Worker     out << "UpdateResourceIDBuffer(" << bufferIndex << ", g"
746*8975f5c5SAndroid Build Coastguard Worker         << GetResourceIDTypeName(resourceIDType) << "Map";
747*8975f5c5SAndroid Build Coastguard Worker     if (IsTrackedPerContext(resourceIDType))
748*8975f5c5SAndroid Build Coastguard Worker     {
749*8975f5c5SAndroid Build Coastguard Worker         out << "PerContext[" << contextID.value << "]";
750*8975f5c5SAndroid Build Coastguard Worker     }
751*8975f5c5SAndroid Build Coastguard Worker     out << "[" << resourceID << "]);\n";
752*8975f5c5SAndroid Build Coastguard Worker }
753*8975f5c5SAndroid Build Coastguard Worker 
754*8975f5c5SAndroid Build Coastguard Worker template <typename ParamT>
WriteResourceIDPointerParamReplay(ReplayWriter & replayWriter,std::ostream & out,std::ostream & header,const CallCapture & call,const ParamCapture & param,size_t * maxResourceIDBufferSize)755*8975f5c5SAndroid Build Coastguard Worker void WriteResourceIDPointerParamReplay(ReplayWriter &replayWriter,
756*8975f5c5SAndroid Build Coastguard Worker                                        std::ostream &out,
757*8975f5c5SAndroid Build Coastguard Worker                                        std::ostream &header,
758*8975f5c5SAndroid Build Coastguard Worker                                        const CallCapture &call,
759*8975f5c5SAndroid Build Coastguard Worker                                        const ParamCapture &param,
760*8975f5c5SAndroid Build Coastguard Worker                                        size_t *maxResourceIDBufferSize)
761*8975f5c5SAndroid Build Coastguard Worker {
762*8975f5c5SAndroid Build Coastguard Worker     const ResourceIDType resourceIDType = GetResourceIDTypeFromParamType(param.type);
763*8975f5c5SAndroid Build Coastguard Worker     ASSERT(resourceIDType != ResourceIDType::InvalidEnum);
764*8975f5c5SAndroid Build Coastguard Worker 
765*8975f5c5SAndroid Build Coastguard Worker     if (param.dataNElements > 0)
766*8975f5c5SAndroid Build Coastguard Worker     {
767*8975f5c5SAndroid Build Coastguard Worker         ASSERT(param.data.size() == 1);
768*8975f5c5SAndroid Build Coastguard Worker 
769*8975f5c5SAndroid Build Coastguard Worker         const ParamT *returnedIDs = reinterpret_cast<const ParamT *>(param.data[0].data());
770*8975f5c5SAndroid Build Coastguard Worker         for (GLsizei resIndex = 0; resIndex < param.dataNElements; ++resIndex)
771*8975f5c5SAndroid Build Coastguard Worker         {
772*8975f5c5SAndroid Build Coastguard Worker             ParamT id = returnedIDs[resIndex];
773*8975f5c5SAndroid Build Coastguard Worker             UpdateResourceIDBuffer(header, Indent::NoIdent, resIndex, resourceIDType,
774*8975f5c5SAndroid Build Coastguard Worker                                    call.contextID, id.value);
775*8975f5c5SAndroid Build Coastguard Worker         }
776*8975f5c5SAndroid Build Coastguard Worker 
777*8975f5c5SAndroid Build Coastguard Worker         *maxResourceIDBufferSize = std::max<size_t>(*maxResourceIDBufferSize, param.dataNElements);
778*8975f5c5SAndroid Build Coastguard Worker     }
779*8975f5c5SAndroid Build Coastguard Worker 
780*8975f5c5SAndroid Build Coastguard Worker     out << "gResourceIDBuffer";
781*8975f5c5SAndroid Build Coastguard Worker }
782*8975f5c5SAndroid Build Coastguard Worker 
WriteBinaryParamReplay(ReplayWriter & replayWriter,std::ostream & out,std::ostream & header,const CallCapture & call,const ParamCapture & param,std::vector<uint8_t> * binaryData)783*8975f5c5SAndroid Build Coastguard Worker void WriteBinaryParamReplay(ReplayWriter &replayWriter,
784*8975f5c5SAndroid Build Coastguard Worker                             std::ostream &out,
785*8975f5c5SAndroid Build Coastguard Worker                             std::ostream &header,
786*8975f5c5SAndroid Build Coastguard Worker                             const CallCapture &call,
787*8975f5c5SAndroid Build Coastguard Worker                             const ParamCapture &param,
788*8975f5c5SAndroid Build Coastguard Worker                             std::vector<uint8_t> *binaryData)
789*8975f5c5SAndroid Build Coastguard Worker {
790*8975f5c5SAndroid Build Coastguard Worker     std::string varName = replayWriter.getInlineVariableName(call.entryPoint, param.name);
791*8975f5c5SAndroid Build Coastguard Worker 
792*8975f5c5SAndroid Build Coastguard Worker     ASSERT(param.data.size() == 1);
793*8975f5c5SAndroid Build Coastguard Worker     const std::vector<uint8_t> &data = param.data[0];
794*8975f5c5SAndroid Build Coastguard Worker 
795*8975f5c5SAndroid Build Coastguard Worker     // Only inline strings (shaders) to simplify the C code.
796*8975f5c5SAndroid Build Coastguard Worker     ParamType overrideType = param.type;
797*8975f5c5SAndroid Build Coastguard Worker     if (param.type == ParamType::TvoidConstPointer)
798*8975f5c5SAndroid Build Coastguard Worker     {
799*8975f5c5SAndroid Build Coastguard Worker         overrideType = ParamType::TGLubyteConstPointer;
800*8975f5c5SAndroid Build Coastguard Worker     }
801*8975f5c5SAndroid Build Coastguard Worker     if (overrideType == ParamType::TGLcharPointer)
802*8975f5c5SAndroid Build Coastguard Worker     {
803*8975f5c5SAndroid Build Coastguard Worker         // Inline if data is of type string
804*8975f5c5SAndroid Build Coastguard Worker         std::string paramTypeString = ParamTypeToString(param.type);
805*8975f5c5SAndroid Build Coastguard Worker         header << paramTypeString.substr(0, paramTypeString.length() - 1) << varName << "[] = { ";
806*8975f5c5SAndroid Build Coastguard Worker         WriteInlineData<GLchar>(data, header);
807*8975f5c5SAndroid Build Coastguard Worker         header << " };\n";
808*8975f5c5SAndroid Build Coastguard Worker         out << varName;
809*8975f5c5SAndroid Build Coastguard Worker     }
810*8975f5c5SAndroid Build Coastguard Worker     else
811*8975f5c5SAndroid Build Coastguard Worker     {
812*8975f5c5SAndroid Build Coastguard Worker         // Store in binary file if data are not of type string
813*8975f5c5SAndroid Build Coastguard Worker         // Round up to 16-byte boundary for cross ABI safety
814*8975f5c5SAndroid Build Coastguard Worker         size_t offset = rx::roundUpPow2(binaryData->size(), kBinaryAlignment);
815*8975f5c5SAndroid Build Coastguard Worker         binaryData->resize(offset + data.size());
816*8975f5c5SAndroid Build Coastguard Worker         memcpy(binaryData->data() + offset, data.data(), data.size());
817*8975f5c5SAndroid Build Coastguard Worker         out << "(" << ParamTypeToString(overrideType) << ")&gBinaryData[" << offset << "]";
818*8975f5c5SAndroid Build Coastguard Worker     }
819*8975f5c5SAndroid Build Coastguard Worker }
820*8975f5c5SAndroid Build Coastguard Worker 
WriteComment(std::ostream & out,const CallCapture & call)821*8975f5c5SAndroid Build Coastguard Worker void WriteComment(std::ostream &out, const CallCapture &call)
822*8975f5c5SAndroid Build Coastguard Worker {
823*8975f5c5SAndroid Build Coastguard Worker     // Read the string parameter
824*8975f5c5SAndroid Build Coastguard Worker     const ParamCapture &stringParam =
825*8975f5c5SAndroid Build Coastguard Worker         call.params.getParam("comment", ParamType::TGLcharConstPointer, 0);
826*8975f5c5SAndroid Build Coastguard Worker     const std::vector<uint8_t> &data = stringParam.data[0];
827*8975f5c5SAndroid Build Coastguard Worker     ASSERT(data.size() > 0 && data.back() == '\0');
828*8975f5c5SAndroid Build Coastguard Worker     std::string str(data.begin(), data.end() - 1);
829*8975f5c5SAndroid Build Coastguard Worker 
830*8975f5c5SAndroid Build Coastguard Worker     // Write the string prefixed with single line comment
831*8975f5c5SAndroid Build Coastguard Worker     out << "// " << str;
832*8975f5c5SAndroid Build Coastguard Worker }
833*8975f5c5SAndroid Build Coastguard Worker 
WriteCppReplayForCall(const CallCapture & call,ReplayWriter & replayWriter,std::ostream & out,std::ostream & header,std::vector<uint8_t> * binaryData,size_t * maxResourceIDBufferSize)834*8975f5c5SAndroid Build Coastguard Worker void WriteCppReplayForCall(const CallCapture &call,
835*8975f5c5SAndroid Build Coastguard Worker                            ReplayWriter &replayWriter,
836*8975f5c5SAndroid Build Coastguard Worker                            std::ostream &out,
837*8975f5c5SAndroid Build Coastguard Worker                            std::ostream &header,
838*8975f5c5SAndroid Build Coastguard Worker                            std::vector<uint8_t> *binaryData,
839*8975f5c5SAndroid Build Coastguard Worker                            size_t *maxResourceIDBufferSize)
840*8975f5c5SAndroid Build Coastguard Worker {
841*8975f5c5SAndroid Build Coastguard Worker     if (call.customFunctionName == "Comment")
842*8975f5c5SAndroid Build Coastguard Worker     {
843*8975f5c5SAndroid Build Coastguard Worker         // Just write it directly to the file and move on
844*8975f5c5SAndroid Build Coastguard Worker         WriteComment(out, call);
845*8975f5c5SAndroid Build Coastguard Worker         return;
846*8975f5c5SAndroid Build Coastguard Worker     }
847*8975f5c5SAndroid Build Coastguard Worker 
848*8975f5c5SAndroid Build Coastguard Worker     std::ostringstream callOut;
849*8975f5c5SAndroid Build Coastguard Worker 
850*8975f5c5SAndroid Build Coastguard Worker     callOut << call.name() << "(";
851*8975f5c5SAndroid Build Coastguard Worker 
852*8975f5c5SAndroid Build Coastguard Worker     bool first = true;
853*8975f5c5SAndroid Build Coastguard Worker     for (const ParamCapture &param : call.params.getParamCaptures())
854*8975f5c5SAndroid Build Coastguard Worker     {
855*8975f5c5SAndroid Build Coastguard Worker         if (!first)
856*8975f5c5SAndroid Build Coastguard Worker         {
857*8975f5c5SAndroid Build Coastguard Worker             callOut << ", ";
858*8975f5c5SAndroid Build Coastguard Worker         }
859*8975f5c5SAndroid Build Coastguard Worker 
860*8975f5c5SAndroid Build Coastguard Worker         if (param.arrayClientPointerIndex != -1 && param.value.voidConstPointerVal != nullptr)
861*8975f5c5SAndroid Build Coastguard Worker         {
862*8975f5c5SAndroid Build Coastguard Worker             callOut << "gClientArrays[" << param.arrayClientPointerIndex << "]";
863*8975f5c5SAndroid Build Coastguard Worker         }
864*8975f5c5SAndroid Build Coastguard Worker         else if (param.readBufferSizeBytes > 0)
865*8975f5c5SAndroid Build Coastguard Worker         {
866*8975f5c5SAndroid Build Coastguard Worker             callOut << "(" << ParamTypeToString(param.type) << ")gReadBuffer";
867*8975f5c5SAndroid Build Coastguard Worker         }
868*8975f5c5SAndroid Build Coastguard Worker         else if (param.data.empty())
869*8975f5c5SAndroid Build Coastguard Worker         {
870*8975f5c5SAndroid Build Coastguard Worker             if (param.type == ParamType::TGLenum)
871*8975f5c5SAndroid Build Coastguard Worker             {
872*8975f5c5SAndroid Build Coastguard Worker                 OutputGLenumString(callOut, param.enumGroup, param.value.GLenumVal);
873*8975f5c5SAndroid Build Coastguard Worker             }
874*8975f5c5SAndroid Build Coastguard Worker             else if (param.type == ParamType::TGLbitfield)
875*8975f5c5SAndroid Build Coastguard Worker             {
876*8975f5c5SAndroid Build Coastguard Worker                 OutputGLbitfieldString(callOut, param.enumGroup, param.value.GLbitfieldVal);
877*8975f5c5SAndroid Build Coastguard Worker             }
878*8975f5c5SAndroid Build Coastguard Worker             else if (param.type == ParamType::TGLfloat)
879*8975f5c5SAndroid Build Coastguard Worker             {
880*8975f5c5SAndroid Build Coastguard Worker                 WriteGLFloatValue(callOut, param.value.GLfloatVal);
881*8975f5c5SAndroid Build Coastguard Worker             }
882*8975f5c5SAndroid Build Coastguard Worker             else if (param.type == ParamType::TGLsync)
883*8975f5c5SAndroid Build Coastguard Worker             {
884*8975f5c5SAndroid Build Coastguard Worker                 callOut << "gSyncMap[" << FmtPointerIndex(param.value.GLsyncVal) << "]";
885*8975f5c5SAndroid Build Coastguard Worker             }
886*8975f5c5SAndroid Build Coastguard Worker             else if (param.type == ParamType::TGLuint64 && param.name == "timeout")
887*8975f5c5SAndroid Build Coastguard Worker             {
888*8975f5c5SAndroid Build Coastguard Worker                 if (param.value.GLuint64Val == GL_TIMEOUT_IGNORED)
889*8975f5c5SAndroid Build Coastguard Worker                 {
890*8975f5c5SAndroid Build Coastguard Worker                     callOut << "GL_TIMEOUT_IGNORED";
891*8975f5c5SAndroid Build Coastguard Worker                 }
892*8975f5c5SAndroid Build Coastguard Worker                 else
893*8975f5c5SAndroid Build Coastguard Worker                 {
894*8975f5c5SAndroid Build Coastguard Worker                     WriteParamCaptureReplay(callOut, call, param);
895*8975f5c5SAndroid Build Coastguard Worker                 }
896*8975f5c5SAndroid Build Coastguard Worker             }
897*8975f5c5SAndroid Build Coastguard Worker             else
898*8975f5c5SAndroid Build Coastguard Worker             {
899*8975f5c5SAndroid Build Coastguard Worker                 WriteParamCaptureReplay(callOut, call, param);
900*8975f5c5SAndroid Build Coastguard Worker             }
901*8975f5c5SAndroid Build Coastguard Worker         }
902*8975f5c5SAndroid Build Coastguard Worker         else
903*8975f5c5SAndroid Build Coastguard Worker         {
904*8975f5c5SAndroid Build Coastguard Worker             switch (param.type)
905*8975f5c5SAndroid Build Coastguard Worker             {
906*8975f5c5SAndroid Build Coastguard Worker                 case ParamType::TGLcharConstPointer:
907*8975f5c5SAndroid Build Coastguard Worker                     WriteStringParamReplay(replayWriter, callOut, header, call, param, binaryData);
908*8975f5c5SAndroid Build Coastguard Worker                     break;
909*8975f5c5SAndroid Build Coastguard Worker                 case ParamType::TGLcharConstPointerPointer:
910*8975f5c5SAndroid Build Coastguard Worker                     WriteStringPointerParamReplay(replayWriter, callOut, header, call, param);
911*8975f5c5SAndroid Build Coastguard Worker                     break;
912*8975f5c5SAndroid Build Coastguard Worker                 case ParamType::TBufferIDConstPointer:
913*8975f5c5SAndroid Build Coastguard Worker                     WriteResourceIDPointerParamReplay<gl::BufferID>(
914*8975f5c5SAndroid Build Coastguard Worker                         replayWriter, callOut, out, call, param, maxResourceIDBufferSize);
915*8975f5c5SAndroid Build Coastguard Worker                     break;
916*8975f5c5SAndroid Build Coastguard Worker                 case ParamType::TFenceNVIDConstPointer:
917*8975f5c5SAndroid Build Coastguard Worker                     WriteResourceIDPointerParamReplay<gl::FenceNVID>(
918*8975f5c5SAndroid Build Coastguard Worker                         replayWriter, callOut, out, call, param, maxResourceIDBufferSize);
919*8975f5c5SAndroid Build Coastguard Worker                     break;
920*8975f5c5SAndroid Build Coastguard Worker                 case ParamType::TFramebufferIDConstPointer:
921*8975f5c5SAndroid Build Coastguard Worker                     WriteResourceIDPointerParamReplay<gl::FramebufferID>(
922*8975f5c5SAndroid Build Coastguard Worker                         replayWriter, callOut, out, call, param, maxResourceIDBufferSize);
923*8975f5c5SAndroid Build Coastguard Worker                     break;
924*8975f5c5SAndroid Build Coastguard Worker                 case ParamType::TMemoryObjectIDConstPointer:
925*8975f5c5SAndroid Build Coastguard Worker                     WriteResourceIDPointerParamReplay<gl::MemoryObjectID>(
926*8975f5c5SAndroid Build Coastguard Worker                         replayWriter, callOut, out, call, param, maxResourceIDBufferSize);
927*8975f5c5SAndroid Build Coastguard Worker                     break;
928*8975f5c5SAndroid Build Coastguard Worker                 case ParamType::TProgramPipelineIDConstPointer:
929*8975f5c5SAndroid Build Coastguard Worker                     WriteResourceIDPointerParamReplay<gl::ProgramPipelineID>(
930*8975f5c5SAndroid Build Coastguard Worker                         replayWriter, callOut, out, call, param, maxResourceIDBufferSize);
931*8975f5c5SAndroid Build Coastguard Worker                     break;
932*8975f5c5SAndroid Build Coastguard Worker                 case ParamType::TQueryIDConstPointer:
933*8975f5c5SAndroid Build Coastguard Worker                     WriteResourceIDPointerParamReplay<gl::QueryID>(replayWriter, callOut, out, call,
934*8975f5c5SAndroid Build Coastguard Worker                                                                    param, maxResourceIDBufferSize);
935*8975f5c5SAndroid Build Coastguard Worker                     break;
936*8975f5c5SAndroid Build Coastguard Worker                 case ParamType::TRenderbufferIDConstPointer:
937*8975f5c5SAndroid Build Coastguard Worker                     WriteResourceIDPointerParamReplay<gl::RenderbufferID>(
938*8975f5c5SAndroid Build Coastguard Worker                         replayWriter, callOut, out, call, param, maxResourceIDBufferSize);
939*8975f5c5SAndroid Build Coastguard Worker                     break;
940*8975f5c5SAndroid Build Coastguard Worker                 case ParamType::TSamplerIDConstPointer:
941*8975f5c5SAndroid Build Coastguard Worker                     WriteResourceIDPointerParamReplay<gl::SamplerID>(
942*8975f5c5SAndroid Build Coastguard Worker                         replayWriter, callOut, out, call, param, maxResourceIDBufferSize);
943*8975f5c5SAndroid Build Coastguard Worker                     break;
944*8975f5c5SAndroid Build Coastguard Worker                 case ParamType::TSemaphoreIDConstPointer:
945*8975f5c5SAndroid Build Coastguard Worker                     WriteResourceIDPointerParamReplay<gl::SemaphoreID>(
946*8975f5c5SAndroid Build Coastguard Worker                         replayWriter, callOut, out, call, param, maxResourceIDBufferSize);
947*8975f5c5SAndroid Build Coastguard Worker                     break;
948*8975f5c5SAndroid Build Coastguard Worker                 case ParamType::TTextureIDConstPointer:
949*8975f5c5SAndroid Build Coastguard Worker                     WriteResourceIDPointerParamReplay<gl::TextureID>(
950*8975f5c5SAndroid Build Coastguard Worker                         replayWriter, callOut, out, call, param, maxResourceIDBufferSize);
951*8975f5c5SAndroid Build Coastguard Worker                     break;
952*8975f5c5SAndroid Build Coastguard Worker                 case ParamType::TTransformFeedbackIDConstPointer:
953*8975f5c5SAndroid Build Coastguard Worker                     WriteResourceIDPointerParamReplay<gl::TransformFeedbackID>(
954*8975f5c5SAndroid Build Coastguard Worker                         replayWriter, callOut, out, call, param, maxResourceIDBufferSize);
955*8975f5c5SAndroid Build Coastguard Worker                     break;
956*8975f5c5SAndroid Build Coastguard Worker                 case ParamType::TVertexArrayIDConstPointer:
957*8975f5c5SAndroid Build Coastguard Worker                     WriteResourceIDPointerParamReplay<gl::VertexArrayID>(
958*8975f5c5SAndroid Build Coastguard Worker                         replayWriter, callOut, out, call, param, maxResourceIDBufferSize);
959*8975f5c5SAndroid Build Coastguard Worker                     break;
960*8975f5c5SAndroid Build Coastguard Worker                 default:
961*8975f5c5SAndroid Build Coastguard Worker                     WriteBinaryParamReplay(replayWriter, callOut, header, call, param, binaryData);
962*8975f5c5SAndroid Build Coastguard Worker                     break;
963*8975f5c5SAndroid Build Coastguard Worker             }
964*8975f5c5SAndroid Build Coastguard Worker         }
965*8975f5c5SAndroid Build Coastguard Worker 
966*8975f5c5SAndroid Build Coastguard Worker         first = false;
967*8975f5c5SAndroid Build Coastguard Worker     }
968*8975f5c5SAndroid Build Coastguard Worker 
969*8975f5c5SAndroid Build Coastguard Worker     callOut << ")";
970*8975f5c5SAndroid Build Coastguard Worker 
971*8975f5c5SAndroid Build Coastguard Worker     out << callOut.str();
972*8975f5c5SAndroid Build Coastguard Worker }
973*8975f5c5SAndroid Build Coastguard Worker 
AddComment(std::vector<CallCapture> * outCalls,const std::string & comment)974*8975f5c5SAndroid Build Coastguard Worker void AddComment(std::vector<CallCapture> *outCalls, const std::string &comment)
975*8975f5c5SAndroid Build Coastguard Worker {
976*8975f5c5SAndroid Build Coastguard Worker 
977*8975f5c5SAndroid Build Coastguard Worker     ParamBuffer commentParamBuffer;
978*8975f5c5SAndroid Build Coastguard Worker     ParamCapture commentParam("comment", ParamType::TGLcharConstPointer);
979*8975f5c5SAndroid Build Coastguard Worker     CaptureString(comment.c_str(), &commentParam);
980*8975f5c5SAndroid Build Coastguard Worker     commentParamBuffer.addParam(std::move(commentParam));
981*8975f5c5SAndroid Build Coastguard Worker     outCalls->emplace_back("Comment", std::move(commentParamBuffer));
982*8975f5c5SAndroid Build Coastguard Worker }
983*8975f5c5SAndroid Build Coastguard Worker 
MaxClientArraySize(const gl::AttribArray<size_t> & clientArraySizes)984*8975f5c5SAndroid Build Coastguard Worker size_t MaxClientArraySize(const gl::AttribArray<size_t> &clientArraySizes)
985*8975f5c5SAndroid Build Coastguard Worker {
986*8975f5c5SAndroid Build Coastguard Worker     size_t found = 0;
987*8975f5c5SAndroid Build Coastguard Worker     for (size_t size : clientArraySizes)
988*8975f5c5SAndroid Build Coastguard Worker     {
989*8975f5c5SAndroid Build Coastguard Worker         if (size > found)
990*8975f5c5SAndroid Build Coastguard Worker         {
991*8975f5c5SAndroid Build Coastguard Worker             found = size;
992*8975f5c5SAndroid Build Coastguard Worker         }
993*8975f5c5SAndroid Build Coastguard Worker     }
994*8975f5c5SAndroid Build Coastguard Worker 
995*8975f5c5SAndroid Build Coastguard Worker     return found;
996*8975f5c5SAndroid Build Coastguard Worker }
997*8975f5c5SAndroid Build Coastguard Worker 
GetBinaryDataFilePath(bool compression,const std::string & captureLabel)998*8975f5c5SAndroid Build Coastguard Worker std::string GetBinaryDataFilePath(bool compression, const std::string &captureLabel)
999*8975f5c5SAndroid Build Coastguard Worker {
1000*8975f5c5SAndroid Build Coastguard Worker     std::stringstream fnameStream;
1001*8975f5c5SAndroid Build Coastguard Worker     fnameStream << FmtCapturePrefix(kNoContextId, captureLabel) << ".angledata";
1002*8975f5c5SAndroid Build Coastguard Worker     if (compression)
1003*8975f5c5SAndroid Build Coastguard Worker     {
1004*8975f5c5SAndroid Build Coastguard Worker         fnameStream << ".gz";
1005*8975f5c5SAndroid Build Coastguard Worker     }
1006*8975f5c5SAndroid Build Coastguard Worker     return fnameStream.str();
1007*8975f5c5SAndroid Build Coastguard Worker }
1008*8975f5c5SAndroid Build Coastguard Worker 
1009*8975f5c5SAndroid Build Coastguard Worker struct SaveFileHelper
1010*8975f5c5SAndroid Build Coastguard Worker {
1011*8975f5c5SAndroid Build Coastguard Worker   public:
1012*8975f5c5SAndroid Build Coastguard Worker     // We always use ios::binary to avoid inconsistent line endings when captured on Linux vs Win.
SaveFileHelperangle::__anoncf31a3f40111::SaveFileHelper1013*8975f5c5SAndroid Build Coastguard Worker     SaveFileHelper(const std::string &filePathIn)
1014*8975f5c5SAndroid Build Coastguard Worker         : mOfs(filePathIn, std::ios::binary | std::ios::out), mFilePath(filePathIn)
1015*8975f5c5SAndroid Build Coastguard Worker     {
1016*8975f5c5SAndroid Build Coastguard Worker         if (!mOfs.is_open())
1017*8975f5c5SAndroid Build Coastguard Worker         {
1018*8975f5c5SAndroid Build Coastguard Worker             FATAL() << "Could not open " << filePathIn;
1019*8975f5c5SAndroid Build Coastguard Worker         }
1020*8975f5c5SAndroid Build Coastguard Worker     }
~SaveFileHelperangle::__anoncf31a3f40111::SaveFileHelper1021*8975f5c5SAndroid Build Coastguard Worker     ~SaveFileHelper() { printf("Saved '%s'.\n", mFilePath.c_str()); }
1022*8975f5c5SAndroid Build Coastguard Worker 
1023*8975f5c5SAndroid Build Coastguard Worker     template <typename T>
operator <<angle::__anoncf31a3f40111::SaveFileHelper1024*8975f5c5SAndroid Build Coastguard Worker     SaveFileHelper &operator<<(const T &value)
1025*8975f5c5SAndroid Build Coastguard Worker     {
1026*8975f5c5SAndroid Build Coastguard Worker         mOfs << value;
1027*8975f5c5SAndroid Build Coastguard Worker         if (mOfs.bad())
1028*8975f5c5SAndroid Build Coastguard Worker         {
1029*8975f5c5SAndroid Build Coastguard Worker             FATAL() << "Error writing to " << mFilePath;
1030*8975f5c5SAndroid Build Coastguard Worker         }
1031*8975f5c5SAndroid Build Coastguard Worker         return *this;
1032*8975f5c5SAndroid Build Coastguard Worker     }
1033*8975f5c5SAndroid Build Coastguard Worker 
writeangle::__anoncf31a3f40111::SaveFileHelper1034*8975f5c5SAndroid Build Coastguard Worker     void write(const uint8_t *data, size_t size)
1035*8975f5c5SAndroid Build Coastguard Worker     {
1036*8975f5c5SAndroid Build Coastguard Worker         mOfs.write(reinterpret_cast<const char *>(data), size);
1037*8975f5c5SAndroid Build Coastguard Worker     }
1038*8975f5c5SAndroid Build Coastguard Worker 
1039*8975f5c5SAndroid Build Coastguard Worker   private:
1040*8975f5c5SAndroid Build Coastguard Worker     void checkError();
1041*8975f5c5SAndroid Build Coastguard Worker 
1042*8975f5c5SAndroid Build Coastguard Worker     std::ofstream mOfs;
1043*8975f5c5SAndroid Build Coastguard Worker     std::string mFilePath;
1044*8975f5c5SAndroid Build Coastguard Worker };
1045*8975f5c5SAndroid Build Coastguard Worker 
SaveBinaryData(bool compression,const std::string & outDir,gl::ContextID contextId,const std::string & captureLabel,const std::vector<uint8_t> & binaryData)1046*8975f5c5SAndroid Build Coastguard Worker void SaveBinaryData(bool compression,
1047*8975f5c5SAndroid Build Coastguard Worker                     const std::string &outDir,
1048*8975f5c5SAndroid Build Coastguard Worker                     gl::ContextID contextId,
1049*8975f5c5SAndroid Build Coastguard Worker                     const std::string &captureLabel,
1050*8975f5c5SAndroid Build Coastguard Worker                     const std::vector<uint8_t> &binaryData)
1051*8975f5c5SAndroid Build Coastguard Worker {
1052*8975f5c5SAndroid Build Coastguard Worker     std::string binaryDataFileName = GetBinaryDataFilePath(compression, captureLabel);
1053*8975f5c5SAndroid Build Coastguard Worker     std::string dataFilepath       = outDir + binaryDataFileName;
1054*8975f5c5SAndroid Build Coastguard Worker 
1055*8975f5c5SAndroid Build Coastguard Worker     SaveFileHelper saveData(dataFilepath);
1056*8975f5c5SAndroid Build Coastguard Worker 
1057*8975f5c5SAndroid Build Coastguard Worker     if (compression)
1058*8975f5c5SAndroid Build Coastguard Worker     {
1059*8975f5c5SAndroid Build Coastguard Worker         // Save compressed data.
1060*8975f5c5SAndroid Build Coastguard Worker         uLong uncompressedSize       = static_cast<uLong>(binaryData.size());
1061*8975f5c5SAndroid Build Coastguard Worker         uLong expectedCompressedSize = zlib_internal::GzipExpectedCompressedSize(uncompressedSize);
1062*8975f5c5SAndroid Build Coastguard Worker 
1063*8975f5c5SAndroid Build Coastguard Worker         std::vector<uint8_t> compressedData(expectedCompressedSize, 0);
1064*8975f5c5SAndroid Build Coastguard Worker 
1065*8975f5c5SAndroid Build Coastguard Worker         uLong compressedSize = expectedCompressedSize;
1066*8975f5c5SAndroid Build Coastguard Worker         int zResult = zlib_internal::GzipCompressHelper(compressedData.data(), &compressedSize,
1067*8975f5c5SAndroid Build Coastguard Worker                                                         binaryData.data(), uncompressedSize,
1068*8975f5c5SAndroid Build Coastguard Worker                                                         nullptr, nullptr);
1069*8975f5c5SAndroid Build Coastguard Worker 
1070*8975f5c5SAndroid Build Coastguard Worker         if (zResult != Z_OK)
1071*8975f5c5SAndroid Build Coastguard Worker         {
1072*8975f5c5SAndroid Build Coastguard Worker             FATAL() << "Error compressing binary data: " << zResult;
1073*8975f5c5SAndroid Build Coastguard Worker         }
1074*8975f5c5SAndroid Build Coastguard Worker 
1075*8975f5c5SAndroid Build Coastguard Worker         saveData.write(compressedData.data(), compressedSize);
1076*8975f5c5SAndroid Build Coastguard Worker     }
1077*8975f5c5SAndroid Build Coastguard Worker     else
1078*8975f5c5SAndroid Build Coastguard Worker     {
1079*8975f5c5SAndroid Build Coastguard Worker         saveData.write(binaryData.data(), binaryData.size());
1080*8975f5c5SAndroid Build Coastguard Worker     }
1081*8975f5c5SAndroid Build Coastguard Worker }
1082*8975f5c5SAndroid Build Coastguard Worker 
WriteInitReplayCall(bool compression,std::ostream & out,gl::ContextID contextID,const std::string & captureLabel,size_t maxClientArraySize,size_t readBufferSize,size_t resourceIDBufferSize,const PackedEnumMap<ResourceIDType,uint32_t> & maxIDs)1083*8975f5c5SAndroid Build Coastguard Worker void WriteInitReplayCall(bool compression,
1084*8975f5c5SAndroid Build Coastguard Worker                          std::ostream &out,
1085*8975f5c5SAndroid Build Coastguard Worker                          gl::ContextID contextID,
1086*8975f5c5SAndroid Build Coastguard Worker                          const std::string &captureLabel,
1087*8975f5c5SAndroid Build Coastguard Worker                          size_t maxClientArraySize,
1088*8975f5c5SAndroid Build Coastguard Worker                          size_t readBufferSize,
1089*8975f5c5SAndroid Build Coastguard Worker                          size_t resourceIDBufferSize,
1090*8975f5c5SAndroid Build Coastguard Worker                          const PackedEnumMap<ResourceIDType, uint32_t> &maxIDs)
1091*8975f5c5SAndroid Build Coastguard Worker {
1092*8975f5c5SAndroid Build Coastguard Worker     std::string binaryDataFileName = GetBinaryDataFilePath(compression, captureLabel);
1093*8975f5c5SAndroid Build Coastguard Worker 
1094*8975f5c5SAndroid Build Coastguard Worker     out << "    // binaryDataFileName = " << binaryDataFileName << "\n";
1095*8975f5c5SAndroid Build Coastguard Worker     out << "    // maxClientArraySize = " << maxClientArraySize << "\n";
1096*8975f5c5SAndroid Build Coastguard Worker     out << "    // maxClientArraySize = " << maxClientArraySize << "\n";
1097*8975f5c5SAndroid Build Coastguard Worker     out << "    // readBufferSize = " << readBufferSize << "\n";
1098*8975f5c5SAndroid Build Coastguard Worker     out << "    // resourceIDBufferSize = " << resourceIDBufferSize << "\n";
1099*8975f5c5SAndroid Build Coastguard Worker     out << "    // contextID = " << contextID << "\n";
1100*8975f5c5SAndroid Build Coastguard Worker 
1101*8975f5c5SAndroid Build Coastguard Worker     for (ResourceIDType resourceID : AllEnums<ResourceIDType>())
1102*8975f5c5SAndroid Build Coastguard Worker     {
1103*8975f5c5SAndroid Build Coastguard Worker         const char *name = GetResourceIDTypeName(resourceID);
1104*8975f5c5SAndroid Build Coastguard Worker         out << "    // max" << name << " = " << maxIDs[resourceID] << "\n";
1105*8975f5c5SAndroid Build Coastguard Worker     }
1106*8975f5c5SAndroid Build Coastguard Worker 
1107*8975f5c5SAndroid Build Coastguard Worker     out << "    InitializeReplay4(\"" << binaryDataFileName << "\", " << maxClientArraySize << ", "
1108*8975f5c5SAndroid Build Coastguard Worker         << readBufferSize << ", " << resourceIDBufferSize << ", " << contextID;
1109*8975f5c5SAndroid Build Coastguard Worker 
1110*8975f5c5SAndroid Build Coastguard Worker     for (ResourceIDType resourceID : AllEnums<ResourceIDType>())
1111*8975f5c5SAndroid Build Coastguard Worker     {
1112*8975f5c5SAndroid Build Coastguard Worker         // Sanity check for catching e.g. uninitialized memory reads like b/380296979
1113*8975f5c5SAndroid Build Coastguard Worker         ASSERT(maxIDs[resourceID] < 1000000);
1114*8975f5c5SAndroid Build Coastguard Worker         out << ", " << maxIDs[resourceID];
1115*8975f5c5SAndroid Build Coastguard Worker     }
1116*8975f5c5SAndroid Build Coastguard Worker 
1117*8975f5c5SAndroid Build Coastguard Worker     out << ");\n";
1118*8975f5c5SAndroid Build Coastguard Worker }
1119*8975f5c5SAndroid Build Coastguard Worker 
DeleteResourcesInReset(std::stringstream & out,const gl::ContextID contextID,const ResourceSet & newResources,const ResourceSet & resourcesToDelete,const ResourceIDType resourceIDType,size_t * maxResourceIDBufferSize)1120*8975f5c5SAndroid Build Coastguard Worker void DeleteResourcesInReset(std::stringstream &out,
1121*8975f5c5SAndroid Build Coastguard Worker                             const gl::ContextID contextID,
1122*8975f5c5SAndroid Build Coastguard Worker                             const ResourceSet &newResources,
1123*8975f5c5SAndroid Build Coastguard Worker                             const ResourceSet &resourcesToDelete,
1124*8975f5c5SAndroid Build Coastguard Worker                             const ResourceIDType resourceIDType,
1125*8975f5c5SAndroid Build Coastguard Worker                             size_t *maxResourceIDBufferSize)
1126*8975f5c5SAndroid Build Coastguard Worker {
1127*8975f5c5SAndroid Build Coastguard Worker     if (!newResources.empty() || !resourcesToDelete.empty())
1128*8975f5c5SAndroid Build Coastguard Worker     {
1129*8975f5c5SAndroid Build Coastguard Worker         size_t count = 0;
1130*8975f5c5SAndroid Build Coastguard Worker 
1131*8975f5c5SAndroid Build Coastguard Worker         for (GLuint oldResource : resourcesToDelete)
1132*8975f5c5SAndroid Build Coastguard Worker         {
1133*8975f5c5SAndroid Build Coastguard Worker             UpdateResourceIDBuffer(out, Indent::Indent, count++, resourceIDType, contextID,
1134*8975f5c5SAndroid Build Coastguard Worker                                    oldResource);
1135*8975f5c5SAndroid Build Coastguard Worker         }
1136*8975f5c5SAndroid Build Coastguard Worker 
1137*8975f5c5SAndroid Build Coastguard Worker         for (GLuint newResource : newResources)
1138*8975f5c5SAndroid Build Coastguard Worker         {
1139*8975f5c5SAndroid Build Coastguard Worker             UpdateResourceIDBuffer(out, Indent::Indent, count++, resourceIDType, contextID,
1140*8975f5c5SAndroid Build Coastguard Worker                                    newResource);
1141*8975f5c5SAndroid Build Coastguard Worker         }
1142*8975f5c5SAndroid Build Coastguard Worker 
1143*8975f5c5SAndroid Build Coastguard Worker         // Delete all the new and old buffers at once
1144*8975f5c5SAndroid Build Coastguard Worker         out << "    glDelete" << GetResourceIDTypeName(resourceIDType) << "s(" << count
1145*8975f5c5SAndroid Build Coastguard Worker             << ", gResourceIDBuffer);\n";
1146*8975f5c5SAndroid Build Coastguard Worker 
1147*8975f5c5SAndroid Build Coastguard Worker         *maxResourceIDBufferSize = std::max(*maxResourceIDBufferSize, count);
1148*8975f5c5SAndroid Build Coastguard Worker     }
1149*8975f5c5SAndroid Build Coastguard Worker }
1150*8975f5c5SAndroid Build Coastguard Worker 
1151*8975f5c5SAndroid Build Coastguard Worker // TODO (http://anglebug.com/42263204): Reset more state on frame loop
MaybeResetResources(egl::Display * display,gl::ContextID contextID,ResourceIDType resourceIDType,ReplayWriter & replayWriter,std::stringstream & out,std::stringstream & header,ResourceTracker * resourceTracker,std::vector<uint8_t> * binaryData,bool & anyResourceReset,size_t * maxResourceIDBufferSize)1152*8975f5c5SAndroid Build Coastguard Worker void MaybeResetResources(egl::Display *display,
1153*8975f5c5SAndroid Build Coastguard Worker                          gl::ContextID contextID,
1154*8975f5c5SAndroid Build Coastguard Worker                          ResourceIDType resourceIDType,
1155*8975f5c5SAndroid Build Coastguard Worker                          ReplayWriter &replayWriter,
1156*8975f5c5SAndroid Build Coastguard Worker                          std::stringstream &out,
1157*8975f5c5SAndroid Build Coastguard Worker                          std::stringstream &header,
1158*8975f5c5SAndroid Build Coastguard Worker                          ResourceTracker *resourceTracker,
1159*8975f5c5SAndroid Build Coastguard Worker                          std::vector<uint8_t> *binaryData,
1160*8975f5c5SAndroid Build Coastguard Worker                          bool &anyResourceReset,
1161*8975f5c5SAndroid Build Coastguard Worker                          size_t *maxResourceIDBufferSize)
1162*8975f5c5SAndroid Build Coastguard Worker {
1163*8975f5c5SAndroid Build Coastguard Worker     // Track the initial output position so we can detect if it has moved
1164*8975f5c5SAndroid Build Coastguard Worker     std::streampos initialOutPos = out.tellp();
1165*8975f5c5SAndroid Build Coastguard Worker 
1166*8975f5c5SAndroid Build Coastguard Worker     switch (resourceIDType)
1167*8975f5c5SAndroid Build Coastguard Worker     {
1168*8975f5c5SAndroid Build Coastguard Worker         case ResourceIDType::Buffer:
1169*8975f5c5SAndroid Build Coastguard Worker         {
1170*8975f5c5SAndroid Build Coastguard Worker             TrackedResource &trackedBuffers =
1171*8975f5c5SAndroid Build Coastguard Worker                 resourceTracker->getTrackedResource(contextID, ResourceIDType::Buffer);
1172*8975f5c5SAndroid Build Coastguard Worker             ResourceSet &newBuffers           = trackedBuffers.getNewResources();
1173*8975f5c5SAndroid Build Coastguard Worker             ResourceSet &buffersToDelete      = trackedBuffers.getResourcesToDelete();
1174*8975f5c5SAndroid Build Coastguard Worker             ResourceSet &buffersToRegen       = trackedBuffers.getResourcesToRegen();
1175*8975f5c5SAndroid Build Coastguard Worker             ResourceCalls &bufferRegenCalls   = trackedBuffers.getResourceRegenCalls();
1176*8975f5c5SAndroid Build Coastguard Worker             ResourceCalls &bufferRestoreCalls = trackedBuffers.getResourceRestoreCalls();
1177*8975f5c5SAndroid Build Coastguard Worker 
1178*8975f5c5SAndroid Build Coastguard Worker             BufferCalls &bufferMapCalls   = resourceTracker->getBufferMapCalls();
1179*8975f5c5SAndroid Build Coastguard Worker             BufferCalls &bufferUnmapCalls = resourceTracker->getBufferUnmapCalls();
1180*8975f5c5SAndroid Build Coastguard Worker 
1181*8975f5c5SAndroid Build Coastguard Worker             DeleteResourcesInReset(out, contextID, newBuffers, buffersToDelete, resourceIDType,
1182*8975f5c5SAndroid Build Coastguard Worker                                    maxResourceIDBufferSize);
1183*8975f5c5SAndroid Build Coastguard Worker 
1184*8975f5c5SAndroid Build Coastguard Worker             // If any of our starting buffers were deleted during the run, recreate them
1185*8975f5c5SAndroid Build Coastguard Worker             for (GLuint id : buffersToRegen)
1186*8975f5c5SAndroid Build Coastguard Worker             {
1187*8975f5c5SAndroid Build Coastguard Worker                 // Emit their regen calls
1188*8975f5c5SAndroid Build Coastguard Worker                 for (CallCapture &call : bufferRegenCalls[id])
1189*8975f5c5SAndroid Build Coastguard Worker                 {
1190*8975f5c5SAndroid Build Coastguard Worker                     out << "    ";
1191*8975f5c5SAndroid Build Coastguard Worker                     WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
1192*8975f5c5SAndroid Build Coastguard Worker                                           maxResourceIDBufferSize);
1193*8975f5c5SAndroid Build Coastguard Worker                     out << ";\n";
1194*8975f5c5SAndroid Build Coastguard Worker                 }
1195*8975f5c5SAndroid Build Coastguard Worker             }
1196*8975f5c5SAndroid Build Coastguard Worker 
1197*8975f5c5SAndroid Build Coastguard Worker             // If any of our starting buffers were modified during the run, restore their contents
1198*8975f5c5SAndroid Build Coastguard Worker             ResourceSet &buffersToRestore = trackedBuffers.getResourcesToRestore();
1199*8975f5c5SAndroid Build Coastguard Worker             for (GLuint id : buffersToRestore)
1200*8975f5c5SAndroid Build Coastguard Worker             {
1201*8975f5c5SAndroid Build Coastguard Worker                 if (resourceTracker->getStartingBuffersMappedCurrent(id))
1202*8975f5c5SAndroid Build Coastguard Worker                 {
1203*8975f5c5SAndroid Build Coastguard Worker                     // Some drivers require the buffer to be unmapped before you can update data,
1204*8975f5c5SAndroid Build Coastguard Worker                     // which violates the spec. See gl::Buffer::bufferDataImpl().
1205*8975f5c5SAndroid Build Coastguard Worker                     for (CallCapture &call : bufferUnmapCalls[id])
1206*8975f5c5SAndroid Build Coastguard Worker                     {
1207*8975f5c5SAndroid Build Coastguard Worker                         out << "    ";
1208*8975f5c5SAndroid Build Coastguard Worker                         WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
1209*8975f5c5SAndroid Build Coastguard Worker                                               maxResourceIDBufferSize);
1210*8975f5c5SAndroid Build Coastguard Worker                         out << ";\n";
1211*8975f5c5SAndroid Build Coastguard Worker                     }
1212*8975f5c5SAndroid Build Coastguard Worker                 }
1213*8975f5c5SAndroid Build Coastguard Worker 
1214*8975f5c5SAndroid Build Coastguard Worker                 // Emit their restore calls
1215*8975f5c5SAndroid Build Coastguard Worker                 for (CallCapture &call : bufferRestoreCalls[id])
1216*8975f5c5SAndroid Build Coastguard Worker                 {
1217*8975f5c5SAndroid Build Coastguard Worker                     out << "    ";
1218*8975f5c5SAndroid Build Coastguard Worker                     WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
1219*8975f5c5SAndroid Build Coastguard Worker                                           maxResourceIDBufferSize);
1220*8975f5c5SAndroid Build Coastguard Worker                     out << ";\n";
1221*8975f5c5SAndroid Build Coastguard Worker 
1222*8975f5c5SAndroid Build Coastguard Worker                     // Also note that this buffer has been implicitly unmapped by this call
1223*8975f5c5SAndroid Build Coastguard Worker                     resourceTracker->setBufferUnmapped(contextID, id);
1224*8975f5c5SAndroid Build Coastguard Worker                 }
1225*8975f5c5SAndroid Build Coastguard Worker             }
1226*8975f5c5SAndroid Build Coastguard Worker 
1227*8975f5c5SAndroid Build Coastguard Worker             // Update the map/unmap of buffers to match the starting state
1228*8975f5c5SAndroid Build Coastguard Worker             ResourceSet startingBuffers = trackedBuffers.getStartingResources();
1229*8975f5c5SAndroid Build Coastguard Worker             for (GLuint id : startingBuffers)
1230*8975f5c5SAndroid Build Coastguard Worker             {
1231*8975f5c5SAndroid Build Coastguard Worker                 // If the buffer was mapped at the start, but is not mapped now, we need to map
1232*8975f5c5SAndroid Build Coastguard Worker                 if (resourceTracker->getStartingBuffersMappedInitial(id) &&
1233*8975f5c5SAndroid Build Coastguard Worker                     !resourceTracker->getStartingBuffersMappedCurrent(id))
1234*8975f5c5SAndroid Build Coastguard Worker                 {
1235*8975f5c5SAndroid Build Coastguard Worker                     // Emit their map calls
1236*8975f5c5SAndroid Build Coastguard Worker                     for (CallCapture &call : bufferMapCalls[id])
1237*8975f5c5SAndroid Build Coastguard Worker                     {
1238*8975f5c5SAndroid Build Coastguard Worker                         out << "    ";
1239*8975f5c5SAndroid Build Coastguard Worker                         WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
1240*8975f5c5SAndroid Build Coastguard Worker                                               maxResourceIDBufferSize);
1241*8975f5c5SAndroid Build Coastguard Worker                         out << ";\n";
1242*8975f5c5SAndroid Build Coastguard Worker                     }
1243*8975f5c5SAndroid Build Coastguard Worker                 }
1244*8975f5c5SAndroid Build Coastguard Worker                 // If the buffer was unmapped at the start, but is mapped now, we need to unmap
1245*8975f5c5SAndroid Build Coastguard Worker                 if (!resourceTracker->getStartingBuffersMappedInitial(id) &&
1246*8975f5c5SAndroid Build Coastguard Worker                     resourceTracker->getStartingBuffersMappedCurrent(id))
1247*8975f5c5SAndroid Build Coastguard Worker                 {
1248*8975f5c5SAndroid Build Coastguard Worker                     // Emit their unmap calls
1249*8975f5c5SAndroid Build Coastguard Worker                     for (CallCapture &call : bufferUnmapCalls[id])
1250*8975f5c5SAndroid Build Coastguard Worker                     {
1251*8975f5c5SAndroid Build Coastguard Worker                         out << "    ";
1252*8975f5c5SAndroid Build Coastguard Worker                         WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
1253*8975f5c5SAndroid Build Coastguard Worker                                               maxResourceIDBufferSize);
1254*8975f5c5SAndroid Build Coastguard Worker                         out << ";\n";
1255*8975f5c5SAndroid Build Coastguard Worker                     }
1256*8975f5c5SAndroid Build Coastguard Worker                 }
1257*8975f5c5SAndroid Build Coastguard Worker             }
1258*8975f5c5SAndroid Build Coastguard Worker             break;
1259*8975f5c5SAndroid Build Coastguard Worker         }
1260*8975f5c5SAndroid Build Coastguard Worker         case ResourceIDType::Framebuffer:
1261*8975f5c5SAndroid Build Coastguard Worker         {
1262*8975f5c5SAndroid Build Coastguard Worker             TrackedResource &trackedFramebuffers =
1263*8975f5c5SAndroid Build Coastguard Worker                 resourceTracker->getTrackedResource(contextID, ResourceIDType::Framebuffer);
1264*8975f5c5SAndroid Build Coastguard Worker             ResourceSet &newFramebuffers           = trackedFramebuffers.getNewResources();
1265*8975f5c5SAndroid Build Coastguard Worker             ResourceSet &framebuffersToDelete      = trackedFramebuffers.getResourcesToDelete();
1266*8975f5c5SAndroid Build Coastguard Worker             ResourceSet &framebuffersToRegen       = trackedFramebuffers.getResourcesToRegen();
1267*8975f5c5SAndroid Build Coastguard Worker             ResourceCalls &framebufferRegenCalls   = trackedFramebuffers.getResourceRegenCalls();
1268*8975f5c5SAndroid Build Coastguard Worker             ResourceCalls &framebufferRestoreCalls = trackedFramebuffers.getResourceRestoreCalls();
1269*8975f5c5SAndroid Build Coastguard Worker 
1270*8975f5c5SAndroid Build Coastguard Worker             DeleteResourcesInReset(out, contextID, newFramebuffers, framebuffersToDelete,
1271*8975f5c5SAndroid Build Coastguard Worker                                    resourceIDType, maxResourceIDBufferSize);
1272*8975f5c5SAndroid Build Coastguard Worker 
1273*8975f5c5SAndroid Build Coastguard Worker             for (GLuint id : framebuffersToRegen)
1274*8975f5c5SAndroid Build Coastguard Worker             {
1275*8975f5c5SAndroid Build Coastguard Worker                 // Emit their regen calls
1276*8975f5c5SAndroid Build Coastguard Worker                 for (CallCapture &call : framebufferRegenCalls[id])
1277*8975f5c5SAndroid Build Coastguard Worker                 {
1278*8975f5c5SAndroid Build Coastguard Worker                     out << "    ";
1279*8975f5c5SAndroid Build Coastguard Worker                     WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
1280*8975f5c5SAndroid Build Coastguard Worker                                           maxResourceIDBufferSize);
1281*8975f5c5SAndroid Build Coastguard Worker                     out << ";\n";
1282*8975f5c5SAndroid Build Coastguard Worker                 }
1283*8975f5c5SAndroid Build Coastguard Worker             }
1284*8975f5c5SAndroid Build Coastguard Worker 
1285*8975f5c5SAndroid Build Coastguard Worker             // If any of our starting framebuffers were modified during the run, restore their
1286*8975f5c5SAndroid Build Coastguard Worker             // contents
1287*8975f5c5SAndroid Build Coastguard Worker             ResourceSet &framebuffersToRestore = trackedFramebuffers.getResourcesToRestore();
1288*8975f5c5SAndroid Build Coastguard Worker             for (GLuint id : framebuffersToRestore)
1289*8975f5c5SAndroid Build Coastguard Worker             {
1290*8975f5c5SAndroid Build Coastguard Worker                 // Emit their restore calls
1291*8975f5c5SAndroid Build Coastguard Worker                 for (CallCapture &call : framebufferRestoreCalls[id])
1292*8975f5c5SAndroid Build Coastguard Worker                 {
1293*8975f5c5SAndroid Build Coastguard Worker                     out << "    ";
1294*8975f5c5SAndroid Build Coastguard Worker                     WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
1295*8975f5c5SAndroid Build Coastguard Worker                                           maxResourceIDBufferSize);
1296*8975f5c5SAndroid Build Coastguard Worker                     out << ";\n";
1297*8975f5c5SAndroid Build Coastguard Worker                 }
1298*8975f5c5SAndroid Build Coastguard Worker             }
1299*8975f5c5SAndroid Build Coastguard Worker             break;
1300*8975f5c5SAndroid Build Coastguard Worker         }
1301*8975f5c5SAndroid Build Coastguard Worker         case ResourceIDType::Renderbuffer:
1302*8975f5c5SAndroid Build Coastguard Worker         {
1303*8975f5c5SAndroid Build Coastguard Worker             TrackedResource &trackedRenderbuffers =
1304*8975f5c5SAndroid Build Coastguard Worker                 resourceTracker->getTrackedResource(contextID, ResourceIDType::Renderbuffer);
1305*8975f5c5SAndroid Build Coastguard Worker             ResourceSet &newRenderbuffers         = trackedRenderbuffers.getNewResources();
1306*8975f5c5SAndroid Build Coastguard Worker             ResourceSet &renderbuffersToDelete    = trackedRenderbuffers.getResourcesToDelete();
1307*8975f5c5SAndroid Build Coastguard Worker             ResourceSet &renderbuffersToRegen     = trackedRenderbuffers.getResourcesToRegen();
1308*8975f5c5SAndroid Build Coastguard Worker             ResourceCalls &renderbufferRegenCalls = trackedRenderbuffers.getResourceRegenCalls();
1309*8975f5c5SAndroid Build Coastguard Worker             ResourceCalls &renderbufferRestoreCalls =
1310*8975f5c5SAndroid Build Coastguard Worker                 trackedRenderbuffers.getResourceRestoreCalls();
1311*8975f5c5SAndroid Build Coastguard Worker 
1312*8975f5c5SAndroid Build Coastguard Worker             DeleteResourcesInReset(out, contextID, newRenderbuffers, renderbuffersToDelete,
1313*8975f5c5SAndroid Build Coastguard Worker                                    resourceIDType, maxResourceIDBufferSize);
1314*8975f5c5SAndroid Build Coastguard Worker 
1315*8975f5c5SAndroid Build Coastguard Worker             for (GLuint id : renderbuffersToRegen)
1316*8975f5c5SAndroid Build Coastguard Worker             {
1317*8975f5c5SAndroid Build Coastguard Worker                 // Emit their regen calls
1318*8975f5c5SAndroid Build Coastguard Worker                 for (CallCapture &call : renderbufferRegenCalls[id])
1319*8975f5c5SAndroid Build Coastguard Worker                 {
1320*8975f5c5SAndroid Build Coastguard Worker                     out << "    ";
1321*8975f5c5SAndroid Build Coastguard Worker                     WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
1322*8975f5c5SAndroid Build Coastguard Worker                                           maxResourceIDBufferSize);
1323*8975f5c5SAndroid Build Coastguard Worker                     out << ";\n";
1324*8975f5c5SAndroid Build Coastguard Worker                 }
1325*8975f5c5SAndroid Build Coastguard Worker             }
1326*8975f5c5SAndroid Build Coastguard Worker 
1327*8975f5c5SAndroid Build Coastguard Worker             // If any of our starting renderbuffers were modified during the run, restore their
1328*8975f5c5SAndroid Build Coastguard Worker             // contents
1329*8975f5c5SAndroid Build Coastguard Worker             ResourceSet &renderbuffersToRestore = trackedRenderbuffers.getResourcesToRestore();
1330*8975f5c5SAndroid Build Coastguard Worker             for (GLuint id : renderbuffersToRestore)
1331*8975f5c5SAndroid Build Coastguard Worker             {
1332*8975f5c5SAndroid Build Coastguard Worker                 // Emit their restore calls
1333*8975f5c5SAndroid Build Coastguard Worker                 for (CallCapture &call : renderbufferRestoreCalls[id])
1334*8975f5c5SAndroid Build Coastguard Worker                 {
1335*8975f5c5SAndroid Build Coastguard Worker                     out << "    ";
1336*8975f5c5SAndroid Build Coastguard Worker                     WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
1337*8975f5c5SAndroid Build Coastguard Worker                                           maxResourceIDBufferSize);
1338*8975f5c5SAndroid Build Coastguard Worker                     out << ";\n";
1339*8975f5c5SAndroid Build Coastguard Worker                 }
1340*8975f5c5SAndroid Build Coastguard Worker             }
1341*8975f5c5SAndroid Build Coastguard Worker             break;
1342*8975f5c5SAndroid Build Coastguard Worker         }
1343*8975f5c5SAndroid Build Coastguard Worker         case ResourceIDType::ShaderProgram:
1344*8975f5c5SAndroid Build Coastguard Worker         {
1345*8975f5c5SAndroid Build Coastguard Worker             TrackedResource &trackedShaderPrograms =
1346*8975f5c5SAndroid Build Coastguard Worker                 resourceTracker->getTrackedResource(contextID, ResourceIDType::ShaderProgram);
1347*8975f5c5SAndroid Build Coastguard Worker             ResourceSet &newShaderPrograms         = trackedShaderPrograms.getNewResources();
1348*8975f5c5SAndroid Build Coastguard Worker             ResourceSet &shaderProgramsToDelete    = trackedShaderPrograms.getResourcesToDelete();
1349*8975f5c5SAndroid Build Coastguard Worker             ResourceSet &shaderProgramsToRegen     = trackedShaderPrograms.getResourcesToRegen();
1350*8975f5c5SAndroid Build Coastguard Worker             ResourceSet &shaderProgramsToRestore   = trackedShaderPrograms.getResourcesToRestore();
1351*8975f5c5SAndroid Build Coastguard Worker             ResourceCalls &shaderProgramRegenCalls = trackedShaderPrograms.getResourceRegenCalls();
1352*8975f5c5SAndroid Build Coastguard Worker             ResourceCalls &shaderProgramRestoreCalls =
1353*8975f5c5SAndroid Build Coastguard Worker                 trackedShaderPrograms.getResourceRestoreCalls();
1354*8975f5c5SAndroid Build Coastguard Worker 
1355*8975f5c5SAndroid Build Coastguard Worker             // If we have any new shaders or programs created and not deleted during the run, delete
1356*8975f5c5SAndroid Build Coastguard Worker             // them now
1357*8975f5c5SAndroid Build Coastguard Worker             for (const GLuint &newShaderProgram : newShaderPrograms)
1358*8975f5c5SAndroid Build Coastguard Worker             {
1359*8975f5c5SAndroid Build Coastguard Worker                 if (resourceTracker->getShaderProgramType({newShaderProgram}) ==
1360*8975f5c5SAndroid Build Coastguard Worker                     ShaderProgramType::ShaderType)
1361*8975f5c5SAndroid Build Coastguard Worker                 {
1362*8975f5c5SAndroid Build Coastguard Worker                     out << "    glDeleteShader(gShaderProgramMap[" << newShaderProgram << "]);\n";
1363*8975f5c5SAndroid Build Coastguard Worker                 }
1364*8975f5c5SAndroid Build Coastguard Worker                 else
1365*8975f5c5SAndroid Build Coastguard Worker                 {
1366*8975f5c5SAndroid Build Coastguard Worker                     ASSERT(resourceTracker->getShaderProgramType({newShaderProgram}) ==
1367*8975f5c5SAndroid Build Coastguard Worker                            ShaderProgramType::ProgramType);
1368*8975f5c5SAndroid Build Coastguard Worker                     out << "    glDeleteProgram(gShaderProgramMap[" << newShaderProgram << "]);\n";
1369*8975f5c5SAndroid Build Coastguard Worker                 }
1370*8975f5c5SAndroid Build Coastguard Worker             }
1371*8975f5c5SAndroid Build Coastguard Worker 
1372*8975f5c5SAndroid Build Coastguard Worker             // Do the same for shaders/programs to be deleted
1373*8975f5c5SAndroid Build Coastguard Worker             for (const GLuint &shaderProgramToDelete : shaderProgramsToDelete)
1374*8975f5c5SAndroid Build Coastguard Worker             {
1375*8975f5c5SAndroid Build Coastguard Worker                 if (resourceTracker->getShaderProgramType({shaderProgramToDelete}) ==
1376*8975f5c5SAndroid Build Coastguard Worker                     ShaderProgramType::ShaderType)
1377*8975f5c5SAndroid Build Coastguard Worker                 {
1378*8975f5c5SAndroid Build Coastguard Worker                     out << "    glDeleteShader(gShaderProgramMap[" << shaderProgramToDelete
1379*8975f5c5SAndroid Build Coastguard Worker                         << "]);\n";
1380*8975f5c5SAndroid Build Coastguard Worker                 }
1381*8975f5c5SAndroid Build Coastguard Worker                 else
1382*8975f5c5SAndroid Build Coastguard Worker                 {
1383*8975f5c5SAndroid Build Coastguard Worker                     ASSERT(resourceTracker->getShaderProgramType({shaderProgramToDelete}) ==
1384*8975f5c5SAndroid Build Coastguard Worker                            ShaderProgramType::ProgramType);
1385*8975f5c5SAndroid Build Coastguard Worker                     out << "    glDeleteProgram(gShaderProgramMap[" << shaderProgramToDelete
1386*8975f5c5SAndroid Build Coastguard Worker                         << "]);\n";
1387*8975f5c5SAndroid Build Coastguard Worker                 }
1388*8975f5c5SAndroid Build Coastguard Worker             }
1389*8975f5c5SAndroid Build Coastguard Worker 
1390*8975f5c5SAndroid Build Coastguard Worker             for (const GLuint id : shaderProgramsToRegen)
1391*8975f5c5SAndroid Build Coastguard Worker             {
1392*8975f5c5SAndroid Build Coastguard Worker                 // Emit their regen calls
1393*8975f5c5SAndroid Build Coastguard Worker                 for (CallCapture &call : shaderProgramRegenCalls[id])
1394*8975f5c5SAndroid Build Coastguard Worker                 {
1395*8975f5c5SAndroid Build Coastguard Worker                     out << "    ";
1396*8975f5c5SAndroid Build Coastguard Worker                     WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
1397*8975f5c5SAndroid Build Coastguard Worker                                           maxResourceIDBufferSize);
1398*8975f5c5SAndroid Build Coastguard Worker                     out << ";\n";
1399*8975f5c5SAndroid Build Coastguard Worker                 }
1400*8975f5c5SAndroid Build Coastguard Worker             }
1401*8975f5c5SAndroid Build Coastguard Worker 
1402*8975f5c5SAndroid Build Coastguard Worker             for (const GLuint id : shaderProgramsToRestore)
1403*8975f5c5SAndroid Build Coastguard Worker             {
1404*8975f5c5SAndroid Build Coastguard Worker                 // Emit their restore calls
1405*8975f5c5SAndroid Build Coastguard Worker                 for (CallCapture &call : shaderProgramRestoreCalls[id])
1406*8975f5c5SAndroid Build Coastguard Worker                 {
1407*8975f5c5SAndroid Build Coastguard Worker                     out << "    ";
1408*8975f5c5SAndroid Build Coastguard Worker                     WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
1409*8975f5c5SAndroid Build Coastguard Worker                                           maxResourceIDBufferSize);
1410*8975f5c5SAndroid Build Coastguard Worker                     out << ";\n";
1411*8975f5c5SAndroid Build Coastguard Worker                 }
1412*8975f5c5SAndroid Build Coastguard Worker             }
1413*8975f5c5SAndroid Build Coastguard Worker 
1414*8975f5c5SAndroid Build Coastguard Worker             break;
1415*8975f5c5SAndroid Build Coastguard Worker         }
1416*8975f5c5SAndroid Build Coastguard Worker         case ResourceIDType::Texture:
1417*8975f5c5SAndroid Build Coastguard Worker         {
1418*8975f5c5SAndroid Build Coastguard Worker             TrackedResource &trackedTextures =
1419*8975f5c5SAndroid Build Coastguard Worker                 resourceTracker->getTrackedResource(contextID, ResourceIDType::Texture);
1420*8975f5c5SAndroid Build Coastguard Worker             ResourceSet &newTextures           = trackedTextures.getNewResources();
1421*8975f5c5SAndroid Build Coastguard Worker             ResourceSet &texturesToDelete      = trackedTextures.getResourcesToDelete();
1422*8975f5c5SAndroid Build Coastguard Worker             ResourceSet &texturesToRegen       = trackedTextures.getResourcesToRegen();
1423*8975f5c5SAndroid Build Coastguard Worker             ResourceCalls &textureRegenCalls   = trackedTextures.getResourceRegenCalls();
1424*8975f5c5SAndroid Build Coastguard Worker             ResourceCalls &textureRestoreCalls = trackedTextures.getResourceRestoreCalls();
1425*8975f5c5SAndroid Build Coastguard Worker 
1426*8975f5c5SAndroid Build Coastguard Worker             DeleteResourcesInReset(out, contextID, newTextures, texturesToDelete, resourceIDType,
1427*8975f5c5SAndroid Build Coastguard Worker                                    maxResourceIDBufferSize);
1428*8975f5c5SAndroid Build Coastguard Worker 
1429*8975f5c5SAndroid Build Coastguard Worker             // If any of our starting textures were deleted, regen them
1430*8975f5c5SAndroid Build Coastguard Worker             for (GLuint id : texturesToRegen)
1431*8975f5c5SAndroid Build Coastguard Worker             {
1432*8975f5c5SAndroid Build Coastguard Worker                 // Emit their regen calls
1433*8975f5c5SAndroid Build Coastguard Worker                 for (CallCapture &call : textureRegenCalls[id])
1434*8975f5c5SAndroid Build Coastguard Worker                 {
1435*8975f5c5SAndroid Build Coastguard Worker                     out << "    ";
1436*8975f5c5SAndroid Build Coastguard Worker                     WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
1437*8975f5c5SAndroid Build Coastguard Worker                                           maxResourceIDBufferSize);
1438*8975f5c5SAndroid Build Coastguard Worker                     out << ";\n";
1439*8975f5c5SAndroid Build Coastguard Worker                 }
1440*8975f5c5SAndroid Build Coastguard Worker             }
1441*8975f5c5SAndroid Build Coastguard Worker 
1442*8975f5c5SAndroid Build Coastguard Worker             // If any of our starting textures were modified during the run, restore their contents
1443*8975f5c5SAndroid Build Coastguard Worker             ResourceSet &texturesToRestore = trackedTextures.getResourcesToRestore();
1444*8975f5c5SAndroid Build Coastguard Worker 
1445*8975f5c5SAndroid Build Coastguard Worker             // Do some setup if we have any textures to restore
1446*8975f5c5SAndroid Build Coastguard Worker             if (texturesToRestore.size() != 0)
1447*8975f5c5SAndroid Build Coastguard Worker             {
1448*8975f5c5SAndroid Build Coastguard Worker                 // We need to unbind PIXEL_UNPACK_BUFFER before restoring textures
1449*8975f5c5SAndroid Build Coastguard Worker                 // The correct binding will be restored in context state reset
1450*8975f5c5SAndroid Build Coastguard Worker                 gl::Context *context = display->getContext(contextID);
1451*8975f5c5SAndroid Build Coastguard Worker                 if (context->getState().getTargetBuffer(gl::BufferBinding::PixelUnpack))
1452*8975f5c5SAndroid Build Coastguard Worker                 {
1453*8975f5c5SAndroid Build Coastguard Worker                     out << "    // Clearing PIXEL_UNPACK_BUFFER binding for texture restore\n";
1454*8975f5c5SAndroid Build Coastguard Worker                     out << "    ";
1455*8975f5c5SAndroid Build Coastguard Worker                     WriteCppReplayForCall(CaptureBindBuffer(context->getState(), true,
1456*8975f5c5SAndroid Build Coastguard Worker                                                             gl::BufferBinding::PixelUnpack, {0}),
1457*8975f5c5SAndroid Build Coastguard Worker                                           replayWriter, out, header, binaryData,
1458*8975f5c5SAndroid Build Coastguard Worker                                           maxResourceIDBufferSize);
1459*8975f5c5SAndroid Build Coastguard Worker                     out << ";\n";
1460*8975f5c5SAndroid Build Coastguard Worker                 }
1461*8975f5c5SAndroid Build Coastguard Worker             }
1462*8975f5c5SAndroid Build Coastguard Worker 
1463*8975f5c5SAndroid Build Coastguard Worker             for (GLuint id : texturesToRestore)
1464*8975f5c5SAndroid Build Coastguard Worker             {
1465*8975f5c5SAndroid Build Coastguard Worker                 // Emit their restore calls
1466*8975f5c5SAndroid Build Coastguard Worker                 for (CallCapture &call : textureRestoreCalls[id])
1467*8975f5c5SAndroid Build Coastguard Worker                 {
1468*8975f5c5SAndroid Build Coastguard Worker                     out << "    ";
1469*8975f5c5SAndroid Build Coastguard Worker                     WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
1470*8975f5c5SAndroid Build Coastguard Worker                                           maxResourceIDBufferSize);
1471*8975f5c5SAndroid Build Coastguard Worker                     out << ";\n";
1472*8975f5c5SAndroid Build Coastguard Worker                 }
1473*8975f5c5SAndroid Build Coastguard Worker             }
1474*8975f5c5SAndroid Build Coastguard Worker             break;
1475*8975f5c5SAndroid Build Coastguard Worker         }
1476*8975f5c5SAndroid Build Coastguard Worker         case ResourceIDType::VertexArray:
1477*8975f5c5SAndroid Build Coastguard Worker         {
1478*8975f5c5SAndroid Build Coastguard Worker             TrackedResource &trackedVertexArrays =
1479*8975f5c5SAndroid Build Coastguard Worker                 resourceTracker->getTrackedResource(contextID, ResourceIDType::VertexArray);
1480*8975f5c5SAndroid Build Coastguard Worker             ResourceSet &newVertexArrays           = trackedVertexArrays.getNewResources();
1481*8975f5c5SAndroid Build Coastguard Worker             ResourceSet &vertexArraysToDelete      = trackedVertexArrays.getResourcesToDelete();
1482*8975f5c5SAndroid Build Coastguard Worker             ResourceSet &vertexArraysToRegen       = trackedVertexArrays.getResourcesToRegen();
1483*8975f5c5SAndroid Build Coastguard Worker             ResourceSet &vertexArraysToRestore     = trackedVertexArrays.getResourcesToRestore();
1484*8975f5c5SAndroid Build Coastguard Worker             ResourceCalls &vertexArrayRegenCalls   = trackedVertexArrays.getResourceRegenCalls();
1485*8975f5c5SAndroid Build Coastguard Worker             ResourceCalls &vertexArrayRestoreCalls = trackedVertexArrays.getResourceRestoreCalls();
1486*8975f5c5SAndroid Build Coastguard Worker 
1487*8975f5c5SAndroid Build Coastguard Worker             DeleteResourcesInReset(out, contextID, newVertexArrays, vertexArraysToDelete,
1488*8975f5c5SAndroid Build Coastguard Worker                                    resourceIDType, maxResourceIDBufferSize);
1489*8975f5c5SAndroid Build Coastguard Worker 
1490*8975f5c5SAndroid Build Coastguard Worker             // If any of our starting vertex arrays were deleted during the run, recreate them
1491*8975f5c5SAndroid Build Coastguard Worker             for (GLuint id : vertexArraysToRegen)
1492*8975f5c5SAndroid Build Coastguard Worker             {
1493*8975f5c5SAndroid Build Coastguard Worker                 // Emit their regen calls
1494*8975f5c5SAndroid Build Coastguard Worker                 for (CallCapture &call : vertexArrayRegenCalls[id])
1495*8975f5c5SAndroid Build Coastguard Worker                 {
1496*8975f5c5SAndroid Build Coastguard Worker                     out << "    ";
1497*8975f5c5SAndroid Build Coastguard Worker                     WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
1498*8975f5c5SAndroid Build Coastguard Worker                                           maxResourceIDBufferSize);
1499*8975f5c5SAndroid Build Coastguard Worker                     out << ";\n";
1500*8975f5c5SAndroid Build Coastguard Worker                 }
1501*8975f5c5SAndroid Build Coastguard Worker             }
1502*8975f5c5SAndroid Build Coastguard Worker 
1503*8975f5c5SAndroid Build Coastguard Worker             // If any of our starting vertex arrays were modified during the run, restore their
1504*8975f5c5SAndroid Build Coastguard Worker             // contents
1505*8975f5c5SAndroid Build Coastguard Worker             for (GLuint id : vertexArraysToRestore)
1506*8975f5c5SAndroid Build Coastguard Worker             {
1507*8975f5c5SAndroid Build Coastguard Worker                 // Emit their restore calls
1508*8975f5c5SAndroid Build Coastguard Worker                 for (CallCapture &call : vertexArrayRestoreCalls[id])
1509*8975f5c5SAndroid Build Coastguard Worker                 {
1510*8975f5c5SAndroid Build Coastguard Worker                     out << "    ";
1511*8975f5c5SAndroid Build Coastguard Worker                     WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
1512*8975f5c5SAndroid Build Coastguard Worker                                           maxResourceIDBufferSize);
1513*8975f5c5SAndroid Build Coastguard Worker                     out << ";\n";
1514*8975f5c5SAndroid Build Coastguard Worker                 }
1515*8975f5c5SAndroid Build Coastguard Worker             }
1516*8975f5c5SAndroid Build Coastguard Worker             break;
1517*8975f5c5SAndroid Build Coastguard Worker         }
1518*8975f5c5SAndroid Build Coastguard Worker         case ResourceIDType::egl_Sync:
1519*8975f5c5SAndroid Build Coastguard Worker         {
1520*8975f5c5SAndroid Build Coastguard Worker             TrackedResource &trackedEGLSyncs =
1521*8975f5c5SAndroid Build Coastguard Worker                 resourceTracker->getTrackedResource(contextID, ResourceIDType::egl_Sync);
1522*8975f5c5SAndroid Build Coastguard Worker             ResourceSet &newEGLSyncs         = trackedEGLSyncs.getNewResources();
1523*8975f5c5SAndroid Build Coastguard Worker             ResourceSet &eglSyncsToDelete    = trackedEGLSyncs.getResourcesToDelete();
1524*8975f5c5SAndroid Build Coastguard Worker             ResourceSet &eglSyncsToRegen     = trackedEGLSyncs.getResourcesToRegen();
1525*8975f5c5SAndroid Build Coastguard Worker             ResourceCalls &eglSyncRegenCalls = trackedEGLSyncs.getResourceRegenCalls();
1526*8975f5c5SAndroid Build Coastguard Worker 
1527*8975f5c5SAndroid Build Coastguard Worker             if (!newEGLSyncs.empty() || !eglSyncsToDelete.empty())
1528*8975f5c5SAndroid Build Coastguard Worker             {
1529*8975f5c5SAndroid Build Coastguard Worker                 for (GLuint oldResource : eglSyncsToDelete)
1530*8975f5c5SAndroid Build Coastguard Worker                 {
1531*8975f5c5SAndroid Build Coastguard Worker                     out << "    eglDestroySyncKHR(gEGLDisplay, gEGLSyncMap[" << oldResource
1532*8975f5c5SAndroid Build Coastguard Worker                         << "]);\n";
1533*8975f5c5SAndroid Build Coastguard Worker                 }
1534*8975f5c5SAndroid Build Coastguard Worker 
1535*8975f5c5SAndroid Build Coastguard Worker                 for (GLuint newResource : newEGLSyncs)
1536*8975f5c5SAndroid Build Coastguard Worker                 {
1537*8975f5c5SAndroid Build Coastguard Worker                     out << "    eglDestroySyncKHR(gEGLDisplay, gEGLSyncMap[" << newResource
1538*8975f5c5SAndroid Build Coastguard Worker                         << "]);\n";
1539*8975f5c5SAndroid Build Coastguard Worker                 }
1540*8975f5c5SAndroid Build Coastguard Worker             }
1541*8975f5c5SAndroid Build Coastguard Worker 
1542*8975f5c5SAndroid Build Coastguard Worker             // If any of our starting EGLsyncs were deleted during the run, recreate them
1543*8975f5c5SAndroid Build Coastguard Worker             for (GLuint id : eglSyncsToRegen)
1544*8975f5c5SAndroid Build Coastguard Worker             {
1545*8975f5c5SAndroid Build Coastguard Worker                 // Emit their regen calls
1546*8975f5c5SAndroid Build Coastguard Worker                 for (CallCapture &call : eglSyncRegenCalls[id])
1547*8975f5c5SAndroid Build Coastguard Worker                 {
1548*8975f5c5SAndroid Build Coastguard Worker                     out << "    ";
1549*8975f5c5SAndroid Build Coastguard Worker                     WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
1550*8975f5c5SAndroid Build Coastguard Worker                                           maxResourceIDBufferSize);
1551*8975f5c5SAndroid Build Coastguard Worker                     out << ";\n";
1552*8975f5c5SAndroid Build Coastguard Worker                 }
1553*8975f5c5SAndroid Build Coastguard Worker             }
1554*8975f5c5SAndroid Build Coastguard Worker             break;
1555*8975f5c5SAndroid Build Coastguard Worker         }
1556*8975f5c5SAndroid Build Coastguard Worker         case ResourceIDType::Image:
1557*8975f5c5SAndroid Build Coastguard Worker         {
1558*8975f5c5SAndroid Build Coastguard Worker             TrackedResource &trackedEGLImages =
1559*8975f5c5SAndroid Build Coastguard Worker                 resourceTracker->getTrackedResource(contextID, ResourceIDType::Image);
1560*8975f5c5SAndroid Build Coastguard Worker             ResourceSet &newEGLImages         = trackedEGLImages.getNewResources();
1561*8975f5c5SAndroid Build Coastguard Worker             ResourceSet &eglImagesToDelete    = trackedEGLImages.getResourcesToDelete();
1562*8975f5c5SAndroid Build Coastguard Worker             ResourceSet &eglImagesToRegen     = trackedEGLImages.getResourcesToRegen();
1563*8975f5c5SAndroid Build Coastguard Worker             ResourceCalls &eglImageRegenCalls = trackedEGLImages.getResourceRegenCalls();
1564*8975f5c5SAndroid Build Coastguard Worker 
1565*8975f5c5SAndroid Build Coastguard Worker             if (!newEGLImages.empty() || !eglImagesToDelete.empty())
1566*8975f5c5SAndroid Build Coastguard Worker             {
1567*8975f5c5SAndroid Build Coastguard Worker                 for (GLuint oldResource : eglImagesToDelete)
1568*8975f5c5SAndroid Build Coastguard Worker                 {
1569*8975f5c5SAndroid Build Coastguard Worker                     out << "    DestroyEGLImageKHR(gEGLDisplay, gEGLImageMap2[" << oldResource
1570*8975f5c5SAndroid Build Coastguard Worker                         << "], " << oldResource << ");\n";
1571*8975f5c5SAndroid Build Coastguard Worker                 }
1572*8975f5c5SAndroid Build Coastguard Worker 
1573*8975f5c5SAndroid Build Coastguard Worker                 for (GLuint newResource : newEGLImages)
1574*8975f5c5SAndroid Build Coastguard Worker                 {
1575*8975f5c5SAndroid Build Coastguard Worker                     out << "    DestroyEGLImageKHR(gEGLDisplay, gEGLImageMap2[" << newResource
1576*8975f5c5SAndroid Build Coastguard Worker                         << "], " << newResource << ");\n";
1577*8975f5c5SAndroid Build Coastguard Worker                 }
1578*8975f5c5SAndroid Build Coastguard Worker             }
1579*8975f5c5SAndroid Build Coastguard Worker             // If any of our starting EGLImages were deleted during the run, recreate them
1580*8975f5c5SAndroid Build Coastguard Worker             for (GLuint id : eglImagesToRegen)
1581*8975f5c5SAndroid Build Coastguard Worker             {
1582*8975f5c5SAndroid Build Coastguard Worker                 // Emit their regen calls
1583*8975f5c5SAndroid Build Coastguard Worker                 for (CallCapture &call : eglImageRegenCalls[id])
1584*8975f5c5SAndroid Build Coastguard Worker                 {
1585*8975f5c5SAndroid Build Coastguard Worker                     out << "    ";
1586*8975f5c5SAndroid Build Coastguard Worker                     WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
1587*8975f5c5SAndroid Build Coastguard Worker                                           maxResourceIDBufferSize);
1588*8975f5c5SAndroid Build Coastguard Worker                     out << ";\n";
1589*8975f5c5SAndroid Build Coastguard Worker                 }
1590*8975f5c5SAndroid Build Coastguard Worker             }
1591*8975f5c5SAndroid Build Coastguard Worker             break;
1592*8975f5c5SAndroid Build Coastguard Worker         }
1593*8975f5c5SAndroid Build Coastguard Worker         default:
1594*8975f5c5SAndroid Build Coastguard Worker             // TODO (http://anglebug.com/42263204): Reset more resource types
1595*8975f5c5SAndroid Build Coastguard Worker             break;
1596*8975f5c5SAndroid Build Coastguard Worker     }
1597*8975f5c5SAndroid Build Coastguard Worker 
1598*8975f5c5SAndroid Build Coastguard Worker     // If the output position has moved, we Reset something
1599*8975f5c5SAndroid Build Coastguard Worker     anyResourceReset = (initialOutPos != out.tellp());
1600*8975f5c5SAndroid Build Coastguard Worker }
1601*8975f5c5SAndroid Build Coastguard Worker 
MaybeResetFenceSyncObjects(std::stringstream & out,ReplayWriter & replayWriter,std::stringstream & header,ResourceTracker * resourceTracker,std::vector<uint8_t> * binaryData,size_t * maxResourceIDBufferSize)1602*8975f5c5SAndroid Build Coastguard Worker void MaybeResetFenceSyncObjects(std::stringstream &out,
1603*8975f5c5SAndroid Build Coastguard Worker                                 ReplayWriter &replayWriter,
1604*8975f5c5SAndroid Build Coastguard Worker                                 std::stringstream &header,
1605*8975f5c5SAndroid Build Coastguard Worker                                 ResourceTracker *resourceTracker,
1606*8975f5c5SAndroid Build Coastguard Worker                                 std::vector<uint8_t> *binaryData,
1607*8975f5c5SAndroid Build Coastguard Worker                                 size_t *maxResourceIDBufferSize)
1608*8975f5c5SAndroid Build Coastguard Worker {
1609*8975f5c5SAndroid Build Coastguard Worker     FenceSyncCalls &fenceSyncRegenCalls = resourceTracker->getFenceSyncRegenCalls();
1610*8975f5c5SAndroid Build Coastguard Worker 
1611*8975f5c5SAndroid Build Coastguard Worker     // If any of our starting fence sync objects were deleted during the run, recreate them
1612*8975f5c5SAndroid Build Coastguard Worker     FenceSyncSet &fenceSyncsToRegen = resourceTracker->getFenceSyncsToRegen();
1613*8975f5c5SAndroid Build Coastguard Worker     for (const gl::SyncID syncID : fenceSyncsToRegen)
1614*8975f5c5SAndroid Build Coastguard Worker     {
1615*8975f5c5SAndroid Build Coastguard Worker         // Emit their regen calls
1616*8975f5c5SAndroid Build Coastguard Worker         for (CallCapture &call : fenceSyncRegenCalls[syncID])
1617*8975f5c5SAndroid Build Coastguard Worker         {
1618*8975f5c5SAndroid Build Coastguard Worker             out << "    ";
1619*8975f5c5SAndroid Build Coastguard Worker             WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
1620*8975f5c5SAndroid Build Coastguard Worker                                   maxResourceIDBufferSize);
1621*8975f5c5SAndroid Build Coastguard Worker             out << ";\n";
1622*8975f5c5SAndroid Build Coastguard Worker         }
1623*8975f5c5SAndroid Build Coastguard Worker     }
1624*8975f5c5SAndroid Build Coastguard Worker }
1625*8975f5c5SAndroid Build Coastguard Worker 
Capture(std::vector<CallCapture> * setupCalls,CallCapture && call)1626*8975f5c5SAndroid Build Coastguard Worker void Capture(std::vector<CallCapture> *setupCalls, CallCapture &&call)
1627*8975f5c5SAndroid Build Coastguard Worker {
1628*8975f5c5SAndroid Build Coastguard Worker     setupCalls->emplace_back(std::move(call));
1629*8975f5c5SAndroid Build Coastguard Worker }
1630*8975f5c5SAndroid Build Coastguard Worker 
CaptureUpdateCurrentProgram(const CallCapture & call,int programParamPos,std::vector<CallCapture> * callsOut)1631*8975f5c5SAndroid Build Coastguard Worker void CaptureUpdateCurrentProgram(const CallCapture &call,
1632*8975f5c5SAndroid Build Coastguard Worker                                  int programParamPos,
1633*8975f5c5SAndroid Build Coastguard Worker                                  std::vector<CallCapture> *callsOut)
1634*8975f5c5SAndroid Build Coastguard Worker {
1635*8975f5c5SAndroid Build Coastguard Worker     const ParamCapture &param =
1636*8975f5c5SAndroid Build Coastguard Worker         call.params.getParam("programPacked", ParamType::TShaderProgramID, programParamPos);
1637*8975f5c5SAndroid Build Coastguard Worker     gl::ShaderProgramID programID = param.value.ShaderProgramIDVal;
1638*8975f5c5SAndroid Build Coastguard Worker 
1639*8975f5c5SAndroid Build Coastguard Worker     ParamBuffer paramBuffer;
1640*8975f5c5SAndroid Build Coastguard Worker     paramBuffer.addValueParam("program", ParamType::TGLuint, programID.value);
1641*8975f5c5SAndroid Build Coastguard Worker 
1642*8975f5c5SAndroid Build Coastguard Worker     callsOut->emplace_back("UpdateCurrentProgram", std::move(paramBuffer));
1643*8975f5c5SAndroid Build Coastguard Worker }
1644*8975f5c5SAndroid Build Coastguard Worker 
ProgramNeedsReset(const gl::Context * context,ResourceTracker * resourceTracker,gl::ShaderProgramID programID)1645*8975f5c5SAndroid Build Coastguard Worker bool ProgramNeedsReset(const gl::Context *context,
1646*8975f5c5SAndroid Build Coastguard Worker                        ResourceTracker *resourceTracker,
1647*8975f5c5SAndroid Build Coastguard Worker                        gl::ShaderProgramID programID)
1648*8975f5c5SAndroid Build Coastguard Worker {
1649*8975f5c5SAndroid Build Coastguard Worker     // Check whether the program is listed in programs to regen or restore
1650*8975f5c5SAndroid Build Coastguard Worker     TrackedResource &trackedShaderPrograms =
1651*8975f5c5SAndroid Build Coastguard Worker         resourceTracker->getTrackedResource(context->id(), ResourceIDType::ShaderProgram);
1652*8975f5c5SAndroid Build Coastguard Worker 
1653*8975f5c5SAndroid Build Coastguard Worker     ResourceSet &shaderProgramsToRegen = trackedShaderPrograms.getResourcesToRegen();
1654*8975f5c5SAndroid Build Coastguard Worker     if (shaderProgramsToRegen.count(programID.value) != 0)
1655*8975f5c5SAndroid Build Coastguard Worker     {
1656*8975f5c5SAndroid Build Coastguard Worker         return true;
1657*8975f5c5SAndroid Build Coastguard Worker     }
1658*8975f5c5SAndroid Build Coastguard Worker 
1659*8975f5c5SAndroid Build Coastguard Worker     ResourceSet &shaderProgramsToRestore = trackedShaderPrograms.getResourcesToRestore();
1660*8975f5c5SAndroid Build Coastguard Worker     if (shaderProgramsToRestore.count(programID.value) != 0)
1661*8975f5c5SAndroid Build Coastguard Worker     {
1662*8975f5c5SAndroid Build Coastguard Worker         return true;
1663*8975f5c5SAndroid Build Coastguard Worker     }
1664*8975f5c5SAndroid Build Coastguard Worker 
1665*8975f5c5SAndroid Build Coastguard Worker     // Deferred linked programs will also update their own uniforms
1666*8975f5c5SAndroid Build Coastguard Worker     FrameCaptureShared *frameCaptureShared = context->getShareGroup()->getFrameCaptureShared();
1667*8975f5c5SAndroid Build Coastguard Worker     if (frameCaptureShared->isDeferredLinkProgram(programID))
1668*8975f5c5SAndroid Build Coastguard Worker     {
1669*8975f5c5SAndroid Build Coastguard Worker         return true;
1670*8975f5c5SAndroid Build Coastguard Worker     }
1671*8975f5c5SAndroid Build Coastguard Worker 
1672*8975f5c5SAndroid Build Coastguard Worker     return false;
1673*8975f5c5SAndroid Build Coastguard Worker }
1674*8975f5c5SAndroid Build Coastguard Worker 
MaybeResetDefaultUniforms(std::stringstream & out,ReplayWriter & replayWriter,std::stringstream & header,const gl::Context * context,ResourceTracker * resourceTracker,std::vector<uint8_t> * binaryData,size_t * maxResourceIDBufferSize)1675*8975f5c5SAndroid Build Coastguard Worker void MaybeResetDefaultUniforms(std::stringstream &out,
1676*8975f5c5SAndroid Build Coastguard Worker                                ReplayWriter &replayWriter,
1677*8975f5c5SAndroid Build Coastguard Worker                                std::stringstream &header,
1678*8975f5c5SAndroid Build Coastguard Worker                                const gl::Context *context,
1679*8975f5c5SAndroid Build Coastguard Worker                                ResourceTracker *resourceTracker,
1680*8975f5c5SAndroid Build Coastguard Worker                                std::vector<uint8_t> *binaryData,
1681*8975f5c5SAndroid Build Coastguard Worker                                size_t *maxResourceIDBufferSize)
1682*8975f5c5SAndroid Build Coastguard Worker {
1683*8975f5c5SAndroid Build Coastguard Worker     DefaultUniformLocationsPerProgramMap &defaultUniformsToReset =
1684*8975f5c5SAndroid Build Coastguard Worker         resourceTracker->getDefaultUniformsToReset();
1685*8975f5c5SAndroid Build Coastguard Worker 
1686*8975f5c5SAndroid Build Coastguard Worker     for (const auto &uniformIter : defaultUniformsToReset)
1687*8975f5c5SAndroid Build Coastguard Worker     {
1688*8975f5c5SAndroid Build Coastguard Worker         gl::ShaderProgramID programID               = uniformIter.first;
1689*8975f5c5SAndroid Build Coastguard Worker         const DefaultUniformLocationsSet &locations = uniformIter.second;
1690*8975f5c5SAndroid Build Coastguard Worker 
1691*8975f5c5SAndroid Build Coastguard Worker         if (ProgramNeedsReset(context, resourceTracker, programID))
1692*8975f5c5SAndroid Build Coastguard Worker         {
1693*8975f5c5SAndroid Build Coastguard Worker             // Skip programs marked for reset as they will update their own uniforms
1694*8975f5c5SAndroid Build Coastguard Worker             return;
1695*8975f5c5SAndroid Build Coastguard Worker         }
1696*8975f5c5SAndroid Build Coastguard Worker 
1697*8975f5c5SAndroid Build Coastguard Worker         // Bind the program to update its uniforms
1698*8975f5c5SAndroid Build Coastguard Worker         std::vector<CallCapture> bindCalls;
1699*8975f5c5SAndroid Build Coastguard Worker         Capture(&bindCalls, CaptureUseProgram(context->getState(), true, programID));
1700*8975f5c5SAndroid Build Coastguard Worker         CaptureUpdateCurrentProgram((&bindCalls)->back(), 0, &bindCalls);
1701*8975f5c5SAndroid Build Coastguard Worker         for (CallCapture &call : bindCalls)
1702*8975f5c5SAndroid Build Coastguard Worker         {
1703*8975f5c5SAndroid Build Coastguard Worker             out << "    ";
1704*8975f5c5SAndroid Build Coastguard Worker             WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
1705*8975f5c5SAndroid Build Coastguard Worker                                   maxResourceIDBufferSize);
1706*8975f5c5SAndroid Build Coastguard Worker             out << ";\n";
1707*8975f5c5SAndroid Build Coastguard Worker         }
1708*8975f5c5SAndroid Build Coastguard Worker 
1709*8975f5c5SAndroid Build Coastguard Worker         DefaultUniformCallsPerLocationMap &defaultUniformResetCalls =
1710*8975f5c5SAndroid Build Coastguard Worker             resourceTracker->getDefaultUniformResetCalls(programID);
1711*8975f5c5SAndroid Build Coastguard Worker 
1712*8975f5c5SAndroid Build Coastguard Worker         // Uniform arrays might have been modified in the middle (i.e. location 5 out of 10)
1713*8975f5c5SAndroid Build Coastguard Worker         // We only have Reset calls for the entire array, so emit them once for the entire array
1714*8975f5c5SAndroid Build Coastguard Worker         std::set<gl::UniformLocation> alreadyReset;
1715*8975f5c5SAndroid Build Coastguard Worker 
1716*8975f5c5SAndroid Build Coastguard Worker         // Emit the reset calls per modified location
1717*8975f5c5SAndroid Build Coastguard Worker         for (const gl::UniformLocation &location : locations)
1718*8975f5c5SAndroid Build Coastguard Worker         {
1719*8975f5c5SAndroid Build Coastguard Worker             gl::UniformLocation baseLocation =
1720*8975f5c5SAndroid Build Coastguard Worker                 resourceTracker->getDefaultUniformBaseLocation(programID, location);
1721*8975f5c5SAndroid Build Coastguard Worker             if (alreadyReset.find(baseLocation) != alreadyReset.end())
1722*8975f5c5SAndroid Build Coastguard Worker             {
1723*8975f5c5SAndroid Build Coastguard Worker                 // We've already Reset this array
1724*8975f5c5SAndroid Build Coastguard Worker                 continue;
1725*8975f5c5SAndroid Build Coastguard Worker             }
1726*8975f5c5SAndroid Build Coastguard Worker             alreadyReset.insert(baseLocation);
1727*8975f5c5SAndroid Build Coastguard Worker 
1728*8975f5c5SAndroid Build Coastguard Worker             ASSERT(defaultUniformResetCalls.find(baseLocation) != defaultUniformResetCalls.end());
1729*8975f5c5SAndroid Build Coastguard Worker             std::vector<CallCapture> &callsPerLocation = defaultUniformResetCalls[baseLocation];
1730*8975f5c5SAndroid Build Coastguard Worker 
1731*8975f5c5SAndroid Build Coastguard Worker             for (CallCapture &call : callsPerLocation)
1732*8975f5c5SAndroid Build Coastguard Worker             {
1733*8975f5c5SAndroid Build Coastguard Worker                 out << "    ";
1734*8975f5c5SAndroid Build Coastguard Worker                 WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
1735*8975f5c5SAndroid Build Coastguard Worker                                       maxResourceIDBufferSize);
1736*8975f5c5SAndroid Build Coastguard Worker                 out << ";\n";
1737*8975f5c5SAndroid Build Coastguard Worker             }
1738*8975f5c5SAndroid Build Coastguard Worker         }
1739*8975f5c5SAndroid Build Coastguard Worker     }
1740*8975f5c5SAndroid Build Coastguard Worker }
1741*8975f5c5SAndroid Build Coastguard Worker 
MaybeResetOpaqueTypeObjects(ReplayWriter & replayWriter,std::stringstream & out,std::stringstream & header,const gl::Context * context,ResourceTracker * resourceTracker,std::vector<uint8_t> * binaryData,size_t * maxResourceIDBufferSize)1742*8975f5c5SAndroid Build Coastguard Worker void MaybeResetOpaqueTypeObjects(ReplayWriter &replayWriter,
1743*8975f5c5SAndroid Build Coastguard Worker                                  std::stringstream &out,
1744*8975f5c5SAndroid Build Coastguard Worker                                  std::stringstream &header,
1745*8975f5c5SAndroid Build Coastguard Worker                                  const gl::Context *context,
1746*8975f5c5SAndroid Build Coastguard Worker                                  ResourceTracker *resourceTracker,
1747*8975f5c5SAndroid Build Coastguard Worker                                  std::vector<uint8_t> *binaryData,
1748*8975f5c5SAndroid Build Coastguard Worker                                  size_t *maxResourceIDBufferSize)
1749*8975f5c5SAndroid Build Coastguard Worker {
1750*8975f5c5SAndroid Build Coastguard Worker     MaybeResetFenceSyncObjects(out, replayWriter, header, resourceTracker, binaryData,
1751*8975f5c5SAndroid Build Coastguard Worker                                maxResourceIDBufferSize);
1752*8975f5c5SAndroid Build Coastguard Worker 
1753*8975f5c5SAndroid Build Coastguard Worker     MaybeResetDefaultUniforms(out, replayWriter, header, context, resourceTracker, binaryData,
1754*8975f5c5SAndroid Build Coastguard Worker                               maxResourceIDBufferSize);
1755*8975f5c5SAndroid Build Coastguard Worker }
1756*8975f5c5SAndroid Build Coastguard Worker 
MaybeResetContextState(ReplayWriter & replayWriter,std::stringstream & out,std::stringstream & header,ResourceTracker * resourceTracker,const gl::Context * context,std::vector<uint8_t> * binaryData,StateResetHelper & stateResetHelper,size_t * maxResourceIDBufferSize)1757*8975f5c5SAndroid Build Coastguard Worker void MaybeResetContextState(ReplayWriter &replayWriter,
1758*8975f5c5SAndroid Build Coastguard Worker                             std::stringstream &out,
1759*8975f5c5SAndroid Build Coastguard Worker                             std::stringstream &header,
1760*8975f5c5SAndroid Build Coastguard Worker                             ResourceTracker *resourceTracker,
1761*8975f5c5SAndroid Build Coastguard Worker                             const gl::Context *context,
1762*8975f5c5SAndroid Build Coastguard Worker                             std::vector<uint8_t> *binaryData,
1763*8975f5c5SAndroid Build Coastguard Worker                             StateResetHelper &stateResetHelper,
1764*8975f5c5SAndroid Build Coastguard Worker                             size_t *maxResourceIDBufferSize)
1765*8975f5c5SAndroid Build Coastguard Worker {
1766*8975f5c5SAndroid Build Coastguard Worker     // Check dirty states per entrypoint
1767*8975f5c5SAndroid Build Coastguard Worker     for (const EntryPoint &entryPoint : stateResetHelper.getDirtyEntryPoints())
1768*8975f5c5SAndroid Build Coastguard Worker     {
1769*8975f5c5SAndroid Build Coastguard Worker         const CallResetMap *resetCalls = &stateResetHelper.getResetCalls();
1770*8975f5c5SAndroid Build Coastguard Worker 
1771*8975f5c5SAndroid Build Coastguard Worker         // Create the default reset call for this entrypoint
1772*8975f5c5SAndroid Build Coastguard Worker         if (resetCalls->find(entryPoint) == resetCalls->end())
1773*8975f5c5SAndroid Build Coastguard Worker         {
1774*8975f5c5SAndroid Build Coastguard Worker             // If we don't have any reset calls for these entrypoints, that means we started capture
1775*8975f5c5SAndroid Build Coastguard Worker             // from the beginning, amd mid-execution capture was not invoked.
1776*8975f5c5SAndroid Build Coastguard Worker             stateResetHelper.setDefaultResetCalls(context, entryPoint);
1777*8975f5c5SAndroid Build Coastguard Worker         }
1778*8975f5c5SAndroid Build Coastguard Worker 
1779*8975f5c5SAndroid Build Coastguard Worker         // Emit the calls, if we added any
1780*8975f5c5SAndroid Build Coastguard Worker         if (resetCalls->find(entryPoint) != resetCalls->end())
1781*8975f5c5SAndroid Build Coastguard Worker         {
1782*8975f5c5SAndroid Build Coastguard Worker             for (const auto &call : resetCalls->at(entryPoint))
1783*8975f5c5SAndroid Build Coastguard Worker             {
1784*8975f5c5SAndroid Build Coastguard Worker                 out << "    ";
1785*8975f5c5SAndroid Build Coastguard Worker                 WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
1786*8975f5c5SAndroid Build Coastguard Worker                                       maxResourceIDBufferSize);
1787*8975f5c5SAndroid Build Coastguard Worker                 out << ";\n";
1788*8975f5c5SAndroid Build Coastguard Worker             }
1789*8975f5c5SAndroid Build Coastguard Worker         }
1790*8975f5c5SAndroid Build Coastguard Worker     }
1791*8975f5c5SAndroid Build Coastguard Worker 
1792*8975f5c5SAndroid Build Coastguard Worker     // Reset buffer bindings that weren't bound at the beginning
1793*8975f5c5SAndroid Build Coastguard Worker     for (const gl::BufferBinding &dirtyBufferBinding : stateResetHelper.getDirtyBufferBindings())
1794*8975f5c5SAndroid Build Coastguard Worker     {
1795*8975f5c5SAndroid Build Coastguard Worker         // Check to see if dirty binding was part of starting set
1796*8975f5c5SAndroid Build Coastguard Worker         bool dirtyStartingBinding = false;
1797*8975f5c5SAndroid Build Coastguard Worker         for (const BufferBindingPair &startingBufferBinding :
1798*8975f5c5SAndroid Build Coastguard Worker              stateResetHelper.getStartingBufferBindings())
1799*8975f5c5SAndroid Build Coastguard Worker         {
1800*8975f5c5SAndroid Build Coastguard Worker             gl::BufferBinding startingBinding = startingBufferBinding.first;
1801*8975f5c5SAndroid Build Coastguard Worker             if (startingBinding == dirtyBufferBinding)
1802*8975f5c5SAndroid Build Coastguard Worker             {
1803*8975f5c5SAndroid Build Coastguard Worker                 dirtyStartingBinding = true;
1804*8975f5c5SAndroid Build Coastguard Worker             }
1805*8975f5c5SAndroid Build Coastguard Worker         }
1806*8975f5c5SAndroid Build Coastguard Worker 
1807*8975f5c5SAndroid Build Coastguard Worker         // If the dirty binding was not part of starting bindings, clear it
1808*8975f5c5SAndroid Build Coastguard Worker         if (!dirtyStartingBinding)
1809*8975f5c5SAndroid Build Coastguard Worker         {
1810*8975f5c5SAndroid Build Coastguard Worker             out << "    ";
1811*8975f5c5SAndroid Build Coastguard Worker             WriteCppReplayForCall(
1812*8975f5c5SAndroid Build Coastguard Worker                 CaptureBindBuffer(context->getState(), true, dirtyBufferBinding, {0}), replayWriter,
1813*8975f5c5SAndroid Build Coastguard Worker                 out, header, binaryData, maxResourceIDBufferSize);
1814*8975f5c5SAndroid Build Coastguard Worker             out << ";\n";
1815*8975f5c5SAndroid Build Coastguard Worker         }
1816*8975f5c5SAndroid Build Coastguard Worker     }
1817*8975f5c5SAndroid Build Coastguard Worker 
1818*8975f5c5SAndroid Build Coastguard Worker     // Restore starting buffer bindings to initial state
1819*8975f5c5SAndroid Build Coastguard Worker     std::vector<CallCapture> &bufferBindingCalls = resourceTracker->getBufferBindingCalls();
1820*8975f5c5SAndroid Build Coastguard Worker     for (CallCapture &call : bufferBindingCalls)
1821*8975f5c5SAndroid Build Coastguard Worker     {
1822*8975f5c5SAndroid Build Coastguard Worker         out << "    ";
1823*8975f5c5SAndroid Build Coastguard Worker         WriteCppReplayForCall(call, replayWriter, out, header, binaryData, maxResourceIDBufferSize);
1824*8975f5c5SAndroid Build Coastguard Worker         out << ";\n";
1825*8975f5c5SAndroid Build Coastguard Worker     }
1826*8975f5c5SAndroid Build Coastguard Worker 
1827*8975f5c5SAndroid Build Coastguard Worker     // Restore texture bindings to initial state
1828*8975f5c5SAndroid Build Coastguard Worker     size_t activeTexture                 = context->getState().getActiveSampler();
1829*8975f5c5SAndroid Build Coastguard Worker     const TextureResetMap &resetBindings = stateResetHelper.getResetTextureBindings();
1830*8975f5c5SAndroid Build Coastguard Worker     for (const auto &textureBinding : stateResetHelper.getDirtyTextureBindings())
1831*8975f5c5SAndroid Build Coastguard Worker     {
1832*8975f5c5SAndroid Build Coastguard Worker         TextureResetMap::const_iterator id = resetBindings.find(textureBinding);
1833*8975f5c5SAndroid Build Coastguard Worker         if (id != resetBindings.end())
1834*8975f5c5SAndroid Build Coastguard Worker         {
1835*8975f5c5SAndroid Build Coastguard Worker             const auto &[unit, target] = textureBinding;
1836*8975f5c5SAndroid Build Coastguard Worker 
1837*8975f5c5SAndroid Build Coastguard Worker             // Set active texture unit if necessary
1838*8975f5c5SAndroid Build Coastguard Worker             if (unit != activeTexture)
1839*8975f5c5SAndroid Build Coastguard Worker             {
1840*8975f5c5SAndroid Build Coastguard Worker                 out << "    ";
1841*8975f5c5SAndroid Build Coastguard Worker                 WriteCppReplayForCall(CaptureActiveTexture(context->getState(), true,
1842*8975f5c5SAndroid Build Coastguard Worker                                                            GL_TEXTURE0 + static_cast<GLenum>(unit)),
1843*8975f5c5SAndroid Build Coastguard Worker                                       replayWriter, out, header, binaryData,
1844*8975f5c5SAndroid Build Coastguard Worker                                       maxResourceIDBufferSize);
1845*8975f5c5SAndroid Build Coastguard Worker                 out << ";\n";
1846*8975f5c5SAndroid Build Coastguard Worker                 activeTexture = unit;
1847*8975f5c5SAndroid Build Coastguard Worker             }
1848*8975f5c5SAndroid Build Coastguard Worker 
1849*8975f5c5SAndroid Build Coastguard Worker             // Bind texture for this target
1850*8975f5c5SAndroid Build Coastguard Worker             out << "    ";
1851*8975f5c5SAndroid Build Coastguard Worker             WriteCppReplayForCall(CaptureBindTexture(context->getState(), true, target, id->second),
1852*8975f5c5SAndroid Build Coastguard Worker                                   replayWriter, out, header, binaryData, maxResourceIDBufferSize);
1853*8975f5c5SAndroid Build Coastguard Worker             out << ";\n";
1854*8975f5c5SAndroid Build Coastguard Worker         }
1855*8975f5c5SAndroid Build Coastguard Worker     }
1856*8975f5c5SAndroid Build Coastguard Worker 
1857*8975f5c5SAndroid Build Coastguard Worker     // Restore active texture unit to initial state if necessary
1858*8975f5c5SAndroid Build Coastguard Worker     if (activeTexture != stateResetHelper.getResetActiveTexture())
1859*8975f5c5SAndroid Build Coastguard Worker     {
1860*8975f5c5SAndroid Build Coastguard Worker         out << "    ";
1861*8975f5c5SAndroid Build Coastguard Worker         WriteCppReplayForCall(
1862*8975f5c5SAndroid Build Coastguard Worker             CaptureActiveTexture(
1863*8975f5c5SAndroid Build Coastguard Worker                 context->getState(), true,
1864*8975f5c5SAndroid Build Coastguard Worker                 GL_TEXTURE0 + static_cast<GLenum>(stateResetHelper.getResetActiveTexture())),
1865*8975f5c5SAndroid Build Coastguard Worker             replayWriter, out, header, binaryData, maxResourceIDBufferSize);
1866*8975f5c5SAndroid Build Coastguard Worker         out << ";\n";
1867*8975f5c5SAndroid Build Coastguard Worker     }
1868*8975f5c5SAndroid Build Coastguard Worker }
1869*8975f5c5SAndroid Build Coastguard Worker 
MarkResourceIDActive(ResourceIDType resourceType,GLuint id,std::vector<CallCapture> * setupCalls,const ResourceIDToSetupCallsMap * resourceIDToSetupCallsMap)1870*8975f5c5SAndroid Build Coastguard Worker void MarkResourceIDActive(ResourceIDType resourceType,
1871*8975f5c5SAndroid Build Coastguard Worker                           GLuint id,
1872*8975f5c5SAndroid Build Coastguard Worker                           std::vector<CallCapture> *setupCalls,
1873*8975f5c5SAndroid Build Coastguard Worker                           const ResourceIDToSetupCallsMap *resourceIDToSetupCallsMap)
1874*8975f5c5SAndroid Build Coastguard Worker {
1875*8975f5c5SAndroid Build Coastguard Worker     const std::map<GLuint, gl::Range<size_t>> &resourceSetupCalls =
1876*8975f5c5SAndroid Build Coastguard Worker         (*resourceIDToSetupCallsMap)[resourceType];
1877*8975f5c5SAndroid Build Coastguard Worker     const auto iter = resourceSetupCalls.find(id);
1878*8975f5c5SAndroid Build Coastguard Worker     if (iter == resourceSetupCalls.end())
1879*8975f5c5SAndroid Build Coastguard Worker     {
1880*8975f5c5SAndroid Build Coastguard Worker         return;
1881*8975f5c5SAndroid Build Coastguard Worker     }
1882*8975f5c5SAndroid Build Coastguard Worker 
1883*8975f5c5SAndroid Build Coastguard Worker     // Mark all of the calls that were used to initialize this resource as ACTIVE
1884*8975f5c5SAndroid Build Coastguard Worker     const gl::Range<size_t> &calls = iter->second;
1885*8975f5c5SAndroid Build Coastguard Worker     for (size_t index : calls)
1886*8975f5c5SAndroid Build Coastguard Worker     {
1887*8975f5c5SAndroid Build Coastguard Worker         (*setupCalls)[index].isActive = true;
1888*8975f5c5SAndroid Build Coastguard Worker     }
1889*8975f5c5SAndroid Build Coastguard Worker }
1890*8975f5c5SAndroid Build Coastguard Worker 
1891*8975f5c5SAndroid Build Coastguard Worker // Some replay functions can get quite large. If over a certain size, this method breaks up the
1892*8975f5c5SAndroid Build Coastguard Worker // function into parts to avoid overflowing the stack and causing slow compilation.
WriteCppReplayFunctionWithParts(const gl::ContextID contextID,ReplayFunc replayFunc,ReplayWriter & replayWriter,uint32_t frameIndex,std::vector<uint8_t> * binaryData,const std::vector<CallCapture> & calls,std::stringstream & header,std::stringstream & out,size_t * maxResourceIDBufferSize)1893*8975f5c5SAndroid Build Coastguard Worker void WriteCppReplayFunctionWithParts(const gl::ContextID contextID,
1894*8975f5c5SAndroid Build Coastguard Worker                                      ReplayFunc replayFunc,
1895*8975f5c5SAndroid Build Coastguard Worker                                      ReplayWriter &replayWriter,
1896*8975f5c5SAndroid Build Coastguard Worker                                      uint32_t frameIndex,
1897*8975f5c5SAndroid Build Coastguard Worker                                      std::vector<uint8_t> *binaryData,
1898*8975f5c5SAndroid Build Coastguard Worker                                      const std::vector<CallCapture> &calls,
1899*8975f5c5SAndroid Build Coastguard Worker                                      std::stringstream &header,
1900*8975f5c5SAndroid Build Coastguard Worker                                      std::stringstream &out,
1901*8975f5c5SAndroid Build Coastguard Worker                                      size_t *maxResourceIDBufferSize)
1902*8975f5c5SAndroid Build Coastguard Worker {
1903*8975f5c5SAndroid Build Coastguard Worker     int callCount = 0;
1904*8975f5c5SAndroid Build Coastguard Worker     int partCount = 0;
1905*8975f5c5SAndroid Build Coastguard Worker 
1906*8975f5c5SAndroid Build Coastguard Worker     if (calls.size() > kFunctionSizeLimit)
1907*8975f5c5SAndroid Build Coastguard Worker     {
1908*8975f5c5SAndroid Build Coastguard Worker         out << "void "
1909*8975f5c5SAndroid Build Coastguard Worker             << FmtFunction(replayFunc, contextID, FuncUsage::Definition, frameIndex, ++partCount)
1910*8975f5c5SAndroid Build Coastguard Worker             << "\n";
1911*8975f5c5SAndroid Build Coastguard Worker     }
1912*8975f5c5SAndroid Build Coastguard Worker     else
1913*8975f5c5SAndroid Build Coastguard Worker     {
1914*8975f5c5SAndroid Build Coastguard Worker         out << "void "
1915*8975f5c5SAndroid Build Coastguard Worker             << FmtFunction(replayFunc, contextID, FuncUsage::Definition, frameIndex, kNoPartId)
1916*8975f5c5SAndroid Build Coastguard Worker             << "\n";
1917*8975f5c5SAndroid Build Coastguard Worker     }
1918*8975f5c5SAndroid Build Coastguard Worker 
1919*8975f5c5SAndroid Build Coastguard Worker     out << "{\n";
1920*8975f5c5SAndroid Build Coastguard Worker 
1921*8975f5c5SAndroid Build Coastguard Worker     for (const CallCapture &call : calls)
1922*8975f5c5SAndroid Build Coastguard Worker     {
1923*8975f5c5SAndroid Build Coastguard Worker         // Process active calls for Setup and inactive calls for SetupInactive
1924*8975f5c5SAndroid Build Coastguard Worker         if ((call.isActive && replayFunc != ReplayFunc::SetupInactive) ||
1925*8975f5c5SAndroid Build Coastguard Worker             (!call.isActive && replayFunc == ReplayFunc::SetupInactive))
1926*8975f5c5SAndroid Build Coastguard Worker         {
1927*8975f5c5SAndroid Build Coastguard Worker             out << "    ";
1928*8975f5c5SAndroid Build Coastguard Worker             WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
1929*8975f5c5SAndroid Build Coastguard Worker                                   maxResourceIDBufferSize);
1930*8975f5c5SAndroid Build Coastguard Worker             out << ";\n";
1931*8975f5c5SAndroid Build Coastguard Worker 
1932*8975f5c5SAndroid Build Coastguard Worker             if (partCount > 0 && ++callCount % kFunctionSizeLimit == 0)
1933*8975f5c5SAndroid Build Coastguard Worker             {
1934*8975f5c5SAndroid Build Coastguard Worker                 out << "}\n";
1935*8975f5c5SAndroid Build Coastguard Worker                 out << "\n";
1936*8975f5c5SAndroid Build Coastguard Worker                 out << "void "
1937*8975f5c5SAndroid Build Coastguard Worker                     << FmtFunction(replayFunc, contextID, FuncUsage::Definition, frameIndex,
1938*8975f5c5SAndroid Build Coastguard Worker                                    ++partCount)
1939*8975f5c5SAndroid Build Coastguard Worker                     << "\n";
1940*8975f5c5SAndroid Build Coastguard Worker                 out << "{\n";
1941*8975f5c5SAndroid Build Coastguard Worker             }
1942*8975f5c5SAndroid Build Coastguard Worker         }
1943*8975f5c5SAndroid Build Coastguard Worker     }
1944*8975f5c5SAndroid Build Coastguard Worker     out << "}\n";
1945*8975f5c5SAndroid Build Coastguard Worker 
1946*8975f5c5SAndroid Build Coastguard Worker     if (partCount > 0)
1947*8975f5c5SAndroid Build Coastguard Worker     {
1948*8975f5c5SAndroid Build Coastguard Worker         out << "\n";
1949*8975f5c5SAndroid Build Coastguard Worker         out << "void "
1950*8975f5c5SAndroid Build Coastguard Worker             << FmtFunction(replayFunc, contextID, FuncUsage::Definition, frameIndex, kNoPartId)
1951*8975f5c5SAndroid Build Coastguard Worker             << "\n";
1952*8975f5c5SAndroid Build Coastguard Worker         out << "{\n";
1953*8975f5c5SAndroid Build Coastguard Worker 
1954*8975f5c5SAndroid Build Coastguard Worker         // Write out the main call which calls all the parts.
1955*8975f5c5SAndroid Build Coastguard Worker         for (int i = 1; i <= partCount; i++)
1956*8975f5c5SAndroid Build Coastguard Worker         {
1957*8975f5c5SAndroid Build Coastguard Worker             out << "    " << FmtFunction(replayFunc, contextID, FuncUsage::Call, frameIndex, i)
1958*8975f5c5SAndroid Build Coastguard Worker                 << ";\n";
1959*8975f5c5SAndroid Build Coastguard Worker         }
1960*8975f5c5SAndroid Build Coastguard Worker 
1961*8975f5c5SAndroid Build Coastguard Worker         out << "}\n";
1962*8975f5c5SAndroid Build Coastguard Worker     }
1963*8975f5c5SAndroid Build Coastguard Worker }
1964*8975f5c5SAndroid Build Coastguard Worker 
1965*8975f5c5SAndroid Build Coastguard Worker // Performance can be gained by reordering traced calls and grouping them by context.
1966*8975f5c5SAndroid Build Coastguard Worker // Side context calls (as opposed to main context) can be grouped together paying attention
1967*8975f5c5SAndroid Build Coastguard Worker // to synchronization points in the original call stream.
WriteCppReplayFunctionWithPartsMultiContext(const gl::ContextID contextID,ReplayFunc replayFunc,ReplayWriter & replayWriter,uint32_t frameIndex,std::vector<uint8_t> * binaryData,std::vector<CallCapture> & calls,std::stringstream & header,std::stringstream & out,size_t * maxResourceIDBufferSize)1968*8975f5c5SAndroid Build Coastguard Worker void WriteCppReplayFunctionWithPartsMultiContext(const gl::ContextID contextID,
1969*8975f5c5SAndroid Build Coastguard Worker                                                  ReplayFunc replayFunc,
1970*8975f5c5SAndroid Build Coastguard Worker                                                  ReplayWriter &replayWriter,
1971*8975f5c5SAndroid Build Coastguard Worker                                                  uint32_t frameIndex,
1972*8975f5c5SAndroid Build Coastguard Worker                                                  std::vector<uint8_t> *binaryData,
1973*8975f5c5SAndroid Build Coastguard Worker                                                  std::vector<CallCapture> &calls,
1974*8975f5c5SAndroid Build Coastguard Worker                                                  std::stringstream &header,
1975*8975f5c5SAndroid Build Coastguard Worker                                                  std::stringstream &out,
1976*8975f5c5SAndroid Build Coastguard Worker                                                  size_t *maxResourceIDBufferSize)
1977*8975f5c5SAndroid Build Coastguard Worker {
1978*8975f5c5SAndroid Build Coastguard Worker     int callCount = 0;
1979*8975f5c5SAndroid Build Coastguard Worker     int partCount = 0;
1980*8975f5c5SAndroid Build Coastguard Worker 
1981*8975f5c5SAndroid Build Coastguard Worker     if (calls.size() > kFunctionSizeLimit)
1982*8975f5c5SAndroid Build Coastguard Worker     {
1983*8975f5c5SAndroid Build Coastguard Worker         out << "void "
1984*8975f5c5SAndroid Build Coastguard Worker             << FmtFunction(replayFunc, contextID, FuncUsage::Definition, frameIndex, ++partCount)
1985*8975f5c5SAndroid Build Coastguard Worker             << "\n";
1986*8975f5c5SAndroid Build Coastguard Worker     }
1987*8975f5c5SAndroid Build Coastguard Worker     else
1988*8975f5c5SAndroid Build Coastguard Worker     {
1989*8975f5c5SAndroid Build Coastguard Worker         out << "void "
1990*8975f5c5SAndroid Build Coastguard Worker             << FmtFunction(replayFunc, contextID, FuncUsage::Definition, frameIndex, kNoPartId)
1991*8975f5c5SAndroid Build Coastguard Worker             << "\n";
1992*8975f5c5SAndroid Build Coastguard Worker     }
1993*8975f5c5SAndroid Build Coastguard Worker 
1994*8975f5c5SAndroid Build Coastguard Worker     out << "{\n";
1995*8975f5c5SAndroid Build Coastguard Worker 
1996*8975f5c5SAndroid Build Coastguard Worker     std::map<gl::ContextID, std::queue<int>> sideContextCallIndices;
1997*8975f5c5SAndroid Build Coastguard Worker 
1998*8975f5c5SAndroid Build Coastguard Worker     // Helper lambda to write a context change command to the call stream
1999*8975f5c5SAndroid Build Coastguard Worker     auto writeMakeCurrentCall = [&](gl::ContextID cID) {
2000*8975f5c5SAndroid Build Coastguard Worker         CallCapture makeCurrentCall =
2001*8975f5c5SAndroid Build Coastguard Worker             egl::CaptureMakeCurrent(nullptr, true, nullptr, {0}, {0}, cID, EGL_TRUE);
2002*8975f5c5SAndroid Build Coastguard Worker         out << "    ";
2003*8975f5c5SAndroid Build Coastguard Worker         WriteCppReplayForCall(makeCurrentCall, replayWriter, out, header, binaryData,
2004*8975f5c5SAndroid Build Coastguard Worker                               maxResourceIDBufferSize);
2005*8975f5c5SAndroid Build Coastguard Worker         out << ";\n";
2006*8975f5c5SAndroid Build Coastguard Worker         callCount++;
2007*8975f5c5SAndroid Build Coastguard Worker     };
2008*8975f5c5SAndroid Build Coastguard Worker 
2009*8975f5c5SAndroid Build Coastguard Worker     // Helper lambda to write a call to the call stream
2010*8975f5c5SAndroid Build Coastguard Worker     auto writeCall = [&](CallCapture &outCall, gl::ContextID cID) {
2011*8975f5c5SAndroid Build Coastguard Worker         out << "    ";
2012*8975f5c5SAndroid Build Coastguard Worker         WriteCppReplayForCall(outCall, replayWriter, out, header, binaryData,
2013*8975f5c5SAndroid Build Coastguard Worker                               maxResourceIDBufferSize);
2014*8975f5c5SAndroid Build Coastguard Worker         out << ";\n";
2015*8975f5c5SAndroid Build Coastguard Worker         if (cID != contextID)
2016*8975f5c5SAndroid Build Coastguard Worker         {
2017*8975f5c5SAndroid Build Coastguard Worker             sideContextCallIndices[cID].pop();
2018*8975f5c5SAndroid Build Coastguard Worker         }
2019*8975f5c5SAndroid Build Coastguard Worker         callCount++;
2020*8975f5c5SAndroid Build Coastguard Worker     };
2021*8975f5c5SAndroid Build Coastguard Worker 
2022*8975f5c5SAndroid Build Coastguard Worker     int callIndex = 0;
2023*8975f5c5SAndroid Build Coastguard Worker     // Iterate through calls saving side context call indices in a per-side-context queue
2024*8975f5c5SAndroid Build Coastguard Worker     for (CallCapture &call : calls)
2025*8975f5c5SAndroid Build Coastguard Worker     {
2026*8975f5c5SAndroid Build Coastguard Worker         if (call.contextID != contextID)
2027*8975f5c5SAndroid Build Coastguard Worker         {
2028*8975f5c5SAndroid Build Coastguard Worker             sideContextCallIndices[call.contextID].push(callIndex);
2029*8975f5c5SAndroid Build Coastguard Worker         }
2030*8975f5c5SAndroid Build Coastguard Worker         callIndex++;
2031*8975f5c5SAndroid Build Coastguard Worker     }
2032*8975f5c5SAndroid Build Coastguard Worker 
2033*8975f5c5SAndroid Build Coastguard Worker     // At the beginning of the frame, output all side context calls occuring before a sync point.
2034*8975f5c5SAndroid Build Coastguard Worker     // If no sync points are present, all calls in that side context are written at this time
2035*8975f5c5SAndroid Build Coastguard Worker     for (auto const &sideContext : sideContextCallIndices)
2036*8975f5c5SAndroid Build Coastguard Worker     {
2037*8975f5c5SAndroid Build Coastguard Worker         gl::ContextID sideContextID = sideContext.first;
2038*8975f5c5SAndroid Build Coastguard Worker 
2039*8975f5c5SAndroid Build Coastguard Worker         // Make sidecontext current if there are commands before the first syncpoint
2040*8975f5c5SAndroid Build Coastguard Worker         if (!calls[sideContextCallIndices[sideContextID].front()].isSyncPoint)
2041*8975f5c5SAndroid Build Coastguard Worker         {
2042*8975f5c5SAndroid Build Coastguard Worker             writeMakeCurrentCall(sideContextID);
2043*8975f5c5SAndroid Build Coastguard Worker         }
2044*8975f5c5SAndroid Build Coastguard Worker         // Output all commands in sidecontext until a syncpoint is reached
2045*8975f5c5SAndroid Build Coastguard Worker         while (!sideContextCallIndices[sideContextID].empty() &&
2046*8975f5c5SAndroid Build Coastguard Worker                !calls[sideContextCallIndices[sideContextID].front()].isSyncPoint)
2047*8975f5c5SAndroid Build Coastguard Worker         {
2048*8975f5c5SAndroid Build Coastguard Worker             writeCall(calls[sideContextCallIndices[sideContextID].front()], sideContextID);
2049*8975f5c5SAndroid Build Coastguard Worker         }
2050*8975f5c5SAndroid Build Coastguard Worker     }
2051*8975f5c5SAndroid Build Coastguard Worker 
2052*8975f5c5SAndroid Build Coastguard Worker     // Make mainContext current
2053*8975f5c5SAndroid Build Coastguard Worker     writeMakeCurrentCall(contextID);
2054*8975f5c5SAndroid Build Coastguard Worker 
2055*8975f5c5SAndroid Build Coastguard Worker     // Iterate through calls writing out main context calls. When a sync point is reached, write the
2056*8975f5c5SAndroid Build Coastguard Worker     // next queued sequence of side context calls until another sync point is reached.
2057*8975f5c5SAndroid Build Coastguard Worker     for (CallCapture &call : calls)
2058*8975f5c5SAndroid Build Coastguard Worker     {
2059*8975f5c5SAndroid Build Coastguard Worker         if (call.contextID == contextID)
2060*8975f5c5SAndroid Build Coastguard Worker         {
2061*8975f5c5SAndroid Build Coastguard Worker             writeCall(call, call.contextID);
2062*8975f5c5SAndroid Build Coastguard Worker         }
2063*8975f5c5SAndroid Build Coastguard Worker         else
2064*8975f5c5SAndroid Build Coastguard Worker         {
2065*8975f5c5SAndroid Build Coastguard Worker             if (call.isSyncPoint)
2066*8975f5c5SAndroid Build Coastguard Worker             {
2067*8975f5c5SAndroid Build Coastguard Worker                 // Make sideContext current
2068*8975f5c5SAndroid Build Coastguard Worker                 writeMakeCurrentCall(call.contextID);
2069*8975f5c5SAndroid Build Coastguard Worker 
2070*8975f5c5SAndroid Build Coastguard Worker                 do
2071*8975f5c5SAndroid Build Coastguard Worker                 {
2072*8975f5c5SAndroid Build Coastguard Worker                     writeCall(calls[sideContextCallIndices[call.contextID].front()],
2073*8975f5c5SAndroid Build Coastguard Worker                               call.contextID);
2074*8975f5c5SAndroid Build Coastguard Worker                 } while (!sideContextCallIndices[call.contextID].empty() &&
2075*8975f5c5SAndroid Build Coastguard Worker                          !calls[sideContextCallIndices[call.contextID].front()].isSyncPoint);
2076*8975f5c5SAndroid Build Coastguard Worker 
2077*8975f5c5SAndroid Build Coastguard Worker                 // Make mainContext current
2078*8975f5c5SAndroid Build Coastguard Worker                 writeMakeCurrentCall(contextID);
2079*8975f5c5SAndroid Build Coastguard Worker 
2080*8975f5c5SAndroid Build Coastguard Worker                 if (partCount > 0 && ++callCount % kFunctionSizeLimit == 0)
2081*8975f5c5SAndroid Build Coastguard Worker                 {
2082*8975f5c5SAndroid Build Coastguard Worker                     out << "}\n";
2083*8975f5c5SAndroid Build Coastguard Worker                     out << "\n";
2084*8975f5c5SAndroid Build Coastguard Worker                     out << "void "
2085*8975f5c5SAndroid Build Coastguard Worker                         << FmtFunction(replayFunc, contextID, FuncUsage::Definition, frameIndex,
2086*8975f5c5SAndroid Build Coastguard Worker                                        ++partCount)
2087*8975f5c5SAndroid Build Coastguard Worker                         << "\n";
2088*8975f5c5SAndroid Build Coastguard Worker                     out << "{\n";
2089*8975f5c5SAndroid Build Coastguard Worker                 }
2090*8975f5c5SAndroid Build Coastguard Worker             }
2091*8975f5c5SAndroid Build Coastguard Worker         }
2092*8975f5c5SAndroid Build Coastguard Worker     }
2093*8975f5c5SAndroid Build Coastguard Worker     out << "}\n";
2094*8975f5c5SAndroid Build Coastguard Worker 
2095*8975f5c5SAndroid Build Coastguard Worker     if (partCount > 0)
2096*8975f5c5SAndroid Build Coastguard Worker     {
2097*8975f5c5SAndroid Build Coastguard Worker         out << "\n";
2098*8975f5c5SAndroid Build Coastguard Worker         out << "void "
2099*8975f5c5SAndroid Build Coastguard Worker             << FmtFunction(replayFunc, contextID, FuncUsage::Definition, frameIndex, kNoPartId)
2100*8975f5c5SAndroid Build Coastguard Worker             << "\n";
2101*8975f5c5SAndroid Build Coastguard Worker         out << "{\n";
2102*8975f5c5SAndroid Build Coastguard Worker 
2103*8975f5c5SAndroid Build Coastguard Worker         // Write out the main call which calls all the parts.
2104*8975f5c5SAndroid Build Coastguard Worker         for (int i = 1; i <= partCount; i++)
2105*8975f5c5SAndroid Build Coastguard Worker         {
2106*8975f5c5SAndroid Build Coastguard Worker             out << "    " << FmtFunction(replayFunc, contextID, FuncUsage::Call, frameIndex, i)
2107*8975f5c5SAndroid Build Coastguard Worker                 << ";\n";
2108*8975f5c5SAndroid Build Coastguard Worker         }
2109*8975f5c5SAndroid Build Coastguard Worker 
2110*8975f5c5SAndroid Build Coastguard Worker         out << "}\n";
2111*8975f5c5SAndroid Build Coastguard Worker     }
2112*8975f5c5SAndroid Build Coastguard Worker }
2113*8975f5c5SAndroid Build Coastguard Worker 
2114*8975f5c5SAndroid Build Coastguard Worker // Auxiliary contexts are other contexts in the share group that aren't the context calling
2115*8975f5c5SAndroid Build Coastguard Worker // eglSwapBuffers().
WriteAuxiliaryContextCppSetupReplay(ReplayWriter & replayWriter,bool compression,const std::string & outDir,const gl::Context * context,const std::string & captureLabel,uint32_t frameIndex,const std::vector<CallCapture> & setupCalls,std::vector<uint8_t> * binaryData,bool serializeStateEnabled,const FrameCaptureShared & frameCaptureShared,size_t * maxResourceIDBufferSize)2116*8975f5c5SAndroid Build Coastguard Worker void WriteAuxiliaryContextCppSetupReplay(ReplayWriter &replayWriter,
2117*8975f5c5SAndroid Build Coastguard Worker                                          bool compression,
2118*8975f5c5SAndroid Build Coastguard Worker                                          const std::string &outDir,
2119*8975f5c5SAndroid Build Coastguard Worker                                          const gl::Context *context,
2120*8975f5c5SAndroid Build Coastguard Worker                                          const std::string &captureLabel,
2121*8975f5c5SAndroid Build Coastguard Worker                                          uint32_t frameIndex,
2122*8975f5c5SAndroid Build Coastguard Worker                                          const std::vector<CallCapture> &setupCalls,
2123*8975f5c5SAndroid Build Coastguard Worker                                          std::vector<uint8_t> *binaryData,
2124*8975f5c5SAndroid Build Coastguard Worker                                          bool serializeStateEnabled,
2125*8975f5c5SAndroid Build Coastguard Worker                                          const FrameCaptureShared &frameCaptureShared,
2126*8975f5c5SAndroid Build Coastguard Worker                                          size_t *maxResourceIDBufferSize)
2127*8975f5c5SAndroid Build Coastguard Worker {
2128*8975f5c5SAndroid Build Coastguard Worker     ASSERT(frameCaptureShared.getWindowSurfaceContextID() != context->id());
2129*8975f5c5SAndroid Build Coastguard Worker 
2130*8975f5c5SAndroid Build Coastguard Worker     {
2131*8975f5c5SAndroid Build Coastguard Worker         std::stringstream filenameStream;
2132*8975f5c5SAndroid Build Coastguard Worker         filenameStream << outDir << FmtCapturePrefix(context->id(), captureLabel);
2133*8975f5c5SAndroid Build Coastguard Worker         std::string filenamePattern = filenameStream.str();
2134*8975f5c5SAndroid Build Coastguard Worker         replayWriter.setFilenamePattern(filenamePattern);
2135*8975f5c5SAndroid Build Coastguard Worker     }
2136*8975f5c5SAndroid Build Coastguard Worker 
2137*8975f5c5SAndroid Build Coastguard Worker     {
2138*8975f5c5SAndroid Build Coastguard Worker         std::stringstream include;
2139*8975f5c5SAndroid Build Coastguard Worker         include << "#include \""
2140*8975f5c5SAndroid Build Coastguard Worker                 << FmtCapturePrefix(frameCaptureShared.getWindowSurfaceContextID(), captureLabel)
2141*8975f5c5SAndroid Build Coastguard Worker                 << ".h\"\n";
2142*8975f5c5SAndroid Build Coastguard Worker         include << "#include \"angle_trace_gl.h\"\n";
2143*8975f5c5SAndroid Build Coastguard Worker 
2144*8975f5c5SAndroid Build Coastguard Worker         std::string frameIncludes = include.str();
2145*8975f5c5SAndroid Build Coastguard Worker         replayWriter.setSourcePrologue(frameIncludes);
2146*8975f5c5SAndroid Build Coastguard Worker         replayWriter.setHeaderPrologue(frameIncludes);
2147*8975f5c5SAndroid Build Coastguard Worker     }
2148*8975f5c5SAndroid Build Coastguard Worker 
2149*8975f5c5SAndroid Build Coastguard Worker     {
2150*8975f5c5SAndroid Build Coastguard Worker         std::stringstream protoStream;
2151*8975f5c5SAndroid Build Coastguard Worker         std::stringstream headerStream;
2152*8975f5c5SAndroid Build Coastguard Worker         std::stringstream bodyStream;
2153*8975f5c5SAndroid Build Coastguard Worker 
2154*8975f5c5SAndroid Build Coastguard Worker         protoStream << "void " << FmtSetupFunction(kNoPartId, context->id(), FuncUsage::Prototype);
2155*8975f5c5SAndroid Build Coastguard Worker         std::string proto = protoStream.str();
2156*8975f5c5SAndroid Build Coastguard Worker 
2157*8975f5c5SAndroid Build Coastguard Worker         WriteCppReplayFunctionWithParts(context->id(), ReplayFunc::Setup, replayWriter, frameIndex,
2158*8975f5c5SAndroid Build Coastguard Worker                                         binaryData, setupCalls, headerStream, bodyStream,
2159*8975f5c5SAndroid Build Coastguard Worker                                         maxResourceIDBufferSize);
2160*8975f5c5SAndroid Build Coastguard Worker 
2161*8975f5c5SAndroid Build Coastguard Worker         replayWriter.addPrivateFunction(proto, headerStream, bodyStream);
2162*8975f5c5SAndroid Build Coastguard Worker     }
2163*8975f5c5SAndroid Build Coastguard Worker 
2164*8975f5c5SAndroid Build Coastguard Worker     replayWriter.saveFrame();
2165*8975f5c5SAndroid Build Coastguard Worker }
2166*8975f5c5SAndroid Build Coastguard Worker 
WriteShareGroupCppSetupReplay(ReplayWriter & replayWriter,bool compression,const std::string & outDir,const std::string & captureLabel,uint32_t frameIndex,uint32_t frameCount,const std::vector<CallCapture> & setupCalls,ResourceTracker * resourceTracker,std::vector<uint8_t> * binaryData,bool serializeStateEnabled,gl::ContextID windowSurfaceContextID,size_t * maxResourceIDBufferSize)2167*8975f5c5SAndroid Build Coastguard Worker void WriteShareGroupCppSetupReplay(ReplayWriter &replayWriter,
2168*8975f5c5SAndroid Build Coastguard Worker                                    bool compression,
2169*8975f5c5SAndroid Build Coastguard Worker                                    const std::string &outDir,
2170*8975f5c5SAndroid Build Coastguard Worker                                    const std::string &captureLabel,
2171*8975f5c5SAndroid Build Coastguard Worker                                    uint32_t frameIndex,
2172*8975f5c5SAndroid Build Coastguard Worker                                    uint32_t frameCount,
2173*8975f5c5SAndroid Build Coastguard Worker                                    const std::vector<CallCapture> &setupCalls,
2174*8975f5c5SAndroid Build Coastguard Worker                                    ResourceTracker *resourceTracker,
2175*8975f5c5SAndroid Build Coastguard Worker                                    std::vector<uint8_t> *binaryData,
2176*8975f5c5SAndroid Build Coastguard Worker                                    bool serializeStateEnabled,
2177*8975f5c5SAndroid Build Coastguard Worker                                    gl::ContextID windowSurfaceContextID,
2178*8975f5c5SAndroid Build Coastguard Worker                                    size_t *maxResourceIDBufferSize)
2179*8975f5c5SAndroid Build Coastguard Worker {
2180*8975f5c5SAndroid Build Coastguard Worker     {
2181*8975f5c5SAndroid Build Coastguard Worker 
2182*8975f5c5SAndroid Build Coastguard Worker         std::stringstream include;
2183*8975f5c5SAndroid Build Coastguard Worker 
2184*8975f5c5SAndroid Build Coastguard Worker         include << "#include \"angle_trace_gl.h\"\n";
2185*8975f5c5SAndroid Build Coastguard Worker         include << "#include \"" << FmtCapturePrefix(windowSurfaceContextID, captureLabel)
2186*8975f5c5SAndroid Build Coastguard Worker                 << ".h\"\n";
2187*8975f5c5SAndroid Build Coastguard Worker 
2188*8975f5c5SAndroid Build Coastguard Worker         std::string includeString = include.str();
2189*8975f5c5SAndroid Build Coastguard Worker 
2190*8975f5c5SAndroid Build Coastguard Worker         replayWriter.setSourcePrologue(includeString);
2191*8975f5c5SAndroid Build Coastguard Worker     }
2192*8975f5c5SAndroid Build Coastguard Worker 
2193*8975f5c5SAndroid Build Coastguard Worker     {
2194*8975f5c5SAndroid Build Coastguard Worker         std::stringstream protoStream;
2195*8975f5c5SAndroid Build Coastguard Worker         std::stringstream headerStream;
2196*8975f5c5SAndroid Build Coastguard Worker         std::stringstream bodyStream;
2197*8975f5c5SAndroid Build Coastguard Worker 
2198*8975f5c5SAndroid Build Coastguard Worker         protoStream << "void "
2199*8975f5c5SAndroid Build Coastguard Worker                     << FmtSetupFunction(kNoPartId, kSharedContextId, FuncUsage::Prototype);
2200*8975f5c5SAndroid Build Coastguard Worker         std::string proto = protoStream.str();
2201*8975f5c5SAndroid Build Coastguard Worker 
2202*8975f5c5SAndroid Build Coastguard Worker         WriteCppReplayFunctionWithParts(kSharedContextId, ReplayFunc::Setup, replayWriter,
2203*8975f5c5SAndroid Build Coastguard Worker                                         frameIndex, binaryData, setupCalls, headerStream,
2204*8975f5c5SAndroid Build Coastguard Worker                                         bodyStream, maxResourceIDBufferSize);
2205*8975f5c5SAndroid Build Coastguard Worker 
2206*8975f5c5SAndroid Build Coastguard Worker         replayWriter.addPrivateFunction(proto, headerStream, bodyStream);
2207*8975f5c5SAndroid Build Coastguard Worker 
2208*8975f5c5SAndroid Build Coastguard Worker         protoStream.str("");
2209*8975f5c5SAndroid Build Coastguard Worker         headerStream.str("");
2210*8975f5c5SAndroid Build Coastguard Worker         bodyStream.str("");
2211*8975f5c5SAndroid Build Coastguard Worker         protoStream << "void "
2212*8975f5c5SAndroid Build Coastguard Worker                     << FmtSetupInactiveFunction(kNoPartId, kSharedContextId, FuncUsage::Prototype);
2213*8975f5c5SAndroid Build Coastguard Worker         proto = protoStream.str();
2214*8975f5c5SAndroid Build Coastguard Worker 
2215*8975f5c5SAndroid Build Coastguard Worker         WriteCppReplayFunctionWithParts(kSharedContextId, ReplayFunc::SetupInactive, replayWriter,
2216*8975f5c5SAndroid Build Coastguard Worker                                         frameIndex, binaryData, setupCalls, headerStream,
2217*8975f5c5SAndroid Build Coastguard Worker                                         bodyStream, maxResourceIDBufferSize);
2218*8975f5c5SAndroid Build Coastguard Worker         replayWriter.addPrivateFunction(proto, headerStream, bodyStream);
2219*8975f5c5SAndroid Build Coastguard Worker     }
2220*8975f5c5SAndroid Build Coastguard Worker 
2221*8975f5c5SAndroid Build Coastguard Worker     {
2222*8975f5c5SAndroid Build Coastguard Worker         std::stringstream filenameStream;
2223*8975f5c5SAndroid Build Coastguard Worker         filenameStream << outDir << FmtCapturePrefix(kSharedContextId, captureLabel);
2224*8975f5c5SAndroid Build Coastguard Worker 
2225*8975f5c5SAndroid Build Coastguard Worker         std::string filenamePattern = filenameStream.str();
2226*8975f5c5SAndroid Build Coastguard Worker 
2227*8975f5c5SAndroid Build Coastguard Worker         replayWriter.setFilenamePattern(filenamePattern);
2228*8975f5c5SAndroid Build Coastguard Worker     }
2229*8975f5c5SAndroid Build Coastguard Worker 
2230*8975f5c5SAndroid Build Coastguard Worker     replayWriter.saveSetupFile();
2231*8975f5c5SAndroid Build Coastguard Worker }
2232*8975f5c5SAndroid Build Coastguard Worker 
GetAttachedProgramSources(const gl::Context * context,const gl::Program * program)2233*8975f5c5SAndroid Build Coastguard Worker ProgramSources GetAttachedProgramSources(const gl::Context *context, const gl::Program *program)
2234*8975f5c5SAndroid Build Coastguard Worker {
2235*8975f5c5SAndroid Build Coastguard Worker     ProgramSources sources;
2236*8975f5c5SAndroid Build Coastguard Worker     for (gl::ShaderType shaderType : gl::AllShaderTypes())
2237*8975f5c5SAndroid Build Coastguard Worker     {
2238*8975f5c5SAndroid Build Coastguard Worker         const gl::Shader *shader = program->getAttachedShader(shaderType);
2239*8975f5c5SAndroid Build Coastguard Worker         if (shader)
2240*8975f5c5SAndroid Build Coastguard Worker         {
2241*8975f5c5SAndroid Build Coastguard Worker             sources[shaderType] = shader->getSourceString();
2242*8975f5c5SAndroid Build Coastguard Worker         }
2243*8975f5c5SAndroid Build Coastguard Worker     }
2244*8975f5c5SAndroid Build Coastguard Worker     return sources;
2245*8975f5c5SAndroid Build Coastguard Worker }
2246*8975f5c5SAndroid Build Coastguard Worker 
2247*8975f5c5SAndroid Build Coastguard Worker template <typename IDType>
CaptureUpdateResourceIDs(const gl::Context * context,const CallCapture & call,const ParamCapture & param,ResourceTracker * resourceTracker,std::vector<CallCapture> * callsOut)2248*8975f5c5SAndroid Build Coastguard Worker void CaptureUpdateResourceIDs(const gl::Context *context,
2249*8975f5c5SAndroid Build Coastguard Worker                               const CallCapture &call,
2250*8975f5c5SAndroid Build Coastguard Worker                               const ParamCapture &param,
2251*8975f5c5SAndroid Build Coastguard Worker                               ResourceTracker *resourceTracker,
2252*8975f5c5SAndroid Build Coastguard Worker                               std::vector<CallCapture> *callsOut)
2253*8975f5c5SAndroid Build Coastguard Worker {
2254*8975f5c5SAndroid Build Coastguard Worker     GLsizei n = call.params.getParamFlexName("n", "count", ParamType::TGLsizei, 0).value.GLsizeiVal;
2255*8975f5c5SAndroid Build Coastguard Worker     ASSERT(param.data.size() == 1);
2256*8975f5c5SAndroid Build Coastguard Worker     ResourceIDType resourceIDType = GetResourceIDTypeFromParamType(param.type);
2257*8975f5c5SAndroid Build Coastguard Worker     ASSERT(resourceIDType != ResourceIDType::InvalidEnum &&
2258*8975f5c5SAndroid Build Coastguard Worker            resourceIDType != ResourceIDType::ShaderProgram);
2259*8975f5c5SAndroid Build Coastguard Worker     const char *resourceName = GetResourceIDTypeName(resourceIDType);
2260*8975f5c5SAndroid Build Coastguard Worker 
2261*8975f5c5SAndroid Build Coastguard Worker     std::stringstream updateFuncNameStr;
2262*8975f5c5SAndroid Build Coastguard Worker     updateFuncNameStr << "Update" << resourceName << "ID";
2263*8975f5c5SAndroid Build Coastguard Worker     bool trackedPerContext = IsTrackedPerContext(resourceIDType);
2264*8975f5c5SAndroid Build Coastguard Worker     if (trackedPerContext)
2265*8975f5c5SAndroid Build Coastguard Worker     {
2266*8975f5c5SAndroid Build Coastguard Worker         // TODO (https://issuetracker.google.com/169868803) The '2' version can be removed after all
2267*8975f5c5SAndroid Build Coastguard Worker         // context-local objects are tracked per-context
2268*8975f5c5SAndroid Build Coastguard Worker         updateFuncNameStr << "2";
2269*8975f5c5SAndroid Build Coastguard Worker     }
2270*8975f5c5SAndroid Build Coastguard Worker     std::string updateFuncName = updateFuncNameStr.str();
2271*8975f5c5SAndroid Build Coastguard Worker 
2272*8975f5c5SAndroid Build Coastguard Worker     const IDType *returnedIDs = reinterpret_cast<const IDType *>(param.data[0].data());
2273*8975f5c5SAndroid Build Coastguard Worker 
2274*8975f5c5SAndroid Build Coastguard Worker     ResourceSet &startingSet =
2275*8975f5c5SAndroid Build Coastguard Worker         resourceTracker->getTrackedResource(context->id(), resourceIDType).getStartingResources();
2276*8975f5c5SAndroid Build Coastguard Worker 
2277*8975f5c5SAndroid Build Coastguard Worker     for (GLsizei idIndex = 0; idIndex < n; ++idIndex)
2278*8975f5c5SAndroid Build Coastguard Worker     {
2279*8975f5c5SAndroid Build Coastguard Worker         IDType id                = returnedIDs[idIndex];
2280*8975f5c5SAndroid Build Coastguard Worker         GLsizei readBufferOffset = idIndex * sizeof(gl::RenderbufferID);
2281*8975f5c5SAndroid Build Coastguard Worker         ParamBuffer params;
2282*8975f5c5SAndroid Build Coastguard Worker         if (trackedPerContext)
2283*8975f5c5SAndroid Build Coastguard Worker         {
2284*8975f5c5SAndroid Build Coastguard Worker             params.addValueParam("contextId", ParamType::TGLuint, context->id().value);
2285*8975f5c5SAndroid Build Coastguard Worker         }
2286*8975f5c5SAndroid Build Coastguard Worker         params.addValueParam("id", ParamType::TGLuint, id.value);
2287*8975f5c5SAndroid Build Coastguard Worker         params.addValueParam("readBufferOffset", ParamType::TGLsizei, readBufferOffset);
2288*8975f5c5SAndroid Build Coastguard Worker         callsOut->emplace_back(updateFuncName, std::move(params));
2289*8975f5c5SAndroid Build Coastguard Worker 
2290*8975f5c5SAndroid Build Coastguard Worker         // Add only if not in starting resources.
2291*8975f5c5SAndroid Build Coastguard Worker         if (startingSet.find(id.value) == startingSet.end())
2292*8975f5c5SAndroid Build Coastguard Worker         {
2293*8975f5c5SAndroid Build Coastguard Worker             resourceTracker->getTrackedResource(context->id(), resourceIDType)
2294*8975f5c5SAndroid Build Coastguard Worker                 .getNewResources()
2295*8975f5c5SAndroid Build Coastguard Worker                 .insert(id.value);
2296*8975f5c5SAndroid Build Coastguard Worker         }
2297*8975f5c5SAndroid Build Coastguard Worker     }
2298*8975f5c5SAndroid Build Coastguard Worker }
2299*8975f5c5SAndroid Build Coastguard Worker 
CaptureUpdateUniformLocations(const gl::Program * program,std::vector<CallCapture> * callsOut)2300*8975f5c5SAndroid Build Coastguard Worker void CaptureUpdateUniformLocations(const gl::Program *program, std::vector<CallCapture> *callsOut)
2301*8975f5c5SAndroid Build Coastguard Worker {
2302*8975f5c5SAndroid Build Coastguard Worker     const gl::ProgramExecutable &executable            = program->getExecutable();
2303*8975f5c5SAndroid Build Coastguard Worker     const std::vector<gl::LinkedUniform> &uniforms     = executable.getUniforms();
2304*8975f5c5SAndroid Build Coastguard Worker     const std::vector<gl::VariableLocation> &locations = executable.getUniformLocations();
2305*8975f5c5SAndroid Build Coastguard Worker 
2306*8975f5c5SAndroid Build Coastguard Worker     for (GLint location = 0; location < static_cast<GLint>(locations.size()); ++location)
2307*8975f5c5SAndroid Build Coastguard Worker     {
2308*8975f5c5SAndroid Build Coastguard Worker         const gl::VariableLocation &locationVar = locations[location];
2309*8975f5c5SAndroid Build Coastguard Worker 
2310*8975f5c5SAndroid Build Coastguard Worker         // This handles the case where the application calls glBindUniformLocationCHROMIUM
2311*8975f5c5SAndroid Build Coastguard Worker         // on an unused uniform. We must still store a -1 into gUniformLocations in case the
2312*8975f5c5SAndroid Build Coastguard Worker         // application attempts to call a glUniform* call. To do this we'll pass in a blank name to
2313*8975f5c5SAndroid Build Coastguard Worker         // force glGetUniformLocation to return -1.
2314*8975f5c5SAndroid Build Coastguard Worker         std::string name;
2315*8975f5c5SAndroid Build Coastguard Worker         int count = 1;
2316*8975f5c5SAndroid Build Coastguard Worker         ParamBuffer params;
2317*8975f5c5SAndroid Build Coastguard Worker         params.addValueParam("program", ParamType::TGLuint, program->id().value);
2318*8975f5c5SAndroid Build Coastguard Worker 
2319*8975f5c5SAndroid Build Coastguard Worker         if (locationVar.index >= uniforms.size())
2320*8975f5c5SAndroid Build Coastguard Worker         {
2321*8975f5c5SAndroid Build Coastguard Worker             name = "";
2322*8975f5c5SAndroid Build Coastguard Worker         }
2323*8975f5c5SAndroid Build Coastguard Worker         else
2324*8975f5c5SAndroid Build Coastguard Worker         {
2325*8975f5c5SAndroid Build Coastguard Worker             const gl::LinkedUniform &uniform = uniforms[locationVar.index];
2326*8975f5c5SAndroid Build Coastguard Worker 
2327*8975f5c5SAndroid Build Coastguard Worker             name = executable.getUniformNameByIndex(locationVar.index);
2328*8975f5c5SAndroid Build Coastguard Worker 
2329*8975f5c5SAndroid Build Coastguard Worker             if (uniform.isArray())
2330*8975f5c5SAndroid Build Coastguard Worker             {
2331*8975f5c5SAndroid Build Coastguard Worker                 if (locationVar.arrayIndex > 0)
2332*8975f5c5SAndroid Build Coastguard Worker                 {
2333*8975f5c5SAndroid Build Coastguard Worker                     // Non-sequential array uniform locations are not currently handled.
2334*8975f5c5SAndroid Build Coastguard Worker                     // In practice array locations shouldn't ever be non-sequential.
2335*8975f5c5SAndroid Build Coastguard Worker                     ASSERT(uniform.getLocation() == -1 ||
2336*8975f5c5SAndroid Build Coastguard Worker                            location ==
2337*8975f5c5SAndroid Build Coastguard Worker                                uniform.getLocation() + static_cast<int>(locationVar.arrayIndex));
2338*8975f5c5SAndroid Build Coastguard Worker                     continue;
2339*8975f5c5SAndroid Build Coastguard Worker                 }
2340*8975f5c5SAndroid Build Coastguard Worker 
2341*8975f5c5SAndroid Build Coastguard Worker                 name  = gl::StripLastArrayIndex(name);
2342*8975f5c5SAndroid Build Coastguard Worker                 count = uniform.getBasicTypeElementCount();
2343*8975f5c5SAndroid Build Coastguard Worker             }
2344*8975f5c5SAndroid Build Coastguard Worker         }
2345*8975f5c5SAndroid Build Coastguard Worker 
2346*8975f5c5SAndroid Build Coastguard Worker         ParamCapture nameParam("name", ParamType::TGLcharConstPointer);
2347*8975f5c5SAndroid Build Coastguard Worker         CaptureString(name.c_str(), &nameParam);
2348*8975f5c5SAndroid Build Coastguard Worker         params.addParam(std::move(nameParam));
2349*8975f5c5SAndroid Build Coastguard Worker         params.addValueParam("location", ParamType::TGLint, location);
2350*8975f5c5SAndroid Build Coastguard Worker         params.addValueParam("count", ParamType::TGLint, static_cast<GLint>(count));
2351*8975f5c5SAndroid Build Coastguard Worker         callsOut->emplace_back("UpdateUniformLocation", std::move(params));
2352*8975f5c5SAndroid Build Coastguard Worker     }
2353*8975f5c5SAndroid Build Coastguard Worker }
2354*8975f5c5SAndroid Build Coastguard Worker 
CaptureValidateSerializedState(const gl::Context * context,std::vector<CallCapture> * callsOut)2355*8975f5c5SAndroid Build Coastguard Worker void CaptureValidateSerializedState(const gl::Context *context, std::vector<CallCapture> *callsOut)
2356*8975f5c5SAndroid Build Coastguard Worker {
2357*8975f5c5SAndroid Build Coastguard Worker     INFO() << "Capturing validation checkpoint at position " << callsOut->size();
2358*8975f5c5SAndroid Build Coastguard Worker 
2359*8975f5c5SAndroid Build Coastguard Worker     context->finishImmutable();
2360*8975f5c5SAndroid Build Coastguard Worker 
2361*8975f5c5SAndroid Build Coastguard Worker     std::string serializedState;
2362*8975f5c5SAndroid Build Coastguard Worker     angle::Result result = angle::SerializeContextToString(context, &serializedState);
2363*8975f5c5SAndroid Build Coastguard Worker     if (result != angle::Result::Continue)
2364*8975f5c5SAndroid Build Coastguard Worker     {
2365*8975f5c5SAndroid Build Coastguard Worker         ERR() << "Internal error serializing context state.";
2366*8975f5c5SAndroid Build Coastguard Worker         return;
2367*8975f5c5SAndroid Build Coastguard Worker     }
2368*8975f5c5SAndroid Build Coastguard Worker     ParamCapture serializedStateParam("serializedState", ParamType::TGLcharConstPointer);
2369*8975f5c5SAndroid Build Coastguard Worker     CaptureString(serializedState.c_str(), &serializedStateParam);
2370*8975f5c5SAndroid Build Coastguard Worker 
2371*8975f5c5SAndroid Build Coastguard Worker     ParamBuffer params;
2372*8975f5c5SAndroid Build Coastguard Worker     params.addParam(std::move(serializedStateParam));
2373*8975f5c5SAndroid Build Coastguard Worker 
2374*8975f5c5SAndroid Build Coastguard Worker     callsOut->emplace_back("VALIDATE_CHECKPOINT", std::move(params));
2375*8975f5c5SAndroid Build Coastguard Worker }
2376*8975f5c5SAndroid Build Coastguard Worker 
CaptureUpdateUniformBlockIndexes(const gl::Program * program,std::vector<CallCapture> * callsOut)2377*8975f5c5SAndroid Build Coastguard Worker void CaptureUpdateUniformBlockIndexes(const gl::Program *program,
2378*8975f5c5SAndroid Build Coastguard Worker                                       std::vector<CallCapture> *callsOut)
2379*8975f5c5SAndroid Build Coastguard Worker {
2380*8975f5c5SAndroid Build Coastguard Worker     const std::vector<gl::InterfaceBlock> &uniformBlocks =
2381*8975f5c5SAndroid Build Coastguard Worker         program->getExecutable().getUniformBlocks();
2382*8975f5c5SAndroid Build Coastguard Worker 
2383*8975f5c5SAndroid Build Coastguard Worker     for (GLuint index = 0; index < uniformBlocks.size(); ++index)
2384*8975f5c5SAndroid Build Coastguard Worker     {
2385*8975f5c5SAndroid Build Coastguard Worker         ParamBuffer params;
2386*8975f5c5SAndroid Build Coastguard Worker 
2387*8975f5c5SAndroid Build Coastguard Worker         std::string name;
2388*8975f5c5SAndroid Build Coastguard Worker         params.addValueParam("program", ParamType::TShaderProgramID, program->id());
2389*8975f5c5SAndroid Build Coastguard Worker 
2390*8975f5c5SAndroid Build Coastguard Worker         const std::string fullName = uniformBlocks[index].nameWithArrayIndex();
2391*8975f5c5SAndroid Build Coastguard Worker         ParamCapture nameParam("name", ParamType::TGLcharConstPointer);
2392*8975f5c5SAndroid Build Coastguard Worker         CaptureString(fullName.c_str(), &nameParam);
2393*8975f5c5SAndroid Build Coastguard Worker         params.addParam(std::move(nameParam));
2394*8975f5c5SAndroid Build Coastguard Worker 
2395*8975f5c5SAndroid Build Coastguard Worker         params.addValueParam("index", ParamType::TGLuint, index);
2396*8975f5c5SAndroid Build Coastguard Worker         callsOut->emplace_back("UpdateUniformBlockIndex", std::move(params));
2397*8975f5c5SAndroid Build Coastguard Worker     }
2398*8975f5c5SAndroid Build Coastguard Worker }
2399*8975f5c5SAndroid Build Coastguard Worker 
CaptureDeleteUniformLocations(gl::ShaderProgramID program,std::vector<CallCapture> * callsOut)2400*8975f5c5SAndroid Build Coastguard Worker void CaptureDeleteUniformLocations(gl::ShaderProgramID program, std::vector<CallCapture> *callsOut)
2401*8975f5c5SAndroid Build Coastguard Worker {
2402*8975f5c5SAndroid Build Coastguard Worker     ParamBuffer params;
2403*8975f5c5SAndroid Build Coastguard Worker     params.addValueParam("program", ParamType::TShaderProgramID, program);
2404*8975f5c5SAndroid Build Coastguard Worker     callsOut->emplace_back("DeleteUniformLocations", std::move(params));
2405*8975f5c5SAndroid Build Coastguard Worker }
2406*8975f5c5SAndroid Build Coastguard Worker 
MaybeCaptureUpdateResourceIDs(const gl::Context * context,ResourceTracker * resourceTracker,std::vector<CallCapture> * callsOut)2407*8975f5c5SAndroid Build Coastguard Worker void MaybeCaptureUpdateResourceIDs(const gl::Context *context,
2408*8975f5c5SAndroid Build Coastguard Worker                                    ResourceTracker *resourceTracker,
2409*8975f5c5SAndroid Build Coastguard Worker                                    std::vector<CallCapture> *callsOut)
2410*8975f5c5SAndroid Build Coastguard Worker {
2411*8975f5c5SAndroid Build Coastguard Worker     const CallCapture &call = callsOut->back();
2412*8975f5c5SAndroid Build Coastguard Worker 
2413*8975f5c5SAndroid Build Coastguard Worker     switch (call.entryPoint)
2414*8975f5c5SAndroid Build Coastguard Worker     {
2415*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLGenBuffers:
2416*8975f5c5SAndroid Build Coastguard Worker         {
2417*8975f5c5SAndroid Build Coastguard Worker             const ParamCapture &buffers =
2418*8975f5c5SAndroid Build Coastguard Worker                 call.params.getParam("buffersPacked", ParamType::TBufferIDPointer, 1);
2419*8975f5c5SAndroid Build Coastguard Worker             CaptureUpdateResourceIDs<gl::BufferID>(context, call, buffers, resourceTracker,
2420*8975f5c5SAndroid Build Coastguard Worker                                                    callsOut);
2421*8975f5c5SAndroid Build Coastguard Worker             break;
2422*8975f5c5SAndroid Build Coastguard Worker         }
2423*8975f5c5SAndroid Build Coastguard Worker 
2424*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLGenFencesNV:
2425*8975f5c5SAndroid Build Coastguard Worker         {
2426*8975f5c5SAndroid Build Coastguard Worker             const ParamCapture &fences =
2427*8975f5c5SAndroid Build Coastguard Worker                 call.params.getParam("fencesPacked", ParamType::TFenceNVIDPointer, 1);
2428*8975f5c5SAndroid Build Coastguard Worker             CaptureUpdateResourceIDs<gl::FenceNVID>(context, call, fences, resourceTracker,
2429*8975f5c5SAndroid Build Coastguard Worker                                                     callsOut);
2430*8975f5c5SAndroid Build Coastguard Worker             break;
2431*8975f5c5SAndroid Build Coastguard Worker         }
2432*8975f5c5SAndroid Build Coastguard Worker 
2433*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLGenFramebuffers:
2434*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLGenFramebuffersOES:
2435*8975f5c5SAndroid Build Coastguard Worker         {
2436*8975f5c5SAndroid Build Coastguard Worker             const ParamCapture &framebuffers =
2437*8975f5c5SAndroid Build Coastguard Worker                 call.params.getParam("framebuffersPacked", ParamType::TFramebufferIDPointer, 1);
2438*8975f5c5SAndroid Build Coastguard Worker             CaptureUpdateResourceIDs<gl::FramebufferID>(context, call, framebuffers,
2439*8975f5c5SAndroid Build Coastguard Worker                                                         resourceTracker, callsOut);
2440*8975f5c5SAndroid Build Coastguard Worker             break;
2441*8975f5c5SAndroid Build Coastguard Worker         }
2442*8975f5c5SAndroid Build Coastguard Worker 
2443*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLGenProgramPipelines:
2444*8975f5c5SAndroid Build Coastguard Worker         {
2445*8975f5c5SAndroid Build Coastguard Worker             const ParamCapture &pipelines =
2446*8975f5c5SAndroid Build Coastguard Worker                 call.params.getParam("pipelinesPacked", ParamType::TProgramPipelineIDPointer, 1);
2447*8975f5c5SAndroid Build Coastguard Worker             CaptureUpdateResourceIDs<gl::ProgramPipelineID>(context, call, pipelines,
2448*8975f5c5SAndroid Build Coastguard Worker                                                             resourceTracker, callsOut);
2449*8975f5c5SAndroid Build Coastguard Worker             break;
2450*8975f5c5SAndroid Build Coastguard Worker         }
2451*8975f5c5SAndroid Build Coastguard Worker 
2452*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLGenQueries:
2453*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLGenQueriesEXT:
2454*8975f5c5SAndroid Build Coastguard Worker         {
2455*8975f5c5SAndroid Build Coastguard Worker             const ParamCapture &queries =
2456*8975f5c5SAndroid Build Coastguard Worker                 call.params.getParam("idsPacked", ParamType::TQueryIDPointer, 1);
2457*8975f5c5SAndroid Build Coastguard Worker             CaptureUpdateResourceIDs<gl::QueryID>(context, call, queries, resourceTracker,
2458*8975f5c5SAndroid Build Coastguard Worker                                                   callsOut);
2459*8975f5c5SAndroid Build Coastguard Worker             break;
2460*8975f5c5SAndroid Build Coastguard Worker         }
2461*8975f5c5SAndroid Build Coastguard Worker 
2462*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLGenRenderbuffers:
2463*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLGenRenderbuffersOES:
2464*8975f5c5SAndroid Build Coastguard Worker         {
2465*8975f5c5SAndroid Build Coastguard Worker             const ParamCapture &renderbuffers =
2466*8975f5c5SAndroid Build Coastguard Worker                 call.params.getParam("renderbuffersPacked", ParamType::TRenderbufferIDPointer, 1);
2467*8975f5c5SAndroid Build Coastguard Worker             CaptureUpdateResourceIDs<gl::RenderbufferID>(context, call, renderbuffers,
2468*8975f5c5SAndroid Build Coastguard Worker                                                          resourceTracker, callsOut);
2469*8975f5c5SAndroid Build Coastguard Worker             break;
2470*8975f5c5SAndroid Build Coastguard Worker         }
2471*8975f5c5SAndroid Build Coastguard Worker 
2472*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLGenSamplers:
2473*8975f5c5SAndroid Build Coastguard Worker         {
2474*8975f5c5SAndroid Build Coastguard Worker             const ParamCapture &samplers =
2475*8975f5c5SAndroid Build Coastguard Worker                 call.params.getParam("samplersPacked", ParamType::TSamplerIDPointer, 1);
2476*8975f5c5SAndroid Build Coastguard Worker             CaptureUpdateResourceIDs<gl::SamplerID>(context, call, samplers, resourceTracker,
2477*8975f5c5SAndroid Build Coastguard Worker                                                     callsOut);
2478*8975f5c5SAndroid Build Coastguard Worker             break;
2479*8975f5c5SAndroid Build Coastguard Worker         }
2480*8975f5c5SAndroid Build Coastguard Worker 
2481*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLGenSemaphoresEXT:
2482*8975f5c5SAndroid Build Coastguard Worker         {
2483*8975f5c5SAndroid Build Coastguard Worker             const ParamCapture &semaphores =
2484*8975f5c5SAndroid Build Coastguard Worker                 call.params.getParam("semaphoresPacked", ParamType::TSemaphoreIDPointer, 1);
2485*8975f5c5SAndroid Build Coastguard Worker             CaptureUpdateResourceIDs<gl::SemaphoreID>(context, call, semaphores, resourceTracker,
2486*8975f5c5SAndroid Build Coastguard Worker                                                       callsOut);
2487*8975f5c5SAndroid Build Coastguard Worker             break;
2488*8975f5c5SAndroid Build Coastguard Worker         }
2489*8975f5c5SAndroid Build Coastguard Worker 
2490*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLGenTextures:
2491*8975f5c5SAndroid Build Coastguard Worker         {
2492*8975f5c5SAndroid Build Coastguard Worker             const ParamCapture &textures =
2493*8975f5c5SAndroid Build Coastguard Worker                 call.params.getParam("texturesPacked", ParamType::TTextureIDPointer, 1);
2494*8975f5c5SAndroid Build Coastguard Worker             CaptureUpdateResourceIDs<gl::TextureID>(context, call, textures, resourceTracker,
2495*8975f5c5SAndroid Build Coastguard Worker                                                     callsOut);
2496*8975f5c5SAndroid Build Coastguard Worker             break;
2497*8975f5c5SAndroid Build Coastguard Worker         }
2498*8975f5c5SAndroid Build Coastguard Worker 
2499*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLGenTransformFeedbacks:
2500*8975f5c5SAndroid Build Coastguard Worker         {
2501*8975f5c5SAndroid Build Coastguard Worker             const ParamCapture &xfbs =
2502*8975f5c5SAndroid Build Coastguard Worker                 call.params.getParam("idsPacked", ParamType::TTransformFeedbackIDPointer, 1);
2503*8975f5c5SAndroid Build Coastguard Worker             CaptureUpdateResourceIDs<gl::TransformFeedbackID>(context, call, xfbs, resourceTracker,
2504*8975f5c5SAndroid Build Coastguard Worker                                                               callsOut);
2505*8975f5c5SAndroid Build Coastguard Worker             break;
2506*8975f5c5SAndroid Build Coastguard Worker         }
2507*8975f5c5SAndroid Build Coastguard Worker 
2508*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLGenVertexArrays:
2509*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLGenVertexArraysOES:
2510*8975f5c5SAndroid Build Coastguard Worker         {
2511*8975f5c5SAndroid Build Coastguard Worker             const ParamCapture &vertexArrays =
2512*8975f5c5SAndroid Build Coastguard Worker                 call.params.getParam("arraysPacked", ParamType::TVertexArrayIDPointer, 1);
2513*8975f5c5SAndroid Build Coastguard Worker             CaptureUpdateResourceIDs<gl::VertexArrayID>(context, call, vertexArrays,
2514*8975f5c5SAndroid Build Coastguard Worker                                                         resourceTracker, callsOut);
2515*8975f5c5SAndroid Build Coastguard Worker             break;
2516*8975f5c5SAndroid Build Coastguard Worker         }
2517*8975f5c5SAndroid Build Coastguard Worker 
2518*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLCreateMemoryObjectsEXT:
2519*8975f5c5SAndroid Build Coastguard Worker         {
2520*8975f5c5SAndroid Build Coastguard Worker             const ParamCapture &memoryObjects =
2521*8975f5c5SAndroid Build Coastguard Worker                 call.params.getParam("memoryObjectsPacked", ParamType::TMemoryObjectIDPointer, 1);
2522*8975f5c5SAndroid Build Coastguard Worker             CaptureUpdateResourceIDs<gl::MemoryObjectID>(context, call, memoryObjects,
2523*8975f5c5SAndroid Build Coastguard Worker                                                          resourceTracker, callsOut);
2524*8975f5c5SAndroid Build Coastguard Worker             break;
2525*8975f5c5SAndroid Build Coastguard Worker         }
2526*8975f5c5SAndroid Build Coastguard Worker 
2527*8975f5c5SAndroid Build Coastguard Worker         default:
2528*8975f5c5SAndroid Build Coastguard Worker             break;
2529*8975f5c5SAndroid Build Coastguard Worker     }
2530*8975f5c5SAndroid Build Coastguard Worker }
2531*8975f5c5SAndroid Build Coastguard Worker 
IsDefaultCurrentValue(const gl::VertexAttribCurrentValueData & currentValue)2532*8975f5c5SAndroid Build Coastguard Worker bool IsDefaultCurrentValue(const gl::VertexAttribCurrentValueData &currentValue)
2533*8975f5c5SAndroid Build Coastguard Worker {
2534*8975f5c5SAndroid Build Coastguard Worker     if (currentValue.Type != gl::VertexAttribType::Float)
2535*8975f5c5SAndroid Build Coastguard Worker         return false;
2536*8975f5c5SAndroid Build Coastguard Worker 
2537*8975f5c5SAndroid Build Coastguard Worker     return currentValue.Values.FloatValues[0] == 0.0f &&
2538*8975f5c5SAndroid Build Coastguard Worker            currentValue.Values.FloatValues[1] == 0.0f &&
2539*8975f5c5SAndroid Build Coastguard Worker            currentValue.Values.FloatValues[2] == 0.0f && currentValue.Values.FloatValues[3] == 1.0f;
2540*8975f5c5SAndroid Build Coastguard Worker }
2541*8975f5c5SAndroid Build Coastguard Worker 
IsQueryActive(const gl::State & glState,gl::QueryID & queryID)2542*8975f5c5SAndroid Build Coastguard Worker bool IsQueryActive(const gl::State &glState, gl::QueryID &queryID)
2543*8975f5c5SAndroid Build Coastguard Worker {
2544*8975f5c5SAndroid Build Coastguard Worker     const gl::ActiveQueryMap &activeQueries = glState.getActiveQueriesForCapture();
2545*8975f5c5SAndroid Build Coastguard Worker     for (const auto &activeQueryIter : activeQueries)
2546*8975f5c5SAndroid Build Coastguard Worker     {
2547*8975f5c5SAndroid Build Coastguard Worker         const gl::Query *activeQuery = activeQueryIter.get();
2548*8975f5c5SAndroid Build Coastguard Worker         if (activeQuery && activeQuery->id() == queryID)
2549*8975f5c5SAndroid Build Coastguard Worker         {
2550*8975f5c5SAndroid Build Coastguard Worker             return true;
2551*8975f5c5SAndroid Build Coastguard Worker         }
2552*8975f5c5SAndroid Build Coastguard Worker     }
2553*8975f5c5SAndroid Build Coastguard Worker 
2554*8975f5c5SAndroid Build Coastguard Worker     return false;
2555*8975f5c5SAndroid Build Coastguard Worker }
2556*8975f5c5SAndroid Build Coastguard Worker 
IsTextureUpdate(CallCapture & call)2557*8975f5c5SAndroid Build Coastguard Worker bool IsTextureUpdate(CallCapture &call)
2558*8975f5c5SAndroid Build Coastguard Worker {
2559*8975f5c5SAndroid Build Coastguard Worker     switch (call.entryPoint)
2560*8975f5c5SAndroid Build Coastguard Worker     {
2561*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLCompressedCopyTextureCHROMIUM:
2562*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLCompressedTexImage2D:
2563*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLCompressedTexImage2DRobustANGLE:
2564*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLCompressedTexImage3D:
2565*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLCompressedTexImage3DOES:
2566*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLCompressedTexImage3DRobustANGLE:
2567*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLCompressedTexSubImage2D:
2568*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLCompressedTexSubImage2DRobustANGLE:
2569*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLCompressedTexSubImage3D:
2570*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLCompressedTexSubImage3DOES:
2571*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLCompressedTexSubImage3DRobustANGLE:
2572*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLCopyTexImage2D:
2573*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLCopyTexSubImage2D:
2574*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLCopyTexSubImage3D:
2575*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLCopyTexSubImage3DOES:
2576*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLCopyTexture3DANGLE:
2577*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLCopyTextureCHROMIUM:
2578*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLTexImage2D:
2579*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLTexImage2DExternalANGLE:
2580*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLTexImage2DRobustANGLE:
2581*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLTexImage3D:
2582*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLTexImage3DOES:
2583*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLTexImage3DRobustANGLE:
2584*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLTexSubImage2D:
2585*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLTexSubImage2DRobustANGLE:
2586*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLTexSubImage3D:
2587*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLTexSubImage3DOES:
2588*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLTexSubImage3DRobustANGLE:
2589*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLCopyImageSubData:
2590*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLCopyImageSubDataEXT:
2591*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLCopyImageSubDataOES:
2592*8975f5c5SAndroid Build Coastguard Worker             return true;
2593*8975f5c5SAndroid Build Coastguard Worker         default:
2594*8975f5c5SAndroid Build Coastguard Worker             return false;
2595*8975f5c5SAndroid Build Coastguard Worker     }
2596*8975f5c5SAndroid Build Coastguard Worker }
2597*8975f5c5SAndroid Build Coastguard Worker 
IsImageUpdate(CallCapture & call)2598*8975f5c5SAndroid Build Coastguard Worker bool IsImageUpdate(CallCapture &call)
2599*8975f5c5SAndroid Build Coastguard Worker {
2600*8975f5c5SAndroid Build Coastguard Worker     switch (call.entryPoint)
2601*8975f5c5SAndroid Build Coastguard Worker     {
2602*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLDispatchCompute:
2603*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLDispatchComputeIndirect:
2604*8975f5c5SAndroid Build Coastguard Worker             return true;
2605*8975f5c5SAndroid Build Coastguard Worker         default:
2606*8975f5c5SAndroid Build Coastguard Worker             return false;
2607*8975f5c5SAndroid Build Coastguard Worker     }
2608*8975f5c5SAndroid Build Coastguard Worker }
2609*8975f5c5SAndroid Build Coastguard Worker 
IsVertexArrayUpdate(CallCapture & call)2610*8975f5c5SAndroid Build Coastguard Worker bool IsVertexArrayUpdate(CallCapture &call)
2611*8975f5c5SAndroid Build Coastguard Worker {
2612*8975f5c5SAndroid Build Coastguard Worker     switch (call.entryPoint)
2613*8975f5c5SAndroid Build Coastguard Worker     {
2614*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLVertexAttribFormat:
2615*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLVertexAttribIFormat:
2616*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLBindVertexBuffer:
2617*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLVertexAttribBinding:
2618*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLVertexAttribPointer:
2619*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLVertexAttribIPointer:
2620*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLEnableVertexAttribArray:
2621*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLDisableVertexAttribArray:
2622*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLVertexBindingDivisor:
2623*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLVertexAttribDivisor:
2624*8975f5c5SAndroid Build Coastguard Worker             return true;
2625*8975f5c5SAndroid Build Coastguard Worker         default:
2626*8975f5c5SAndroid Build Coastguard Worker             return false;
2627*8975f5c5SAndroid Build Coastguard Worker     }
2628*8975f5c5SAndroid Build Coastguard Worker }
2629*8975f5c5SAndroid Build Coastguard Worker 
IsSharedObjectResource(ResourceIDType type)2630*8975f5c5SAndroid Build Coastguard Worker bool IsSharedObjectResource(ResourceIDType type)
2631*8975f5c5SAndroid Build Coastguard Worker {
2632*8975f5c5SAndroid Build Coastguard Worker     // This helper function informs us which objects are shared vs. per context
2633*8975f5c5SAndroid Build Coastguard Worker     //
2634*8975f5c5SAndroid Build Coastguard Worker     //   OpenGL ES Version 3.2 (October 22, 2019)
2635*8975f5c5SAndroid Build Coastguard Worker     //   Chapter 5 Shared Objects and Multiple Contexts:
2636*8975f5c5SAndroid Build Coastguard Worker     //
2637*8975f5c5SAndroid Build Coastguard Worker     //   - Objects that can be shared between contexts include buffer objects, program
2638*8975f5c5SAndroid Build Coastguard Worker     //     and shader objects, renderbuffer objects, sampler objects, sync objects, and texture
2639*8975f5c5SAndroid Build Coastguard Worker     //     objects (except for the texture objects named zero).
2640*8975f5c5SAndroid Build Coastguard Worker     //   - Objects which contain references to other objects include framebuffer, program
2641*8975f5c5SAndroid Build Coastguard Worker     //     pipeline, transform feedback, and vertex array objects. Such objects are called
2642*8975f5c5SAndroid Build Coastguard Worker     //     container objects and are not shared.
2643*8975f5c5SAndroid Build Coastguard Worker     //
2644*8975f5c5SAndroid Build Coastguard Worker     // Notably absent from this list are Sync objects, which are not ResourceIDType, are handled
2645*8975f5c5SAndroid Build Coastguard Worker     // elsewhere, and are shared:
2646*8975f5c5SAndroid Build Coastguard Worker     //   - 2.6.13 Sync Objects: Sync objects may be shared.
2647*8975f5c5SAndroid Build Coastguard Worker 
2648*8975f5c5SAndroid Build Coastguard Worker     switch (type)
2649*8975f5c5SAndroid Build Coastguard Worker     {
2650*8975f5c5SAndroid Build Coastguard Worker         case ResourceIDType::Buffer:
2651*8975f5c5SAndroid Build Coastguard Worker             // 2.6.2 Buffer Objects: Buffer objects may be shared.
2652*8975f5c5SAndroid Build Coastguard Worker             return true;
2653*8975f5c5SAndroid Build Coastguard Worker 
2654*8975f5c5SAndroid Build Coastguard Worker         case ResourceIDType::Framebuffer:
2655*8975f5c5SAndroid Build Coastguard Worker             // 2.6.9 Framebuffer Objects: Framebuffer objects are container objects including
2656*8975f5c5SAndroid Build Coastguard Worker             // references to renderbuffer and / or texture objects, and are not shared.
2657*8975f5c5SAndroid Build Coastguard Worker             return false;
2658*8975f5c5SAndroid Build Coastguard Worker 
2659*8975f5c5SAndroid Build Coastguard Worker         case ResourceIDType::ProgramPipeline:
2660*8975f5c5SAndroid Build Coastguard Worker             // 2.6.5 Program Pipeline Objects: Program pipeline objects are container objects
2661*8975f5c5SAndroid Build Coastguard Worker             // including references to program objects, and are not shared.
2662*8975f5c5SAndroid Build Coastguard Worker             return false;
2663*8975f5c5SAndroid Build Coastguard Worker 
2664*8975f5c5SAndroid Build Coastguard Worker         case ResourceIDType::TransformFeedback:
2665*8975f5c5SAndroid Build Coastguard Worker             // 2.6.11 Transform Feedback Objects: Transform feedback objects are container objects
2666*8975f5c5SAndroid Build Coastguard Worker             // including references to buffer objects, and are not shared
2667*8975f5c5SAndroid Build Coastguard Worker             return false;
2668*8975f5c5SAndroid Build Coastguard Worker 
2669*8975f5c5SAndroid Build Coastguard Worker         case ResourceIDType::VertexArray:
2670*8975f5c5SAndroid Build Coastguard Worker             // 2.6.10 Vertex Array Objects: Vertex array objects are container objects including
2671*8975f5c5SAndroid Build Coastguard Worker             // references to buffer objects, and are not shared
2672*8975f5c5SAndroid Build Coastguard Worker             return false;
2673*8975f5c5SAndroid Build Coastguard Worker 
2674*8975f5c5SAndroid Build Coastguard Worker         case ResourceIDType::FenceNV:
2675*8975f5c5SAndroid Build Coastguard Worker             // From https://registry.khronos.org/OpenGL/extensions/NV/NV_fence.txt
2676*8975f5c5SAndroid Build Coastguard Worker             //  Are the fences sharable between multiple contexts?
2677*8975f5c5SAndroid Build Coastguard Worker             //   RESOLUTION: No.
2678*8975f5c5SAndroid Build Coastguard Worker             return false;
2679*8975f5c5SAndroid Build Coastguard Worker 
2680*8975f5c5SAndroid Build Coastguard Worker         case ResourceIDType::Renderbuffer:
2681*8975f5c5SAndroid Build Coastguard Worker             // 2.6.8 Renderbuffer Objects: Renderbuffer objects may be shared.
2682*8975f5c5SAndroid Build Coastguard Worker             return true;
2683*8975f5c5SAndroid Build Coastguard Worker 
2684*8975f5c5SAndroid Build Coastguard Worker         case ResourceIDType::ShaderProgram:
2685*8975f5c5SAndroid Build Coastguard Worker             // 2.6.3 Shader Objects: Shader objects may be shared.
2686*8975f5c5SAndroid Build Coastguard Worker             // 2.6.4 Program Objects: Program objects may be shared.
2687*8975f5c5SAndroid Build Coastguard Worker             return true;
2688*8975f5c5SAndroid Build Coastguard Worker 
2689*8975f5c5SAndroid Build Coastguard Worker         case ResourceIDType::Sampler:
2690*8975f5c5SAndroid Build Coastguard Worker             // 2.6.7 Sampler Objects: Sampler objects may be shared
2691*8975f5c5SAndroid Build Coastguard Worker             return true;
2692*8975f5c5SAndroid Build Coastguard Worker 
2693*8975f5c5SAndroid Build Coastguard Worker         case ResourceIDType::Sync:
2694*8975f5c5SAndroid Build Coastguard Worker             // 2.6.13 Sync Objects: Sync objects may be shared.
2695*8975f5c5SAndroid Build Coastguard Worker             return true;
2696*8975f5c5SAndroid Build Coastguard Worker 
2697*8975f5c5SAndroid Build Coastguard Worker         case ResourceIDType::Texture:
2698*8975f5c5SAndroid Build Coastguard Worker             // 2.6.6 Texture Objects: Texture objects may be shared
2699*8975f5c5SAndroid Build Coastguard Worker             return true;
2700*8975f5c5SAndroid Build Coastguard Worker 
2701*8975f5c5SAndroid Build Coastguard Worker         case ResourceIDType::Query:
2702*8975f5c5SAndroid Build Coastguard Worker             // 2.6.12 Query Objects: Query objects are not shared
2703*8975f5c5SAndroid Build Coastguard Worker             return false;
2704*8975f5c5SAndroid Build Coastguard Worker 
2705*8975f5c5SAndroid Build Coastguard Worker         case ResourceIDType::Semaphore:
2706*8975f5c5SAndroid Build Coastguard Worker             // From https://registry.khronos.org/OpenGL/extensions/EXT/EXT_external_objects.txt
2707*8975f5c5SAndroid Build Coastguard Worker             // 2.6.14 Semaphore Objects: Semaphore objects may be shared.
2708*8975f5c5SAndroid Build Coastguard Worker             return true;
2709*8975f5c5SAndroid Build Coastguard Worker 
2710*8975f5c5SAndroid Build Coastguard Worker         case ResourceIDType::MemoryObject:
2711*8975f5c5SAndroid Build Coastguard Worker             // From https://registry.khronos.org/OpenGL/extensions/EXT/EXT_external_objects.txt
2712*8975f5c5SAndroid Build Coastguard Worker             // 2.6.15 Memory Objects: Memory objects may be shared.
2713*8975f5c5SAndroid Build Coastguard Worker             return true;
2714*8975f5c5SAndroid Build Coastguard Worker 
2715*8975f5c5SAndroid Build Coastguard Worker         case ResourceIDType::Context:
2716*8975f5c5SAndroid Build Coastguard Worker         case ResourceIDType::Image:
2717*8975f5c5SAndroid Build Coastguard Worker         case ResourceIDType::Surface:
2718*8975f5c5SAndroid Build Coastguard Worker         case ResourceIDType::egl_Sync:
2719*8975f5c5SAndroid Build Coastguard Worker             // EGL types are associated with a display and not bound to a context
2720*8975f5c5SAndroid Build Coastguard Worker             // For the way this function is used, we can treat them as shared.
2721*8975f5c5SAndroid Build Coastguard Worker             return true;
2722*8975f5c5SAndroid Build Coastguard Worker 
2723*8975f5c5SAndroid Build Coastguard Worker         case ResourceIDType::EnumCount:
2724*8975f5c5SAndroid Build Coastguard Worker         default:
2725*8975f5c5SAndroid Build Coastguard Worker             ERR() << "Unhandled ResourceIDType= " << static_cast<int>(type);
2726*8975f5c5SAndroid Build Coastguard Worker             UNREACHABLE();
2727*8975f5c5SAndroid Build Coastguard Worker             return false;
2728*8975f5c5SAndroid Build Coastguard Worker     }
2729*8975f5c5SAndroid Build Coastguard Worker }
2730*8975f5c5SAndroid Build Coastguard Worker 
2731*8975f5c5SAndroid Build Coastguard Worker enum class DefaultUniformType
2732*8975f5c5SAndroid Build Coastguard Worker {
2733*8975f5c5SAndroid Build Coastguard Worker     None,
2734*8975f5c5SAndroid Build Coastguard Worker     CurrentProgram,
2735*8975f5c5SAndroid Build Coastguard Worker     SpecifiedProgram,
2736*8975f5c5SAndroid Build Coastguard Worker };
2737*8975f5c5SAndroid Build Coastguard Worker 
GetDefaultUniformType(const CallCapture & call)2738*8975f5c5SAndroid Build Coastguard Worker DefaultUniformType GetDefaultUniformType(const CallCapture &call)
2739*8975f5c5SAndroid Build Coastguard Worker {
2740*8975f5c5SAndroid Build Coastguard Worker     switch (call.entryPoint)
2741*8975f5c5SAndroid Build Coastguard Worker     {
2742*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLProgramUniform1f:
2743*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLProgramUniform1fEXT:
2744*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLProgramUniform1fv:
2745*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLProgramUniform1fvEXT:
2746*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLProgramUniform1i:
2747*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLProgramUniform1iEXT:
2748*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLProgramUniform1iv:
2749*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLProgramUniform1ivEXT:
2750*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLProgramUniform1ui:
2751*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLProgramUniform1uiEXT:
2752*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLProgramUniform1uiv:
2753*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLProgramUniform1uivEXT:
2754*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLProgramUniform2f:
2755*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLProgramUniform2fEXT:
2756*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLProgramUniform2fv:
2757*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLProgramUniform2fvEXT:
2758*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLProgramUniform2i:
2759*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLProgramUniform2iEXT:
2760*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLProgramUniform2iv:
2761*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLProgramUniform2ivEXT:
2762*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLProgramUniform2ui:
2763*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLProgramUniform2uiEXT:
2764*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLProgramUniform2uiv:
2765*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLProgramUniform2uivEXT:
2766*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLProgramUniform3f:
2767*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLProgramUniform3fEXT:
2768*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLProgramUniform3fv:
2769*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLProgramUniform3fvEXT:
2770*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLProgramUniform3i:
2771*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLProgramUniform3iEXT:
2772*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLProgramUniform3iv:
2773*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLProgramUniform3ivEXT:
2774*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLProgramUniform3ui:
2775*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLProgramUniform3uiEXT:
2776*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLProgramUniform3uiv:
2777*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLProgramUniform3uivEXT:
2778*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLProgramUniform4f:
2779*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLProgramUniform4fEXT:
2780*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLProgramUniform4fv:
2781*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLProgramUniform4fvEXT:
2782*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLProgramUniform4i:
2783*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLProgramUniform4iEXT:
2784*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLProgramUniform4iv:
2785*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLProgramUniform4ivEXT:
2786*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLProgramUniform4ui:
2787*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLProgramUniform4uiEXT:
2788*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLProgramUniform4uiv:
2789*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLProgramUniform4uivEXT:
2790*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLProgramUniformMatrix2fv:
2791*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLProgramUniformMatrix2fvEXT:
2792*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLProgramUniformMatrix2x3fv:
2793*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLProgramUniformMatrix2x3fvEXT:
2794*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLProgramUniformMatrix2x4fv:
2795*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLProgramUniformMatrix2x4fvEXT:
2796*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLProgramUniformMatrix3fv:
2797*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLProgramUniformMatrix3fvEXT:
2798*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLProgramUniformMatrix3x2fv:
2799*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLProgramUniformMatrix3x2fvEXT:
2800*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLProgramUniformMatrix3x4fv:
2801*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLProgramUniformMatrix3x4fvEXT:
2802*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLProgramUniformMatrix4fv:
2803*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLProgramUniformMatrix4fvEXT:
2804*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLProgramUniformMatrix4x2fv:
2805*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLProgramUniformMatrix4x2fvEXT:
2806*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLProgramUniformMatrix4x3fv:
2807*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLProgramUniformMatrix4x3fvEXT:
2808*8975f5c5SAndroid Build Coastguard Worker             return DefaultUniformType::SpecifiedProgram;
2809*8975f5c5SAndroid Build Coastguard Worker 
2810*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLUniform1f:
2811*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLUniform1fv:
2812*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLUniform1i:
2813*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLUniform1iv:
2814*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLUniform1ui:
2815*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLUniform1uiv:
2816*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLUniform2f:
2817*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLUniform2fv:
2818*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLUniform2i:
2819*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLUniform2iv:
2820*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLUniform2ui:
2821*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLUniform2uiv:
2822*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLUniform3f:
2823*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLUniform3fv:
2824*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLUniform3i:
2825*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLUniform3iv:
2826*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLUniform3ui:
2827*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLUniform3uiv:
2828*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLUniform4f:
2829*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLUniform4fv:
2830*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLUniform4i:
2831*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLUniform4iv:
2832*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLUniform4ui:
2833*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLUniform4uiv:
2834*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLUniformMatrix2fv:
2835*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLUniformMatrix2x3fv:
2836*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLUniformMatrix2x4fv:
2837*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLUniformMatrix3fv:
2838*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLUniformMatrix3x2fv:
2839*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLUniformMatrix3x4fv:
2840*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLUniformMatrix4fv:
2841*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLUniformMatrix4x2fv:
2842*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLUniformMatrix4x3fv:
2843*8975f5c5SAndroid Build Coastguard Worker             return DefaultUniformType::CurrentProgram;
2844*8975f5c5SAndroid Build Coastguard Worker 
2845*8975f5c5SAndroid Build Coastguard Worker         default:
2846*8975f5c5SAndroid Build Coastguard Worker             return DefaultUniformType::None;
2847*8975f5c5SAndroid Build Coastguard Worker     }
2848*8975f5c5SAndroid Build Coastguard Worker }
2849*8975f5c5SAndroid Build Coastguard Worker 
CaptureFramebufferAttachment(std::vector<CallCapture> * setupCalls,const gl::State & replayState,const FramebufferCaptureFuncs & framebufferFuncs,const gl::FramebufferAttachment & attachment,std::vector<CallCapture> * shareGroupSetupCalls,ResourceIDToSetupCallsMap * resourceIDToSetupCalls)2850*8975f5c5SAndroid Build Coastguard Worker void CaptureFramebufferAttachment(std::vector<CallCapture> *setupCalls,
2851*8975f5c5SAndroid Build Coastguard Worker                                   const gl::State &replayState,
2852*8975f5c5SAndroid Build Coastguard Worker                                   const FramebufferCaptureFuncs &framebufferFuncs,
2853*8975f5c5SAndroid Build Coastguard Worker                                   const gl::FramebufferAttachment &attachment,
2854*8975f5c5SAndroid Build Coastguard Worker                                   std::vector<CallCapture> *shareGroupSetupCalls,
2855*8975f5c5SAndroid Build Coastguard Worker                                   ResourceIDToSetupCallsMap *resourceIDToSetupCalls)
2856*8975f5c5SAndroid Build Coastguard Worker {
2857*8975f5c5SAndroid Build Coastguard Worker     GLuint resourceID = attachment.getResource()->getId();
2858*8975f5c5SAndroid Build Coastguard Worker 
2859*8975f5c5SAndroid Build Coastguard Worker     if (attachment.type() == GL_TEXTURE)
2860*8975f5c5SAndroid Build Coastguard Worker     {
2861*8975f5c5SAndroid Build Coastguard Worker         gl::ImageIndex index = attachment.getTextureImageIndex();
2862*8975f5c5SAndroid Build Coastguard Worker 
2863*8975f5c5SAndroid Build Coastguard Worker         if (index.usesTex3D())
2864*8975f5c5SAndroid Build Coastguard Worker         {
2865*8975f5c5SAndroid Build Coastguard Worker             Capture(setupCalls, CaptureFramebufferTextureLayer(
2866*8975f5c5SAndroid Build Coastguard Worker                                     replayState, true, GL_FRAMEBUFFER, attachment.getBinding(),
2867*8975f5c5SAndroid Build Coastguard Worker                                     {resourceID}, index.getLevelIndex(), index.getLayerIndex()));
2868*8975f5c5SAndroid Build Coastguard Worker         }
2869*8975f5c5SAndroid Build Coastguard Worker         else
2870*8975f5c5SAndroid Build Coastguard Worker         {
2871*8975f5c5SAndroid Build Coastguard Worker             Capture(setupCalls,
2872*8975f5c5SAndroid Build Coastguard Worker                     framebufferFuncs.framebufferTexture2D(
2873*8975f5c5SAndroid Build Coastguard Worker                         replayState, true, GL_FRAMEBUFFER, attachment.getBinding(),
2874*8975f5c5SAndroid Build Coastguard Worker                         index.getTargetOrFirstCubeFace(), {resourceID}, index.getLevelIndex()));
2875*8975f5c5SAndroid Build Coastguard Worker         }
2876*8975f5c5SAndroid Build Coastguard Worker 
2877*8975f5c5SAndroid Build Coastguard Worker         std::vector<gl::TextureID> textureIDs;
2878*8975f5c5SAndroid Build Coastguard Worker         const CallCapture &call = setupCalls->back();
2879*8975f5c5SAndroid Build Coastguard Worker         if (FindResourceIDsInCall<gl::TextureID>(call, textureIDs))
2880*8975f5c5SAndroid Build Coastguard Worker         {
2881*8975f5c5SAndroid Build Coastguard Worker             // We skip the is active check on the assumption this call is made during MEC
2882*8975f5c5SAndroid Build Coastguard Worker             for (gl::TextureID textureID : textureIDs)
2883*8975f5c5SAndroid Build Coastguard Worker             {
2884*8975f5c5SAndroid Build Coastguard Worker                 // Track that this call referenced a Texture, setting it active for Setup
2885*8975f5c5SAndroid Build Coastguard Worker                 MarkResourceIDActive(ResourceIDType::Texture, textureID.value, shareGroupSetupCalls,
2886*8975f5c5SAndroid Build Coastguard Worker                                      resourceIDToSetupCalls);
2887*8975f5c5SAndroid Build Coastguard Worker             }
2888*8975f5c5SAndroid Build Coastguard Worker         }
2889*8975f5c5SAndroid Build Coastguard Worker     }
2890*8975f5c5SAndroid Build Coastguard Worker     else
2891*8975f5c5SAndroid Build Coastguard Worker     {
2892*8975f5c5SAndroid Build Coastguard Worker         ASSERT(attachment.type() == GL_RENDERBUFFER);
2893*8975f5c5SAndroid Build Coastguard Worker         Capture(setupCalls, framebufferFuncs.framebufferRenderbuffer(
2894*8975f5c5SAndroid Build Coastguard Worker                                 replayState, true, GL_FRAMEBUFFER, attachment.getBinding(),
2895*8975f5c5SAndroid Build Coastguard Worker                                 GL_RENDERBUFFER, {resourceID}));
2896*8975f5c5SAndroid Build Coastguard Worker     }
2897*8975f5c5SAndroid Build Coastguard Worker }
2898*8975f5c5SAndroid Build Coastguard Worker 
CaptureUpdateUniformValues(const gl::State & replayState,const gl::Context * context,gl::Program * program,ResourceTracker * resourceTracker,std::vector<CallCapture> * callsOut)2899*8975f5c5SAndroid Build Coastguard Worker void CaptureUpdateUniformValues(const gl::State &replayState,
2900*8975f5c5SAndroid Build Coastguard Worker                                 const gl::Context *context,
2901*8975f5c5SAndroid Build Coastguard Worker                                 gl::Program *program,
2902*8975f5c5SAndroid Build Coastguard Worker                                 ResourceTracker *resourceTracker,
2903*8975f5c5SAndroid Build Coastguard Worker                                 std::vector<CallCapture> *callsOut)
2904*8975f5c5SAndroid Build Coastguard Worker {
2905*8975f5c5SAndroid Build Coastguard Worker     if (!program->isLinked())
2906*8975f5c5SAndroid Build Coastguard Worker     {
2907*8975f5c5SAndroid Build Coastguard Worker         // We can't populate uniforms if the program hasn't been linked
2908*8975f5c5SAndroid Build Coastguard Worker         return;
2909*8975f5c5SAndroid Build Coastguard Worker     }
2910*8975f5c5SAndroid Build Coastguard Worker 
2911*8975f5c5SAndroid Build Coastguard Worker     // We need to bind the program and update its uniforms
2912*8975f5c5SAndroid Build Coastguard Worker     if (!replayState.getProgram() || replayState.getProgram()->id() != program->id())
2913*8975f5c5SAndroid Build Coastguard Worker     {
2914*8975f5c5SAndroid Build Coastguard Worker         Capture(callsOut, CaptureUseProgram(replayState, true, program->id()));
2915*8975f5c5SAndroid Build Coastguard Worker         CaptureUpdateCurrentProgram(callsOut->back(), 0, callsOut);
2916*8975f5c5SAndroid Build Coastguard Worker     }
2917*8975f5c5SAndroid Build Coastguard Worker 
2918*8975f5c5SAndroid Build Coastguard Worker     const gl::ProgramExecutable &executable = program->getExecutable();
2919*8975f5c5SAndroid Build Coastguard Worker 
2920*8975f5c5SAndroid Build Coastguard Worker     for (GLuint uniformIndex = 0;
2921*8975f5c5SAndroid Build Coastguard Worker          uniformIndex < static_cast<GLuint>(executable.getUniforms().size()); uniformIndex++)
2922*8975f5c5SAndroid Build Coastguard Worker     {
2923*8975f5c5SAndroid Build Coastguard Worker         std::string uniformName          = executable.getUniformNameByIndex(uniformIndex);
2924*8975f5c5SAndroid Build Coastguard Worker         const gl::LinkedUniform &uniform = executable.getUniformByIndex(uniformIndex);
2925*8975f5c5SAndroid Build Coastguard Worker 
2926*8975f5c5SAndroid Build Coastguard Worker         int uniformCount = 1;
2927*8975f5c5SAndroid Build Coastguard Worker         if (uniform.isArray())
2928*8975f5c5SAndroid Build Coastguard Worker         {
2929*8975f5c5SAndroid Build Coastguard Worker             uniformCount = uniform.getBasicTypeElementCount();
2930*8975f5c5SAndroid Build Coastguard Worker             uniformName  = gl::StripLastArrayIndex(uniformName);
2931*8975f5c5SAndroid Build Coastguard Worker         }
2932*8975f5c5SAndroid Build Coastguard Worker 
2933*8975f5c5SAndroid Build Coastguard Worker         gl::UniformLocation uniformLoc      = executable.getUniformLocation(uniformName);
2934*8975f5c5SAndroid Build Coastguard Worker         const gl::UniformTypeInfo &typeInfo = gl::GetUniformTypeInfo(uniform.getType());
2935*8975f5c5SAndroid Build Coastguard Worker         int componentCount                  = typeInfo.componentCount;
2936*8975f5c5SAndroid Build Coastguard Worker         int uniformSize                     = uniformCount * componentCount;
2937*8975f5c5SAndroid Build Coastguard Worker 
2938*8975f5c5SAndroid Build Coastguard Worker         // For arrayed uniforms, we'll need to increment a read location
2939*8975f5c5SAndroid Build Coastguard Worker         gl::UniformLocation readLoc = uniformLoc;
2940*8975f5c5SAndroid Build Coastguard Worker 
2941*8975f5c5SAndroid Build Coastguard Worker         // If the uniform is unused, just continue
2942*8975f5c5SAndroid Build Coastguard Worker         if (readLoc.value == -1)
2943*8975f5c5SAndroid Build Coastguard Worker         {
2944*8975f5c5SAndroid Build Coastguard Worker             continue;
2945*8975f5c5SAndroid Build Coastguard Worker         }
2946*8975f5c5SAndroid Build Coastguard Worker 
2947*8975f5c5SAndroid Build Coastguard Worker         // Image uniforms are special and cannot be set this way
2948*8975f5c5SAndroid Build Coastguard Worker         if (typeInfo.isImageType)
2949*8975f5c5SAndroid Build Coastguard Worker         {
2950*8975f5c5SAndroid Build Coastguard Worker             continue;
2951*8975f5c5SAndroid Build Coastguard Worker         }
2952*8975f5c5SAndroid Build Coastguard Worker 
2953*8975f5c5SAndroid Build Coastguard Worker         DefaultUniformCallsPerLocationMap &resetCalls =
2954*8975f5c5SAndroid Build Coastguard Worker             resourceTracker->getDefaultUniformResetCalls(program->id());
2955*8975f5c5SAndroid Build Coastguard Worker 
2956*8975f5c5SAndroid Build Coastguard Worker         // Create two lists of calls for uniforms, one for Setup, one for Reset
2957*8975f5c5SAndroid Build Coastguard Worker         CallVector defaultUniformCalls({callsOut, &resetCalls[uniformLoc]});
2958*8975f5c5SAndroid Build Coastguard Worker 
2959*8975f5c5SAndroid Build Coastguard Worker         // Samplers should be populated with GL_INT, regardless of return type
2960*8975f5c5SAndroid Build Coastguard Worker         if (typeInfo.isSampler)
2961*8975f5c5SAndroid Build Coastguard Worker         {
2962*8975f5c5SAndroid Build Coastguard Worker             std::vector<GLint> uniformBuffer(uniformSize);
2963*8975f5c5SAndroid Build Coastguard Worker             for (int index = 0; index < uniformCount; index++, readLoc.value++)
2964*8975f5c5SAndroid Build Coastguard Worker             {
2965*8975f5c5SAndroid Build Coastguard Worker                 executable.getUniformiv(context, readLoc,
2966*8975f5c5SAndroid Build Coastguard Worker                                         uniformBuffer.data() + index * componentCount);
2967*8975f5c5SAndroid Build Coastguard Worker                 resourceTracker->setDefaultUniformBaseLocation(program->id(), readLoc, uniformLoc);
2968*8975f5c5SAndroid Build Coastguard Worker             }
2969*8975f5c5SAndroid Build Coastguard Worker 
2970*8975f5c5SAndroid Build Coastguard Worker             for (std::vector<CallCapture> *calls : defaultUniformCalls)
2971*8975f5c5SAndroid Build Coastguard Worker             {
2972*8975f5c5SAndroid Build Coastguard Worker                 Capture(calls, CaptureUniform1iv(replayState, true, uniformLoc, uniformCount,
2973*8975f5c5SAndroid Build Coastguard Worker                                                  uniformBuffer.data()));
2974*8975f5c5SAndroid Build Coastguard Worker             }
2975*8975f5c5SAndroid Build Coastguard Worker 
2976*8975f5c5SAndroid Build Coastguard Worker             continue;
2977*8975f5c5SAndroid Build Coastguard Worker         }
2978*8975f5c5SAndroid Build Coastguard Worker 
2979*8975f5c5SAndroid Build Coastguard Worker         switch (typeInfo.componentType)
2980*8975f5c5SAndroid Build Coastguard Worker         {
2981*8975f5c5SAndroid Build Coastguard Worker             case GL_FLOAT:
2982*8975f5c5SAndroid Build Coastguard Worker             {
2983*8975f5c5SAndroid Build Coastguard Worker                 std::vector<GLfloat> uniformBuffer(uniformSize);
2984*8975f5c5SAndroid Build Coastguard Worker                 for (int index = 0; index < uniformCount; index++, readLoc.value++)
2985*8975f5c5SAndroid Build Coastguard Worker                 {
2986*8975f5c5SAndroid Build Coastguard Worker                     executable.getUniformfv(context, readLoc,
2987*8975f5c5SAndroid Build Coastguard Worker                                             uniformBuffer.data() + index * componentCount);
2988*8975f5c5SAndroid Build Coastguard Worker                     resourceTracker->setDefaultUniformBaseLocation(program->id(), readLoc,
2989*8975f5c5SAndroid Build Coastguard Worker                                                                    uniformLoc);
2990*8975f5c5SAndroid Build Coastguard Worker                 }
2991*8975f5c5SAndroid Build Coastguard Worker                 switch (typeInfo.type)
2992*8975f5c5SAndroid Build Coastguard Worker                 {
2993*8975f5c5SAndroid Build Coastguard Worker                     // Note: All matrix uniforms are populated without transpose
2994*8975f5c5SAndroid Build Coastguard Worker                     case GL_FLOAT_MAT4x3:
2995*8975f5c5SAndroid Build Coastguard Worker                         for (std::vector<CallCapture> *calls : defaultUniformCalls)
2996*8975f5c5SAndroid Build Coastguard Worker                         {
2997*8975f5c5SAndroid Build Coastguard Worker                             Capture(calls, CaptureUniformMatrix4x3fv(replayState, true, uniformLoc,
2998*8975f5c5SAndroid Build Coastguard Worker                                                                      uniformCount, false,
2999*8975f5c5SAndroid Build Coastguard Worker                                                                      uniformBuffer.data()));
3000*8975f5c5SAndroid Build Coastguard Worker                         }
3001*8975f5c5SAndroid Build Coastguard Worker                         break;
3002*8975f5c5SAndroid Build Coastguard Worker                     case GL_FLOAT_MAT4x2:
3003*8975f5c5SAndroid Build Coastguard Worker                         for (std::vector<CallCapture> *calls : defaultUniformCalls)
3004*8975f5c5SAndroid Build Coastguard Worker                         {
3005*8975f5c5SAndroid Build Coastguard Worker                             Capture(calls, CaptureUniformMatrix4x2fv(replayState, true, uniformLoc,
3006*8975f5c5SAndroid Build Coastguard Worker                                                                      uniformCount, false,
3007*8975f5c5SAndroid Build Coastguard Worker                                                                      uniformBuffer.data()));
3008*8975f5c5SAndroid Build Coastguard Worker                         }
3009*8975f5c5SAndroid Build Coastguard Worker                         break;
3010*8975f5c5SAndroid Build Coastguard Worker                     case GL_FLOAT_MAT4:
3011*8975f5c5SAndroid Build Coastguard Worker                         for (std::vector<CallCapture> *calls : defaultUniformCalls)
3012*8975f5c5SAndroid Build Coastguard Worker                         {
3013*8975f5c5SAndroid Build Coastguard Worker                             Capture(calls, CaptureUniformMatrix4fv(replayState, true, uniformLoc,
3014*8975f5c5SAndroid Build Coastguard Worker                                                                    uniformCount, false,
3015*8975f5c5SAndroid Build Coastguard Worker                                                                    uniformBuffer.data()));
3016*8975f5c5SAndroid Build Coastguard Worker                         }
3017*8975f5c5SAndroid Build Coastguard Worker                         break;
3018*8975f5c5SAndroid Build Coastguard Worker                     case GL_FLOAT_MAT3x4:
3019*8975f5c5SAndroid Build Coastguard Worker                         for (std::vector<CallCapture> *calls : defaultUniformCalls)
3020*8975f5c5SAndroid Build Coastguard Worker                         {
3021*8975f5c5SAndroid Build Coastguard Worker                             Capture(calls, CaptureUniformMatrix3x4fv(replayState, true, uniformLoc,
3022*8975f5c5SAndroid Build Coastguard Worker                                                                      uniformCount, false,
3023*8975f5c5SAndroid Build Coastguard Worker                                                                      uniformBuffer.data()));
3024*8975f5c5SAndroid Build Coastguard Worker                         }
3025*8975f5c5SAndroid Build Coastguard Worker                         break;
3026*8975f5c5SAndroid Build Coastguard Worker                     case GL_FLOAT_MAT3x2:
3027*8975f5c5SAndroid Build Coastguard Worker                         for (std::vector<CallCapture> *calls : defaultUniformCalls)
3028*8975f5c5SAndroid Build Coastguard Worker                         {
3029*8975f5c5SAndroid Build Coastguard Worker                             Capture(calls, CaptureUniformMatrix3x2fv(replayState, true, uniformLoc,
3030*8975f5c5SAndroid Build Coastguard Worker                                                                      uniformCount, false,
3031*8975f5c5SAndroid Build Coastguard Worker                                                                      uniformBuffer.data()));
3032*8975f5c5SAndroid Build Coastguard Worker                         }
3033*8975f5c5SAndroid Build Coastguard Worker                         break;
3034*8975f5c5SAndroid Build Coastguard Worker                     case GL_FLOAT_MAT3:
3035*8975f5c5SAndroid Build Coastguard Worker                         for (std::vector<CallCapture> *calls : defaultUniformCalls)
3036*8975f5c5SAndroid Build Coastguard Worker                         {
3037*8975f5c5SAndroid Build Coastguard Worker                             Capture(calls, CaptureUniformMatrix3fv(replayState, true, uniformLoc,
3038*8975f5c5SAndroid Build Coastguard Worker                                                                    uniformCount, false,
3039*8975f5c5SAndroid Build Coastguard Worker                                                                    uniformBuffer.data()));
3040*8975f5c5SAndroid Build Coastguard Worker                         }
3041*8975f5c5SAndroid Build Coastguard Worker                         break;
3042*8975f5c5SAndroid Build Coastguard Worker                     case GL_FLOAT_MAT2x4:
3043*8975f5c5SAndroid Build Coastguard Worker                         for (std::vector<CallCapture> *calls : defaultUniformCalls)
3044*8975f5c5SAndroid Build Coastguard Worker                         {
3045*8975f5c5SAndroid Build Coastguard Worker                             Capture(calls, CaptureUniformMatrix2x4fv(replayState, true, uniformLoc,
3046*8975f5c5SAndroid Build Coastguard Worker                                                                      uniformCount, false,
3047*8975f5c5SAndroid Build Coastguard Worker                                                                      uniformBuffer.data()));
3048*8975f5c5SAndroid Build Coastguard Worker                         }
3049*8975f5c5SAndroid Build Coastguard Worker                         break;
3050*8975f5c5SAndroid Build Coastguard Worker                     case GL_FLOAT_MAT2x3:
3051*8975f5c5SAndroid Build Coastguard Worker                         for (std::vector<CallCapture> *calls : defaultUniformCalls)
3052*8975f5c5SAndroid Build Coastguard Worker                         {
3053*8975f5c5SAndroid Build Coastguard Worker                             Capture(calls, CaptureUniformMatrix2x3fv(replayState, true, uniformLoc,
3054*8975f5c5SAndroid Build Coastguard Worker                                                                      uniformCount, false,
3055*8975f5c5SAndroid Build Coastguard Worker                                                                      uniformBuffer.data()));
3056*8975f5c5SAndroid Build Coastguard Worker                         }
3057*8975f5c5SAndroid Build Coastguard Worker                         break;
3058*8975f5c5SAndroid Build Coastguard Worker                     case GL_FLOAT_MAT2:
3059*8975f5c5SAndroid Build Coastguard Worker                         for (std::vector<CallCapture> *calls : defaultUniformCalls)
3060*8975f5c5SAndroid Build Coastguard Worker                         {
3061*8975f5c5SAndroid Build Coastguard Worker                             Capture(calls, CaptureUniformMatrix2fv(replayState, true, uniformLoc,
3062*8975f5c5SAndroid Build Coastguard Worker                                                                    uniformCount, false,
3063*8975f5c5SAndroid Build Coastguard Worker                                                                    uniformBuffer.data()));
3064*8975f5c5SAndroid Build Coastguard Worker                         }
3065*8975f5c5SAndroid Build Coastguard Worker                         break;
3066*8975f5c5SAndroid Build Coastguard Worker                     case GL_FLOAT_VEC4:
3067*8975f5c5SAndroid Build Coastguard Worker                         for (std::vector<CallCapture> *calls : defaultUniformCalls)
3068*8975f5c5SAndroid Build Coastguard Worker                         {
3069*8975f5c5SAndroid Build Coastguard Worker                             Capture(calls, CaptureUniform4fv(replayState, true, uniformLoc,
3070*8975f5c5SAndroid Build Coastguard Worker                                                              uniformCount, uniformBuffer.data()));
3071*8975f5c5SAndroid Build Coastguard Worker                         }
3072*8975f5c5SAndroid Build Coastguard Worker                         break;
3073*8975f5c5SAndroid Build Coastguard Worker                     case GL_FLOAT_VEC3:
3074*8975f5c5SAndroid Build Coastguard Worker                         for (std::vector<CallCapture> *calls : defaultUniformCalls)
3075*8975f5c5SAndroid Build Coastguard Worker                         {
3076*8975f5c5SAndroid Build Coastguard Worker                             Capture(calls, CaptureUniform3fv(replayState, true, uniformLoc,
3077*8975f5c5SAndroid Build Coastguard Worker                                                              uniformCount, uniformBuffer.data()));
3078*8975f5c5SAndroid Build Coastguard Worker                         }
3079*8975f5c5SAndroid Build Coastguard Worker                         break;
3080*8975f5c5SAndroid Build Coastguard Worker                     case GL_FLOAT_VEC2:
3081*8975f5c5SAndroid Build Coastguard Worker                         for (std::vector<CallCapture> *calls : defaultUniformCalls)
3082*8975f5c5SAndroid Build Coastguard Worker                         {
3083*8975f5c5SAndroid Build Coastguard Worker                             Capture(calls, CaptureUniform2fv(replayState, true, uniformLoc,
3084*8975f5c5SAndroid Build Coastguard Worker                                                              uniformCount, uniformBuffer.data()));
3085*8975f5c5SAndroid Build Coastguard Worker                         }
3086*8975f5c5SAndroid Build Coastguard Worker                         break;
3087*8975f5c5SAndroid Build Coastguard Worker                     case GL_FLOAT:
3088*8975f5c5SAndroid Build Coastguard Worker                         for (std::vector<CallCapture> *calls : defaultUniformCalls)
3089*8975f5c5SAndroid Build Coastguard Worker                         {
3090*8975f5c5SAndroid Build Coastguard Worker                             Capture(calls, CaptureUniform1fv(replayState, true, uniformLoc,
3091*8975f5c5SAndroid Build Coastguard Worker                                                              uniformCount, uniformBuffer.data()));
3092*8975f5c5SAndroid Build Coastguard Worker                         }
3093*8975f5c5SAndroid Build Coastguard Worker                         break;
3094*8975f5c5SAndroid Build Coastguard Worker                     default:
3095*8975f5c5SAndroid Build Coastguard Worker                         UNIMPLEMENTED();
3096*8975f5c5SAndroid Build Coastguard Worker                         break;
3097*8975f5c5SAndroid Build Coastguard Worker                 }
3098*8975f5c5SAndroid Build Coastguard Worker                 break;
3099*8975f5c5SAndroid Build Coastguard Worker             }
3100*8975f5c5SAndroid Build Coastguard Worker             case GL_INT:
3101*8975f5c5SAndroid Build Coastguard Worker             {
3102*8975f5c5SAndroid Build Coastguard Worker                 std::vector<GLint> uniformBuffer(uniformSize);
3103*8975f5c5SAndroid Build Coastguard Worker                 for (int index = 0; index < uniformCount; index++, readLoc.value++)
3104*8975f5c5SAndroid Build Coastguard Worker                 {
3105*8975f5c5SAndroid Build Coastguard Worker                     executable.getUniformiv(context, readLoc,
3106*8975f5c5SAndroid Build Coastguard Worker                                             uniformBuffer.data() + index * componentCount);
3107*8975f5c5SAndroid Build Coastguard Worker                     resourceTracker->setDefaultUniformBaseLocation(program->id(), readLoc,
3108*8975f5c5SAndroid Build Coastguard Worker                                                                    uniformLoc);
3109*8975f5c5SAndroid Build Coastguard Worker                 }
3110*8975f5c5SAndroid Build Coastguard Worker                 switch (componentCount)
3111*8975f5c5SAndroid Build Coastguard Worker                 {
3112*8975f5c5SAndroid Build Coastguard Worker                     case 4:
3113*8975f5c5SAndroid Build Coastguard Worker                         for (std::vector<CallCapture> *calls : defaultUniformCalls)
3114*8975f5c5SAndroid Build Coastguard Worker                         {
3115*8975f5c5SAndroid Build Coastguard Worker                             Capture(calls, CaptureUniform4iv(replayState, true, uniformLoc,
3116*8975f5c5SAndroid Build Coastguard Worker                                                              uniformCount, uniformBuffer.data()));
3117*8975f5c5SAndroid Build Coastguard Worker                         }
3118*8975f5c5SAndroid Build Coastguard Worker                         break;
3119*8975f5c5SAndroid Build Coastguard Worker                     case 3:
3120*8975f5c5SAndroid Build Coastguard Worker                         for (std::vector<CallCapture> *calls : defaultUniformCalls)
3121*8975f5c5SAndroid Build Coastguard Worker                         {
3122*8975f5c5SAndroid Build Coastguard Worker                             Capture(calls, CaptureUniform3iv(replayState, true, uniformLoc,
3123*8975f5c5SAndroid Build Coastguard Worker                                                              uniformCount, uniformBuffer.data()));
3124*8975f5c5SAndroid Build Coastguard Worker                         }
3125*8975f5c5SAndroid Build Coastguard Worker                         break;
3126*8975f5c5SAndroid Build Coastguard Worker                     case 2:
3127*8975f5c5SAndroid Build Coastguard Worker                         for (std::vector<CallCapture> *calls : defaultUniformCalls)
3128*8975f5c5SAndroid Build Coastguard Worker                         {
3129*8975f5c5SAndroid Build Coastguard Worker                             Capture(calls, CaptureUniform2iv(replayState, true, uniformLoc,
3130*8975f5c5SAndroid Build Coastguard Worker                                                              uniformCount, uniformBuffer.data()));
3131*8975f5c5SAndroid Build Coastguard Worker                         }
3132*8975f5c5SAndroid Build Coastguard Worker                         break;
3133*8975f5c5SAndroid Build Coastguard Worker                     case 1:
3134*8975f5c5SAndroid Build Coastguard Worker                         for (std::vector<CallCapture> *calls : defaultUniformCalls)
3135*8975f5c5SAndroid Build Coastguard Worker                         {
3136*8975f5c5SAndroid Build Coastguard Worker                             Capture(calls, CaptureUniform1iv(replayState, true, uniformLoc,
3137*8975f5c5SAndroid Build Coastguard Worker                                                              uniformCount, uniformBuffer.data()));
3138*8975f5c5SAndroid Build Coastguard Worker                         }
3139*8975f5c5SAndroid Build Coastguard Worker                         break;
3140*8975f5c5SAndroid Build Coastguard Worker                     default:
3141*8975f5c5SAndroid Build Coastguard Worker                         UNIMPLEMENTED();
3142*8975f5c5SAndroid Build Coastguard Worker                         break;
3143*8975f5c5SAndroid Build Coastguard Worker                 }
3144*8975f5c5SAndroid Build Coastguard Worker                 break;
3145*8975f5c5SAndroid Build Coastguard Worker             }
3146*8975f5c5SAndroid Build Coastguard Worker             case GL_BOOL:
3147*8975f5c5SAndroid Build Coastguard Worker             case GL_UNSIGNED_INT:
3148*8975f5c5SAndroid Build Coastguard Worker             {
3149*8975f5c5SAndroid Build Coastguard Worker                 std::vector<GLuint> uniformBuffer(uniformSize);
3150*8975f5c5SAndroid Build Coastguard Worker                 for (int index = 0; index < uniformCount; index++, readLoc.value++)
3151*8975f5c5SAndroid Build Coastguard Worker                 {
3152*8975f5c5SAndroid Build Coastguard Worker                     executable.getUniformuiv(context, readLoc,
3153*8975f5c5SAndroid Build Coastguard Worker                                              uniformBuffer.data() + index * componentCount);
3154*8975f5c5SAndroid Build Coastguard Worker                     resourceTracker->setDefaultUniformBaseLocation(program->id(), readLoc,
3155*8975f5c5SAndroid Build Coastguard Worker                                                                    uniformLoc);
3156*8975f5c5SAndroid Build Coastguard Worker                 }
3157*8975f5c5SAndroid Build Coastguard Worker                 switch (componentCount)
3158*8975f5c5SAndroid Build Coastguard Worker                 {
3159*8975f5c5SAndroid Build Coastguard Worker                     case 4:
3160*8975f5c5SAndroid Build Coastguard Worker                         for (std::vector<CallCapture> *calls : defaultUniformCalls)
3161*8975f5c5SAndroid Build Coastguard Worker                         {
3162*8975f5c5SAndroid Build Coastguard Worker                             Capture(calls, CaptureUniform4uiv(replayState, true, uniformLoc,
3163*8975f5c5SAndroid Build Coastguard Worker                                                               uniformCount, uniformBuffer.data()));
3164*8975f5c5SAndroid Build Coastguard Worker                         }
3165*8975f5c5SAndroid Build Coastguard Worker                         break;
3166*8975f5c5SAndroid Build Coastguard Worker                     case 3:
3167*8975f5c5SAndroid Build Coastguard Worker                         for (std::vector<CallCapture> *calls : defaultUniformCalls)
3168*8975f5c5SAndroid Build Coastguard Worker                         {
3169*8975f5c5SAndroid Build Coastguard Worker                             Capture(calls, CaptureUniform3uiv(replayState, true, uniformLoc,
3170*8975f5c5SAndroid Build Coastguard Worker                                                               uniformCount, uniformBuffer.data()));
3171*8975f5c5SAndroid Build Coastguard Worker                         }
3172*8975f5c5SAndroid Build Coastguard Worker                         break;
3173*8975f5c5SAndroid Build Coastguard Worker                     case 2:
3174*8975f5c5SAndroid Build Coastguard Worker                         for (std::vector<CallCapture> *calls : defaultUniformCalls)
3175*8975f5c5SAndroid Build Coastguard Worker                         {
3176*8975f5c5SAndroid Build Coastguard Worker                             Capture(calls, CaptureUniform2uiv(replayState, true, uniformLoc,
3177*8975f5c5SAndroid Build Coastguard Worker                                                               uniformCount, uniformBuffer.data()));
3178*8975f5c5SAndroid Build Coastguard Worker                         }
3179*8975f5c5SAndroid Build Coastguard Worker                         break;
3180*8975f5c5SAndroid Build Coastguard Worker                     case 1:
3181*8975f5c5SAndroid Build Coastguard Worker                         for (std::vector<CallCapture> *calls : defaultUniformCalls)
3182*8975f5c5SAndroid Build Coastguard Worker                         {
3183*8975f5c5SAndroid Build Coastguard Worker                             Capture(calls, CaptureUniform1uiv(replayState, true, uniformLoc,
3184*8975f5c5SAndroid Build Coastguard Worker                                                               uniformCount, uniformBuffer.data()));
3185*8975f5c5SAndroid Build Coastguard Worker                         }
3186*8975f5c5SAndroid Build Coastguard Worker                         break;
3187*8975f5c5SAndroid Build Coastguard Worker                     default:
3188*8975f5c5SAndroid Build Coastguard Worker                         UNIMPLEMENTED();
3189*8975f5c5SAndroid Build Coastguard Worker                         break;
3190*8975f5c5SAndroid Build Coastguard Worker                 }
3191*8975f5c5SAndroid Build Coastguard Worker                 break;
3192*8975f5c5SAndroid Build Coastguard Worker             }
3193*8975f5c5SAndroid Build Coastguard Worker             default:
3194*8975f5c5SAndroid Build Coastguard Worker                 UNIMPLEMENTED();
3195*8975f5c5SAndroid Build Coastguard Worker                 break;
3196*8975f5c5SAndroid Build Coastguard Worker         }
3197*8975f5c5SAndroid Build Coastguard Worker     }
3198*8975f5c5SAndroid Build Coastguard Worker }
3199*8975f5c5SAndroid Build Coastguard Worker 
CaptureVertexPointerES1(std::vector<CallCapture> * setupCalls,gl::State * replayState,GLuint attribIndex,const gl::VertexAttribute & attrib,const gl::VertexBinding & binding)3200*8975f5c5SAndroid Build Coastguard Worker void CaptureVertexPointerES1(std::vector<CallCapture> *setupCalls,
3201*8975f5c5SAndroid Build Coastguard Worker                              gl::State *replayState,
3202*8975f5c5SAndroid Build Coastguard Worker                              GLuint attribIndex,
3203*8975f5c5SAndroid Build Coastguard Worker                              const gl::VertexAttribute &attrib,
3204*8975f5c5SAndroid Build Coastguard Worker                              const gl::VertexBinding &binding)
3205*8975f5c5SAndroid Build Coastguard Worker {
3206*8975f5c5SAndroid Build Coastguard Worker     switch (gl::GLES1Renderer::VertexArrayType(attribIndex))
3207*8975f5c5SAndroid Build Coastguard Worker     {
3208*8975f5c5SAndroid Build Coastguard Worker         case gl::ClientVertexArrayType::Vertex:
3209*8975f5c5SAndroid Build Coastguard Worker             Capture(setupCalls,
3210*8975f5c5SAndroid Build Coastguard Worker                     CaptureVertexPointer(*replayState, true, attrib.format->channelCount,
3211*8975f5c5SAndroid Build Coastguard Worker                                          attrib.format->vertexAttribType, binding.getStride(),
3212*8975f5c5SAndroid Build Coastguard Worker                                          attrib.pointer));
3213*8975f5c5SAndroid Build Coastguard Worker             break;
3214*8975f5c5SAndroid Build Coastguard Worker         case gl::ClientVertexArrayType::Normal:
3215*8975f5c5SAndroid Build Coastguard Worker             Capture(setupCalls,
3216*8975f5c5SAndroid Build Coastguard Worker                     CaptureNormalPointer(*replayState, true, attrib.format->vertexAttribType,
3217*8975f5c5SAndroid Build Coastguard Worker                                          binding.getStride(), attrib.pointer));
3218*8975f5c5SAndroid Build Coastguard Worker             break;
3219*8975f5c5SAndroid Build Coastguard Worker         case gl::ClientVertexArrayType::Color:
3220*8975f5c5SAndroid Build Coastguard Worker             Capture(setupCalls, CaptureColorPointer(*replayState, true, attrib.format->channelCount,
3221*8975f5c5SAndroid Build Coastguard Worker                                                     attrib.format->vertexAttribType,
3222*8975f5c5SAndroid Build Coastguard Worker                                                     binding.getStride(), attrib.pointer));
3223*8975f5c5SAndroid Build Coastguard Worker             break;
3224*8975f5c5SAndroid Build Coastguard Worker         case gl::ClientVertexArrayType::PointSize:
3225*8975f5c5SAndroid Build Coastguard Worker             Capture(setupCalls,
3226*8975f5c5SAndroid Build Coastguard Worker                     CapturePointSizePointerOES(*replayState, true, attrib.format->vertexAttribType,
3227*8975f5c5SAndroid Build Coastguard Worker                                                binding.getStride(), attrib.pointer));
3228*8975f5c5SAndroid Build Coastguard Worker             break;
3229*8975f5c5SAndroid Build Coastguard Worker         case gl::ClientVertexArrayType::TextureCoord:
3230*8975f5c5SAndroid Build Coastguard Worker             Capture(setupCalls,
3231*8975f5c5SAndroid Build Coastguard Worker                     CaptureTexCoordPointer(*replayState, true, attrib.format->channelCount,
3232*8975f5c5SAndroid Build Coastguard Worker                                            attrib.format->vertexAttribType, binding.getStride(),
3233*8975f5c5SAndroid Build Coastguard Worker                                            attrib.pointer));
3234*8975f5c5SAndroid Build Coastguard Worker             break;
3235*8975f5c5SAndroid Build Coastguard Worker         default:
3236*8975f5c5SAndroid Build Coastguard Worker             UNREACHABLE();
3237*8975f5c5SAndroid Build Coastguard Worker     }
3238*8975f5c5SAndroid Build Coastguard Worker }
3239*8975f5c5SAndroid Build Coastguard Worker 
CaptureTextureEnvironmentState(std::vector<CallCapture> * setupCalls,gl::State * replayState,const gl::State * apiState,unsigned int unit)3240*8975f5c5SAndroid Build Coastguard Worker void CaptureTextureEnvironmentState(std::vector<CallCapture> *setupCalls,
3241*8975f5c5SAndroid Build Coastguard Worker                                     gl::State *replayState,
3242*8975f5c5SAndroid Build Coastguard Worker                                     const gl::State *apiState,
3243*8975f5c5SAndroid Build Coastguard Worker                                     unsigned int unit)
3244*8975f5c5SAndroid Build Coastguard Worker {
3245*8975f5c5SAndroid Build Coastguard Worker     const gl::TextureEnvironmentParameters &currentEnv = apiState->gles1().textureEnvironment(unit);
3246*8975f5c5SAndroid Build Coastguard Worker     const gl::TextureEnvironmentParameters &defaultEnv =
3247*8975f5c5SAndroid Build Coastguard Worker         replayState->gles1().textureEnvironment(unit);
3248*8975f5c5SAndroid Build Coastguard Worker 
3249*8975f5c5SAndroid Build Coastguard Worker     if (currentEnv == defaultEnv)
3250*8975f5c5SAndroid Build Coastguard Worker     {
3251*8975f5c5SAndroid Build Coastguard Worker         return;
3252*8975f5c5SAndroid Build Coastguard Worker     }
3253*8975f5c5SAndroid Build Coastguard Worker 
3254*8975f5c5SAndroid Build Coastguard Worker     auto capIfNe = [setupCalls](auto currentState, auto defaultState, CallCapture &&call) {
3255*8975f5c5SAndroid Build Coastguard Worker         if (currentState != defaultState)
3256*8975f5c5SAndroid Build Coastguard Worker         {
3257*8975f5c5SAndroid Build Coastguard Worker             setupCalls->emplace_back(std::move(call));
3258*8975f5c5SAndroid Build Coastguard Worker         }
3259*8975f5c5SAndroid Build Coastguard Worker     };
3260*8975f5c5SAndroid Build Coastguard Worker 
3261*8975f5c5SAndroid Build Coastguard Worker     // When the texture env state differs on a non-default sampler unit, emit an ActiveTexture call.
3262*8975f5c5SAndroid Build Coastguard Worker     // The default sampler unit is GL_TEXTURE0.
3263*8975f5c5SAndroid Build Coastguard Worker     GLenum currentUnit = GL_TEXTURE0 + static_cast<GLenum>(unit);
3264*8975f5c5SAndroid Build Coastguard Worker     GLenum defaultUnit = GL_TEXTURE0 + static_cast<GLenum>(replayState->getActiveSampler());
3265*8975f5c5SAndroid Build Coastguard Worker     capIfNe(currentUnit, defaultUnit, CaptureActiveTexture(*replayState, true, currentUnit));
3266*8975f5c5SAndroid Build Coastguard Worker 
3267*8975f5c5SAndroid Build Coastguard Worker     auto capEnum = [capIfNe, replayState](gl::TextureEnvParameter pname, auto currentState,
3268*8975f5c5SAndroid Build Coastguard Worker                                           auto defaultState) {
3269*8975f5c5SAndroid Build Coastguard Worker         capIfNe(currentState, defaultState,
3270*8975f5c5SAndroid Build Coastguard Worker                 CaptureTexEnvi(*replayState, true, gl::TextureEnvTarget::Env, pname,
3271*8975f5c5SAndroid Build Coastguard Worker                                ToGLenum(currentState)));
3272*8975f5c5SAndroid Build Coastguard Worker     };
3273*8975f5c5SAndroid Build Coastguard Worker 
3274*8975f5c5SAndroid Build Coastguard Worker     capEnum(gl::TextureEnvParameter::Mode, currentEnv.mode, defaultEnv.mode);
3275*8975f5c5SAndroid Build Coastguard Worker 
3276*8975f5c5SAndroid Build Coastguard Worker     capEnum(gl::TextureEnvParameter::CombineRgb, currentEnv.combineRgb, defaultEnv.combineRgb);
3277*8975f5c5SAndroid Build Coastguard Worker     capEnum(gl::TextureEnvParameter::CombineAlpha, currentEnv.combineAlpha,
3278*8975f5c5SAndroid Build Coastguard Worker             defaultEnv.combineAlpha);
3279*8975f5c5SAndroid Build Coastguard Worker 
3280*8975f5c5SAndroid Build Coastguard Worker     capEnum(gl::TextureEnvParameter::Src0Rgb, currentEnv.src0Rgb, defaultEnv.src0Rgb);
3281*8975f5c5SAndroid Build Coastguard Worker     capEnum(gl::TextureEnvParameter::Src1Rgb, currentEnv.src1Rgb, defaultEnv.src1Rgb);
3282*8975f5c5SAndroid Build Coastguard Worker     capEnum(gl::TextureEnvParameter::Src2Rgb, currentEnv.src2Rgb, defaultEnv.src2Rgb);
3283*8975f5c5SAndroid Build Coastguard Worker 
3284*8975f5c5SAndroid Build Coastguard Worker     capEnum(gl::TextureEnvParameter::Src0Alpha, currentEnv.src0Alpha, defaultEnv.src0Alpha);
3285*8975f5c5SAndroid Build Coastguard Worker     capEnum(gl::TextureEnvParameter::Src1Alpha, currentEnv.src1Alpha, defaultEnv.src1Alpha);
3286*8975f5c5SAndroid Build Coastguard Worker     capEnum(gl::TextureEnvParameter::Src2Alpha, currentEnv.src2Alpha, defaultEnv.src2Alpha);
3287*8975f5c5SAndroid Build Coastguard Worker 
3288*8975f5c5SAndroid Build Coastguard Worker     capEnum(gl::TextureEnvParameter::Op0Rgb, currentEnv.op0Rgb, defaultEnv.op0Rgb);
3289*8975f5c5SAndroid Build Coastguard Worker     capEnum(gl::TextureEnvParameter::Op1Rgb, currentEnv.op1Rgb, defaultEnv.op1Rgb);
3290*8975f5c5SAndroid Build Coastguard Worker     capEnum(gl::TextureEnvParameter::Op2Rgb, currentEnv.op2Rgb, defaultEnv.op2Rgb);
3291*8975f5c5SAndroid Build Coastguard Worker 
3292*8975f5c5SAndroid Build Coastguard Worker     capEnum(gl::TextureEnvParameter::Op0Alpha, currentEnv.op0Alpha, defaultEnv.op0Alpha);
3293*8975f5c5SAndroid Build Coastguard Worker     capEnum(gl::TextureEnvParameter::Op1Alpha, currentEnv.op1Alpha, defaultEnv.op1Alpha);
3294*8975f5c5SAndroid Build Coastguard Worker     capEnum(gl::TextureEnvParameter::Op2Alpha, currentEnv.op2Alpha, defaultEnv.op2Alpha);
3295*8975f5c5SAndroid Build Coastguard Worker 
3296*8975f5c5SAndroid Build Coastguard Worker     auto capFloat = [capIfNe, replayState](gl::TextureEnvParameter pname, auto currentState,
3297*8975f5c5SAndroid Build Coastguard Worker                                            auto defaultState) {
3298*8975f5c5SAndroid Build Coastguard Worker         capIfNe(currentState, defaultState,
3299*8975f5c5SAndroid Build Coastguard Worker                 CaptureTexEnvf(*replayState, true, gl::TextureEnvTarget::Env, pname, currentState));
3300*8975f5c5SAndroid Build Coastguard Worker     };
3301*8975f5c5SAndroid Build Coastguard Worker 
3302*8975f5c5SAndroid Build Coastguard Worker     capFloat(gl::TextureEnvParameter::RgbScale, currentEnv.rgbScale, defaultEnv.rgbScale);
3303*8975f5c5SAndroid Build Coastguard Worker     capFloat(gl::TextureEnvParameter::AlphaScale, currentEnv.alphaScale, defaultEnv.alphaScale);
3304*8975f5c5SAndroid Build Coastguard Worker 
3305*8975f5c5SAndroid Build Coastguard Worker     capIfNe(currentEnv.color, defaultEnv.color,
3306*8975f5c5SAndroid Build Coastguard Worker             CaptureTexEnvfv(*replayState, true, gl::TextureEnvTarget::Env,
3307*8975f5c5SAndroid Build Coastguard Worker                             gl::TextureEnvParameter::Color, currentEnv.color.data()));
3308*8975f5c5SAndroid Build Coastguard Worker 
3309*8975f5c5SAndroid Build Coastguard Worker     // PointCoordReplace is the only parameter that uses the PointSprite TextureEnvTarget.
3310*8975f5c5SAndroid Build Coastguard Worker     capIfNe(currentEnv.pointSpriteCoordReplace, defaultEnv.pointSpriteCoordReplace,
3311*8975f5c5SAndroid Build Coastguard Worker             CaptureTexEnvi(*replayState, true, gl::TextureEnvTarget::PointSprite,
3312*8975f5c5SAndroid Build Coastguard Worker                            gl::TextureEnvParameter::PointCoordReplace,
3313*8975f5c5SAndroid Build Coastguard Worker                            currentEnv.pointSpriteCoordReplace));
3314*8975f5c5SAndroid Build Coastguard Worker 
3315*8975f5c5SAndroid Build Coastguard Worker     // In case of non-default sampler units, the default unit must be set back here.
3316*8975f5c5SAndroid Build Coastguard Worker     capIfNe(currentUnit, defaultUnit, CaptureActiveTexture(*replayState, true, defaultUnit));
3317*8975f5c5SAndroid Build Coastguard Worker }
3318*8975f5c5SAndroid Build Coastguard Worker 
VertexBindingMatchesAttribStride(const gl::VertexAttribute & attrib,const gl::VertexBinding & binding)3319*8975f5c5SAndroid Build Coastguard Worker bool VertexBindingMatchesAttribStride(const gl::VertexAttribute &attrib,
3320*8975f5c5SAndroid Build Coastguard Worker                                       const gl::VertexBinding &binding)
3321*8975f5c5SAndroid Build Coastguard Worker {
3322*8975f5c5SAndroid Build Coastguard Worker     if (attrib.vertexAttribArrayStride == 0 &&
3323*8975f5c5SAndroid Build Coastguard Worker         binding.getStride() == ComputeVertexAttributeTypeSize(attrib))
3324*8975f5c5SAndroid Build Coastguard Worker     {
3325*8975f5c5SAndroid Build Coastguard Worker         return true;
3326*8975f5c5SAndroid Build Coastguard Worker     }
3327*8975f5c5SAndroid Build Coastguard Worker 
3328*8975f5c5SAndroid Build Coastguard Worker     return attrib.vertexAttribArrayStride == binding.getStride();
3329*8975f5c5SAndroid Build Coastguard Worker }
3330*8975f5c5SAndroid Build Coastguard Worker 
CaptureVertexArrayState(std::vector<CallCapture> * setupCalls,const gl::Context * context,const gl::VertexArray * vertexArray,gl::State * replayState)3331*8975f5c5SAndroid Build Coastguard Worker void CaptureVertexArrayState(std::vector<CallCapture> *setupCalls,
3332*8975f5c5SAndroid Build Coastguard Worker                              const gl::Context *context,
3333*8975f5c5SAndroid Build Coastguard Worker                              const gl::VertexArray *vertexArray,
3334*8975f5c5SAndroid Build Coastguard Worker                              gl::State *replayState)
3335*8975f5c5SAndroid Build Coastguard Worker {
3336*8975f5c5SAndroid Build Coastguard Worker     const std::vector<gl::VertexAttribute> &vertexAttribs = vertexArray->getVertexAttributes();
3337*8975f5c5SAndroid Build Coastguard Worker     const std::vector<gl::VertexBinding> &vertexBindings  = vertexArray->getVertexBindings();
3338*8975f5c5SAndroid Build Coastguard Worker 
3339*8975f5c5SAndroid Build Coastguard Worker     gl::AttributesMask vertexPointerBindings;
3340*8975f5c5SAndroid Build Coastguard Worker 
3341*8975f5c5SAndroid Build Coastguard Worker     ASSERT(vertexAttribs.size() <= vertexBindings.size());
3342*8975f5c5SAndroid Build Coastguard Worker     for (GLuint attribIndex = 0; attribIndex < vertexAttribs.size(); ++attribIndex)
3343*8975f5c5SAndroid Build Coastguard Worker     {
3344*8975f5c5SAndroid Build Coastguard Worker         const gl::VertexAttribute defaultAttrib(attribIndex);
3345*8975f5c5SAndroid Build Coastguard Worker         const gl::VertexBinding defaultBinding;
3346*8975f5c5SAndroid Build Coastguard Worker 
3347*8975f5c5SAndroid Build Coastguard Worker         const gl::VertexAttribute &attrib = vertexAttribs[attribIndex];
3348*8975f5c5SAndroid Build Coastguard Worker         const gl::VertexBinding &binding  = vertexBindings[attrib.bindingIndex];
3349*8975f5c5SAndroid Build Coastguard Worker 
3350*8975f5c5SAndroid Build Coastguard Worker         if (attrib.enabled != defaultAttrib.enabled)
3351*8975f5c5SAndroid Build Coastguard Worker         {
3352*8975f5c5SAndroid Build Coastguard Worker             if (context->isGLES1())
3353*8975f5c5SAndroid Build Coastguard Worker             {
3354*8975f5c5SAndroid Build Coastguard Worker                 Capture(setupCalls,
3355*8975f5c5SAndroid Build Coastguard Worker                         CaptureEnableClientState(*replayState, false,
3356*8975f5c5SAndroid Build Coastguard Worker                                                  gl::GLES1Renderer::VertexArrayType(attribIndex)));
3357*8975f5c5SAndroid Build Coastguard Worker             }
3358*8975f5c5SAndroid Build Coastguard Worker             else
3359*8975f5c5SAndroid Build Coastguard Worker             {
3360*8975f5c5SAndroid Build Coastguard Worker                 Capture(setupCalls,
3361*8975f5c5SAndroid Build Coastguard Worker                         CaptureEnableVertexAttribArray(*replayState, false, attribIndex));
3362*8975f5c5SAndroid Build Coastguard Worker             }
3363*8975f5c5SAndroid Build Coastguard Worker         }
3364*8975f5c5SAndroid Build Coastguard Worker 
3365*8975f5c5SAndroid Build Coastguard Worker         // Don't capture CaptureVertexAttribPointer calls when a non-default VAO is bound, the array
3366*8975f5c5SAndroid Build Coastguard Worker         // buffer is null and a non-null attrib pointer is used.
3367*8975f5c5SAndroid Build Coastguard Worker         bool skipInvalidAttrib = vertexArray->id().value != 0 &&
3368*8975f5c5SAndroid Build Coastguard Worker                                  binding.getBuffer().get() == nullptr && attrib.pointer != nullptr;
3369*8975f5c5SAndroid Build Coastguard Worker 
3370*8975f5c5SAndroid Build Coastguard Worker         if (!skipInvalidAttrib &&
3371*8975f5c5SAndroid Build Coastguard Worker             (attrib.format != defaultAttrib.format || attrib.pointer != defaultAttrib.pointer ||
3372*8975f5c5SAndroid Build Coastguard Worker              binding.getStride() != defaultBinding.getStride() ||
3373*8975f5c5SAndroid Build Coastguard Worker              attrib.bindingIndex != defaultAttrib.bindingIndex ||
3374*8975f5c5SAndroid Build Coastguard Worker              binding.getBuffer().get() != nullptr))
3375*8975f5c5SAndroid Build Coastguard Worker         {
3376*8975f5c5SAndroid Build Coastguard Worker             // Each attribute can pull from a separate buffer, so check the binding
3377*8975f5c5SAndroid Build Coastguard Worker             gl::Buffer *buffer = binding.getBuffer().get();
3378*8975f5c5SAndroid Build Coastguard Worker             if (buffer != replayState->getArrayBuffer())
3379*8975f5c5SAndroid Build Coastguard Worker             {
3380*8975f5c5SAndroid Build Coastguard Worker                 replayState->setBufferBinding(context, gl::BufferBinding::Array, buffer);
3381*8975f5c5SAndroid Build Coastguard Worker 
3382*8975f5c5SAndroid Build Coastguard Worker                 gl::BufferID bufferID = {0};
3383*8975f5c5SAndroid Build Coastguard Worker                 if (buffer)
3384*8975f5c5SAndroid Build Coastguard Worker                 {
3385*8975f5c5SAndroid Build Coastguard Worker                     bufferID = buffer->id();
3386*8975f5c5SAndroid Build Coastguard Worker                 }
3387*8975f5c5SAndroid Build Coastguard Worker                 Capture(setupCalls,
3388*8975f5c5SAndroid Build Coastguard Worker                         CaptureBindBuffer(*replayState, true, gl::BufferBinding::Array, bufferID));
3389*8975f5c5SAndroid Build Coastguard Worker             }
3390*8975f5c5SAndroid Build Coastguard Worker 
3391*8975f5c5SAndroid Build Coastguard Worker             // Establish the relationship between currently bound buffer and the VAO
3392*8975f5c5SAndroid Build Coastguard Worker             if (context->isGLES1())
3393*8975f5c5SAndroid Build Coastguard Worker             {
3394*8975f5c5SAndroid Build Coastguard Worker                 // Track indexes that used ES1 calls
3395*8975f5c5SAndroid Build Coastguard Worker                 vertexPointerBindings.set(attribIndex);
3396*8975f5c5SAndroid Build Coastguard Worker 
3397*8975f5c5SAndroid Build Coastguard Worker                 CaptureVertexPointerES1(setupCalls, replayState, attribIndex, attrib, binding);
3398*8975f5c5SAndroid Build Coastguard Worker             }
3399*8975f5c5SAndroid Build Coastguard Worker             else if (attrib.bindingIndex == attribIndex &&
3400*8975f5c5SAndroid Build Coastguard Worker                      VertexBindingMatchesAttribStride(attrib, binding) &&
3401*8975f5c5SAndroid Build Coastguard Worker                      (!buffer || binding.getOffset() == reinterpret_cast<GLintptr>(attrib.pointer)))
3402*8975f5c5SAndroid Build Coastguard Worker             {
3403*8975f5c5SAndroid Build Coastguard Worker                 // Check if we can use strictly ES2 semantics, and track indexes that do.
3404*8975f5c5SAndroid Build Coastguard Worker                 vertexPointerBindings.set(attribIndex);
3405*8975f5c5SAndroid Build Coastguard Worker 
3406*8975f5c5SAndroid Build Coastguard Worker                 if (attrib.format->isPureInt())
3407*8975f5c5SAndroid Build Coastguard Worker                 {
3408*8975f5c5SAndroid Build Coastguard Worker                     Capture(setupCalls, CaptureVertexAttribIPointer(*replayState, true, attribIndex,
3409*8975f5c5SAndroid Build Coastguard Worker                                                                     attrib.format->channelCount,
3410*8975f5c5SAndroid Build Coastguard Worker                                                                     attrib.format->vertexAttribType,
3411*8975f5c5SAndroid Build Coastguard Worker                                                                     attrib.vertexAttribArrayStride,
3412*8975f5c5SAndroid Build Coastguard Worker                                                                     attrib.pointer));
3413*8975f5c5SAndroid Build Coastguard Worker                 }
3414*8975f5c5SAndroid Build Coastguard Worker                 else
3415*8975f5c5SAndroid Build Coastguard Worker                 {
3416*8975f5c5SAndroid Build Coastguard Worker                     Capture(setupCalls,
3417*8975f5c5SAndroid Build Coastguard Worker                             CaptureVertexAttribPointer(
3418*8975f5c5SAndroid Build Coastguard Worker                                 *replayState, true, attribIndex, attrib.format->channelCount,
3419*8975f5c5SAndroid Build Coastguard Worker                                 attrib.format->vertexAttribType, attrib.format->isNorm(),
3420*8975f5c5SAndroid Build Coastguard Worker                                 attrib.vertexAttribArrayStride, attrib.pointer));
3421*8975f5c5SAndroid Build Coastguard Worker                 }
3422*8975f5c5SAndroid Build Coastguard Worker 
3423*8975f5c5SAndroid Build Coastguard Worker                 if (binding.getDivisor() != 0)
3424*8975f5c5SAndroid Build Coastguard Worker                 {
3425*8975f5c5SAndroid Build Coastguard Worker                     Capture(setupCalls, CaptureVertexAttribDivisor(*replayState, true, attribIndex,
3426*8975f5c5SAndroid Build Coastguard Worker                                                                    binding.getDivisor()));
3427*8975f5c5SAndroid Build Coastguard Worker                 }
3428*8975f5c5SAndroid Build Coastguard Worker             }
3429*8975f5c5SAndroid Build Coastguard Worker             else
3430*8975f5c5SAndroid Build Coastguard Worker             {
3431*8975f5c5SAndroid Build Coastguard Worker                 ASSERT(context->getClientVersion() >= gl::ES_3_1);
3432*8975f5c5SAndroid Build Coastguard Worker 
3433*8975f5c5SAndroid Build Coastguard Worker                 if (attrib.format->isPureInt())
3434*8975f5c5SAndroid Build Coastguard Worker                 {
3435*8975f5c5SAndroid Build Coastguard Worker                     Capture(setupCalls, CaptureVertexAttribIFormat(*replayState, true, attribIndex,
3436*8975f5c5SAndroid Build Coastguard Worker                                                                    attrib.format->channelCount,
3437*8975f5c5SAndroid Build Coastguard Worker                                                                    attrib.format->vertexAttribType,
3438*8975f5c5SAndroid Build Coastguard Worker                                                                    attrib.relativeOffset));
3439*8975f5c5SAndroid Build Coastguard Worker                 }
3440*8975f5c5SAndroid Build Coastguard Worker                 else
3441*8975f5c5SAndroid Build Coastguard Worker                 {
3442*8975f5c5SAndroid Build Coastguard Worker                     Capture(setupCalls, CaptureVertexAttribFormat(*replayState, true, attribIndex,
3443*8975f5c5SAndroid Build Coastguard Worker                                                                   attrib.format->channelCount,
3444*8975f5c5SAndroid Build Coastguard Worker                                                                   attrib.format->vertexAttribType,
3445*8975f5c5SAndroid Build Coastguard Worker                                                                   attrib.format->isNorm(),
3446*8975f5c5SAndroid Build Coastguard Worker                                                                   attrib.relativeOffset));
3447*8975f5c5SAndroid Build Coastguard Worker                 }
3448*8975f5c5SAndroid Build Coastguard Worker 
3449*8975f5c5SAndroid Build Coastguard Worker                 Capture(setupCalls, CaptureVertexAttribBinding(*replayState, true, attribIndex,
3450*8975f5c5SAndroid Build Coastguard Worker                                                                attrib.bindingIndex));
3451*8975f5c5SAndroid Build Coastguard Worker             }
3452*8975f5c5SAndroid Build Coastguard Worker         }
3453*8975f5c5SAndroid Build Coastguard Worker     }
3454*8975f5c5SAndroid Build Coastguard Worker 
3455*8975f5c5SAndroid Build Coastguard Worker     // The loop below expects attribs and bindings to have equal counts
3456*8975f5c5SAndroid Build Coastguard Worker     static_assert(gl::MAX_VERTEX_ATTRIBS == gl::MAX_VERTEX_ATTRIB_BINDINGS,
3457*8975f5c5SAndroid Build Coastguard Worker                   "Max vertex attribs and bindings count mismatch");
3458*8975f5c5SAndroid Build Coastguard Worker 
3459*8975f5c5SAndroid Build Coastguard Worker     // Loop through binding indices that weren't used by VertexAttribPointer
3460*8975f5c5SAndroid Build Coastguard Worker     for (size_t bindingIndex : vertexPointerBindings.flip())
3461*8975f5c5SAndroid Build Coastguard Worker     {
3462*8975f5c5SAndroid Build Coastguard Worker         const gl::VertexBinding &binding = vertexBindings[bindingIndex];
3463*8975f5c5SAndroid Build Coastguard Worker 
3464*8975f5c5SAndroid Build Coastguard Worker         if (binding.getBuffer().id().value != 0)
3465*8975f5c5SAndroid Build Coastguard Worker         {
3466*8975f5c5SAndroid Build Coastguard Worker             Capture(setupCalls,
3467*8975f5c5SAndroid Build Coastguard Worker                     CaptureBindVertexBuffer(*replayState, true, static_cast<GLuint>(bindingIndex),
3468*8975f5c5SAndroid Build Coastguard Worker                                             binding.getBuffer().id(), binding.getOffset(),
3469*8975f5c5SAndroid Build Coastguard Worker                                             binding.getStride()));
3470*8975f5c5SAndroid Build Coastguard Worker         }
3471*8975f5c5SAndroid Build Coastguard Worker 
3472*8975f5c5SAndroid Build Coastguard Worker         if (binding.getDivisor() != 0)
3473*8975f5c5SAndroid Build Coastguard Worker         {
3474*8975f5c5SAndroid Build Coastguard Worker             Capture(setupCalls, CaptureVertexBindingDivisor(*replayState, true,
3475*8975f5c5SAndroid Build Coastguard Worker                                                             static_cast<GLuint>(bindingIndex),
3476*8975f5c5SAndroid Build Coastguard Worker                                                             binding.getDivisor()));
3477*8975f5c5SAndroid Build Coastguard Worker         }
3478*8975f5c5SAndroid Build Coastguard Worker     }
3479*8975f5c5SAndroid Build Coastguard Worker 
3480*8975f5c5SAndroid Build Coastguard Worker     // The element array buffer is not per attribute, but per VAO
3481*8975f5c5SAndroid Build Coastguard Worker     gl::Buffer *elementArrayBuffer = vertexArray->getElementArrayBuffer();
3482*8975f5c5SAndroid Build Coastguard Worker     if (elementArrayBuffer)
3483*8975f5c5SAndroid Build Coastguard Worker     {
3484*8975f5c5SAndroid Build Coastguard Worker         Capture(setupCalls, CaptureBindBuffer(*replayState, true, gl::BufferBinding::ElementArray,
3485*8975f5c5SAndroid Build Coastguard Worker                                               elementArrayBuffer->id()));
3486*8975f5c5SAndroid Build Coastguard Worker     }
3487*8975f5c5SAndroid Build Coastguard Worker }
3488*8975f5c5SAndroid Build Coastguard Worker 
CaptureTextureStorage(std::vector<CallCapture> * setupCalls,gl::State * replayState,const gl::Texture * texture)3489*8975f5c5SAndroid Build Coastguard Worker void CaptureTextureStorage(std::vector<CallCapture> *setupCalls,
3490*8975f5c5SAndroid Build Coastguard Worker                            gl::State *replayState,
3491*8975f5c5SAndroid Build Coastguard Worker                            const gl::Texture *texture)
3492*8975f5c5SAndroid Build Coastguard Worker {
3493*8975f5c5SAndroid Build Coastguard Worker     // Use mip-level 0 for the base dimensions
3494*8975f5c5SAndroid Build Coastguard Worker     gl::ImageIndex imageIndex = gl::ImageIndex::MakeFromType(texture->getType(), 0);
3495*8975f5c5SAndroid Build Coastguard Worker     const gl::ImageDesc &desc = texture->getTextureState().getImageDesc(imageIndex);
3496*8975f5c5SAndroid Build Coastguard Worker 
3497*8975f5c5SAndroid Build Coastguard Worker     switch (texture->getType())
3498*8975f5c5SAndroid Build Coastguard Worker     {
3499*8975f5c5SAndroid Build Coastguard Worker         case gl::TextureType::_2D:
3500*8975f5c5SAndroid Build Coastguard Worker         case gl::TextureType::CubeMap:
3501*8975f5c5SAndroid Build Coastguard Worker         {
3502*8975f5c5SAndroid Build Coastguard Worker             Capture(setupCalls, CaptureTexStorage2D(*replayState, true, texture->getType(),
3503*8975f5c5SAndroid Build Coastguard Worker                                                     texture->getImmutableLevels(),
3504*8975f5c5SAndroid Build Coastguard Worker                                                     desc.format.info->internalFormat,
3505*8975f5c5SAndroid Build Coastguard Worker                                                     desc.size.width, desc.size.height));
3506*8975f5c5SAndroid Build Coastguard Worker             break;
3507*8975f5c5SAndroid Build Coastguard Worker         }
3508*8975f5c5SAndroid Build Coastguard Worker         case gl::TextureType::_3D:
3509*8975f5c5SAndroid Build Coastguard Worker         case gl::TextureType::_2DArray:
3510*8975f5c5SAndroid Build Coastguard Worker         case gl::TextureType::CubeMapArray:
3511*8975f5c5SAndroid Build Coastguard Worker         {
3512*8975f5c5SAndroid Build Coastguard Worker             Capture(setupCalls, CaptureTexStorage3D(
3513*8975f5c5SAndroid Build Coastguard Worker                                     *replayState, true, texture->getType(),
3514*8975f5c5SAndroid Build Coastguard Worker                                     texture->getImmutableLevels(), desc.format.info->internalFormat,
3515*8975f5c5SAndroid Build Coastguard Worker                                     desc.size.width, desc.size.height, desc.size.depth));
3516*8975f5c5SAndroid Build Coastguard Worker             break;
3517*8975f5c5SAndroid Build Coastguard Worker         }
3518*8975f5c5SAndroid Build Coastguard Worker         case gl::TextureType::Buffer:
3519*8975f5c5SAndroid Build Coastguard Worker         {
3520*8975f5c5SAndroid Build Coastguard Worker             // Do nothing. This will already be captured as a buffer.
3521*8975f5c5SAndroid Build Coastguard Worker             break;
3522*8975f5c5SAndroid Build Coastguard Worker         }
3523*8975f5c5SAndroid Build Coastguard Worker         default:
3524*8975f5c5SAndroid Build Coastguard Worker             UNIMPLEMENTED();
3525*8975f5c5SAndroid Build Coastguard Worker             break;
3526*8975f5c5SAndroid Build Coastguard Worker     }
3527*8975f5c5SAndroid Build Coastguard Worker }
3528*8975f5c5SAndroid Build Coastguard Worker 
CaptureTextureContents(std::vector<CallCapture> * setupCalls,gl::State * replayState,const gl::Texture * texture,const gl::ImageIndex & index,const gl::ImageDesc & desc,GLuint size,const void * data)3529*8975f5c5SAndroid Build Coastguard Worker void CaptureTextureContents(std::vector<CallCapture> *setupCalls,
3530*8975f5c5SAndroid Build Coastguard Worker                             gl::State *replayState,
3531*8975f5c5SAndroid Build Coastguard Worker                             const gl::Texture *texture,
3532*8975f5c5SAndroid Build Coastguard Worker                             const gl::ImageIndex &index,
3533*8975f5c5SAndroid Build Coastguard Worker                             const gl::ImageDesc &desc,
3534*8975f5c5SAndroid Build Coastguard Worker                             GLuint size,
3535*8975f5c5SAndroid Build Coastguard Worker                             const void *data)
3536*8975f5c5SAndroid Build Coastguard Worker {
3537*8975f5c5SAndroid Build Coastguard Worker     const gl::InternalFormat &format = *desc.format.info;
3538*8975f5c5SAndroid Build Coastguard Worker 
3539*8975f5c5SAndroid Build Coastguard Worker     if (index.getType() == gl::TextureType::Buffer)
3540*8975f5c5SAndroid Build Coastguard Worker     {
3541*8975f5c5SAndroid Build Coastguard Worker         // Zero binding size indicates full buffer bound
3542*8975f5c5SAndroid Build Coastguard Worker         if (texture->getBuffer().getSize() == 0)
3543*8975f5c5SAndroid Build Coastguard Worker         {
3544*8975f5c5SAndroid Build Coastguard Worker             Capture(setupCalls,
3545*8975f5c5SAndroid Build Coastguard Worker                     CaptureTexBufferEXT(*replayState, true, index.getType(), format.internalFormat,
3546*8975f5c5SAndroid Build Coastguard Worker                                         texture->getBuffer().get()->id()));
3547*8975f5c5SAndroid Build Coastguard Worker         }
3548*8975f5c5SAndroid Build Coastguard Worker         else
3549*8975f5c5SAndroid Build Coastguard Worker         {
3550*8975f5c5SAndroid Build Coastguard Worker             Capture(setupCalls, CaptureTexBufferRangeEXT(*replayState, true, index.getType(),
3551*8975f5c5SAndroid Build Coastguard Worker                                                          format.internalFormat,
3552*8975f5c5SAndroid Build Coastguard Worker                                                          texture->getBuffer().get()->id(),
3553*8975f5c5SAndroid Build Coastguard Worker                                                          texture->getBuffer().getOffset(),
3554*8975f5c5SAndroid Build Coastguard Worker                                                          texture->getBuffer().getSize()));
3555*8975f5c5SAndroid Build Coastguard Worker         }
3556*8975f5c5SAndroid Build Coastguard Worker 
3557*8975f5c5SAndroid Build Coastguard Worker         // For buffers, we're done
3558*8975f5c5SAndroid Build Coastguard Worker         return;
3559*8975f5c5SAndroid Build Coastguard Worker     }
3560*8975f5c5SAndroid Build Coastguard Worker 
3561*8975f5c5SAndroid Build Coastguard Worker     bool is3D =
3562*8975f5c5SAndroid Build Coastguard Worker         (index.getType() == gl::TextureType::_3D || index.getType() == gl::TextureType::_2DArray ||
3563*8975f5c5SAndroid Build Coastguard Worker          index.getType() == gl::TextureType::CubeMapArray);
3564*8975f5c5SAndroid Build Coastguard Worker 
3565*8975f5c5SAndroid Build Coastguard Worker     if (format.compressed || format.paletted)
3566*8975f5c5SAndroid Build Coastguard Worker     {
3567*8975f5c5SAndroid Build Coastguard Worker         if (is3D)
3568*8975f5c5SAndroid Build Coastguard Worker         {
3569*8975f5c5SAndroid Build Coastguard Worker             if (texture->getImmutableFormat())
3570*8975f5c5SAndroid Build Coastguard Worker             {
3571*8975f5c5SAndroid Build Coastguard Worker                 Capture(setupCalls,
3572*8975f5c5SAndroid Build Coastguard Worker                         CaptureCompressedTexSubImage3D(
3573*8975f5c5SAndroid Build Coastguard Worker                             *replayState, true, index.getTarget(), index.getLevelIndex(), 0, 0, 0,
3574*8975f5c5SAndroid Build Coastguard Worker                             desc.size.width, desc.size.height, desc.size.depth,
3575*8975f5c5SAndroid Build Coastguard Worker                             format.internalFormat, size, data));
3576*8975f5c5SAndroid Build Coastguard Worker             }
3577*8975f5c5SAndroid Build Coastguard Worker             else
3578*8975f5c5SAndroid Build Coastguard Worker             {
3579*8975f5c5SAndroid Build Coastguard Worker                 Capture(setupCalls,
3580*8975f5c5SAndroid Build Coastguard Worker                         CaptureCompressedTexImage3D(*replayState, true, index.getTarget(),
3581*8975f5c5SAndroid Build Coastguard Worker                                                     index.getLevelIndex(), format.internalFormat,
3582*8975f5c5SAndroid Build Coastguard Worker                                                     desc.size.width, desc.size.height,
3583*8975f5c5SAndroid Build Coastguard Worker                                                     desc.size.depth, 0, size, data));
3584*8975f5c5SAndroid Build Coastguard Worker             }
3585*8975f5c5SAndroid Build Coastguard Worker         }
3586*8975f5c5SAndroid Build Coastguard Worker         else
3587*8975f5c5SAndroid Build Coastguard Worker         {
3588*8975f5c5SAndroid Build Coastguard Worker             if (texture->getImmutableFormat())
3589*8975f5c5SAndroid Build Coastguard Worker             {
3590*8975f5c5SAndroid Build Coastguard Worker                 Capture(setupCalls,
3591*8975f5c5SAndroid Build Coastguard Worker                         CaptureCompressedTexSubImage2D(
3592*8975f5c5SAndroid Build Coastguard Worker                             *replayState, true, index.getTarget(), index.getLevelIndex(), 0, 0,
3593*8975f5c5SAndroid Build Coastguard Worker                             desc.size.width, desc.size.height, format.internalFormat, size, data));
3594*8975f5c5SAndroid Build Coastguard Worker             }
3595*8975f5c5SAndroid Build Coastguard Worker             else
3596*8975f5c5SAndroid Build Coastguard Worker             {
3597*8975f5c5SAndroid Build Coastguard Worker                 Capture(setupCalls, CaptureCompressedTexImage2D(
3598*8975f5c5SAndroid Build Coastguard Worker                                         *replayState, true, index.getTarget(),
3599*8975f5c5SAndroid Build Coastguard Worker                                         index.getLevelIndex(), format.internalFormat,
3600*8975f5c5SAndroid Build Coastguard Worker                                         desc.size.width, desc.size.height, 0, size, data));
3601*8975f5c5SAndroid Build Coastguard Worker             }
3602*8975f5c5SAndroid Build Coastguard Worker         }
3603*8975f5c5SAndroid Build Coastguard Worker     }
3604*8975f5c5SAndroid Build Coastguard Worker     else
3605*8975f5c5SAndroid Build Coastguard Worker     {
3606*8975f5c5SAndroid Build Coastguard Worker         if (is3D)
3607*8975f5c5SAndroid Build Coastguard Worker         {
3608*8975f5c5SAndroid Build Coastguard Worker             if (texture->getImmutableFormat())
3609*8975f5c5SAndroid Build Coastguard Worker             {
3610*8975f5c5SAndroid Build Coastguard Worker                 Capture(setupCalls,
3611*8975f5c5SAndroid Build Coastguard Worker                         CaptureTexSubImage3D(*replayState, true, index.getTarget(),
3612*8975f5c5SAndroid Build Coastguard Worker                                              index.getLevelIndex(), 0, 0, 0, desc.size.width,
3613*8975f5c5SAndroid Build Coastguard Worker                                              desc.size.height, desc.size.depth, format.format,
3614*8975f5c5SAndroid Build Coastguard Worker                                              format.type, data));
3615*8975f5c5SAndroid Build Coastguard Worker             }
3616*8975f5c5SAndroid Build Coastguard Worker             else
3617*8975f5c5SAndroid Build Coastguard Worker             {
3618*8975f5c5SAndroid Build Coastguard Worker                 Capture(
3619*8975f5c5SAndroid Build Coastguard Worker                     setupCalls,
3620*8975f5c5SAndroid Build Coastguard Worker                     CaptureTexImage3D(*replayState, true, index.getTarget(), index.getLevelIndex(),
3621*8975f5c5SAndroid Build Coastguard Worker                                       format.internalFormat, desc.size.width, desc.size.height,
3622*8975f5c5SAndroid Build Coastguard Worker                                       desc.size.depth, 0, format.format, format.type, data));
3623*8975f5c5SAndroid Build Coastguard Worker             }
3624*8975f5c5SAndroid Build Coastguard Worker         }
3625*8975f5c5SAndroid Build Coastguard Worker         else
3626*8975f5c5SAndroid Build Coastguard Worker         {
3627*8975f5c5SAndroid Build Coastguard Worker             if (texture->getImmutableFormat())
3628*8975f5c5SAndroid Build Coastguard Worker             {
3629*8975f5c5SAndroid Build Coastguard Worker                 Capture(setupCalls,
3630*8975f5c5SAndroid Build Coastguard Worker                         CaptureTexSubImage2D(*replayState, true, index.getTarget(),
3631*8975f5c5SAndroid Build Coastguard Worker                                              index.getLevelIndex(), 0, 0, desc.size.width,
3632*8975f5c5SAndroid Build Coastguard Worker                                              desc.size.height, format.format, format.type, data));
3633*8975f5c5SAndroid Build Coastguard Worker             }
3634*8975f5c5SAndroid Build Coastguard Worker             else
3635*8975f5c5SAndroid Build Coastguard Worker             {
3636*8975f5c5SAndroid Build Coastguard Worker                 Capture(setupCalls, CaptureTexImage2D(*replayState, true, index.getTarget(),
3637*8975f5c5SAndroid Build Coastguard Worker                                                       index.getLevelIndex(), format.internalFormat,
3638*8975f5c5SAndroid Build Coastguard Worker                                                       desc.size.width, desc.size.height, 0,
3639*8975f5c5SAndroid Build Coastguard Worker                                                       format.format, format.type, data));
3640*8975f5c5SAndroid Build Coastguard Worker             }
3641*8975f5c5SAndroid Build Coastguard Worker         }
3642*8975f5c5SAndroid Build Coastguard Worker     }
3643*8975f5c5SAndroid Build Coastguard Worker }
3644*8975f5c5SAndroid Build Coastguard Worker 
CaptureCustomUniformBlockBinding(const CallCapture & callIn,std::vector<CallCapture> & callsOut)3645*8975f5c5SAndroid Build Coastguard Worker void CaptureCustomUniformBlockBinding(const CallCapture &callIn, std::vector<CallCapture> &callsOut)
3646*8975f5c5SAndroid Build Coastguard Worker {
3647*8975f5c5SAndroid Build Coastguard Worker     const ParamBuffer &paramsIn = callIn.params;
3648*8975f5c5SAndroid Build Coastguard Worker 
3649*8975f5c5SAndroid Build Coastguard Worker     const ParamCapture &programID =
3650*8975f5c5SAndroid Build Coastguard Worker         paramsIn.getParam("programPacked", ParamType::TShaderProgramID, 0);
3651*8975f5c5SAndroid Build Coastguard Worker     const ParamCapture &blockIndex =
3652*8975f5c5SAndroid Build Coastguard Worker         paramsIn.getParam("uniformBlockIndexPacked", ParamType::TUniformBlockIndex, 1);
3653*8975f5c5SAndroid Build Coastguard Worker     const ParamCapture &blockBinding =
3654*8975f5c5SAndroid Build Coastguard Worker         paramsIn.getParam("uniformBlockBinding", ParamType::TGLuint, 2);
3655*8975f5c5SAndroid Build Coastguard Worker 
3656*8975f5c5SAndroid Build Coastguard Worker     ParamBuffer params;
3657*8975f5c5SAndroid Build Coastguard Worker     params.addValueParam("program", ParamType::TGLuint, programID.value.ShaderProgramIDVal.value);
3658*8975f5c5SAndroid Build Coastguard Worker     params.addValueParam("uniformBlockIndex", ParamType::TGLuint,
3659*8975f5c5SAndroid Build Coastguard Worker                          blockIndex.value.UniformBlockIndexVal.value);
3660*8975f5c5SAndroid Build Coastguard Worker     params.addValueParam("uniformBlockBinding", ParamType::TGLuint, blockBinding.value.GLuintVal);
3661*8975f5c5SAndroid Build Coastguard Worker 
3662*8975f5c5SAndroid Build Coastguard Worker     callsOut.emplace_back("UniformBlockBinding", std::move(params));
3663*8975f5c5SAndroid Build Coastguard Worker }
3664*8975f5c5SAndroid Build Coastguard Worker 
CaptureCustomMapBuffer(const char * entryPointName,CallCapture & call,std::vector<CallCapture> & callsOut,gl::BufferID mappedBufferID)3665*8975f5c5SAndroid Build Coastguard Worker void CaptureCustomMapBuffer(const char *entryPointName,
3666*8975f5c5SAndroid Build Coastguard Worker                             CallCapture &call,
3667*8975f5c5SAndroid Build Coastguard Worker                             std::vector<CallCapture> &callsOut,
3668*8975f5c5SAndroid Build Coastguard Worker                             gl::BufferID mappedBufferID)
3669*8975f5c5SAndroid Build Coastguard Worker {
3670*8975f5c5SAndroid Build Coastguard Worker     call.params.addValueParam("buffer", ParamType::TGLuint, mappedBufferID.value);
3671*8975f5c5SAndroid Build Coastguard Worker     callsOut.emplace_back(entryPointName, std::move(call.params));
3672*8975f5c5SAndroid Build Coastguard Worker }
3673*8975f5c5SAndroid Build Coastguard Worker 
CaptureCustomShaderProgram(const char * name,CallCapture & call,std::vector<CallCapture> & callsOut)3674*8975f5c5SAndroid Build Coastguard Worker void CaptureCustomShaderProgram(const char *name,
3675*8975f5c5SAndroid Build Coastguard Worker                                 CallCapture &call,
3676*8975f5c5SAndroid Build Coastguard Worker                                 std::vector<CallCapture> &callsOut)
3677*8975f5c5SAndroid Build Coastguard Worker {
3678*8975f5c5SAndroid Build Coastguard Worker     call.params.addValueParam("shaderProgram", ParamType::TGLuint,
3679*8975f5c5SAndroid Build Coastguard Worker                               call.params.getReturnValue().value.GLuintVal);
3680*8975f5c5SAndroid Build Coastguard Worker     call.customFunctionName = name;
3681*8975f5c5SAndroid Build Coastguard Worker     callsOut.emplace_back(std::move(call));
3682*8975f5c5SAndroid Build Coastguard Worker }
3683*8975f5c5SAndroid Build Coastguard Worker 
CaptureCustomFenceSync(CallCapture & call,std::vector<CallCapture> & callsOut)3684*8975f5c5SAndroid Build Coastguard Worker void CaptureCustomFenceSync(CallCapture &call, std::vector<CallCapture> &callsOut)
3685*8975f5c5SAndroid Build Coastguard Worker {
3686*8975f5c5SAndroid Build Coastguard Worker     ParamBuffer &&params = std::move(call.params);
3687*8975f5c5SAndroid Build Coastguard Worker     params.addValueParam("fenceSync", ParamType::TGLuint64,
3688*8975f5c5SAndroid Build Coastguard Worker                          params.getReturnValue().value.GLuint64Val);
3689*8975f5c5SAndroid Build Coastguard Worker     call.customFunctionName = "FenceSync2";
3690*8975f5c5SAndroid Build Coastguard Worker     call.isSyncPoint        = true;
3691*8975f5c5SAndroid Build Coastguard Worker     callsOut.emplace_back(std::move(call));
3692*8975f5c5SAndroid Build Coastguard Worker }
3693*8975f5c5SAndroid Build Coastguard Worker 
GetImageFromParam(const gl::Context * context,const ParamCapture & param)3694*8975f5c5SAndroid Build Coastguard Worker const egl::Image *GetImageFromParam(const gl::Context *context, const ParamCapture &param)
3695*8975f5c5SAndroid Build Coastguard Worker {
3696*8975f5c5SAndroid Build Coastguard Worker     const egl::ImageID eglImageID = egl::PackParam<egl::ImageID>(param.value.EGLImageVal);
3697*8975f5c5SAndroid Build Coastguard Worker     const egl::Image *eglImage    = context->getDisplay()->getImage(eglImageID);
3698*8975f5c5SAndroid Build Coastguard Worker     ASSERT(eglImage != nullptr);
3699*8975f5c5SAndroid Build Coastguard Worker     return eglImage;
3700*8975f5c5SAndroid Build Coastguard Worker }
3701*8975f5c5SAndroid Build Coastguard Worker 
CaptureCustomCreateEGLImage(const gl::Context * context,const char * name,size_t width,size_t height,CallCapture & call,std::vector<CallCapture> & callsOut)3702*8975f5c5SAndroid Build Coastguard Worker void CaptureCustomCreateEGLImage(const gl::Context *context,
3703*8975f5c5SAndroid Build Coastguard Worker                                  const char *name,
3704*8975f5c5SAndroid Build Coastguard Worker                                  size_t width,
3705*8975f5c5SAndroid Build Coastguard Worker                                  size_t height,
3706*8975f5c5SAndroid Build Coastguard Worker                                  CallCapture &call,
3707*8975f5c5SAndroid Build Coastguard Worker                                  std::vector<CallCapture> &callsOut)
3708*8975f5c5SAndroid Build Coastguard Worker {
3709*8975f5c5SAndroid Build Coastguard Worker     ParamBuffer &&params    = std::move(call.params);
3710*8975f5c5SAndroid Build Coastguard Worker     EGLImage returnVal      = params.getReturnValue().value.EGLImageVal;
3711*8975f5c5SAndroid Build Coastguard Worker     egl::ImageID imageID    = egl::PackParam<egl::ImageID>(returnVal);
3712*8975f5c5SAndroid Build Coastguard Worker     call.customFunctionName = name;
3713*8975f5c5SAndroid Build Coastguard Worker 
3714*8975f5c5SAndroid Build Coastguard Worker     // Clear client buffer value if it is a pointer to a hardware buffer. It is
3715*8975f5c5SAndroid Build Coastguard Worker     // not used by replay and will not be portable to 32-bit builds
3716*8975f5c5SAndroid Build Coastguard Worker     if (params.getParam("target", ParamType::TEGLenum, 2).value.EGLenumVal ==
3717*8975f5c5SAndroid Build Coastguard Worker         EGL_NATIVE_BUFFER_ANDROID)
3718*8975f5c5SAndroid Build Coastguard Worker     {
3719*8975f5c5SAndroid Build Coastguard Worker         params.setValueParamAtIndex("buffer", ParamType::TEGLClientBuffer,
3720*8975f5c5SAndroid Build Coastguard Worker                                     reinterpret_cast<EGLClientBuffer>(static_cast<uintptr_t>(0)),
3721*8975f5c5SAndroid Build Coastguard Worker                                     3);
3722*8975f5c5SAndroid Build Coastguard Worker     }
3723*8975f5c5SAndroid Build Coastguard Worker 
3724*8975f5c5SAndroid Build Coastguard Worker     // Record image dimensions in case a backing resource needs to be created during replay
3725*8975f5c5SAndroid Build Coastguard Worker     params.addValueParam("width", ParamType::TGLsizei, static_cast<GLsizei>(width));
3726*8975f5c5SAndroid Build Coastguard Worker     params.addValueParam("height", ParamType::TGLsizei, static_cast<GLsizei>(height));
3727*8975f5c5SAndroid Build Coastguard Worker 
3728*8975f5c5SAndroid Build Coastguard Worker     params.addValueParam("image", ParamType::TGLuint, imageID.value);
3729*8975f5c5SAndroid Build Coastguard Worker     callsOut.emplace_back(std::move(call));
3730*8975f5c5SAndroid Build Coastguard Worker }
3731*8975f5c5SAndroid Build Coastguard Worker 
CaptureCustomDestroyEGLImage(const char * name,CallCapture & call,std::vector<CallCapture> & callsOut)3732*8975f5c5SAndroid Build Coastguard Worker void CaptureCustomDestroyEGLImage(const char *name,
3733*8975f5c5SAndroid Build Coastguard Worker                                   CallCapture &call,
3734*8975f5c5SAndroid Build Coastguard Worker                                   std::vector<CallCapture> &callsOut)
3735*8975f5c5SAndroid Build Coastguard Worker {
3736*8975f5c5SAndroid Build Coastguard Worker     call.customFunctionName = name;
3737*8975f5c5SAndroid Build Coastguard Worker     ParamBuffer &&params    = std::move(call.params);
3738*8975f5c5SAndroid Build Coastguard Worker 
3739*8975f5c5SAndroid Build Coastguard Worker     const ParamCapture &imageID = params.getParam("imagePacked", ParamType::TImageID, 1);
3740*8975f5c5SAndroid Build Coastguard Worker     params.addValueParam("imageID", ParamType::TGLuint, imageID.value.ImageIDVal.value);
3741*8975f5c5SAndroid Build Coastguard Worker 
3742*8975f5c5SAndroid Build Coastguard Worker     callsOut.emplace_back(std::move(call));
3743*8975f5c5SAndroid Build Coastguard Worker }
3744*8975f5c5SAndroid Build Coastguard Worker 
CaptureCustomCreateEGLSync(const char * name,CallCapture & call,std::vector<CallCapture> & callsOut)3745*8975f5c5SAndroid Build Coastguard Worker void CaptureCustomCreateEGLSync(const char *name,
3746*8975f5c5SAndroid Build Coastguard Worker                                 CallCapture &call,
3747*8975f5c5SAndroid Build Coastguard Worker                                 std::vector<CallCapture> &callsOut)
3748*8975f5c5SAndroid Build Coastguard Worker {
3749*8975f5c5SAndroid Build Coastguard Worker     ParamBuffer &&params = std::move(call.params);
3750*8975f5c5SAndroid Build Coastguard Worker     EGLSync returnVal    = params.getReturnValue().value.EGLSyncVal;
3751*8975f5c5SAndroid Build Coastguard Worker     egl::SyncID syncID   = egl::PackParam<egl::SyncID>(returnVal);
3752*8975f5c5SAndroid Build Coastguard Worker     params.addValueParam("sync", ParamType::TGLuint, syncID.value);
3753*8975f5c5SAndroid Build Coastguard Worker     call.customFunctionName = name;
3754*8975f5c5SAndroid Build Coastguard Worker     callsOut.emplace_back(std::move(call));
3755*8975f5c5SAndroid Build Coastguard Worker }
3756*8975f5c5SAndroid Build Coastguard Worker 
CaptureCustomCreatePbufferSurface(CallCapture & call,std::vector<CallCapture> & callsOut)3757*8975f5c5SAndroid Build Coastguard Worker void CaptureCustomCreatePbufferSurface(CallCapture &call, std::vector<CallCapture> &callsOut)
3758*8975f5c5SAndroid Build Coastguard Worker {
3759*8975f5c5SAndroid Build Coastguard Worker     ParamBuffer &&params     = std::move(call.params);
3760*8975f5c5SAndroid Build Coastguard Worker     EGLSurface returnVal     = params.getReturnValue().value.EGLSurfaceVal;
3761*8975f5c5SAndroid Build Coastguard Worker     egl::SurfaceID surfaceID = egl::PackParam<egl::SurfaceID>(returnVal);
3762*8975f5c5SAndroid Build Coastguard Worker 
3763*8975f5c5SAndroid Build Coastguard Worker     params.addValueParam("surface", ParamType::TGLuint, surfaceID.value);
3764*8975f5c5SAndroid Build Coastguard Worker     call.customFunctionName = "CreatePbufferSurface";
3765*8975f5c5SAndroid Build Coastguard Worker     callsOut.emplace_back(std::move(call));
3766*8975f5c5SAndroid Build Coastguard Worker }
3767*8975f5c5SAndroid Build Coastguard Worker 
CaptureCustomCreateNativeClientbuffer(CallCapture & call,std::vector<CallCapture> & callsOut)3768*8975f5c5SAndroid Build Coastguard Worker void CaptureCustomCreateNativeClientbuffer(CallCapture &call, std::vector<CallCapture> &callsOut)
3769*8975f5c5SAndroid Build Coastguard Worker {
3770*8975f5c5SAndroid Build Coastguard Worker     ParamBuffer &&params = std::move(call.params);
3771*8975f5c5SAndroid Build Coastguard Worker     params.addValueParam("clientBuffer", ParamType::TEGLClientBuffer,
3772*8975f5c5SAndroid Build Coastguard Worker                          params.getReturnValue().value.EGLClientBufferVal);
3773*8975f5c5SAndroid Build Coastguard Worker     call.customFunctionName = "CreateNativeClientBufferANDROID";
3774*8975f5c5SAndroid Build Coastguard Worker     callsOut.emplace_back(std::move(call));
3775*8975f5c5SAndroid Build Coastguard Worker }
3776*8975f5c5SAndroid Build Coastguard Worker 
GenerateLinkedProgram(const gl::Context * context,const gl::State & replayState,ResourceTracker * resourceTracker,std::vector<CallCapture> * setupCalls,gl::Program * program,gl::ShaderProgramID id,gl::ShaderProgramID tempIDStart,const ProgramSources & linkedSources)3777*8975f5c5SAndroid Build Coastguard Worker void GenerateLinkedProgram(const gl::Context *context,
3778*8975f5c5SAndroid Build Coastguard Worker                            const gl::State &replayState,
3779*8975f5c5SAndroid Build Coastguard Worker                            ResourceTracker *resourceTracker,
3780*8975f5c5SAndroid Build Coastguard Worker                            std::vector<CallCapture> *setupCalls,
3781*8975f5c5SAndroid Build Coastguard Worker                            gl::Program *program,
3782*8975f5c5SAndroid Build Coastguard Worker                            gl::ShaderProgramID id,
3783*8975f5c5SAndroid Build Coastguard Worker                            gl::ShaderProgramID tempIDStart,
3784*8975f5c5SAndroid Build Coastguard Worker                            const ProgramSources &linkedSources)
3785*8975f5c5SAndroid Build Coastguard Worker {
3786*8975f5c5SAndroid Build Coastguard Worker     // A map to store the gShaderProgram map lookup index of the temp shaders we attached below. We
3787*8975f5c5SAndroid Build Coastguard Worker     // need this map to retrieve the lookup index to pass to CaptureDetachShader calls at the end of
3788*8975f5c5SAndroid Build Coastguard Worker     // GenerateLinkedProgram.
3789*8975f5c5SAndroid Build Coastguard Worker     PackedEnumMap<gl::ShaderType, gl::ShaderProgramID> tempShaderIDTracker;
3790*8975f5c5SAndroid Build Coastguard Worker 
3791*8975f5c5SAndroid Build Coastguard Worker     const gl::ProgramExecutable &executable = program->getExecutable();
3792*8975f5c5SAndroid Build Coastguard Worker 
3793*8975f5c5SAndroid Build Coastguard Worker     // Compile with last linked sources.
3794*8975f5c5SAndroid Build Coastguard Worker     for (gl::ShaderType shaderType : executable.getLinkedShaderStages())
3795*8975f5c5SAndroid Build Coastguard Worker     {
3796*8975f5c5SAndroid Build Coastguard Worker         // Bump the max shader program id for each new tempIDStart we use to create, compile, and
3797*8975f5c5SAndroid Build Coastguard Worker         // attach the temp shader object.
3798*8975f5c5SAndroid Build Coastguard Worker         resourceTracker->onShaderProgramAccess(tempIDStart);
3799*8975f5c5SAndroid Build Coastguard Worker         // Store the tempIDStart in the tempShaderIDTracker to retrieve for CaptureDetachShader
3800*8975f5c5SAndroid Build Coastguard Worker         // calls later.
3801*8975f5c5SAndroid Build Coastguard Worker         tempShaderIDTracker[shaderType] = tempIDStart;
3802*8975f5c5SAndroid Build Coastguard Worker         const std::string &sourceString = linkedSources[shaderType];
3803*8975f5c5SAndroid Build Coastguard Worker         const char *sourcePointer       = sourceString.c_str();
3804*8975f5c5SAndroid Build Coastguard Worker 
3805*8975f5c5SAndroid Build Coastguard Worker         if (sourceString.empty())
3806*8975f5c5SAndroid Build Coastguard Worker         {
3807*8975f5c5SAndroid Build Coastguard Worker             // If we don't have source for this shader, that means it was populated by the app
3808*8975f5c5SAndroid Build Coastguard Worker             // using glProgramBinary.  We need to look it up from our cached copy.
3809*8975f5c5SAndroid Build Coastguard Worker             const ProgramSources &cachedLinkedSources =
3810*8975f5c5SAndroid Build Coastguard Worker                 context->getShareGroup()->getFrameCaptureShared()->getProgramSources(id);
3811*8975f5c5SAndroid Build Coastguard Worker 
3812*8975f5c5SAndroid Build Coastguard Worker             const std::string &cachedSourceString = cachedLinkedSources[shaderType];
3813*8975f5c5SAndroid Build Coastguard Worker             sourcePointer                         = cachedSourceString.c_str();
3814*8975f5c5SAndroid Build Coastguard Worker             ASSERT(!cachedSourceString.empty());
3815*8975f5c5SAndroid Build Coastguard Worker         }
3816*8975f5c5SAndroid Build Coastguard Worker 
3817*8975f5c5SAndroid Build Coastguard Worker         // Compile and attach the temporary shader. Then free it immediately.
3818*8975f5c5SAndroid Build Coastguard Worker         CallCapture createShader =
3819*8975f5c5SAndroid Build Coastguard Worker             CaptureCreateShader(replayState, true, shaderType, tempIDStart.value);
3820*8975f5c5SAndroid Build Coastguard Worker         CaptureCustomShaderProgram("CreateShader", createShader, *setupCalls);
3821*8975f5c5SAndroid Build Coastguard Worker         Capture(setupCalls,
3822*8975f5c5SAndroid Build Coastguard Worker                 CaptureShaderSource(replayState, true, tempIDStart, 1, &sourcePointer, nullptr));
3823*8975f5c5SAndroid Build Coastguard Worker         Capture(setupCalls, CaptureCompileShader(replayState, true, tempIDStart));
3824*8975f5c5SAndroid Build Coastguard Worker         Capture(setupCalls, CaptureAttachShader(replayState, true, id, tempIDStart));
3825*8975f5c5SAndroid Build Coastguard Worker         // Increment tempIDStart to get a new gShaderProgram map index for the next linked stage
3826*8975f5c5SAndroid Build Coastguard Worker         // shader object. We can't reuse the same tempIDStart as we need to retrieve the index of
3827*8975f5c5SAndroid Build Coastguard Worker         // each attached shader object later to pass to CaptureDetachShader calls.
3828*8975f5c5SAndroid Build Coastguard Worker         tempIDStart.value += 1;
3829*8975f5c5SAndroid Build Coastguard Worker     }
3830*8975f5c5SAndroid Build Coastguard Worker 
3831*8975f5c5SAndroid Build Coastguard Worker     // Gather XFB varyings
3832*8975f5c5SAndroid Build Coastguard Worker     std::vector<std::string> xfbVaryings;
3833*8975f5c5SAndroid Build Coastguard Worker     for (const gl::TransformFeedbackVarying &xfbVarying :
3834*8975f5c5SAndroid Build Coastguard Worker          executable.getLinkedTransformFeedbackVaryings())
3835*8975f5c5SAndroid Build Coastguard Worker     {
3836*8975f5c5SAndroid Build Coastguard Worker         xfbVaryings.push_back(xfbVarying.nameWithArrayIndex());
3837*8975f5c5SAndroid Build Coastguard Worker     }
3838*8975f5c5SAndroid Build Coastguard Worker 
3839*8975f5c5SAndroid Build Coastguard Worker     if (!xfbVaryings.empty())
3840*8975f5c5SAndroid Build Coastguard Worker     {
3841*8975f5c5SAndroid Build Coastguard Worker         std::vector<const char *> varyingsStrings;
3842*8975f5c5SAndroid Build Coastguard Worker         for (const std::string &varyingString : xfbVaryings)
3843*8975f5c5SAndroid Build Coastguard Worker         {
3844*8975f5c5SAndroid Build Coastguard Worker             varyingsStrings.push_back(varyingString.data());
3845*8975f5c5SAndroid Build Coastguard Worker         }
3846*8975f5c5SAndroid Build Coastguard Worker 
3847*8975f5c5SAndroid Build Coastguard Worker         GLenum xfbMode = executable.getTransformFeedbackBufferMode();
3848*8975f5c5SAndroid Build Coastguard Worker         Capture(setupCalls, CaptureTransformFeedbackVaryings(replayState, true, id,
3849*8975f5c5SAndroid Build Coastguard Worker                                                              static_cast<GLint>(xfbVaryings.size()),
3850*8975f5c5SAndroid Build Coastguard Worker                                                              varyingsStrings.data(), xfbMode));
3851*8975f5c5SAndroid Build Coastguard Worker     }
3852*8975f5c5SAndroid Build Coastguard Worker 
3853*8975f5c5SAndroid Build Coastguard Worker     // Force the attributes to be bound the same way as in the existing program.
3854*8975f5c5SAndroid Build Coastguard Worker     // This can affect attributes that are optimized out in some implementations.
3855*8975f5c5SAndroid Build Coastguard Worker     for (const gl::ProgramInput &attrib : executable.getProgramInputs())
3856*8975f5c5SAndroid Build Coastguard Worker     {
3857*8975f5c5SAndroid Build Coastguard Worker         if (gl::IsBuiltInName(attrib.name))
3858*8975f5c5SAndroid Build Coastguard Worker         {
3859*8975f5c5SAndroid Build Coastguard Worker             // Don't try to bind built-in attributes
3860*8975f5c5SAndroid Build Coastguard Worker             continue;
3861*8975f5c5SAndroid Build Coastguard Worker         }
3862*8975f5c5SAndroid Build Coastguard Worker 
3863*8975f5c5SAndroid Build Coastguard Worker         // Separable programs may not have a VS, meaning it may not have attributes.
3864*8975f5c5SAndroid Build Coastguard Worker         if (executable.hasLinkedShaderStage(gl::ShaderType::Vertex))
3865*8975f5c5SAndroid Build Coastguard Worker         {
3866*8975f5c5SAndroid Build Coastguard Worker             ASSERT(attrib.getLocation() != -1);
3867*8975f5c5SAndroid Build Coastguard Worker             Capture(setupCalls, CaptureBindAttribLocation(replayState, true, id,
3868*8975f5c5SAndroid Build Coastguard Worker                                                           static_cast<GLuint>(attrib.getLocation()),
3869*8975f5c5SAndroid Build Coastguard Worker                                                           attrib.name.c_str()));
3870*8975f5c5SAndroid Build Coastguard Worker         }
3871*8975f5c5SAndroid Build Coastguard Worker     }
3872*8975f5c5SAndroid Build Coastguard Worker 
3873*8975f5c5SAndroid Build Coastguard Worker     if (program->isSeparable())
3874*8975f5c5SAndroid Build Coastguard Worker     {
3875*8975f5c5SAndroid Build Coastguard Worker         // MEC manually recreates separable programs, rather than attempting to recreate a call
3876*8975f5c5SAndroid Build Coastguard Worker         // to glCreateShaderProgramv(), so insert a call to mark it separable.
3877*8975f5c5SAndroid Build Coastguard Worker         Capture(setupCalls,
3878*8975f5c5SAndroid Build Coastguard Worker                 CaptureProgramParameteri(replayState, true, id, GL_PROGRAM_SEPARABLE, GL_TRUE));
3879*8975f5c5SAndroid Build Coastguard Worker     }
3880*8975f5c5SAndroid Build Coastguard Worker 
3881*8975f5c5SAndroid Build Coastguard Worker     Capture(setupCalls, CaptureLinkProgram(replayState, true, id));
3882*8975f5c5SAndroid Build Coastguard Worker     CaptureUpdateUniformLocations(program, setupCalls);
3883*8975f5c5SAndroid Build Coastguard Worker     CaptureUpdateUniformValues(replayState, context, program, resourceTracker, setupCalls);
3884*8975f5c5SAndroid Build Coastguard Worker     CaptureUpdateUniformBlockIndexes(program, setupCalls);
3885*8975f5c5SAndroid Build Coastguard Worker 
3886*8975f5c5SAndroid Build Coastguard Worker     // Capture uniform block bindings for each program
3887*8975f5c5SAndroid Build Coastguard Worker     for (uint32_t uniformBlockIndex = 0;
3888*8975f5c5SAndroid Build Coastguard Worker          uniformBlockIndex < static_cast<uint32_t>(executable.getUniformBlocks().size());
3889*8975f5c5SAndroid Build Coastguard Worker          uniformBlockIndex++)
3890*8975f5c5SAndroid Build Coastguard Worker     {
3891*8975f5c5SAndroid Build Coastguard Worker         GLuint blockBinding = executable.getUniformBlocks()[uniformBlockIndex].pod.inShaderBinding;
3892*8975f5c5SAndroid Build Coastguard Worker         CallCapture updateCallCapture =
3893*8975f5c5SAndroid Build Coastguard Worker             CaptureUniformBlockBinding(replayState, true, id, {uniformBlockIndex}, blockBinding);
3894*8975f5c5SAndroid Build Coastguard Worker         CaptureCustomUniformBlockBinding(updateCallCapture, *setupCalls);
3895*8975f5c5SAndroid Build Coastguard Worker     }
3896*8975f5c5SAndroid Build Coastguard Worker 
3897*8975f5c5SAndroid Build Coastguard Worker     // Add DetachShader call if that's what the app does, so that the
3898*8975f5c5SAndroid Build Coastguard Worker     // ResourceManagerBase::mHandleAllocator can release the ShaderProgramID handle assigned to the
3899*8975f5c5SAndroid Build Coastguard Worker     // shader object when glDeleteShader is called. This ensures the ShaderProgramID handles used in
3900*8975f5c5SAndroid Build Coastguard Worker     // SetupReplayContextShared() are consistent with the ShaderProgramID handles used by the app.
3901*8975f5c5SAndroid Build Coastguard Worker     for (gl::ShaderType shaderType : executable.getLinkedShaderStages())
3902*8975f5c5SAndroid Build Coastguard Worker     {
3903*8975f5c5SAndroid Build Coastguard Worker         gl::Shader *attachedShader = program->getAttachedShader(shaderType);
3904*8975f5c5SAndroid Build Coastguard Worker         if (attachedShader == nullptr)
3905*8975f5c5SAndroid Build Coastguard Worker         {
3906*8975f5c5SAndroid Build Coastguard Worker             Capture(setupCalls,
3907*8975f5c5SAndroid Build Coastguard Worker                     CaptureDetachShader(replayState, true, id, tempShaderIDTracker[shaderType]));
3908*8975f5c5SAndroid Build Coastguard Worker         }
3909*8975f5c5SAndroid Build Coastguard Worker         Capture(setupCalls,
3910*8975f5c5SAndroid Build Coastguard Worker                 CaptureDeleteShader(replayState, true, tempShaderIDTracker[shaderType]));
3911*8975f5c5SAndroid Build Coastguard Worker     }
3912*8975f5c5SAndroid Build Coastguard Worker }
3913*8975f5c5SAndroid Build Coastguard Worker 
3914*8975f5c5SAndroid Build Coastguard Worker // TODO(http://anglebug.com/42263204): Improve reset/restore call generation
3915*8975f5c5SAndroid Build Coastguard Worker // There are multiple ways to track reset calls for individual resources. For now, we are tracking
3916*8975f5c5SAndroid Build Coastguard Worker // separate lists of instructions that mirror the calls created during mid-execution setup. Other
3917*8975f5c5SAndroid Build Coastguard Worker // methods could involve passing the original CallCaptures to this function, or tracking the
3918*8975f5c5SAndroid Build Coastguard Worker // indices of original setup calls.
CaptureBufferResetCalls(const gl::Context * context,const gl::State & replayState,ResourceTracker * resourceTracker,gl::BufferID * id,const gl::Buffer * buffer)3919*8975f5c5SAndroid Build Coastguard Worker void CaptureBufferResetCalls(const gl::Context *context,
3920*8975f5c5SAndroid Build Coastguard Worker                              const gl::State &replayState,
3921*8975f5c5SAndroid Build Coastguard Worker                              ResourceTracker *resourceTracker,
3922*8975f5c5SAndroid Build Coastguard Worker                              gl::BufferID *id,
3923*8975f5c5SAndroid Build Coastguard Worker                              const gl::Buffer *buffer)
3924*8975f5c5SAndroid Build Coastguard Worker {
3925*8975f5c5SAndroid Build Coastguard Worker     GLuint bufferID = (*id).value;
3926*8975f5c5SAndroid Build Coastguard Worker 
3927*8975f5c5SAndroid Build Coastguard Worker     // Track this as a starting resource that may need to be restored.
3928*8975f5c5SAndroid Build Coastguard Worker     TrackedResource &trackedBuffers =
3929*8975f5c5SAndroid Build Coastguard Worker         resourceTracker->getTrackedResource(context->id(), ResourceIDType::Buffer);
3930*8975f5c5SAndroid Build Coastguard Worker 
3931*8975f5c5SAndroid Build Coastguard Worker     // Track calls to regenerate a given buffer
3932*8975f5c5SAndroid Build Coastguard Worker     ResourceCalls &bufferRegenCalls = trackedBuffers.getResourceRegenCalls();
3933*8975f5c5SAndroid Build Coastguard Worker     Capture(&bufferRegenCalls[bufferID], CaptureGenBuffers(replayState, true, 1, id));
3934*8975f5c5SAndroid Build Coastguard Worker     MaybeCaptureUpdateResourceIDs(context, resourceTracker, &bufferRegenCalls[bufferID]);
3935*8975f5c5SAndroid Build Coastguard Worker 
3936*8975f5c5SAndroid Build Coastguard Worker     // Call glBufferStorageEXT when regenerating immutable buffers,
3937*8975f5c5SAndroid Build Coastguard Worker     // as we can't call glBufferData on restore.
3938*8975f5c5SAndroid Build Coastguard Worker     if (buffer->isImmutable())
3939*8975f5c5SAndroid Build Coastguard Worker     {
3940*8975f5c5SAndroid Build Coastguard Worker         Capture(&bufferRegenCalls[bufferID],
3941*8975f5c5SAndroid Build Coastguard Worker                 CaptureBindBuffer(replayState, true, gl::BufferBinding::Array, *id));
3942*8975f5c5SAndroid Build Coastguard Worker         Capture(
3943*8975f5c5SAndroid Build Coastguard Worker             &bufferRegenCalls[bufferID],
3944*8975f5c5SAndroid Build Coastguard Worker             CaptureBufferStorageEXT(replayState, true, gl::BufferBinding::Array,
3945*8975f5c5SAndroid Build Coastguard Worker                                     static_cast<GLsizeiptr>(buffer->getSize()),
3946*8975f5c5SAndroid Build Coastguard Worker                                     buffer->getMapPointer(), buffer->getStorageExtUsageFlags()));
3947*8975f5c5SAndroid Build Coastguard Worker     }
3948*8975f5c5SAndroid Build Coastguard Worker 
3949*8975f5c5SAndroid Build Coastguard Worker     // Track calls to restore a given buffer's contents
3950*8975f5c5SAndroid Build Coastguard Worker     ResourceCalls &bufferRestoreCalls = trackedBuffers.getResourceRestoreCalls();
3951*8975f5c5SAndroid Build Coastguard Worker     Capture(&bufferRestoreCalls[bufferID],
3952*8975f5c5SAndroid Build Coastguard Worker             CaptureBindBuffer(replayState, true, gl::BufferBinding::Array, *id));
3953*8975f5c5SAndroid Build Coastguard Worker 
3954*8975f5c5SAndroid Build Coastguard Worker     // Mutable buffers will be restored here using glBufferData.
3955*8975f5c5SAndroid Build Coastguard Worker     // Immutable buffers need to be restored below, after maping.
3956*8975f5c5SAndroid Build Coastguard Worker     if (!buffer->isImmutable())
3957*8975f5c5SAndroid Build Coastguard Worker     {
3958*8975f5c5SAndroid Build Coastguard Worker         Capture(&bufferRestoreCalls[bufferID],
3959*8975f5c5SAndroid Build Coastguard Worker                 CaptureBufferData(replayState, true, gl::BufferBinding::Array,
3960*8975f5c5SAndroid Build Coastguard Worker                                   static_cast<GLsizeiptr>(buffer->getSize()),
3961*8975f5c5SAndroid Build Coastguard Worker                                   buffer->getMapPointer(), buffer->getUsage()));
3962*8975f5c5SAndroid Build Coastguard Worker     }
3963*8975f5c5SAndroid Build Coastguard Worker 
3964*8975f5c5SAndroid Build Coastguard Worker     if (buffer->isMapped())
3965*8975f5c5SAndroid Build Coastguard Worker     {
3966*8975f5c5SAndroid Build Coastguard Worker         // Track calls to remap a buffer that started as mapped
3967*8975f5c5SAndroid Build Coastguard Worker         BufferCalls &bufferMapCalls = resourceTracker->getBufferMapCalls();
3968*8975f5c5SAndroid Build Coastguard Worker 
3969*8975f5c5SAndroid Build Coastguard Worker         Capture(&bufferMapCalls[bufferID],
3970*8975f5c5SAndroid Build Coastguard Worker                 CaptureBindBuffer(replayState, true, gl::BufferBinding::Array, *id));
3971*8975f5c5SAndroid Build Coastguard Worker 
3972*8975f5c5SAndroid Build Coastguard Worker         void *dontCare             = nullptr;
3973*8975f5c5SAndroid Build Coastguard Worker         CallCapture mapBufferRange = CaptureMapBufferRange(
3974*8975f5c5SAndroid Build Coastguard Worker             replayState, true, gl::BufferBinding::Array,
3975*8975f5c5SAndroid Build Coastguard Worker             static_cast<GLsizeiptr>(buffer->getMapOffset()),
3976*8975f5c5SAndroid Build Coastguard Worker             static_cast<GLsizeiptr>(buffer->getMapLength()), buffer->getAccessFlags(), dontCare);
3977*8975f5c5SAndroid Build Coastguard Worker         CaptureCustomMapBuffer("MapBufferRange", mapBufferRange, bufferMapCalls[bufferID],
3978*8975f5c5SAndroid Build Coastguard Worker                                buffer->id());
3979*8975f5c5SAndroid Build Coastguard Worker 
3980*8975f5c5SAndroid Build Coastguard Worker         // Restore immutable mapped buffers. Needs to happen after mapping.
3981*8975f5c5SAndroid Build Coastguard Worker         if (buffer->isImmutable())
3982*8975f5c5SAndroid Build Coastguard Worker         {
3983*8975f5c5SAndroid Build Coastguard Worker             ParamBuffer dataParamBuffer;
3984*8975f5c5SAndroid Build Coastguard Worker             dataParamBuffer.addValueParam("dest", ParamType::TGLuint, buffer->id().value);
3985*8975f5c5SAndroid Build Coastguard Worker             ParamCapture captureData("source", ParamType::TvoidConstPointer);
3986*8975f5c5SAndroid Build Coastguard Worker             CaptureMemory(buffer->getMapPointer(), static_cast<GLsizeiptr>(buffer->getSize()),
3987*8975f5c5SAndroid Build Coastguard Worker                           &captureData);
3988*8975f5c5SAndroid Build Coastguard Worker             dataParamBuffer.addParam(std::move(captureData));
3989*8975f5c5SAndroid Build Coastguard Worker             dataParamBuffer.addValueParam<GLsizeiptr>("size", ParamType::TGLsizeiptr,
3990*8975f5c5SAndroid Build Coastguard Worker                                                       static_cast<GLsizeiptr>(buffer->getSize()));
3991*8975f5c5SAndroid Build Coastguard Worker             bufferMapCalls[bufferID].emplace_back("UpdateClientBufferData",
3992*8975f5c5SAndroid Build Coastguard Worker                                                   std::move(dataParamBuffer));
3993*8975f5c5SAndroid Build Coastguard Worker         }
3994*8975f5c5SAndroid Build Coastguard Worker     }
3995*8975f5c5SAndroid Build Coastguard Worker 
3996*8975f5c5SAndroid Build Coastguard Worker     // Track calls unmap a buffer that started as unmapped
3997*8975f5c5SAndroid Build Coastguard Worker     BufferCalls &bufferUnmapCalls = resourceTracker->getBufferUnmapCalls();
3998*8975f5c5SAndroid Build Coastguard Worker     Capture(&bufferUnmapCalls[bufferID],
3999*8975f5c5SAndroid Build Coastguard Worker             CaptureBindBuffer(replayState, true, gl::BufferBinding::Array, *id));
4000*8975f5c5SAndroid Build Coastguard Worker     Capture(&bufferUnmapCalls[bufferID],
4001*8975f5c5SAndroid Build Coastguard Worker             CaptureUnmapBuffer(replayState, true, gl::BufferBinding::Array, GL_TRUE));
4002*8975f5c5SAndroid Build Coastguard Worker }
4003*8975f5c5SAndroid Build Coastguard Worker 
CaptureFenceSyncResetCalls(const gl::Context * context,const gl::State & replayState,ResourceTracker * resourceTracker,gl::SyncID syncID,GLsync syncObject,const gl::Sync * sync)4004*8975f5c5SAndroid Build Coastguard Worker void CaptureFenceSyncResetCalls(const gl::Context *context,
4005*8975f5c5SAndroid Build Coastguard Worker                                 const gl::State &replayState,
4006*8975f5c5SAndroid Build Coastguard Worker                                 ResourceTracker *resourceTracker,
4007*8975f5c5SAndroid Build Coastguard Worker                                 gl::SyncID syncID,
4008*8975f5c5SAndroid Build Coastguard Worker                                 GLsync syncObject,
4009*8975f5c5SAndroid Build Coastguard Worker                                 const gl::Sync *sync)
4010*8975f5c5SAndroid Build Coastguard Worker {
4011*8975f5c5SAndroid Build Coastguard Worker     // Track calls to regenerate a given fence sync
4012*8975f5c5SAndroid Build Coastguard Worker     FenceSyncCalls &fenceSyncRegenCalls = resourceTracker->getFenceSyncRegenCalls();
4013*8975f5c5SAndroid Build Coastguard Worker     CallCapture fenceSync =
4014*8975f5c5SAndroid Build Coastguard Worker         CaptureFenceSync(replayState, true, sync->getCondition(), sync->getFlags(), syncObject);
4015*8975f5c5SAndroid Build Coastguard Worker     CaptureCustomFenceSync(fenceSync, fenceSyncRegenCalls[syncID]);
4016*8975f5c5SAndroid Build Coastguard Worker     MaybeCaptureUpdateResourceIDs(context, resourceTracker, &fenceSyncRegenCalls[syncID]);
4017*8975f5c5SAndroid Build Coastguard Worker }
4018*8975f5c5SAndroid Build Coastguard Worker 
CaptureEGLSyncResetCalls(const gl::Context * context,const gl::State & replayState,ResourceTracker * resourceTracker,egl::SyncID eglSyncID,EGLSync eglSyncObject,const egl::Sync * eglSync)4019*8975f5c5SAndroid Build Coastguard Worker void CaptureEGLSyncResetCalls(const gl::Context *context,
4020*8975f5c5SAndroid Build Coastguard Worker                               const gl::State &replayState,
4021*8975f5c5SAndroid Build Coastguard Worker                               ResourceTracker *resourceTracker,
4022*8975f5c5SAndroid Build Coastguard Worker                               egl::SyncID eglSyncID,
4023*8975f5c5SAndroid Build Coastguard Worker                               EGLSync eglSyncObject,
4024*8975f5c5SAndroid Build Coastguard Worker                               const egl::Sync *eglSync)
4025*8975f5c5SAndroid Build Coastguard Worker {
4026*8975f5c5SAndroid Build Coastguard Worker     // Track this as a starting resource that may need to be restored.
4027*8975f5c5SAndroid Build Coastguard Worker     TrackedResource &trackedEGLSyncs =
4028*8975f5c5SAndroid Build Coastguard Worker         resourceTracker->getTrackedResource(context->id(), ResourceIDType::egl_Sync);
4029*8975f5c5SAndroid Build Coastguard Worker 
4030*8975f5c5SAndroid Build Coastguard Worker     // Track calls to regenerate a given buffer
4031*8975f5c5SAndroid Build Coastguard Worker     ResourceCalls &eglSyncRegenCalls = trackedEGLSyncs.getResourceRegenCalls();
4032*8975f5c5SAndroid Build Coastguard Worker 
4033*8975f5c5SAndroid Build Coastguard Worker     CallCapture createEGLSync =
4034*8975f5c5SAndroid Build Coastguard Worker         CaptureCreateSyncKHR(nullptr, true, context->getDisplay(), eglSync->getType(),
4035*8975f5c5SAndroid Build Coastguard Worker                              eglSync->getAttributeMap(), eglSyncObject);
4036*8975f5c5SAndroid Build Coastguard Worker     CaptureCustomCreateEGLSync("CreateEGLSyncKHR", createEGLSync,
4037*8975f5c5SAndroid Build Coastguard Worker                                eglSyncRegenCalls[eglSyncID.value]);
4038*8975f5c5SAndroid Build Coastguard Worker     MaybeCaptureUpdateResourceIDs(context, resourceTracker, &eglSyncRegenCalls[eglSyncID.value]);
4039*8975f5c5SAndroid Build Coastguard Worker }
4040*8975f5c5SAndroid Build Coastguard Worker 
CaptureBufferBindingResetCalls(const gl::State & replayState,ResourceTracker * resourceTracker,gl::BufferBinding binding,gl::BufferID id)4041*8975f5c5SAndroid Build Coastguard Worker void CaptureBufferBindingResetCalls(const gl::State &replayState,
4042*8975f5c5SAndroid Build Coastguard Worker                                     ResourceTracker *resourceTracker,
4043*8975f5c5SAndroid Build Coastguard Worker                                     gl::BufferBinding binding,
4044*8975f5c5SAndroid Build Coastguard Worker                                     gl::BufferID id)
4045*8975f5c5SAndroid Build Coastguard Worker {
4046*8975f5c5SAndroid Build Coastguard Worker     // Track the calls to reset it
4047*8975f5c5SAndroid Build Coastguard Worker     std::vector<CallCapture> &bufferBindingCalls = resourceTracker->getBufferBindingCalls();
4048*8975f5c5SAndroid Build Coastguard Worker     Capture(&bufferBindingCalls, CaptureBindBuffer(replayState, true, binding, id));
4049*8975f5c5SAndroid Build Coastguard Worker }
4050*8975f5c5SAndroid Build Coastguard Worker 
CaptureIndexedBuffers(const gl::State & glState,const gl::BufferVector & indexedBuffers,gl::BufferBinding binding,std::vector<CallCapture> * setupCalls)4051*8975f5c5SAndroid Build Coastguard Worker void CaptureIndexedBuffers(const gl::State &glState,
4052*8975f5c5SAndroid Build Coastguard Worker                            const gl::BufferVector &indexedBuffers,
4053*8975f5c5SAndroid Build Coastguard Worker                            gl::BufferBinding binding,
4054*8975f5c5SAndroid Build Coastguard Worker                            std::vector<CallCapture> *setupCalls)
4055*8975f5c5SAndroid Build Coastguard Worker {
4056*8975f5c5SAndroid Build Coastguard Worker     for (unsigned int index = 0; index < indexedBuffers.size(); ++index)
4057*8975f5c5SAndroid Build Coastguard Worker     {
4058*8975f5c5SAndroid Build Coastguard Worker         const gl::OffsetBindingPointer<gl::Buffer> &buffer = indexedBuffers[index];
4059*8975f5c5SAndroid Build Coastguard Worker 
4060*8975f5c5SAndroid Build Coastguard Worker         if (buffer.get() == nullptr)
4061*8975f5c5SAndroid Build Coastguard Worker         {
4062*8975f5c5SAndroid Build Coastguard Worker             continue;
4063*8975f5c5SAndroid Build Coastguard Worker         }
4064*8975f5c5SAndroid Build Coastguard Worker 
4065*8975f5c5SAndroid Build Coastguard Worker         GLintptr offset       = buffer.getOffset();
4066*8975f5c5SAndroid Build Coastguard Worker         GLsizeiptr size       = buffer.getSize();
4067*8975f5c5SAndroid Build Coastguard Worker         gl::BufferID bufferID = buffer.get()->id();
4068*8975f5c5SAndroid Build Coastguard Worker 
4069*8975f5c5SAndroid Build Coastguard Worker         // Context::bindBufferBase() calls Context::bindBufferRange() with size and offset = 0.
4070*8975f5c5SAndroid Build Coastguard Worker         if ((offset == 0) && (size == 0))
4071*8975f5c5SAndroid Build Coastguard Worker         {
4072*8975f5c5SAndroid Build Coastguard Worker             Capture(setupCalls, CaptureBindBufferBase(glState, true, binding, index, bufferID));
4073*8975f5c5SAndroid Build Coastguard Worker         }
4074*8975f5c5SAndroid Build Coastguard Worker         else
4075*8975f5c5SAndroid Build Coastguard Worker         {
4076*8975f5c5SAndroid Build Coastguard Worker             Capture(setupCalls,
4077*8975f5c5SAndroid Build Coastguard Worker                     CaptureBindBufferRange(glState, true, binding, index, bufferID, offset, size));
4078*8975f5c5SAndroid Build Coastguard Worker         }
4079*8975f5c5SAndroid Build Coastguard Worker     }
4080*8975f5c5SAndroid Build Coastguard Worker }
4081*8975f5c5SAndroid Build Coastguard Worker 
CaptureDefaultVertexAttribs(const gl::State & replayState,const gl::State & apiState,std::vector<CallCapture> * setupCalls)4082*8975f5c5SAndroid Build Coastguard Worker void CaptureDefaultVertexAttribs(const gl::State &replayState,
4083*8975f5c5SAndroid Build Coastguard Worker                                  const gl::State &apiState,
4084*8975f5c5SAndroid Build Coastguard Worker                                  std::vector<CallCapture> *setupCalls)
4085*8975f5c5SAndroid Build Coastguard Worker {
4086*8975f5c5SAndroid Build Coastguard Worker     const std::vector<gl::VertexAttribCurrentValueData> &currentValues =
4087*8975f5c5SAndroid Build Coastguard Worker         apiState.getVertexAttribCurrentValues();
4088*8975f5c5SAndroid Build Coastguard Worker 
4089*8975f5c5SAndroid Build Coastguard Worker     for (GLuint attribIndex = 0; attribIndex < currentValues.size(); ++attribIndex)
4090*8975f5c5SAndroid Build Coastguard Worker     {
4091*8975f5c5SAndroid Build Coastguard Worker         const gl::VertexAttribCurrentValueData &defaultValue = currentValues[attribIndex];
4092*8975f5c5SAndroid Build Coastguard Worker         if (!IsDefaultCurrentValue(defaultValue))
4093*8975f5c5SAndroid Build Coastguard Worker         {
4094*8975f5c5SAndroid Build Coastguard Worker             Capture(setupCalls, CaptureVertexAttrib4fv(replayState, true, attribIndex,
4095*8975f5c5SAndroid Build Coastguard Worker                                                        defaultValue.Values.FloatValues));
4096*8975f5c5SAndroid Build Coastguard Worker         }
4097*8975f5c5SAndroid Build Coastguard Worker     }
4098*8975f5c5SAndroid Build Coastguard Worker }
4099*8975f5c5SAndroid Build Coastguard Worker 
CompressPalettedTexture(angle::MemoryBuffer & data,angle::MemoryBuffer & tmp,const gl::InternalFormat & compressedFormat,const gl::Extents & extents)4100*8975f5c5SAndroid Build Coastguard Worker void CompressPalettedTexture(angle::MemoryBuffer &data,
4101*8975f5c5SAndroid Build Coastguard Worker                              angle::MemoryBuffer &tmp,
4102*8975f5c5SAndroid Build Coastguard Worker                              const gl::InternalFormat &compressedFormat,
4103*8975f5c5SAndroid Build Coastguard Worker                              const gl::Extents &extents)
4104*8975f5c5SAndroid Build Coastguard Worker {
4105*8975f5c5SAndroid Build Coastguard Worker     constexpr int uncompressedChannelCount = 4;
4106*8975f5c5SAndroid Build Coastguard Worker 
4107*8975f5c5SAndroid Build Coastguard Worker     uint32_t indexBits = 0, redBlueBits = 0, greenBits = 0, alphaBits = 0;
4108*8975f5c5SAndroid Build Coastguard Worker     switch (compressedFormat.internalFormat)
4109*8975f5c5SAndroid Build Coastguard Worker     {
4110*8975f5c5SAndroid Build Coastguard Worker         case GL_PALETTE4_RGB8_OES:
4111*8975f5c5SAndroid Build Coastguard Worker             indexBits   = 4;
4112*8975f5c5SAndroid Build Coastguard Worker             redBlueBits = 8;
4113*8975f5c5SAndroid Build Coastguard Worker             greenBits   = 8;
4114*8975f5c5SAndroid Build Coastguard Worker             alphaBits   = 0;
4115*8975f5c5SAndroid Build Coastguard Worker             break;
4116*8975f5c5SAndroid Build Coastguard Worker         case GL_PALETTE4_RGBA8_OES:
4117*8975f5c5SAndroid Build Coastguard Worker             indexBits   = 4;
4118*8975f5c5SAndroid Build Coastguard Worker             redBlueBits = 8;
4119*8975f5c5SAndroid Build Coastguard Worker             greenBits   = 8;
4120*8975f5c5SAndroid Build Coastguard Worker             alphaBits   = 8;
4121*8975f5c5SAndroid Build Coastguard Worker             break;
4122*8975f5c5SAndroid Build Coastguard Worker         case GL_PALETTE4_R5_G6_B5_OES:
4123*8975f5c5SAndroid Build Coastguard Worker             indexBits   = 4;
4124*8975f5c5SAndroid Build Coastguard Worker             redBlueBits = 5;
4125*8975f5c5SAndroid Build Coastguard Worker             greenBits   = 6;
4126*8975f5c5SAndroid Build Coastguard Worker             alphaBits   = 0;
4127*8975f5c5SAndroid Build Coastguard Worker             break;
4128*8975f5c5SAndroid Build Coastguard Worker         case GL_PALETTE4_RGBA4_OES:
4129*8975f5c5SAndroid Build Coastguard Worker             indexBits   = 4;
4130*8975f5c5SAndroid Build Coastguard Worker             redBlueBits = 4;
4131*8975f5c5SAndroid Build Coastguard Worker             greenBits   = 4;
4132*8975f5c5SAndroid Build Coastguard Worker             alphaBits   = 4;
4133*8975f5c5SAndroid Build Coastguard Worker             break;
4134*8975f5c5SAndroid Build Coastguard Worker         case GL_PALETTE4_RGB5_A1_OES:
4135*8975f5c5SAndroid Build Coastguard Worker             indexBits   = 4;
4136*8975f5c5SAndroid Build Coastguard Worker             redBlueBits = 5;
4137*8975f5c5SAndroid Build Coastguard Worker             greenBits   = 5;
4138*8975f5c5SAndroid Build Coastguard Worker             alphaBits   = 1;
4139*8975f5c5SAndroid Build Coastguard Worker             break;
4140*8975f5c5SAndroid Build Coastguard Worker         case GL_PALETTE8_RGB8_OES:
4141*8975f5c5SAndroid Build Coastguard Worker             indexBits   = 8;
4142*8975f5c5SAndroid Build Coastguard Worker             redBlueBits = 8;
4143*8975f5c5SAndroid Build Coastguard Worker             greenBits   = 8;
4144*8975f5c5SAndroid Build Coastguard Worker             alphaBits   = 0;
4145*8975f5c5SAndroid Build Coastguard Worker             break;
4146*8975f5c5SAndroid Build Coastguard Worker         case GL_PALETTE8_RGBA8_OES:
4147*8975f5c5SAndroid Build Coastguard Worker             indexBits   = 8;
4148*8975f5c5SAndroid Build Coastguard Worker             redBlueBits = 8;
4149*8975f5c5SAndroid Build Coastguard Worker             greenBits   = 8;
4150*8975f5c5SAndroid Build Coastguard Worker             alphaBits   = 8;
4151*8975f5c5SAndroid Build Coastguard Worker             break;
4152*8975f5c5SAndroid Build Coastguard Worker         case GL_PALETTE8_R5_G6_B5_OES:
4153*8975f5c5SAndroid Build Coastguard Worker             indexBits   = 8;
4154*8975f5c5SAndroid Build Coastguard Worker             redBlueBits = 5;
4155*8975f5c5SAndroid Build Coastguard Worker             greenBits   = 6;
4156*8975f5c5SAndroid Build Coastguard Worker             alphaBits   = 0;
4157*8975f5c5SAndroid Build Coastguard Worker             break;
4158*8975f5c5SAndroid Build Coastguard Worker         case GL_PALETTE8_RGBA4_OES:
4159*8975f5c5SAndroid Build Coastguard Worker             indexBits   = 8;
4160*8975f5c5SAndroid Build Coastguard Worker             redBlueBits = 4;
4161*8975f5c5SAndroid Build Coastguard Worker             greenBits   = 4;
4162*8975f5c5SAndroid Build Coastguard Worker             alphaBits   = 4;
4163*8975f5c5SAndroid Build Coastguard Worker             break;
4164*8975f5c5SAndroid Build Coastguard Worker         case GL_PALETTE8_RGB5_A1_OES:
4165*8975f5c5SAndroid Build Coastguard Worker             indexBits   = 8;
4166*8975f5c5SAndroid Build Coastguard Worker             redBlueBits = 5;
4167*8975f5c5SAndroid Build Coastguard Worker             greenBits   = 5;
4168*8975f5c5SAndroid Build Coastguard Worker             alphaBits   = 1;
4169*8975f5c5SAndroid Build Coastguard Worker             break;
4170*8975f5c5SAndroid Build Coastguard Worker 
4171*8975f5c5SAndroid Build Coastguard Worker         default:
4172*8975f5c5SAndroid Build Coastguard Worker             UNREACHABLE();
4173*8975f5c5SAndroid Build Coastguard Worker             break;
4174*8975f5c5SAndroid Build Coastguard Worker     }
4175*8975f5c5SAndroid Build Coastguard Worker 
4176*8975f5c5SAndroid Build Coastguard Worker     bool result = data.resize(
4177*8975f5c5SAndroid Build Coastguard Worker         // Palette size
4178*8975f5c5SAndroid Build Coastguard Worker         (1 << indexBits) * (2 * redBlueBits + greenBits + alphaBits) / 8 +
4179*8975f5c5SAndroid Build Coastguard Worker         // Texels size
4180*8975f5c5SAndroid Build Coastguard Worker         indexBits * extents.width * extents.height * extents.depth / 8);
4181*8975f5c5SAndroid Build Coastguard Worker     ASSERT(result);
4182*8975f5c5SAndroid Build Coastguard Worker 
4183*8975f5c5SAndroid Build Coastguard Worker     angle::StoreRGBA8ToPalettedImpl(
4184*8975f5c5SAndroid Build Coastguard Worker         extents.width, extents.height, extents.depth, indexBits, redBlueBits, greenBits, alphaBits,
4185*8975f5c5SAndroid Build Coastguard Worker         tmp.data(),
4186*8975f5c5SAndroid Build Coastguard Worker         uncompressedChannelCount * extents.width,                   // inputRowPitch
4187*8975f5c5SAndroid Build Coastguard Worker         uncompressedChannelCount * extents.width * extents.height,  // inputDepthPitch
4188*8975f5c5SAndroid Build Coastguard Worker         data.data(),                                                // output
4189*8975f5c5SAndroid Build Coastguard Worker         indexBits * extents.width / 8,                              // outputRowPitch
4190*8975f5c5SAndroid Build Coastguard Worker         indexBits * extents.width * extents.height / 8              // outputDepthPitch
4191*8975f5c5SAndroid Build Coastguard Worker     );
4192*8975f5c5SAndroid Build Coastguard Worker }
4193*8975f5c5SAndroid Build Coastguard Worker 
4194*8975f5c5SAndroid Build Coastguard Worker // Capture the setup of the state that's shared by all of the contexts in the share group
4195*8975f5c5SAndroid Build Coastguard Worker // See IsSharedObjectResource for the list of objects covered here.
CaptureShareGroupMidExecutionSetup(gl::Context * context,std::vector<CallCapture> * setupCalls,ResourceTracker * resourceTracker,gl::State & replayState,const PackedEnumMap<ResourceIDType,uint32_t> & maxAccessedResourceIDs)4196*8975f5c5SAndroid Build Coastguard Worker void CaptureShareGroupMidExecutionSetup(
4197*8975f5c5SAndroid Build Coastguard Worker     gl::Context *context,
4198*8975f5c5SAndroid Build Coastguard Worker     std::vector<CallCapture> *setupCalls,
4199*8975f5c5SAndroid Build Coastguard Worker     ResourceTracker *resourceTracker,
4200*8975f5c5SAndroid Build Coastguard Worker     gl::State &replayState,
4201*8975f5c5SAndroid Build Coastguard Worker     const PackedEnumMap<ResourceIDType, uint32_t> &maxAccessedResourceIDs)
4202*8975f5c5SAndroid Build Coastguard Worker {
4203*8975f5c5SAndroid Build Coastguard Worker     FrameCaptureShared *frameCaptureShared = context->getShareGroup()->getFrameCaptureShared();
4204*8975f5c5SAndroid Build Coastguard Worker     const gl::State &apiState              = context->getState();
4205*8975f5c5SAndroid Build Coastguard Worker 
4206*8975f5c5SAndroid Build Coastguard Worker     // Small helper function to make the code more readable.
4207*8975f5c5SAndroid Build Coastguard Worker     auto cap = [setupCalls](CallCapture &&call) { setupCalls->emplace_back(std::move(call)); };
4208*8975f5c5SAndroid Build Coastguard Worker 
4209*8975f5c5SAndroid Build Coastguard Worker     // Capture Buffer data.
4210*8975f5c5SAndroid Build Coastguard Worker     const gl::BufferManager &buffers = apiState.getBufferManagerForCapture();
4211*8975f5c5SAndroid Build Coastguard Worker     for (const auto &bufferIter : gl::UnsafeResourceMapIter(buffers.getResourcesForCapture()))
4212*8975f5c5SAndroid Build Coastguard Worker     {
4213*8975f5c5SAndroid Build Coastguard Worker         gl::BufferID id    = {bufferIter.first};
4214*8975f5c5SAndroid Build Coastguard Worker         gl::Buffer *buffer = bufferIter.second;
4215*8975f5c5SAndroid Build Coastguard Worker 
4216*8975f5c5SAndroid Build Coastguard Worker         if (id.value == 0)
4217*8975f5c5SAndroid Build Coastguard Worker         {
4218*8975f5c5SAndroid Build Coastguard Worker             continue;
4219*8975f5c5SAndroid Build Coastguard Worker         }
4220*8975f5c5SAndroid Build Coastguard Worker 
4221*8975f5c5SAndroid Build Coastguard Worker         // Generate binding.
4222*8975f5c5SAndroid Build Coastguard Worker         cap(CaptureGenBuffers(replayState, true, 1, &id));
4223*8975f5c5SAndroid Build Coastguard Worker 
4224*8975f5c5SAndroid Build Coastguard Worker         resourceTracker->getTrackedResource(context->id(), ResourceIDType::Buffer)
4225*8975f5c5SAndroid Build Coastguard Worker             .getStartingResources()
4226*8975f5c5SAndroid Build Coastguard Worker             .insert(id.value);
4227*8975f5c5SAndroid Build Coastguard Worker 
4228*8975f5c5SAndroid Build Coastguard Worker         MaybeCaptureUpdateResourceIDs(context, resourceTracker, setupCalls);
4229*8975f5c5SAndroid Build Coastguard Worker 
4230*8975f5c5SAndroid Build Coastguard Worker         // glBufferData. Would possibly be better implemented using a getData impl method.
4231*8975f5c5SAndroid Build Coastguard Worker         // Saving buffers that are mapped during a swap is not yet handled.
4232*8975f5c5SAndroid Build Coastguard Worker         if (buffer->getSize() == 0)
4233*8975f5c5SAndroid Build Coastguard Worker         {
4234*8975f5c5SAndroid Build Coastguard Worker             resourceTracker->setStartingBufferMapped(buffer->id().value, false);
4235*8975f5c5SAndroid Build Coastguard Worker             continue;
4236*8975f5c5SAndroid Build Coastguard Worker         }
4237*8975f5c5SAndroid Build Coastguard Worker 
4238*8975f5c5SAndroid Build Coastguard Worker         // Remember if the buffer was already mapped
4239*8975f5c5SAndroid Build Coastguard Worker         GLboolean bufferMapped = buffer->isMapped();
4240*8975f5c5SAndroid Build Coastguard Worker 
4241*8975f5c5SAndroid Build Coastguard Worker         // If needed, map the buffer so we can capture its contents
4242*8975f5c5SAndroid Build Coastguard Worker         if (!bufferMapped)
4243*8975f5c5SAndroid Build Coastguard Worker         {
4244*8975f5c5SAndroid Build Coastguard Worker             (void)buffer->mapRange(context, 0, static_cast<GLsizeiptr>(buffer->getSize()),
4245*8975f5c5SAndroid Build Coastguard Worker                                    GL_MAP_READ_BIT);
4246*8975f5c5SAndroid Build Coastguard Worker         }
4247*8975f5c5SAndroid Build Coastguard Worker 
4248*8975f5c5SAndroid Build Coastguard Worker         // Always use the array buffer binding point to upload data to keep things simple.
4249*8975f5c5SAndroid Build Coastguard Worker         if (buffer != replayState.getArrayBuffer())
4250*8975f5c5SAndroid Build Coastguard Worker         {
4251*8975f5c5SAndroid Build Coastguard Worker             replayState.setBufferBinding(context, gl::BufferBinding::Array, buffer);
4252*8975f5c5SAndroid Build Coastguard Worker             cap(CaptureBindBuffer(replayState, true, gl::BufferBinding::Array, id));
4253*8975f5c5SAndroid Build Coastguard Worker         }
4254*8975f5c5SAndroid Build Coastguard Worker 
4255*8975f5c5SAndroid Build Coastguard Worker         if (buffer->isImmutable())
4256*8975f5c5SAndroid Build Coastguard Worker         {
4257*8975f5c5SAndroid Build Coastguard Worker             cap(CaptureBufferStorageEXT(replayState, true, gl::BufferBinding::Array,
4258*8975f5c5SAndroid Build Coastguard Worker                                         static_cast<GLsizeiptr>(buffer->getSize()),
4259*8975f5c5SAndroid Build Coastguard Worker                                         buffer->getMapPointer(),
4260*8975f5c5SAndroid Build Coastguard Worker                                         buffer->getStorageExtUsageFlags()));
4261*8975f5c5SAndroid Build Coastguard Worker         }
4262*8975f5c5SAndroid Build Coastguard Worker         else
4263*8975f5c5SAndroid Build Coastguard Worker         {
4264*8975f5c5SAndroid Build Coastguard Worker             cap(CaptureBufferData(replayState, true, gl::BufferBinding::Array,
4265*8975f5c5SAndroid Build Coastguard Worker                                   static_cast<GLsizeiptr>(buffer->getSize()),
4266*8975f5c5SAndroid Build Coastguard Worker                                   buffer->getMapPointer(), buffer->getUsage()));
4267*8975f5c5SAndroid Build Coastguard Worker         }
4268*8975f5c5SAndroid Build Coastguard Worker 
4269*8975f5c5SAndroid Build Coastguard Worker         if (bufferMapped)
4270*8975f5c5SAndroid Build Coastguard Worker         {
4271*8975f5c5SAndroid Build Coastguard Worker             void *dontCare = nullptr;
4272*8975f5c5SAndroid Build Coastguard Worker             CallCapture mapBufferRange =
4273*8975f5c5SAndroid Build Coastguard Worker                 CaptureMapBufferRange(replayState, true, gl::BufferBinding::Array,
4274*8975f5c5SAndroid Build Coastguard Worker                                       static_cast<GLsizeiptr>(buffer->getMapOffset()),
4275*8975f5c5SAndroid Build Coastguard Worker                                       static_cast<GLsizeiptr>(buffer->getMapLength()),
4276*8975f5c5SAndroid Build Coastguard Worker                                       buffer->getAccessFlags(), dontCare);
4277*8975f5c5SAndroid Build Coastguard Worker             CaptureCustomMapBuffer("MapBufferRange", mapBufferRange, *setupCalls, buffer->id());
4278*8975f5c5SAndroid Build Coastguard Worker 
4279*8975f5c5SAndroid Build Coastguard Worker             resourceTracker->setStartingBufferMapped(buffer->id().value, true);
4280*8975f5c5SAndroid Build Coastguard Worker 
4281*8975f5c5SAndroid Build Coastguard Worker             frameCaptureShared->trackBufferMapping(
4282*8975f5c5SAndroid Build Coastguard Worker                 context, &setupCalls->back(), buffer->id(), buffer,
4283*8975f5c5SAndroid Build Coastguard Worker                 static_cast<GLsizeiptr>(buffer->getMapOffset()),
4284*8975f5c5SAndroid Build Coastguard Worker                 static_cast<GLsizeiptr>(buffer->getMapLength()),
4285*8975f5c5SAndroid Build Coastguard Worker                 (buffer->getAccessFlags() & GL_MAP_WRITE_BIT) != 0,
4286*8975f5c5SAndroid Build Coastguard Worker                 (buffer->getStorageExtUsageFlags() & GL_MAP_COHERENT_BIT_EXT) != 0);
4287*8975f5c5SAndroid Build Coastguard Worker         }
4288*8975f5c5SAndroid Build Coastguard Worker         else
4289*8975f5c5SAndroid Build Coastguard Worker         {
4290*8975f5c5SAndroid Build Coastguard Worker             resourceTracker->setStartingBufferMapped(buffer->id().value, false);
4291*8975f5c5SAndroid Build Coastguard Worker         }
4292*8975f5c5SAndroid Build Coastguard Worker 
4293*8975f5c5SAndroid Build Coastguard Worker         // Generate the calls needed to restore this buffer to original state for frame looping
4294*8975f5c5SAndroid Build Coastguard Worker         CaptureBufferResetCalls(context, replayState, resourceTracker, &id, buffer);
4295*8975f5c5SAndroid Build Coastguard Worker 
4296*8975f5c5SAndroid Build Coastguard Worker         // Unmap the buffer if it wasn't already mapped
4297*8975f5c5SAndroid Build Coastguard Worker         if (!bufferMapped)
4298*8975f5c5SAndroid Build Coastguard Worker         {
4299*8975f5c5SAndroid Build Coastguard Worker             GLboolean dontCare;
4300*8975f5c5SAndroid Build Coastguard Worker             (void)buffer->unmap(context, &dontCare);
4301*8975f5c5SAndroid Build Coastguard Worker         }
4302*8975f5c5SAndroid Build Coastguard Worker     }
4303*8975f5c5SAndroid Build Coastguard Worker 
4304*8975f5c5SAndroid Build Coastguard Worker     // Clear the array buffer binding.
4305*8975f5c5SAndroid Build Coastguard Worker     if (replayState.getTargetBuffer(gl::BufferBinding::Array))
4306*8975f5c5SAndroid Build Coastguard Worker     {
4307*8975f5c5SAndroid Build Coastguard Worker         cap(CaptureBindBuffer(replayState, true, gl::BufferBinding::Array, {0}));
4308*8975f5c5SAndroid Build Coastguard Worker         replayState.setBufferBinding(context, gl::BufferBinding::Array, nullptr);
4309*8975f5c5SAndroid Build Coastguard Worker     }
4310*8975f5c5SAndroid Build Coastguard Worker 
4311*8975f5c5SAndroid Build Coastguard Worker     // Set a unpack alignment of 1. Otherwise, computeRowPitch() will compute the wrong value,
4312*8975f5c5SAndroid Build Coastguard Worker     // leading to a crash in memcpy() when capturing the texture contents.
4313*8975f5c5SAndroid Build Coastguard Worker     gl::PixelUnpackState &currentUnpackState = replayState.getUnpackState();
4314*8975f5c5SAndroid Build Coastguard Worker     if (currentUnpackState.alignment != 1)
4315*8975f5c5SAndroid Build Coastguard Worker     {
4316*8975f5c5SAndroid Build Coastguard Worker         cap(CapturePixelStorei(replayState, true, GL_UNPACK_ALIGNMENT, 1));
4317*8975f5c5SAndroid Build Coastguard Worker         replayState.getMutablePrivateStateForCapture()->setUnpackAlignment(1);
4318*8975f5c5SAndroid Build Coastguard Worker     }
4319*8975f5c5SAndroid Build Coastguard Worker 
4320*8975f5c5SAndroid Build Coastguard Worker     const egl::ImageMap eglImageMap = context->getDisplay()->getImagesForCapture();
4321*8975f5c5SAndroid Build Coastguard Worker     for (const auto &[eglImageID, eglImage] : eglImageMap)
4322*8975f5c5SAndroid Build Coastguard Worker     {
4323*8975f5c5SAndroid Build Coastguard Worker         // Track this as a starting resource that may need to be restored.
4324*8975f5c5SAndroid Build Coastguard Worker         TrackedResource &trackedImages =
4325*8975f5c5SAndroid Build Coastguard Worker             resourceTracker->getTrackedResource(context->id(), ResourceIDType::Image);
4326*8975f5c5SAndroid Build Coastguard Worker         trackedImages.getStartingResources().insert(eglImageID);
4327*8975f5c5SAndroid Build Coastguard Worker 
4328*8975f5c5SAndroid Build Coastguard Worker         ResourceCalls &imageRegenCalls = trackedImages.getResourceRegenCalls();
4329*8975f5c5SAndroid Build Coastguard Worker         CallVector imageGenCalls({setupCalls, &imageRegenCalls[eglImageID]});
4330*8975f5c5SAndroid Build Coastguard Worker 
4331*8975f5c5SAndroid Build Coastguard Worker         auto eglImageAttribIter = resourceTracker->getImageToAttribTable().find(
4332*8975f5c5SAndroid Build Coastguard Worker             reinterpret_cast<EGLImage>(static_cast<uintptr_t>(eglImageID)));
4333*8975f5c5SAndroid Build Coastguard Worker         ASSERT(eglImageAttribIter != resourceTracker->getImageToAttribTable().end());
4334*8975f5c5SAndroid Build Coastguard Worker         const egl::AttributeMap &attribs = eglImageAttribIter->second;
4335*8975f5c5SAndroid Build Coastguard Worker 
4336*8975f5c5SAndroid Build Coastguard Worker         for (std::vector<CallCapture> *calls : imageGenCalls)
4337*8975f5c5SAndroid Build Coastguard Worker         {
4338*8975f5c5SAndroid Build Coastguard Worker             // Create the image on demand with the same attrib retrieved above
4339*8975f5c5SAndroid Build Coastguard Worker             CallCapture eglCreateImageKHRCall = egl::CaptureCreateImageKHR(
4340*8975f5c5SAndroid Build Coastguard Worker                 nullptr, true, nullptr, context->id(), EGL_GL_TEXTURE_2D,
4341*8975f5c5SAndroid Build Coastguard Worker                 reinterpret_cast<EGLClientBuffer>(static_cast<uintptr_t>(0)), attribs,
4342*8975f5c5SAndroid Build Coastguard Worker                 reinterpret_cast<EGLImage>(static_cast<uintptr_t>(eglImageID)));
4343*8975f5c5SAndroid Build Coastguard Worker 
4344*8975f5c5SAndroid Build Coastguard Worker             // Convert the CaptureCreateImageKHR CallCapture to the customized CallCapture
4345*8975f5c5SAndroid Build Coastguard Worker             CaptureCustomCreateEGLImage(context, "CreateEGLImageKHR", eglImage->getWidth(),
4346*8975f5c5SAndroid Build Coastguard Worker                                         eglImage->getHeight(), eglCreateImageKHRCall, *calls);
4347*8975f5c5SAndroid Build Coastguard Worker         }
4348*8975f5c5SAndroid Build Coastguard Worker     }
4349*8975f5c5SAndroid Build Coastguard Worker 
4350*8975f5c5SAndroid Build Coastguard Worker     // Capture Texture setup and data.
4351*8975f5c5SAndroid Build Coastguard Worker     const gl::TextureManager &textures = apiState.getTextureManagerForCapture();
4352*8975f5c5SAndroid Build Coastguard Worker 
4353*8975f5c5SAndroid Build Coastguard Worker     for (const auto &textureIter : gl::UnsafeResourceMapIter(textures.getResourcesForCapture()))
4354*8975f5c5SAndroid Build Coastguard Worker     {
4355*8975f5c5SAndroid Build Coastguard Worker         gl::TextureID id     = {textureIter.first};
4356*8975f5c5SAndroid Build Coastguard Worker         gl::Texture *texture = textureIter.second;
4357*8975f5c5SAndroid Build Coastguard Worker 
4358*8975f5c5SAndroid Build Coastguard Worker         if (id.value == 0)
4359*8975f5c5SAndroid Build Coastguard Worker         {
4360*8975f5c5SAndroid Build Coastguard Worker             continue;
4361*8975f5c5SAndroid Build Coastguard Worker         }
4362*8975f5c5SAndroid Build Coastguard Worker 
4363*8975f5c5SAndroid Build Coastguard Worker         size_t textureSetupStart = setupCalls->size();
4364*8975f5c5SAndroid Build Coastguard Worker 
4365*8975f5c5SAndroid Build Coastguard Worker         // Track this as a starting resource that may need to be restored.
4366*8975f5c5SAndroid Build Coastguard Worker         TrackedResource &trackedTextures =
4367*8975f5c5SAndroid Build Coastguard Worker             resourceTracker->getTrackedResource(context->id(), ResourceIDType::Texture);
4368*8975f5c5SAndroid Build Coastguard Worker         ResourceSet &startingTextures = trackedTextures.getStartingResources();
4369*8975f5c5SAndroid Build Coastguard Worker         startingTextures.insert(id.value);
4370*8975f5c5SAndroid Build Coastguard Worker 
4371*8975f5c5SAndroid Build Coastguard Worker         // For the initial texture creation calls, track in the generate list
4372*8975f5c5SAndroid Build Coastguard Worker         ResourceCalls &textureRegenCalls = trackedTextures.getResourceRegenCalls();
4373*8975f5c5SAndroid Build Coastguard Worker         CallVector texGenCalls({setupCalls, &textureRegenCalls[id.value]});
4374*8975f5c5SAndroid Build Coastguard Worker 
4375*8975f5c5SAndroid Build Coastguard Worker         // Gen the Texture.
4376*8975f5c5SAndroid Build Coastguard Worker         for (std::vector<CallCapture> *calls : texGenCalls)
4377*8975f5c5SAndroid Build Coastguard Worker         {
4378*8975f5c5SAndroid Build Coastguard Worker             Capture(calls, CaptureGenTextures(replayState, true, 1, &id));
4379*8975f5c5SAndroid Build Coastguard Worker             MaybeCaptureUpdateResourceIDs(context, resourceTracker, calls);
4380*8975f5c5SAndroid Build Coastguard Worker         }
4381*8975f5c5SAndroid Build Coastguard Worker 
4382*8975f5c5SAndroid Build Coastguard Worker         // For the remaining texture setup calls, track in the restore list
4383*8975f5c5SAndroid Build Coastguard Worker         ResourceCalls &textureRestoreCalls = trackedTextures.getResourceRestoreCalls();
4384*8975f5c5SAndroid Build Coastguard Worker         CallVector texSetupCalls({setupCalls, &textureRestoreCalls[id.value]});
4385*8975f5c5SAndroid Build Coastguard Worker 
4386*8975f5c5SAndroid Build Coastguard Worker         // For each texture, set the correct active texture and binding
4387*8975f5c5SAndroid Build Coastguard Worker         // There is similar code in CaptureMidExecutionSetup for per-context setup
4388*8975f5c5SAndroid Build Coastguard Worker         const gl::TextureBindingMap &currentBoundTextures = apiState.getBoundTexturesForCapture();
4389*8975f5c5SAndroid Build Coastguard Worker         const gl::TextureBindingVector &currentBindings = currentBoundTextures[texture->getType()];
4390*8975f5c5SAndroid Build Coastguard Worker         const gl::TextureBindingVector &replayBindings =
4391*8975f5c5SAndroid Build Coastguard Worker             replayState.getBoundTexturesForCapture()[texture->getType()];
4392*8975f5c5SAndroid Build Coastguard Worker         ASSERT(currentBindings.size() == replayBindings.size());
4393*8975f5c5SAndroid Build Coastguard Worker 
4394*8975f5c5SAndroid Build Coastguard Worker         // Look up the replay binding
4395*8975f5c5SAndroid Build Coastguard Worker         size_t replayActiveTexture = replayState.getActiveSampler();
4396*8975f5c5SAndroid Build Coastguard Worker         // If there ends up being no binding, just use the replay binding
4397*8975f5c5SAndroid Build Coastguard Worker         // TODO: We may want to start using index 0 for everything, mark it dirty, and restore it
4398*8975f5c5SAndroid Build Coastguard Worker         size_t currentActiveTexture = replayActiveTexture;
4399*8975f5c5SAndroid Build Coastguard Worker 
4400*8975f5c5SAndroid Build Coastguard Worker         // Iterate through current bindings and find the correct index for this texture ID
4401*8975f5c5SAndroid Build Coastguard Worker         for (size_t bindingIndex = 0; bindingIndex < currentBindings.size(); ++bindingIndex)
4402*8975f5c5SAndroid Build Coastguard Worker         {
4403*8975f5c5SAndroid Build Coastguard Worker             gl::TextureID currentTextureID = currentBindings[bindingIndex].id();
4404*8975f5c5SAndroid Build Coastguard Worker             gl::TextureID replayTextureID  = replayBindings[bindingIndex].id();
4405*8975f5c5SAndroid Build Coastguard Worker 
4406*8975f5c5SAndroid Build Coastguard Worker             // Only check the texture we care about
4407*8975f5c5SAndroid Build Coastguard Worker             if (currentTextureID == texture->id())
4408*8975f5c5SAndroid Build Coastguard Worker             {
4409*8975f5c5SAndroid Build Coastguard Worker                 // If the binding doesn't match, track it
4410*8975f5c5SAndroid Build Coastguard Worker                 if (currentTextureID != replayTextureID)
4411*8975f5c5SAndroid Build Coastguard Worker                 {
4412*8975f5c5SAndroid Build Coastguard Worker                     currentActiveTexture = bindingIndex;
4413*8975f5c5SAndroid Build Coastguard Worker                 }
4414*8975f5c5SAndroid Build Coastguard Worker 
4415*8975f5c5SAndroid Build Coastguard Worker                 break;
4416*8975f5c5SAndroid Build Coastguard Worker             }
4417*8975f5c5SAndroid Build Coastguard Worker         }
4418*8975f5c5SAndroid Build Coastguard Worker 
4419*8975f5c5SAndroid Build Coastguard Worker         // Set the correct active texture before performing any state changes, including binding
4420*8975f5c5SAndroid Build Coastguard Worker         if (currentActiveTexture != replayActiveTexture)
4421*8975f5c5SAndroid Build Coastguard Worker         {
4422*8975f5c5SAndroid Build Coastguard Worker             for (std::vector<CallCapture> *calls : texSetupCalls)
4423*8975f5c5SAndroid Build Coastguard Worker             {
4424*8975f5c5SAndroid Build Coastguard Worker                 Capture(calls, CaptureActiveTexture(
4425*8975f5c5SAndroid Build Coastguard Worker                                    replayState, true,
4426*8975f5c5SAndroid Build Coastguard Worker                                    GL_TEXTURE0 + static_cast<GLenum>(currentActiveTexture)));
4427*8975f5c5SAndroid Build Coastguard Worker             }
4428*8975f5c5SAndroid Build Coastguard Worker             replayState.getMutablePrivateStateForCapture()->setActiveSampler(
4429*8975f5c5SAndroid Build Coastguard Worker                 static_cast<unsigned int>(currentActiveTexture));
4430*8975f5c5SAndroid Build Coastguard Worker         }
4431*8975f5c5SAndroid Build Coastguard Worker 
4432*8975f5c5SAndroid Build Coastguard Worker         for (std::vector<CallCapture> *calls : texSetupCalls)
4433*8975f5c5SAndroid Build Coastguard Worker         {
4434*8975f5c5SAndroid Build Coastguard Worker             Capture(calls, CaptureBindTexture(replayState, true, texture->getType(), id));
4435*8975f5c5SAndroid Build Coastguard Worker         }
4436*8975f5c5SAndroid Build Coastguard Worker         replayState.setSamplerTexture(context, texture->getType(), texture);
4437*8975f5c5SAndroid Build Coastguard Worker 
4438*8975f5c5SAndroid Build Coastguard Worker         // Capture sampler parameter states.
4439*8975f5c5SAndroid Build Coastguard Worker         // TODO(jmadill): More sampler / texture states. http://anglebug.com/42262323
4440*8975f5c5SAndroid Build Coastguard Worker         gl::SamplerState defaultSamplerState =
4441*8975f5c5SAndroid Build Coastguard Worker             gl::SamplerState::CreateDefaultForTarget(texture->getType());
4442*8975f5c5SAndroid Build Coastguard Worker         const gl::SamplerState &textureSamplerState = texture->getSamplerState();
4443*8975f5c5SAndroid Build Coastguard Worker 
4444*8975f5c5SAndroid Build Coastguard Worker         auto capTexParam = [&replayState, texture, &texSetupCalls](GLenum pname, GLint param) {
4445*8975f5c5SAndroid Build Coastguard Worker             for (std::vector<CallCapture> *calls : texSetupCalls)
4446*8975f5c5SAndroid Build Coastguard Worker             {
4447*8975f5c5SAndroid Build Coastguard Worker                 Capture(calls,
4448*8975f5c5SAndroid Build Coastguard Worker                         CaptureTexParameteri(replayState, true, texture->getType(), pname, param));
4449*8975f5c5SAndroid Build Coastguard Worker             }
4450*8975f5c5SAndroid Build Coastguard Worker         };
4451*8975f5c5SAndroid Build Coastguard Worker 
4452*8975f5c5SAndroid Build Coastguard Worker         auto capTexParamf = [&replayState, texture, &texSetupCalls](GLenum pname, GLfloat param) {
4453*8975f5c5SAndroid Build Coastguard Worker             for (std::vector<CallCapture> *calls : texSetupCalls)
4454*8975f5c5SAndroid Build Coastguard Worker             {
4455*8975f5c5SAndroid Build Coastguard Worker                 Capture(calls,
4456*8975f5c5SAndroid Build Coastguard Worker                         CaptureTexParameterf(replayState, true, texture->getType(), pname, param));
4457*8975f5c5SAndroid Build Coastguard Worker             }
4458*8975f5c5SAndroid Build Coastguard Worker         };
4459*8975f5c5SAndroid Build Coastguard Worker 
4460*8975f5c5SAndroid Build Coastguard Worker         if (textureSamplerState.getMinFilter() != defaultSamplerState.getMinFilter())
4461*8975f5c5SAndroid Build Coastguard Worker         {
4462*8975f5c5SAndroid Build Coastguard Worker             capTexParam(GL_TEXTURE_MIN_FILTER, textureSamplerState.getMinFilter());
4463*8975f5c5SAndroid Build Coastguard Worker         }
4464*8975f5c5SAndroid Build Coastguard Worker 
4465*8975f5c5SAndroid Build Coastguard Worker         if (textureSamplerState.getMagFilter() != defaultSamplerState.getMagFilter())
4466*8975f5c5SAndroid Build Coastguard Worker         {
4467*8975f5c5SAndroid Build Coastguard Worker             capTexParam(GL_TEXTURE_MAG_FILTER, textureSamplerState.getMagFilter());
4468*8975f5c5SAndroid Build Coastguard Worker         }
4469*8975f5c5SAndroid Build Coastguard Worker 
4470*8975f5c5SAndroid Build Coastguard Worker         if (textureSamplerState.getWrapR() != defaultSamplerState.getWrapR())
4471*8975f5c5SAndroid Build Coastguard Worker         {
4472*8975f5c5SAndroid Build Coastguard Worker             capTexParam(GL_TEXTURE_WRAP_R, textureSamplerState.getWrapR());
4473*8975f5c5SAndroid Build Coastguard Worker         }
4474*8975f5c5SAndroid Build Coastguard Worker 
4475*8975f5c5SAndroid Build Coastguard Worker         if (textureSamplerState.getWrapS() != defaultSamplerState.getWrapS())
4476*8975f5c5SAndroid Build Coastguard Worker         {
4477*8975f5c5SAndroid Build Coastguard Worker             capTexParam(GL_TEXTURE_WRAP_S, textureSamplerState.getWrapS());
4478*8975f5c5SAndroid Build Coastguard Worker         }
4479*8975f5c5SAndroid Build Coastguard Worker 
4480*8975f5c5SAndroid Build Coastguard Worker         if (textureSamplerState.getWrapT() != defaultSamplerState.getWrapT())
4481*8975f5c5SAndroid Build Coastguard Worker         {
4482*8975f5c5SAndroid Build Coastguard Worker             capTexParam(GL_TEXTURE_WRAP_T, textureSamplerState.getWrapT());
4483*8975f5c5SAndroid Build Coastguard Worker         }
4484*8975f5c5SAndroid Build Coastguard Worker 
4485*8975f5c5SAndroid Build Coastguard Worker         if (textureSamplerState.getMinLod() != defaultSamplerState.getMinLod())
4486*8975f5c5SAndroid Build Coastguard Worker         {
4487*8975f5c5SAndroid Build Coastguard Worker             capTexParamf(GL_TEXTURE_MIN_LOD, textureSamplerState.getMinLod());
4488*8975f5c5SAndroid Build Coastguard Worker         }
4489*8975f5c5SAndroid Build Coastguard Worker 
4490*8975f5c5SAndroid Build Coastguard Worker         if (textureSamplerState.getMaxLod() != defaultSamplerState.getMaxLod())
4491*8975f5c5SAndroid Build Coastguard Worker         {
4492*8975f5c5SAndroid Build Coastguard Worker             capTexParamf(GL_TEXTURE_MAX_LOD, textureSamplerState.getMaxLod());
4493*8975f5c5SAndroid Build Coastguard Worker         }
4494*8975f5c5SAndroid Build Coastguard Worker 
4495*8975f5c5SAndroid Build Coastguard Worker         if (textureSamplerState.getCompareMode() != defaultSamplerState.getCompareMode())
4496*8975f5c5SAndroid Build Coastguard Worker         {
4497*8975f5c5SAndroid Build Coastguard Worker             capTexParam(GL_TEXTURE_COMPARE_MODE, textureSamplerState.getCompareMode());
4498*8975f5c5SAndroid Build Coastguard Worker         }
4499*8975f5c5SAndroid Build Coastguard Worker 
4500*8975f5c5SAndroid Build Coastguard Worker         if (textureSamplerState.getCompareFunc() != defaultSamplerState.getCompareFunc())
4501*8975f5c5SAndroid Build Coastguard Worker         {
4502*8975f5c5SAndroid Build Coastguard Worker             capTexParam(GL_TEXTURE_COMPARE_FUNC, textureSamplerState.getCompareFunc());
4503*8975f5c5SAndroid Build Coastguard Worker         }
4504*8975f5c5SAndroid Build Coastguard Worker 
4505*8975f5c5SAndroid Build Coastguard Worker         // Texture parameters
4506*8975f5c5SAndroid Build Coastguard Worker         if (texture->getSwizzleRed() != GL_RED)
4507*8975f5c5SAndroid Build Coastguard Worker         {
4508*8975f5c5SAndroid Build Coastguard Worker             capTexParam(GL_TEXTURE_SWIZZLE_R, texture->getSwizzleRed());
4509*8975f5c5SAndroid Build Coastguard Worker         }
4510*8975f5c5SAndroid Build Coastguard Worker 
4511*8975f5c5SAndroid Build Coastguard Worker         if (texture->getSwizzleGreen() != GL_GREEN)
4512*8975f5c5SAndroid Build Coastguard Worker         {
4513*8975f5c5SAndroid Build Coastguard Worker             capTexParam(GL_TEXTURE_SWIZZLE_G, texture->getSwizzleGreen());
4514*8975f5c5SAndroid Build Coastguard Worker         }
4515*8975f5c5SAndroid Build Coastguard Worker 
4516*8975f5c5SAndroid Build Coastguard Worker         if (texture->getSwizzleBlue() != GL_BLUE)
4517*8975f5c5SAndroid Build Coastguard Worker         {
4518*8975f5c5SAndroid Build Coastguard Worker             capTexParam(GL_TEXTURE_SWIZZLE_B, texture->getSwizzleBlue());
4519*8975f5c5SAndroid Build Coastguard Worker         }
4520*8975f5c5SAndroid Build Coastguard Worker 
4521*8975f5c5SAndroid Build Coastguard Worker         if (texture->getSwizzleAlpha() != GL_ALPHA)
4522*8975f5c5SAndroid Build Coastguard Worker         {
4523*8975f5c5SAndroid Build Coastguard Worker             capTexParam(GL_TEXTURE_SWIZZLE_A, texture->getSwizzleAlpha());
4524*8975f5c5SAndroid Build Coastguard Worker         }
4525*8975f5c5SAndroid Build Coastguard Worker 
4526*8975f5c5SAndroid Build Coastguard Worker         if (texture->getBaseLevel() != 0)
4527*8975f5c5SAndroid Build Coastguard Worker         {
4528*8975f5c5SAndroid Build Coastguard Worker             capTexParam(GL_TEXTURE_BASE_LEVEL, texture->getBaseLevel());
4529*8975f5c5SAndroid Build Coastguard Worker         }
4530*8975f5c5SAndroid Build Coastguard Worker 
4531*8975f5c5SAndroid Build Coastguard Worker         if (texture->getMaxLevel() != 1000)
4532*8975f5c5SAndroid Build Coastguard Worker         {
4533*8975f5c5SAndroid Build Coastguard Worker             capTexParam(GL_TEXTURE_MAX_LEVEL, texture->getMaxLevel());
4534*8975f5c5SAndroid Build Coastguard Worker         }
4535*8975f5c5SAndroid Build Coastguard Worker 
4536*8975f5c5SAndroid Build Coastguard Worker         // If the texture is immutable, initialize it with TexStorage
4537*8975f5c5SAndroid Build Coastguard Worker         if (texture->getImmutableFormat())
4538*8975f5c5SAndroid Build Coastguard Worker         {
4539*8975f5c5SAndroid Build Coastguard Worker             // We can only call TexStorage *once* on an immutable texture, so it needs special
4540*8975f5c5SAndroid Build Coastguard Worker             // handling. To solve this, immutable textures will have a BindTexture and TexStorage as
4541*8975f5c5SAndroid Build Coastguard Worker             // part of their textureRegenCalls. The resulting regen sequence will be:
4542*8975f5c5SAndroid Build Coastguard Worker             //
4543*8975f5c5SAndroid Build Coastguard Worker             //    const GLuint glDeleteTextures_texturesPacked_0[] = { gTextureMap[52] };
4544*8975f5c5SAndroid Build Coastguard Worker             //    glDeleteTextures(1, glDeleteTextures_texturesPacked_0);
4545*8975f5c5SAndroid Build Coastguard Worker             //    glGenTextures(1, reinterpret_cast<GLuint *>(gReadBuffer));
4546*8975f5c5SAndroid Build Coastguard Worker             //    UpdateTextureID(52, 0);
4547*8975f5c5SAndroid Build Coastguard Worker             //    glBindTexture(GL_TEXTURE_2D, gTextureMap[52]);
4548*8975f5c5SAndroid Build Coastguard Worker             //    glTexStorage2D(GL_TEXTURE_2D, 1, GL_R8, 256, 512);
4549*8975f5c5SAndroid Build Coastguard Worker 
4550*8975f5c5SAndroid Build Coastguard Worker             // Bind the texture first just for textureRegenCalls
4551*8975f5c5SAndroid Build Coastguard Worker             Capture(&textureRegenCalls[id.value],
4552*8975f5c5SAndroid Build Coastguard Worker                     CaptureBindTexture(replayState, true, texture->getType(), id));
4553*8975f5c5SAndroid Build Coastguard Worker 
4554*8975f5c5SAndroid Build Coastguard Worker             // Then add TexStorage to texGenCalls instead of texSetupCalls
4555*8975f5c5SAndroid Build Coastguard Worker             for (std::vector<CallCapture> *calls : texGenCalls)
4556*8975f5c5SAndroid Build Coastguard Worker             {
4557*8975f5c5SAndroid Build Coastguard Worker                 CaptureTextureStorage(calls, &replayState, texture);
4558*8975f5c5SAndroid Build Coastguard Worker             }
4559*8975f5c5SAndroid Build Coastguard Worker         }
4560*8975f5c5SAndroid Build Coastguard Worker 
4561*8975f5c5SAndroid Build Coastguard Worker         // Iterate texture levels and layers.
4562*8975f5c5SAndroid Build Coastguard Worker         gl::ImageIndexIterator imageIter = gl::ImageIndexIterator::MakeGeneric(
4563*8975f5c5SAndroid Build Coastguard Worker             texture->getType(), 0, texture->getMipmapMaxLevel() + 1, gl::ImageIndex::kEntireLevel,
4564*8975f5c5SAndroid Build Coastguard Worker             gl::ImageIndex::kEntireLevel);
4565*8975f5c5SAndroid Build Coastguard Worker         while (imageIter.hasNext())
4566*8975f5c5SAndroid Build Coastguard Worker         {
4567*8975f5c5SAndroid Build Coastguard Worker             gl::ImageIndex index = imageIter.next();
4568*8975f5c5SAndroid Build Coastguard Worker 
4569*8975f5c5SAndroid Build Coastguard Worker             const gl::ImageDesc &desc = texture->getTextureState().getImageDesc(index);
4570*8975f5c5SAndroid Build Coastguard Worker 
4571*8975f5c5SAndroid Build Coastguard Worker             if (desc.size.empty())
4572*8975f5c5SAndroid Build Coastguard Worker             {
4573*8975f5c5SAndroid Build Coastguard Worker                 continue;
4574*8975f5c5SAndroid Build Coastguard Worker             }
4575*8975f5c5SAndroid Build Coastguard Worker 
4576*8975f5c5SAndroid Build Coastguard Worker             const gl::InternalFormat &format = *desc.format.info;
4577*8975f5c5SAndroid Build Coastguard Worker 
4578*8975f5c5SAndroid Build Coastguard Worker             bool supportedType = (index.getType() == gl::TextureType::_2D ||
4579*8975f5c5SAndroid Build Coastguard Worker                                   index.getType() == gl::TextureType::_3D ||
4580*8975f5c5SAndroid Build Coastguard Worker                                   index.getType() == gl::TextureType::_2DArray ||
4581*8975f5c5SAndroid Build Coastguard Worker                                   index.getType() == gl::TextureType::Buffer ||
4582*8975f5c5SAndroid Build Coastguard Worker                                   index.getType() == gl::TextureType::CubeMap ||
4583*8975f5c5SAndroid Build Coastguard Worker                                   index.getType() == gl::TextureType::CubeMapArray ||
4584*8975f5c5SAndroid Build Coastguard Worker                                   index.getType() == gl::TextureType::External);
4585*8975f5c5SAndroid Build Coastguard Worker 
4586*8975f5c5SAndroid Build Coastguard Worker             // Check for supported textures
4587*8975f5c5SAndroid Build Coastguard Worker             if (!supportedType)
4588*8975f5c5SAndroid Build Coastguard Worker             {
4589*8975f5c5SAndroid Build Coastguard Worker                 ERR() << "Unsupported texture type: " << index.getType();
4590*8975f5c5SAndroid Build Coastguard Worker                 UNREACHABLE();
4591*8975f5c5SAndroid Build Coastguard Worker             }
4592*8975f5c5SAndroid Build Coastguard Worker 
4593*8975f5c5SAndroid Build Coastguard Worker             if (index.getType() == gl::TextureType::Buffer)
4594*8975f5c5SAndroid Build Coastguard Worker             {
4595*8975f5c5SAndroid Build Coastguard Worker                 // The buffer contents are already backed up, but we need to emit the TexBuffer
4596*8975f5c5SAndroid Build Coastguard Worker                 // binding calls
4597*8975f5c5SAndroid Build Coastguard Worker                 for (std::vector<CallCapture> *calls : texSetupCalls)
4598*8975f5c5SAndroid Build Coastguard Worker                 {
4599*8975f5c5SAndroid Build Coastguard Worker                     CaptureTextureContents(calls, &replayState, texture, index, desc, 0, 0);
4600*8975f5c5SAndroid Build Coastguard Worker                 }
4601*8975f5c5SAndroid Build Coastguard Worker                 continue;
4602*8975f5c5SAndroid Build Coastguard Worker             }
4603*8975f5c5SAndroid Build Coastguard Worker 
4604*8975f5c5SAndroid Build Coastguard Worker             if (index.getType() == gl::TextureType::External)
4605*8975f5c5SAndroid Build Coastguard Worker             {
4606*8975f5c5SAndroid Build Coastguard Worker                 // Lookup the eglImage ID associated with this texture when the app issued
4607*8975f5c5SAndroid Build Coastguard Worker                 // glEGLImageTargetTexture2DOES()
4608*8975f5c5SAndroid Build Coastguard Worker                 auto eglImageIter = resourceTracker->getTextureIDToImageTable().find(id.value);
4609*8975f5c5SAndroid Build Coastguard Worker                 egl::ImageID eglImageID;
4610*8975f5c5SAndroid Build Coastguard Worker                 if (eglImageIter != resourceTracker->getTextureIDToImageTable().end())
4611*8975f5c5SAndroid Build Coastguard Worker                 {
4612*8975f5c5SAndroid Build Coastguard Worker                     eglImageID = eglImageIter->second;
4613*8975f5c5SAndroid Build Coastguard Worker                 }
4614*8975f5c5SAndroid Build Coastguard Worker                 else
4615*8975f5c5SAndroid Build Coastguard Worker                 {
4616*8975f5c5SAndroid Build Coastguard Worker                     // Original image was deleted and needs to be recreated first
4617*8975f5c5SAndroid Build Coastguard Worker                     eglImageID = {maxAccessedResourceIDs[ResourceIDType::Image] + 1};
4618*8975f5c5SAndroid Build Coastguard Worker                     for (std::vector<CallCapture> *calls : texSetupCalls)
4619*8975f5c5SAndroid Build Coastguard Worker                     {
4620*8975f5c5SAndroid Build Coastguard Worker                         egl::AttributeMap attribs = egl::AttributeMap::CreateFromIntArray(nullptr);
4621*8975f5c5SAndroid Build Coastguard Worker                         CallCapture eglCreateImageKHRCall = egl::CaptureCreateImageKHR(
4622*8975f5c5SAndroid Build Coastguard Worker                             nullptr, true, nullptr, context->id(), EGL_GL_TEXTURE_2D,
4623*8975f5c5SAndroid Build Coastguard Worker                             reinterpret_cast<EGLClientBuffer>(static_cast<uintptr_t>(0)), attribs,
4624*8975f5c5SAndroid Build Coastguard Worker                             reinterpret_cast<EGLImage>(static_cast<uintptr_t>(eglImageID.value)));
4625*8975f5c5SAndroid Build Coastguard Worker                         CaptureCustomCreateEGLImage(context, "CreateEGLImageKHR", desc.size.width,
4626*8975f5c5SAndroid Build Coastguard Worker                                                     desc.size.height, eglCreateImageKHRCall,
4627*8975f5c5SAndroid Build Coastguard Worker                                                     *calls);
4628*8975f5c5SAndroid Build Coastguard Worker                     }
4629*8975f5c5SAndroid Build Coastguard Worker                 }
4630*8975f5c5SAndroid Build Coastguard Worker                 // Pass the eglImage to the texture that is bound to GL_TEXTURE_EXTERNAL_OES target
4631*8975f5c5SAndroid Build Coastguard Worker                 for (std::vector<CallCapture> *calls : texSetupCalls)
4632*8975f5c5SAndroid Build Coastguard Worker                 {
4633*8975f5c5SAndroid Build Coastguard Worker                     Capture(calls, CaptureEGLImageTargetTexture2DOES(
4634*8975f5c5SAndroid Build Coastguard Worker                                        replayState, true, gl::TextureType::External, eglImageID));
4635*8975f5c5SAndroid Build Coastguard Worker                 }
4636*8975f5c5SAndroid Build Coastguard Worker             }
4637*8975f5c5SAndroid Build Coastguard Worker             else if (context->getExtensions().getImageANGLE)
4638*8975f5c5SAndroid Build Coastguard Worker             {
4639*8975f5c5SAndroid Build Coastguard Worker                 // Use ANGLE_get_image to read back pixel data.
4640*8975f5c5SAndroid Build Coastguard Worker                 angle::MemoryBuffer data;
4641*8975f5c5SAndroid Build Coastguard Worker 
4642*8975f5c5SAndroid Build Coastguard Worker                 const gl::Extents extents(desc.size.width, desc.size.height, desc.size.depth);
4643*8975f5c5SAndroid Build Coastguard Worker 
4644*8975f5c5SAndroid Build Coastguard Worker                 gl::PixelPackState packState;
4645*8975f5c5SAndroid Build Coastguard Worker                 packState.alignment = 1;
4646*8975f5c5SAndroid Build Coastguard Worker 
4647*8975f5c5SAndroid Build Coastguard Worker                 if (format.paletted)
4648*8975f5c5SAndroid Build Coastguard Worker                 {
4649*8975f5c5SAndroid Build Coastguard Worker                     // Read back the uncompressed texture, then re-compress it
4650*8975f5c5SAndroid Build Coastguard Worker                     // to store in the trace.
4651*8975f5c5SAndroid Build Coastguard Worker 
4652*8975f5c5SAndroid Build Coastguard Worker                     angle::MemoryBuffer tmp;
4653*8975f5c5SAndroid Build Coastguard Worker 
4654*8975f5c5SAndroid Build Coastguard Worker                     // The uncompressed format (R8G8B8A8) is 4 bytes per texel
4655*8975f5c5SAndroid Build Coastguard Worker                     bool result = tmp.resize(4 * extents.width * extents.height * extents.depth);
4656*8975f5c5SAndroid Build Coastguard Worker                     ASSERT(result);
4657*8975f5c5SAndroid Build Coastguard Worker 
4658*8975f5c5SAndroid Build Coastguard Worker                     (void)texture->getTexImage(context, packState, nullptr, index.getTarget(),
4659*8975f5c5SAndroid Build Coastguard Worker                                                index.getLevelIndex(), GL_RGBA, GL_UNSIGNED_BYTE,
4660*8975f5c5SAndroid Build Coastguard Worker                                                tmp.data());
4661*8975f5c5SAndroid Build Coastguard Worker 
4662*8975f5c5SAndroid Build Coastguard Worker                     CompressPalettedTexture(data, tmp, format, extents);
4663*8975f5c5SAndroid Build Coastguard Worker                 }
4664*8975f5c5SAndroid Build Coastguard Worker                 else if (format.compressed)
4665*8975f5c5SAndroid Build Coastguard Worker                 {
4666*8975f5c5SAndroid Build Coastguard Worker                     // Calculate the size needed to store the compressed level
4667*8975f5c5SAndroid Build Coastguard Worker                     GLuint sizeInBytes;
4668*8975f5c5SAndroid Build Coastguard Worker                     bool result = format.computeCompressedImageSize(extents, &sizeInBytes);
4669*8975f5c5SAndroid Build Coastguard Worker                     ASSERT(result);
4670*8975f5c5SAndroid Build Coastguard Worker 
4671*8975f5c5SAndroid Build Coastguard Worker                     result = data.resize(sizeInBytes);
4672*8975f5c5SAndroid Build Coastguard Worker                     ASSERT(result);
4673*8975f5c5SAndroid Build Coastguard Worker 
4674*8975f5c5SAndroid Build Coastguard Worker                     (void)texture->getCompressedTexImage(context, packState, nullptr,
4675*8975f5c5SAndroid Build Coastguard Worker                                                          index.getTarget(), index.getLevelIndex(),
4676*8975f5c5SAndroid Build Coastguard Worker                                                          data.data());
4677*8975f5c5SAndroid Build Coastguard Worker                 }
4678*8975f5c5SAndroid Build Coastguard Worker                 else
4679*8975f5c5SAndroid Build Coastguard Worker                 {
4680*8975f5c5SAndroid Build Coastguard Worker                     GLenum getFormat = format.format;
4681*8975f5c5SAndroid Build Coastguard Worker                     GLenum getType   = format.type;
4682*8975f5c5SAndroid Build Coastguard Worker 
4683*8975f5c5SAndroid Build Coastguard Worker                     const gl::PixelUnpackState &unpack = apiState.getUnpackState();
4684*8975f5c5SAndroid Build Coastguard Worker 
4685*8975f5c5SAndroid Build Coastguard Worker                     GLuint endByte = 0;
4686*8975f5c5SAndroid Build Coastguard Worker                     bool unpackSize =
4687*8975f5c5SAndroid Build Coastguard Worker                         format.computePackUnpackEndByte(getType, extents, unpack, true, &endByte);
4688*8975f5c5SAndroid Build Coastguard Worker                     ASSERT(unpackSize);
4689*8975f5c5SAndroid Build Coastguard Worker 
4690*8975f5c5SAndroid Build Coastguard Worker                     bool result = data.resize(endByte);
4691*8975f5c5SAndroid Build Coastguard Worker                     ASSERT(result);
4692*8975f5c5SAndroid Build Coastguard Worker 
4693*8975f5c5SAndroid Build Coastguard Worker                     (void)texture->getTexImage(context, packState, nullptr, index.getTarget(),
4694*8975f5c5SAndroid Build Coastguard Worker                                                index.getLevelIndex(), getFormat, getType,
4695*8975f5c5SAndroid Build Coastguard Worker                                                data.data());
4696*8975f5c5SAndroid Build Coastguard Worker                 }
4697*8975f5c5SAndroid Build Coastguard Worker 
4698*8975f5c5SAndroid Build Coastguard Worker                 for (std::vector<CallCapture> *calls : texSetupCalls)
4699*8975f5c5SAndroid Build Coastguard Worker                 {
4700*8975f5c5SAndroid Build Coastguard Worker                     CaptureTextureContents(calls, &replayState, texture, index, desc,
4701*8975f5c5SAndroid Build Coastguard Worker                                            static_cast<GLuint>(data.size()), data.data());
4702*8975f5c5SAndroid Build Coastguard Worker                 }
4703*8975f5c5SAndroid Build Coastguard Worker             }
4704*8975f5c5SAndroid Build Coastguard Worker             else
4705*8975f5c5SAndroid Build Coastguard Worker             {
4706*8975f5c5SAndroid Build Coastguard Worker                 for (std::vector<CallCapture> *calls : texSetupCalls)
4707*8975f5c5SAndroid Build Coastguard Worker                 {
4708*8975f5c5SAndroid Build Coastguard Worker                     CaptureTextureContents(calls, &replayState, texture, index, desc, 0, nullptr);
4709*8975f5c5SAndroid Build Coastguard Worker                 }
4710*8975f5c5SAndroid Build Coastguard Worker             }
4711*8975f5c5SAndroid Build Coastguard Worker         }
4712*8975f5c5SAndroid Build Coastguard Worker 
4713*8975f5c5SAndroid Build Coastguard Worker         size_t textureSetupEnd = setupCalls->size();
4714*8975f5c5SAndroid Build Coastguard Worker 
4715*8975f5c5SAndroid Build Coastguard Worker         // Mark the range of calls used to setup this texture
4716*8975f5c5SAndroid Build Coastguard Worker         frameCaptureShared->markResourceSetupCallsInactive(
4717*8975f5c5SAndroid Build Coastguard Worker             setupCalls, ResourceIDType::Texture, id.value,
4718*8975f5c5SAndroid Build Coastguard Worker             gl::Range<size_t>(textureSetupStart, textureSetupEnd));
4719*8975f5c5SAndroid Build Coastguard Worker     }
4720*8975f5c5SAndroid Build Coastguard Worker 
4721*8975f5c5SAndroid Build Coastguard Worker     // Capture Renderbuffers.
4722*8975f5c5SAndroid Build Coastguard Worker     const gl::RenderbufferManager &renderbuffers = apiState.getRenderbufferManagerForCapture();
4723*8975f5c5SAndroid Build Coastguard Worker     FramebufferCaptureFuncs framebufferFuncs(context->isGLES1());
4724*8975f5c5SAndroid Build Coastguard Worker 
4725*8975f5c5SAndroid Build Coastguard Worker     for (const auto &renderbufIter :
4726*8975f5c5SAndroid Build Coastguard Worker          gl::UnsafeResourceMapIter(renderbuffers.getResourcesForCapture()))
4727*8975f5c5SAndroid Build Coastguard Worker     {
4728*8975f5c5SAndroid Build Coastguard Worker         gl::RenderbufferID id                = {renderbufIter.first};
4729*8975f5c5SAndroid Build Coastguard Worker         const gl::Renderbuffer *renderbuffer = renderbufIter.second;
4730*8975f5c5SAndroid Build Coastguard Worker 
4731*8975f5c5SAndroid Build Coastguard Worker         // Track this as a starting resource that may need to be restored.
4732*8975f5c5SAndroid Build Coastguard Worker         TrackedResource &trackedRenderbuffers =
4733*8975f5c5SAndroid Build Coastguard Worker             resourceTracker->getTrackedResource(context->id(), ResourceIDType::Renderbuffer);
4734*8975f5c5SAndroid Build Coastguard Worker         ResourceSet &startingRenderbuffers = trackedRenderbuffers.getStartingResources();
4735*8975f5c5SAndroid Build Coastguard Worker         startingRenderbuffers.insert(id.value);
4736*8975f5c5SAndroid Build Coastguard Worker 
4737*8975f5c5SAndroid Build Coastguard Worker         // For the initial renderbuffer creation calls, track in the generate list
4738*8975f5c5SAndroid Build Coastguard Worker         ResourceCalls &renderbufferRegenCalls = trackedRenderbuffers.getResourceRegenCalls();
4739*8975f5c5SAndroid Build Coastguard Worker         CallVector rbGenCalls({setupCalls, &renderbufferRegenCalls[id.value]});
4740*8975f5c5SAndroid Build Coastguard Worker 
4741*8975f5c5SAndroid Build Coastguard Worker         // Generate renderbuffer id.
4742*8975f5c5SAndroid Build Coastguard Worker         for (std::vector<CallCapture> *calls : rbGenCalls)
4743*8975f5c5SAndroid Build Coastguard Worker         {
4744*8975f5c5SAndroid Build Coastguard Worker             Capture(calls, framebufferFuncs.genRenderbuffers(replayState, true, 1, &id));
4745*8975f5c5SAndroid Build Coastguard Worker             MaybeCaptureUpdateResourceIDs(context, resourceTracker, calls);
4746*8975f5c5SAndroid Build Coastguard Worker             Capture(calls,
4747*8975f5c5SAndroid Build Coastguard Worker                     framebufferFuncs.bindRenderbuffer(replayState, true, GL_RENDERBUFFER, id));
4748*8975f5c5SAndroid Build Coastguard Worker         }
4749*8975f5c5SAndroid Build Coastguard Worker 
4750*8975f5c5SAndroid Build Coastguard Worker         GLenum internalformat = renderbuffer->getFormat().info->internalFormat;
4751*8975f5c5SAndroid Build Coastguard Worker 
4752*8975f5c5SAndroid Build Coastguard Worker         if (renderbuffer->getSamples() > 0)
4753*8975f5c5SAndroid Build Coastguard Worker         {
4754*8975f5c5SAndroid Build Coastguard Worker             // Note: We could also use extensions if available.
4755*8975f5c5SAndroid Build Coastguard Worker             for (std::vector<CallCapture> *calls : rbGenCalls)
4756*8975f5c5SAndroid Build Coastguard Worker             {
4757*8975f5c5SAndroid Build Coastguard Worker                 Capture(calls,
4758*8975f5c5SAndroid Build Coastguard Worker                         CaptureRenderbufferStorageMultisample(
4759*8975f5c5SAndroid Build Coastguard Worker                             replayState, true, GL_RENDERBUFFER, renderbuffer->getSamples(),
4760*8975f5c5SAndroid Build Coastguard Worker                             internalformat, renderbuffer->getWidth(), renderbuffer->getHeight()));
4761*8975f5c5SAndroid Build Coastguard Worker             }
4762*8975f5c5SAndroid Build Coastguard Worker         }
4763*8975f5c5SAndroid Build Coastguard Worker         else
4764*8975f5c5SAndroid Build Coastguard Worker         {
4765*8975f5c5SAndroid Build Coastguard Worker             for (std::vector<CallCapture> *calls : rbGenCalls)
4766*8975f5c5SAndroid Build Coastguard Worker             {
4767*8975f5c5SAndroid Build Coastguard Worker                 Capture(calls, framebufferFuncs.renderbufferStorage(
4768*8975f5c5SAndroid Build Coastguard Worker                                    replayState, true, GL_RENDERBUFFER, internalformat,
4769*8975f5c5SAndroid Build Coastguard Worker                                    renderbuffer->getWidth(), renderbuffer->getHeight()));
4770*8975f5c5SAndroid Build Coastguard Worker             }
4771*8975f5c5SAndroid Build Coastguard Worker         }
4772*8975f5c5SAndroid Build Coastguard Worker 
4773*8975f5c5SAndroid Build Coastguard Worker         // TODO: Capture renderbuffer contents. http://anglebug.com/42262323
4774*8975f5c5SAndroid Build Coastguard Worker     }
4775*8975f5c5SAndroid Build Coastguard Worker 
4776*8975f5c5SAndroid Build Coastguard Worker     // Capture Shaders and Programs.
4777*8975f5c5SAndroid Build Coastguard Worker     const gl::ShaderProgramManager &shadersAndPrograms =
4778*8975f5c5SAndroid Build Coastguard Worker         apiState.getShaderProgramManagerForCapture();
4779*8975f5c5SAndroid Build Coastguard Worker     const gl::ResourceMap<gl::Shader, gl::ShaderProgramID> &shaders =
4780*8975f5c5SAndroid Build Coastguard Worker         shadersAndPrograms.getShadersForCapture();
4781*8975f5c5SAndroid Build Coastguard Worker     const gl::ResourceMap<gl::Program, gl::ShaderProgramID> &programs =
4782*8975f5c5SAndroid Build Coastguard Worker         shadersAndPrograms.getProgramsForCaptureAndPerf();
4783*8975f5c5SAndroid Build Coastguard Worker 
4784*8975f5c5SAndroid Build Coastguard Worker     TrackedResource &trackedShaderPrograms =
4785*8975f5c5SAndroid Build Coastguard Worker         resourceTracker->getTrackedResource(context->id(), ResourceIDType::ShaderProgram);
4786*8975f5c5SAndroid Build Coastguard Worker 
4787*8975f5c5SAndroid Build Coastguard Worker     // Capture Program binary state.
4788*8975f5c5SAndroid Build Coastguard Worker     gl::ShaderProgramID tempShaderStartID = {resourceTracker->getMaxShaderPrograms()};
4789*8975f5c5SAndroid Build Coastguard Worker     std::map<gl::ShaderProgramID, std::vector<gl::ShaderProgramID>> deferredAttachCalls;
4790*8975f5c5SAndroid Build Coastguard Worker     for (const auto &programIter : gl::UnsafeResourceMapIter(programs))
4791*8975f5c5SAndroid Build Coastguard Worker     {
4792*8975f5c5SAndroid Build Coastguard Worker         gl::ShaderProgramID id = {programIter.first};
4793*8975f5c5SAndroid Build Coastguard Worker         gl::Program *program   = programIter.second;
4794*8975f5c5SAndroid Build Coastguard Worker 
4795*8975f5c5SAndroid Build Coastguard Worker         // Unlinked programs don't have an executable so track in case linking is deferred
4796*8975f5c5SAndroid Build Coastguard Worker         // Programs are shared by contexts in the share group and only need to be captured once.
4797*8975f5c5SAndroid Build Coastguard Worker         if (!program->isLinked())
4798*8975f5c5SAndroid Build Coastguard Worker         {
4799*8975f5c5SAndroid Build Coastguard Worker             frameCaptureShared->setDeferredLinkProgram(id);
4800*8975f5c5SAndroid Build Coastguard Worker 
4801*8975f5c5SAndroid Build Coastguard Worker             if (program->getAttachedShadersCount() > 0)
4802*8975f5c5SAndroid Build Coastguard Worker             {
4803*8975f5c5SAndroid Build Coastguard Worker                 // AttachShader calls will be generated at shader-handling time
4804*8975f5c5SAndroid Build Coastguard Worker                 for (gl::ShaderType shaderType : gl::AllShaderTypes())
4805*8975f5c5SAndroid Build Coastguard Worker                 {
4806*8975f5c5SAndroid Build Coastguard Worker                     gl::Shader *shader = program->getAttachedShader(shaderType);
4807*8975f5c5SAndroid Build Coastguard Worker                     if (shader != nullptr)
4808*8975f5c5SAndroid Build Coastguard Worker                     {
4809*8975f5c5SAndroid Build Coastguard Worker                         deferredAttachCalls[shader->getHandle()].push_back(id);
4810*8975f5c5SAndroid Build Coastguard Worker                     }
4811*8975f5c5SAndroid Build Coastguard Worker                 }
4812*8975f5c5SAndroid Build Coastguard Worker             }
4813*8975f5c5SAndroid Build Coastguard Worker             else
4814*8975f5c5SAndroid Build Coastguard Worker             {
4815*8975f5c5SAndroid Build Coastguard Worker                 WARN() << "Deferred attachment of shaders is not yet supported";
4816*8975f5c5SAndroid Build Coastguard Worker             }
4817*8975f5c5SAndroid Build Coastguard Worker         }
4818*8975f5c5SAndroid Build Coastguard Worker 
4819*8975f5c5SAndroid Build Coastguard Worker         size_t programSetupStart = setupCalls->size();
4820*8975f5c5SAndroid Build Coastguard Worker 
4821*8975f5c5SAndroid Build Coastguard Worker         // Create two lists for program regen calls
4822*8975f5c5SAndroid Build Coastguard Worker         ResourceCalls &shaderProgramRegenCalls = trackedShaderPrograms.getResourceRegenCalls();
4823*8975f5c5SAndroid Build Coastguard Worker         CallVector programRegenCalls({setupCalls, &shaderProgramRegenCalls[id.value]});
4824*8975f5c5SAndroid Build Coastguard Worker 
4825*8975f5c5SAndroid Build Coastguard Worker         for (std::vector<CallCapture> *calls : programRegenCalls)
4826*8975f5c5SAndroid Build Coastguard Worker         {
4827*8975f5c5SAndroid Build Coastguard Worker             CallCapture createProgram = CaptureCreateProgram(replayState, true, id.value);
4828*8975f5c5SAndroid Build Coastguard Worker             CaptureCustomShaderProgram("CreateProgram", createProgram, *calls);
4829*8975f5c5SAndroid Build Coastguard Worker         }
4830*8975f5c5SAndroid Build Coastguard Worker 
4831*8975f5c5SAndroid Build Coastguard Worker         if (program->isLinked())
4832*8975f5c5SAndroid Build Coastguard Worker         {
4833*8975f5c5SAndroid Build Coastguard Worker             // Get last linked shader source.
4834*8975f5c5SAndroid Build Coastguard Worker             const ProgramSources &linkedSources =
4835*8975f5c5SAndroid Build Coastguard Worker                 context->getShareGroup()->getFrameCaptureShared()->getProgramSources(id);
4836*8975f5c5SAndroid Build Coastguard Worker 
4837*8975f5c5SAndroid Build Coastguard Worker             // Create two lists for program restore calls
4838*8975f5c5SAndroid Build Coastguard Worker             ResourceCalls &shaderProgramRestoreCalls =
4839*8975f5c5SAndroid Build Coastguard Worker                 trackedShaderPrograms.getResourceRestoreCalls();
4840*8975f5c5SAndroid Build Coastguard Worker             CallVector programRestoreCalls({setupCalls, &shaderProgramRestoreCalls[id.value]});
4841*8975f5c5SAndroid Build Coastguard Worker 
4842*8975f5c5SAndroid Build Coastguard Worker             for (std::vector<CallCapture> *calls : programRestoreCalls)
4843*8975f5c5SAndroid Build Coastguard Worker             {
4844*8975f5c5SAndroid Build Coastguard Worker                 GenerateLinkedProgram(context, replayState, resourceTracker, calls, program, id,
4845*8975f5c5SAndroid Build Coastguard Worker                                       tempShaderStartID, linkedSources);
4846*8975f5c5SAndroid Build Coastguard Worker             }
4847*8975f5c5SAndroid Build Coastguard Worker 
4848*8975f5c5SAndroid Build Coastguard Worker             // Update the program in replayState
4849*8975f5c5SAndroid Build Coastguard Worker             if (!replayState.getProgram() || replayState.getProgram()->id() != program->id())
4850*8975f5c5SAndroid Build Coastguard Worker             {
4851*8975f5c5SAndroid Build Coastguard Worker                 // Note: We don't do this in GenerateLinkedProgram because it can't modify state
4852*8975f5c5SAndroid Build Coastguard Worker                 (void)replayState.setProgram(context, program);
4853*8975f5c5SAndroid Build Coastguard Worker             }
4854*8975f5c5SAndroid Build Coastguard Worker         }
4855*8975f5c5SAndroid Build Coastguard Worker 
4856*8975f5c5SAndroid Build Coastguard Worker         resourceTracker->getTrackedResource(context->id(), ResourceIDType::ShaderProgram)
4857*8975f5c5SAndroid Build Coastguard Worker             .getStartingResources()
4858*8975f5c5SAndroid Build Coastguard Worker             .insert(id.value);
4859*8975f5c5SAndroid Build Coastguard Worker         resourceTracker->setShaderProgramType(id, ShaderProgramType::ProgramType);
4860*8975f5c5SAndroid Build Coastguard Worker 
4861*8975f5c5SAndroid Build Coastguard Worker         // Mark linked programs/shaders as inactive, leaving deferred-linked programs/shaders marked
4862*8975f5c5SAndroid Build Coastguard Worker         // as active
4863*8975f5c5SAndroid Build Coastguard Worker         if (!frameCaptureShared->isDeferredLinkProgram(id))
4864*8975f5c5SAndroid Build Coastguard Worker         {
4865*8975f5c5SAndroid Build Coastguard Worker             size_t programSetupEnd = setupCalls->size();
4866*8975f5c5SAndroid Build Coastguard Worker 
4867*8975f5c5SAndroid Build Coastguard Worker             // Mark the range of calls used to setup this program
4868*8975f5c5SAndroid Build Coastguard Worker             frameCaptureShared->markResourceSetupCallsInactive(
4869*8975f5c5SAndroid Build Coastguard Worker                 setupCalls, ResourceIDType::ShaderProgram, id.value,
4870*8975f5c5SAndroid Build Coastguard Worker                 gl::Range<size_t>(programSetupStart, programSetupEnd));
4871*8975f5c5SAndroid Build Coastguard Worker         }
4872*8975f5c5SAndroid Build Coastguard Worker     }
4873*8975f5c5SAndroid Build Coastguard Worker 
4874*8975f5c5SAndroid Build Coastguard Worker     // Handle shaders.
4875*8975f5c5SAndroid Build Coastguard Worker     for (const auto &shaderIter : gl::UnsafeResourceMapIter(shaders))
4876*8975f5c5SAndroid Build Coastguard Worker     {
4877*8975f5c5SAndroid Build Coastguard Worker         gl::ShaderProgramID id = {shaderIter.first};
4878*8975f5c5SAndroid Build Coastguard Worker         gl::Shader *shader     = shaderIter.second;
4879*8975f5c5SAndroid Build Coastguard Worker 
4880*8975f5c5SAndroid Build Coastguard Worker         // Skip shaders scheduled for deletion.
4881*8975f5c5SAndroid Build Coastguard Worker         // Shaders are shared by contexts in the share group and only need to be captured once.
4882*8975f5c5SAndroid Build Coastguard Worker         if (shader->hasBeenDeleted())
4883*8975f5c5SAndroid Build Coastguard Worker         {
4884*8975f5c5SAndroid Build Coastguard Worker             continue;
4885*8975f5c5SAndroid Build Coastguard Worker         }
4886*8975f5c5SAndroid Build Coastguard Worker 
4887*8975f5c5SAndroid Build Coastguard Worker         size_t shaderSetupStart = setupCalls->size();
4888*8975f5c5SAndroid Build Coastguard Worker 
4889*8975f5c5SAndroid Build Coastguard Worker         // Create two lists for shader regen calls
4890*8975f5c5SAndroid Build Coastguard Worker         ResourceCalls &shaderProgramRegenCalls = trackedShaderPrograms.getResourceRegenCalls();
4891*8975f5c5SAndroid Build Coastguard Worker         CallVector shaderRegenCalls({setupCalls, &shaderProgramRegenCalls[id.value]});
4892*8975f5c5SAndroid Build Coastguard Worker 
4893*8975f5c5SAndroid Build Coastguard Worker         for (std::vector<CallCapture> *calls : shaderRegenCalls)
4894*8975f5c5SAndroid Build Coastguard Worker         {
4895*8975f5c5SAndroid Build Coastguard Worker             CallCapture createShader =
4896*8975f5c5SAndroid Build Coastguard Worker                 CaptureCreateShader(replayState, true, shader->getType(), id.value);
4897*8975f5c5SAndroid Build Coastguard Worker             CaptureCustomShaderProgram("CreateShader", createShader, *calls);
4898*8975f5c5SAndroid Build Coastguard Worker 
4899*8975f5c5SAndroid Build Coastguard Worker             // If unlinked programs have been created which reference this shader emit corresponding
4900*8975f5c5SAndroid Build Coastguard Worker             // attach calls
4901*8975f5c5SAndroid Build Coastguard Worker             for (const auto deferredAttachedProgramID : deferredAttachCalls[id])
4902*8975f5c5SAndroid Build Coastguard Worker             {
4903*8975f5c5SAndroid Build Coastguard Worker                 CallCapture attachShader =
4904*8975f5c5SAndroid Build Coastguard Worker                     CaptureAttachShader(replayState, true, deferredAttachedProgramID, id);
4905*8975f5c5SAndroid Build Coastguard Worker                 calls->emplace_back(std::move(attachShader));
4906*8975f5c5SAndroid Build Coastguard Worker             }
4907*8975f5c5SAndroid Build Coastguard Worker         }
4908*8975f5c5SAndroid Build Coastguard Worker 
4909*8975f5c5SAndroid Build Coastguard Worker         std::string shaderSource  = shader->getSourceString();
4910*8975f5c5SAndroid Build Coastguard Worker         const char *sourcePointer = shaderSource.empty() ? nullptr : shaderSource.c_str();
4911*8975f5c5SAndroid Build Coastguard Worker 
4912*8975f5c5SAndroid Build Coastguard Worker         // Create two lists for shader restore calls
4913*8975f5c5SAndroid Build Coastguard Worker         ResourceCalls &shaderProgramRestoreCalls = trackedShaderPrograms.getResourceRestoreCalls();
4914*8975f5c5SAndroid Build Coastguard Worker         CallVector shaderRestoreCalls({setupCalls, &shaderProgramRestoreCalls[id.value]});
4915*8975f5c5SAndroid Build Coastguard Worker 
4916*8975f5c5SAndroid Build Coastguard Worker         // This does not handle some more tricky situations like attaching and then deleting a
4917*8975f5c5SAndroid Build Coastguard Worker         // shader.
4918*8975f5c5SAndroid Build Coastguard Worker         // TODO(jmadill): Handle trickier program uses. http://anglebug.com/42262323
4919*8975f5c5SAndroid Build Coastguard Worker         if (shader->isCompiled(context))
4920*8975f5c5SAndroid Build Coastguard Worker         {
4921*8975f5c5SAndroid Build Coastguard Worker             const std::string &capturedSource =
4922*8975f5c5SAndroid Build Coastguard Worker                 context->getShareGroup()->getFrameCaptureShared()->getShaderSource(id);
4923*8975f5c5SAndroid Build Coastguard Worker             if (capturedSource != shaderSource)
4924*8975f5c5SAndroid Build Coastguard Worker             {
4925*8975f5c5SAndroid Build Coastguard Worker                 ASSERT(!capturedSource.empty());
4926*8975f5c5SAndroid Build Coastguard Worker                 sourcePointer = capturedSource.c_str();
4927*8975f5c5SAndroid Build Coastguard Worker             }
4928*8975f5c5SAndroid Build Coastguard Worker 
4929*8975f5c5SAndroid Build Coastguard Worker             for (std::vector<CallCapture> *calls : shaderRestoreCalls)
4930*8975f5c5SAndroid Build Coastguard Worker             {
4931*8975f5c5SAndroid Build Coastguard Worker                 Capture(calls,
4932*8975f5c5SAndroid Build Coastguard Worker                         CaptureShaderSource(replayState, true, id, 1, &sourcePointer, nullptr));
4933*8975f5c5SAndroid Build Coastguard Worker                 Capture(calls, CaptureCompileShader(replayState, true, id));
4934*8975f5c5SAndroid Build Coastguard Worker             }
4935*8975f5c5SAndroid Build Coastguard Worker         }
4936*8975f5c5SAndroid Build Coastguard Worker 
4937*8975f5c5SAndroid Build Coastguard Worker         if (sourcePointer &&
4938*8975f5c5SAndroid Build Coastguard Worker             (!shader->isCompiled(context) || sourcePointer != shaderSource.c_str()))
4939*8975f5c5SAndroid Build Coastguard Worker         {
4940*8975f5c5SAndroid Build Coastguard Worker             for (std::vector<CallCapture> *calls : shaderRestoreCalls)
4941*8975f5c5SAndroid Build Coastguard Worker             {
4942*8975f5c5SAndroid Build Coastguard Worker                 Capture(calls,
4943*8975f5c5SAndroid Build Coastguard Worker                         CaptureShaderSource(replayState, true, id, 1, &sourcePointer, nullptr));
4944*8975f5c5SAndroid Build Coastguard Worker             }
4945*8975f5c5SAndroid Build Coastguard Worker         }
4946*8975f5c5SAndroid Build Coastguard Worker 
4947*8975f5c5SAndroid Build Coastguard Worker         // Deferred-linked programs/shaders must be left marked as active
4948*8975f5c5SAndroid Build Coastguard Worker         if (deferredAttachCalls[id].empty())
4949*8975f5c5SAndroid Build Coastguard Worker         {
4950*8975f5c5SAndroid Build Coastguard Worker             // Mark the range of calls used to setup this shader
4951*8975f5c5SAndroid Build Coastguard Worker             frameCaptureShared->markResourceSetupCallsInactive(
4952*8975f5c5SAndroid Build Coastguard Worker                 setupCalls, ResourceIDType::ShaderProgram, id.value,
4953*8975f5c5SAndroid Build Coastguard Worker                 gl::Range<size_t>(shaderSetupStart, setupCalls->size()));
4954*8975f5c5SAndroid Build Coastguard Worker         }
4955*8975f5c5SAndroid Build Coastguard Worker 
4956*8975f5c5SAndroid Build Coastguard Worker         resourceTracker->getTrackedResource(context->id(), ResourceIDType::ShaderProgram)
4957*8975f5c5SAndroid Build Coastguard Worker             .getStartingResources()
4958*8975f5c5SAndroid Build Coastguard Worker             .insert(id.value);
4959*8975f5c5SAndroid Build Coastguard Worker         resourceTracker->setShaderProgramType(id, ShaderProgramType::ShaderType);
4960*8975f5c5SAndroid Build Coastguard Worker     }
4961*8975f5c5SAndroid Build Coastguard Worker 
4962*8975f5c5SAndroid Build Coastguard Worker     // Capture Sampler Objects
4963*8975f5c5SAndroid Build Coastguard Worker     const gl::SamplerManager &samplers = apiState.getSamplerManagerForCapture();
4964*8975f5c5SAndroid Build Coastguard Worker     for (const auto &samplerIter : gl::UnsafeResourceMapIter(samplers.getResourcesForCapture()))
4965*8975f5c5SAndroid Build Coastguard Worker     {
4966*8975f5c5SAndroid Build Coastguard Worker         gl::SamplerID samplerID = {samplerIter.first};
4967*8975f5c5SAndroid Build Coastguard Worker 
4968*8975f5c5SAndroid Build Coastguard Worker         // Don't gen the sampler if we've seen it before, since they are shared across the context
4969*8975f5c5SAndroid Build Coastguard Worker         // share group.
4970*8975f5c5SAndroid Build Coastguard Worker         cap(CaptureGenSamplers(replayState, true, 1, &samplerID));
4971*8975f5c5SAndroid Build Coastguard Worker         MaybeCaptureUpdateResourceIDs(context, resourceTracker, setupCalls);
4972*8975f5c5SAndroid Build Coastguard Worker 
4973*8975f5c5SAndroid Build Coastguard Worker         gl::Sampler *sampler = samplerIter.second;
4974*8975f5c5SAndroid Build Coastguard Worker         if (!sampler)
4975*8975f5c5SAndroid Build Coastguard Worker         {
4976*8975f5c5SAndroid Build Coastguard Worker             continue;
4977*8975f5c5SAndroid Build Coastguard Worker         }
4978*8975f5c5SAndroid Build Coastguard Worker 
4979*8975f5c5SAndroid Build Coastguard Worker         gl::SamplerState defaultSamplerState;
4980*8975f5c5SAndroid Build Coastguard Worker         if (sampler->getMinFilter() != defaultSamplerState.getMinFilter())
4981*8975f5c5SAndroid Build Coastguard Worker         {
4982*8975f5c5SAndroid Build Coastguard Worker             cap(CaptureSamplerParameteri(replayState, true, samplerID, GL_TEXTURE_MIN_FILTER,
4983*8975f5c5SAndroid Build Coastguard Worker                                          sampler->getMinFilter()));
4984*8975f5c5SAndroid Build Coastguard Worker         }
4985*8975f5c5SAndroid Build Coastguard Worker         if (sampler->getMagFilter() != defaultSamplerState.getMagFilter())
4986*8975f5c5SAndroid Build Coastguard Worker         {
4987*8975f5c5SAndroid Build Coastguard Worker             cap(CaptureSamplerParameteri(replayState, true, samplerID, GL_TEXTURE_MAG_FILTER,
4988*8975f5c5SAndroid Build Coastguard Worker                                          sampler->getMagFilter()));
4989*8975f5c5SAndroid Build Coastguard Worker         }
4990*8975f5c5SAndroid Build Coastguard Worker         if (sampler->getWrapS() != defaultSamplerState.getWrapS())
4991*8975f5c5SAndroid Build Coastguard Worker         {
4992*8975f5c5SAndroid Build Coastguard Worker             cap(CaptureSamplerParameteri(replayState, true, samplerID, GL_TEXTURE_WRAP_S,
4993*8975f5c5SAndroid Build Coastguard Worker                                          sampler->getWrapS()));
4994*8975f5c5SAndroid Build Coastguard Worker         }
4995*8975f5c5SAndroid Build Coastguard Worker         if (sampler->getWrapR() != defaultSamplerState.getWrapR())
4996*8975f5c5SAndroid Build Coastguard Worker         {
4997*8975f5c5SAndroid Build Coastguard Worker             cap(CaptureSamplerParameteri(replayState, true, samplerID, GL_TEXTURE_WRAP_R,
4998*8975f5c5SAndroid Build Coastguard Worker                                          sampler->getWrapR()));
4999*8975f5c5SAndroid Build Coastguard Worker         }
5000*8975f5c5SAndroid Build Coastguard Worker         if (sampler->getWrapT() != defaultSamplerState.getWrapT())
5001*8975f5c5SAndroid Build Coastguard Worker         {
5002*8975f5c5SAndroid Build Coastguard Worker             cap(CaptureSamplerParameteri(replayState, true, samplerID, GL_TEXTURE_WRAP_T,
5003*8975f5c5SAndroid Build Coastguard Worker                                          sampler->getWrapT()));
5004*8975f5c5SAndroid Build Coastguard Worker         }
5005*8975f5c5SAndroid Build Coastguard Worker         if (sampler->getMinLod() != defaultSamplerState.getMinLod())
5006*8975f5c5SAndroid Build Coastguard Worker         {
5007*8975f5c5SAndroid Build Coastguard Worker             cap(CaptureSamplerParameterf(replayState, true, samplerID, GL_TEXTURE_MIN_LOD,
5008*8975f5c5SAndroid Build Coastguard Worker                                          sampler->getMinLod()));
5009*8975f5c5SAndroid Build Coastguard Worker         }
5010*8975f5c5SAndroid Build Coastguard Worker         if (sampler->getMaxLod() != defaultSamplerState.getMaxLod())
5011*8975f5c5SAndroid Build Coastguard Worker         {
5012*8975f5c5SAndroid Build Coastguard Worker             cap(CaptureSamplerParameterf(replayState, true, samplerID, GL_TEXTURE_MAX_LOD,
5013*8975f5c5SAndroid Build Coastguard Worker                                          sampler->getMaxLod()));
5014*8975f5c5SAndroid Build Coastguard Worker         }
5015*8975f5c5SAndroid Build Coastguard Worker         if (sampler->getCompareMode() != defaultSamplerState.getCompareMode())
5016*8975f5c5SAndroid Build Coastguard Worker         {
5017*8975f5c5SAndroid Build Coastguard Worker             cap(CaptureSamplerParameteri(replayState, true, samplerID, GL_TEXTURE_COMPARE_MODE,
5018*8975f5c5SAndroid Build Coastguard Worker                                          sampler->getCompareMode()));
5019*8975f5c5SAndroid Build Coastguard Worker         }
5020*8975f5c5SAndroid Build Coastguard Worker         if (sampler->getCompareFunc() != defaultSamplerState.getCompareFunc())
5021*8975f5c5SAndroid Build Coastguard Worker         {
5022*8975f5c5SAndroid Build Coastguard Worker             cap(CaptureSamplerParameteri(replayState, true, samplerID, GL_TEXTURE_COMPARE_FUNC,
5023*8975f5c5SAndroid Build Coastguard Worker                                          sampler->getCompareFunc()));
5024*8975f5c5SAndroid Build Coastguard Worker         }
5025*8975f5c5SAndroid Build Coastguard Worker     }
5026*8975f5c5SAndroid Build Coastguard Worker 
5027*8975f5c5SAndroid Build Coastguard Worker     // Capture Sync Objects
5028*8975f5c5SAndroid Build Coastguard Worker     const gl::SyncManager &syncs = apiState.getSyncManagerForCapture();
5029*8975f5c5SAndroid Build Coastguard Worker     for (const auto &syncIter : gl::UnsafeResourceMapIter(syncs.getResourcesForCapture()))
5030*8975f5c5SAndroid Build Coastguard Worker     {
5031*8975f5c5SAndroid Build Coastguard Worker         gl::SyncID syncID    = {syncIter.first};
5032*8975f5c5SAndroid Build Coastguard Worker         const gl::Sync *sync = syncIter.second;
5033*8975f5c5SAndroid Build Coastguard Worker         GLsync syncObject    = gl::unsafe_int_to_pointer_cast<GLsync>(syncID.value);
5034*8975f5c5SAndroid Build Coastguard Worker 
5035*8975f5c5SAndroid Build Coastguard Worker         if (!sync)
5036*8975f5c5SAndroid Build Coastguard Worker         {
5037*8975f5c5SAndroid Build Coastguard Worker             continue;
5038*8975f5c5SAndroid Build Coastguard Worker         }
5039*8975f5c5SAndroid Build Coastguard Worker         CallCapture fenceSync =
5040*8975f5c5SAndroid Build Coastguard Worker             CaptureFenceSync(replayState, true, sync->getCondition(), sync->getFlags(), syncObject);
5041*8975f5c5SAndroid Build Coastguard Worker         CaptureCustomFenceSync(fenceSync, *setupCalls);
5042*8975f5c5SAndroid Build Coastguard Worker         CaptureFenceSyncResetCalls(context, replayState, resourceTracker, syncID, syncObject, sync);
5043*8975f5c5SAndroid Build Coastguard Worker         resourceTracker->getStartingFenceSyncs().insert(syncID);
5044*8975f5c5SAndroid Build Coastguard Worker     }
5045*8975f5c5SAndroid Build Coastguard Worker 
5046*8975f5c5SAndroid Build Coastguard Worker     // Capture EGL Sync Objects
5047*8975f5c5SAndroid Build Coastguard Worker     const egl::SyncMap &eglSyncMap = context->getDisplay()->getSyncsForCapture();
5048*8975f5c5SAndroid Build Coastguard Worker     for (const auto &eglSyncIter : eglSyncMap)
5049*8975f5c5SAndroid Build Coastguard Worker     {
5050*8975f5c5SAndroid Build Coastguard Worker         egl::SyncID eglSyncID    = {eglSyncIter.first};
5051*8975f5c5SAndroid Build Coastguard Worker         const egl::Sync *eglSync = eglSyncIter.second.get();
5052*8975f5c5SAndroid Build Coastguard Worker         EGLSync eglSyncObject    = gl::unsafe_int_to_pointer_cast<EGLSync>(eglSyncID.value);
5053*8975f5c5SAndroid Build Coastguard Worker 
5054*8975f5c5SAndroid Build Coastguard Worker         if (!eglSync)
5055*8975f5c5SAndroid Build Coastguard Worker         {
5056*8975f5c5SAndroid Build Coastguard Worker             continue;
5057*8975f5c5SAndroid Build Coastguard Worker         }
5058*8975f5c5SAndroid Build Coastguard Worker         CallCapture createEGLSync =
5059*8975f5c5SAndroid Build Coastguard Worker             CaptureCreateSync(nullptr, true, context->getDisplay(), eglSync->getType(),
5060*8975f5c5SAndroid Build Coastguard Worker                               eglSync->getAttributeMap(), eglSyncObject);
5061*8975f5c5SAndroid Build Coastguard Worker         CaptureCustomCreateEGLSync("CreateEGLSyncKHR", createEGLSync, *setupCalls);
5062*8975f5c5SAndroid Build Coastguard Worker         CaptureEGLSyncResetCalls(context, replayState, resourceTracker, eglSyncID, eglSyncObject,
5063*8975f5c5SAndroid Build Coastguard Worker                                  eglSync);
5064*8975f5c5SAndroid Build Coastguard Worker         resourceTracker->getTrackedResource(context->id(), ResourceIDType::egl_Sync)
5065*8975f5c5SAndroid Build Coastguard Worker             .getStartingResources()
5066*8975f5c5SAndroid Build Coastguard Worker             .insert(eglSyncID.value);
5067*8975f5c5SAndroid Build Coastguard Worker     }
5068*8975f5c5SAndroid Build Coastguard Worker 
5069*8975f5c5SAndroid Build Coastguard Worker     GLint contextUnpackAlignment = context->getState().getUnpackState().alignment;
5070*8975f5c5SAndroid Build Coastguard Worker     if (currentUnpackState.alignment != contextUnpackAlignment)
5071*8975f5c5SAndroid Build Coastguard Worker     {
5072*8975f5c5SAndroid Build Coastguard Worker         cap(CapturePixelStorei(replayState, true, GL_UNPACK_ALIGNMENT, contextUnpackAlignment));
5073*8975f5c5SAndroid Build Coastguard Worker         replayState.getMutablePrivateStateForCapture()->setUnpackAlignment(contextUnpackAlignment);
5074*8975f5c5SAndroid Build Coastguard Worker     }
5075*8975f5c5SAndroid Build Coastguard Worker }
5076*8975f5c5SAndroid Build Coastguard Worker 
CaptureMidExecutionSetup(const gl::Context * context,std::vector<CallCapture> * setupCalls,StateResetHelper & resetHelper,std::vector<CallCapture> * shareGroupSetupCalls,ResourceIDToSetupCallsMap * resourceIDToSetupCalls,ResourceTracker * resourceTracker,gl::State & replayState,bool validationEnabled)5077*8975f5c5SAndroid Build Coastguard Worker void CaptureMidExecutionSetup(const gl::Context *context,
5078*8975f5c5SAndroid Build Coastguard Worker                               std::vector<CallCapture> *setupCalls,
5079*8975f5c5SAndroid Build Coastguard Worker                               StateResetHelper &resetHelper,
5080*8975f5c5SAndroid Build Coastguard Worker                               std::vector<CallCapture> *shareGroupSetupCalls,
5081*8975f5c5SAndroid Build Coastguard Worker                               ResourceIDToSetupCallsMap *resourceIDToSetupCalls,
5082*8975f5c5SAndroid Build Coastguard Worker                               ResourceTracker *resourceTracker,
5083*8975f5c5SAndroid Build Coastguard Worker                               gl::State &replayState,
5084*8975f5c5SAndroid Build Coastguard Worker                               bool validationEnabled)
5085*8975f5c5SAndroid Build Coastguard Worker {
5086*8975f5c5SAndroid Build Coastguard Worker     const gl::State &apiState = context->getState();
5087*8975f5c5SAndroid Build Coastguard Worker 
5088*8975f5c5SAndroid Build Coastguard Worker     // Small helper function to make the code more readable.
5089*8975f5c5SAndroid Build Coastguard Worker     auto cap = [setupCalls](CallCapture &&call) { setupCalls->emplace_back(std::move(call)); };
5090*8975f5c5SAndroid Build Coastguard Worker 
5091*8975f5c5SAndroid Build Coastguard Worker     cap(egl::CaptureMakeCurrent(nullptr, true, nullptr, {0}, {0}, context->id(), EGL_TRUE));
5092*8975f5c5SAndroid Build Coastguard Worker 
5093*8975f5c5SAndroid Build Coastguard Worker     // Vertex input states. Must happen after buffer data initialization. Do not capture on GLES1.
5094*8975f5c5SAndroid Build Coastguard Worker     if (!context->isGLES1())
5095*8975f5c5SAndroid Build Coastguard Worker     {
5096*8975f5c5SAndroid Build Coastguard Worker         CaptureDefaultVertexAttribs(replayState, apiState, setupCalls);
5097*8975f5c5SAndroid Build Coastguard Worker     }
5098*8975f5c5SAndroid Build Coastguard Worker 
5099*8975f5c5SAndroid Build Coastguard Worker     // Capture vertex array objects
5100*8975f5c5SAndroid Build Coastguard Worker     VertexArrayCaptureFuncs vertexArrayFuncs(context->isGLES1());
5101*8975f5c5SAndroid Build Coastguard Worker 
5102*8975f5c5SAndroid Build Coastguard Worker     const gl::VertexArrayMap &vertexArrayMap = context->getVertexArraysForCapture();
5103*8975f5c5SAndroid Build Coastguard Worker     gl::VertexArrayID boundVertexArrayID     = {0};
5104*8975f5c5SAndroid Build Coastguard Worker     for (const auto &vertexArrayIter : gl::UnsafeResourceMapIter(vertexArrayMap))
5105*8975f5c5SAndroid Build Coastguard Worker     {
5106*8975f5c5SAndroid Build Coastguard Worker         TrackedResource &trackedVertexArrays =
5107*8975f5c5SAndroid Build Coastguard Worker             resourceTracker->getTrackedResource(context->id(), ResourceIDType::VertexArray);
5108*8975f5c5SAndroid Build Coastguard Worker 
5109*8975f5c5SAndroid Build Coastguard Worker         gl::VertexArrayID vertexArrayID = {vertexArrayIter.first};
5110*8975f5c5SAndroid Build Coastguard Worker 
5111*8975f5c5SAndroid Build Coastguard Worker         // Track this as a starting resource that may need to be restored
5112*8975f5c5SAndroid Build Coastguard Worker         resourceTracker->getTrackedResource(context->id(), ResourceIDType::VertexArray)
5113*8975f5c5SAndroid Build Coastguard Worker             .getStartingResources()
5114*8975f5c5SAndroid Build Coastguard Worker             .insert(vertexArrayID.value);
5115*8975f5c5SAndroid Build Coastguard Worker 
5116*8975f5c5SAndroid Build Coastguard Worker         // Create two lists of calls for initial setup
5117*8975f5c5SAndroid Build Coastguard Worker         ResourceCalls &vertexArrayRegenCalls = trackedVertexArrays.getResourceRegenCalls();
5118*8975f5c5SAndroid Build Coastguard Worker         CallVector vertexArrayGenCalls({setupCalls, &vertexArrayRegenCalls[vertexArrayID.value]});
5119*8975f5c5SAndroid Build Coastguard Worker 
5120*8975f5c5SAndroid Build Coastguard Worker         if (vertexArrayID.value != 0)
5121*8975f5c5SAndroid Build Coastguard Worker         {
5122*8975f5c5SAndroid Build Coastguard Worker             // Gen the vertex array
5123*8975f5c5SAndroid Build Coastguard Worker             for (std::vector<CallCapture> *calls : vertexArrayGenCalls)
5124*8975f5c5SAndroid Build Coastguard Worker             {
5125*8975f5c5SAndroid Build Coastguard Worker                 Capture(calls,
5126*8975f5c5SAndroid Build Coastguard Worker                         vertexArrayFuncs.genVertexArrays(replayState, true, 1, &vertexArrayID));
5127*8975f5c5SAndroid Build Coastguard Worker                 MaybeCaptureUpdateResourceIDs(context, resourceTracker, calls);
5128*8975f5c5SAndroid Build Coastguard Worker             }
5129*8975f5c5SAndroid Build Coastguard Worker         }
5130*8975f5c5SAndroid Build Coastguard Worker 
5131*8975f5c5SAndroid Build Coastguard Worker         // Create two lists of calls for populating the vertex array
5132*8975f5c5SAndroid Build Coastguard Worker         ResourceCalls &vertexArrayRestoreCalls = trackedVertexArrays.getResourceRestoreCalls();
5133*8975f5c5SAndroid Build Coastguard Worker         CallVector vertexArraySetupCalls(
5134*8975f5c5SAndroid Build Coastguard Worker             {setupCalls, &vertexArrayRestoreCalls[vertexArrayID.value]});
5135*8975f5c5SAndroid Build Coastguard Worker 
5136*8975f5c5SAndroid Build Coastguard Worker         if (vertexArrayIter.second)
5137*8975f5c5SAndroid Build Coastguard Worker         {
5138*8975f5c5SAndroid Build Coastguard Worker             const gl::VertexArray *vertexArray = vertexArrayIter.second;
5139*8975f5c5SAndroid Build Coastguard Worker 
5140*8975f5c5SAndroid Build Coastguard Worker             // Populate the vertex array
5141*8975f5c5SAndroid Build Coastguard Worker             for (std::vector<CallCapture> *calls : vertexArraySetupCalls)
5142*8975f5c5SAndroid Build Coastguard Worker             {
5143*8975f5c5SAndroid Build Coastguard Worker                 // Bind the vertexArray (if needed) and populate it
5144*8975f5c5SAndroid Build Coastguard Worker                 if (vertexArrayID != boundVertexArrayID)
5145*8975f5c5SAndroid Build Coastguard Worker                 {
5146*8975f5c5SAndroid Build Coastguard Worker                     Capture(calls,
5147*8975f5c5SAndroid Build Coastguard Worker                             vertexArrayFuncs.bindVertexArray(replayState, true, vertexArrayID));
5148*8975f5c5SAndroid Build Coastguard Worker                 }
5149*8975f5c5SAndroid Build Coastguard Worker                 CaptureVertexArrayState(calls, context, vertexArray, &replayState);
5150*8975f5c5SAndroid Build Coastguard Worker             }
5151*8975f5c5SAndroid Build Coastguard Worker             boundVertexArrayID = vertexArrayID;
5152*8975f5c5SAndroid Build Coastguard Worker         }
5153*8975f5c5SAndroid Build Coastguard Worker     }
5154*8975f5c5SAndroid Build Coastguard Worker 
5155*8975f5c5SAndroid Build Coastguard Worker     // Bind the current vertex array
5156*8975f5c5SAndroid Build Coastguard Worker     const gl::VertexArray *currentVertexArray = apiState.getVertexArray();
5157*8975f5c5SAndroid Build Coastguard Worker     if (currentVertexArray->id() != boundVertexArrayID)
5158*8975f5c5SAndroid Build Coastguard Worker     {
5159*8975f5c5SAndroid Build Coastguard Worker         cap(vertexArrayFuncs.bindVertexArray(replayState, true, currentVertexArray->id()));
5160*8975f5c5SAndroid Build Coastguard Worker     }
5161*8975f5c5SAndroid Build Coastguard Worker 
5162*8975f5c5SAndroid Build Coastguard Worker     // Track the calls necessary to bind the vertex array back to initial state
5163*8975f5c5SAndroid Build Coastguard Worker     CallResetMap &resetCalls = resetHelper.getResetCalls();
5164*8975f5c5SAndroid Build Coastguard Worker     Capture(&resetCalls[angle::EntryPoint::GLBindVertexArray],
5165*8975f5c5SAndroid Build Coastguard Worker             vertexArrayFuncs.bindVertexArray(replayState, true, currentVertexArray->id()));
5166*8975f5c5SAndroid Build Coastguard Worker 
5167*8975f5c5SAndroid Build Coastguard Worker     // Capture indexed buffer bindings.
5168*8975f5c5SAndroid Build Coastguard Worker     const gl::BufferVector &uniformIndexedBuffers =
5169*8975f5c5SAndroid Build Coastguard Worker         apiState.getOffsetBindingPointerUniformBuffers();
5170*8975f5c5SAndroid Build Coastguard Worker     const gl::BufferVector &atomicCounterIndexedBuffers =
5171*8975f5c5SAndroid Build Coastguard Worker         apiState.getOffsetBindingPointerAtomicCounterBuffers();
5172*8975f5c5SAndroid Build Coastguard Worker     const gl::BufferVector &shaderStorageIndexedBuffers =
5173*8975f5c5SAndroid Build Coastguard Worker         apiState.getOffsetBindingPointerShaderStorageBuffers();
5174*8975f5c5SAndroid Build Coastguard Worker     CaptureIndexedBuffers(replayState, uniformIndexedBuffers, gl::BufferBinding::Uniform,
5175*8975f5c5SAndroid Build Coastguard Worker                           setupCalls);
5176*8975f5c5SAndroid Build Coastguard Worker     CaptureIndexedBuffers(replayState, atomicCounterIndexedBuffers,
5177*8975f5c5SAndroid Build Coastguard Worker                           gl::BufferBinding::AtomicCounter, setupCalls);
5178*8975f5c5SAndroid Build Coastguard Worker     CaptureIndexedBuffers(replayState, shaderStorageIndexedBuffers,
5179*8975f5c5SAndroid Build Coastguard Worker                           gl::BufferBinding::ShaderStorage, setupCalls);
5180*8975f5c5SAndroid Build Coastguard Worker 
5181*8975f5c5SAndroid Build Coastguard Worker     // Capture Buffer bindings.
5182*8975f5c5SAndroid Build Coastguard Worker     const gl::BoundBufferMap &boundBuffers = apiState.getBoundBuffersForCapture();
5183*8975f5c5SAndroid Build Coastguard Worker     for (gl::BufferBinding binding : angle::AllEnums<gl::BufferBinding>())
5184*8975f5c5SAndroid Build Coastguard Worker     {
5185*8975f5c5SAndroid Build Coastguard Worker         gl::BufferID bufferID = boundBuffers[binding].id();
5186*8975f5c5SAndroid Build Coastguard Worker 
5187*8975f5c5SAndroid Build Coastguard Worker         // Filter out redundant buffer binding commands. Note that the code in the previous section
5188*8975f5c5SAndroid Build Coastguard Worker         // only binds to ARRAY_BUFFER. Therefore we only check the array binding against the binding
5189*8975f5c5SAndroid Build Coastguard Worker         // we set earlier.
5190*8975f5c5SAndroid Build Coastguard Worker         const gl::Buffer *arrayBuffer = replayState.getArrayBuffer();
5191*8975f5c5SAndroid Build Coastguard Worker         bool isArray                  = binding == gl::BufferBinding::Array;
5192*8975f5c5SAndroid Build Coastguard Worker         bool isArrayBufferChanging    = isArray && arrayBuffer && arrayBuffer->id() != bufferID;
5193*8975f5c5SAndroid Build Coastguard Worker         if (isArrayBufferChanging || (!isArray && bufferID.value != 0))
5194*8975f5c5SAndroid Build Coastguard Worker         {
5195*8975f5c5SAndroid Build Coastguard Worker             cap(CaptureBindBuffer(replayState, true, binding, bufferID));
5196*8975f5c5SAndroid Build Coastguard Worker             replayState.setBufferBinding(context, binding, boundBuffers[binding].get());
5197*8975f5c5SAndroid Build Coastguard Worker         }
5198*8975f5c5SAndroid Build Coastguard Worker 
5199*8975f5c5SAndroid Build Coastguard Worker         // Restore all buffer bindings for Reset
5200*8975f5c5SAndroid Build Coastguard Worker         if (bufferID.value != 0 || isArrayBufferChanging)
5201*8975f5c5SAndroid Build Coastguard Worker         {
5202*8975f5c5SAndroid Build Coastguard Worker             CaptureBufferBindingResetCalls(replayState, resourceTracker, binding, bufferID);
5203*8975f5c5SAndroid Build Coastguard Worker 
5204*8975f5c5SAndroid Build Coastguard Worker             // Track this as a starting binding
5205*8975f5c5SAndroid Build Coastguard Worker             resetHelper.setStartingBufferBinding(binding, bufferID);
5206*8975f5c5SAndroid Build Coastguard Worker         }
5207*8975f5c5SAndroid Build Coastguard Worker     }
5208*8975f5c5SAndroid Build Coastguard Worker 
5209*8975f5c5SAndroid Build Coastguard Worker     // Set a unpack alignment of 1. Otherwise, computeRowPitch() will compute the wrong value,
5210*8975f5c5SAndroid Build Coastguard Worker     // leading to a crash in memcpy() when capturing the texture contents.
5211*8975f5c5SAndroid Build Coastguard Worker     gl::PixelUnpackState &currentUnpackState = replayState.getUnpackState();
5212*8975f5c5SAndroid Build Coastguard Worker     if (currentUnpackState.alignment != 1)
5213*8975f5c5SAndroid Build Coastguard Worker     {
5214*8975f5c5SAndroid Build Coastguard Worker         cap(CapturePixelStorei(replayState, true, GL_UNPACK_ALIGNMENT, 1));
5215*8975f5c5SAndroid Build Coastguard Worker         replayState.getMutablePrivateStateForCapture()->setUnpackAlignment(1);
5216*8975f5c5SAndroid Build Coastguard Worker     }
5217*8975f5c5SAndroid Build Coastguard Worker 
5218*8975f5c5SAndroid Build Coastguard Worker     // Capture Texture setup and data.
5219*8975f5c5SAndroid Build Coastguard Worker     const gl::TextureBindingMap &apiBoundTextures = apiState.getBoundTexturesForCapture();
5220*8975f5c5SAndroid Build Coastguard Worker     resetHelper.setResetActiveTexture(apiState.getActiveSampler());
5221*8975f5c5SAndroid Build Coastguard Worker 
5222*8975f5c5SAndroid Build Coastguard Worker     // Set Texture bindings.
5223*8975f5c5SAndroid Build Coastguard Worker     for (gl::TextureType textureType : angle::AllEnums<gl::TextureType>())
5224*8975f5c5SAndroid Build Coastguard Worker     {
5225*8975f5c5SAndroid Build Coastguard Worker         const gl::TextureBindingVector &apiBindings = apiBoundTextures[textureType];
5226*8975f5c5SAndroid Build Coastguard Worker         const gl::TextureBindingVector &replayBindings =
5227*8975f5c5SAndroid Build Coastguard Worker             replayState.getBoundTexturesForCapture()[textureType];
5228*8975f5c5SAndroid Build Coastguard Worker         ASSERT(apiBindings.size() == replayBindings.size());
5229*8975f5c5SAndroid Build Coastguard Worker         for (size_t bindingIndex = 0; bindingIndex < apiBindings.size(); ++bindingIndex)
5230*8975f5c5SAndroid Build Coastguard Worker         {
5231*8975f5c5SAndroid Build Coastguard Worker             gl::TextureID apiTextureID    = apiBindings[bindingIndex].id();
5232*8975f5c5SAndroid Build Coastguard Worker             gl::TextureID replayTextureID = replayBindings[bindingIndex].id();
5233*8975f5c5SAndroid Build Coastguard Worker 
5234*8975f5c5SAndroid Build Coastguard Worker             if (apiTextureID != replayTextureID)
5235*8975f5c5SAndroid Build Coastguard Worker             {
5236*8975f5c5SAndroid Build Coastguard Worker                 if (replayState.getActiveSampler() != bindingIndex)
5237*8975f5c5SAndroid Build Coastguard Worker                 {
5238*8975f5c5SAndroid Build Coastguard Worker                     cap(CaptureActiveTexture(replayState, true,
5239*8975f5c5SAndroid Build Coastguard Worker                                              GL_TEXTURE0 + static_cast<GLenum>(bindingIndex)));
5240*8975f5c5SAndroid Build Coastguard Worker                     replayState.getMutablePrivateStateForCapture()->setActiveSampler(
5241*8975f5c5SAndroid Build Coastguard Worker                         static_cast<unsigned int>(bindingIndex));
5242*8975f5c5SAndroid Build Coastguard Worker                 }
5243*8975f5c5SAndroid Build Coastguard Worker 
5244*8975f5c5SAndroid Build Coastguard Worker                 cap(CaptureBindTexture(replayState, true, textureType, apiTextureID));
5245*8975f5c5SAndroid Build Coastguard Worker                 replayState.setSamplerTexture(context, textureType,
5246*8975f5c5SAndroid Build Coastguard Worker                                               apiBindings[bindingIndex].get());
5247*8975f5c5SAndroid Build Coastguard Worker             }
5248*8975f5c5SAndroid Build Coastguard Worker 
5249*8975f5c5SAndroid Build Coastguard Worker             if (apiTextureID.value)
5250*8975f5c5SAndroid Build Coastguard Worker             {
5251*8975f5c5SAndroid Build Coastguard Worker                 // Set this texture as active so it will be generated in Setup
5252*8975f5c5SAndroid Build Coastguard Worker                 MarkResourceIDActive(ResourceIDType::Texture, apiTextureID.value,
5253*8975f5c5SAndroid Build Coastguard Worker                                      shareGroupSetupCalls, resourceIDToSetupCalls);
5254*8975f5c5SAndroid Build Coastguard Worker                 // Save currently bound textures for reset
5255*8975f5c5SAndroid Build Coastguard Worker                 resetHelper.getResetTextureBindings().emplace(
5256*8975f5c5SAndroid Build Coastguard Worker                     std::make_pair(bindingIndex, textureType), apiTextureID);
5257*8975f5c5SAndroid Build Coastguard Worker             }
5258*8975f5c5SAndroid Build Coastguard Worker         }
5259*8975f5c5SAndroid Build Coastguard Worker     }
5260*8975f5c5SAndroid Build Coastguard Worker 
5261*8975f5c5SAndroid Build Coastguard Worker     // Capture Texture Environment
5262*8975f5c5SAndroid Build Coastguard Worker     if (context->isGLES1())
5263*8975f5c5SAndroid Build Coastguard Worker     {
5264*8975f5c5SAndroid Build Coastguard Worker         const gl::Caps &caps = context->getCaps();
5265*8975f5c5SAndroid Build Coastguard Worker         for (GLuint unit = 0; unit < caps.maxMultitextureUnits; ++unit)
5266*8975f5c5SAndroid Build Coastguard Worker         {
5267*8975f5c5SAndroid Build Coastguard Worker             CaptureTextureEnvironmentState(setupCalls, &replayState, &apiState, unit);
5268*8975f5c5SAndroid Build Coastguard Worker         }
5269*8975f5c5SAndroid Build Coastguard Worker     }
5270*8975f5c5SAndroid Build Coastguard Worker 
5271*8975f5c5SAndroid Build Coastguard Worker     // Set active Texture.
5272*8975f5c5SAndroid Build Coastguard Worker     if (replayState.getActiveSampler() != apiState.getActiveSampler())
5273*8975f5c5SAndroid Build Coastguard Worker     {
5274*8975f5c5SAndroid Build Coastguard Worker         cap(CaptureActiveTexture(replayState, true,
5275*8975f5c5SAndroid Build Coastguard Worker                                  GL_TEXTURE0 + static_cast<GLenum>(apiState.getActiveSampler())));
5276*8975f5c5SAndroid Build Coastguard Worker         replayState.getMutablePrivateStateForCapture()->setActiveSampler(
5277*8975f5c5SAndroid Build Coastguard Worker             apiState.getActiveSampler());
5278*8975f5c5SAndroid Build Coastguard Worker     }
5279*8975f5c5SAndroid Build Coastguard Worker 
5280*8975f5c5SAndroid Build Coastguard Worker     // Set Renderbuffer binding.
5281*8975f5c5SAndroid Build Coastguard Worker     FramebufferCaptureFuncs framebufferFuncs(context->isGLES1());
5282*8975f5c5SAndroid Build Coastguard Worker 
5283*8975f5c5SAndroid Build Coastguard Worker     const gl::RenderbufferManager &renderbuffers = apiState.getRenderbufferManagerForCapture();
5284*8975f5c5SAndroid Build Coastguard Worker     gl::RenderbufferID currentRenderbuffer       = {0};
5285*8975f5c5SAndroid Build Coastguard Worker     for (const auto &renderbufIter :
5286*8975f5c5SAndroid Build Coastguard Worker          gl::UnsafeResourceMapIter(renderbuffers.getResourcesForCapture()))
5287*8975f5c5SAndroid Build Coastguard Worker     {
5288*8975f5c5SAndroid Build Coastguard Worker         currentRenderbuffer = renderbufIter.second->id();
5289*8975f5c5SAndroid Build Coastguard Worker     }
5290*8975f5c5SAndroid Build Coastguard Worker 
5291*8975f5c5SAndroid Build Coastguard Worker     if (currentRenderbuffer != apiState.getRenderbufferId())
5292*8975f5c5SAndroid Build Coastguard Worker     {
5293*8975f5c5SAndroid Build Coastguard Worker         cap(framebufferFuncs.bindRenderbuffer(replayState, true, GL_RENDERBUFFER,
5294*8975f5c5SAndroid Build Coastguard Worker                                               apiState.getRenderbufferId()));
5295*8975f5c5SAndroid Build Coastguard Worker     }
5296*8975f5c5SAndroid Build Coastguard Worker 
5297*8975f5c5SAndroid Build Coastguard Worker     // Capture Framebuffers.
5298*8975f5c5SAndroid Build Coastguard Worker     const gl::FramebufferManager &framebuffers = apiState.getFramebufferManagerForCapture();
5299*8975f5c5SAndroid Build Coastguard Worker 
5300*8975f5c5SAndroid Build Coastguard Worker     gl::FramebufferID currentDrawFramebuffer = {0};
5301*8975f5c5SAndroid Build Coastguard Worker     gl::FramebufferID currentReadFramebuffer = {0};
5302*8975f5c5SAndroid Build Coastguard Worker 
5303*8975f5c5SAndroid Build Coastguard Worker     for (const auto &framebufferIter :
5304*8975f5c5SAndroid Build Coastguard Worker          gl::UnsafeResourceMapIter(framebuffers.getResourcesForCapture()))
5305*8975f5c5SAndroid Build Coastguard Worker     {
5306*8975f5c5SAndroid Build Coastguard Worker         gl::FramebufferID id               = {framebufferIter.first};
5307*8975f5c5SAndroid Build Coastguard Worker         const gl::Framebuffer *framebuffer = framebufferIter.second;
5308*8975f5c5SAndroid Build Coastguard Worker 
5309*8975f5c5SAndroid Build Coastguard Worker         // The default Framebuffer exists (by default).
5310*8975f5c5SAndroid Build Coastguard Worker         if (framebuffer->isDefault())
5311*8975f5c5SAndroid Build Coastguard Worker         {
5312*8975f5c5SAndroid Build Coastguard Worker             continue;
5313*8975f5c5SAndroid Build Coastguard Worker         }
5314*8975f5c5SAndroid Build Coastguard Worker 
5315*8975f5c5SAndroid Build Coastguard Worker         // Track this as a starting resource that may need to be restored
5316*8975f5c5SAndroid Build Coastguard Worker         TrackedResource &trackedFramebuffers =
5317*8975f5c5SAndroid Build Coastguard Worker             resourceTracker->getTrackedResource(context->id(), ResourceIDType::Framebuffer);
5318*8975f5c5SAndroid Build Coastguard Worker         ResourceSet &startingFramebuffers = trackedFramebuffers.getStartingResources();
5319*8975f5c5SAndroid Build Coastguard Worker         startingFramebuffers.insert(id.value);
5320*8975f5c5SAndroid Build Coastguard Worker 
5321*8975f5c5SAndroid Build Coastguard Worker         // Create two lists of calls for initial setup
5322*8975f5c5SAndroid Build Coastguard Worker         ResourceCalls &framebufferRegenCalls = trackedFramebuffers.getResourceRegenCalls();
5323*8975f5c5SAndroid Build Coastguard Worker         CallVector framebufferGenCalls({setupCalls, &framebufferRegenCalls[id.value]});
5324*8975f5c5SAndroid Build Coastguard Worker 
5325*8975f5c5SAndroid Build Coastguard Worker         // Gen the framebuffer
5326*8975f5c5SAndroid Build Coastguard Worker         for (std::vector<CallCapture> *calls : framebufferGenCalls)
5327*8975f5c5SAndroid Build Coastguard Worker         {
5328*8975f5c5SAndroid Build Coastguard Worker             Capture(calls, framebufferFuncs.genFramebuffers(replayState, true, 1, &id));
5329*8975f5c5SAndroid Build Coastguard Worker             MaybeCaptureUpdateResourceIDs(context, resourceTracker, calls);
5330*8975f5c5SAndroid Build Coastguard Worker         }
5331*8975f5c5SAndroid Build Coastguard Worker 
5332*8975f5c5SAndroid Build Coastguard Worker         // Create two lists of calls for remaining setup calls.  One for setup, and one for restore
5333*8975f5c5SAndroid Build Coastguard Worker         // during reset.
5334*8975f5c5SAndroid Build Coastguard Worker         ResourceCalls &framebufferRestoreCalls = trackedFramebuffers.getResourceRestoreCalls();
5335*8975f5c5SAndroid Build Coastguard Worker         CallVector framebufferSetupCalls({setupCalls, &framebufferRestoreCalls[id.value]});
5336*8975f5c5SAndroid Build Coastguard Worker 
5337*8975f5c5SAndroid Build Coastguard Worker         for (std::vector<CallCapture> *calls : framebufferSetupCalls)
5338*8975f5c5SAndroid Build Coastguard Worker         {
5339*8975f5c5SAndroid Build Coastguard Worker             Capture(calls, framebufferFuncs.bindFramebuffer(replayState, true, GL_FRAMEBUFFER, id));
5340*8975f5c5SAndroid Build Coastguard Worker             // Set current context for this CallCapture
5341*8975f5c5SAndroid Build Coastguard Worker             calls->back().contextID = context->id();
5342*8975f5c5SAndroid Build Coastguard Worker         }
5343*8975f5c5SAndroid Build Coastguard Worker         currentDrawFramebuffer = currentReadFramebuffer = id;
5344*8975f5c5SAndroid Build Coastguard Worker 
5345*8975f5c5SAndroid Build Coastguard Worker         // Color Attachments.
5346*8975f5c5SAndroid Build Coastguard Worker         for (const gl::FramebufferAttachment &colorAttachment : framebuffer->getColorAttachments())
5347*8975f5c5SAndroid Build Coastguard Worker         {
5348*8975f5c5SAndroid Build Coastguard Worker             if (!colorAttachment.isAttached())
5349*8975f5c5SAndroid Build Coastguard Worker             {
5350*8975f5c5SAndroid Build Coastguard Worker                 continue;
5351*8975f5c5SAndroid Build Coastguard Worker             }
5352*8975f5c5SAndroid Build Coastguard Worker 
5353*8975f5c5SAndroid Build Coastguard Worker             for (std::vector<CallCapture> *calls : framebufferSetupCalls)
5354*8975f5c5SAndroid Build Coastguard Worker             {
5355*8975f5c5SAndroid Build Coastguard Worker                 CaptureFramebufferAttachment(calls, replayState, framebufferFuncs, colorAttachment,
5356*8975f5c5SAndroid Build Coastguard Worker                                              shareGroupSetupCalls, resourceIDToSetupCalls);
5357*8975f5c5SAndroid Build Coastguard Worker             }
5358*8975f5c5SAndroid Build Coastguard Worker         }
5359*8975f5c5SAndroid Build Coastguard Worker 
5360*8975f5c5SAndroid Build Coastguard Worker         const gl::FramebufferAttachment *depthAttachment = framebuffer->getDepthAttachment();
5361*8975f5c5SAndroid Build Coastguard Worker         if (depthAttachment)
5362*8975f5c5SAndroid Build Coastguard Worker         {
5363*8975f5c5SAndroid Build Coastguard Worker             ASSERT(depthAttachment->getBinding() == GL_DEPTH_ATTACHMENT ||
5364*8975f5c5SAndroid Build Coastguard Worker                    depthAttachment->getBinding() == GL_DEPTH_STENCIL_ATTACHMENT);
5365*8975f5c5SAndroid Build Coastguard Worker             for (std::vector<CallCapture> *calls : framebufferSetupCalls)
5366*8975f5c5SAndroid Build Coastguard Worker             {
5367*8975f5c5SAndroid Build Coastguard Worker                 CaptureFramebufferAttachment(calls, replayState, framebufferFuncs, *depthAttachment,
5368*8975f5c5SAndroid Build Coastguard Worker                                              shareGroupSetupCalls, resourceIDToSetupCalls);
5369*8975f5c5SAndroid Build Coastguard Worker             }
5370*8975f5c5SAndroid Build Coastguard Worker         }
5371*8975f5c5SAndroid Build Coastguard Worker 
5372*8975f5c5SAndroid Build Coastguard Worker         const gl::FramebufferAttachment *stencilAttachment = framebuffer->getStencilAttachment();
5373*8975f5c5SAndroid Build Coastguard Worker         if (stencilAttachment)
5374*8975f5c5SAndroid Build Coastguard Worker         {
5375*8975f5c5SAndroid Build Coastguard Worker             ASSERT(stencilAttachment->getBinding() == GL_STENCIL_ATTACHMENT ||
5376*8975f5c5SAndroid Build Coastguard Worker                    depthAttachment->getBinding() == GL_DEPTH_STENCIL_ATTACHMENT);
5377*8975f5c5SAndroid Build Coastguard Worker             for (std::vector<CallCapture> *calls : framebufferSetupCalls)
5378*8975f5c5SAndroid Build Coastguard Worker             {
5379*8975f5c5SAndroid Build Coastguard Worker                 CaptureFramebufferAttachment(calls, replayState, framebufferFuncs,
5380*8975f5c5SAndroid Build Coastguard Worker                                              *stencilAttachment, shareGroupSetupCalls,
5381*8975f5c5SAndroid Build Coastguard Worker                                              resourceIDToSetupCalls);
5382*8975f5c5SAndroid Build Coastguard Worker             }
5383*8975f5c5SAndroid Build Coastguard Worker         }
5384*8975f5c5SAndroid Build Coastguard Worker 
5385*8975f5c5SAndroid Build Coastguard Worker         gl::FramebufferState defaultFramebufferState(
5386*8975f5c5SAndroid Build Coastguard Worker             context->getCaps(), framebuffer->getState().id(),
5387*8975f5c5SAndroid Build Coastguard Worker             framebuffer->getState().getFramebufferSerial());
5388*8975f5c5SAndroid Build Coastguard Worker         const gl::DrawBuffersVector<GLenum> &defaultDrawBufferStates =
5389*8975f5c5SAndroid Build Coastguard Worker             defaultFramebufferState.getDrawBufferStates();
5390*8975f5c5SAndroid Build Coastguard Worker         const gl::DrawBuffersVector<GLenum> &drawBufferStates = framebuffer->getDrawBufferStates();
5391*8975f5c5SAndroid Build Coastguard Worker 
5392*8975f5c5SAndroid Build Coastguard Worker         if (drawBufferStates != defaultDrawBufferStates)
5393*8975f5c5SAndroid Build Coastguard Worker         {
5394*8975f5c5SAndroid Build Coastguard Worker             for (std::vector<CallCapture> *calls : framebufferSetupCalls)
5395*8975f5c5SAndroid Build Coastguard Worker             {
5396*8975f5c5SAndroid Build Coastguard Worker                 Capture(calls, CaptureDrawBuffers(replayState, true,
5397*8975f5c5SAndroid Build Coastguard Worker                                                   static_cast<GLsizei>(drawBufferStates.size()),
5398*8975f5c5SAndroid Build Coastguard Worker                                                   drawBufferStates.data()));
5399*8975f5c5SAndroid Build Coastguard Worker             }
5400*8975f5c5SAndroid Build Coastguard Worker         }
5401*8975f5c5SAndroid Build Coastguard Worker     }
5402*8975f5c5SAndroid Build Coastguard Worker 
5403*8975f5c5SAndroid Build Coastguard Worker     // Capture framebuffer bindings.
5404*8975f5c5SAndroid Build Coastguard Worker     if (apiState.getDrawFramebuffer())
5405*8975f5c5SAndroid Build Coastguard Worker     {
5406*8975f5c5SAndroid Build Coastguard Worker         ASSERT(apiState.getReadFramebuffer());
5407*8975f5c5SAndroid Build Coastguard Worker         gl::FramebufferID stateReadFramebuffer = apiState.getReadFramebuffer()->id();
5408*8975f5c5SAndroid Build Coastguard Worker         gl::FramebufferID stateDrawFramebuffer = apiState.getDrawFramebuffer()->id();
5409*8975f5c5SAndroid Build Coastguard Worker         if (stateDrawFramebuffer == stateReadFramebuffer)
5410*8975f5c5SAndroid Build Coastguard Worker         {
5411*8975f5c5SAndroid Build Coastguard Worker             if (currentDrawFramebuffer != stateDrawFramebuffer ||
5412*8975f5c5SAndroid Build Coastguard Worker                 currentReadFramebuffer != stateReadFramebuffer)
5413*8975f5c5SAndroid Build Coastguard Worker             {
5414*8975f5c5SAndroid Build Coastguard Worker                 cap(framebufferFuncs.bindFramebuffer(replayState, true, GL_FRAMEBUFFER,
5415*8975f5c5SAndroid Build Coastguard Worker                                                      stateDrawFramebuffer));
5416*8975f5c5SAndroid Build Coastguard Worker                 currentDrawFramebuffer = currentReadFramebuffer = stateDrawFramebuffer;
5417*8975f5c5SAndroid Build Coastguard Worker             }
5418*8975f5c5SAndroid Build Coastguard Worker         }
5419*8975f5c5SAndroid Build Coastguard Worker         else
5420*8975f5c5SAndroid Build Coastguard Worker         {
5421*8975f5c5SAndroid Build Coastguard Worker             if (currentDrawFramebuffer != stateDrawFramebuffer)
5422*8975f5c5SAndroid Build Coastguard Worker             {
5423*8975f5c5SAndroid Build Coastguard Worker                 cap(framebufferFuncs.bindFramebuffer(replayState, true, GL_DRAW_FRAMEBUFFER,
5424*8975f5c5SAndroid Build Coastguard Worker                                                      currentDrawFramebuffer));
5425*8975f5c5SAndroid Build Coastguard Worker                 currentDrawFramebuffer = stateDrawFramebuffer;
5426*8975f5c5SAndroid Build Coastguard Worker             }
5427*8975f5c5SAndroid Build Coastguard Worker 
5428*8975f5c5SAndroid Build Coastguard Worker             if (currentReadFramebuffer != stateReadFramebuffer)
5429*8975f5c5SAndroid Build Coastguard Worker             {
5430*8975f5c5SAndroid Build Coastguard Worker                 cap(framebufferFuncs.bindFramebuffer(replayState, true, GL_READ_FRAMEBUFFER,
5431*8975f5c5SAndroid Build Coastguard Worker                                                      replayState.getReadFramebuffer()->id()));
5432*8975f5c5SAndroid Build Coastguard Worker                 currentReadFramebuffer = stateReadFramebuffer;
5433*8975f5c5SAndroid Build Coastguard Worker             }
5434*8975f5c5SAndroid Build Coastguard Worker         }
5435*8975f5c5SAndroid Build Coastguard Worker     }
5436*8975f5c5SAndroid Build Coastguard Worker 
5437*8975f5c5SAndroid Build Coastguard Worker     // Capture Program Pipelines
5438*8975f5c5SAndroid Build Coastguard Worker     const gl::ProgramPipelineManager *programPipelineManager =
5439*8975f5c5SAndroid Build Coastguard Worker         apiState.getProgramPipelineManagerForCapture();
5440*8975f5c5SAndroid Build Coastguard Worker 
5441*8975f5c5SAndroid Build Coastguard Worker     for (const auto &ppoIterator :
5442*8975f5c5SAndroid Build Coastguard Worker          gl::UnsafeResourceMapIter(programPipelineManager->getResourcesForCapture()))
5443*8975f5c5SAndroid Build Coastguard Worker     {
5444*8975f5c5SAndroid Build Coastguard Worker         gl::ProgramPipeline *pipeline = ppoIterator.second;
5445*8975f5c5SAndroid Build Coastguard Worker         gl::ProgramPipelineID id      = {ppoIterator.first};
5446*8975f5c5SAndroid Build Coastguard Worker         cap(CaptureGenProgramPipelines(replayState, true, 1, &id));
5447*8975f5c5SAndroid Build Coastguard Worker         MaybeCaptureUpdateResourceIDs(context, resourceTracker, setupCalls);
5448*8975f5c5SAndroid Build Coastguard Worker 
5449*8975f5c5SAndroid Build Coastguard Worker         // PPOs can contain graphics and compute programs, so loop through all shader types rather
5450*8975f5c5SAndroid Build Coastguard Worker         // than just the linked ones since getLinkedShaderStages() will return either only graphics
5451*8975f5c5SAndroid Build Coastguard Worker         // or compute stages.
5452*8975f5c5SAndroid Build Coastguard Worker         for (gl::ShaderType shaderType : gl::AllShaderTypes())
5453*8975f5c5SAndroid Build Coastguard Worker         {
5454*8975f5c5SAndroid Build Coastguard Worker             const gl::Program *program = pipeline->getShaderProgram(shaderType);
5455*8975f5c5SAndroid Build Coastguard Worker             if (!program)
5456*8975f5c5SAndroid Build Coastguard Worker             {
5457*8975f5c5SAndroid Build Coastguard Worker                 continue;
5458*8975f5c5SAndroid Build Coastguard Worker             }
5459*8975f5c5SAndroid Build Coastguard Worker             ASSERT(program->isLinked());
5460*8975f5c5SAndroid Build Coastguard Worker             GLbitfield gLbitfield = GetBitfieldFromShaderType(shaderType);
5461*8975f5c5SAndroid Build Coastguard Worker             cap(CaptureUseProgramStages(replayState, true, pipeline->id(), gLbitfield,
5462*8975f5c5SAndroid Build Coastguard Worker                                         program->id()));
5463*8975f5c5SAndroid Build Coastguard Worker 
5464*8975f5c5SAndroid Build Coastguard Worker             // Set this program as active so it will be generated in Setup
5465*8975f5c5SAndroid Build Coastguard Worker             // Note: We aren't filtering ProgramPipelines, so this could be setting programs
5466*8975f5c5SAndroid Build Coastguard Worker             // active that aren't actually used.
5467*8975f5c5SAndroid Build Coastguard Worker             MarkResourceIDActive(ResourceIDType::ShaderProgram, program->id().value,
5468*8975f5c5SAndroid Build Coastguard Worker                                  shareGroupSetupCalls, resourceIDToSetupCalls);
5469*8975f5c5SAndroid Build Coastguard Worker         }
5470*8975f5c5SAndroid Build Coastguard Worker 
5471*8975f5c5SAndroid Build Coastguard Worker         gl::Program *program = pipeline->getActiveShaderProgram();
5472*8975f5c5SAndroid Build Coastguard Worker         if (program)
5473*8975f5c5SAndroid Build Coastguard Worker         {
5474*8975f5c5SAndroid Build Coastguard Worker             cap(CaptureActiveShaderProgram(replayState, true, id, program->id()));
5475*8975f5c5SAndroid Build Coastguard Worker         }
5476*8975f5c5SAndroid Build Coastguard Worker     }
5477*8975f5c5SAndroid Build Coastguard Worker 
5478*8975f5c5SAndroid Build Coastguard Worker     // For now we assume the installed program executable is the same as the current program.
5479*8975f5c5SAndroid Build Coastguard Worker     // TODO(jmadill): Handle installed program executable. http://anglebug.com/42262323
5480*8975f5c5SAndroid Build Coastguard Worker     if (!context->isGLES1())
5481*8975f5c5SAndroid Build Coastguard Worker     {
5482*8975f5c5SAndroid Build Coastguard Worker         // If we have a program bound in the API, or if there is no program bound to the API at
5483*8975f5c5SAndroid Build Coastguard Worker         // time of capture and we bound a program for uniform updates during MEC, we must add
5484*8975f5c5SAndroid Build Coastguard Worker         // a set program call to replay the correct states.
5485*8975f5c5SAndroid Build Coastguard Worker         GLuint currentProgram = 0;
5486*8975f5c5SAndroid Build Coastguard Worker         if (apiState.getProgram())
5487*8975f5c5SAndroid Build Coastguard Worker         {
5488*8975f5c5SAndroid Build Coastguard Worker             cap(CaptureUseProgram(replayState, true, apiState.getProgram()->id()));
5489*8975f5c5SAndroid Build Coastguard Worker             CaptureUpdateCurrentProgram(setupCalls->back(), 0, setupCalls);
5490*8975f5c5SAndroid Build Coastguard Worker             (void)replayState.setProgram(context, apiState.getProgram());
5491*8975f5c5SAndroid Build Coastguard Worker 
5492*8975f5c5SAndroid Build Coastguard Worker             // Set this program as active so it will be generated in Setup
5493*8975f5c5SAndroid Build Coastguard Worker             MarkResourceIDActive(ResourceIDType::ShaderProgram, apiState.getProgram()->id().value,
5494*8975f5c5SAndroid Build Coastguard Worker                                  shareGroupSetupCalls, resourceIDToSetupCalls);
5495*8975f5c5SAndroid Build Coastguard Worker 
5496*8975f5c5SAndroid Build Coastguard Worker             currentProgram = apiState.getProgram()->id().value;
5497*8975f5c5SAndroid Build Coastguard Worker         }
5498*8975f5c5SAndroid Build Coastguard Worker         else if (replayState.getProgram())
5499*8975f5c5SAndroid Build Coastguard Worker         {
5500*8975f5c5SAndroid Build Coastguard Worker             cap(CaptureUseProgram(replayState, true, {0}));
5501*8975f5c5SAndroid Build Coastguard Worker             CaptureUpdateCurrentProgram(setupCalls->back(), 0, setupCalls);
5502*8975f5c5SAndroid Build Coastguard Worker             (void)replayState.setProgram(context, nullptr);
5503*8975f5c5SAndroid Build Coastguard Worker         }
5504*8975f5c5SAndroid Build Coastguard Worker 
5505*8975f5c5SAndroid Build Coastguard Worker         // Track the calls necessary to reset active program back to initial state
5506*8975f5c5SAndroid Build Coastguard Worker         Capture(&resetCalls[angle::EntryPoint::GLUseProgram],
5507*8975f5c5SAndroid Build Coastguard Worker                 CaptureUseProgram(replayState, true, {currentProgram}));
5508*8975f5c5SAndroid Build Coastguard Worker         CaptureUpdateCurrentProgram((&resetCalls[angle::EntryPoint::GLUseProgram])->back(), 0,
5509*8975f5c5SAndroid Build Coastguard Worker                                     &resetCalls[angle::EntryPoint::GLUseProgram]);
5510*8975f5c5SAndroid Build Coastguard Worker 
5511*8975f5c5SAndroid Build Coastguard Worker         // Same for program pipelines as for programs, see comment above.
5512*8975f5c5SAndroid Build Coastguard Worker         if (apiState.getProgramPipeline())
5513*8975f5c5SAndroid Build Coastguard Worker         {
5514*8975f5c5SAndroid Build Coastguard Worker             cap(CaptureBindProgramPipeline(replayState, true, apiState.getProgramPipeline()->id()));
5515*8975f5c5SAndroid Build Coastguard Worker         }
5516*8975f5c5SAndroid Build Coastguard Worker         else if (replayState.getProgramPipeline())
5517*8975f5c5SAndroid Build Coastguard Worker         {
5518*8975f5c5SAndroid Build Coastguard Worker             cap(CaptureBindProgramPipeline(replayState, true, {0}));
5519*8975f5c5SAndroid Build Coastguard Worker         }
5520*8975f5c5SAndroid Build Coastguard Worker     }
5521*8975f5c5SAndroid Build Coastguard Worker 
5522*8975f5c5SAndroid Build Coastguard Worker     // Capture Queries
5523*8975f5c5SAndroid Build Coastguard Worker     const gl::QueryMap &queryMap = context->getQueriesForCapture();
5524*8975f5c5SAndroid Build Coastguard Worker 
5525*8975f5c5SAndroid Build Coastguard Worker     // Create existing queries. Note that queries may be genned and not yet started. In that
5526*8975f5c5SAndroid Build Coastguard Worker     // case the queries will exist in the query map as nullptr entries.
5527*8975f5c5SAndroid Build Coastguard Worker     // If any queries are active between frames, we want to defer creation and do them last,
5528*8975f5c5SAndroid Build Coastguard Worker     // otherwise you'll get GL errors about starting a query while one is already active.
5529*8975f5c5SAndroid Build Coastguard Worker     for (gl::QueryMap::Iterator queryIter = gl::UnsafeResourceMapIter(queryMap).beginWithNull(),
5530*8975f5c5SAndroid Build Coastguard Worker                                 endIter   = gl::UnsafeResourceMapIter(queryMap).endWithNull();
5531*8975f5c5SAndroid Build Coastguard Worker          queryIter != endIter; ++queryIter)
5532*8975f5c5SAndroid Build Coastguard Worker     {
5533*8975f5c5SAndroid Build Coastguard Worker         ASSERT(queryIter->first);
5534*8975f5c5SAndroid Build Coastguard Worker         gl::QueryID queryID = {queryIter->first};
5535*8975f5c5SAndroid Build Coastguard Worker 
5536*8975f5c5SAndroid Build Coastguard Worker         cap(CaptureGenQueries(replayState, true, 1, &queryID));
5537*8975f5c5SAndroid Build Coastguard Worker         MaybeCaptureUpdateResourceIDs(context, resourceTracker, setupCalls);
5538*8975f5c5SAndroid Build Coastguard Worker 
5539*8975f5c5SAndroid Build Coastguard Worker         gl::Query *query = queryIter->second;
5540*8975f5c5SAndroid Build Coastguard Worker         if (query)
5541*8975f5c5SAndroid Build Coastguard Worker         {
5542*8975f5c5SAndroid Build Coastguard Worker             gl::QueryType queryType = query->getType();
5543*8975f5c5SAndroid Build Coastguard Worker 
5544*8975f5c5SAndroid Build Coastguard Worker             // Defer active queries until we've created them all
5545*8975f5c5SAndroid Build Coastguard Worker             if (IsQueryActive(apiState, queryID))
5546*8975f5c5SAndroid Build Coastguard Worker             {
5547*8975f5c5SAndroid Build Coastguard Worker                 continue;
5548*8975f5c5SAndroid Build Coastguard Worker             }
5549*8975f5c5SAndroid Build Coastguard Worker 
5550*8975f5c5SAndroid Build Coastguard Worker             // Begin the query to generate the object
5551*8975f5c5SAndroid Build Coastguard Worker             cap(CaptureBeginQuery(replayState, true, queryType, queryID));
5552*8975f5c5SAndroid Build Coastguard Worker 
5553*8975f5c5SAndroid Build Coastguard Worker             // End the query if it was not active
5554*8975f5c5SAndroid Build Coastguard Worker             cap(CaptureEndQuery(replayState, true, queryType));
5555*8975f5c5SAndroid Build Coastguard Worker         }
5556*8975f5c5SAndroid Build Coastguard Worker     }
5557*8975f5c5SAndroid Build Coastguard Worker 
5558*8975f5c5SAndroid Build Coastguard Worker     const gl::ActiveQueryMap &activeQueries = apiState.getActiveQueriesForCapture();
5559*8975f5c5SAndroid Build Coastguard Worker     for (const auto &activeQueryIter : activeQueries)
5560*8975f5c5SAndroid Build Coastguard Worker     {
5561*8975f5c5SAndroid Build Coastguard Worker         const gl::Query *activeQuery = activeQueryIter.get();
5562*8975f5c5SAndroid Build Coastguard Worker         if (activeQuery)
5563*8975f5c5SAndroid Build Coastguard Worker         {
5564*8975f5c5SAndroid Build Coastguard Worker             cap(CaptureBeginQuery(replayState, true, activeQuery->getType(), activeQuery->id()));
5565*8975f5c5SAndroid Build Coastguard Worker         }
5566*8975f5c5SAndroid Build Coastguard Worker     }
5567*8975f5c5SAndroid Build Coastguard Worker 
5568*8975f5c5SAndroid Build Coastguard Worker     // Transform Feedback
5569*8975f5c5SAndroid Build Coastguard Worker     const gl::TransformFeedbackMap &xfbMap = context->getTransformFeedbacksForCapture();
5570*8975f5c5SAndroid Build Coastguard Worker     for (const auto &xfbIter : gl::UnsafeResourceMapIter(xfbMap))
5571*8975f5c5SAndroid Build Coastguard Worker     {
5572*8975f5c5SAndroid Build Coastguard Worker         gl::TransformFeedbackID xfbID = {xfbIter.first};
5573*8975f5c5SAndroid Build Coastguard Worker 
5574*8975f5c5SAndroid Build Coastguard Worker         // Do not capture the default XFB object.
5575*8975f5c5SAndroid Build Coastguard Worker         if (xfbID.value == 0)
5576*8975f5c5SAndroid Build Coastguard Worker         {
5577*8975f5c5SAndroid Build Coastguard Worker             continue;
5578*8975f5c5SAndroid Build Coastguard Worker         }
5579*8975f5c5SAndroid Build Coastguard Worker 
5580*8975f5c5SAndroid Build Coastguard Worker         cap(CaptureGenTransformFeedbacks(replayState, true, 1, &xfbID));
5581*8975f5c5SAndroid Build Coastguard Worker         MaybeCaptureUpdateResourceIDs(context, resourceTracker, setupCalls);
5582*8975f5c5SAndroid Build Coastguard Worker 
5583*8975f5c5SAndroid Build Coastguard Worker         gl::TransformFeedback *xfb = xfbIter.second;
5584*8975f5c5SAndroid Build Coastguard Worker         if (!xfb)
5585*8975f5c5SAndroid Build Coastguard Worker         {
5586*8975f5c5SAndroid Build Coastguard Worker             // The object was never created
5587*8975f5c5SAndroid Build Coastguard Worker             continue;
5588*8975f5c5SAndroid Build Coastguard Worker         }
5589*8975f5c5SAndroid Build Coastguard Worker 
5590*8975f5c5SAndroid Build Coastguard Worker         // Bind XFB to create the object
5591*8975f5c5SAndroid Build Coastguard Worker         cap(CaptureBindTransformFeedback(replayState, true, GL_TRANSFORM_FEEDBACK, xfbID));
5592*8975f5c5SAndroid Build Coastguard Worker 
5593*8975f5c5SAndroid Build Coastguard Worker         // Bind the buffers associated with this XFB object
5594*8975f5c5SAndroid Build Coastguard Worker         for (size_t i = 0; i < xfb->getIndexedBufferCount(); ++i)
5595*8975f5c5SAndroid Build Coastguard Worker         {
5596*8975f5c5SAndroid Build Coastguard Worker             const gl::OffsetBindingPointer<gl::Buffer> &xfbBuffer = xfb->getIndexedBuffer(i);
5597*8975f5c5SAndroid Build Coastguard Worker 
5598*8975f5c5SAndroid Build Coastguard Worker             // Note: Buffers bound with BindBufferBase can be used with BindBuffer
5599*8975f5c5SAndroid Build Coastguard Worker             cap(CaptureBindBufferRange(replayState, true, gl::BufferBinding::TransformFeedback, 0,
5600*8975f5c5SAndroid Build Coastguard Worker                                        xfbBuffer.id(), xfbBuffer.getOffset(), xfbBuffer.getSize()));
5601*8975f5c5SAndroid Build Coastguard Worker         }
5602*8975f5c5SAndroid Build Coastguard Worker 
5603*8975f5c5SAndroid Build Coastguard Worker         if (xfb->isActive() || xfb->isPaused())
5604*8975f5c5SAndroid Build Coastguard Worker         {
5605*8975f5c5SAndroid Build Coastguard Worker             // We don't support active XFB in MEC yet
5606*8975f5c5SAndroid Build Coastguard Worker             UNIMPLEMENTED();
5607*8975f5c5SAndroid Build Coastguard Worker         }
5608*8975f5c5SAndroid Build Coastguard Worker     }
5609*8975f5c5SAndroid Build Coastguard Worker 
5610*8975f5c5SAndroid Build Coastguard Worker     // Bind the current XFB buffer after populating XFB objects
5611*8975f5c5SAndroid Build Coastguard Worker     gl::TransformFeedback *currentXFB = apiState.getCurrentTransformFeedback();
5612*8975f5c5SAndroid Build Coastguard Worker     if (currentXFB)
5613*8975f5c5SAndroid Build Coastguard Worker     {
5614*8975f5c5SAndroid Build Coastguard Worker         cap(CaptureBindTransformFeedback(replayState, true, GL_TRANSFORM_FEEDBACK,
5615*8975f5c5SAndroid Build Coastguard Worker                                          currentXFB->id()));
5616*8975f5c5SAndroid Build Coastguard Worker     }
5617*8975f5c5SAndroid Build Coastguard Worker 
5618*8975f5c5SAndroid Build Coastguard Worker     // Bind samplers
5619*8975f5c5SAndroid Build Coastguard Worker     const gl::SamplerBindingVector &samplerBindings = apiState.getSamplers();
5620*8975f5c5SAndroid Build Coastguard Worker     for (GLuint bindingIndex = 0; bindingIndex < static_cast<GLuint>(samplerBindings.size());
5621*8975f5c5SAndroid Build Coastguard Worker          ++bindingIndex)
5622*8975f5c5SAndroid Build Coastguard Worker     {
5623*8975f5c5SAndroid Build Coastguard Worker         gl::SamplerID samplerID = samplerBindings[bindingIndex].id();
5624*8975f5c5SAndroid Build Coastguard Worker         if (samplerID.value != 0)
5625*8975f5c5SAndroid Build Coastguard Worker         {
5626*8975f5c5SAndroid Build Coastguard Worker             cap(CaptureBindSampler(replayState, true, bindingIndex, samplerID));
5627*8975f5c5SAndroid Build Coastguard Worker         }
5628*8975f5c5SAndroid Build Coastguard Worker     }
5629*8975f5c5SAndroid Build Coastguard Worker 
5630*8975f5c5SAndroid Build Coastguard Worker     // Capture Image Texture bindings
5631*8975f5c5SAndroid Build Coastguard Worker     const std::vector<gl::ImageUnit> &imageUnits = apiState.getImageUnits();
5632*8975f5c5SAndroid Build Coastguard Worker     for (GLuint bindingIndex = 0; bindingIndex < static_cast<GLuint>(imageUnits.size());
5633*8975f5c5SAndroid Build Coastguard Worker          ++bindingIndex)
5634*8975f5c5SAndroid Build Coastguard Worker     {
5635*8975f5c5SAndroid Build Coastguard Worker         const gl::ImageUnit &imageUnit = imageUnits[bindingIndex];
5636*8975f5c5SAndroid Build Coastguard Worker 
5637*8975f5c5SAndroid Build Coastguard Worker         if (imageUnit.texture == 0)
5638*8975f5c5SAndroid Build Coastguard Worker         {
5639*8975f5c5SAndroid Build Coastguard Worker             continue;
5640*8975f5c5SAndroid Build Coastguard Worker         }
5641*8975f5c5SAndroid Build Coastguard Worker 
5642*8975f5c5SAndroid Build Coastguard Worker         cap(CaptureBindImageTexture(replayState, true, bindingIndex, imageUnit.texture.id(),
5643*8975f5c5SAndroid Build Coastguard Worker                                     imageUnit.level, imageUnit.layered, imageUnit.layer,
5644*8975f5c5SAndroid Build Coastguard Worker                                     imageUnit.access, imageUnit.format));
5645*8975f5c5SAndroid Build Coastguard Worker     }
5646*8975f5c5SAndroid Build Coastguard Worker 
5647*8975f5c5SAndroid Build Coastguard Worker     // Capture GL Context states.
5648*8975f5c5SAndroid Build Coastguard Worker     auto capCap = [cap, &replayState](GLenum capEnum, bool capValue) {
5649*8975f5c5SAndroid Build Coastguard Worker         if (capValue)
5650*8975f5c5SAndroid Build Coastguard Worker         {
5651*8975f5c5SAndroid Build Coastguard Worker             cap(CaptureEnable(replayState, true, capEnum));
5652*8975f5c5SAndroid Build Coastguard Worker         }
5653*8975f5c5SAndroid Build Coastguard Worker         else
5654*8975f5c5SAndroid Build Coastguard Worker         {
5655*8975f5c5SAndroid Build Coastguard Worker             cap(CaptureDisable(replayState, true, capEnum));
5656*8975f5c5SAndroid Build Coastguard Worker         }
5657*8975f5c5SAndroid Build Coastguard Worker     };
5658*8975f5c5SAndroid Build Coastguard Worker 
5659*8975f5c5SAndroid Build Coastguard Worker     // Capture GLES1 context states.
5660*8975f5c5SAndroid Build Coastguard Worker     if (context->isGLES1())
5661*8975f5c5SAndroid Build Coastguard Worker     {
5662*8975f5c5SAndroid Build Coastguard Worker         const bool currentTextureState = apiState.getEnableFeature(GL_TEXTURE_2D);
5663*8975f5c5SAndroid Build Coastguard Worker         const bool defaultTextureState = replayState.getEnableFeature(GL_TEXTURE_2D);
5664*8975f5c5SAndroid Build Coastguard Worker         if (currentTextureState != defaultTextureState)
5665*8975f5c5SAndroid Build Coastguard Worker         {
5666*8975f5c5SAndroid Build Coastguard Worker             capCap(GL_TEXTURE_2D, currentTextureState);
5667*8975f5c5SAndroid Build Coastguard Worker         }
5668*8975f5c5SAndroid Build Coastguard Worker 
5669*8975f5c5SAndroid Build Coastguard Worker         cap(CaptureMatrixMode(replayState, true, gl::MatrixType::Projection));
5670*8975f5c5SAndroid Build Coastguard Worker         for (angle::Mat4 projectionMatrix :
5671*8975f5c5SAndroid Build Coastguard Worker              apiState.gles1().getMatrixStack(gl::MatrixType::Projection))
5672*8975f5c5SAndroid Build Coastguard Worker         {
5673*8975f5c5SAndroid Build Coastguard Worker             cap(CapturePushMatrix(replayState, true));
5674*8975f5c5SAndroid Build Coastguard Worker             cap(CaptureLoadMatrixf(replayState, true, projectionMatrix.elements().data()));
5675*8975f5c5SAndroid Build Coastguard Worker         }
5676*8975f5c5SAndroid Build Coastguard Worker 
5677*8975f5c5SAndroid Build Coastguard Worker         cap(CaptureMatrixMode(replayState, true, gl::MatrixType::Modelview));
5678*8975f5c5SAndroid Build Coastguard Worker         for (angle::Mat4 modelViewMatrix :
5679*8975f5c5SAndroid Build Coastguard Worker              apiState.gles1().getMatrixStack(gl::MatrixType::Modelview))
5680*8975f5c5SAndroid Build Coastguard Worker         {
5681*8975f5c5SAndroid Build Coastguard Worker             cap(CapturePushMatrix(replayState, true));
5682*8975f5c5SAndroid Build Coastguard Worker             cap(CaptureLoadMatrixf(replayState, true, modelViewMatrix.elements().data()));
5683*8975f5c5SAndroid Build Coastguard Worker         }
5684*8975f5c5SAndroid Build Coastguard Worker 
5685*8975f5c5SAndroid Build Coastguard Worker         gl::MatrixType currentMatrixMode = apiState.gles1().getMatrixMode();
5686*8975f5c5SAndroid Build Coastguard Worker         if (currentMatrixMode != gl::MatrixType::Modelview)
5687*8975f5c5SAndroid Build Coastguard Worker         {
5688*8975f5c5SAndroid Build Coastguard Worker             cap(CaptureMatrixMode(replayState, true, currentMatrixMode));
5689*8975f5c5SAndroid Build Coastguard Worker         }
5690*8975f5c5SAndroid Build Coastguard Worker 
5691*8975f5c5SAndroid Build Coastguard Worker         // Alpha Test state
5692*8975f5c5SAndroid Build Coastguard Worker         const bool currentAlphaTestState = apiState.getEnableFeature(GL_ALPHA_TEST);
5693*8975f5c5SAndroid Build Coastguard Worker         const bool defaultAlphaTestState = replayState.getEnableFeature(GL_ALPHA_TEST);
5694*8975f5c5SAndroid Build Coastguard Worker 
5695*8975f5c5SAndroid Build Coastguard Worker         if (currentAlphaTestState != defaultAlphaTestState)
5696*8975f5c5SAndroid Build Coastguard Worker         {
5697*8975f5c5SAndroid Build Coastguard Worker             capCap(GL_ALPHA_TEST, currentAlphaTestState);
5698*8975f5c5SAndroid Build Coastguard Worker         }
5699*8975f5c5SAndroid Build Coastguard Worker 
5700*8975f5c5SAndroid Build Coastguard Worker         const gl::AlphaTestParameters currentAlphaTestParameters =
5701*8975f5c5SAndroid Build Coastguard Worker             apiState.gles1().getAlphaTestParameters();
5702*8975f5c5SAndroid Build Coastguard Worker         const gl::AlphaTestParameters defaultAlphaTestParameters =
5703*8975f5c5SAndroid Build Coastguard Worker             replayState.gles1().getAlphaTestParameters();
5704*8975f5c5SAndroid Build Coastguard Worker 
5705*8975f5c5SAndroid Build Coastguard Worker         if (currentAlphaTestParameters != defaultAlphaTestParameters)
5706*8975f5c5SAndroid Build Coastguard Worker         {
5707*8975f5c5SAndroid Build Coastguard Worker             cap(CaptureAlphaFunc(replayState, true, currentAlphaTestParameters.func,
5708*8975f5c5SAndroid Build Coastguard Worker                                  currentAlphaTestParameters.ref));
5709*8975f5c5SAndroid Build Coastguard Worker         }
5710*8975f5c5SAndroid Build Coastguard Worker     }
5711*8975f5c5SAndroid Build Coastguard Worker 
5712*8975f5c5SAndroid Build Coastguard Worker     // Rasterizer state. Missing ES 3.x features.
5713*8975f5c5SAndroid Build Coastguard Worker     const gl::RasterizerState &defaultRasterState = replayState.getRasterizerState();
5714*8975f5c5SAndroid Build Coastguard Worker     const gl::RasterizerState &currentRasterState = apiState.getRasterizerState();
5715*8975f5c5SAndroid Build Coastguard Worker     if (currentRasterState.cullFace != defaultRasterState.cullFace)
5716*8975f5c5SAndroid Build Coastguard Worker     {
5717*8975f5c5SAndroid Build Coastguard Worker         capCap(GL_CULL_FACE, currentRasterState.cullFace);
5718*8975f5c5SAndroid Build Coastguard Worker     }
5719*8975f5c5SAndroid Build Coastguard Worker 
5720*8975f5c5SAndroid Build Coastguard Worker     if (currentRasterState.cullMode != defaultRasterState.cullMode)
5721*8975f5c5SAndroid Build Coastguard Worker     {
5722*8975f5c5SAndroid Build Coastguard Worker         cap(CaptureCullFace(replayState, true, currentRasterState.cullMode));
5723*8975f5c5SAndroid Build Coastguard Worker     }
5724*8975f5c5SAndroid Build Coastguard Worker 
5725*8975f5c5SAndroid Build Coastguard Worker     if (currentRasterState.frontFace != defaultRasterState.frontFace)
5726*8975f5c5SAndroid Build Coastguard Worker     {
5727*8975f5c5SAndroid Build Coastguard Worker         cap(CaptureFrontFace(replayState, true, currentRasterState.frontFace));
5728*8975f5c5SAndroid Build Coastguard Worker     }
5729*8975f5c5SAndroid Build Coastguard Worker 
5730*8975f5c5SAndroid Build Coastguard Worker     if (currentRasterState.polygonMode != defaultRasterState.polygonMode)
5731*8975f5c5SAndroid Build Coastguard Worker     {
5732*8975f5c5SAndroid Build Coastguard Worker         if (context->getExtensions().polygonModeNV)
5733*8975f5c5SAndroid Build Coastguard Worker         {
5734*8975f5c5SAndroid Build Coastguard Worker             cap(CapturePolygonModeNV(replayState, true, GL_FRONT_AND_BACK,
5735*8975f5c5SAndroid Build Coastguard Worker                                      currentRasterState.polygonMode));
5736*8975f5c5SAndroid Build Coastguard Worker         }
5737*8975f5c5SAndroid Build Coastguard Worker         else if (context->getExtensions().polygonModeANGLE)
5738*8975f5c5SAndroid Build Coastguard Worker         {
5739*8975f5c5SAndroid Build Coastguard Worker             cap(CapturePolygonModeANGLE(replayState, true, GL_FRONT_AND_BACK,
5740*8975f5c5SAndroid Build Coastguard Worker                                         currentRasterState.polygonMode));
5741*8975f5c5SAndroid Build Coastguard Worker         }
5742*8975f5c5SAndroid Build Coastguard Worker         else
5743*8975f5c5SAndroid Build Coastguard Worker         {
5744*8975f5c5SAndroid Build Coastguard Worker             UNREACHABLE();
5745*8975f5c5SAndroid Build Coastguard Worker         }
5746*8975f5c5SAndroid Build Coastguard Worker     }
5747*8975f5c5SAndroid Build Coastguard Worker 
5748*8975f5c5SAndroid Build Coastguard Worker     if (currentRasterState.polygonOffsetPoint != defaultRasterState.polygonOffsetPoint)
5749*8975f5c5SAndroid Build Coastguard Worker     {
5750*8975f5c5SAndroid Build Coastguard Worker         capCap(GL_POLYGON_OFFSET_POINT_NV, currentRasterState.polygonOffsetPoint);
5751*8975f5c5SAndroid Build Coastguard Worker     }
5752*8975f5c5SAndroid Build Coastguard Worker 
5753*8975f5c5SAndroid Build Coastguard Worker     if (currentRasterState.polygonOffsetLine != defaultRasterState.polygonOffsetLine)
5754*8975f5c5SAndroid Build Coastguard Worker     {
5755*8975f5c5SAndroid Build Coastguard Worker         capCap(GL_POLYGON_OFFSET_LINE_NV, currentRasterState.polygonOffsetLine);
5756*8975f5c5SAndroid Build Coastguard Worker     }
5757*8975f5c5SAndroid Build Coastguard Worker 
5758*8975f5c5SAndroid Build Coastguard Worker     if (currentRasterState.polygonOffsetFill != defaultRasterState.polygonOffsetFill)
5759*8975f5c5SAndroid Build Coastguard Worker     {
5760*8975f5c5SAndroid Build Coastguard Worker         capCap(GL_POLYGON_OFFSET_FILL, currentRasterState.polygonOffsetFill);
5761*8975f5c5SAndroid Build Coastguard Worker     }
5762*8975f5c5SAndroid Build Coastguard Worker 
5763*8975f5c5SAndroid Build Coastguard Worker     if (currentRasterState.polygonOffsetFactor != defaultRasterState.polygonOffsetFactor ||
5764*8975f5c5SAndroid Build Coastguard Worker         currentRasterState.polygonOffsetUnits != defaultRasterState.polygonOffsetUnits ||
5765*8975f5c5SAndroid Build Coastguard Worker         currentRasterState.polygonOffsetClamp != defaultRasterState.polygonOffsetClamp)
5766*8975f5c5SAndroid Build Coastguard Worker     {
5767*8975f5c5SAndroid Build Coastguard Worker         if (currentRasterState.polygonOffsetClamp == 0.0f)
5768*8975f5c5SAndroid Build Coastguard Worker         {
5769*8975f5c5SAndroid Build Coastguard Worker             cap(CapturePolygonOffset(replayState, true, currentRasterState.polygonOffsetFactor,
5770*8975f5c5SAndroid Build Coastguard Worker                                      currentRasterState.polygonOffsetUnits));
5771*8975f5c5SAndroid Build Coastguard Worker         }
5772*8975f5c5SAndroid Build Coastguard Worker         else
5773*8975f5c5SAndroid Build Coastguard Worker         {
5774*8975f5c5SAndroid Build Coastguard Worker             cap(CapturePolygonOffsetClampEXT(
5775*8975f5c5SAndroid Build Coastguard Worker                 replayState, true, currentRasterState.polygonOffsetFactor,
5776*8975f5c5SAndroid Build Coastguard Worker                 currentRasterState.polygonOffsetUnits, currentRasterState.polygonOffsetClamp));
5777*8975f5c5SAndroid Build Coastguard Worker         }
5778*8975f5c5SAndroid Build Coastguard Worker     }
5779*8975f5c5SAndroid Build Coastguard Worker 
5780*8975f5c5SAndroid Build Coastguard Worker     if (currentRasterState.depthClamp != defaultRasterState.depthClamp)
5781*8975f5c5SAndroid Build Coastguard Worker     {
5782*8975f5c5SAndroid Build Coastguard Worker         capCap(GL_DEPTH_CLAMP_EXT, currentRasterState.depthClamp);
5783*8975f5c5SAndroid Build Coastguard Worker     }
5784*8975f5c5SAndroid Build Coastguard Worker 
5785*8975f5c5SAndroid Build Coastguard Worker     // pointDrawMode/multiSample are only used in the D3D back-end right now.
5786*8975f5c5SAndroid Build Coastguard Worker 
5787*8975f5c5SAndroid Build Coastguard Worker     if (currentRasterState.rasterizerDiscard != defaultRasterState.rasterizerDiscard)
5788*8975f5c5SAndroid Build Coastguard Worker     {
5789*8975f5c5SAndroid Build Coastguard Worker         capCap(GL_RASTERIZER_DISCARD, currentRasterState.rasterizerDiscard);
5790*8975f5c5SAndroid Build Coastguard Worker     }
5791*8975f5c5SAndroid Build Coastguard Worker 
5792*8975f5c5SAndroid Build Coastguard Worker     if (currentRasterState.dither != defaultRasterState.dither)
5793*8975f5c5SAndroid Build Coastguard Worker     {
5794*8975f5c5SAndroid Build Coastguard Worker         capCap(GL_DITHER, currentRasterState.dither);
5795*8975f5c5SAndroid Build Coastguard Worker     }
5796*8975f5c5SAndroid Build Coastguard Worker 
5797*8975f5c5SAndroid Build Coastguard Worker     // Depth/stencil state.
5798*8975f5c5SAndroid Build Coastguard Worker     const gl::DepthStencilState &defaultDSState = replayState.getDepthStencilState();
5799*8975f5c5SAndroid Build Coastguard Worker     const gl::DepthStencilState &currentDSState = apiState.getDepthStencilState();
5800*8975f5c5SAndroid Build Coastguard Worker     if (defaultDSState.depthFunc != currentDSState.depthFunc)
5801*8975f5c5SAndroid Build Coastguard Worker     {
5802*8975f5c5SAndroid Build Coastguard Worker         cap(CaptureDepthFunc(replayState, true, currentDSState.depthFunc));
5803*8975f5c5SAndroid Build Coastguard Worker     }
5804*8975f5c5SAndroid Build Coastguard Worker 
5805*8975f5c5SAndroid Build Coastguard Worker     if (defaultDSState.depthMask != currentDSState.depthMask)
5806*8975f5c5SAndroid Build Coastguard Worker     {
5807*8975f5c5SAndroid Build Coastguard Worker         cap(CaptureDepthMask(replayState, true, gl::ConvertToGLBoolean(currentDSState.depthMask)));
5808*8975f5c5SAndroid Build Coastguard Worker     }
5809*8975f5c5SAndroid Build Coastguard Worker 
5810*8975f5c5SAndroid Build Coastguard Worker     if (defaultDSState.depthTest != currentDSState.depthTest)
5811*8975f5c5SAndroid Build Coastguard Worker     {
5812*8975f5c5SAndroid Build Coastguard Worker         capCap(GL_DEPTH_TEST, currentDSState.depthTest);
5813*8975f5c5SAndroid Build Coastguard Worker     }
5814*8975f5c5SAndroid Build Coastguard Worker 
5815*8975f5c5SAndroid Build Coastguard Worker     if (defaultDSState.stencilTest != currentDSState.stencilTest)
5816*8975f5c5SAndroid Build Coastguard Worker     {
5817*8975f5c5SAndroid Build Coastguard Worker         capCap(GL_STENCIL_TEST, currentDSState.stencilTest);
5818*8975f5c5SAndroid Build Coastguard Worker     }
5819*8975f5c5SAndroid Build Coastguard Worker 
5820*8975f5c5SAndroid Build Coastguard Worker     if (currentDSState.stencilFunc == currentDSState.stencilBackFunc &&
5821*8975f5c5SAndroid Build Coastguard Worker         currentDSState.stencilMask == currentDSState.stencilBackMask)
5822*8975f5c5SAndroid Build Coastguard Worker     {
5823*8975f5c5SAndroid Build Coastguard Worker         // Front and back are equal
5824*8975f5c5SAndroid Build Coastguard Worker         if (defaultDSState.stencilFunc != currentDSState.stencilFunc ||
5825*8975f5c5SAndroid Build Coastguard Worker             defaultDSState.stencilMask != currentDSState.stencilMask ||
5826*8975f5c5SAndroid Build Coastguard Worker             apiState.getStencilRef() != 0)
5827*8975f5c5SAndroid Build Coastguard Worker         {
5828*8975f5c5SAndroid Build Coastguard Worker             cap(CaptureStencilFunc(replayState, true, currentDSState.stencilFunc,
5829*8975f5c5SAndroid Build Coastguard Worker                                    apiState.getStencilRef(), currentDSState.stencilMask));
5830*8975f5c5SAndroid Build Coastguard Worker         }
5831*8975f5c5SAndroid Build Coastguard Worker     }
5832*8975f5c5SAndroid Build Coastguard Worker     else
5833*8975f5c5SAndroid Build Coastguard Worker     {
5834*8975f5c5SAndroid Build Coastguard Worker         // Front and back are separate
5835*8975f5c5SAndroid Build Coastguard Worker         if (defaultDSState.stencilFunc != currentDSState.stencilFunc ||
5836*8975f5c5SAndroid Build Coastguard Worker             defaultDSState.stencilMask != currentDSState.stencilMask ||
5837*8975f5c5SAndroid Build Coastguard Worker             apiState.getStencilRef() != 0)
5838*8975f5c5SAndroid Build Coastguard Worker         {
5839*8975f5c5SAndroid Build Coastguard Worker             cap(CaptureStencilFuncSeparate(replayState, true, GL_FRONT, currentDSState.stencilFunc,
5840*8975f5c5SAndroid Build Coastguard Worker                                            apiState.getStencilRef(), currentDSState.stencilMask));
5841*8975f5c5SAndroid Build Coastguard Worker         }
5842*8975f5c5SAndroid Build Coastguard Worker 
5843*8975f5c5SAndroid Build Coastguard Worker         if (defaultDSState.stencilBackFunc != currentDSState.stencilBackFunc ||
5844*8975f5c5SAndroid Build Coastguard Worker             defaultDSState.stencilBackMask != currentDSState.stencilBackMask ||
5845*8975f5c5SAndroid Build Coastguard Worker             apiState.getStencilBackRef() != 0)
5846*8975f5c5SAndroid Build Coastguard Worker         {
5847*8975f5c5SAndroid Build Coastguard Worker             cap(CaptureStencilFuncSeparate(
5848*8975f5c5SAndroid Build Coastguard Worker                 replayState, true, GL_BACK, currentDSState.stencilBackFunc,
5849*8975f5c5SAndroid Build Coastguard Worker                 apiState.getStencilBackRef(), currentDSState.stencilBackMask));
5850*8975f5c5SAndroid Build Coastguard Worker         }
5851*8975f5c5SAndroid Build Coastguard Worker     }
5852*8975f5c5SAndroid Build Coastguard Worker 
5853*8975f5c5SAndroid Build Coastguard Worker     if (currentDSState.stencilFail == currentDSState.stencilBackFail &&
5854*8975f5c5SAndroid Build Coastguard Worker         currentDSState.stencilPassDepthFail == currentDSState.stencilBackPassDepthFail &&
5855*8975f5c5SAndroid Build Coastguard Worker         currentDSState.stencilPassDepthPass == currentDSState.stencilBackPassDepthPass)
5856*8975f5c5SAndroid Build Coastguard Worker     {
5857*8975f5c5SAndroid Build Coastguard Worker         // Front and back are equal
5858*8975f5c5SAndroid Build Coastguard Worker         if (defaultDSState.stencilFail != currentDSState.stencilFail ||
5859*8975f5c5SAndroid Build Coastguard Worker             defaultDSState.stencilPassDepthFail != currentDSState.stencilPassDepthFail ||
5860*8975f5c5SAndroid Build Coastguard Worker             defaultDSState.stencilPassDepthPass != currentDSState.stencilPassDepthPass)
5861*8975f5c5SAndroid Build Coastguard Worker         {
5862*8975f5c5SAndroid Build Coastguard Worker             cap(CaptureStencilOp(replayState, true, currentDSState.stencilFail,
5863*8975f5c5SAndroid Build Coastguard Worker                                  currentDSState.stencilPassDepthFail,
5864*8975f5c5SAndroid Build Coastguard Worker                                  currentDSState.stencilPassDepthPass));
5865*8975f5c5SAndroid Build Coastguard Worker         }
5866*8975f5c5SAndroid Build Coastguard Worker     }
5867*8975f5c5SAndroid Build Coastguard Worker     else
5868*8975f5c5SAndroid Build Coastguard Worker     {
5869*8975f5c5SAndroid Build Coastguard Worker         // Front and back are separate
5870*8975f5c5SAndroid Build Coastguard Worker         if (defaultDSState.stencilFail != currentDSState.stencilFail ||
5871*8975f5c5SAndroid Build Coastguard Worker             defaultDSState.stencilPassDepthFail != currentDSState.stencilPassDepthFail ||
5872*8975f5c5SAndroid Build Coastguard Worker             defaultDSState.stencilPassDepthPass != currentDSState.stencilPassDepthPass)
5873*8975f5c5SAndroid Build Coastguard Worker         {
5874*8975f5c5SAndroid Build Coastguard Worker             cap(CaptureStencilOpSeparate(replayState, true, GL_FRONT, currentDSState.stencilFail,
5875*8975f5c5SAndroid Build Coastguard Worker                                          currentDSState.stencilPassDepthFail,
5876*8975f5c5SAndroid Build Coastguard Worker                                          currentDSState.stencilPassDepthPass));
5877*8975f5c5SAndroid Build Coastguard Worker         }
5878*8975f5c5SAndroid Build Coastguard Worker 
5879*8975f5c5SAndroid Build Coastguard Worker         if (defaultDSState.stencilBackFail != currentDSState.stencilBackFail ||
5880*8975f5c5SAndroid Build Coastguard Worker             defaultDSState.stencilBackPassDepthFail != currentDSState.stencilBackPassDepthFail ||
5881*8975f5c5SAndroid Build Coastguard Worker             defaultDSState.stencilBackPassDepthPass != currentDSState.stencilBackPassDepthPass)
5882*8975f5c5SAndroid Build Coastguard Worker         {
5883*8975f5c5SAndroid Build Coastguard Worker             cap(CaptureStencilOpSeparate(replayState, true, GL_BACK, currentDSState.stencilBackFail,
5884*8975f5c5SAndroid Build Coastguard Worker                                          currentDSState.stencilBackPassDepthFail,
5885*8975f5c5SAndroid Build Coastguard Worker                                          currentDSState.stencilBackPassDepthPass));
5886*8975f5c5SAndroid Build Coastguard Worker         }
5887*8975f5c5SAndroid Build Coastguard Worker     }
5888*8975f5c5SAndroid Build Coastguard Worker 
5889*8975f5c5SAndroid Build Coastguard Worker     if (currentDSState.stencilWritemask == currentDSState.stencilBackWritemask)
5890*8975f5c5SAndroid Build Coastguard Worker     {
5891*8975f5c5SAndroid Build Coastguard Worker         // Front and back are equal
5892*8975f5c5SAndroid Build Coastguard Worker         if (defaultDSState.stencilWritemask != currentDSState.stencilWritemask)
5893*8975f5c5SAndroid Build Coastguard Worker         {
5894*8975f5c5SAndroid Build Coastguard Worker             cap(CaptureStencilMask(replayState, true, currentDSState.stencilWritemask));
5895*8975f5c5SAndroid Build Coastguard Worker         }
5896*8975f5c5SAndroid Build Coastguard Worker     }
5897*8975f5c5SAndroid Build Coastguard Worker     else
5898*8975f5c5SAndroid Build Coastguard Worker     {
5899*8975f5c5SAndroid Build Coastguard Worker         // Front and back are separate
5900*8975f5c5SAndroid Build Coastguard Worker         if (defaultDSState.stencilWritemask != currentDSState.stencilWritemask)
5901*8975f5c5SAndroid Build Coastguard Worker         {
5902*8975f5c5SAndroid Build Coastguard Worker             cap(CaptureStencilMaskSeparate(replayState, true, GL_FRONT,
5903*8975f5c5SAndroid Build Coastguard Worker                                            currentDSState.stencilWritemask));
5904*8975f5c5SAndroid Build Coastguard Worker         }
5905*8975f5c5SAndroid Build Coastguard Worker 
5906*8975f5c5SAndroid Build Coastguard Worker         if (defaultDSState.stencilBackWritemask != currentDSState.stencilBackWritemask)
5907*8975f5c5SAndroid Build Coastguard Worker         {
5908*8975f5c5SAndroid Build Coastguard Worker             cap(CaptureStencilMaskSeparate(replayState, true, GL_BACK,
5909*8975f5c5SAndroid Build Coastguard Worker                                            currentDSState.stencilBackWritemask));
5910*8975f5c5SAndroid Build Coastguard Worker         }
5911*8975f5c5SAndroid Build Coastguard Worker     }
5912*8975f5c5SAndroid Build Coastguard Worker 
5913*8975f5c5SAndroid Build Coastguard Worker     // Blend state.
5914*8975f5c5SAndroid Build Coastguard Worker     const gl::BlendState &defaultBlendState = replayState.getBlendState();
5915*8975f5c5SAndroid Build Coastguard Worker     const gl::BlendState &currentBlendState = apiState.getBlendState();
5916*8975f5c5SAndroid Build Coastguard Worker 
5917*8975f5c5SAndroid Build Coastguard Worker     if (currentBlendState.blend != defaultBlendState.blend)
5918*8975f5c5SAndroid Build Coastguard Worker     {
5919*8975f5c5SAndroid Build Coastguard Worker         capCap(GL_BLEND, currentBlendState.blend);
5920*8975f5c5SAndroid Build Coastguard Worker     }
5921*8975f5c5SAndroid Build Coastguard Worker 
5922*8975f5c5SAndroid Build Coastguard Worker     if (currentBlendState.sourceBlendRGB != defaultBlendState.sourceBlendRGB ||
5923*8975f5c5SAndroid Build Coastguard Worker         currentBlendState.destBlendRGB != defaultBlendState.destBlendRGB ||
5924*8975f5c5SAndroid Build Coastguard Worker         currentBlendState.sourceBlendAlpha != defaultBlendState.sourceBlendAlpha ||
5925*8975f5c5SAndroid Build Coastguard Worker         currentBlendState.destBlendAlpha != defaultBlendState.destBlendAlpha)
5926*8975f5c5SAndroid Build Coastguard Worker     {
5927*8975f5c5SAndroid Build Coastguard Worker         if (context->isGLES1())
5928*8975f5c5SAndroid Build Coastguard Worker         {
5929*8975f5c5SAndroid Build Coastguard Worker             // Even though their states are tracked independently, in GLES1 blendAlpha
5930*8975f5c5SAndroid Build Coastguard Worker             // and blendRGB cannot be set separately and are always equal
5931*8975f5c5SAndroid Build Coastguard Worker             cap(CaptureBlendFunc(replayState, true, currentBlendState.sourceBlendRGB,
5932*8975f5c5SAndroid Build Coastguard Worker                                  currentBlendState.destBlendRGB));
5933*8975f5c5SAndroid Build Coastguard Worker             Capture(&resetCalls[angle::EntryPoint::GLBlendFunc],
5934*8975f5c5SAndroid Build Coastguard Worker                     CaptureBlendFunc(replayState, true, currentBlendState.sourceBlendRGB,
5935*8975f5c5SAndroid Build Coastguard Worker                                      currentBlendState.destBlendRGB));
5936*8975f5c5SAndroid Build Coastguard Worker         }
5937*8975f5c5SAndroid Build Coastguard Worker         else
5938*8975f5c5SAndroid Build Coastguard Worker         {
5939*8975f5c5SAndroid Build Coastguard Worker             // Always use BlendFuncSeparate for non-GLES1 as it covers all cases
5940*8975f5c5SAndroid Build Coastguard Worker             cap(CaptureBlendFuncSeparate(
5941*8975f5c5SAndroid Build Coastguard Worker                 replayState, true, currentBlendState.sourceBlendRGB, currentBlendState.destBlendRGB,
5942*8975f5c5SAndroid Build Coastguard Worker                 currentBlendState.sourceBlendAlpha, currentBlendState.destBlendAlpha));
5943*8975f5c5SAndroid Build Coastguard Worker             Capture(&resetCalls[angle::EntryPoint::GLBlendFuncSeparate],
5944*8975f5c5SAndroid Build Coastguard Worker                     CaptureBlendFuncSeparate(replayState, true, currentBlendState.sourceBlendRGB,
5945*8975f5c5SAndroid Build Coastguard Worker                                              currentBlendState.destBlendRGB,
5946*8975f5c5SAndroid Build Coastguard Worker                                              currentBlendState.sourceBlendAlpha,
5947*8975f5c5SAndroid Build Coastguard Worker                                              currentBlendState.destBlendAlpha));
5948*8975f5c5SAndroid Build Coastguard Worker         }
5949*8975f5c5SAndroid Build Coastguard Worker     }
5950*8975f5c5SAndroid Build Coastguard Worker 
5951*8975f5c5SAndroid Build Coastguard Worker     if (currentBlendState.blendEquationRGB != defaultBlendState.blendEquationRGB ||
5952*8975f5c5SAndroid Build Coastguard Worker         currentBlendState.blendEquationAlpha != defaultBlendState.blendEquationAlpha)
5953*8975f5c5SAndroid Build Coastguard Worker     {
5954*8975f5c5SAndroid Build Coastguard Worker         // Similarly to BlendFunc, using BlendEquation in some cases complicates Reset.
5955*8975f5c5SAndroid Build Coastguard Worker         cap(CaptureBlendEquationSeparate(replayState, true, currentBlendState.blendEquationRGB,
5956*8975f5c5SAndroid Build Coastguard Worker                                          currentBlendState.blendEquationAlpha));
5957*8975f5c5SAndroid Build Coastguard Worker         Capture(&resetCalls[angle::EntryPoint::GLBlendEquationSeparate],
5958*8975f5c5SAndroid Build Coastguard Worker                 CaptureBlendEquationSeparate(replayState, true, currentBlendState.blendEquationRGB,
5959*8975f5c5SAndroid Build Coastguard Worker                                              currentBlendState.blendEquationAlpha));
5960*8975f5c5SAndroid Build Coastguard Worker     }
5961*8975f5c5SAndroid Build Coastguard Worker 
5962*8975f5c5SAndroid Build Coastguard Worker     if (currentBlendState.colorMaskRed != defaultBlendState.colorMaskRed ||
5963*8975f5c5SAndroid Build Coastguard Worker         currentBlendState.colorMaskGreen != defaultBlendState.colorMaskGreen ||
5964*8975f5c5SAndroid Build Coastguard Worker         currentBlendState.colorMaskBlue != defaultBlendState.colorMaskBlue ||
5965*8975f5c5SAndroid Build Coastguard Worker         currentBlendState.colorMaskAlpha != defaultBlendState.colorMaskAlpha)
5966*8975f5c5SAndroid Build Coastguard Worker     {
5967*8975f5c5SAndroid Build Coastguard Worker         cap(CaptureColorMask(replayState, true,
5968*8975f5c5SAndroid Build Coastguard Worker                              gl::ConvertToGLBoolean(currentBlendState.colorMaskRed),
5969*8975f5c5SAndroid Build Coastguard Worker                              gl::ConvertToGLBoolean(currentBlendState.colorMaskGreen),
5970*8975f5c5SAndroid Build Coastguard Worker                              gl::ConvertToGLBoolean(currentBlendState.colorMaskBlue),
5971*8975f5c5SAndroid Build Coastguard Worker                              gl::ConvertToGLBoolean(currentBlendState.colorMaskAlpha)));
5972*8975f5c5SAndroid Build Coastguard Worker         Capture(&resetCalls[angle::EntryPoint::GLColorMask],
5973*8975f5c5SAndroid Build Coastguard Worker                 CaptureColorMask(replayState, true,
5974*8975f5c5SAndroid Build Coastguard Worker                                  gl::ConvertToGLBoolean(currentBlendState.colorMaskRed),
5975*8975f5c5SAndroid Build Coastguard Worker                                  gl::ConvertToGLBoolean(currentBlendState.colorMaskGreen),
5976*8975f5c5SAndroid Build Coastguard Worker                                  gl::ConvertToGLBoolean(currentBlendState.colorMaskBlue),
5977*8975f5c5SAndroid Build Coastguard Worker                                  gl::ConvertToGLBoolean(currentBlendState.colorMaskAlpha)));
5978*8975f5c5SAndroid Build Coastguard Worker     }
5979*8975f5c5SAndroid Build Coastguard Worker 
5980*8975f5c5SAndroid Build Coastguard Worker     const gl::ColorF &currentBlendColor = apiState.getBlendColor();
5981*8975f5c5SAndroid Build Coastguard Worker     if (currentBlendColor != gl::ColorF())
5982*8975f5c5SAndroid Build Coastguard Worker     {
5983*8975f5c5SAndroid Build Coastguard Worker         cap(CaptureBlendColor(replayState, true, currentBlendColor.red, currentBlendColor.green,
5984*8975f5c5SAndroid Build Coastguard Worker                               currentBlendColor.blue, currentBlendColor.alpha));
5985*8975f5c5SAndroid Build Coastguard Worker         Capture(&resetCalls[angle::EntryPoint::GLBlendColor],
5986*8975f5c5SAndroid Build Coastguard Worker                 CaptureBlendColor(replayState, true, currentBlendColor.red, currentBlendColor.green,
5987*8975f5c5SAndroid Build Coastguard Worker                                   currentBlendColor.blue, currentBlendColor.alpha));
5988*8975f5c5SAndroid Build Coastguard Worker     }
5989*8975f5c5SAndroid Build Coastguard Worker 
5990*8975f5c5SAndroid Build Coastguard Worker     // Pixel storage states.
5991*8975f5c5SAndroid Build Coastguard Worker     gl::PixelPackState &currentPackState = replayState.getPackState();
5992*8975f5c5SAndroid Build Coastguard Worker     if (currentPackState.alignment != apiState.getPackAlignment())
5993*8975f5c5SAndroid Build Coastguard Worker     {
5994*8975f5c5SAndroid Build Coastguard Worker         cap(CapturePixelStorei(replayState, true, GL_PACK_ALIGNMENT, apiState.getPackAlignment()));
5995*8975f5c5SAndroid Build Coastguard Worker         currentPackState.alignment = apiState.getPackAlignment();
5996*8975f5c5SAndroid Build Coastguard Worker     }
5997*8975f5c5SAndroid Build Coastguard Worker 
5998*8975f5c5SAndroid Build Coastguard Worker     if (currentPackState.rowLength != apiState.getPackRowLength())
5999*8975f5c5SAndroid Build Coastguard Worker     {
6000*8975f5c5SAndroid Build Coastguard Worker         cap(CapturePixelStorei(replayState, true, GL_PACK_ROW_LENGTH, apiState.getPackRowLength()));
6001*8975f5c5SAndroid Build Coastguard Worker         currentPackState.rowLength = apiState.getPackRowLength();
6002*8975f5c5SAndroid Build Coastguard Worker     }
6003*8975f5c5SAndroid Build Coastguard Worker 
6004*8975f5c5SAndroid Build Coastguard Worker     if (currentPackState.skipRows != apiState.getPackSkipRows())
6005*8975f5c5SAndroid Build Coastguard Worker     {
6006*8975f5c5SAndroid Build Coastguard Worker         cap(CapturePixelStorei(replayState, true, GL_PACK_SKIP_ROWS, apiState.getPackSkipRows()));
6007*8975f5c5SAndroid Build Coastguard Worker         currentPackState.skipRows = apiState.getPackSkipRows();
6008*8975f5c5SAndroid Build Coastguard Worker     }
6009*8975f5c5SAndroid Build Coastguard Worker 
6010*8975f5c5SAndroid Build Coastguard Worker     if (currentPackState.skipPixels != apiState.getPackSkipPixels())
6011*8975f5c5SAndroid Build Coastguard Worker     {
6012*8975f5c5SAndroid Build Coastguard Worker         cap(CapturePixelStorei(replayState, true, GL_PACK_SKIP_PIXELS,
6013*8975f5c5SAndroid Build Coastguard Worker                                apiState.getPackSkipPixels()));
6014*8975f5c5SAndroid Build Coastguard Worker         currentPackState.skipPixels = apiState.getPackSkipPixels();
6015*8975f5c5SAndroid Build Coastguard Worker     }
6016*8975f5c5SAndroid Build Coastguard Worker 
6017*8975f5c5SAndroid Build Coastguard Worker     // We set unpack alignment above, no need to change it here
6018*8975f5c5SAndroid Build Coastguard Worker     ASSERT(currentUnpackState.alignment == 1);
6019*8975f5c5SAndroid Build Coastguard Worker     if (currentUnpackState.rowLength != apiState.getUnpackRowLength())
6020*8975f5c5SAndroid Build Coastguard Worker     {
6021*8975f5c5SAndroid Build Coastguard Worker         cap(CapturePixelStorei(replayState, true, GL_UNPACK_ROW_LENGTH,
6022*8975f5c5SAndroid Build Coastguard Worker                                apiState.getUnpackRowLength()));
6023*8975f5c5SAndroid Build Coastguard Worker         currentUnpackState.rowLength = apiState.getUnpackRowLength();
6024*8975f5c5SAndroid Build Coastguard Worker     }
6025*8975f5c5SAndroid Build Coastguard Worker 
6026*8975f5c5SAndroid Build Coastguard Worker     if (currentUnpackState.skipRows != apiState.getUnpackSkipRows())
6027*8975f5c5SAndroid Build Coastguard Worker     {
6028*8975f5c5SAndroid Build Coastguard Worker         cap(CapturePixelStorei(replayState, true, GL_UNPACK_SKIP_ROWS,
6029*8975f5c5SAndroid Build Coastguard Worker                                apiState.getUnpackSkipRows()));
6030*8975f5c5SAndroid Build Coastguard Worker         currentUnpackState.skipRows = apiState.getUnpackSkipRows();
6031*8975f5c5SAndroid Build Coastguard Worker     }
6032*8975f5c5SAndroid Build Coastguard Worker 
6033*8975f5c5SAndroid Build Coastguard Worker     if (currentUnpackState.skipPixels != apiState.getUnpackSkipPixels())
6034*8975f5c5SAndroid Build Coastguard Worker     {
6035*8975f5c5SAndroid Build Coastguard Worker         cap(CapturePixelStorei(replayState, true, GL_UNPACK_SKIP_PIXELS,
6036*8975f5c5SAndroid Build Coastguard Worker                                apiState.getUnpackSkipPixels()));
6037*8975f5c5SAndroid Build Coastguard Worker         currentUnpackState.skipPixels = apiState.getUnpackSkipPixels();
6038*8975f5c5SAndroid Build Coastguard Worker     }
6039*8975f5c5SAndroid Build Coastguard Worker 
6040*8975f5c5SAndroid Build Coastguard Worker     if (currentUnpackState.imageHeight != apiState.getUnpackImageHeight())
6041*8975f5c5SAndroid Build Coastguard Worker     {
6042*8975f5c5SAndroid Build Coastguard Worker         cap(CapturePixelStorei(replayState, true, GL_UNPACK_IMAGE_HEIGHT,
6043*8975f5c5SAndroid Build Coastguard Worker                                apiState.getUnpackImageHeight()));
6044*8975f5c5SAndroid Build Coastguard Worker         currentUnpackState.imageHeight = apiState.getUnpackImageHeight();
6045*8975f5c5SAndroid Build Coastguard Worker     }
6046*8975f5c5SAndroid Build Coastguard Worker 
6047*8975f5c5SAndroid Build Coastguard Worker     if (currentUnpackState.skipImages != apiState.getUnpackSkipImages())
6048*8975f5c5SAndroid Build Coastguard Worker     {
6049*8975f5c5SAndroid Build Coastguard Worker         cap(CapturePixelStorei(replayState, true, GL_UNPACK_SKIP_IMAGES,
6050*8975f5c5SAndroid Build Coastguard Worker                                apiState.getUnpackSkipImages()));
6051*8975f5c5SAndroid Build Coastguard Worker         currentUnpackState.skipImages = apiState.getUnpackSkipImages();
6052*8975f5c5SAndroid Build Coastguard Worker     }
6053*8975f5c5SAndroid Build Coastguard Worker 
6054*8975f5c5SAndroid Build Coastguard Worker     // Clear state. Missing ES 3.x features.
6055*8975f5c5SAndroid Build Coastguard Worker     // TODO(http://anglebug.com/42262323): Complete state capture.
6056*8975f5c5SAndroid Build Coastguard Worker     const gl::ColorF &currentClearColor = apiState.getColorClearValue();
6057*8975f5c5SAndroid Build Coastguard Worker     if (currentClearColor != gl::ColorF())
6058*8975f5c5SAndroid Build Coastguard Worker     {
6059*8975f5c5SAndroid Build Coastguard Worker         cap(CaptureClearColor(replayState, true, currentClearColor.red, currentClearColor.green,
6060*8975f5c5SAndroid Build Coastguard Worker                               currentClearColor.blue, currentClearColor.alpha));
6061*8975f5c5SAndroid Build Coastguard Worker     }
6062*8975f5c5SAndroid Build Coastguard Worker 
6063*8975f5c5SAndroid Build Coastguard Worker     if (apiState.getDepthClearValue() != 1.0f)
6064*8975f5c5SAndroid Build Coastguard Worker     {
6065*8975f5c5SAndroid Build Coastguard Worker         cap(CaptureClearDepthf(replayState, true, apiState.getDepthClearValue()));
6066*8975f5c5SAndroid Build Coastguard Worker     }
6067*8975f5c5SAndroid Build Coastguard Worker 
6068*8975f5c5SAndroid Build Coastguard Worker     if (apiState.getStencilClearValue() != 0)
6069*8975f5c5SAndroid Build Coastguard Worker     {
6070*8975f5c5SAndroid Build Coastguard Worker         cap(CaptureClearStencil(replayState, true, apiState.getStencilClearValue()));
6071*8975f5c5SAndroid Build Coastguard Worker     }
6072*8975f5c5SAndroid Build Coastguard Worker 
6073*8975f5c5SAndroid Build Coastguard Worker     // Viewport / scissor / clipping planes.
6074*8975f5c5SAndroid Build Coastguard Worker     const gl::Rectangle &currentViewport = apiState.getViewport();
6075*8975f5c5SAndroid Build Coastguard Worker     if (currentViewport != gl::Rectangle())
6076*8975f5c5SAndroid Build Coastguard Worker     {
6077*8975f5c5SAndroid Build Coastguard Worker         cap(CaptureViewport(replayState, true, currentViewport.x, currentViewport.y,
6078*8975f5c5SAndroid Build Coastguard Worker                             currentViewport.width, currentViewport.height));
6079*8975f5c5SAndroid Build Coastguard Worker     }
6080*8975f5c5SAndroid Build Coastguard Worker 
6081*8975f5c5SAndroid Build Coastguard Worker     if (apiState.getNearPlane() != 0.0f || apiState.getFarPlane() != 1.0f)
6082*8975f5c5SAndroid Build Coastguard Worker     {
6083*8975f5c5SAndroid Build Coastguard Worker         cap(CaptureDepthRangef(replayState, true, apiState.getNearPlane(), apiState.getFarPlane()));
6084*8975f5c5SAndroid Build Coastguard Worker     }
6085*8975f5c5SAndroid Build Coastguard Worker 
6086*8975f5c5SAndroid Build Coastguard Worker     if (apiState.getClipOrigin() != gl::ClipOrigin::LowerLeft ||
6087*8975f5c5SAndroid Build Coastguard Worker         apiState.getClipDepthMode() != gl::ClipDepthMode::NegativeOneToOne)
6088*8975f5c5SAndroid Build Coastguard Worker     {
6089*8975f5c5SAndroid Build Coastguard Worker         cap(CaptureClipControlEXT(replayState, true, apiState.getClipOrigin(),
6090*8975f5c5SAndroid Build Coastguard Worker                                   apiState.getClipDepthMode()));
6091*8975f5c5SAndroid Build Coastguard Worker     }
6092*8975f5c5SAndroid Build Coastguard Worker 
6093*8975f5c5SAndroid Build Coastguard Worker     if (apiState.isScissorTestEnabled())
6094*8975f5c5SAndroid Build Coastguard Worker     {
6095*8975f5c5SAndroid Build Coastguard Worker         capCap(GL_SCISSOR_TEST, apiState.isScissorTestEnabled());
6096*8975f5c5SAndroid Build Coastguard Worker     }
6097*8975f5c5SAndroid Build Coastguard Worker 
6098*8975f5c5SAndroid Build Coastguard Worker     const gl::Rectangle &currentScissor = apiState.getScissor();
6099*8975f5c5SAndroid Build Coastguard Worker     if (currentScissor != gl::Rectangle())
6100*8975f5c5SAndroid Build Coastguard Worker     {
6101*8975f5c5SAndroid Build Coastguard Worker         cap(CaptureScissor(replayState, true, currentScissor.x, currentScissor.y,
6102*8975f5c5SAndroid Build Coastguard Worker                            currentScissor.width, currentScissor.height));
6103*8975f5c5SAndroid Build Coastguard Worker     }
6104*8975f5c5SAndroid Build Coastguard Worker 
6105*8975f5c5SAndroid Build Coastguard Worker     // Allow the replayState object to be destroyed conveniently.
6106*8975f5c5SAndroid Build Coastguard Worker     replayState.setBufferBinding(context, gl::BufferBinding::Array, nullptr);
6107*8975f5c5SAndroid Build Coastguard Worker 
6108*8975f5c5SAndroid Build Coastguard Worker     // Clean up the replay state.
6109*8975f5c5SAndroid Build Coastguard Worker     replayState.reset(context);
6110*8975f5c5SAndroid Build Coastguard Worker 
6111*8975f5c5SAndroid Build Coastguard Worker     GLint contextUnpackAlignment = context->getState().getUnpackState().alignment;
6112*8975f5c5SAndroid Build Coastguard Worker     if (currentUnpackState.alignment != contextUnpackAlignment)
6113*8975f5c5SAndroid Build Coastguard Worker     {
6114*8975f5c5SAndroid Build Coastguard Worker         cap(CapturePixelStorei(replayState, true, GL_UNPACK_ALIGNMENT, contextUnpackAlignment));
6115*8975f5c5SAndroid Build Coastguard Worker         replayState.getMutablePrivateStateForCapture()->setUnpackAlignment(contextUnpackAlignment);
6116*8975f5c5SAndroid Build Coastguard Worker     }
6117*8975f5c5SAndroid Build Coastguard Worker 
6118*8975f5c5SAndroid Build Coastguard Worker     if (validationEnabled)
6119*8975f5c5SAndroid Build Coastguard Worker     {
6120*8975f5c5SAndroid Build Coastguard Worker         CaptureValidateSerializedState(context, setupCalls);
6121*8975f5c5SAndroid Build Coastguard Worker     }
6122*8975f5c5SAndroid Build Coastguard Worker }
6123*8975f5c5SAndroid Build Coastguard Worker 
SkipCall(EntryPoint entryPoint)6124*8975f5c5SAndroid Build Coastguard Worker bool SkipCall(EntryPoint entryPoint)
6125*8975f5c5SAndroid Build Coastguard Worker {
6126*8975f5c5SAndroid Build Coastguard Worker     switch (entryPoint)
6127*8975f5c5SAndroid Build Coastguard Worker     {
6128*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLDebugMessageCallback:
6129*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLDebugMessageCallbackKHR:
6130*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLDebugMessageControl:
6131*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLDebugMessageControlKHR:
6132*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLDebugMessageInsert:
6133*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLDebugMessageInsertKHR:
6134*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLGetDebugMessageLog:
6135*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLGetDebugMessageLogKHR:
6136*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLGetObjectLabel:
6137*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLGetObjectLabelEXT:
6138*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLGetObjectLabelKHR:
6139*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLGetObjectPtrLabelKHR:
6140*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLGetPointervKHR:
6141*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLInsertEventMarkerEXT:
6142*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLLabelObjectEXT:
6143*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLObjectLabel:
6144*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLObjectLabelKHR:
6145*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLObjectPtrLabelKHR:
6146*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLPopDebugGroupKHR:
6147*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLPopGroupMarkerEXT:
6148*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLPushDebugGroupKHR:
6149*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLPushGroupMarkerEXT:
6150*8975f5c5SAndroid Build Coastguard Worker             // Purposefully skip entry points from:
6151*8975f5c5SAndroid Build Coastguard Worker             // - KHR_debug
6152*8975f5c5SAndroid Build Coastguard Worker             // - EXT_debug_label
6153*8975f5c5SAndroid Build Coastguard Worker             // - EXT_debug_marker
6154*8975f5c5SAndroid Build Coastguard Worker             // There is no need to capture these for replaying a trace in our harness
6155*8975f5c5SAndroid Build Coastguard Worker             return true;
6156*8975f5c5SAndroid Build Coastguard Worker 
6157*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLGetActiveUniform:
6158*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLGetActiveUniformsiv:
6159*8975f5c5SAndroid Build Coastguard Worker             // Skip these calls because:
6160*8975f5c5SAndroid Build Coastguard Worker             // - We don't use the return values.
6161*8975f5c5SAndroid Build Coastguard Worker             // - Active uniform counts can vary between platforms due to cross stage optimizations
6162*8975f5c5SAndroid Build Coastguard Worker             //   and asking about uniforms above GL_ACTIVE_UNIFORMS triggers errors.
6163*8975f5c5SAndroid Build Coastguard Worker             return true;
6164*8975f5c5SAndroid Build Coastguard Worker 
6165*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLGetActiveAttrib:
6166*8975f5c5SAndroid Build Coastguard Worker             // Skip these calls because:
6167*8975f5c5SAndroid Build Coastguard Worker             // - We don't use the return values.
6168*8975f5c5SAndroid Build Coastguard Worker             // - Same as uniforms, the value can vary, asking above GL_ACTIVE_ATTRIBUTES is an error
6169*8975f5c5SAndroid Build Coastguard Worker             return true;
6170*8975f5c5SAndroid Build Coastguard Worker 
6171*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLGetActiveUniformBlockiv:
6172*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLGetActiveUniformBlockName:
6173*8975f5c5SAndroid Build Coastguard Worker             // Skip these calls because:
6174*8975f5c5SAndroid Build Coastguard Worker             // - We don't use the return values.
6175*8975f5c5SAndroid Build Coastguard Worker             // - It reduces the number of references to the uniform block index map.
6176*8975f5c5SAndroid Build Coastguard Worker             return true;
6177*8975f5c5SAndroid Build Coastguard Worker 
6178*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::EGLChooseConfig:
6179*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::EGLGetProcAddress:
6180*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::EGLGetConfigAttrib:
6181*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::EGLGetConfigs:
6182*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::EGLGetSyncAttrib:
6183*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::EGLGetSyncAttribKHR:
6184*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::EGLQueryContext:
6185*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::EGLQuerySurface:
6186*8975f5c5SAndroid Build Coastguard Worker             // Skip these calls because:
6187*8975f5c5SAndroid Build Coastguard Worker             // - We don't use the return values.
6188*8975f5c5SAndroid Build Coastguard Worker             // - Some EGL types and pointer parameters aren't yet implemented in EGL capture.
6189*8975f5c5SAndroid Build Coastguard Worker             return true;
6190*8975f5c5SAndroid Build Coastguard Worker 
6191*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::EGLPrepareSwapBuffersANGLE:
6192*8975f5c5SAndroid Build Coastguard Worker             // Skip this call because:
6193*8975f5c5SAndroid Build Coastguard Worker             // - eglPrepareSwapBuffersANGLE is automatically called by eglSwapBuffers
6194*8975f5c5SAndroid Build Coastguard Worker             return true;
6195*8975f5c5SAndroid Build Coastguard Worker 
6196*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::EGLSwapBuffers:
6197*8975f5c5SAndroid Build Coastguard Worker             // Skip these calls because:
6198*8975f5c5SAndroid Build Coastguard Worker             // - Swap is handled specially by the trace harness.
6199*8975f5c5SAndroid Build Coastguard Worker             return true;
6200*8975f5c5SAndroid Build Coastguard Worker 
6201*8975f5c5SAndroid Build Coastguard Worker         default:
6202*8975f5c5SAndroid Build Coastguard Worker             break;
6203*8975f5c5SAndroid Build Coastguard Worker     }
6204*8975f5c5SAndroid Build Coastguard Worker 
6205*8975f5c5SAndroid Build Coastguard Worker     return false;
6206*8975f5c5SAndroid Build Coastguard Worker }
6207*8975f5c5SAndroid Build Coastguard Worker 
GetBaseName(const std::string & nameWithPath)6208*8975f5c5SAndroid Build Coastguard Worker std::string GetBaseName(const std::string &nameWithPath)
6209*8975f5c5SAndroid Build Coastguard Worker {
6210*8975f5c5SAndroid Build Coastguard Worker     std::vector<std::string> result = angle::SplitString(
6211*8975f5c5SAndroid Build Coastguard Worker         nameWithPath, "/\\", WhitespaceHandling::TRIM_WHITESPACE, SplitResult::SPLIT_WANT_NONEMPTY);
6212*8975f5c5SAndroid Build Coastguard Worker     ASSERT(!result.empty());
6213*8975f5c5SAndroid Build Coastguard Worker     return result.back();
6214*8975f5c5SAndroid Build Coastguard Worker }
6215*8975f5c5SAndroid Build Coastguard Worker }  // namespace
6216*8975f5c5SAndroid Build Coastguard Worker 
6217*8975f5c5SAndroid Build Coastguard Worker FrameCapture::FrameCapture()  = default;
6218*8975f5c5SAndroid Build Coastguard Worker FrameCapture::~FrameCapture() = default;
6219*8975f5c5SAndroid Build Coastguard Worker 
reset()6220*8975f5c5SAndroid Build Coastguard Worker void FrameCapture::reset()
6221*8975f5c5SAndroid Build Coastguard Worker {
6222*8975f5c5SAndroid Build Coastguard Worker     mSetupCalls.clear();
6223*8975f5c5SAndroid Build Coastguard Worker }
6224*8975f5c5SAndroid Build Coastguard Worker 
FrameCaptureShared()6225*8975f5c5SAndroid Build Coastguard Worker FrameCaptureShared::FrameCaptureShared()
6226*8975f5c5SAndroid Build Coastguard Worker     : mEnabled(true),
6227*8975f5c5SAndroid Build Coastguard Worker       mSerializeStateEnabled(false),
6228*8975f5c5SAndroid Build Coastguard Worker       mCompression(true),
6229*8975f5c5SAndroid Build Coastguard Worker       mClientVertexArrayMap{},
6230*8975f5c5SAndroid Build Coastguard Worker       mFrameIndex(1),
6231*8975f5c5SAndroid Build Coastguard Worker       mCaptureStartFrame(1),
6232*8975f5c5SAndroid Build Coastguard Worker       mCaptureEndFrame(0),
6233*8975f5c5SAndroid Build Coastguard Worker       mClientArraySizes{},
6234*8975f5c5SAndroid Build Coastguard Worker       mReadBufferSize(0),
6235*8975f5c5SAndroid Build Coastguard Worker       mResourceIDBufferSize(0),
6236*8975f5c5SAndroid Build Coastguard Worker       mHasResourceType{},
6237*8975f5c5SAndroid Build Coastguard Worker       mResourceIDToSetupCalls{},
6238*8975f5c5SAndroid Build Coastguard Worker       mMaxAccessedResourceIDs{},
6239*8975f5c5SAndroid Build Coastguard Worker       mCaptureTrigger(0),
6240*8975f5c5SAndroid Build Coastguard Worker       mCaptureActive(false),
6241*8975f5c5SAndroid Build Coastguard Worker       mWindowSurfaceContextID({0})
6242*8975f5c5SAndroid Build Coastguard Worker {
6243*8975f5c5SAndroid Build Coastguard Worker     reset();
6244*8975f5c5SAndroid Build Coastguard Worker 
6245*8975f5c5SAndroid Build Coastguard Worker     std::string enabledFromEnv =
6246*8975f5c5SAndroid Build Coastguard Worker         GetEnvironmentVarOrUnCachedAndroidProperty(kEnabledVarName, kAndroidEnabled);
6247*8975f5c5SAndroid Build Coastguard Worker     if (enabledFromEnv == "0")
6248*8975f5c5SAndroid Build Coastguard Worker     {
6249*8975f5c5SAndroid Build Coastguard Worker         mEnabled = false;
6250*8975f5c5SAndroid Build Coastguard Worker     }
6251*8975f5c5SAndroid Build Coastguard Worker 
6252*8975f5c5SAndroid Build Coastguard Worker     std::string startFromEnv =
6253*8975f5c5SAndroid Build Coastguard Worker         GetEnvironmentVarOrUnCachedAndroidProperty(kFrameStartVarName, kAndroidFrameStart);
6254*8975f5c5SAndroid Build Coastguard Worker     if (!startFromEnv.empty())
6255*8975f5c5SAndroid Build Coastguard Worker     {
6256*8975f5c5SAndroid Build Coastguard Worker         mCaptureStartFrame = atoi(startFromEnv.c_str());
6257*8975f5c5SAndroid Build Coastguard Worker     }
6258*8975f5c5SAndroid Build Coastguard Worker     if (mCaptureStartFrame < 1)
6259*8975f5c5SAndroid Build Coastguard Worker     {
6260*8975f5c5SAndroid Build Coastguard Worker         WARN() << "Cannot use a capture start frame less than 1.";
6261*8975f5c5SAndroid Build Coastguard Worker         mCaptureStartFrame = 1;
6262*8975f5c5SAndroid Build Coastguard Worker     }
6263*8975f5c5SAndroid Build Coastguard Worker 
6264*8975f5c5SAndroid Build Coastguard Worker     std::string endFromEnv =
6265*8975f5c5SAndroid Build Coastguard Worker         GetEnvironmentVarOrUnCachedAndroidProperty(kFrameEndVarName, kAndroidFrameEnd);
6266*8975f5c5SAndroid Build Coastguard Worker     if (!endFromEnv.empty())
6267*8975f5c5SAndroid Build Coastguard Worker     {
6268*8975f5c5SAndroid Build Coastguard Worker         mCaptureEndFrame = atoi(endFromEnv.c_str());
6269*8975f5c5SAndroid Build Coastguard Worker     }
6270*8975f5c5SAndroid Build Coastguard Worker 
6271*8975f5c5SAndroid Build Coastguard Worker     std::string captureTriggerFromEnv =
6272*8975f5c5SAndroid Build Coastguard Worker         GetEnvironmentVarOrUnCachedAndroidProperty(kTriggerVarName, kAndroidTrigger);
6273*8975f5c5SAndroid Build Coastguard Worker     if (!captureTriggerFromEnv.empty())
6274*8975f5c5SAndroid Build Coastguard Worker     {
6275*8975f5c5SAndroid Build Coastguard Worker         mCaptureTrigger = atoi(captureTriggerFromEnv.c_str());
6276*8975f5c5SAndroid Build Coastguard Worker 
6277*8975f5c5SAndroid Build Coastguard Worker         // If the trigger has been populated, ignore the other frame range variables by setting them
6278*8975f5c5SAndroid Build Coastguard Worker         // to unreasonable values. This isn't perfect, but it is effective.
6279*8975f5c5SAndroid Build Coastguard Worker         mCaptureStartFrame = mCaptureEndFrame = std::numeric_limits<uint32_t>::max();
6280*8975f5c5SAndroid Build Coastguard Worker         INFO() << "Capture trigger detected, disabling capture start/end frame.";
6281*8975f5c5SAndroid Build Coastguard Worker     }
6282*8975f5c5SAndroid Build Coastguard Worker 
6283*8975f5c5SAndroid Build Coastguard Worker     std::string labelFromEnv =
6284*8975f5c5SAndroid Build Coastguard Worker         GetEnvironmentVarOrUnCachedAndroidProperty(kCaptureLabelVarName, kAndroidCaptureLabel);
6285*8975f5c5SAndroid Build Coastguard Worker     // --angle-per-test-capture-label sets the env var, not properties
6286*8975f5c5SAndroid Build Coastguard Worker     if (labelFromEnv.empty())
6287*8975f5c5SAndroid Build Coastguard Worker     {
6288*8975f5c5SAndroid Build Coastguard Worker         labelFromEnv = GetEnvironmentVar(kCaptureLabelVarName);
6289*8975f5c5SAndroid Build Coastguard Worker     }
6290*8975f5c5SAndroid Build Coastguard Worker     if (!labelFromEnv.empty())
6291*8975f5c5SAndroid Build Coastguard Worker     {
6292*8975f5c5SAndroid Build Coastguard Worker         // Optional label to provide unique file names and namespaces
6293*8975f5c5SAndroid Build Coastguard Worker         mCaptureLabel = labelFromEnv;
6294*8975f5c5SAndroid Build Coastguard Worker     }
6295*8975f5c5SAndroid Build Coastguard Worker 
6296*8975f5c5SAndroid Build Coastguard Worker     std::string compressionFromEnv =
6297*8975f5c5SAndroid Build Coastguard Worker         GetEnvironmentVarOrUnCachedAndroidProperty(kCompressionVarName, kAndroidCompression);
6298*8975f5c5SAndroid Build Coastguard Worker     if (compressionFromEnv == "0")
6299*8975f5c5SAndroid Build Coastguard Worker     {
6300*8975f5c5SAndroid Build Coastguard Worker         mCompression = false;
6301*8975f5c5SAndroid Build Coastguard Worker     }
6302*8975f5c5SAndroid Build Coastguard Worker     std::string serializeStateFromEnv = angle::GetEnvironmentVar(kSerializeStateVarName);
6303*8975f5c5SAndroid Build Coastguard Worker     if (serializeStateFromEnv == "1")
6304*8975f5c5SAndroid Build Coastguard Worker     {
6305*8975f5c5SAndroid Build Coastguard Worker         mSerializeStateEnabled = true;
6306*8975f5c5SAndroid Build Coastguard Worker     }
6307*8975f5c5SAndroid Build Coastguard Worker 
6308*8975f5c5SAndroid Build Coastguard Worker     std::string validateSerialiedStateFromEnv =
6309*8975f5c5SAndroid Build Coastguard Worker         GetEnvironmentVarOrUnCachedAndroidProperty(kValidationVarName, kAndroidValidation);
6310*8975f5c5SAndroid Build Coastguard Worker     if (validateSerialiedStateFromEnv == "1")
6311*8975f5c5SAndroid Build Coastguard Worker     {
6312*8975f5c5SAndroid Build Coastguard Worker         mValidateSerializedState = true;
6313*8975f5c5SAndroid Build Coastguard Worker     }
6314*8975f5c5SAndroid Build Coastguard Worker 
6315*8975f5c5SAndroid Build Coastguard Worker     mValidationExpression =
6316*8975f5c5SAndroid Build Coastguard Worker         GetEnvironmentVarOrUnCachedAndroidProperty(kValidationExprVarName, kAndroidValidationExpr);
6317*8975f5c5SAndroid Build Coastguard Worker 
6318*8975f5c5SAndroid Build Coastguard Worker     if (!mValidationExpression.empty())
6319*8975f5c5SAndroid Build Coastguard Worker     {
6320*8975f5c5SAndroid Build Coastguard Worker         INFO() << "Validation expression is " << kValidationExprVarName;
6321*8975f5c5SAndroid Build Coastguard Worker     }
6322*8975f5c5SAndroid Build Coastguard Worker 
6323*8975f5c5SAndroid Build Coastguard Worker     // TODO: Remove. http://anglebug.com/42266223
6324*8975f5c5SAndroid Build Coastguard Worker     std::string sourceExtFromEnv =
6325*8975f5c5SAndroid Build Coastguard Worker         GetEnvironmentVarOrUnCachedAndroidProperty(kSourceExtVarName, kAndroidSourceExt);
6326*8975f5c5SAndroid Build Coastguard Worker     if (!sourceExtFromEnv.empty())
6327*8975f5c5SAndroid Build Coastguard Worker     {
6328*8975f5c5SAndroid Build Coastguard Worker         if (sourceExtFromEnv == "c" || sourceExtFromEnv == "cpp")
6329*8975f5c5SAndroid Build Coastguard Worker         {
6330*8975f5c5SAndroid Build Coastguard Worker             mReplayWriter.setSourceFileExtension(sourceExtFromEnv.c_str());
6331*8975f5c5SAndroid Build Coastguard Worker         }
6332*8975f5c5SAndroid Build Coastguard Worker         else
6333*8975f5c5SAndroid Build Coastguard Worker         {
6334*8975f5c5SAndroid Build Coastguard Worker             WARN() << "Invalid capture source extension: " << sourceExtFromEnv;
6335*8975f5c5SAndroid Build Coastguard Worker         }
6336*8975f5c5SAndroid Build Coastguard Worker     }
6337*8975f5c5SAndroid Build Coastguard Worker 
6338*8975f5c5SAndroid Build Coastguard Worker     std::string sourceSizeFromEnv =
6339*8975f5c5SAndroid Build Coastguard Worker         GetEnvironmentVarOrUnCachedAndroidProperty(kSourceSizeVarName, kAndroidSourceSize);
6340*8975f5c5SAndroid Build Coastguard Worker     if (!sourceSizeFromEnv.empty())
6341*8975f5c5SAndroid Build Coastguard Worker     {
6342*8975f5c5SAndroid Build Coastguard Worker         int sourceSize = atoi(sourceSizeFromEnv.c_str());
6343*8975f5c5SAndroid Build Coastguard Worker         if (sourceSize < 0)
6344*8975f5c5SAndroid Build Coastguard Worker         {
6345*8975f5c5SAndroid Build Coastguard Worker             WARN() << "Invalid capture source size: " << sourceSize;
6346*8975f5c5SAndroid Build Coastguard Worker         }
6347*8975f5c5SAndroid Build Coastguard Worker         else
6348*8975f5c5SAndroid Build Coastguard Worker         {
6349*8975f5c5SAndroid Build Coastguard Worker             mReplayWriter.setSourceFileSizeThreshold(sourceSize);
6350*8975f5c5SAndroid Build Coastguard Worker         }
6351*8975f5c5SAndroid Build Coastguard Worker     }
6352*8975f5c5SAndroid Build Coastguard Worker 
6353*8975f5c5SAndroid Build Coastguard Worker     std::string forceShadowFromEnv =
6354*8975f5c5SAndroid Build Coastguard Worker         GetEnvironmentVarOrUnCachedAndroidProperty(kForceShadowVarName, kAndroidForceShadow);
6355*8975f5c5SAndroid Build Coastguard Worker     if (forceShadowFromEnv == "1")
6356*8975f5c5SAndroid Build Coastguard Worker     {
6357*8975f5c5SAndroid Build Coastguard Worker         INFO() << "Force enabling shadow memory for coherent buffer tracking.";
6358*8975f5c5SAndroid Build Coastguard Worker         mCoherentBufferTracker.enableShadowMemory();
6359*8975f5c5SAndroid Build Coastguard Worker     }
6360*8975f5c5SAndroid Build Coastguard Worker 
6361*8975f5c5SAndroid Build Coastguard Worker     if (mFrameIndex == mCaptureStartFrame)
6362*8975f5c5SAndroid Build Coastguard Worker     {
6363*8975f5c5SAndroid Build Coastguard Worker         // Capture is starting from the first frame, so set the capture active to ensure all GLES
6364*8975f5c5SAndroid Build Coastguard Worker         // commands issued are handled correctly by maybeCapturePreCallUpdates() and
6365*8975f5c5SAndroid Build Coastguard Worker         // maybeCapturePostCallUpdates().
6366*8975f5c5SAndroid Build Coastguard Worker         setCaptureActive();
6367*8975f5c5SAndroid Build Coastguard Worker     }
6368*8975f5c5SAndroid Build Coastguard Worker 
6369*8975f5c5SAndroid Build Coastguard Worker     if (mCaptureEndFrame < mCaptureStartFrame)
6370*8975f5c5SAndroid Build Coastguard Worker     {
6371*8975f5c5SAndroid Build Coastguard Worker         // If we're still in a situation where start frame is after end frame,
6372*8975f5c5SAndroid Build Coastguard Worker         // capture cannot happen. Consider this a disabled state.
6373*8975f5c5SAndroid Build Coastguard Worker         // Note: We won't get here if trigger is in use, as it sets them equal but huge.
6374*8975f5c5SAndroid Build Coastguard Worker         mEnabled = false;
6375*8975f5c5SAndroid Build Coastguard Worker     }
6376*8975f5c5SAndroid Build Coastguard Worker 
6377*8975f5c5SAndroid Build Coastguard Worker     mReplayWriter.setCaptureLabel(mCaptureLabel);
6378*8975f5c5SAndroid Build Coastguard Worker 
6379*8975f5c5SAndroid Build Coastguard Worker     // Special case the output directory
6380*8975f5c5SAndroid Build Coastguard Worker     if (mEnabled)
6381*8975f5c5SAndroid Build Coastguard Worker     {
6382*8975f5c5SAndroid Build Coastguard Worker         // Only perform output directory checks if enabled
6383*8975f5c5SAndroid Build Coastguard Worker         // - This can avoid some expensive process name and filesystem checks
6384*8975f5c5SAndroid Build Coastguard Worker         // - We want to emit errors if the directory doesn't exist
6385*8975f5c5SAndroid Build Coastguard Worker         std::string pathFromEnv =
6386*8975f5c5SAndroid Build Coastguard Worker             GetEnvironmentVarOrUnCachedAndroidProperty(kOutDirectoryVarName, kAndroidOutDir);
6387*8975f5c5SAndroid Build Coastguard Worker         if (pathFromEnv.empty())
6388*8975f5c5SAndroid Build Coastguard Worker         {
6389*8975f5c5SAndroid Build Coastguard Worker             mOutDirectory = GetDefaultOutDirectory();
6390*8975f5c5SAndroid Build Coastguard Worker         }
6391*8975f5c5SAndroid Build Coastguard Worker         else
6392*8975f5c5SAndroid Build Coastguard Worker         {
6393*8975f5c5SAndroid Build Coastguard Worker             mOutDirectory = pathFromEnv;
6394*8975f5c5SAndroid Build Coastguard Worker         }
6395*8975f5c5SAndroid Build Coastguard Worker 
6396*8975f5c5SAndroid Build Coastguard Worker         // Ensure the capture path ends with a slash.
6397*8975f5c5SAndroid Build Coastguard Worker         if (mOutDirectory.back() != '\\' && mOutDirectory.back() != '/')
6398*8975f5c5SAndroid Build Coastguard Worker         {
6399*8975f5c5SAndroid Build Coastguard Worker             mOutDirectory += '/';
6400*8975f5c5SAndroid Build Coastguard Worker         }
6401*8975f5c5SAndroid Build Coastguard Worker     }
6402*8975f5c5SAndroid Build Coastguard Worker }
6403*8975f5c5SAndroid Build Coastguard Worker 
6404*8975f5c5SAndroid Build Coastguard Worker FrameCaptureShared::~FrameCaptureShared() = default;
6405*8975f5c5SAndroid Build Coastguard Worker 
PageRange(size_t start,size_t end)6406*8975f5c5SAndroid Build Coastguard Worker PageRange::PageRange(size_t start, size_t end) : start(start), end(end) {}
6407*8975f5c5SAndroid Build Coastguard Worker PageRange::~PageRange() = default;
6408*8975f5c5SAndroid Build Coastguard Worker 
AddressRange()6409*8975f5c5SAndroid Build Coastguard Worker AddressRange::AddressRange() {}
AddressRange(uintptr_t start,size_t size)6410*8975f5c5SAndroid Build Coastguard Worker AddressRange::AddressRange(uintptr_t start, size_t size) : start(start), size(size) {}
6411*8975f5c5SAndroid Build Coastguard Worker AddressRange::~AddressRange() = default;
6412*8975f5c5SAndroid Build Coastguard Worker 
end()6413*8975f5c5SAndroid Build Coastguard Worker uintptr_t AddressRange::end()
6414*8975f5c5SAndroid Build Coastguard Worker {
6415*8975f5c5SAndroid Build Coastguard Worker     return start + size;
6416*8975f5c5SAndroid Build Coastguard Worker }
6417*8975f5c5SAndroid Build Coastguard Worker 
IsTrackedPerContext(ResourceIDType type)6418*8975f5c5SAndroid Build Coastguard Worker bool IsTrackedPerContext(ResourceIDType type)
6419*8975f5c5SAndroid Build Coastguard Worker {
6420*8975f5c5SAndroid Build Coastguard Worker     // This helper function informs us which context-local (not shared) objects are tracked
6421*8975f5c5SAndroid Build Coastguard Worker     // with per-context object maps.
6422*8975f5c5SAndroid Build Coastguard Worker     if (IsSharedObjectResource(type))
6423*8975f5c5SAndroid Build Coastguard Worker     {
6424*8975f5c5SAndroid Build Coastguard Worker         return false;
6425*8975f5c5SAndroid Build Coastguard Worker     }
6426*8975f5c5SAndroid Build Coastguard Worker 
6427*8975f5c5SAndroid Build Coastguard Worker     // TODO (https://issuetracker.google.com/169868803): Remaining context-local resources (VAOs,
6428*8975f5c5SAndroid Build Coastguard Worker     // PPOs, Transform Feedback Objects, and Query Objects) must also tracked per-context. Once all
6429*8975f5c5SAndroid Build Coastguard Worker     // per-context resource handling is correctly updated then this function can be replaced with
6430*8975f5c5SAndroid Build Coastguard Worker     // !IsSharedObjectResource().
6431*8975f5c5SAndroid Build Coastguard Worker     switch (type)
6432*8975f5c5SAndroid Build Coastguard Worker     {
6433*8975f5c5SAndroid Build Coastguard Worker         case ResourceIDType::Framebuffer:
6434*8975f5c5SAndroid Build Coastguard Worker             return true;
6435*8975f5c5SAndroid Build Coastguard Worker 
6436*8975f5c5SAndroid Build Coastguard Worker         default:
6437*8975f5c5SAndroid Build Coastguard Worker             return false;
6438*8975f5c5SAndroid Build Coastguard Worker     }
6439*8975f5c5SAndroid Build Coastguard Worker }
6440*8975f5c5SAndroid Build Coastguard Worker 
CoherentBuffer(uintptr_t start,size_t size,size_t pageSize,bool isShadowMemoryEnabled)6441*8975f5c5SAndroid Build Coastguard Worker CoherentBuffer::CoherentBuffer(uintptr_t start,
6442*8975f5c5SAndroid Build Coastguard Worker                                size_t size,
6443*8975f5c5SAndroid Build Coastguard Worker                                size_t pageSize,
6444*8975f5c5SAndroid Build Coastguard Worker                                bool isShadowMemoryEnabled)
6445*8975f5c5SAndroid Build Coastguard Worker     : mPageSize(pageSize),
6446*8975f5c5SAndroid Build Coastguard Worker       mShadowMemoryEnabled(isShadowMemoryEnabled),
6447*8975f5c5SAndroid Build Coastguard Worker       mBufferStart(start),
6448*8975f5c5SAndroid Build Coastguard Worker       mShadowMemory(nullptr),
6449*8975f5c5SAndroid Build Coastguard Worker       mShadowDirty(false)
6450*8975f5c5SAndroid Build Coastguard Worker {
6451*8975f5c5SAndroid Build Coastguard Worker     if (mShadowMemoryEnabled)
6452*8975f5c5SAndroid Build Coastguard Worker     {
6453*8975f5c5SAndroid Build Coastguard Worker         // Shadow memory needs to have at least the size of one page, to not protect outside.
6454*8975f5c5SAndroid Build Coastguard Worker         size_t numShadowPages = (size / pageSize) + 1;
6455*8975f5c5SAndroid Build Coastguard Worker         mShadowMemory         = AlignedAlloc(numShadowPages * pageSize, pageSize);
6456*8975f5c5SAndroid Build Coastguard Worker         ASSERT(mShadowMemory != nullptr);
6457*8975f5c5SAndroid Build Coastguard Worker         start = reinterpret_cast<uintptr_t>(mShadowMemory);
6458*8975f5c5SAndroid Build Coastguard Worker     }
6459*8975f5c5SAndroid Build Coastguard Worker 
6460*8975f5c5SAndroid Build Coastguard Worker     mRange.start           = start;
6461*8975f5c5SAndroid Build Coastguard Worker     mRange.size            = size;
6462*8975f5c5SAndroid Build Coastguard Worker     mProtectionRange.start = rx::roundDownPow2(start, pageSize);
6463*8975f5c5SAndroid Build Coastguard Worker 
6464*8975f5c5SAndroid Build Coastguard Worker     uintptr_t protectionEnd = rx::roundUpPow2(start + size, pageSize);
6465*8975f5c5SAndroid Build Coastguard Worker 
6466*8975f5c5SAndroid Build Coastguard Worker     mProtectionRange.size = protectionEnd - mProtectionRange.start;
6467*8975f5c5SAndroid Build Coastguard Worker     mPageCount            = mProtectionRange.size / pageSize;
6468*8975f5c5SAndroid Build Coastguard Worker 
6469*8975f5c5SAndroid Build Coastguard Worker     mProtectionStartPage = mProtectionRange.start / mPageSize;
6470*8975f5c5SAndroid Build Coastguard Worker     mProtectionEndPage   = mProtectionStartPage + mPageCount;
6471*8975f5c5SAndroid Build Coastguard Worker 
6472*8975f5c5SAndroid Build Coastguard Worker     mDirtyPages = std::vector<bool>(mPageCount);
6473*8975f5c5SAndroid Build Coastguard Worker     mDirtyPages.assign(mPageCount, true);
6474*8975f5c5SAndroid Build Coastguard Worker }
6475*8975f5c5SAndroid Build Coastguard Worker 
getDirtyPageRanges()6476*8975f5c5SAndroid Build Coastguard Worker std::vector<PageRange> CoherentBuffer::getDirtyPageRanges()
6477*8975f5c5SAndroid Build Coastguard Worker {
6478*8975f5c5SAndroid Build Coastguard Worker     std::vector<PageRange> dirtyPageRanges;
6479*8975f5c5SAndroid Build Coastguard Worker 
6480*8975f5c5SAndroid Build Coastguard Worker     bool inDirty = false;
6481*8975f5c5SAndroid Build Coastguard Worker     for (size_t i = 0; i < mPageCount; i++)
6482*8975f5c5SAndroid Build Coastguard Worker     {
6483*8975f5c5SAndroid Build Coastguard Worker         if (!inDirty && mDirtyPages[i])
6484*8975f5c5SAndroid Build Coastguard Worker         {
6485*8975f5c5SAndroid Build Coastguard Worker             // Found start of a dirty range
6486*8975f5c5SAndroid Build Coastguard Worker             inDirty = true;
6487*8975f5c5SAndroid Build Coastguard Worker             // Set end page as last page initially
6488*8975f5c5SAndroid Build Coastguard Worker             dirtyPageRanges.push_back(PageRange(i, mPageCount));
6489*8975f5c5SAndroid Build Coastguard Worker         }
6490*8975f5c5SAndroid Build Coastguard Worker         else if (inDirty && !mDirtyPages[i])
6491*8975f5c5SAndroid Build Coastguard Worker         {
6492*8975f5c5SAndroid Build Coastguard Worker             // Found end of a dirty range
6493*8975f5c5SAndroid Build Coastguard Worker             inDirty                    = false;
6494*8975f5c5SAndroid Build Coastguard Worker             dirtyPageRanges.back().end = i;
6495*8975f5c5SAndroid Build Coastguard Worker         }
6496*8975f5c5SAndroid Build Coastguard Worker     }
6497*8975f5c5SAndroid Build Coastguard Worker 
6498*8975f5c5SAndroid Build Coastguard Worker     return dirtyPageRanges;
6499*8975f5c5SAndroid Build Coastguard Worker }
6500*8975f5c5SAndroid Build Coastguard Worker 
getRange()6501*8975f5c5SAndroid Build Coastguard Worker AddressRange CoherentBuffer::getRange()
6502*8975f5c5SAndroid Build Coastguard Worker {
6503*8975f5c5SAndroid Build Coastguard Worker     return mRange;
6504*8975f5c5SAndroid Build Coastguard Worker }
6505*8975f5c5SAndroid Build Coastguard Worker 
getDirtyAddressRange(const PageRange & dirtyPageRange)6506*8975f5c5SAndroid Build Coastguard Worker AddressRange CoherentBuffer::getDirtyAddressRange(const PageRange &dirtyPageRange)
6507*8975f5c5SAndroid Build Coastguard Worker {
6508*8975f5c5SAndroid Build Coastguard Worker     AddressRange range;
6509*8975f5c5SAndroid Build Coastguard Worker 
6510*8975f5c5SAndroid Build Coastguard Worker     if (dirtyPageRange.start == 0)
6511*8975f5c5SAndroid Build Coastguard Worker     {
6512*8975f5c5SAndroid Build Coastguard Worker         // First page, use non page aligned buffer start.
6513*8975f5c5SAndroid Build Coastguard Worker         range.start = mRange.start;
6514*8975f5c5SAndroid Build Coastguard Worker     }
6515*8975f5c5SAndroid Build Coastguard Worker     else
6516*8975f5c5SAndroid Build Coastguard Worker     {
6517*8975f5c5SAndroid Build Coastguard Worker         range.start = mProtectionRange.start + dirtyPageRange.start * mPageSize;
6518*8975f5c5SAndroid Build Coastguard Worker     }
6519*8975f5c5SAndroid Build Coastguard Worker 
6520*8975f5c5SAndroid Build Coastguard Worker     if (dirtyPageRange.end == mPageCount)
6521*8975f5c5SAndroid Build Coastguard Worker     {
6522*8975f5c5SAndroid Build Coastguard Worker         // Last page, use non page aligned buffer end.
6523*8975f5c5SAndroid Build Coastguard Worker         range.size = mRange.end() - range.start;
6524*8975f5c5SAndroid Build Coastguard Worker     }
6525*8975f5c5SAndroid Build Coastguard Worker     else
6526*8975f5c5SAndroid Build Coastguard Worker     {
6527*8975f5c5SAndroid Build Coastguard Worker         range.size = (dirtyPageRange.end - dirtyPageRange.start) * mPageSize;
6528*8975f5c5SAndroid Build Coastguard Worker         // This occurs when a buffer occupies 2 pages, but is smaller than a page.
6529*8975f5c5SAndroid Build Coastguard Worker         if (mRange.end() < range.end())
6530*8975f5c5SAndroid Build Coastguard Worker         {
6531*8975f5c5SAndroid Build Coastguard Worker             range.size = mRange.end() - range.start;
6532*8975f5c5SAndroid Build Coastguard Worker         }
6533*8975f5c5SAndroid Build Coastguard Worker     }
6534*8975f5c5SAndroid Build Coastguard Worker 
6535*8975f5c5SAndroid Build Coastguard Worker     // Dirty range must be in buffer
6536*8975f5c5SAndroid Build Coastguard Worker     ASSERT(range.start >= mRange.start && mRange.end() >= range.end());
6537*8975f5c5SAndroid Build Coastguard Worker 
6538*8975f5c5SAndroid Build Coastguard Worker     return range;
6539*8975f5c5SAndroid Build Coastguard Worker }
6540*8975f5c5SAndroid Build Coastguard Worker 
~CoherentBuffer()6541*8975f5c5SAndroid Build Coastguard Worker CoherentBuffer::~CoherentBuffer()
6542*8975f5c5SAndroid Build Coastguard Worker {
6543*8975f5c5SAndroid Build Coastguard Worker     if (mShadowMemory != nullptr)
6544*8975f5c5SAndroid Build Coastguard Worker     {
6545*8975f5c5SAndroid Build Coastguard Worker         AlignedFree(mShadowMemory);
6546*8975f5c5SAndroid Build Coastguard Worker     }
6547*8975f5c5SAndroid Build Coastguard Worker }
6548*8975f5c5SAndroid Build Coastguard Worker 
isDirty()6549*8975f5c5SAndroid Build Coastguard Worker bool CoherentBuffer::isDirty()
6550*8975f5c5SAndroid Build Coastguard Worker {
6551*8975f5c5SAndroid Build Coastguard Worker     return std::find(mDirtyPages.begin(), mDirtyPages.end(), true) != mDirtyPages.end();
6552*8975f5c5SAndroid Build Coastguard Worker }
6553*8975f5c5SAndroid Build Coastguard Worker 
contains(size_t page,size_t * relativePage)6554*8975f5c5SAndroid Build Coastguard Worker bool CoherentBuffer::contains(size_t page, size_t *relativePage)
6555*8975f5c5SAndroid Build Coastguard Worker {
6556*8975f5c5SAndroid Build Coastguard Worker     bool isInProtectionRange = page >= mProtectionStartPage && page < mProtectionEndPage;
6557*8975f5c5SAndroid Build Coastguard Worker     if (!isInProtectionRange)
6558*8975f5c5SAndroid Build Coastguard Worker     {
6559*8975f5c5SAndroid Build Coastguard Worker         return false;
6560*8975f5c5SAndroid Build Coastguard Worker     }
6561*8975f5c5SAndroid Build Coastguard Worker 
6562*8975f5c5SAndroid Build Coastguard Worker     *relativePage = page - mProtectionStartPage;
6563*8975f5c5SAndroid Build Coastguard Worker 
6564*8975f5c5SAndroid Build Coastguard Worker     ASSERT(page >= mProtectionStartPage);
6565*8975f5c5SAndroid Build Coastguard Worker 
6566*8975f5c5SAndroid Build Coastguard Worker     return true;
6567*8975f5c5SAndroid Build Coastguard Worker }
6568*8975f5c5SAndroid Build Coastguard Worker 
protectPageRange(const PageRange & pageRange)6569*8975f5c5SAndroid Build Coastguard Worker void CoherentBuffer::protectPageRange(const PageRange &pageRange)
6570*8975f5c5SAndroid Build Coastguard Worker {
6571*8975f5c5SAndroid Build Coastguard Worker     for (size_t i = pageRange.start; i < pageRange.end; i++)
6572*8975f5c5SAndroid Build Coastguard Worker     {
6573*8975f5c5SAndroid Build Coastguard Worker         setDirty(i, false);
6574*8975f5c5SAndroid Build Coastguard Worker     }
6575*8975f5c5SAndroid Build Coastguard Worker }
6576*8975f5c5SAndroid Build Coastguard Worker 
protectAll()6577*8975f5c5SAndroid Build Coastguard Worker void CoherentBuffer::protectAll()
6578*8975f5c5SAndroid Build Coastguard Worker {
6579*8975f5c5SAndroid Build Coastguard Worker     for (size_t i = 0; i < mPageCount; i++)
6580*8975f5c5SAndroid Build Coastguard Worker     {
6581*8975f5c5SAndroid Build Coastguard Worker         setDirty(i, false);
6582*8975f5c5SAndroid Build Coastguard Worker     }
6583*8975f5c5SAndroid Build Coastguard Worker }
6584*8975f5c5SAndroid Build Coastguard Worker 
updateBufferMemory()6585*8975f5c5SAndroid Build Coastguard Worker void CoherentBuffer::updateBufferMemory()
6586*8975f5c5SAndroid Build Coastguard Worker {
6587*8975f5c5SAndroid Build Coastguard Worker     memcpy(reinterpret_cast<void *>(mBufferStart), reinterpret_cast<void *>(mRange.start),
6588*8975f5c5SAndroid Build Coastguard Worker            mRange.size);
6589*8975f5c5SAndroid Build Coastguard Worker }
6590*8975f5c5SAndroid Build Coastguard Worker 
updateShadowMemory()6591*8975f5c5SAndroid Build Coastguard Worker void CoherentBuffer::updateShadowMemory()
6592*8975f5c5SAndroid Build Coastguard Worker {
6593*8975f5c5SAndroid Build Coastguard Worker     memcpy(reinterpret_cast<void *>(mRange.start), reinterpret_cast<void *>(mBufferStart),
6594*8975f5c5SAndroid Build Coastguard Worker            mRange.size);
6595*8975f5c5SAndroid Build Coastguard Worker     mShadowDirty = false;
6596*8975f5c5SAndroid Build Coastguard Worker }
6597*8975f5c5SAndroid Build Coastguard Worker 
setDirty(size_t relativePage,bool dirty)6598*8975f5c5SAndroid Build Coastguard Worker void CoherentBuffer::setDirty(size_t relativePage, bool dirty)
6599*8975f5c5SAndroid Build Coastguard Worker {
6600*8975f5c5SAndroid Build Coastguard Worker     if (mDirtyPages[relativePage] == dirty)
6601*8975f5c5SAndroid Build Coastguard Worker     {
6602*8975f5c5SAndroid Build Coastguard Worker         // The page is already set.
6603*8975f5c5SAndroid Build Coastguard Worker         // This can happen when tracked buffers overlap in a page.
6604*8975f5c5SAndroid Build Coastguard Worker         return;
6605*8975f5c5SAndroid Build Coastguard Worker     }
6606*8975f5c5SAndroid Build Coastguard Worker 
6607*8975f5c5SAndroid Build Coastguard Worker     uintptr_t pageStart = mProtectionRange.start + relativePage * mPageSize;
6608*8975f5c5SAndroid Build Coastguard Worker 
6609*8975f5c5SAndroid Build Coastguard Worker     // Last page end must be the same as protection end
6610*8975f5c5SAndroid Build Coastguard Worker     if (relativePage + 1 == mPageCount)
6611*8975f5c5SAndroid Build Coastguard Worker     {
6612*8975f5c5SAndroid Build Coastguard Worker         ASSERT(mProtectionRange.end() == pageStart + mPageSize);
6613*8975f5c5SAndroid Build Coastguard Worker     }
6614*8975f5c5SAndroid Build Coastguard Worker 
6615*8975f5c5SAndroid Build Coastguard Worker     bool ret;
6616*8975f5c5SAndroid Build Coastguard Worker     if (dirty)
6617*8975f5c5SAndroid Build Coastguard Worker     {
6618*8975f5c5SAndroid Build Coastguard Worker         ret = UnprotectMemory(pageStart, mPageSize);
6619*8975f5c5SAndroid Build Coastguard Worker     }
6620*8975f5c5SAndroid Build Coastguard Worker     else
6621*8975f5c5SAndroid Build Coastguard Worker     {
6622*8975f5c5SAndroid Build Coastguard Worker         ret = ProtectMemory(pageStart, mPageSize);
6623*8975f5c5SAndroid Build Coastguard Worker     }
6624*8975f5c5SAndroid Build Coastguard Worker 
6625*8975f5c5SAndroid Build Coastguard Worker     if (!ret)
6626*8975f5c5SAndroid Build Coastguard Worker     {
6627*8975f5c5SAndroid Build Coastguard Worker         ERR() << "Could not set protection for buffer page " << relativePage << " at "
6628*8975f5c5SAndroid Build Coastguard Worker               << reinterpret_cast<void *>(pageStart) << " with size " << mPageSize;
6629*8975f5c5SAndroid Build Coastguard Worker     }
6630*8975f5c5SAndroid Build Coastguard Worker     mDirtyPages[relativePage] = dirty;
6631*8975f5c5SAndroid Build Coastguard Worker }
6632*8975f5c5SAndroid Build Coastguard Worker 
removeProtection(PageSharingType sharingType)6633*8975f5c5SAndroid Build Coastguard Worker void CoherentBuffer::removeProtection(PageSharingType sharingType)
6634*8975f5c5SAndroid Build Coastguard Worker {
6635*8975f5c5SAndroid Build Coastguard Worker     uintptr_t start = mProtectionRange.start;
6636*8975f5c5SAndroid Build Coastguard Worker     size_t size     = mProtectionRange.size;
6637*8975f5c5SAndroid Build Coastguard Worker 
6638*8975f5c5SAndroid Build Coastguard Worker     switch (sharingType)
6639*8975f5c5SAndroid Build Coastguard Worker     {
6640*8975f5c5SAndroid Build Coastguard Worker         case PageSharingType::FirstShared:
6641*8975f5c5SAndroid Build Coastguard Worker         case PageSharingType::FirstAndLastShared:
6642*8975f5c5SAndroid Build Coastguard Worker             start += mPageSize;
6643*8975f5c5SAndroid Build Coastguard Worker             break;
6644*8975f5c5SAndroid Build Coastguard Worker         default:
6645*8975f5c5SAndroid Build Coastguard Worker             break;
6646*8975f5c5SAndroid Build Coastguard Worker     }
6647*8975f5c5SAndroid Build Coastguard Worker 
6648*8975f5c5SAndroid Build Coastguard Worker     switch (sharingType)
6649*8975f5c5SAndroid Build Coastguard Worker     {
6650*8975f5c5SAndroid Build Coastguard Worker         case PageSharingType::FirstShared:
6651*8975f5c5SAndroid Build Coastguard Worker         case PageSharingType::LastShared:
6652*8975f5c5SAndroid Build Coastguard Worker             size -= mPageSize;
6653*8975f5c5SAndroid Build Coastguard Worker             break;
6654*8975f5c5SAndroid Build Coastguard Worker         case PageSharingType::FirstAndLastShared:
6655*8975f5c5SAndroid Build Coastguard Worker             size -= (2 * mPageSize);
6656*8975f5c5SAndroid Build Coastguard Worker             break;
6657*8975f5c5SAndroid Build Coastguard Worker         default:
6658*8975f5c5SAndroid Build Coastguard Worker             break;
6659*8975f5c5SAndroid Build Coastguard Worker     }
6660*8975f5c5SAndroid Build Coastguard Worker 
6661*8975f5c5SAndroid Build Coastguard Worker     if (size == 0)
6662*8975f5c5SAndroid Build Coastguard Worker     {
6663*8975f5c5SAndroid Build Coastguard Worker         return;
6664*8975f5c5SAndroid Build Coastguard Worker     }
6665*8975f5c5SAndroid Build Coastguard Worker 
6666*8975f5c5SAndroid Build Coastguard Worker     if (!UnprotectMemory(start, size))
6667*8975f5c5SAndroid Build Coastguard Worker     {
6668*8975f5c5SAndroid Build Coastguard Worker         ERR() << "Could not remove protection for buffer at " << start << " with size " << size;
6669*8975f5c5SAndroid Build Coastguard Worker     }
6670*8975f5c5SAndroid Build Coastguard Worker }
6671*8975f5c5SAndroid Build Coastguard Worker 
canProtectDirectly(gl::Context * context)6672*8975f5c5SAndroid Build Coastguard Worker bool CoherentBufferTracker::canProtectDirectly(gl::Context *context)
6673*8975f5c5SAndroid Build Coastguard Worker {
6674*8975f5c5SAndroid Build Coastguard Worker     gl::BufferID bufferId = context->createBuffer();
6675*8975f5c5SAndroid Build Coastguard Worker 
6676*8975f5c5SAndroid Build Coastguard Worker     gl::BufferBinding targetPacked = gl::BufferBinding::Array;
6677*8975f5c5SAndroid Build Coastguard Worker     context->bindBuffer(targetPacked, bufferId);
6678*8975f5c5SAndroid Build Coastguard Worker 
6679*8975f5c5SAndroid Build Coastguard Worker     // Allocate 2 pages so we will always have a full aligned page to protect
6680*8975f5c5SAndroid Build Coastguard Worker     GLsizei size = static_cast<GLsizei>(mPageSize * 2);
6681*8975f5c5SAndroid Build Coastguard Worker 
6682*8975f5c5SAndroid Build Coastguard Worker     context->bufferStorage(targetPacked, size, nullptr,
6683*8975f5c5SAndroid Build Coastguard Worker                            GL_DYNAMIC_STORAGE_BIT_EXT | GL_MAP_WRITE_BIT |
6684*8975f5c5SAndroid Build Coastguard Worker                                GL_MAP_PERSISTENT_BIT_EXT | GL_MAP_COHERENT_BIT_EXT);
6685*8975f5c5SAndroid Build Coastguard Worker 
6686*8975f5c5SAndroid Build Coastguard Worker     gl::Buffer *buffer = context->getBuffer(bufferId);
6687*8975f5c5SAndroid Build Coastguard Worker 
6688*8975f5c5SAndroid Build Coastguard Worker     angle::Result result = buffer->mapRange(
6689*8975f5c5SAndroid Build Coastguard Worker         context, 0, size, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT_EXT | GL_MAP_COHERENT_BIT_EXT);
6690*8975f5c5SAndroid Build Coastguard Worker     if (result != angle::Result::Continue)
6691*8975f5c5SAndroid Build Coastguard Worker     {
6692*8975f5c5SAndroid Build Coastguard Worker         ERR() << "Failed to mapRange of buffer.";
6693*8975f5c5SAndroid Build Coastguard Worker     }
6694*8975f5c5SAndroid Build Coastguard Worker 
6695*8975f5c5SAndroid Build Coastguard Worker     void *map = buffer->getMapPointer();
6696*8975f5c5SAndroid Build Coastguard Worker     if (map == nullptr)
6697*8975f5c5SAndroid Build Coastguard Worker     {
6698*8975f5c5SAndroid Build Coastguard Worker         ERR() << "Failed to getMapPointer of buffer.";
6699*8975f5c5SAndroid Build Coastguard Worker     }
6700*8975f5c5SAndroid Build Coastguard Worker 
6701*8975f5c5SAndroid Build Coastguard Worker     // Test mprotect
6702*8975f5c5SAndroid Build Coastguard Worker     auto start = reinterpret_cast<uintptr_t>(map);
6703*8975f5c5SAndroid Build Coastguard Worker 
6704*8975f5c5SAndroid Build Coastguard Worker     // Only protect a whole page inside the allocated memory
6705*8975f5c5SAndroid Build Coastguard Worker     uintptr_t protectionStart = rx::roundUpPow2(start, mPageSize);
6706*8975f5c5SAndroid Build Coastguard Worker     uintptr_t protectionEnd   = protectionStart + mPageSize;
6707*8975f5c5SAndroid Build Coastguard Worker 
6708*8975f5c5SAndroid Build Coastguard Worker     ASSERT(protectionStart < protectionEnd);
6709*8975f5c5SAndroid Build Coastguard Worker 
6710*8975f5c5SAndroid Build Coastguard Worker     angle::PageFaultCallback callback = [](uintptr_t address) {
6711*8975f5c5SAndroid Build Coastguard Worker         return angle::PageFaultHandlerRangeType::InRange;
6712*8975f5c5SAndroid Build Coastguard Worker     };
6713*8975f5c5SAndroid Build Coastguard Worker 
6714*8975f5c5SAndroid Build Coastguard Worker     std::unique_ptr<angle::PageFaultHandler> handler(CreatePageFaultHandler(callback));
6715*8975f5c5SAndroid Build Coastguard Worker 
6716*8975f5c5SAndroid Build Coastguard Worker     if (!handler->enable())
6717*8975f5c5SAndroid Build Coastguard Worker     {
6718*8975f5c5SAndroid Build Coastguard Worker         GLboolean unmapResult;
6719*8975f5c5SAndroid Build Coastguard Worker         if (buffer->unmap(context, &unmapResult) != angle::Result::Continue)
6720*8975f5c5SAndroid Build Coastguard Worker         {
6721*8975f5c5SAndroid Build Coastguard Worker             ERR() << "Could not unmap buffer.";
6722*8975f5c5SAndroid Build Coastguard Worker         }
6723*8975f5c5SAndroid Build Coastguard Worker         context->bindBuffer(targetPacked, {0});
6724*8975f5c5SAndroid Build Coastguard Worker 
6725*8975f5c5SAndroid Build Coastguard Worker         // Page fault handler could not be enabled, memory can't be protected directly.
6726*8975f5c5SAndroid Build Coastguard Worker         return false;
6727*8975f5c5SAndroid Build Coastguard Worker     }
6728*8975f5c5SAndroid Build Coastguard Worker 
6729*8975f5c5SAndroid Build Coastguard Worker     size_t protectionSize = protectionEnd - protectionStart;
6730*8975f5c5SAndroid Build Coastguard Worker 
6731*8975f5c5SAndroid Build Coastguard Worker     ASSERT(protectionSize == mPageSize);
6732*8975f5c5SAndroid Build Coastguard Worker 
6733*8975f5c5SAndroid Build Coastguard Worker     bool canProtect = angle::ProtectMemory(protectionStart, protectionSize);
6734*8975f5c5SAndroid Build Coastguard Worker     if (canProtect)
6735*8975f5c5SAndroid Build Coastguard Worker     {
6736*8975f5c5SAndroid Build Coastguard Worker         angle::UnprotectMemory(protectionStart, protectionSize);
6737*8975f5c5SAndroid Build Coastguard Worker     }
6738*8975f5c5SAndroid Build Coastguard Worker 
6739*8975f5c5SAndroid Build Coastguard Worker     // Clean up
6740*8975f5c5SAndroid Build Coastguard Worker     handler->disable();
6741*8975f5c5SAndroid Build Coastguard Worker 
6742*8975f5c5SAndroid Build Coastguard Worker     GLboolean unmapResult;
6743*8975f5c5SAndroid Build Coastguard Worker     if (buffer->unmap(context, &unmapResult) != angle::Result::Continue)
6744*8975f5c5SAndroid Build Coastguard Worker     {
6745*8975f5c5SAndroid Build Coastguard Worker         ERR() << "Could not unmap buffer.";
6746*8975f5c5SAndroid Build Coastguard Worker     }
6747*8975f5c5SAndroid Build Coastguard Worker     context->bindBuffer(targetPacked, {0});
6748*8975f5c5SAndroid Build Coastguard Worker     context->deleteBuffer(buffer->id());
6749*8975f5c5SAndroid Build Coastguard Worker 
6750*8975f5c5SAndroid Build Coastguard Worker     return canProtect;
6751*8975f5c5SAndroid Build Coastguard Worker }
6752*8975f5c5SAndroid Build Coastguard Worker 
CoherentBufferTracker()6753*8975f5c5SAndroid Build Coastguard Worker CoherentBufferTracker::CoherentBufferTracker() : mEnabled(false), mShadowMemoryEnabled(false)
6754*8975f5c5SAndroid Build Coastguard Worker {
6755*8975f5c5SAndroid Build Coastguard Worker     mPageSize = GetPageSize();
6756*8975f5c5SAndroid Build Coastguard Worker }
6757*8975f5c5SAndroid Build Coastguard Worker 
~CoherentBufferTracker()6758*8975f5c5SAndroid Build Coastguard Worker CoherentBufferTracker::~CoherentBufferTracker()
6759*8975f5c5SAndroid Build Coastguard Worker {
6760*8975f5c5SAndroid Build Coastguard Worker     disable();
6761*8975f5c5SAndroid Build Coastguard Worker }
6762*8975f5c5SAndroid Build Coastguard Worker 
handleWrite(uintptr_t address)6763*8975f5c5SAndroid Build Coastguard Worker PageFaultHandlerRangeType CoherentBufferTracker::handleWrite(uintptr_t address)
6764*8975f5c5SAndroid Build Coastguard Worker {
6765*8975f5c5SAndroid Build Coastguard Worker     std::lock_guard<angle::SimpleMutex> lock(mMutex);
6766*8975f5c5SAndroid Build Coastguard Worker     auto pagesInBuffers = getBufferPagesForAddress(address);
6767*8975f5c5SAndroid Build Coastguard Worker 
6768*8975f5c5SAndroid Build Coastguard Worker     if (pagesInBuffers.empty())
6769*8975f5c5SAndroid Build Coastguard Worker     {
6770*8975f5c5SAndroid Build Coastguard Worker         ERR() << "Didn't find a tracked buffer containing " << reinterpret_cast<void *>(address);
6771*8975f5c5SAndroid Build Coastguard Worker     }
6772*8975f5c5SAndroid Build Coastguard Worker 
6773*8975f5c5SAndroid Build Coastguard Worker     for (const auto &page : pagesInBuffers)
6774*8975f5c5SAndroid Build Coastguard Worker     {
6775*8975f5c5SAndroid Build Coastguard Worker         std::shared_ptr<CoherentBuffer> buffer = page.first;
6776*8975f5c5SAndroid Build Coastguard Worker         size_t relativePage                    = page.second;
6777*8975f5c5SAndroid Build Coastguard Worker         buffer->setDirty(relativePage, true);
6778*8975f5c5SAndroid Build Coastguard Worker     }
6779*8975f5c5SAndroid Build Coastguard Worker 
6780*8975f5c5SAndroid Build Coastguard Worker     return pagesInBuffers.empty() ? PageFaultHandlerRangeType::OutOfRange
6781*8975f5c5SAndroid Build Coastguard Worker                                   : PageFaultHandlerRangeType::InRange;
6782*8975f5c5SAndroid Build Coastguard Worker }
6783*8975f5c5SAndroid Build Coastguard Worker 
getBufferPagesForAddress(uintptr_t address)6784*8975f5c5SAndroid Build Coastguard Worker HashMap<std::shared_ptr<CoherentBuffer>, size_t> CoherentBufferTracker::getBufferPagesForAddress(
6785*8975f5c5SAndroid Build Coastguard Worker     uintptr_t address)
6786*8975f5c5SAndroid Build Coastguard Worker {
6787*8975f5c5SAndroid Build Coastguard Worker     HashMap<std::shared_ptr<CoherentBuffer>, size_t> foundPages;
6788*8975f5c5SAndroid Build Coastguard Worker 
6789*8975f5c5SAndroid Build Coastguard Worker #if defined(ANGLE_PLATFORM_ANDROID)
6790*8975f5c5SAndroid Build Coastguard Worker     size_t page;
6791*8975f5c5SAndroid Build Coastguard Worker     if (mShadowMemoryEnabled)
6792*8975f5c5SAndroid Build Coastguard Worker     {
6793*8975f5c5SAndroid Build Coastguard Worker         // Starting with Android 11 heap pointers get a tag which is stripped by the POSIX mprotect
6794*8975f5c5SAndroid Build Coastguard Worker         // callback. We need to add this tag manually to the untagged pointer in order to determine
6795*8975f5c5SAndroid Build Coastguard Worker         // the corresponding page.
6796*8975f5c5SAndroid Build Coastguard Worker         // See: https://source.android.com/docs/security/test/tagged-pointers
6797*8975f5c5SAndroid Build Coastguard Worker         // TODO(http://anglebug.com/42265874): Determine when heap pointer tagging is not enabled.
6798*8975f5c5SAndroid Build Coastguard Worker         constexpr unsigned long long POINTER_TAG = 0xb400000000000000;
6799*8975f5c5SAndroid Build Coastguard Worker         unsigned long long taggedAddress         = address | POINTER_TAG;
6800*8975f5c5SAndroid Build Coastguard Worker         page                                     = static_cast<size_t>(taggedAddress / mPageSize);
6801*8975f5c5SAndroid Build Coastguard Worker     }
6802*8975f5c5SAndroid Build Coastguard Worker     else
6803*8975f5c5SAndroid Build Coastguard Worker     {
6804*8975f5c5SAndroid Build Coastguard Worker         // VMA allocated memory pointers are not tagged.
6805*8975f5c5SAndroid Build Coastguard Worker         page = address / mPageSize;
6806*8975f5c5SAndroid Build Coastguard Worker     }
6807*8975f5c5SAndroid Build Coastguard Worker #else
6808*8975f5c5SAndroid Build Coastguard Worker     size_t page = address / mPageSize;
6809*8975f5c5SAndroid Build Coastguard Worker #endif
6810*8975f5c5SAndroid Build Coastguard Worker 
6811*8975f5c5SAndroid Build Coastguard Worker     for (const auto &pair : mBuffers)
6812*8975f5c5SAndroid Build Coastguard Worker     {
6813*8975f5c5SAndroid Build Coastguard Worker         std::shared_ptr<CoherentBuffer> buffer = pair.second;
6814*8975f5c5SAndroid Build Coastguard Worker         size_t relativePage;
6815*8975f5c5SAndroid Build Coastguard Worker         if (buffer->contains(page, &relativePage))
6816*8975f5c5SAndroid Build Coastguard Worker         {
6817*8975f5c5SAndroid Build Coastguard Worker             foundPages.insert(std::make_pair(buffer, relativePage));
6818*8975f5c5SAndroid Build Coastguard Worker         }
6819*8975f5c5SAndroid Build Coastguard Worker     }
6820*8975f5c5SAndroid Build Coastguard Worker 
6821*8975f5c5SAndroid Build Coastguard Worker     return foundPages;
6822*8975f5c5SAndroid Build Coastguard Worker }
6823*8975f5c5SAndroid Build Coastguard Worker 
isDirty(gl::BufferID id)6824*8975f5c5SAndroid Build Coastguard Worker bool CoherentBufferTracker::isDirty(gl::BufferID id)
6825*8975f5c5SAndroid Build Coastguard Worker {
6826*8975f5c5SAndroid Build Coastguard Worker     return mBuffers[id.value]->isDirty();
6827*8975f5c5SAndroid Build Coastguard Worker }
6828*8975f5c5SAndroid Build Coastguard Worker 
enable()6829*8975f5c5SAndroid Build Coastguard Worker void CoherentBufferTracker::enable()
6830*8975f5c5SAndroid Build Coastguard Worker {
6831*8975f5c5SAndroid Build Coastguard Worker     if (mEnabled)
6832*8975f5c5SAndroid Build Coastguard Worker     {
6833*8975f5c5SAndroid Build Coastguard Worker         return;
6834*8975f5c5SAndroid Build Coastguard Worker     }
6835*8975f5c5SAndroid Build Coastguard Worker 
6836*8975f5c5SAndroid Build Coastguard Worker     PageFaultCallback callback = [this](uintptr_t address) { return handleWrite(address); };
6837*8975f5c5SAndroid Build Coastguard Worker 
6838*8975f5c5SAndroid Build Coastguard Worker     // This needs to be initialized after canProtectDirectly ran and can only be initialized once.
6839*8975f5c5SAndroid Build Coastguard Worker     if (!mPageFaultHandler)
6840*8975f5c5SAndroid Build Coastguard Worker     {
6841*8975f5c5SAndroid Build Coastguard Worker         mPageFaultHandler = std::unique_ptr<PageFaultHandler>(CreatePageFaultHandler(callback));
6842*8975f5c5SAndroid Build Coastguard Worker     }
6843*8975f5c5SAndroid Build Coastguard Worker 
6844*8975f5c5SAndroid Build Coastguard Worker     bool ret = mPageFaultHandler->enable();
6845*8975f5c5SAndroid Build Coastguard Worker     if (ret)
6846*8975f5c5SAndroid Build Coastguard Worker     {
6847*8975f5c5SAndroid Build Coastguard Worker         mEnabled = true;
6848*8975f5c5SAndroid Build Coastguard Worker     }
6849*8975f5c5SAndroid Build Coastguard Worker     else
6850*8975f5c5SAndroid Build Coastguard Worker     {
6851*8975f5c5SAndroid Build Coastguard Worker         ERR() << "Could not enable page fault handler.";
6852*8975f5c5SAndroid Build Coastguard Worker     }
6853*8975f5c5SAndroid Build Coastguard Worker }
6854*8975f5c5SAndroid Build Coastguard Worker 
haveBuffer(gl::BufferID id)6855*8975f5c5SAndroid Build Coastguard Worker bool CoherentBufferTracker::haveBuffer(gl::BufferID id)
6856*8975f5c5SAndroid Build Coastguard Worker {
6857*8975f5c5SAndroid Build Coastguard Worker     return mBuffers.find(id.value) != mBuffers.end();
6858*8975f5c5SAndroid Build Coastguard Worker }
6859*8975f5c5SAndroid Build Coastguard Worker 
onEndFrame()6860*8975f5c5SAndroid Build Coastguard Worker void CoherentBufferTracker::onEndFrame()
6861*8975f5c5SAndroid Build Coastguard Worker {
6862*8975f5c5SAndroid Build Coastguard Worker     std::lock_guard<angle::SimpleMutex> lock(mMutex);
6863*8975f5c5SAndroid Build Coastguard Worker 
6864*8975f5c5SAndroid Build Coastguard Worker     if (!mEnabled)
6865*8975f5c5SAndroid Build Coastguard Worker     {
6866*8975f5c5SAndroid Build Coastguard Worker         return;
6867*8975f5c5SAndroid Build Coastguard Worker     }
6868*8975f5c5SAndroid Build Coastguard Worker 
6869*8975f5c5SAndroid Build Coastguard Worker     // Remove protection from all buffers
6870*8975f5c5SAndroid Build Coastguard Worker     for (const auto &pair : mBuffers)
6871*8975f5c5SAndroid Build Coastguard Worker     {
6872*8975f5c5SAndroid Build Coastguard Worker         std::shared_ptr<CoherentBuffer> buffer = pair.second;
6873*8975f5c5SAndroid Build Coastguard Worker         buffer->removeProtection(PageSharingType::NoneShared);
6874*8975f5c5SAndroid Build Coastguard Worker     }
6875*8975f5c5SAndroid Build Coastguard Worker 
6876*8975f5c5SAndroid Build Coastguard Worker     disable();
6877*8975f5c5SAndroid Build Coastguard Worker }
6878*8975f5c5SAndroid Build Coastguard Worker 
disable()6879*8975f5c5SAndroid Build Coastguard Worker void CoherentBufferTracker::disable()
6880*8975f5c5SAndroid Build Coastguard Worker {
6881*8975f5c5SAndroid Build Coastguard Worker     if (!mEnabled)
6882*8975f5c5SAndroid Build Coastguard Worker     {
6883*8975f5c5SAndroid Build Coastguard Worker         return;
6884*8975f5c5SAndroid Build Coastguard Worker     }
6885*8975f5c5SAndroid Build Coastguard Worker 
6886*8975f5c5SAndroid Build Coastguard Worker     if (mPageFaultHandler->disable())
6887*8975f5c5SAndroid Build Coastguard Worker     {
6888*8975f5c5SAndroid Build Coastguard Worker         mEnabled = false;
6889*8975f5c5SAndroid Build Coastguard Worker     }
6890*8975f5c5SAndroid Build Coastguard Worker     else
6891*8975f5c5SAndroid Build Coastguard Worker     {
6892*8975f5c5SAndroid Build Coastguard Worker         ERR() << "Could not disable page fault handler.";
6893*8975f5c5SAndroid Build Coastguard Worker     }
6894*8975f5c5SAndroid Build Coastguard Worker 
6895*8975f5c5SAndroid Build Coastguard Worker     if (mShadowMemoryEnabled && mBuffers.size() > 0)
6896*8975f5c5SAndroid Build Coastguard Worker     {
6897*8975f5c5SAndroid Build Coastguard Worker         WARN() << "Disabling coherent buffer tracking while leaving shadow memory without "
6898*8975f5c5SAndroid Build Coastguard Worker                   "synchronization. Expect rendering artifacts after capture ends.";
6899*8975f5c5SAndroid Build Coastguard Worker     }
6900*8975f5c5SAndroid Build Coastguard Worker }
6901*8975f5c5SAndroid Build Coastguard Worker 
addBuffer(gl::BufferID id,uintptr_t start,size_t size)6902*8975f5c5SAndroid Build Coastguard Worker uintptr_t CoherentBufferTracker::addBuffer(gl::BufferID id, uintptr_t start, size_t size)
6903*8975f5c5SAndroid Build Coastguard Worker {
6904*8975f5c5SAndroid Build Coastguard Worker     std::lock_guard<angle::SimpleMutex> lock(mMutex);
6905*8975f5c5SAndroid Build Coastguard Worker 
6906*8975f5c5SAndroid Build Coastguard Worker     if (haveBuffer(id))
6907*8975f5c5SAndroid Build Coastguard Worker     {
6908*8975f5c5SAndroid Build Coastguard Worker         auto buffer = mBuffers[id.value];
6909*8975f5c5SAndroid Build Coastguard Worker         return buffer->getRange().start;
6910*8975f5c5SAndroid Build Coastguard Worker     }
6911*8975f5c5SAndroid Build Coastguard Worker 
6912*8975f5c5SAndroid Build Coastguard Worker     auto buffer = std::make_shared<CoherentBuffer>(start, size, mPageSize, mShadowMemoryEnabled);
6913*8975f5c5SAndroid Build Coastguard Worker     uintptr_t realOrShadowStart = buffer->getRange().start;
6914*8975f5c5SAndroid Build Coastguard Worker 
6915*8975f5c5SAndroid Build Coastguard Worker     mBuffers.insert(std::make_pair(id.value, std::move(buffer)));
6916*8975f5c5SAndroid Build Coastguard Worker 
6917*8975f5c5SAndroid Build Coastguard Worker     return realOrShadowStart;
6918*8975f5c5SAndroid Build Coastguard Worker }
6919*8975f5c5SAndroid Build Coastguard Worker 
maybeUpdateShadowMemory()6920*8975f5c5SAndroid Build Coastguard Worker void CoherentBufferTracker::maybeUpdateShadowMemory()
6921*8975f5c5SAndroid Build Coastguard Worker {
6922*8975f5c5SAndroid Build Coastguard Worker     for (const auto &pair : mBuffers)
6923*8975f5c5SAndroid Build Coastguard Worker     {
6924*8975f5c5SAndroid Build Coastguard Worker         std::shared_ptr<CoherentBuffer> cb = pair.second;
6925*8975f5c5SAndroid Build Coastguard Worker         if (cb->isShadowDirty())
6926*8975f5c5SAndroid Build Coastguard Worker         {
6927*8975f5c5SAndroid Build Coastguard Worker             cb->removeProtection(PageSharingType::NoneShared);
6928*8975f5c5SAndroid Build Coastguard Worker             cb->updateShadowMemory();
6929*8975f5c5SAndroid Build Coastguard Worker             cb->protectAll();
6930*8975f5c5SAndroid Build Coastguard Worker         }
6931*8975f5c5SAndroid Build Coastguard Worker     }
6932*8975f5c5SAndroid Build Coastguard Worker }
6933*8975f5c5SAndroid Build Coastguard Worker 
markAllShadowDirty()6934*8975f5c5SAndroid Build Coastguard Worker void CoherentBufferTracker::markAllShadowDirty()
6935*8975f5c5SAndroid Build Coastguard Worker {
6936*8975f5c5SAndroid Build Coastguard Worker     for (const auto &pair : mBuffers)
6937*8975f5c5SAndroid Build Coastguard Worker     {
6938*8975f5c5SAndroid Build Coastguard Worker         std::shared_ptr<CoherentBuffer> cb = pair.second;
6939*8975f5c5SAndroid Build Coastguard Worker         cb->markShadowDirty();
6940*8975f5c5SAndroid Build Coastguard Worker     }
6941*8975f5c5SAndroid Build Coastguard Worker }
6942*8975f5c5SAndroid Build Coastguard Worker 
doesBufferSharePage(gl::BufferID id)6943*8975f5c5SAndroid Build Coastguard Worker PageSharingType CoherentBufferTracker::doesBufferSharePage(gl::BufferID id)
6944*8975f5c5SAndroid Build Coastguard Worker {
6945*8975f5c5SAndroid Build Coastguard Worker     bool firstPageShared = false;
6946*8975f5c5SAndroid Build Coastguard Worker     bool lastPageShared  = false;
6947*8975f5c5SAndroid Build Coastguard Worker 
6948*8975f5c5SAndroid Build Coastguard Worker     std::shared_ptr<CoherentBuffer> buffer = mBuffers[id.value];
6949*8975f5c5SAndroid Build Coastguard Worker 
6950*8975f5c5SAndroid Build Coastguard Worker     AddressRange range = buffer->getRange();
6951*8975f5c5SAndroid Build Coastguard Worker 
6952*8975f5c5SAndroid Build Coastguard Worker     size_t firstPage = range.start / mPageSize;
6953*8975f5c5SAndroid Build Coastguard Worker     size_t lastPage  = range.end() / mPageSize;
6954*8975f5c5SAndroid Build Coastguard Worker 
6955*8975f5c5SAndroid Build Coastguard Worker     for (const auto &pair : mBuffers)
6956*8975f5c5SAndroid Build Coastguard Worker     {
6957*8975f5c5SAndroid Build Coastguard Worker         gl::BufferID otherId = {pair.first};
6958*8975f5c5SAndroid Build Coastguard Worker         if (otherId != id)
6959*8975f5c5SAndroid Build Coastguard Worker         {
6960*8975f5c5SAndroid Build Coastguard Worker             std::shared_ptr<CoherentBuffer> otherBuffer = pair.second;
6961*8975f5c5SAndroid Build Coastguard Worker             size_t relativePage;
6962*8975f5c5SAndroid Build Coastguard Worker             if (otherBuffer->contains(firstPage, &relativePage))
6963*8975f5c5SAndroid Build Coastguard Worker             {
6964*8975f5c5SAndroid Build Coastguard Worker                 firstPageShared = true;
6965*8975f5c5SAndroid Build Coastguard Worker             }
6966*8975f5c5SAndroid Build Coastguard Worker             else if (otherBuffer->contains(lastPage, &relativePage))
6967*8975f5c5SAndroid Build Coastguard Worker             {
6968*8975f5c5SAndroid Build Coastguard Worker                 lastPageShared = true;
6969*8975f5c5SAndroid Build Coastguard Worker             }
6970*8975f5c5SAndroid Build Coastguard Worker         }
6971*8975f5c5SAndroid Build Coastguard Worker     }
6972*8975f5c5SAndroid Build Coastguard Worker 
6973*8975f5c5SAndroid Build Coastguard Worker     if (firstPageShared && !lastPageShared)
6974*8975f5c5SAndroid Build Coastguard Worker     {
6975*8975f5c5SAndroid Build Coastguard Worker         return PageSharingType::FirstShared;
6976*8975f5c5SAndroid Build Coastguard Worker     }
6977*8975f5c5SAndroid Build Coastguard Worker     else if (!firstPageShared && lastPageShared)
6978*8975f5c5SAndroid Build Coastguard Worker     {
6979*8975f5c5SAndroid Build Coastguard Worker         return PageSharingType::LastShared;
6980*8975f5c5SAndroid Build Coastguard Worker     }
6981*8975f5c5SAndroid Build Coastguard Worker     else if (firstPageShared && lastPageShared)
6982*8975f5c5SAndroid Build Coastguard Worker     {
6983*8975f5c5SAndroid Build Coastguard Worker         return PageSharingType::FirstAndLastShared;
6984*8975f5c5SAndroid Build Coastguard Worker     }
6985*8975f5c5SAndroid Build Coastguard Worker     else
6986*8975f5c5SAndroid Build Coastguard Worker     {
6987*8975f5c5SAndroid Build Coastguard Worker         return PageSharingType::NoneShared;
6988*8975f5c5SAndroid Build Coastguard Worker     }
6989*8975f5c5SAndroid Build Coastguard Worker }
6990*8975f5c5SAndroid Build Coastguard Worker 
removeBuffer(gl::BufferID id)6991*8975f5c5SAndroid Build Coastguard Worker void CoherentBufferTracker::removeBuffer(gl::BufferID id)
6992*8975f5c5SAndroid Build Coastguard Worker {
6993*8975f5c5SAndroid Build Coastguard Worker     std::lock_guard<angle::SimpleMutex> lock(mMutex);
6994*8975f5c5SAndroid Build Coastguard Worker 
6995*8975f5c5SAndroid Build Coastguard Worker     if (!haveBuffer(id))
6996*8975f5c5SAndroid Build Coastguard Worker     {
6997*8975f5c5SAndroid Build Coastguard Worker         return;
6998*8975f5c5SAndroid Build Coastguard Worker     }
6999*8975f5c5SAndroid Build Coastguard Worker 
7000*8975f5c5SAndroid Build Coastguard Worker     // Synchronize graphics buffer memory before the buffer is removed from the tracker.
7001*8975f5c5SAndroid Build Coastguard Worker     if (mShadowMemoryEnabled)
7002*8975f5c5SAndroid Build Coastguard Worker     {
7003*8975f5c5SAndroid Build Coastguard Worker         mBuffers[id.value]->updateBufferMemory();
7004*8975f5c5SAndroid Build Coastguard Worker     }
7005*8975f5c5SAndroid Build Coastguard Worker 
7006*8975f5c5SAndroid Build Coastguard Worker     // If the buffer shares pages with other tracked buffers,
7007*8975f5c5SAndroid Build Coastguard Worker     // don't unprotect the overlapping pages.
7008*8975f5c5SAndroid Build Coastguard Worker     PageSharingType sharingType = doesBufferSharePage(id);
7009*8975f5c5SAndroid Build Coastguard Worker     mBuffers[id.value]->removeProtection(sharingType);
7010*8975f5c5SAndroid Build Coastguard Worker     mBuffers.erase(id.value);
7011*8975f5c5SAndroid Build Coastguard Worker }
7012*8975f5c5SAndroid Build Coastguard Worker 
maybeGetShadowMemoryPointer(gl::Buffer * buffer,GLsizeiptr length,GLbitfield access)7013*8975f5c5SAndroid Build Coastguard Worker void *FrameCaptureShared::maybeGetShadowMemoryPointer(gl::Buffer *buffer,
7014*8975f5c5SAndroid Build Coastguard Worker                                                       GLsizeiptr length,
7015*8975f5c5SAndroid Build Coastguard Worker                                                       GLbitfield access)
7016*8975f5c5SAndroid Build Coastguard Worker {
7017*8975f5c5SAndroid Build Coastguard Worker     if (!(access & GL_MAP_COHERENT_BIT_EXT) || !mCoherentBufferTracker.isShadowMemoryEnabled())
7018*8975f5c5SAndroid Build Coastguard Worker     {
7019*8975f5c5SAndroid Build Coastguard Worker         return buffer->getMapPointer();
7020*8975f5c5SAndroid Build Coastguard Worker     }
7021*8975f5c5SAndroid Build Coastguard Worker 
7022*8975f5c5SAndroid Build Coastguard Worker     mCoherentBufferTracker.enable();
7023*8975f5c5SAndroid Build Coastguard Worker     uintptr_t realMapPointer = reinterpret_cast<uintptr_t>(buffer->getMapPointer());
7024*8975f5c5SAndroid Build Coastguard Worker     return (void *)mCoherentBufferTracker.addBuffer(buffer->id(), realMapPointer, length);
7025*8975f5c5SAndroid Build Coastguard Worker }
7026*8975f5c5SAndroid Build Coastguard Worker 
determineMemoryProtectionSupport(gl::Context * context)7027*8975f5c5SAndroid Build Coastguard Worker void FrameCaptureShared::determineMemoryProtectionSupport(gl::Context *context)
7028*8975f5c5SAndroid Build Coastguard Worker {
7029*8975f5c5SAndroid Build Coastguard Worker     // Skip this test if shadow memory was force enabled or shadow memory requirement was detected
7030*8975f5c5SAndroid Build Coastguard Worker     // previously
7031*8975f5c5SAndroid Build Coastguard Worker     if (mCoherentBufferTracker.isShadowMemoryEnabled())
7032*8975f5c5SAndroid Build Coastguard Worker     {
7033*8975f5c5SAndroid Build Coastguard Worker         return;
7034*8975f5c5SAndroid Build Coastguard Worker     }
7035*8975f5c5SAndroid Build Coastguard Worker 
7036*8975f5c5SAndroid Build Coastguard Worker     // These known devices must use shadow memory
7037*8975f5c5SAndroid Build Coastguard Worker     HashMap<std::string, std::vector<std::string>> denyList = {
7038*8975f5c5SAndroid Build Coastguard Worker         {"Google", {"Pixel 6", "Pixel 6 Pro", "Pixel 6a", "Pixel 7", "Pixel 7 Pro"}},
7039*8975f5c5SAndroid Build Coastguard Worker     };
7040*8975f5c5SAndroid Build Coastguard Worker 
7041*8975f5c5SAndroid Build Coastguard Worker     angle::SystemInfo info;
7042*8975f5c5SAndroid Build Coastguard Worker     angle::GetSystemInfo(&info);
7043*8975f5c5SAndroid Build Coastguard Worker     bool isDeviceDenyListed = false;
7044*8975f5c5SAndroid Build Coastguard Worker 
7045*8975f5c5SAndroid Build Coastguard Worker     if (rx::GetAndroidSDKVersion() < 34)
7046*8975f5c5SAndroid Build Coastguard Worker     {
7047*8975f5c5SAndroid Build Coastguard Worker         // Before Android 14, there was a bug in Mali based Pixel preventing mprotect
7048*8975f5c5SAndroid Build Coastguard Worker         // on Vulkan surfaces. (https://b.corp.google.com/issues/269535398)
7049*8975f5c5SAndroid Build Coastguard Worker         // Check the denylist in this case.
7050*8975f5c5SAndroid Build Coastguard Worker         if (denyList.find(info.machineManufacturer) != denyList.end())
7051*8975f5c5SAndroid Build Coastguard Worker         {
7052*8975f5c5SAndroid Build Coastguard Worker             const std::vector<std::string> &models = denyList[info.machineManufacturer];
7053*8975f5c5SAndroid Build Coastguard Worker             isDeviceDenyListed =
7054*8975f5c5SAndroid Build Coastguard Worker                 std::find(models.begin(), models.end(), info.machineModelName) != models.end();
7055*8975f5c5SAndroid Build Coastguard Worker         }
7056*8975f5c5SAndroid Build Coastguard Worker     }
7057*8975f5c5SAndroid Build Coastguard Worker 
7058*8975f5c5SAndroid Build Coastguard Worker     if (isDeviceDenyListed)
7059*8975f5c5SAndroid Build Coastguard Worker     {
7060*8975f5c5SAndroid Build Coastguard Worker         WARN() << "Direct memory protection not possible on deny listed device '"
7061*8975f5c5SAndroid Build Coastguard Worker                << info.machineModelName
7062*8975f5c5SAndroid Build Coastguard Worker                << "', enabling shadow memory for coherent buffer tracking.";
7063*8975f5c5SAndroid Build Coastguard Worker         mCoherentBufferTracker.enableShadowMemory();
7064*8975f5c5SAndroid Build Coastguard Worker     }
7065*8975f5c5SAndroid Build Coastguard Worker     else
7066*8975f5c5SAndroid Build Coastguard Worker     {
7067*8975f5c5SAndroid Build Coastguard Worker         // Device is not on deny listed. Run a test if we actually can protect directly. Do this
7068*8975f5c5SAndroid Build Coastguard Worker         // only on assertion enabled builds.
7069*8975f5c5SAndroid Build Coastguard Worker         ASSERT(mCoherentBufferTracker.canProtectDirectly(context));
7070*8975f5c5SAndroid Build Coastguard Worker     }
7071*8975f5c5SAndroid Build Coastguard Worker }
7072*8975f5c5SAndroid Build Coastguard Worker 
trackBufferMapping(const gl::Context * context,CallCapture * call,gl::BufferID id,gl::Buffer * buffer,GLintptr offset,GLsizeiptr length,bool writable,bool coherent)7073*8975f5c5SAndroid Build Coastguard Worker void FrameCaptureShared::trackBufferMapping(const gl::Context *context,
7074*8975f5c5SAndroid Build Coastguard Worker                                             CallCapture *call,
7075*8975f5c5SAndroid Build Coastguard Worker                                             gl::BufferID id,
7076*8975f5c5SAndroid Build Coastguard Worker                                             gl::Buffer *buffer,
7077*8975f5c5SAndroid Build Coastguard Worker                                             GLintptr offset,
7078*8975f5c5SAndroid Build Coastguard Worker                                             GLsizeiptr length,
7079*8975f5c5SAndroid Build Coastguard Worker                                             bool writable,
7080*8975f5c5SAndroid Build Coastguard Worker                                             bool coherent)
7081*8975f5c5SAndroid Build Coastguard Worker {
7082*8975f5c5SAndroid Build Coastguard Worker     // Track that the buffer was mapped
7083*8975f5c5SAndroid Build Coastguard Worker     mResourceTracker.setBufferMapped(context->id(), id.value);
7084*8975f5c5SAndroid Build Coastguard Worker 
7085*8975f5c5SAndroid Build Coastguard Worker     if (writable)
7086*8975f5c5SAndroid Build Coastguard Worker     {
7087*8975f5c5SAndroid Build Coastguard Worker         // If this buffer was mapped writable, we don't have any visibility into what
7088*8975f5c5SAndroid Build Coastguard Worker         // happens to it. Therefore, remember the details about it, and we'll read it back
7089*8975f5c5SAndroid Build Coastguard Worker         // on Unmap to repopulate it during replay.
7090*8975f5c5SAndroid Build Coastguard Worker         mBufferDataMap[id] = std::make_pair(offset, length);
7091*8975f5c5SAndroid Build Coastguard Worker 
7092*8975f5c5SAndroid Build Coastguard Worker         // Track that this buffer was potentially modified
7093*8975f5c5SAndroid Build Coastguard Worker         mResourceTracker.getTrackedResource(context->id(), ResourceIDType::Buffer)
7094*8975f5c5SAndroid Build Coastguard Worker             .setModifiedResource(id.value);
7095*8975f5c5SAndroid Build Coastguard Worker 
7096*8975f5c5SAndroid Build Coastguard Worker         // Track coherent buffer
7097*8975f5c5SAndroid Build Coastguard Worker         // Check if capture is active to not initialize the coherent buffer tracker on the
7098*8975f5c5SAndroid Build Coastguard Worker         // first coherent glMapBufferRange call.
7099*8975f5c5SAndroid Build Coastguard Worker         if (coherent && isCaptureActive())
7100*8975f5c5SAndroid Build Coastguard Worker         {
7101*8975f5c5SAndroid Build Coastguard Worker             mCoherentBufferTracker.enable();
7102*8975f5c5SAndroid Build Coastguard Worker             // When not using shadow memory, adding buffers to the tracking happens here instead of
7103*8975f5c5SAndroid Build Coastguard Worker             // during mapping
7104*8975f5c5SAndroid Build Coastguard Worker             if (!mCoherentBufferTracker.isShadowMemoryEnabled())
7105*8975f5c5SAndroid Build Coastguard Worker             {
7106*8975f5c5SAndroid Build Coastguard Worker                 uintptr_t data = reinterpret_cast<uintptr_t>(buffer->getMapPointer());
7107*8975f5c5SAndroid Build Coastguard Worker                 mCoherentBufferTracker.addBuffer(id, data, length);
7108*8975f5c5SAndroid Build Coastguard Worker             }
7109*8975f5c5SAndroid Build Coastguard Worker         }
7110*8975f5c5SAndroid Build Coastguard Worker     }
7111*8975f5c5SAndroid Build Coastguard Worker }
7112*8975f5c5SAndroid Build Coastguard Worker 
trackTextureUpdate(const gl::Context * context,const CallCapture & call)7113*8975f5c5SAndroid Build Coastguard Worker void FrameCaptureShared::trackTextureUpdate(const gl::Context *context, const CallCapture &call)
7114*8975f5c5SAndroid Build Coastguard Worker {
7115*8975f5c5SAndroid Build Coastguard Worker     int index             = 0;
7116*8975f5c5SAndroid Build Coastguard Worker     std::string paramName = "targetPacked";
7117*8975f5c5SAndroid Build Coastguard Worker     ParamType paramType   = ParamType::TTextureTarget;
7118*8975f5c5SAndroid Build Coastguard Worker 
7119*8975f5c5SAndroid Build Coastguard Worker     // Some calls provide the textureID directly
7120*8975f5c5SAndroid Build Coastguard Worker     // For the rest, look it up based on the currently bound texture
7121*8975f5c5SAndroid Build Coastguard Worker     switch (call.entryPoint)
7122*8975f5c5SAndroid Build Coastguard Worker     {
7123*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLCompressedCopyTextureCHROMIUM:
7124*8975f5c5SAndroid Build Coastguard Worker             index     = 1;
7125*8975f5c5SAndroid Build Coastguard Worker             paramName = "destIdPacked";
7126*8975f5c5SAndroid Build Coastguard Worker             paramType = ParamType::TTextureID;
7127*8975f5c5SAndroid Build Coastguard Worker             break;
7128*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLCopyTextureCHROMIUM:
7129*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLCopySubTextureCHROMIUM:
7130*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLCopyTexture3DANGLE:
7131*8975f5c5SAndroid Build Coastguard Worker             index     = 3;
7132*8975f5c5SAndroid Build Coastguard Worker             paramName = "destIdPacked";
7133*8975f5c5SAndroid Build Coastguard Worker             paramType = ParamType::TTextureID;
7134*8975f5c5SAndroid Build Coastguard Worker             break;
7135*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLCopyImageSubData:
7136*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLCopyImageSubDataEXT:
7137*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLCopyImageSubDataOES:
7138*8975f5c5SAndroid Build Coastguard Worker             index     = 7;
7139*8975f5c5SAndroid Build Coastguard Worker             paramName = "dstTarget";
7140*8975f5c5SAndroid Build Coastguard Worker             paramType = ParamType::TGLenum;
7141*8975f5c5SAndroid Build Coastguard Worker             break;
7142*8975f5c5SAndroid Build Coastguard Worker         default:
7143*8975f5c5SAndroid Build Coastguard Worker             break;
7144*8975f5c5SAndroid Build Coastguard Worker     }
7145*8975f5c5SAndroid Build Coastguard Worker 
7146*8975f5c5SAndroid Build Coastguard Worker     GLuint id = 0;
7147*8975f5c5SAndroid Build Coastguard Worker     switch (paramType)
7148*8975f5c5SAndroid Build Coastguard Worker     {
7149*8975f5c5SAndroid Build Coastguard Worker         case ParamType::TTextureTarget:
7150*8975f5c5SAndroid Build Coastguard Worker         {
7151*8975f5c5SAndroid Build Coastguard Worker             gl::TextureTarget targetPacked =
7152*8975f5c5SAndroid Build Coastguard Worker                 call.params.getParam(paramName.c_str(), ParamType::TTextureTarget, index)
7153*8975f5c5SAndroid Build Coastguard Worker                     .value.TextureTargetVal;
7154*8975f5c5SAndroid Build Coastguard Worker             gl::TextureType textureType = gl::TextureTargetToType(targetPacked);
7155*8975f5c5SAndroid Build Coastguard Worker             gl::Texture *texture        = context->getState().getTargetTexture(textureType);
7156*8975f5c5SAndroid Build Coastguard Worker             id                          = texture->id().value;
7157*8975f5c5SAndroid Build Coastguard Worker             break;
7158*8975f5c5SAndroid Build Coastguard Worker         }
7159*8975f5c5SAndroid Build Coastguard Worker         case ParamType::TTextureID:
7160*8975f5c5SAndroid Build Coastguard Worker         {
7161*8975f5c5SAndroid Build Coastguard Worker             gl::TextureID destIDPacked =
7162*8975f5c5SAndroid Build Coastguard Worker                 call.params.getParam(paramName.c_str(), ParamType::TTextureID, index)
7163*8975f5c5SAndroid Build Coastguard Worker                     .value.TextureIDVal;
7164*8975f5c5SAndroid Build Coastguard Worker             id = destIDPacked.value;
7165*8975f5c5SAndroid Build Coastguard Worker             break;
7166*8975f5c5SAndroid Build Coastguard Worker         }
7167*8975f5c5SAndroid Build Coastguard Worker         case ParamType::TGLenum:
7168*8975f5c5SAndroid Build Coastguard Worker         {
7169*8975f5c5SAndroid Build Coastguard Worker             GLenum target =
7170*8975f5c5SAndroid Build Coastguard Worker                 call.params.getParam(paramName.c_str(), ParamType::TGLenum, index).value.GLenumVal;
7171*8975f5c5SAndroid Build Coastguard Worker 
7172*8975f5c5SAndroid Build Coastguard Worker             if (target == GL_TEXTURE_CUBE_MAP)
7173*8975f5c5SAndroid Build Coastguard Worker             {
7174*8975f5c5SAndroid Build Coastguard Worker                 // CopyImageSubData doesn't support cube faces, but PackedParams requires one
7175*8975f5c5SAndroid Build Coastguard Worker                 target = GL_TEXTURE_CUBE_MAP_POSITIVE_X;
7176*8975f5c5SAndroid Build Coastguard Worker             }
7177*8975f5c5SAndroid Build Coastguard Worker 
7178*8975f5c5SAndroid Build Coastguard Worker             gl::TextureTarget targetPacked = gl::PackParam<gl::TextureTarget>(target);
7179*8975f5c5SAndroid Build Coastguard Worker             gl::TextureType textureType    = gl::TextureTargetToType(targetPacked);
7180*8975f5c5SAndroid Build Coastguard Worker             gl::Texture *texture           = context->getState().getTargetTexture(textureType);
7181*8975f5c5SAndroid Build Coastguard Worker             id                             = texture->id().value;
7182*8975f5c5SAndroid Build Coastguard Worker             break;
7183*8975f5c5SAndroid Build Coastguard Worker         }
7184*8975f5c5SAndroid Build Coastguard Worker         default:
7185*8975f5c5SAndroid Build Coastguard Worker             ERR() << "Unhandled paramType= " << static_cast<int>(paramType);
7186*8975f5c5SAndroid Build Coastguard Worker             UNREACHABLE();
7187*8975f5c5SAndroid Build Coastguard Worker             break;
7188*8975f5c5SAndroid Build Coastguard Worker     }
7189*8975f5c5SAndroid Build Coastguard Worker 
7190*8975f5c5SAndroid Build Coastguard Worker     // Mark it as modified
7191*8975f5c5SAndroid Build Coastguard Worker     mResourceTracker.getTrackedResource(context->id(), ResourceIDType::Texture)
7192*8975f5c5SAndroid Build Coastguard Worker         .setModifiedResource(id);
7193*8975f5c5SAndroid Build Coastguard Worker }
7194*8975f5c5SAndroid Build Coastguard Worker 
7195*8975f5c5SAndroid Build Coastguard Worker // Identify and mark writeable shader image textures as modified
trackImageUpdate(const gl::Context * context,const CallCapture & call)7196*8975f5c5SAndroid Build Coastguard Worker void FrameCaptureShared::trackImageUpdate(const gl::Context *context, const CallCapture &call)
7197*8975f5c5SAndroid Build Coastguard Worker {
7198*8975f5c5SAndroid Build Coastguard Worker     const gl::ProgramExecutable *executable = context->getState().getProgramExecutable();
7199*8975f5c5SAndroid Build Coastguard Worker     for (const gl::ImageBinding &imageBinding : executable->getImageBindings())
7200*8975f5c5SAndroid Build Coastguard Worker     {
7201*8975f5c5SAndroid Build Coastguard Worker         for (GLuint binding : imageBinding.boundImageUnits)
7202*8975f5c5SAndroid Build Coastguard Worker         {
7203*8975f5c5SAndroid Build Coastguard Worker             const gl::ImageUnit &imageUnit = context->getState().getImageUnit(binding);
7204*8975f5c5SAndroid Build Coastguard Worker             if (imageUnit.access != GL_READ_ONLY)
7205*8975f5c5SAndroid Build Coastguard Worker             {
7206*8975f5c5SAndroid Build Coastguard Worker                 // Get image binding texture id and mark it as modified
7207*8975f5c5SAndroid Build Coastguard Worker                 GLuint id = imageUnit.texture.id().value;
7208*8975f5c5SAndroid Build Coastguard Worker                 mResourceTracker.getTrackedResource(context->id(), ResourceIDType::Texture)
7209*8975f5c5SAndroid Build Coastguard Worker                     .setModifiedResource(id);
7210*8975f5c5SAndroid Build Coastguard Worker             }
7211*8975f5c5SAndroid Build Coastguard Worker         }
7212*8975f5c5SAndroid Build Coastguard Worker     }
7213*8975f5c5SAndroid Build Coastguard Worker }
7214*8975f5c5SAndroid Build Coastguard Worker 
trackDefaultUniformUpdate(const gl::Context * context,const CallCapture & call)7215*8975f5c5SAndroid Build Coastguard Worker void FrameCaptureShared::trackDefaultUniformUpdate(const gl::Context *context,
7216*8975f5c5SAndroid Build Coastguard Worker                                                    const CallCapture &call)
7217*8975f5c5SAndroid Build Coastguard Worker {
7218*8975f5c5SAndroid Build Coastguard Worker     DefaultUniformType defaultUniformType = GetDefaultUniformType(call);
7219*8975f5c5SAndroid Build Coastguard Worker 
7220*8975f5c5SAndroid Build Coastguard Worker     GLuint programID = 0;
7221*8975f5c5SAndroid Build Coastguard Worker     int location     = 0;
7222*8975f5c5SAndroid Build Coastguard Worker 
7223*8975f5c5SAndroid Build Coastguard Worker     // We track default uniform updates by program and location, so look them up in parameters
7224*8975f5c5SAndroid Build Coastguard Worker     if (defaultUniformType == DefaultUniformType::CurrentProgram)
7225*8975f5c5SAndroid Build Coastguard Worker     {
7226*8975f5c5SAndroid Build Coastguard Worker         programID = context->getActiveLinkedProgram()->id().value;
7227*8975f5c5SAndroid Build Coastguard Worker 
7228*8975f5c5SAndroid Build Coastguard Worker         location = call.params.getParam("locationPacked", ParamType::TUniformLocation, 0)
7229*8975f5c5SAndroid Build Coastguard Worker                        .value.UniformLocationVal.value;
7230*8975f5c5SAndroid Build Coastguard Worker     }
7231*8975f5c5SAndroid Build Coastguard Worker     else
7232*8975f5c5SAndroid Build Coastguard Worker     {
7233*8975f5c5SAndroid Build Coastguard Worker         ASSERT(defaultUniformType == DefaultUniformType::SpecifiedProgram);
7234*8975f5c5SAndroid Build Coastguard Worker 
7235*8975f5c5SAndroid Build Coastguard Worker         programID = call.params.getParam("programPacked", ParamType::TShaderProgramID, 0)
7236*8975f5c5SAndroid Build Coastguard Worker                         .value.ShaderProgramIDVal.value;
7237*8975f5c5SAndroid Build Coastguard Worker 
7238*8975f5c5SAndroid Build Coastguard Worker         location = call.params.getParam("locationPacked", ParamType::TUniformLocation, 1)
7239*8975f5c5SAndroid Build Coastguard Worker                        .value.UniformLocationVal.value;
7240*8975f5c5SAndroid Build Coastguard Worker     }
7241*8975f5c5SAndroid Build Coastguard Worker 
7242*8975f5c5SAndroid Build Coastguard Worker     const TrackedResource &trackedShaderProgram =
7243*8975f5c5SAndroid Build Coastguard Worker         mResourceTracker.getTrackedResource(context->id(), ResourceIDType::ShaderProgram);
7244*8975f5c5SAndroid Build Coastguard Worker     const ResourceSet &startingPrograms = trackedShaderProgram.getStartingResources();
7245*8975f5c5SAndroid Build Coastguard Worker     const ResourceSet &programsToRegen  = trackedShaderProgram.getResourcesToRegen();
7246*8975f5c5SAndroid Build Coastguard Worker 
7247*8975f5c5SAndroid Build Coastguard Worker     // If this program was in our starting set, track its uniform updates. Unless it was deleted,
7248*8975f5c5SAndroid Build Coastguard Worker     // then its uniforms will all be regenned along wih with the program.
7249*8975f5c5SAndroid Build Coastguard Worker     if (startingPrograms.find(programID) != startingPrograms.end() &&
7250*8975f5c5SAndroid Build Coastguard Worker         programsToRegen.find(programID) == programsToRegen.end())
7251*8975f5c5SAndroid Build Coastguard Worker     {
7252*8975f5c5SAndroid Build Coastguard Worker         // Track that we need to set this default uniform value again
7253*8975f5c5SAndroid Build Coastguard Worker         mResourceTracker.setModifiedDefaultUniform({programID}, {location});
7254*8975f5c5SAndroid Build Coastguard Worker     }
7255*8975f5c5SAndroid Build Coastguard Worker }
7256*8975f5c5SAndroid Build Coastguard Worker 
trackVertexArrayUpdate(const gl::Context * context,const CallCapture & call)7257*8975f5c5SAndroid Build Coastguard Worker void FrameCaptureShared::trackVertexArrayUpdate(const gl::Context *context, const CallCapture &call)
7258*8975f5c5SAndroid Build Coastguard Worker {
7259*8975f5c5SAndroid Build Coastguard Worker     // Look up the currently bound vertex array
7260*8975f5c5SAndroid Build Coastguard Worker     gl::VertexArrayID id = context->getState().getVertexArray()->id();
7261*8975f5c5SAndroid Build Coastguard Worker 
7262*8975f5c5SAndroid Build Coastguard Worker     // Mark it as modified
7263*8975f5c5SAndroid Build Coastguard Worker     mResourceTracker.getTrackedResource(context->id(), ResourceIDType::VertexArray)
7264*8975f5c5SAndroid Build Coastguard Worker         .setModifiedResource(id.value);
7265*8975f5c5SAndroid Build Coastguard Worker }
7266*8975f5c5SAndroid Build Coastguard Worker 
updateCopyImageSubData(CallCapture & call)7267*8975f5c5SAndroid Build Coastguard Worker void FrameCaptureShared::updateCopyImageSubData(CallCapture &call)
7268*8975f5c5SAndroid Build Coastguard Worker {
7269*8975f5c5SAndroid Build Coastguard Worker     // This call modifies srcName and dstName to no longer be object IDs (GLuint), but actual
7270*8975f5c5SAndroid Build Coastguard Worker     // packed types that can remapped using gTextureMap and gRenderbufferMap
7271*8975f5c5SAndroid Build Coastguard Worker 
7272*8975f5c5SAndroid Build Coastguard Worker     GLint srcName    = call.params.getParam("srcName", ParamType::TGLuint, 0).value.GLuintVal;
7273*8975f5c5SAndroid Build Coastguard Worker     GLenum srcTarget = call.params.getParam("srcTarget", ParamType::TGLenum, 1).value.GLenumVal;
7274*8975f5c5SAndroid Build Coastguard Worker     switch (srcTarget)
7275*8975f5c5SAndroid Build Coastguard Worker     {
7276*8975f5c5SAndroid Build Coastguard Worker         case GL_RENDERBUFFER:
7277*8975f5c5SAndroid Build Coastguard Worker         {
7278*8975f5c5SAndroid Build Coastguard Worker             // Convert the GLuint to RenderbufferID
7279*8975f5c5SAndroid Build Coastguard Worker             gl::RenderbufferID srcRenderbufferID = {static_cast<GLuint>(srcName)};
7280*8975f5c5SAndroid Build Coastguard Worker             call.params.setValueParamAtIndex("srcName", ParamType::TRenderbufferID,
7281*8975f5c5SAndroid Build Coastguard Worker                                              srcRenderbufferID, 0);
7282*8975f5c5SAndroid Build Coastguard Worker             break;
7283*8975f5c5SAndroid Build Coastguard Worker         }
7284*8975f5c5SAndroid Build Coastguard Worker         case GL_TEXTURE_2D:
7285*8975f5c5SAndroid Build Coastguard Worker         case GL_TEXTURE_2D_ARRAY:
7286*8975f5c5SAndroid Build Coastguard Worker         case GL_TEXTURE_3D:
7287*8975f5c5SAndroid Build Coastguard Worker         case GL_TEXTURE_CUBE_MAP:
7288*8975f5c5SAndroid Build Coastguard Worker         case GL_TEXTURE_EXTERNAL_OES:
7289*8975f5c5SAndroid Build Coastguard Worker         {
7290*8975f5c5SAndroid Build Coastguard Worker             // Convert the GLuint to TextureID
7291*8975f5c5SAndroid Build Coastguard Worker             gl::TextureID srcTextureID = {static_cast<GLuint>(srcName)};
7292*8975f5c5SAndroid Build Coastguard Worker             call.params.setValueParamAtIndex("srcName", ParamType::TTextureID, srcTextureID, 0);
7293*8975f5c5SAndroid Build Coastguard Worker             break;
7294*8975f5c5SAndroid Build Coastguard Worker         }
7295*8975f5c5SAndroid Build Coastguard Worker         default:
7296*8975f5c5SAndroid Build Coastguard Worker             ERR() << "Unhandled srcTarget = " << srcTarget;
7297*8975f5c5SAndroid Build Coastguard Worker             UNREACHABLE();
7298*8975f5c5SAndroid Build Coastguard Worker             break;
7299*8975f5c5SAndroid Build Coastguard Worker     }
7300*8975f5c5SAndroid Build Coastguard Worker 
7301*8975f5c5SAndroid Build Coastguard Worker     // Change dstName to the appropriate type based on dstTarget
7302*8975f5c5SAndroid Build Coastguard Worker     GLint dstName    = call.params.getParam("dstName", ParamType::TGLuint, 6).value.GLuintVal;
7303*8975f5c5SAndroid Build Coastguard Worker     GLenum dstTarget = call.params.getParam("dstTarget", ParamType::TGLenum, 7).value.GLenumVal;
7304*8975f5c5SAndroid Build Coastguard Worker     switch (dstTarget)
7305*8975f5c5SAndroid Build Coastguard Worker     {
7306*8975f5c5SAndroid Build Coastguard Worker         case GL_RENDERBUFFER:
7307*8975f5c5SAndroid Build Coastguard Worker         {
7308*8975f5c5SAndroid Build Coastguard Worker             // Convert the GLuint to RenderbufferID
7309*8975f5c5SAndroid Build Coastguard Worker             gl::RenderbufferID dstRenderbufferID = {static_cast<GLuint>(dstName)};
7310*8975f5c5SAndroid Build Coastguard Worker             call.params.setValueParamAtIndex("dstName", ParamType::TRenderbufferID,
7311*8975f5c5SAndroid Build Coastguard Worker                                              dstRenderbufferID, 6);
7312*8975f5c5SAndroid Build Coastguard Worker             break;
7313*8975f5c5SAndroid Build Coastguard Worker         }
7314*8975f5c5SAndroid Build Coastguard Worker         case GL_TEXTURE_2D:
7315*8975f5c5SAndroid Build Coastguard Worker         case GL_TEXTURE_2D_ARRAY:
7316*8975f5c5SAndroid Build Coastguard Worker         case GL_TEXTURE_3D:
7317*8975f5c5SAndroid Build Coastguard Worker         case GL_TEXTURE_CUBE_MAP:
7318*8975f5c5SAndroid Build Coastguard Worker         case GL_TEXTURE_EXTERNAL_OES:
7319*8975f5c5SAndroid Build Coastguard Worker         {
7320*8975f5c5SAndroid Build Coastguard Worker             // Convert the GLuint to TextureID
7321*8975f5c5SAndroid Build Coastguard Worker             gl::TextureID dstTextureID = {static_cast<GLuint>(dstName)};
7322*8975f5c5SAndroid Build Coastguard Worker             call.params.setValueParamAtIndex("dstName", ParamType::TTextureID, dstTextureID, 6);
7323*8975f5c5SAndroid Build Coastguard Worker             break;
7324*8975f5c5SAndroid Build Coastguard Worker         }
7325*8975f5c5SAndroid Build Coastguard Worker         default:
7326*8975f5c5SAndroid Build Coastguard Worker             ERR() << "Unhandled dstTarget = " << dstTarget;
7327*8975f5c5SAndroid Build Coastguard Worker             UNREACHABLE();
7328*8975f5c5SAndroid Build Coastguard Worker             break;
7329*8975f5c5SAndroid Build Coastguard Worker     }
7330*8975f5c5SAndroid Build Coastguard Worker }
7331*8975f5c5SAndroid Build Coastguard Worker 
overrideProgramBinary(const gl::Context * context,CallCapture & inCall,std::vector<CallCapture> & outCalls)7332*8975f5c5SAndroid Build Coastguard Worker void FrameCaptureShared::overrideProgramBinary(const gl::Context *context,
7333*8975f5c5SAndroid Build Coastguard Worker                                                CallCapture &inCall,
7334*8975f5c5SAndroid Build Coastguard Worker                                                std::vector<CallCapture> &outCalls)
7335*8975f5c5SAndroid Build Coastguard Worker {
7336*8975f5c5SAndroid Build Coastguard Worker     // Program binaries are inherently non-portable, even between two ANGLE builds.
7337*8975f5c5SAndroid Build Coastguard Worker     // If an application is using glProgramBinary in the middle of a trace, we need to replace
7338*8975f5c5SAndroid Build Coastguard Worker     // those calls with an equivalent sequence of portable calls.
7339*8975f5c5SAndroid Build Coastguard Worker     //
7340*8975f5c5SAndroid Build Coastguard Worker     // For example, here is a sequence an app could use for glProgramBinary:
7341*8975f5c5SAndroid Build Coastguard Worker     //
7342*8975f5c5SAndroid Build Coastguard Worker     //   gShaderProgramMap[42] = glCreateProgram();
7343*8975f5c5SAndroid Build Coastguard Worker     //   glProgramBinary(gShaderProgramMap[42], GL_PROGRAM_BINARY_ANGLE, gBinaryData[x], 1000);
7344*8975f5c5SAndroid Build Coastguard Worker     //   glGetProgramiv(gShaderProgramMap[42], GL_LINK_STATUS, gReadBuffer);
7345*8975f5c5SAndroid Build Coastguard Worker     //   glGetProgramiv(gShaderProgramMap[42], GL_PROGRAM_BINARY_LENGTH, gReadBuffer);
7346*8975f5c5SAndroid Build Coastguard Worker     //
7347*8975f5c5SAndroid Build Coastguard Worker     // With this override, the glProgramBinary call will be replaced like so:
7348*8975f5c5SAndroid Build Coastguard Worker     //
7349*8975f5c5SAndroid Build Coastguard Worker     //   gShaderProgramMap[42] = glCreateProgram();
7350*8975f5c5SAndroid Build Coastguard Worker     //   === Begin override ===
7351*8975f5c5SAndroid Build Coastguard Worker     //   gShaderProgramMap[43] = glCreateShader(GL_VERTEX_SHADER);
7352*8975f5c5SAndroid Build Coastguard Worker     //   glShaderSource(gShaderProgramMap[43], 1, string_0, &gBinaryData[100]);
7353*8975f5c5SAndroid Build Coastguard Worker     //   glCompileShader(gShaderProgramMap[43]);
7354*8975f5c5SAndroid Build Coastguard Worker     //   glAttachShader(gShaderProgramMap[42], gShaderProgramMap[43]);
7355*8975f5c5SAndroid Build Coastguard Worker     //   glDeleteShader(gShaderProgramMap[43]);
7356*8975f5c5SAndroid Build Coastguard Worker     //   gShaderProgramMap[43] = glCreateShader(GL_FRAGMENT_SHADER);
7357*8975f5c5SAndroid Build Coastguard Worker     //   glShaderSource(gShaderProgramMap[43], 1, string_1, &gBinaryData[200]);
7358*8975f5c5SAndroid Build Coastguard Worker     //   glCompileShader(gShaderProgramMap[43]);
7359*8975f5c5SAndroid Build Coastguard Worker     //   glAttachShader(gShaderProgramMap[42], gShaderProgramMap[43]);
7360*8975f5c5SAndroid Build Coastguard Worker     //   glDeleteShader(gShaderProgramMap[43]);
7361*8975f5c5SAndroid Build Coastguard Worker     //   glBindAttribLocation(gShaderProgramMap[42], 0, "attrib1");
7362*8975f5c5SAndroid Build Coastguard Worker     //   glBindAttribLocation(gShaderProgramMap[42], 1, "attrib2");
7363*8975f5c5SAndroid Build Coastguard Worker     //   glLinkProgram(gShaderProgramMap[42]);
7364*8975f5c5SAndroid Build Coastguard Worker     //   UpdateUniformLocation(gShaderProgramMap[42], "foo", 0, 20);
7365*8975f5c5SAndroid Build Coastguard Worker     //   UpdateUniformLocation(gShaderProgramMap[42], "bar", 72, 1);
7366*8975f5c5SAndroid Build Coastguard Worker     //   glUseProgram(gShaderProgramMap[42]);
7367*8975f5c5SAndroid Build Coastguard Worker     //   UpdateCurrentProgram(gShaderProgramMap[42]);
7368*8975f5c5SAndroid Build Coastguard Worker     //   glUniform4fv(gUniformLocations[gCurrentProgram][0], 20, &gBinaryData[300]);
7369*8975f5c5SAndroid Build Coastguard Worker     //   glUniform1iv(gUniformLocations[gCurrentProgram][72], 1, &gBinaryData[400]);
7370*8975f5c5SAndroid Build Coastguard Worker     //   === End override ===
7371*8975f5c5SAndroid Build Coastguard Worker     //   glGetProgramiv(gShaderProgramMap[42], GL_LINK_STATUS, gReadBuffer);
7372*8975f5c5SAndroid Build Coastguard Worker     //   glGetProgramiv(gShaderProgramMap[42], GL_PROGRAM_BINARY_LENGTH, gReadBuffer);
7373*8975f5c5SAndroid Build Coastguard Worker     //
7374*8975f5c5SAndroid Build Coastguard Worker     // To facilitate this override, we are serializing each shader stage source into the binary
7375*8975f5c5SAndroid Build Coastguard Worker     // itself.  See Program::serialize and Program::deserialize.  Once extracted from the binary,
7376*8975f5c5SAndroid Build Coastguard Worker     // they will be available via getProgramSources.
7377*8975f5c5SAndroid Build Coastguard Worker 
7378*8975f5c5SAndroid Build Coastguard Worker     gl::ShaderProgramID id = inCall.params.getParam("programPacked", ParamType::TShaderProgramID, 0)
7379*8975f5c5SAndroid Build Coastguard Worker                                  .value.ShaderProgramIDVal;
7380*8975f5c5SAndroid Build Coastguard Worker 
7381*8975f5c5SAndroid Build Coastguard Worker     gl::Program *program = context->getProgramResolveLink(id);
7382*8975f5c5SAndroid Build Coastguard Worker     ASSERT(program);
7383*8975f5c5SAndroid Build Coastguard Worker 
7384*8975f5c5SAndroid Build Coastguard Worker     mResourceTracker.onShaderProgramAccess(id);
7385*8975f5c5SAndroid Build Coastguard Worker     gl::ShaderProgramID tempShaderStartID = {mResourceTracker.getMaxShaderPrograms()};
7386*8975f5c5SAndroid Build Coastguard Worker     GenerateLinkedProgram(context, context->getState(), &mResourceTracker, &outCalls, program, id,
7387*8975f5c5SAndroid Build Coastguard Worker                           tempShaderStartID, getProgramSources(id));
7388*8975f5c5SAndroid Build Coastguard Worker }
7389*8975f5c5SAndroid Build Coastguard Worker 
captureCustomMapBufferFromContext(const gl::Context * context,const char * entryPointName,CallCapture & call,std::vector<CallCapture> & callsOut)7390*8975f5c5SAndroid Build Coastguard Worker void FrameCaptureShared::captureCustomMapBufferFromContext(const gl::Context *context,
7391*8975f5c5SAndroid Build Coastguard Worker                                                            const char *entryPointName,
7392*8975f5c5SAndroid Build Coastguard Worker                                                            CallCapture &call,
7393*8975f5c5SAndroid Build Coastguard Worker                                                            std::vector<CallCapture> &callsOut)
7394*8975f5c5SAndroid Build Coastguard Worker {
7395*8975f5c5SAndroid Build Coastguard Worker     gl::BufferBinding binding =
7396*8975f5c5SAndroid Build Coastguard Worker         call.params.getParam("targetPacked", ParamType::TBufferBinding, 0).value.BufferBindingVal;
7397*8975f5c5SAndroid Build Coastguard Worker     gl::Buffer *buffer = context->getState().getTargetBuffer(binding);
7398*8975f5c5SAndroid Build Coastguard Worker 
7399*8975f5c5SAndroid Build Coastguard Worker     if (call.entryPoint == EntryPoint::GLMapBufferRange ||
7400*8975f5c5SAndroid Build Coastguard Worker         call.entryPoint == EntryPoint::GLMapBufferRangeEXT)
7401*8975f5c5SAndroid Build Coastguard Worker     {
7402*8975f5c5SAndroid Build Coastguard Worker         GLintptr offset = call.params.getParam("offset", ParamType::TGLintptr, 1).value.GLintptrVal;
7403*8975f5c5SAndroid Build Coastguard Worker         GLsizeiptr length =
7404*8975f5c5SAndroid Build Coastguard Worker             call.params.getParam("length", ParamType::TGLsizeiptr, 2).value.GLsizeiptrVal;
7405*8975f5c5SAndroid Build Coastguard Worker         GLbitfield access =
7406*8975f5c5SAndroid Build Coastguard Worker             call.params.getParam("access", ParamType::TGLbitfield, 3).value.GLbitfieldVal;
7407*8975f5c5SAndroid Build Coastguard Worker 
7408*8975f5c5SAndroid Build Coastguard Worker         trackBufferMapping(context, &call, buffer->id(), buffer, offset, length,
7409*8975f5c5SAndroid Build Coastguard Worker                            access & GL_MAP_WRITE_BIT, access & GL_MAP_COHERENT_BIT_EXT);
7410*8975f5c5SAndroid Build Coastguard Worker     }
7411*8975f5c5SAndroid Build Coastguard Worker     else
7412*8975f5c5SAndroid Build Coastguard Worker     {
7413*8975f5c5SAndroid Build Coastguard Worker         ASSERT(call.entryPoint == EntryPoint::GLMapBufferOES);
7414*8975f5c5SAndroid Build Coastguard Worker         GLenum access = call.params.getParam("access", ParamType::TGLenum, 1).value.GLenumVal;
7415*8975f5c5SAndroid Build Coastguard Worker         bool writeAccess =
7416*8975f5c5SAndroid Build Coastguard Worker             (access == GL_WRITE_ONLY_OES || access == GL_WRITE_ONLY || access == GL_READ_WRITE);
7417*8975f5c5SAndroid Build Coastguard Worker         trackBufferMapping(context, &call, buffer->id(), buffer, 0,
7418*8975f5c5SAndroid Build Coastguard Worker                            static_cast<GLsizeiptr>(buffer->getSize()), writeAccess, false);
7419*8975f5c5SAndroid Build Coastguard Worker     }
7420*8975f5c5SAndroid Build Coastguard Worker 
7421*8975f5c5SAndroid Build Coastguard Worker     CaptureCustomMapBuffer(entryPointName, call, callsOut, buffer->id());
7422*8975f5c5SAndroid Build Coastguard Worker }
7423*8975f5c5SAndroid Build Coastguard Worker 
maybeOverrideEntryPoint(const gl::Context * context,CallCapture & inCall,std::vector<CallCapture> & outCalls)7424*8975f5c5SAndroid Build Coastguard Worker void FrameCaptureShared::maybeOverrideEntryPoint(const gl::Context *context,
7425*8975f5c5SAndroid Build Coastguard Worker                                                  CallCapture &inCall,
7426*8975f5c5SAndroid Build Coastguard Worker                                                  std::vector<CallCapture> &outCalls)
7427*8975f5c5SAndroid Build Coastguard Worker {
7428*8975f5c5SAndroid Build Coastguard Worker     switch (inCall.entryPoint)
7429*8975f5c5SAndroid Build Coastguard Worker     {
7430*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLCopyImageSubData:
7431*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLCopyImageSubDataEXT:
7432*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLCopyImageSubDataOES:
7433*8975f5c5SAndroid Build Coastguard Worker         {
7434*8975f5c5SAndroid Build Coastguard Worker             // We must look at the src and dst target types to determine which remap table to use
7435*8975f5c5SAndroid Build Coastguard Worker             updateCopyImageSubData(inCall);
7436*8975f5c5SAndroid Build Coastguard Worker             outCalls.emplace_back(std::move(inCall));
7437*8975f5c5SAndroid Build Coastguard Worker             break;
7438*8975f5c5SAndroid Build Coastguard Worker         }
7439*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLProgramBinary:
7440*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLProgramBinaryOES:
7441*8975f5c5SAndroid Build Coastguard Worker         {
7442*8975f5c5SAndroid Build Coastguard Worker             // Binary formats are not portable at all, so replace the calls with full linking
7443*8975f5c5SAndroid Build Coastguard Worker             // sequence
7444*8975f5c5SAndroid Build Coastguard Worker             overrideProgramBinary(context, inCall, outCalls);
7445*8975f5c5SAndroid Build Coastguard Worker             break;
7446*8975f5c5SAndroid Build Coastguard Worker         }
7447*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLUniformBlockBinding:
7448*8975f5c5SAndroid Build Coastguard Worker         {
7449*8975f5c5SAndroid Build Coastguard Worker             CaptureCustomUniformBlockBinding(inCall, outCalls);
7450*8975f5c5SAndroid Build Coastguard Worker             break;
7451*8975f5c5SAndroid Build Coastguard Worker         }
7452*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLMapBufferRange:
7453*8975f5c5SAndroid Build Coastguard Worker         {
7454*8975f5c5SAndroid Build Coastguard Worker             captureCustomMapBufferFromContext(context, "MapBufferRange", inCall, outCalls);
7455*8975f5c5SAndroid Build Coastguard Worker             break;
7456*8975f5c5SAndroid Build Coastguard Worker         }
7457*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLMapBufferRangeEXT:
7458*8975f5c5SAndroid Build Coastguard Worker         {
7459*8975f5c5SAndroid Build Coastguard Worker             captureCustomMapBufferFromContext(context, "MapBufferRangeEXT", inCall, outCalls);
7460*8975f5c5SAndroid Build Coastguard Worker             break;
7461*8975f5c5SAndroid Build Coastguard Worker         }
7462*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLMapBufferOES:
7463*8975f5c5SAndroid Build Coastguard Worker         {
7464*8975f5c5SAndroid Build Coastguard Worker             captureCustomMapBufferFromContext(context, "MapBufferOES", inCall, outCalls);
7465*8975f5c5SAndroid Build Coastguard Worker             break;
7466*8975f5c5SAndroid Build Coastguard Worker         }
7467*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLCreateShader:
7468*8975f5c5SAndroid Build Coastguard Worker         {
7469*8975f5c5SAndroid Build Coastguard Worker             CaptureCustomShaderProgram("CreateShader", inCall, outCalls);
7470*8975f5c5SAndroid Build Coastguard Worker             break;
7471*8975f5c5SAndroid Build Coastguard Worker         }
7472*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLCreateProgram:
7473*8975f5c5SAndroid Build Coastguard Worker         {
7474*8975f5c5SAndroid Build Coastguard Worker             CaptureCustomShaderProgram("CreateProgram", inCall, outCalls);
7475*8975f5c5SAndroid Build Coastguard Worker             break;
7476*8975f5c5SAndroid Build Coastguard Worker         }
7477*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLCreateShaderProgramv:
7478*8975f5c5SAndroid Build Coastguard Worker         {
7479*8975f5c5SAndroid Build Coastguard Worker             CaptureCustomShaderProgram("CreateShaderProgramv", inCall, outCalls);
7480*8975f5c5SAndroid Build Coastguard Worker             break;
7481*8975f5c5SAndroid Build Coastguard Worker         }
7482*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLFenceSync:
7483*8975f5c5SAndroid Build Coastguard Worker         {
7484*8975f5c5SAndroid Build Coastguard Worker             CaptureCustomFenceSync(inCall, outCalls);
7485*8975f5c5SAndroid Build Coastguard Worker             break;
7486*8975f5c5SAndroid Build Coastguard Worker         }
7487*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::EGLCreateImage:
7488*8975f5c5SAndroid Build Coastguard Worker         {
7489*8975f5c5SAndroid Build Coastguard Worker             const egl::Image *eglImage = GetImageFromParam(context, inCall.params.getReturnValue());
7490*8975f5c5SAndroid Build Coastguard Worker             CaptureCustomCreateEGLImage(context, "CreateEGLImage", eglImage->getWidth(),
7491*8975f5c5SAndroid Build Coastguard Worker                                         eglImage->getHeight(), inCall, outCalls);
7492*8975f5c5SAndroid Build Coastguard Worker             break;
7493*8975f5c5SAndroid Build Coastguard Worker         }
7494*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::EGLCreateImageKHR:
7495*8975f5c5SAndroid Build Coastguard Worker         {
7496*8975f5c5SAndroid Build Coastguard Worker             const egl::Image *eglImage = GetImageFromParam(context, inCall.params.getReturnValue());
7497*8975f5c5SAndroid Build Coastguard Worker             CaptureCustomCreateEGLImage(context, "CreateEGLImageKHR", eglImage->getWidth(),
7498*8975f5c5SAndroid Build Coastguard Worker                                         eglImage->getHeight(), inCall, outCalls);
7499*8975f5c5SAndroid Build Coastguard Worker             break;
7500*8975f5c5SAndroid Build Coastguard Worker         }
7501*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::EGLDestroyImage:
7502*8975f5c5SAndroid Build Coastguard Worker         {
7503*8975f5c5SAndroid Build Coastguard Worker             CaptureCustomDestroyEGLImage("DestroyEGLImage", inCall, outCalls);
7504*8975f5c5SAndroid Build Coastguard Worker             break;
7505*8975f5c5SAndroid Build Coastguard Worker         }
7506*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::EGLDestroyImageKHR:
7507*8975f5c5SAndroid Build Coastguard Worker         {
7508*8975f5c5SAndroid Build Coastguard Worker             CaptureCustomDestroyEGLImage("DestroyEGLImageKHR", inCall, outCalls);
7509*8975f5c5SAndroid Build Coastguard Worker             break;
7510*8975f5c5SAndroid Build Coastguard Worker         }
7511*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::EGLCreateSync:
7512*8975f5c5SAndroid Build Coastguard Worker         {
7513*8975f5c5SAndroid Build Coastguard Worker             CaptureCustomCreateEGLSync("CreateEGLSync", inCall, outCalls);
7514*8975f5c5SAndroid Build Coastguard Worker             break;
7515*8975f5c5SAndroid Build Coastguard Worker         }
7516*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::EGLCreateSyncKHR:
7517*8975f5c5SAndroid Build Coastguard Worker         {
7518*8975f5c5SAndroid Build Coastguard Worker             CaptureCustomCreateEGLSync("CreateEGLSyncKHR", inCall, outCalls);
7519*8975f5c5SAndroid Build Coastguard Worker             break;
7520*8975f5c5SAndroid Build Coastguard Worker         }
7521*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::EGLCreatePbufferSurface:
7522*8975f5c5SAndroid Build Coastguard Worker         {
7523*8975f5c5SAndroid Build Coastguard Worker             CaptureCustomCreatePbufferSurface(inCall, outCalls);
7524*8975f5c5SAndroid Build Coastguard Worker             break;
7525*8975f5c5SAndroid Build Coastguard Worker         }
7526*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::EGLCreateNativeClientBufferANDROID:
7527*8975f5c5SAndroid Build Coastguard Worker         {
7528*8975f5c5SAndroid Build Coastguard Worker             CaptureCustomCreateNativeClientbuffer(inCall, outCalls);
7529*8975f5c5SAndroid Build Coastguard Worker             break;
7530*8975f5c5SAndroid Build Coastguard Worker         }
7531*8975f5c5SAndroid Build Coastguard Worker 
7532*8975f5c5SAndroid Build Coastguard Worker         default:
7533*8975f5c5SAndroid Build Coastguard Worker         {
7534*8975f5c5SAndroid Build Coastguard Worker             // Pass the single call through
7535*8975f5c5SAndroid Build Coastguard Worker             outCalls.emplace_back(std::move(inCall));
7536*8975f5c5SAndroid Build Coastguard Worker             break;
7537*8975f5c5SAndroid Build Coastguard Worker         }
7538*8975f5c5SAndroid Build Coastguard Worker     }
7539*8975f5c5SAndroid Build Coastguard Worker }
7540*8975f5c5SAndroid Build Coastguard Worker 
maybeCaptureCoherentBuffers(const gl::Context * context)7541*8975f5c5SAndroid Build Coastguard Worker void FrameCaptureShared::maybeCaptureCoherentBuffers(const gl::Context *context)
7542*8975f5c5SAndroid Build Coastguard Worker {
7543*8975f5c5SAndroid Build Coastguard Worker     if (!isCaptureActive())
7544*8975f5c5SAndroid Build Coastguard Worker     {
7545*8975f5c5SAndroid Build Coastguard Worker         return;
7546*8975f5c5SAndroid Build Coastguard Worker     }
7547*8975f5c5SAndroid Build Coastguard Worker 
7548*8975f5c5SAndroid Build Coastguard Worker     std::lock_guard<angle::SimpleMutex> lock(mCoherentBufferTracker.mMutex);
7549*8975f5c5SAndroid Build Coastguard Worker 
7550*8975f5c5SAndroid Build Coastguard Worker     for (const auto &pair : mCoherentBufferTracker.mBuffers)
7551*8975f5c5SAndroid Build Coastguard Worker     {
7552*8975f5c5SAndroid Build Coastguard Worker         gl::BufferID id = {pair.first};
7553*8975f5c5SAndroid Build Coastguard Worker         if (mCoherentBufferTracker.isDirty(id))
7554*8975f5c5SAndroid Build Coastguard Worker         {
7555*8975f5c5SAndroid Build Coastguard Worker             captureCoherentBufferSnapshot(context, id);
7556*8975f5c5SAndroid Build Coastguard Worker         }
7557*8975f5c5SAndroid Build Coastguard Worker     }
7558*8975f5c5SAndroid Build Coastguard Worker }
7559*8975f5c5SAndroid Build Coastguard Worker 
maybeCaptureDrawArraysClientData(const gl::Context * context,CallCapture & call,size_t instanceCount)7560*8975f5c5SAndroid Build Coastguard Worker void FrameCaptureShared::maybeCaptureDrawArraysClientData(const gl::Context *context,
7561*8975f5c5SAndroid Build Coastguard Worker                                                           CallCapture &call,
7562*8975f5c5SAndroid Build Coastguard Worker                                                           size_t instanceCount)
7563*8975f5c5SAndroid Build Coastguard Worker {
7564*8975f5c5SAndroid Build Coastguard Worker     if (!context->getStateCache().hasAnyActiveClientAttrib())
7565*8975f5c5SAndroid Build Coastguard Worker     {
7566*8975f5c5SAndroid Build Coastguard Worker         return;
7567*8975f5c5SAndroid Build Coastguard Worker     }
7568*8975f5c5SAndroid Build Coastguard Worker 
7569*8975f5c5SAndroid Build Coastguard Worker     // Get counts from paramBuffer.
7570*8975f5c5SAndroid Build Coastguard Worker     GLint firstVertex =
7571*8975f5c5SAndroid Build Coastguard Worker         call.params.getParamFlexName("first", "start", ParamType::TGLint, 1).value.GLintVal;
7572*8975f5c5SAndroid Build Coastguard Worker     GLsizei drawCount = call.params.getParam("count", ParamType::TGLsizei, 2).value.GLsizeiVal;
7573*8975f5c5SAndroid Build Coastguard Worker     captureClientArraySnapshot(context, firstVertex + drawCount, instanceCount);
7574*8975f5c5SAndroid Build Coastguard Worker }
7575*8975f5c5SAndroid Build Coastguard Worker 
maybeCaptureDrawElementsClientData(const gl::Context * context,CallCapture & call,size_t instanceCount)7576*8975f5c5SAndroid Build Coastguard Worker void FrameCaptureShared::maybeCaptureDrawElementsClientData(const gl::Context *context,
7577*8975f5c5SAndroid Build Coastguard Worker                                                             CallCapture &call,
7578*8975f5c5SAndroid Build Coastguard Worker                                                             size_t instanceCount)
7579*8975f5c5SAndroid Build Coastguard Worker {
7580*8975f5c5SAndroid Build Coastguard Worker     if (!context->getStateCache().hasAnyActiveClientAttrib())
7581*8975f5c5SAndroid Build Coastguard Worker     {
7582*8975f5c5SAndroid Build Coastguard Worker         return;
7583*8975f5c5SAndroid Build Coastguard Worker     }
7584*8975f5c5SAndroid Build Coastguard Worker 
7585*8975f5c5SAndroid Build Coastguard Worker     // if the count is zero then the index evaluation is not valid and we wouldn't be drawing
7586*8975f5c5SAndroid Build Coastguard Worker     // anything anyway, so skip capturing
7587*8975f5c5SAndroid Build Coastguard Worker     GLsizei count = call.params.getParam("count", ParamType::TGLsizei, 1).value.GLsizeiVal;
7588*8975f5c5SAndroid Build Coastguard Worker     if (count == 0)
7589*8975f5c5SAndroid Build Coastguard Worker     {
7590*8975f5c5SAndroid Build Coastguard Worker         return;
7591*8975f5c5SAndroid Build Coastguard Worker     }
7592*8975f5c5SAndroid Build Coastguard Worker 
7593*8975f5c5SAndroid Build Coastguard Worker     gl::DrawElementsType drawElementsType =
7594*8975f5c5SAndroid Build Coastguard Worker         call.params.getParam("typePacked", ParamType::TDrawElementsType, 2)
7595*8975f5c5SAndroid Build Coastguard Worker             .value.DrawElementsTypeVal;
7596*8975f5c5SAndroid Build Coastguard Worker     const void *indices =
7597*8975f5c5SAndroid Build Coastguard Worker         call.params.getParam("indices", ParamType::TvoidConstPointer, 3).value.voidConstPointerVal;
7598*8975f5c5SAndroid Build Coastguard Worker 
7599*8975f5c5SAndroid Build Coastguard Worker     gl::IndexRange indexRange;
7600*8975f5c5SAndroid Build Coastguard Worker 
7601*8975f5c5SAndroid Build Coastguard Worker     bool restart = context->getState().isPrimitiveRestartEnabled();
7602*8975f5c5SAndroid Build Coastguard Worker 
7603*8975f5c5SAndroid Build Coastguard Worker     gl::Buffer *elementArrayBuffer = context->getState().getVertexArray()->getElementArrayBuffer();
7604*8975f5c5SAndroid Build Coastguard Worker     if (elementArrayBuffer)
7605*8975f5c5SAndroid Build Coastguard Worker     {
7606*8975f5c5SAndroid Build Coastguard Worker         size_t offset = reinterpret_cast<size_t>(indices);
7607*8975f5c5SAndroid Build Coastguard Worker         (void)elementArrayBuffer->getIndexRange(context, drawElementsType, offset, count, restart,
7608*8975f5c5SAndroid Build Coastguard Worker                                                 &indexRange);
7609*8975f5c5SAndroid Build Coastguard Worker     }
7610*8975f5c5SAndroid Build Coastguard Worker     else
7611*8975f5c5SAndroid Build Coastguard Worker     {
7612*8975f5c5SAndroid Build Coastguard Worker         ASSERT(indices);
7613*8975f5c5SAndroid Build Coastguard Worker         indexRange = gl::ComputeIndexRange(drawElementsType, indices, count, restart);
7614*8975f5c5SAndroid Build Coastguard Worker     }
7615*8975f5c5SAndroid Build Coastguard Worker 
7616*8975f5c5SAndroid Build Coastguard Worker     // index starts from 0
7617*8975f5c5SAndroid Build Coastguard Worker     captureClientArraySnapshot(context, indexRange.end + 1, instanceCount);
7618*8975f5c5SAndroid Build Coastguard Worker }
7619*8975f5c5SAndroid Build Coastguard Worker 
7620*8975f5c5SAndroid Build Coastguard Worker template <typename AttribT, typename FactoryT>
CreateEGLImagePreCallUpdate(const CallCapture & call,ResourceTracker & resourceTracker,ParamType paramType,FactoryT factory)7621*8975f5c5SAndroid Build Coastguard Worker void CreateEGLImagePreCallUpdate(const CallCapture &call,
7622*8975f5c5SAndroid Build Coastguard Worker                                  ResourceTracker &resourceTracker,
7623*8975f5c5SAndroid Build Coastguard Worker                                  ParamType paramType,
7624*8975f5c5SAndroid Build Coastguard Worker                                  FactoryT factory)
7625*8975f5c5SAndroid Build Coastguard Worker {
7626*8975f5c5SAndroid Build Coastguard Worker     EGLImage image            = call.params.getReturnValue().value.EGLImageVal;
7627*8975f5c5SAndroid Build Coastguard Worker     const ParamCapture &param = call.params.getParam("attrib_list", paramType, 4);
7628*8975f5c5SAndroid Build Coastguard Worker     const AttribT *attribs =
7629*8975f5c5SAndroid Build Coastguard Worker         param.data.empty() ? nullptr : reinterpret_cast<const AttribT *>(param.data[0].data());
7630*8975f5c5SAndroid Build Coastguard Worker     egl::AttributeMap attributeMap = factory(attribs);
7631*8975f5c5SAndroid Build Coastguard Worker     attributeMap.initializeWithoutValidation();
7632*8975f5c5SAndroid Build Coastguard Worker     resourceTracker.getImageToAttribTable().insert(
7633*8975f5c5SAndroid Build Coastguard Worker         std::pair<EGLImage, egl::AttributeMap>(image, attributeMap));
7634*8975f5c5SAndroid Build Coastguard Worker }
7635*8975f5c5SAndroid Build Coastguard Worker 
maybeCapturePreCallUpdates(const gl::Context * context,CallCapture & call,std::vector<CallCapture> * shareGroupSetupCalls,ResourceIDToSetupCallsMap * resourceIDToSetupCalls)7636*8975f5c5SAndroid Build Coastguard Worker void FrameCaptureShared::maybeCapturePreCallUpdates(
7637*8975f5c5SAndroid Build Coastguard Worker     const gl::Context *context,
7638*8975f5c5SAndroid Build Coastguard Worker     CallCapture &call,
7639*8975f5c5SAndroid Build Coastguard Worker     std::vector<CallCapture> *shareGroupSetupCalls,
7640*8975f5c5SAndroid Build Coastguard Worker     ResourceIDToSetupCallsMap *resourceIDToSetupCalls)
7641*8975f5c5SAndroid Build Coastguard Worker {
7642*8975f5c5SAndroid Build Coastguard Worker     switch (call.entryPoint)
7643*8975f5c5SAndroid Build Coastguard Worker     {
7644*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLVertexAttribPointer:
7645*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLVertexPointer:
7646*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLColorPointer:
7647*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLTexCoordPointer:
7648*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLNormalPointer:
7649*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLPointSizePointerOES:
7650*8975f5c5SAndroid Build Coastguard Worker         {
7651*8975f5c5SAndroid Build Coastguard Worker             // Get array location
7652*8975f5c5SAndroid Build Coastguard Worker             GLuint index = 0;
7653*8975f5c5SAndroid Build Coastguard Worker             if (call.entryPoint == EntryPoint::GLVertexAttribPointer)
7654*8975f5c5SAndroid Build Coastguard Worker             {
7655*8975f5c5SAndroid Build Coastguard Worker                 index = call.params.getParam("index", ParamType::TGLuint, 0).value.GLuintVal;
7656*8975f5c5SAndroid Build Coastguard Worker             }
7657*8975f5c5SAndroid Build Coastguard Worker             else
7658*8975f5c5SAndroid Build Coastguard Worker             {
7659*8975f5c5SAndroid Build Coastguard Worker                 gl::ClientVertexArrayType type;
7660*8975f5c5SAndroid Build Coastguard Worker                 switch (call.entryPoint)
7661*8975f5c5SAndroid Build Coastguard Worker                 {
7662*8975f5c5SAndroid Build Coastguard Worker                     case EntryPoint::GLVertexPointer:
7663*8975f5c5SAndroid Build Coastguard Worker                         type = gl::ClientVertexArrayType::Vertex;
7664*8975f5c5SAndroid Build Coastguard Worker                         break;
7665*8975f5c5SAndroid Build Coastguard Worker                     case EntryPoint::GLColorPointer:
7666*8975f5c5SAndroid Build Coastguard Worker                         type = gl::ClientVertexArrayType::Color;
7667*8975f5c5SAndroid Build Coastguard Worker                         break;
7668*8975f5c5SAndroid Build Coastguard Worker                     case EntryPoint::GLTexCoordPointer:
7669*8975f5c5SAndroid Build Coastguard Worker                         type = gl::ClientVertexArrayType::TextureCoord;
7670*8975f5c5SAndroid Build Coastguard Worker                         break;
7671*8975f5c5SAndroid Build Coastguard Worker                     case EntryPoint::GLNormalPointer:
7672*8975f5c5SAndroid Build Coastguard Worker                         type = gl::ClientVertexArrayType::Normal;
7673*8975f5c5SAndroid Build Coastguard Worker                         break;
7674*8975f5c5SAndroid Build Coastguard Worker                     case EntryPoint::GLPointSizePointerOES:
7675*8975f5c5SAndroid Build Coastguard Worker                         type = gl::ClientVertexArrayType::PointSize;
7676*8975f5c5SAndroid Build Coastguard Worker                         break;
7677*8975f5c5SAndroid Build Coastguard Worker                     default:
7678*8975f5c5SAndroid Build Coastguard Worker                         UNREACHABLE();
7679*8975f5c5SAndroid Build Coastguard Worker                         type = gl::ClientVertexArrayType::InvalidEnum;
7680*8975f5c5SAndroid Build Coastguard Worker                 }
7681*8975f5c5SAndroid Build Coastguard Worker                 index = gl::GLES1Renderer::VertexArrayIndex(type, context->getState().gles1());
7682*8975f5c5SAndroid Build Coastguard Worker             }
7683*8975f5c5SAndroid Build Coastguard Worker 
7684*8975f5c5SAndroid Build Coastguard Worker             if (call.params.hasClientArrayData())
7685*8975f5c5SAndroid Build Coastguard Worker             {
7686*8975f5c5SAndroid Build Coastguard Worker                 mClientVertexArrayMap[index] = static_cast<int>(mFrameCalls.size());
7687*8975f5c5SAndroid Build Coastguard Worker             }
7688*8975f5c5SAndroid Build Coastguard Worker             else
7689*8975f5c5SAndroid Build Coastguard Worker             {
7690*8975f5c5SAndroid Build Coastguard Worker                 mClientVertexArrayMap[index] = -1;
7691*8975f5c5SAndroid Build Coastguard Worker             }
7692*8975f5c5SAndroid Build Coastguard Worker             break;
7693*8975f5c5SAndroid Build Coastguard Worker         }
7694*8975f5c5SAndroid Build Coastguard Worker 
7695*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLGenFramebuffers:
7696*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLGenFramebuffersOES:
7697*8975f5c5SAndroid Build Coastguard Worker         {
7698*8975f5c5SAndroid Build Coastguard Worker             GLsizei count = call.params.getParam("n", ParamType::TGLsizei, 0).value.GLsizeiVal;
7699*8975f5c5SAndroid Build Coastguard Worker             const gl::FramebufferID *framebufferIDs =
7700*8975f5c5SAndroid Build Coastguard Worker                 call.params.getParam("framebuffersPacked", ParamType::TFramebufferIDPointer, 1)
7701*8975f5c5SAndroid Build Coastguard Worker                     .value.FramebufferIDPointerVal;
7702*8975f5c5SAndroid Build Coastguard Worker             for (GLsizei i = 0; i < count; i++)
7703*8975f5c5SAndroid Build Coastguard Worker             {
7704*8975f5c5SAndroid Build Coastguard Worker                 handleGennedResource(context, framebufferIDs[i]);
7705*8975f5c5SAndroid Build Coastguard Worker             }
7706*8975f5c5SAndroid Build Coastguard Worker             break;
7707*8975f5c5SAndroid Build Coastguard Worker         }
7708*8975f5c5SAndroid Build Coastguard Worker 
7709*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLBindFramebuffer:
7710*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLBindFramebufferOES:
7711*8975f5c5SAndroid Build Coastguard Worker             maybeGenResourceOnBind<gl::FramebufferID>(context, call);
7712*8975f5c5SAndroid Build Coastguard Worker             break;
7713*8975f5c5SAndroid Build Coastguard Worker 
7714*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLGenRenderbuffers:
7715*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLGenRenderbuffersOES:
7716*8975f5c5SAndroid Build Coastguard Worker         {
7717*8975f5c5SAndroid Build Coastguard Worker             GLsizei count = call.params.getParam("n", ParamType::TGLsizei, 0).value.GLsizeiVal;
7718*8975f5c5SAndroid Build Coastguard Worker             const gl::RenderbufferID *renderbufferIDs =
7719*8975f5c5SAndroid Build Coastguard Worker                 call.params.getParam("renderbuffersPacked", ParamType::TRenderbufferIDPointer, 1)
7720*8975f5c5SAndroid Build Coastguard Worker                     .value.RenderbufferIDPointerVal;
7721*8975f5c5SAndroid Build Coastguard Worker             for (GLsizei i = 0; i < count; i++)
7722*8975f5c5SAndroid Build Coastguard Worker             {
7723*8975f5c5SAndroid Build Coastguard Worker                 handleGennedResource(context, renderbufferIDs[i]);
7724*8975f5c5SAndroid Build Coastguard Worker             }
7725*8975f5c5SAndroid Build Coastguard Worker             break;
7726*8975f5c5SAndroid Build Coastguard Worker         }
7727*8975f5c5SAndroid Build Coastguard Worker 
7728*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLBindRenderbuffer:
7729*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLBindRenderbufferOES:
7730*8975f5c5SAndroid Build Coastguard Worker             maybeGenResourceOnBind<gl::RenderbufferID>(context, call);
7731*8975f5c5SAndroid Build Coastguard Worker             break;
7732*8975f5c5SAndroid Build Coastguard Worker 
7733*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLDeleteRenderbuffers:
7734*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLDeleteRenderbuffersOES:
7735*8975f5c5SAndroid Build Coastguard Worker         {
7736*8975f5c5SAndroid Build Coastguard Worker             // Look up how many renderbuffers are being deleted
7737*8975f5c5SAndroid Build Coastguard Worker             GLsizei n = call.params.getParam("n", ParamType::TGLsizei, 0).value.GLsizeiVal;
7738*8975f5c5SAndroid Build Coastguard Worker 
7739*8975f5c5SAndroid Build Coastguard Worker             // Look up the pointer to list of renderbuffers
7740*8975f5c5SAndroid Build Coastguard Worker             const gl::RenderbufferID *renderbufferIDs =
7741*8975f5c5SAndroid Build Coastguard Worker                 call.params
7742*8975f5c5SAndroid Build Coastguard Worker                     .getParam("renderbuffersPacked", ParamType::TRenderbufferIDConstPointer, 1)
7743*8975f5c5SAndroid Build Coastguard Worker                     .value.RenderbufferIDConstPointerVal;
7744*8975f5c5SAndroid Build Coastguard Worker 
7745*8975f5c5SAndroid Build Coastguard Worker             // For each renderbuffer listed for deletion
7746*8975f5c5SAndroid Build Coastguard Worker             for (int32_t i = 0; i < n; ++i)
7747*8975f5c5SAndroid Build Coastguard Worker             {
7748*8975f5c5SAndroid Build Coastguard Worker                 // If we're capturing, track what renderbuffers have been deleted
7749*8975f5c5SAndroid Build Coastguard Worker                 handleDeletedResource(context, renderbufferIDs[i]);
7750*8975f5c5SAndroid Build Coastguard Worker             }
7751*8975f5c5SAndroid Build Coastguard Worker             break;
7752*8975f5c5SAndroid Build Coastguard Worker         }
7753*8975f5c5SAndroid Build Coastguard Worker 
7754*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLGenTextures:
7755*8975f5c5SAndroid Build Coastguard Worker         {
7756*8975f5c5SAndroid Build Coastguard Worker             GLsizei count = call.params.getParam("n", ParamType::TGLsizei, 0).value.GLsizeiVal;
7757*8975f5c5SAndroid Build Coastguard Worker             const gl::TextureID *textureIDs =
7758*8975f5c5SAndroid Build Coastguard Worker                 call.params.getParam("texturesPacked", ParamType::TTextureIDPointer, 1)
7759*8975f5c5SAndroid Build Coastguard Worker                     .value.TextureIDPointerVal;
7760*8975f5c5SAndroid Build Coastguard Worker             for (GLsizei i = 0; i < count; i++)
7761*8975f5c5SAndroid Build Coastguard Worker             {
7762*8975f5c5SAndroid Build Coastguard Worker                 // If we're capturing, track what new textures have been genned
7763*8975f5c5SAndroid Build Coastguard Worker                 handleGennedResource(context, textureIDs[i]);
7764*8975f5c5SAndroid Build Coastguard Worker             }
7765*8975f5c5SAndroid Build Coastguard Worker             break;
7766*8975f5c5SAndroid Build Coastguard Worker         }
7767*8975f5c5SAndroid Build Coastguard Worker 
7768*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLBindTexture:
7769*8975f5c5SAndroid Build Coastguard Worker             maybeGenResourceOnBind<gl::TextureID>(context, call);
7770*8975f5c5SAndroid Build Coastguard Worker             if (isCaptureActive())
7771*8975f5c5SAndroid Build Coastguard Worker             {
7772*8975f5c5SAndroid Build Coastguard Worker                 gl::TextureType target =
7773*8975f5c5SAndroid Build Coastguard Worker                     call.params.getParam("targetPacked", ParamType::TTextureType, 0)
7774*8975f5c5SAndroid Build Coastguard Worker                         .value.TextureTypeVal;
7775*8975f5c5SAndroid Build Coastguard Worker                 context->getFrameCapture()->getStateResetHelper().setTextureBindingDirty(
7776*8975f5c5SAndroid Build Coastguard Worker                     context->getState().getActiveSampler(), target);
7777*8975f5c5SAndroid Build Coastguard Worker             }
7778*8975f5c5SAndroid Build Coastguard Worker             break;
7779*8975f5c5SAndroid Build Coastguard Worker 
7780*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLDeleteBuffers:
7781*8975f5c5SAndroid Build Coastguard Worker         {
7782*8975f5c5SAndroid Build Coastguard Worker             GLsizei count = call.params.getParam("n", ParamType::TGLsizei, 0).value.GLsizeiVal;
7783*8975f5c5SAndroid Build Coastguard Worker             const gl::BufferID *bufferIDs =
7784*8975f5c5SAndroid Build Coastguard Worker                 call.params.getParam("buffersPacked", ParamType::TBufferIDConstPointer, 1)
7785*8975f5c5SAndroid Build Coastguard Worker                     .value.BufferIDConstPointerVal;
7786*8975f5c5SAndroid Build Coastguard Worker             for (GLsizei i = 0; i < count; i++)
7787*8975f5c5SAndroid Build Coastguard Worker             {
7788*8975f5c5SAndroid Build Coastguard Worker                 // For each buffer being deleted, check our backup of data and remove it
7789*8975f5c5SAndroid Build Coastguard Worker                 const auto &bufferDataInfo = mBufferDataMap.find(bufferIDs[i]);
7790*8975f5c5SAndroid Build Coastguard Worker                 if (bufferDataInfo != mBufferDataMap.end())
7791*8975f5c5SAndroid Build Coastguard Worker                 {
7792*8975f5c5SAndroid Build Coastguard Worker                     mBufferDataMap.erase(bufferDataInfo);
7793*8975f5c5SAndroid Build Coastguard Worker                 }
7794*8975f5c5SAndroid Build Coastguard Worker                 // If we're capturing, track what buffers have been deleted
7795*8975f5c5SAndroid Build Coastguard Worker                 handleDeletedResource(context, bufferIDs[i]);
7796*8975f5c5SAndroid Build Coastguard Worker             }
7797*8975f5c5SAndroid Build Coastguard Worker             break;
7798*8975f5c5SAndroid Build Coastguard Worker         }
7799*8975f5c5SAndroid Build Coastguard Worker 
7800*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLGenBuffers:
7801*8975f5c5SAndroid Build Coastguard Worker         {
7802*8975f5c5SAndroid Build Coastguard Worker             GLsizei count = call.params.getParam("n", ParamType::TGLsizei, 0).value.GLsizeiVal;
7803*8975f5c5SAndroid Build Coastguard Worker             const gl::BufferID *bufferIDs =
7804*8975f5c5SAndroid Build Coastguard Worker                 call.params.getParam("buffersPacked", ParamType::TBufferIDPointer, 1)
7805*8975f5c5SAndroid Build Coastguard Worker                     .value.BufferIDPointerVal;
7806*8975f5c5SAndroid Build Coastguard Worker             for (GLsizei i = 0; i < count; i++)
7807*8975f5c5SAndroid Build Coastguard Worker             {
7808*8975f5c5SAndroid Build Coastguard Worker                 handleGennedResource(context, bufferIDs[i]);
7809*8975f5c5SAndroid Build Coastguard Worker             }
7810*8975f5c5SAndroid Build Coastguard Worker             break;
7811*8975f5c5SAndroid Build Coastguard Worker         }
7812*8975f5c5SAndroid Build Coastguard Worker 
7813*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLBindBuffer:
7814*8975f5c5SAndroid Build Coastguard Worker             maybeGenResourceOnBind<gl::BufferID>(context, call);
7815*8975f5c5SAndroid Build Coastguard Worker             if (isCaptureActive())
7816*8975f5c5SAndroid Build Coastguard Worker             {
7817*8975f5c5SAndroid Build Coastguard Worker                 gl::BufferBinding binding =
7818*8975f5c5SAndroid Build Coastguard Worker                     call.params.getParam("targetPacked", ParamType::TBufferBinding, 0)
7819*8975f5c5SAndroid Build Coastguard Worker                         .value.BufferBindingVal;
7820*8975f5c5SAndroid Build Coastguard Worker 
7821*8975f5c5SAndroid Build Coastguard Worker                 context->getFrameCapture()->getStateResetHelper().setBufferBindingDirty(binding);
7822*8975f5c5SAndroid Build Coastguard Worker             }
7823*8975f5c5SAndroid Build Coastguard Worker             break;
7824*8975f5c5SAndroid Build Coastguard Worker 
7825*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLBindBufferBase:
7826*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLBindBufferRange:
7827*8975f5c5SAndroid Build Coastguard Worker             if (isCaptureActive())
7828*8975f5c5SAndroid Build Coastguard Worker             {
7829*8975f5c5SAndroid Build Coastguard Worker                 WARN() << "Indexed buffer binding changed during capture, Reset doesn't handle it "
7830*8975f5c5SAndroid Build Coastguard Worker                           "yet.";
7831*8975f5c5SAndroid Build Coastguard Worker             }
7832*8975f5c5SAndroid Build Coastguard Worker             break;
7833*8975f5c5SAndroid Build Coastguard Worker 
7834*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLDeleteProgramPipelines:
7835*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLDeleteProgramPipelinesEXT:
7836*8975f5c5SAndroid Build Coastguard Worker         {
7837*8975f5c5SAndroid Build Coastguard Worker             GLsizei count = call.params.getParam("n", ParamType::TGLsizei, 0).value.GLsizeiVal;
7838*8975f5c5SAndroid Build Coastguard Worker             const gl::ProgramPipelineID *pipelineIDs =
7839*8975f5c5SAndroid Build Coastguard Worker                 call.params
7840*8975f5c5SAndroid Build Coastguard Worker                     .getParam("pipelinesPacked", ParamType::TProgramPipelineIDConstPointer, 1)
7841*8975f5c5SAndroid Build Coastguard Worker                     .value.ProgramPipelineIDPointerVal;
7842*8975f5c5SAndroid Build Coastguard Worker             for (GLsizei i = 0; i < count; i++)
7843*8975f5c5SAndroid Build Coastguard Worker             {
7844*8975f5c5SAndroid Build Coastguard Worker                 handleDeletedResource(context, pipelineIDs[i]);
7845*8975f5c5SAndroid Build Coastguard Worker             }
7846*8975f5c5SAndroid Build Coastguard Worker             break;
7847*8975f5c5SAndroid Build Coastguard Worker         }
7848*8975f5c5SAndroid Build Coastguard Worker 
7849*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLGenProgramPipelines:
7850*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLGenProgramPipelinesEXT:
7851*8975f5c5SAndroid Build Coastguard Worker         {
7852*8975f5c5SAndroid Build Coastguard Worker             GLsizei count = call.params.getParam("n", ParamType::TGLsizei, 0).value.GLsizeiVal;
7853*8975f5c5SAndroid Build Coastguard Worker             const gl::ProgramPipelineID *pipelineIDs =
7854*8975f5c5SAndroid Build Coastguard Worker                 call.params.getParam("pipelinesPacked", ParamType::TProgramPipelineIDPointer, 1)
7855*8975f5c5SAndroid Build Coastguard Worker                     .value.ProgramPipelineIDPointerVal;
7856*8975f5c5SAndroid Build Coastguard Worker             for (GLsizei i = 0; i < count; i++)
7857*8975f5c5SAndroid Build Coastguard Worker             {
7858*8975f5c5SAndroid Build Coastguard Worker                 handleGennedResource(context, pipelineIDs[i]);
7859*8975f5c5SAndroid Build Coastguard Worker             }
7860*8975f5c5SAndroid Build Coastguard Worker             break;
7861*8975f5c5SAndroid Build Coastguard Worker         }
7862*8975f5c5SAndroid Build Coastguard Worker 
7863*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLDeleteSync:
7864*8975f5c5SAndroid Build Coastguard Worker         {
7865*8975f5c5SAndroid Build Coastguard Worker             gl::SyncID sync =
7866*8975f5c5SAndroid Build Coastguard Worker                 call.params.getParam("syncPacked", ParamType::TSyncID, 0).value.SyncIDVal;
7867*8975f5c5SAndroid Build Coastguard Worker             FrameCaptureShared *frameCaptureShared =
7868*8975f5c5SAndroid Build Coastguard Worker                 context->getShareGroup()->getFrameCaptureShared();
7869*8975f5c5SAndroid Build Coastguard Worker             // If we're capturing, track which fence sync has been deleted
7870*8975f5c5SAndroid Build Coastguard Worker             if (frameCaptureShared->isCaptureActive())
7871*8975f5c5SAndroid Build Coastguard Worker             {
7872*8975f5c5SAndroid Build Coastguard Worker                 mResourceTracker.setDeletedFenceSync(sync);
7873*8975f5c5SAndroid Build Coastguard Worker             }
7874*8975f5c5SAndroid Build Coastguard Worker             break;
7875*8975f5c5SAndroid Build Coastguard Worker         }
7876*8975f5c5SAndroid Build Coastguard Worker 
7877*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLDrawArrays:
7878*8975f5c5SAndroid Build Coastguard Worker         {
7879*8975f5c5SAndroid Build Coastguard Worker             maybeCaptureDrawArraysClientData(context, call, 1);
7880*8975f5c5SAndroid Build Coastguard Worker             maybeCaptureCoherentBuffers(context);
7881*8975f5c5SAndroid Build Coastguard Worker             break;
7882*8975f5c5SAndroid Build Coastguard Worker         }
7883*8975f5c5SAndroid Build Coastguard Worker 
7884*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLDrawArraysInstanced:
7885*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLDrawArraysInstancedANGLE:
7886*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLDrawArraysInstancedEXT:
7887*8975f5c5SAndroid Build Coastguard Worker         {
7888*8975f5c5SAndroid Build Coastguard Worker             GLsizei instancecount =
7889*8975f5c5SAndroid Build Coastguard Worker                 call.params.getParamFlexName("instancecount", "primcount", ParamType::TGLsizei, 3)
7890*8975f5c5SAndroid Build Coastguard Worker                     .value.GLsizeiVal;
7891*8975f5c5SAndroid Build Coastguard Worker 
7892*8975f5c5SAndroid Build Coastguard Worker             maybeCaptureDrawArraysClientData(context, call, instancecount);
7893*8975f5c5SAndroid Build Coastguard Worker             maybeCaptureCoherentBuffers(context);
7894*8975f5c5SAndroid Build Coastguard Worker             break;
7895*8975f5c5SAndroid Build Coastguard Worker         }
7896*8975f5c5SAndroid Build Coastguard Worker 
7897*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLDrawElements:
7898*8975f5c5SAndroid Build Coastguard Worker         {
7899*8975f5c5SAndroid Build Coastguard Worker             maybeCaptureDrawElementsClientData(context, call, 1);
7900*8975f5c5SAndroid Build Coastguard Worker             maybeCaptureCoherentBuffers(context);
7901*8975f5c5SAndroid Build Coastguard Worker             break;
7902*8975f5c5SAndroid Build Coastguard Worker         }
7903*8975f5c5SAndroid Build Coastguard Worker 
7904*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLDrawElementsInstanced:
7905*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLDrawElementsInstancedANGLE:
7906*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLDrawElementsInstancedEXT:
7907*8975f5c5SAndroid Build Coastguard Worker         {
7908*8975f5c5SAndroid Build Coastguard Worker             GLsizei instancecount =
7909*8975f5c5SAndroid Build Coastguard Worker                 call.params.getParamFlexName("instancecount", "primcount", ParamType::TGLsizei, 4)
7910*8975f5c5SAndroid Build Coastguard Worker                     .value.GLsizeiVal;
7911*8975f5c5SAndroid Build Coastguard Worker 
7912*8975f5c5SAndroid Build Coastguard Worker             maybeCaptureDrawElementsClientData(context, call, instancecount);
7913*8975f5c5SAndroid Build Coastguard Worker             maybeCaptureCoherentBuffers(context);
7914*8975f5c5SAndroid Build Coastguard Worker             break;
7915*8975f5c5SAndroid Build Coastguard Worker         }
7916*8975f5c5SAndroid Build Coastguard Worker 
7917*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLCreateShaderProgramv:
7918*8975f5c5SAndroid Build Coastguard Worker         {
7919*8975f5c5SAndroid Build Coastguard Worker             // Refresh the cached shader sources.
7920*8975f5c5SAndroid Build Coastguard Worker             // The command CreateShaderProgramv() creates a stand-alone program from an array of
7921*8975f5c5SAndroid Build Coastguard Worker             // null-terminated source code strings for a single shader type, so we need update the
7922*8975f5c5SAndroid Build Coastguard Worker             // Shader and Program sources, similar to GLCompileShader + GLLinkProgram handling.
7923*8975f5c5SAndroid Build Coastguard Worker             gl::ShaderProgramID programID = {call.params.getReturnValue().value.GLuintVal};
7924*8975f5c5SAndroid Build Coastguard Worker             const ParamCapture &paramCapture =
7925*8975f5c5SAndroid Build Coastguard Worker                 call.params.getParam("typePacked", ParamType::TShaderType, 0);
7926*8975f5c5SAndroid Build Coastguard Worker             const ParamCapture &lineCount = call.params.getParam("count", ParamType::TGLsizei, 1);
7927*8975f5c5SAndroid Build Coastguard Worker             const ParamCapture &strings =
7928*8975f5c5SAndroid Build Coastguard Worker                 call.params.getParam("strings", ParamType::TGLcharConstPointerPointer, 2);
7929*8975f5c5SAndroid Build Coastguard Worker 
7930*8975f5c5SAndroid Build Coastguard Worker             std::ostringstream sourceString;
7931*8975f5c5SAndroid Build Coastguard Worker             for (int i = 0; i < lineCount.value.GLsizeiVal; ++i)
7932*8975f5c5SAndroid Build Coastguard Worker             {
7933*8975f5c5SAndroid Build Coastguard Worker                 sourceString << strings.value.GLcharConstPointerPointerVal[i];
7934*8975f5c5SAndroid Build Coastguard Worker             }
7935*8975f5c5SAndroid Build Coastguard Worker 
7936*8975f5c5SAndroid Build Coastguard Worker             gl::ShaderType shaderType = paramCapture.value.ShaderTypeVal;
7937*8975f5c5SAndroid Build Coastguard Worker             ProgramSources source;
7938*8975f5c5SAndroid Build Coastguard Worker             source[shaderType] = sourceString.str();
7939*8975f5c5SAndroid Build Coastguard Worker             setProgramSources(programID, source);
7940*8975f5c5SAndroid Build Coastguard Worker             handleGennedResource(context, programID);
7941*8975f5c5SAndroid Build Coastguard Worker             mResourceTracker.setShaderProgramType(programID, ShaderProgramType::ProgramType);
7942*8975f5c5SAndroid Build Coastguard Worker             break;
7943*8975f5c5SAndroid Build Coastguard Worker         }
7944*8975f5c5SAndroid Build Coastguard Worker 
7945*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLCreateProgram:
7946*8975f5c5SAndroid Build Coastguard Worker         {
7947*8975f5c5SAndroid Build Coastguard Worker             // If we're capturing, track which programs have been created
7948*8975f5c5SAndroid Build Coastguard Worker             gl::ShaderProgramID programID = {call.params.getReturnValue().value.GLuintVal};
7949*8975f5c5SAndroid Build Coastguard Worker             handleGennedResource(context, programID);
7950*8975f5c5SAndroid Build Coastguard Worker 
7951*8975f5c5SAndroid Build Coastguard Worker             mResourceTracker.setShaderProgramType(programID, ShaderProgramType::ProgramType);
7952*8975f5c5SAndroid Build Coastguard Worker             break;
7953*8975f5c5SAndroid Build Coastguard Worker         }
7954*8975f5c5SAndroid Build Coastguard Worker 
7955*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLDeleteProgram:
7956*8975f5c5SAndroid Build Coastguard Worker         {
7957*8975f5c5SAndroid Build Coastguard Worker             // If we're capturing, track which programs have been deleted
7958*8975f5c5SAndroid Build Coastguard Worker             const ParamCapture &param =
7959*8975f5c5SAndroid Build Coastguard Worker                 call.params.getParam("programPacked", ParamType::TShaderProgramID, 0);
7960*8975f5c5SAndroid Build Coastguard Worker             handleDeletedResource(context, param.value.ShaderProgramIDVal);
7961*8975f5c5SAndroid Build Coastguard Worker 
7962*8975f5c5SAndroid Build Coastguard Worker             // If this assert fires, it means a ShaderProgramID has changed from program to shader
7963*8975f5c5SAndroid Build Coastguard Worker             // which is unsupported
7964*8975f5c5SAndroid Build Coastguard Worker             ASSERT(mResourceTracker.getShaderProgramType(param.value.ShaderProgramIDVal) ==
7965*8975f5c5SAndroid Build Coastguard Worker                    ShaderProgramType::ProgramType);
7966*8975f5c5SAndroid Build Coastguard Worker 
7967*8975f5c5SAndroid Build Coastguard Worker             break;
7968*8975f5c5SAndroid Build Coastguard Worker         }
7969*8975f5c5SAndroid Build Coastguard Worker 
7970*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLCreateShader:
7971*8975f5c5SAndroid Build Coastguard Worker         {
7972*8975f5c5SAndroid Build Coastguard Worker             // If we're capturing, track which shaders have been created
7973*8975f5c5SAndroid Build Coastguard Worker             gl::ShaderProgramID shaderID = {call.params.getReturnValue().value.GLuintVal};
7974*8975f5c5SAndroid Build Coastguard Worker             handleGennedResource(context, shaderID);
7975*8975f5c5SAndroid Build Coastguard Worker 
7976*8975f5c5SAndroid Build Coastguard Worker             mResourceTracker.setShaderProgramType(shaderID, ShaderProgramType::ShaderType);
7977*8975f5c5SAndroid Build Coastguard Worker             break;
7978*8975f5c5SAndroid Build Coastguard Worker         }
7979*8975f5c5SAndroid Build Coastguard Worker 
7980*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLDeleteShader:
7981*8975f5c5SAndroid Build Coastguard Worker         {
7982*8975f5c5SAndroid Build Coastguard Worker             // If we're capturing, track which shaders have been deleted
7983*8975f5c5SAndroid Build Coastguard Worker             const ParamCapture &param =
7984*8975f5c5SAndroid Build Coastguard Worker                 call.params.getParam("shaderPacked", ParamType::TShaderProgramID, 0);
7985*8975f5c5SAndroid Build Coastguard Worker             handleDeletedResource(context, param.value.ShaderProgramIDVal);
7986*8975f5c5SAndroid Build Coastguard Worker 
7987*8975f5c5SAndroid Build Coastguard Worker             // If this assert fires, it means a ShaderProgramID has changed from shader to program
7988*8975f5c5SAndroid Build Coastguard Worker             // which is unsupported
7989*8975f5c5SAndroid Build Coastguard Worker             ASSERT(mResourceTracker.getShaderProgramType(param.value.ShaderProgramIDVal) ==
7990*8975f5c5SAndroid Build Coastguard Worker                    ShaderProgramType::ShaderType);
7991*8975f5c5SAndroid Build Coastguard Worker             break;
7992*8975f5c5SAndroid Build Coastguard Worker         }
7993*8975f5c5SAndroid Build Coastguard Worker 
7994*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLCompileShader:
7995*8975f5c5SAndroid Build Coastguard Worker         {
7996*8975f5c5SAndroid Build Coastguard Worker             // Refresh the cached shader sources.
7997*8975f5c5SAndroid Build Coastguard Worker             gl::ShaderProgramID shaderID =
7998*8975f5c5SAndroid Build Coastguard Worker                 call.params.getParam("shaderPacked", ParamType::TShaderProgramID, 0)
7999*8975f5c5SAndroid Build Coastguard Worker                     .value.ShaderProgramIDVal;
8000*8975f5c5SAndroid Build Coastguard Worker             const gl::Shader *shader = context->getShaderNoResolveCompile(shaderID);
8001*8975f5c5SAndroid Build Coastguard Worker             // Shaders compiled for ProgramBinary will not have a shader created
8002*8975f5c5SAndroid Build Coastguard Worker             if (shader)
8003*8975f5c5SAndroid Build Coastguard Worker             {
8004*8975f5c5SAndroid Build Coastguard Worker                 setShaderSource(shaderID, shader->getSourceString());
8005*8975f5c5SAndroid Build Coastguard Worker             }
8006*8975f5c5SAndroid Build Coastguard Worker             break;
8007*8975f5c5SAndroid Build Coastguard Worker         }
8008*8975f5c5SAndroid Build Coastguard Worker 
8009*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLLinkProgram:
8010*8975f5c5SAndroid Build Coastguard Worker         {
8011*8975f5c5SAndroid Build Coastguard Worker             // Refresh the cached program sources.
8012*8975f5c5SAndroid Build Coastguard Worker             gl::ShaderProgramID programID =
8013*8975f5c5SAndroid Build Coastguard Worker                 call.params.getParam("programPacked", ParamType::TShaderProgramID, 0)
8014*8975f5c5SAndroid Build Coastguard Worker                     .value.ShaderProgramIDVal;
8015*8975f5c5SAndroid Build Coastguard Worker             const gl::Program *program = context->getProgramResolveLink(programID);
8016*8975f5c5SAndroid Build Coastguard Worker             // Programs linked in support of ProgramBinary will not have attached shaders
8017*8975f5c5SAndroid Build Coastguard Worker             if (program->getState().hasAnyAttachedShader())
8018*8975f5c5SAndroid Build Coastguard Worker             {
8019*8975f5c5SAndroid Build Coastguard Worker                 setProgramSources(programID, GetAttachedProgramSources(context, program));
8020*8975f5c5SAndroid Build Coastguard Worker             }
8021*8975f5c5SAndroid Build Coastguard Worker             break;
8022*8975f5c5SAndroid Build Coastguard Worker         }
8023*8975f5c5SAndroid Build Coastguard Worker 
8024*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLDeleteTextures:
8025*8975f5c5SAndroid Build Coastguard Worker         {
8026*8975f5c5SAndroid Build Coastguard Worker             // Free any TextureLevelDataMap entries being tracked for this texture
8027*8975f5c5SAndroid Build Coastguard Worker             // This is to cover the scenario where a texture has been created, its
8028*8975f5c5SAndroid Build Coastguard Worker             // levels cached, then texture deleted and recreated, receiving the same ID
8029*8975f5c5SAndroid Build Coastguard Worker 
8030*8975f5c5SAndroid Build Coastguard Worker             // Look up how many textures are being deleted
8031*8975f5c5SAndroid Build Coastguard Worker             GLsizei n = call.params.getParam("n", ParamType::TGLsizei, 0).value.GLsizeiVal;
8032*8975f5c5SAndroid Build Coastguard Worker 
8033*8975f5c5SAndroid Build Coastguard Worker             // Look up the pointer to list of textures
8034*8975f5c5SAndroid Build Coastguard Worker             const gl::TextureID *textureIDs =
8035*8975f5c5SAndroid Build Coastguard Worker                 call.params.getParam("texturesPacked", ParamType::TTextureIDConstPointer, 1)
8036*8975f5c5SAndroid Build Coastguard Worker                     .value.TextureIDConstPointerVal;
8037*8975f5c5SAndroid Build Coastguard Worker 
8038*8975f5c5SAndroid Build Coastguard Worker             // For each texture listed for deletion
8039*8975f5c5SAndroid Build Coastguard Worker             for (int32_t i = 0; i < n; ++i)
8040*8975f5c5SAndroid Build Coastguard Worker             {
8041*8975f5c5SAndroid Build Coastguard Worker                 // If we're capturing, track what textures have been deleted
8042*8975f5c5SAndroid Build Coastguard Worker                 handleDeletedResource(context, textureIDs[i]);
8043*8975f5c5SAndroid Build Coastguard Worker             }
8044*8975f5c5SAndroid Build Coastguard Worker             break;
8045*8975f5c5SAndroid Build Coastguard Worker         }
8046*8975f5c5SAndroid Build Coastguard Worker 
8047*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLMapBufferOES:
8048*8975f5c5SAndroid Build Coastguard Worker         {
8049*8975f5c5SAndroid Build Coastguard Worker             gl::BufferBinding target =
8050*8975f5c5SAndroid Build Coastguard Worker                 call.params.getParam("targetPacked", ParamType::TBufferBinding, 0)
8051*8975f5c5SAndroid Build Coastguard Worker                     .value.BufferBindingVal;
8052*8975f5c5SAndroid Build Coastguard Worker 
8053*8975f5c5SAndroid Build Coastguard Worker             GLbitfield access =
8054*8975f5c5SAndroid Build Coastguard Worker                 call.params.getParam("access", ParamType::TGLenum, 1).value.GLenumVal;
8055*8975f5c5SAndroid Build Coastguard Worker 
8056*8975f5c5SAndroid Build Coastguard Worker             gl::Buffer *buffer = context->getState().getTargetBuffer(target);
8057*8975f5c5SAndroid Build Coastguard Worker 
8058*8975f5c5SAndroid Build Coastguard Worker             GLintptr offset   = 0;
8059*8975f5c5SAndroid Build Coastguard Worker             GLsizeiptr length = static_cast<GLsizeiptr>(buffer->getSize());
8060*8975f5c5SAndroid Build Coastguard Worker 
8061*8975f5c5SAndroid Build Coastguard Worker             bool writable =
8062*8975f5c5SAndroid Build Coastguard Worker                 access == GL_WRITE_ONLY_OES || access == GL_WRITE_ONLY || access == GL_READ_WRITE;
8063*8975f5c5SAndroid Build Coastguard Worker 
8064*8975f5c5SAndroid Build Coastguard Worker             FrameCaptureShared *frameCaptureShared =
8065*8975f5c5SAndroid Build Coastguard Worker                 context->getShareGroup()->getFrameCaptureShared();
8066*8975f5c5SAndroid Build Coastguard Worker             frameCaptureShared->trackBufferMapping(context, &call, buffer->id(), buffer, offset,
8067*8975f5c5SAndroid Build Coastguard Worker                                                    length, writable, false);
8068*8975f5c5SAndroid Build Coastguard Worker             break;
8069*8975f5c5SAndroid Build Coastguard Worker         }
8070*8975f5c5SAndroid Build Coastguard Worker 
8071*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLUnmapBuffer:
8072*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLUnmapBufferOES:
8073*8975f5c5SAndroid Build Coastguard Worker         {
8074*8975f5c5SAndroid Build Coastguard Worker             // See if we need to capture the buffer contents
8075*8975f5c5SAndroid Build Coastguard Worker             captureMappedBufferSnapshot(context, call);
8076*8975f5c5SAndroid Build Coastguard Worker 
8077*8975f5c5SAndroid Build Coastguard Worker             // Track that the buffer was unmapped, for use during state reset
8078*8975f5c5SAndroid Build Coastguard Worker             gl::BufferBinding target =
8079*8975f5c5SAndroid Build Coastguard Worker                 call.params.getParam("targetPacked", ParamType::TBufferBinding, 0)
8080*8975f5c5SAndroid Build Coastguard Worker                     .value.BufferBindingVal;
8081*8975f5c5SAndroid Build Coastguard Worker             gl::Buffer *buffer = context->getState().getTargetBuffer(target);
8082*8975f5c5SAndroid Build Coastguard Worker             mResourceTracker.setBufferUnmapped(context->id(), buffer->id().value);
8083*8975f5c5SAndroid Build Coastguard Worker 
8084*8975f5c5SAndroid Build Coastguard Worker             // Remove from CoherentBufferTracker
8085*8975f5c5SAndroid Build Coastguard Worker             mCoherentBufferTracker.removeBuffer(buffer->id());
8086*8975f5c5SAndroid Build Coastguard Worker             break;
8087*8975f5c5SAndroid Build Coastguard Worker         }
8088*8975f5c5SAndroid Build Coastguard Worker 
8089*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLBufferData:
8090*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLBufferSubData:
8091*8975f5c5SAndroid Build Coastguard Worker         {
8092*8975f5c5SAndroid Build Coastguard Worker             gl::BufferBinding target =
8093*8975f5c5SAndroid Build Coastguard Worker                 call.params.getParam("targetPacked", ParamType::TBufferBinding, 0)
8094*8975f5c5SAndroid Build Coastguard Worker                     .value.BufferBindingVal;
8095*8975f5c5SAndroid Build Coastguard Worker 
8096*8975f5c5SAndroid Build Coastguard Worker             gl::Buffer *buffer = context->getState().getTargetBuffer(target);
8097*8975f5c5SAndroid Build Coastguard Worker 
8098*8975f5c5SAndroid Build Coastguard Worker             // Track that this buffer's contents have been modified
8099*8975f5c5SAndroid Build Coastguard Worker             mResourceTracker.getTrackedResource(context->id(), ResourceIDType::Buffer)
8100*8975f5c5SAndroid Build Coastguard Worker                 .setModifiedResource(buffer->id().value);
8101*8975f5c5SAndroid Build Coastguard Worker 
8102*8975f5c5SAndroid Build Coastguard Worker             // BufferData is equivalent to UnmapBuffer, for what we're tracking.
8103*8975f5c5SAndroid Build Coastguard Worker             // From the ES 3.1 spec in BufferData section:
8104*8975f5c5SAndroid Build Coastguard Worker             //     If any portion of the buffer object is mapped in the current context or any
8105*8975f5c5SAndroid Build Coastguard Worker             //     context current to another thread, it is as though UnmapBuffer (see section
8106*8975f5c5SAndroid Build Coastguard Worker             //     6.3.1) is executed in each such context prior to deleting the existing data
8107*8975f5c5SAndroid Build Coastguard Worker             //     store.
8108*8975f5c5SAndroid Build Coastguard Worker             // Track that the buffer was unmapped, for use during state reset
8109*8975f5c5SAndroid Build Coastguard Worker             mResourceTracker.setBufferUnmapped(context->id(), buffer->id().value);
8110*8975f5c5SAndroid Build Coastguard Worker 
8111*8975f5c5SAndroid Build Coastguard Worker             break;
8112*8975f5c5SAndroid Build Coastguard Worker         }
8113*8975f5c5SAndroid Build Coastguard Worker 
8114*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLCopyBufferSubData:
8115*8975f5c5SAndroid Build Coastguard Worker         {
8116*8975f5c5SAndroid Build Coastguard Worker             maybeCaptureCoherentBuffers(context);
8117*8975f5c5SAndroid Build Coastguard Worker             break;
8118*8975f5c5SAndroid Build Coastguard Worker         }
8119*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLFinish:
8120*8975f5c5SAndroid Build Coastguard Worker         {
8121*8975f5c5SAndroid Build Coastguard Worker             // When using shadow memory we might need to synchronize it here.
8122*8975f5c5SAndroid Build Coastguard Worker             if (mCoherentBufferTracker.isShadowMemoryEnabled())
8123*8975f5c5SAndroid Build Coastguard Worker             {
8124*8975f5c5SAndroid Build Coastguard Worker                 mCoherentBufferTracker.maybeUpdateShadowMemory();
8125*8975f5c5SAndroid Build Coastguard Worker             }
8126*8975f5c5SAndroid Build Coastguard Worker             break;
8127*8975f5c5SAndroid Build Coastguard Worker         }
8128*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLDeleteFramebuffers:
8129*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLDeleteFramebuffersOES:
8130*8975f5c5SAndroid Build Coastguard Worker         {
8131*8975f5c5SAndroid Build Coastguard Worker             // Look up how many framebuffers are being deleted
8132*8975f5c5SAndroid Build Coastguard Worker             GLsizei n = call.params.getParam("n", ParamType::TGLsizei, 0).value.GLsizeiVal;
8133*8975f5c5SAndroid Build Coastguard Worker 
8134*8975f5c5SAndroid Build Coastguard Worker             // Look up the pointer to list of framebuffers
8135*8975f5c5SAndroid Build Coastguard Worker             const gl::FramebufferID *framebufferIDs =
8136*8975f5c5SAndroid Build Coastguard Worker                 call.params.getParam("framebuffersPacked", ParamType::TFramebufferIDConstPointer, 1)
8137*8975f5c5SAndroid Build Coastguard Worker                     .value.FramebufferIDConstPointerVal;
8138*8975f5c5SAndroid Build Coastguard Worker 
8139*8975f5c5SAndroid Build Coastguard Worker             // For each framebuffer listed for deletion
8140*8975f5c5SAndroid Build Coastguard Worker             for (int32_t i = 0; i < n; ++i)
8141*8975f5c5SAndroid Build Coastguard Worker             {
8142*8975f5c5SAndroid Build Coastguard Worker                 // If we're capturing, track what framebuffers have been deleted
8143*8975f5c5SAndroid Build Coastguard Worker                 handleDeletedResource(context, framebufferIDs[i]);
8144*8975f5c5SAndroid Build Coastguard Worker             }
8145*8975f5c5SAndroid Build Coastguard Worker             break;
8146*8975f5c5SAndroid Build Coastguard Worker         }
8147*8975f5c5SAndroid Build Coastguard Worker 
8148*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLUseProgram:
8149*8975f5c5SAndroid Build Coastguard Worker         {
8150*8975f5c5SAndroid Build Coastguard Worker             if (isCaptureActive())
8151*8975f5c5SAndroid Build Coastguard Worker             {
8152*8975f5c5SAndroid Build Coastguard Worker                 context->getFrameCapture()->getStateResetHelper().setEntryPointDirty(
8153*8975f5c5SAndroid Build Coastguard Worker                     EntryPoint::GLUseProgram);
8154*8975f5c5SAndroid Build Coastguard Worker             }
8155*8975f5c5SAndroid Build Coastguard Worker             break;
8156*8975f5c5SAndroid Build Coastguard Worker         }
8157*8975f5c5SAndroid Build Coastguard Worker 
8158*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLGenVertexArrays:
8159*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLGenVertexArraysOES:
8160*8975f5c5SAndroid Build Coastguard Worker         {
8161*8975f5c5SAndroid Build Coastguard Worker             GLsizei count = call.params.getParam("n", ParamType::TGLsizei, 0).value.GLsizeiVal;
8162*8975f5c5SAndroid Build Coastguard Worker             const gl::VertexArrayID *arrayIDs =
8163*8975f5c5SAndroid Build Coastguard Worker                 call.params.getParam("arraysPacked", ParamType::TVertexArrayIDPointer, 1)
8164*8975f5c5SAndroid Build Coastguard Worker                     .value.VertexArrayIDPointerVal;
8165*8975f5c5SAndroid Build Coastguard Worker             for (GLsizei i = 0; i < count; i++)
8166*8975f5c5SAndroid Build Coastguard Worker             {
8167*8975f5c5SAndroid Build Coastguard Worker                 handleGennedResource(context, arrayIDs[i]);
8168*8975f5c5SAndroid Build Coastguard Worker             }
8169*8975f5c5SAndroid Build Coastguard Worker             break;
8170*8975f5c5SAndroid Build Coastguard Worker         }
8171*8975f5c5SAndroid Build Coastguard Worker 
8172*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLDeleteVertexArrays:
8173*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLDeleteVertexArraysOES:
8174*8975f5c5SAndroid Build Coastguard Worker         {
8175*8975f5c5SAndroid Build Coastguard Worker             GLsizei count = call.params.getParam("n", ParamType::TGLsizei, 0).value.GLsizeiVal;
8176*8975f5c5SAndroid Build Coastguard Worker             const gl::VertexArrayID *arrayIDs =
8177*8975f5c5SAndroid Build Coastguard Worker                 call.params.getParam("arraysPacked", ParamType::TVertexArrayIDConstPointer, 1)
8178*8975f5c5SAndroid Build Coastguard Worker                     .value.VertexArrayIDConstPointerVal;
8179*8975f5c5SAndroid Build Coastguard Worker             for (GLsizei i = 0; i < count; i++)
8180*8975f5c5SAndroid Build Coastguard Worker             {
8181*8975f5c5SAndroid Build Coastguard Worker                 // If we're capturing, track which vertex arrays have been deleted
8182*8975f5c5SAndroid Build Coastguard Worker                 handleDeletedResource(context, arrayIDs[i]);
8183*8975f5c5SAndroid Build Coastguard Worker             }
8184*8975f5c5SAndroid Build Coastguard Worker             break;
8185*8975f5c5SAndroid Build Coastguard Worker         }
8186*8975f5c5SAndroid Build Coastguard Worker 
8187*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLBindVertexArray:
8188*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLBindVertexArrayOES:
8189*8975f5c5SAndroid Build Coastguard Worker         {
8190*8975f5c5SAndroid Build Coastguard Worker             if (isCaptureActive())
8191*8975f5c5SAndroid Build Coastguard Worker             {
8192*8975f5c5SAndroid Build Coastguard Worker                 context->getFrameCapture()->getStateResetHelper().setEntryPointDirty(
8193*8975f5c5SAndroid Build Coastguard Worker                     EntryPoint::GLBindVertexArray);
8194*8975f5c5SAndroid Build Coastguard Worker             }
8195*8975f5c5SAndroid Build Coastguard Worker             break;
8196*8975f5c5SAndroid Build Coastguard Worker         }
8197*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLBlendFunc:
8198*8975f5c5SAndroid Build Coastguard Worker         {
8199*8975f5c5SAndroid Build Coastguard Worker             if (isCaptureActive())
8200*8975f5c5SAndroid Build Coastguard Worker             {
8201*8975f5c5SAndroid Build Coastguard Worker                 context->getFrameCapture()->getStateResetHelper().setEntryPointDirty(
8202*8975f5c5SAndroid Build Coastguard Worker                     EntryPoint::GLBlendFunc);
8203*8975f5c5SAndroid Build Coastguard Worker             }
8204*8975f5c5SAndroid Build Coastguard Worker             break;
8205*8975f5c5SAndroid Build Coastguard Worker         }
8206*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLBlendFuncSeparate:
8207*8975f5c5SAndroid Build Coastguard Worker         {
8208*8975f5c5SAndroid Build Coastguard Worker             if (isCaptureActive())
8209*8975f5c5SAndroid Build Coastguard Worker             {
8210*8975f5c5SAndroid Build Coastguard Worker                 context->getFrameCapture()->getStateResetHelper().setEntryPointDirty(
8211*8975f5c5SAndroid Build Coastguard Worker                     EntryPoint::GLBlendFuncSeparate);
8212*8975f5c5SAndroid Build Coastguard Worker             }
8213*8975f5c5SAndroid Build Coastguard Worker             break;
8214*8975f5c5SAndroid Build Coastguard Worker         }
8215*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLBlendEquation:
8216*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLBlendEquationSeparate:
8217*8975f5c5SAndroid Build Coastguard Worker         {
8218*8975f5c5SAndroid Build Coastguard Worker             if (isCaptureActive())
8219*8975f5c5SAndroid Build Coastguard Worker             {
8220*8975f5c5SAndroid Build Coastguard Worker                 context->getFrameCapture()->getStateResetHelper().setEntryPointDirty(
8221*8975f5c5SAndroid Build Coastguard Worker                     EntryPoint::GLBlendEquationSeparate);
8222*8975f5c5SAndroid Build Coastguard Worker             }
8223*8975f5c5SAndroid Build Coastguard Worker             break;
8224*8975f5c5SAndroid Build Coastguard Worker         }
8225*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLColorMask:
8226*8975f5c5SAndroid Build Coastguard Worker         {
8227*8975f5c5SAndroid Build Coastguard Worker             if (isCaptureActive())
8228*8975f5c5SAndroid Build Coastguard Worker             {
8229*8975f5c5SAndroid Build Coastguard Worker                 context->getFrameCapture()->getStateResetHelper().setEntryPointDirty(
8230*8975f5c5SAndroid Build Coastguard Worker                     EntryPoint::GLColorMask);
8231*8975f5c5SAndroid Build Coastguard Worker             }
8232*8975f5c5SAndroid Build Coastguard Worker             break;
8233*8975f5c5SAndroid Build Coastguard Worker         }
8234*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLBlendColor:
8235*8975f5c5SAndroid Build Coastguard Worker         {
8236*8975f5c5SAndroid Build Coastguard Worker             if (isCaptureActive())
8237*8975f5c5SAndroid Build Coastguard Worker             {
8238*8975f5c5SAndroid Build Coastguard Worker                 context->getFrameCapture()->getStateResetHelper().setEntryPointDirty(
8239*8975f5c5SAndroid Build Coastguard Worker                     EntryPoint::GLBlendColor);
8240*8975f5c5SAndroid Build Coastguard Worker             }
8241*8975f5c5SAndroid Build Coastguard Worker             break;
8242*8975f5c5SAndroid Build Coastguard Worker         }
8243*8975f5c5SAndroid Build Coastguard Worker 
8244*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLEGLImageTargetTexture2DOES:
8245*8975f5c5SAndroid Build Coastguard Worker         {
8246*8975f5c5SAndroid Build Coastguard Worker             gl::TextureType target =
8247*8975f5c5SAndroid Build Coastguard Worker                 call.params.getParam("targetPacked", ParamType::TTextureType, 0)
8248*8975f5c5SAndroid Build Coastguard Worker                     .value.TextureTypeVal;
8249*8975f5c5SAndroid Build Coastguard Worker             egl::ImageID imageID =
8250*8975f5c5SAndroid Build Coastguard Worker                 call.params.getParam("imagePacked", ParamType::TImageID, 1).value.ImageIDVal;
8251*8975f5c5SAndroid Build Coastguard Worker             mResourceTracker.getTextureIDToImageTable().insert(std::pair<GLuint, egl::ImageID>(
8252*8975f5c5SAndroid Build Coastguard Worker                 context->getState().getTargetTexture(target)->getId(), imageID));
8253*8975f5c5SAndroid Build Coastguard Worker             break;
8254*8975f5c5SAndroid Build Coastguard Worker         }
8255*8975f5c5SAndroid Build Coastguard Worker 
8256*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::EGLCreateImage:
8257*8975f5c5SAndroid Build Coastguard Worker         {
8258*8975f5c5SAndroid Build Coastguard Worker             CreateEGLImagePreCallUpdate<EGLAttrib>(call, mResourceTracker,
8259*8975f5c5SAndroid Build Coastguard Worker                                                    ParamType::TEGLAttribPointer,
8260*8975f5c5SAndroid Build Coastguard Worker                                                    egl::AttributeMap::CreateFromAttribArray);
8261*8975f5c5SAndroid Build Coastguard Worker             if (isCaptureActive())
8262*8975f5c5SAndroid Build Coastguard Worker             {
8263*8975f5c5SAndroid Build Coastguard Worker                 EGLImage eglImage    = call.params.getReturnValue().value.EGLImageVal;
8264*8975f5c5SAndroid Build Coastguard Worker                 egl::ImageID imageID = egl::PackParam<egl::ImageID>(eglImage);
8265*8975f5c5SAndroid Build Coastguard Worker                 handleGennedResource(context, imageID);
8266*8975f5c5SAndroid Build Coastguard Worker             }
8267*8975f5c5SAndroid Build Coastguard Worker             break;
8268*8975f5c5SAndroid Build Coastguard Worker         }
8269*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::EGLCreateImageKHR:
8270*8975f5c5SAndroid Build Coastguard Worker         {
8271*8975f5c5SAndroid Build Coastguard Worker             CreateEGLImagePreCallUpdate<EGLint>(call, mResourceTracker, ParamType::TEGLintPointer,
8272*8975f5c5SAndroid Build Coastguard Worker                                                 egl::AttributeMap::CreateFromIntArray);
8273*8975f5c5SAndroid Build Coastguard Worker             if (isCaptureActive())
8274*8975f5c5SAndroid Build Coastguard Worker             {
8275*8975f5c5SAndroid Build Coastguard Worker                 EGLImageKHR eglImage = call.params.getReturnValue().value.EGLImageKHRVal;
8276*8975f5c5SAndroid Build Coastguard Worker                 egl::ImageID imageID = egl::PackParam<egl::ImageID>(eglImage);
8277*8975f5c5SAndroid Build Coastguard Worker                 handleGennedResource(context, imageID);
8278*8975f5c5SAndroid Build Coastguard Worker             }
8279*8975f5c5SAndroid Build Coastguard Worker             break;
8280*8975f5c5SAndroid Build Coastguard Worker         }
8281*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::EGLDestroyImage:
8282*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::EGLDestroyImageKHR:
8283*8975f5c5SAndroid Build Coastguard Worker         {
8284*8975f5c5SAndroid Build Coastguard Worker             egl::ImageID eglImageID =
8285*8975f5c5SAndroid Build Coastguard Worker                 call.params.getParam("imagePacked", ParamType::TImageID, 1).value.ImageIDVal;
8286*8975f5c5SAndroid Build Coastguard Worker 
8287*8975f5c5SAndroid Build Coastguard Worker             // Clear any texture->image mappings that involve this image
8288*8975f5c5SAndroid Build Coastguard Worker             for (auto texImageIter = mResourceTracker.getTextureIDToImageTable().begin();
8289*8975f5c5SAndroid Build Coastguard Worker                  texImageIter != mResourceTracker.getTextureIDToImageTable().end();)
8290*8975f5c5SAndroid Build Coastguard Worker             {
8291*8975f5c5SAndroid Build Coastguard Worker                 if (texImageIter->second == eglImageID)
8292*8975f5c5SAndroid Build Coastguard Worker                 {
8293*8975f5c5SAndroid Build Coastguard Worker                     texImageIter = mResourceTracker.getTextureIDToImageTable().erase(texImageIter);
8294*8975f5c5SAndroid Build Coastguard Worker                 }
8295*8975f5c5SAndroid Build Coastguard Worker                 else
8296*8975f5c5SAndroid Build Coastguard Worker                 {
8297*8975f5c5SAndroid Build Coastguard Worker                     ++texImageIter;
8298*8975f5c5SAndroid Build Coastguard Worker                 }
8299*8975f5c5SAndroid Build Coastguard Worker             }
8300*8975f5c5SAndroid Build Coastguard Worker 
8301*8975f5c5SAndroid Build Coastguard Worker             FrameCaptureShared *frameCaptureShared =
8302*8975f5c5SAndroid Build Coastguard Worker                 context->getShareGroup()->getFrameCaptureShared();
8303*8975f5c5SAndroid Build Coastguard Worker             if (frameCaptureShared->isCaptureActive())
8304*8975f5c5SAndroid Build Coastguard Worker             {
8305*8975f5c5SAndroid Build Coastguard Worker                 handleDeletedResource(context, eglImageID);
8306*8975f5c5SAndroid Build Coastguard Worker             }
8307*8975f5c5SAndroid Build Coastguard Worker             break;
8308*8975f5c5SAndroid Build Coastguard Worker         }
8309*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::EGLCreateSync:
8310*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::EGLCreateSyncKHR:
8311*8975f5c5SAndroid Build Coastguard Worker         {
8312*8975f5c5SAndroid Build Coastguard Worker             egl::SyncID eglSyncID = call.params.getReturnValue().value.egl_SyncIDVal;
8313*8975f5c5SAndroid Build Coastguard Worker             FrameCaptureShared *frameCaptureShared =
8314*8975f5c5SAndroid Build Coastguard Worker                 context->getShareGroup()->getFrameCaptureShared();
8315*8975f5c5SAndroid Build Coastguard Worker             // If we're capturing, track which egl sync has been created
8316*8975f5c5SAndroid Build Coastguard Worker             if (frameCaptureShared->isCaptureActive())
8317*8975f5c5SAndroid Build Coastguard Worker             {
8318*8975f5c5SAndroid Build Coastguard Worker                 handleGennedResource(context, eglSyncID);
8319*8975f5c5SAndroid Build Coastguard Worker             }
8320*8975f5c5SAndroid Build Coastguard Worker             break;
8321*8975f5c5SAndroid Build Coastguard Worker         }
8322*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::EGLDestroySync:
8323*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::EGLDestroySyncKHR:
8324*8975f5c5SAndroid Build Coastguard Worker         {
8325*8975f5c5SAndroid Build Coastguard Worker             egl::SyncID eglSyncID =
8326*8975f5c5SAndroid Build Coastguard Worker                 call.params.getParam("syncPacked", ParamType::Tegl_SyncID, 1).value.egl_SyncIDVal;
8327*8975f5c5SAndroid Build Coastguard Worker             FrameCaptureShared *frameCaptureShared =
8328*8975f5c5SAndroid Build Coastguard Worker                 context->getShareGroup()->getFrameCaptureShared();
8329*8975f5c5SAndroid Build Coastguard Worker             // If we're capturing, track which EGL sync has been deleted
8330*8975f5c5SAndroid Build Coastguard Worker             if (frameCaptureShared->isCaptureActive())
8331*8975f5c5SAndroid Build Coastguard Worker             {
8332*8975f5c5SAndroid Build Coastguard Worker                 handleDeletedResource(context, eglSyncID);
8333*8975f5c5SAndroid Build Coastguard Worker             }
8334*8975f5c5SAndroid Build Coastguard Worker             break;
8335*8975f5c5SAndroid Build Coastguard Worker         }
8336*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLDispatchCompute:
8337*8975f5c5SAndroid Build Coastguard Worker         {
8338*8975f5c5SAndroid Build Coastguard Worker             // When using shadow memory we need to update the real memory here
8339*8975f5c5SAndroid Build Coastguard Worker             if (mCoherentBufferTracker.isShadowMemoryEnabled())
8340*8975f5c5SAndroid Build Coastguard Worker             {
8341*8975f5c5SAndroid Build Coastguard Worker                 maybeCaptureCoherentBuffers(context);
8342*8975f5c5SAndroid Build Coastguard Worker             }
8343*8975f5c5SAndroid Build Coastguard Worker             break;
8344*8975f5c5SAndroid Build Coastguard Worker         }
8345*8975f5c5SAndroid Build Coastguard Worker         default:
8346*8975f5c5SAndroid Build Coastguard Worker             break;
8347*8975f5c5SAndroid Build Coastguard Worker     }
8348*8975f5c5SAndroid Build Coastguard Worker 
8349*8975f5c5SAndroid Build Coastguard Worker     if (IsTextureUpdate(call))
8350*8975f5c5SAndroid Build Coastguard Worker     {
8351*8975f5c5SAndroid Build Coastguard Worker         // If this call modified texture contents, track it for possible reset
8352*8975f5c5SAndroid Build Coastguard Worker         trackTextureUpdate(context, call);
8353*8975f5c5SAndroid Build Coastguard Worker     }
8354*8975f5c5SAndroid Build Coastguard Worker 
8355*8975f5c5SAndroid Build Coastguard Worker     if (IsImageUpdate(call))
8356*8975f5c5SAndroid Build Coastguard Worker     {
8357*8975f5c5SAndroid Build Coastguard Worker         // If this call modified shader image contents, track it for possible reset
8358*8975f5c5SAndroid Build Coastguard Worker         trackImageUpdate(context, call);
8359*8975f5c5SAndroid Build Coastguard Worker     }
8360*8975f5c5SAndroid Build Coastguard Worker 
8361*8975f5c5SAndroid Build Coastguard Worker     if (isCaptureActive() && GetDefaultUniformType(call) != DefaultUniformType::None)
8362*8975f5c5SAndroid Build Coastguard Worker     {
8363*8975f5c5SAndroid Build Coastguard Worker         trackDefaultUniformUpdate(context, call);
8364*8975f5c5SAndroid Build Coastguard Worker     }
8365*8975f5c5SAndroid Build Coastguard Worker 
8366*8975f5c5SAndroid Build Coastguard Worker     if (IsVertexArrayUpdate(call))
8367*8975f5c5SAndroid Build Coastguard Worker     {
8368*8975f5c5SAndroid Build Coastguard Worker         trackVertexArrayUpdate(context, call);
8369*8975f5c5SAndroid Build Coastguard Worker     }
8370*8975f5c5SAndroid Build Coastguard Worker 
8371*8975f5c5SAndroid Build Coastguard Worker     updateReadBufferSize(call.params.getReadBufferSize());
8372*8975f5c5SAndroid Build Coastguard Worker 
8373*8975f5c5SAndroid Build Coastguard Worker     std::vector<gl::ShaderProgramID> shaderProgramIDs;
8374*8975f5c5SAndroid Build Coastguard Worker     if (FindResourceIDsInCall<gl::ShaderProgramID>(call, shaderProgramIDs))
8375*8975f5c5SAndroid Build Coastguard Worker     {
8376*8975f5c5SAndroid Build Coastguard Worker         for (gl::ShaderProgramID shaderProgramID : shaderProgramIDs)
8377*8975f5c5SAndroid Build Coastguard Worker         {
8378*8975f5c5SAndroid Build Coastguard Worker             mResourceTracker.onShaderProgramAccess(shaderProgramID);
8379*8975f5c5SAndroid Build Coastguard Worker 
8380*8975f5c5SAndroid Build Coastguard Worker             if (isCaptureActive())
8381*8975f5c5SAndroid Build Coastguard Worker             {
8382*8975f5c5SAndroid Build Coastguard Worker                 // Track that this call referenced a ShaderProgram, setting it active for Setup
8383*8975f5c5SAndroid Build Coastguard Worker                 MarkResourceIDActive(ResourceIDType::ShaderProgram, shaderProgramID.value,
8384*8975f5c5SAndroid Build Coastguard Worker                                      shareGroupSetupCalls, resourceIDToSetupCalls);
8385*8975f5c5SAndroid Build Coastguard Worker             }
8386*8975f5c5SAndroid Build Coastguard Worker         }
8387*8975f5c5SAndroid Build Coastguard Worker     }
8388*8975f5c5SAndroid Build Coastguard Worker 
8389*8975f5c5SAndroid Build Coastguard Worker     std::vector<gl::TextureID> textureIDs;
8390*8975f5c5SAndroid Build Coastguard Worker     if (FindResourceIDsInCall<gl::TextureID>(call, textureIDs))
8391*8975f5c5SAndroid Build Coastguard Worker     {
8392*8975f5c5SAndroid Build Coastguard Worker         for (gl::TextureID textureID : textureIDs)
8393*8975f5c5SAndroid Build Coastguard Worker         {
8394*8975f5c5SAndroid Build Coastguard Worker             if (isCaptureActive())
8395*8975f5c5SAndroid Build Coastguard Worker             {
8396*8975f5c5SAndroid Build Coastguard Worker                 // Track that this call referenced a Texture, setting it active for Setup
8397*8975f5c5SAndroid Build Coastguard Worker                 MarkResourceIDActive(ResourceIDType::Texture, textureID.value, shareGroupSetupCalls,
8398*8975f5c5SAndroid Build Coastguard Worker                                      resourceIDToSetupCalls);
8399*8975f5c5SAndroid Build Coastguard Worker             }
8400*8975f5c5SAndroid Build Coastguard Worker         }
8401*8975f5c5SAndroid Build Coastguard Worker     }
8402*8975f5c5SAndroid Build Coastguard Worker }
8403*8975f5c5SAndroid Build Coastguard Worker 
8404*8975f5c5SAndroid Build Coastguard Worker template <typename ParamValueType>
maybeGenResourceOnBind(const gl::Context * context,CallCapture & call)8405*8975f5c5SAndroid Build Coastguard Worker void FrameCaptureShared::maybeGenResourceOnBind(const gl::Context *context, CallCapture &call)
8406*8975f5c5SAndroid Build Coastguard Worker {
8407*8975f5c5SAndroid Build Coastguard Worker     const char *paramName     = ParamValueTrait<ParamValueType>::name;
8408*8975f5c5SAndroid Build Coastguard Worker     const ParamType paramType = ParamValueTrait<ParamValueType>::typeID;
8409*8975f5c5SAndroid Build Coastguard Worker 
8410*8975f5c5SAndroid Build Coastguard Worker     const ParamCapture &param = call.params.getParam(paramName, paramType, 1);
8411*8975f5c5SAndroid Build Coastguard Worker     const ParamValueType id   = AccessParamValue<ParamValueType>(paramType, param.value);
8412*8975f5c5SAndroid Build Coastguard Worker 
8413*8975f5c5SAndroid Build Coastguard Worker     // Don't inject the default resource or resources that are already generated
8414*8975f5c5SAndroid Build Coastguard Worker     if (id.value != 0 && !resourceIsGenerated(context, id))
8415*8975f5c5SAndroid Build Coastguard Worker     {
8416*8975f5c5SAndroid Build Coastguard Worker         handleGennedResource(context, id);
8417*8975f5c5SAndroid Build Coastguard Worker 
8418*8975f5c5SAndroid Build Coastguard Worker         ResourceIDType resourceIDType = GetResourceIDTypeFromParamType(param.type);
8419*8975f5c5SAndroid Build Coastguard Worker         const char *resourceName      = GetResourceIDTypeName(resourceIDType);
8420*8975f5c5SAndroid Build Coastguard Worker 
8421*8975f5c5SAndroid Build Coastguard Worker         std::stringstream updateFuncNameStr;
8422*8975f5c5SAndroid Build Coastguard Worker         updateFuncNameStr << "Set" << resourceName << "ID";
8423*8975f5c5SAndroid Build Coastguard Worker         ParamBuffer params;
8424*8975f5c5SAndroid Build Coastguard Worker         if (IsTrackedPerContext(resourceIDType))
8425*8975f5c5SAndroid Build Coastguard Worker         {
8426*8975f5c5SAndroid Build Coastguard Worker             // TODO (https://issuetracker.google.com/169868803) The '2' version can be removed after
8427*8975f5c5SAndroid Build Coastguard Worker             // all context-local objects are tracked per-context
8428*8975f5c5SAndroid Build Coastguard Worker             updateFuncNameStr << "2";
8429*8975f5c5SAndroid Build Coastguard Worker             params.addValueParam("contextID", ParamType::TGLuint, context->id().value);
8430*8975f5c5SAndroid Build Coastguard Worker         }
8431*8975f5c5SAndroid Build Coastguard Worker         std::string updateFuncName = updateFuncNameStr.str();
8432*8975f5c5SAndroid Build Coastguard Worker         params.addValueParam("id", ParamType::TGLuint, id.value);
8433*8975f5c5SAndroid Build Coastguard Worker         mFrameCalls.emplace_back(updateFuncName, std::move(params));
8434*8975f5c5SAndroid Build Coastguard Worker     }
8435*8975f5c5SAndroid Build Coastguard Worker }
8436*8975f5c5SAndroid Build Coastguard Worker 
updateResourceCountsFromParamCapture(const ParamCapture & param,ResourceIDType idType)8437*8975f5c5SAndroid Build Coastguard Worker void FrameCaptureShared::updateResourceCountsFromParamCapture(const ParamCapture &param,
8438*8975f5c5SAndroid Build Coastguard Worker                                                               ResourceIDType idType)
8439*8975f5c5SAndroid Build Coastguard Worker {
8440*8975f5c5SAndroid Build Coastguard Worker     if (idType != ResourceIDType::InvalidEnum)
8441*8975f5c5SAndroid Build Coastguard Worker     {
8442*8975f5c5SAndroid Build Coastguard Worker         mHasResourceType.set(idType);
8443*8975f5c5SAndroid Build Coastguard Worker 
8444*8975f5c5SAndroid Build Coastguard Worker         // Capture resource IDs for non-pointer types.
8445*8975f5c5SAndroid Build Coastguard Worker         if (strcmp(ParamTypeToString(param.type), "GLuint") == 0)
8446*8975f5c5SAndroid Build Coastguard Worker         {
8447*8975f5c5SAndroid Build Coastguard Worker             mMaxAccessedResourceIDs[idType] =
8448*8975f5c5SAndroid Build Coastguard Worker                 std::max(mMaxAccessedResourceIDs[idType], param.value.GLuintVal);
8449*8975f5c5SAndroid Build Coastguard Worker         }
8450*8975f5c5SAndroid Build Coastguard Worker         // Capture resource IDs for pointer types.
8451*8975f5c5SAndroid Build Coastguard Worker         if (strstr(ParamTypeToString(param.type), "GLuint *") != nullptr)
8452*8975f5c5SAndroid Build Coastguard Worker         {
8453*8975f5c5SAndroid Build Coastguard Worker             if (param.data.size() == 1u)
8454*8975f5c5SAndroid Build Coastguard Worker             {
8455*8975f5c5SAndroid Build Coastguard Worker                 const GLuint *dataPtr = reinterpret_cast<const GLuint *>(param.data[0].data());
8456*8975f5c5SAndroid Build Coastguard Worker                 size_t numHandles     = param.data[0].size() / sizeof(GLuint);
8457*8975f5c5SAndroid Build Coastguard Worker                 for (size_t handleIndex = 0; handleIndex < numHandles; ++handleIndex)
8458*8975f5c5SAndroid Build Coastguard Worker                 {
8459*8975f5c5SAndroid Build Coastguard Worker                     mMaxAccessedResourceIDs[idType] =
8460*8975f5c5SAndroid Build Coastguard Worker                         std::max(mMaxAccessedResourceIDs[idType], dataPtr[handleIndex]);
8461*8975f5c5SAndroid Build Coastguard Worker                 }
8462*8975f5c5SAndroid Build Coastguard Worker             }
8463*8975f5c5SAndroid Build Coastguard Worker         }
8464*8975f5c5SAndroid Build Coastguard Worker         if (idType == ResourceIDType::Sync)
8465*8975f5c5SAndroid Build Coastguard Worker         {
8466*8975f5c5SAndroid Build Coastguard Worker             mMaxAccessedResourceIDs[idType] =
8467*8975f5c5SAndroid Build Coastguard Worker                 std::max(mMaxAccessedResourceIDs[idType], param.value.GLuintVal);
8468*8975f5c5SAndroid Build Coastguard Worker         }
8469*8975f5c5SAndroid Build Coastguard Worker     }
8470*8975f5c5SAndroid Build Coastguard Worker }
8471*8975f5c5SAndroid Build Coastguard Worker 
updateResourceCountsFromCallCapture(const CallCapture & call)8472*8975f5c5SAndroid Build Coastguard Worker void FrameCaptureShared::updateResourceCountsFromCallCapture(const CallCapture &call)
8473*8975f5c5SAndroid Build Coastguard Worker {
8474*8975f5c5SAndroid Build Coastguard Worker     for (const ParamCapture &param : call.params.getParamCaptures())
8475*8975f5c5SAndroid Build Coastguard Worker     {
8476*8975f5c5SAndroid Build Coastguard Worker         ResourceIDType idType = GetResourceIDTypeFromParamType(param.type);
8477*8975f5c5SAndroid Build Coastguard Worker         updateResourceCountsFromParamCapture(param, idType);
8478*8975f5c5SAndroid Build Coastguard Worker     }
8479*8975f5c5SAndroid Build Coastguard Worker 
8480*8975f5c5SAndroid Build Coastguard Worker     // Update resource IDs in the return value. Return values types are not stored as resource IDs,
8481*8975f5c5SAndroid Build Coastguard Worker     // but instead are stored as GLuints. Therefore we need to explicitly label the resource ID type
8482*8975f5c5SAndroid Build Coastguard Worker     // when we call update. Currently only shader and program creation are explicitly tracked.
8483*8975f5c5SAndroid Build Coastguard Worker     switch (call.entryPoint)
8484*8975f5c5SAndroid Build Coastguard Worker     {
8485*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLCreateShader:
8486*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLCreateProgram:
8487*8975f5c5SAndroid Build Coastguard Worker             updateResourceCountsFromParamCapture(call.params.getReturnValue(),
8488*8975f5c5SAndroid Build Coastguard Worker                                                  ResourceIDType::ShaderProgram);
8489*8975f5c5SAndroid Build Coastguard Worker             break;
8490*8975f5c5SAndroid Build Coastguard Worker 
8491*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLFenceSync:
8492*8975f5c5SAndroid Build Coastguard Worker             updateResourceCountsFromParamCapture(call.params.getReturnValue(),
8493*8975f5c5SAndroid Build Coastguard Worker                                                  ResourceIDType::Sync);
8494*8975f5c5SAndroid Build Coastguard Worker             break;
8495*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::EGLCreateSync:
8496*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::EGLCreateSyncKHR:
8497*8975f5c5SAndroid Build Coastguard Worker             updateResourceCountsFromParamCapture(call.params.getReturnValue(),
8498*8975f5c5SAndroid Build Coastguard Worker                                                  ResourceIDType::egl_Sync);
8499*8975f5c5SAndroid Build Coastguard Worker             break;
8500*8975f5c5SAndroid Build Coastguard Worker         default:
8501*8975f5c5SAndroid Build Coastguard Worker             break;
8502*8975f5c5SAndroid Build Coastguard Worker     }
8503*8975f5c5SAndroid Build Coastguard Worker }
8504*8975f5c5SAndroid Build Coastguard Worker 
captureCall(gl::Context * context,CallCapture && inCall,bool isCallValid)8505*8975f5c5SAndroid Build Coastguard Worker void FrameCaptureShared::captureCall(gl::Context *context, CallCapture &&inCall, bool isCallValid)
8506*8975f5c5SAndroid Build Coastguard Worker {
8507*8975f5c5SAndroid Build Coastguard Worker     if (SkipCall(inCall.entryPoint))
8508*8975f5c5SAndroid Build Coastguard Worker     {
8509*8975f5c5SAndroid Build Coastguard Worker         return;
8510*8975f5c5SAndroid Build Coastguard Worker     }
8511*8975f5c5SAndroid Build Coastguard Worker 
8512*8975f5c5SAndroid Build Coastguard Worker     if (isCallValid)
8513*8975f5c5SAndroid Build Coastguard Worker     {
8514*8975f5c5SAndroid Build Coastguard Worker         // Save the call's contextID
8515*8975f5c5SAndroid Build Coastguard Worker         inCall.contextID = context->id();
8516*8975f5c5SAndroid Build Coastguard Worker 
8517*8975f5c5SAndroid Build Coastguard Worker         // Update resource counts before we override entry points with custom calls.
8518*8975f5c5SAndroid Build Coastguard Worker         updateResourceCountsFromCallCapture(inCall);
8519*8975f5c5SAndroid Build Coastguard Worker 
8520*8975f5c5SAndroid Build Coastguard Worker         size_t j = mFrameCalls.size();
8521*8975f5c5SAndroid Build Coastguard Worker 
8522*8975f5c5SAndroid Build Coastguard Worker         std::vector<CallCapture> outCalls;
8523*8975f5c5SAndroid Build Coastguard Worker         maybeOverrideEntryPoint(context, inCall, outCalls);
8524*8975f5c5SAndroid Build Coastguard Worker 
8525*8975f5c5SAndroid Build Coastguard Worker         // Need to loop on any new calls we added during override
8526*8975f5c5SAndroid Build Coastguard Worker         for (CallCapture &call : outCalls)
8527*8975f5c5SAndroid Build Coastguard Worker         {
8528*8975f5c5SAndroid Build Coastguard Worker             // During capture, consider all frame calls active
8529*8975f5c5SAndroid Build Coastguard Worker             if (isCaptureActive())
8530*8975f5c5SAndroid Build Coastguard Worker             {
8531*8975f5c5SAndroid Build Coastguard Worker                 call.isActive = true;
8532*8975f5c5SAndroid Build Coastguard Worker             }
8533*8975f5c5SAndroid Build Coastguard Worker 
8534*8975f5c5SAndroid Build Coastguard Worker             maybeCapturePreCallUpdates(context, call, &mShareGroupSetupCalls,
8535*8975f5c5SAndroid Build Coastguard Worker                                        &mResourceIDToSetupCalls);
8536*8975f5c5SAndroid Build Coastguard Worker             mFrameCalls.emplace_back(std::move(call));
8537*8975f5c5SAndroid Build Coastguard Worker             maybeCapturePostCallUpdates(context);
8538*8975f5c5SAndroid Build Coastguard Worker         }
8539*8975f5c5SAndroid Build Coastguard Worker 
8540*8975f5c5SAndroid Build Coastguard Worker         // Tag all 'added' commands with this context
8541*8975f5c5SAndroid Build Coastguard Worker         for (size_t k = j; k < mFrameCalls.size(); k++)
8542*8975f5c5SAndroid Build Coastguard Worker         {
8543*8975f5c5SAndroid Build Coastguard Worker             mFrameCalls[k].contextID = context->id();
8544*8975f5c5SAndroid Build Coastguard Worker         }
8545*8975f5c5SAndroid Build Coastguard Worker 
8546*8975f5c5SAndroid Build Coastguard Worker         // Evaluate the validation expression to determine if we insert a validation checkpoint.
8547*8975f5c5SAndroid Build Coastguard Worker         // This lets the user pick a subset of calls to check instead of checking every call.
8548*8975f5c5SAndroid Build Coastguard Worker         if (mValidateSerializedState && !mValidationExpression.empty())
8549*8975f5c5SAndroid Build Coastguard Worker         {
8550*8975f5c5SAndroid Build Coastguard Worker             // Example substitution for frame #2, call #110:
8551*8975f5c5SAndroid Build Coastguard Worker             // Before: (call == 2) && (frame >= 100) && (frame <= 120) && ((frame % 10) == 0)
8552*8975f5c5SAndroid Build Coastguard Worker             // After:  (2 == 2) && (110 >= 100) && (110 <= 120) && ((110 % 10) == 0)
8553*8975f5c5SAndroid Build Coastguard Worker             // Evaluates to 1.0.
8554*8975f5c5SAndroid Build Coastguard Worker             std::string expression = mValidationExpression;
8555*8975f5c5SAndroid Build Coastguard Worker 
8556*8975f5c5SAndroid Build Coastguard Worker             angle::ReplaceAllSubstrings(&expression, "frame", std::to_string(mFrameIndex));
8557*8975f5c5SAndroid Build Coastguard Worker             angle::ReplaceAllSubstrings(&expression, "call", std::to_string(mFrameCalls.size()));
8558*8975f5c5SAndroid Build Coastguard Worker 
8559*8975f5c5SAndroid Build Coastguard Worker             double result = ceval_result(expression);
8560*8975f5c5SAndroid Build Coastguard Worker             if (result > 0)
8561*8975f5c5SAndroid Build Coastguard Worker             {
8562*8975f5c5SAndroid Build Coastguard Worker                 CaptureValidateSerializedState(context, &mFrameCalls);
8563*8975f5c5SAndroid Build Coastguard Worker             }
8564*8975f5c5SAndroid Build Coastguard Worker         }
8565*8975f5c5SAndroid Build Coastguard Worker     }
8566*8975f5c5SAndroid Build Coastguard Worker     else
8567*8975f5c5SAndroid Build Coastguard Worker     {
8568*8975f5c5SAndroid Build Coastguard Worker         const int maxInvalidCallLogs = 3;
8569*8975f5c5SAndroid Build Coastguard Worker         size_t &callCount = isCaptureActive() ? mInvalidCallCountsActive[inCall.entryPoint]
8570*8975f5c5SAndroid Build Coastguard Worker                                               : mInvalidCallCountsInactive[inCall.entryPoint];
8571*8975f5c5SAndroid Build Coastguard Worker         callCount++;
8572*8975f5c5SAndroid Build Coastguard Worker         if (callCount <= maxInvalidCallLogs)
8573*8975f5c5SAndroid Build Coastguard Worker         {
8574*8975f5c5SAndroid Build Coastguard Worker             std::ostringstream msg;
8575*8975f5c5SAndroid Build Coastguard Worker             msg << "FrameCapture (capture " << (isCaptureActive() ? "active" : "inactive")
8576*8975f5c5SAndroid Build Coastguard Worker                 << "): Not capturing invalid call to " << GetEntryPointName(inCall.entryPoint);
8577*8975f5c5SAndroid Build Coastguard Worker             if (callCount == maxInvalidCallLogs)
8578*8975f5c5SAndroid Build Coastguard Worker             {
8579*8975f5c5SAndroid Build Coastguard Worker                 msg << " (will no longer repeat for this entry point)";
8580*8975f5c5SAndroid Build Coastguard Worker             }
8581*8975f5c5SAndroid Build Coastguard Worker             INFO() << msg.str();
8582*8975f5c5SAndroid Build Coastguard Worker         }
8583*8975f5c5SAndroid Build Coastguard Worker 
8584*8975f5c5SAndroid Build Coastguard Worker         std::stringstream skipCall;
8585*8975f5c5SAndroid Build Coastguard Worker         skipCall << "Skipping invalid call to " << GetEntryPointName(inCall.entryPoint)
8586*8975f5c5SAndroid Build Coastguard Worker                  << " with error: "
8587*8975f5c5SAndroid Build Coastguard Worker                  << gl::GLenumToString(gl::GLESEnum::ErrorCode, context->getErrorForCapture());
8588*8975f5c5SAndroid Build Coastguard Worker         AddComment(&mFrameCalls, skipCall.str());
8589*8975f5c5SAndroid Build Coastguard Worker     }
8590*8975f5c5SAndroid Build Coastguard Worker }
8591*8975f5c5SAndroid Build Coastguard Worker 
maybeCapturePostCallUpdates(const gl::Context * context)8592*8975f5c5SAndroid Build Coastguard Worker void FrameCaptureShared::maybeCapturePostCallUpdates(const gl::Context *context)
8593*8975f5c5SAndroid Build Coastguard Worker {
8594*8975f5c5SAndroid Build Coastguard Worker     // Process resource ID updates.
8595*8975f5c5SAndroid Build Coastguard Worker     if (isCaptureActive())
8596*8975f5c5SAndroid Build Coastguard Worker     {
8597*8975f5c5SAndroid Build Coastguard Worker         MaybeCaptureUpdateResourceIDs(context, &mResourceTracker, &mFrameCalls);
8598*8975f5c5SAndroid Build Coastguard Worker     }
8599*8975f5c5SAndroid Build Coastguard Worker 
8600*8975f5c5SAndroid Build Coastguard Worker     CallCapture &lastCall = mFrameCalls.back();
8601*8975f5c5SAndroid Build Coastguard Worker     switch (lastCall.entryPoint)
8602*8975f5c5SAndroid Build Coastguard Worker     {
8603*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLCreateShaderProgramv:
8604*8975f5c5SAndroid Build Coastguard Worker         {
8605*8975f5c5SAndroid Build Coastguard Worker             gl::ShaderProgramID programId;
8606*8975f5c5SAndroid Build Coastguard Worker             programId.value            = lastCall.params.getReturnValue().value.GLuintVal;
8607*8975f5c5SAndroid Build Coastguard Worker             const gl::Program *program = context->getProgramResolveLink(programId);
8608*8975f5c5SAndroid Build Coastguard Worker             CaptureUpdateUniformLocations(program, &mFrameCalls);
8609*8975f5c5SAndroid Build Coastguard Worker             CaptureUpdateUniformBlockIndexes(program, &mFrameCalls);
8610*8975f5c5SAndroid Build Coastguard Worker             break;
8611*8975f5c5SAndroid Build Coastguard Worker         }
8612*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLLinkProgram:
8613*8975f5c5SAndroid Build Coastguard Worker         {
8614*8975f5c5SAndroid Build Coastguard Worker             const ParamCapture &param =
8615*8975f5c5SAndroid Build Coastguard Worker                 lastCall.params.getParam("programPacked", ParamType::TShaderProgramID, 0);
8616*8975f5c5SAndroid Build Coastguard Worker             const gl::Program *program =
8617*8975f5c5SAndroid Build Coastguard Worker                 context->getProgramResolveLink(param.value.ShaderProgramIDVal);
8618*8975f5c5SAndroid Build Coastguard Worker             CaptureUpdateUniformLocations(program, &mFrameCalls);
8619*8975f5c5SAndroid Build Coastguard Worker             CaptureUpdateUniformBlockIndexes(program, &mFrameCalls);
8620*8975f5c5SAndroid Build Coastguard Worker             break;
8621*8975f5c5SAndroid Build Coastguard Worker         }
8622*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLUseProgram:
8623*8975f5c5SAndroid Build Coastguard Worker             CaptureUpdateCurrentProgram(lastCall, 0, &mFrameCalls);
8624*8975f5c5SAndroid Build Coastguard Worker             break;
8625*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLActiveShaderProgram:
8626*8975f5c5SAndroid Build Coastguard Worker             CaptureUpdateCurrentProgram(lastCall, 1, &mFrameCalls);
8627*8975f5c5SAndroid Build Coastguard Worker             break;
8628*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLDeleteProgram:
8629*8975f5c5SAndroid Build Coastguard Worker         {
8630*8975f5c5SAndroid Build Coastguard Worker             const ParamCapture &param =
8631*8975f5c5SAndroid Build Coastguard Worker                 lastCall.params.getParam("programPacked", ParamType::TShaderProgramID, 0);
8632*8975f5c5SAndroid Build Coastguard Worker             CaptureDeleteUniformLocations(param.value.ShaderProgramIDVal, &mFrameCalls);
8633*8975f5c5SAndroid Build Coastguard Worker             break;
8634*8975f5c5SAndroid Build Coastguard Worker         }
8635*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLShaderSource:
8636*8975f5c5SAndroid Build Coastguard Worker         {
8637*8975f5c5SAndroid Build Coastguard Worker             lastCall.params.setValueParamAtIndex("count", ParamType::TGLsizei, 1, 1);
8638*8975f5c5SAndroid Build Coastguard Worker 
8639*8975f5c5SAndroid Build Coastguard Worker             ParamCapture &paramLength =
8640*8975f5c5SAndroid Build Coastguard Worker                 lastCall.params.getParam("length", ParamType::TGLintConstPointer, 3);
8641*8975f5c5SAndroid Build Coastguard Worker             paramLength.data.resize(1);
8642*8975f5c5SAndroid Build Coastguard Worker             // Set the length parameter to {-1} to signal that the actual string length
8643*8975f5c5SAndroid Build Coastguard Worker             // is to be used. Since we store the parameter blob as an array of four uint8_t
8644*8975f5c5SAndroid Build Coastguard Worker             // values, we have to pass the binary equivalent of -1.
8645*8975f5c5SAndroid Build Coastguard Worker             paramLength.data[0] = {0xff, 0xff, 0xff, 0xff};
8646*8975f5c5SAndroid Build Coastguard Worker             break;
8647*8975f5c5SAndroid Build Coastguard Worker         }
8648*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLBufferData:
8649*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLBufferSubData:
8650*8975f5c5SAndroid Build Coastguard Worker         {
8651*8975f5c5SAndroid Build Coastguard Worker             // When using shadow memory we need to update it from real memory here
8652*8975f5c5SAndroid Build Coastguard Worker             if (mCoherentBufferTracker.isShadowMemoryEnabled())
8653*8975f5c5SAndroid Build Coastguard Worker             {
8654*8975f5c5SAndroid Build Coastguard Worker                 gl::BufferBinding target =
8655*8975f5c5SAndroid Build Coastguard Worker                     lastCall.params.getParam("targetPacked", ParamType::TBufferBinding, 0)
8656*8975f5c5SAndroid Build Coastguard Worker                         .value.BufferBindingVal;
8657*8975f5c5SAndroid Build Coastguard Worker 
8658*8975f5c5SAndroid Build Coastguard Worker                 gl::Buffer *buffer = context->getState().getTargetBuffer(target);
8659*8975f5c5SAndroid Build Coastguard Worker                 if (mCoherentBufferTracker.haveBuffer(buffer->id()))
8660*8975f5c5SAndroid Build Coastguard Worker                 {
8661*8975f5c5SAndroid Build Coastguard Worker                     std::shared_ptr<CoherentBuffer> cb =
8662*8975f5c5SAndroid Build Coastguard Worker                         mCoherentBufferTracker.mBuffers[buffer->id().value];
8663*8975f5c5SAndroid Build Coastguard Worker                     cb->removeProtection(PageSharingType::NoneShared);
8664*8975f5c5SAndroid Build Coastguard Worker                     cb->updateShadowMemory();
8665*8975f5c5SAndroid Build Coastguard Worker                     cb->protectAll();
8666*8975f5c5SAndroid Build Coastguard Worker                 }
8667*8975f5c5SAndroid Build Coastguard Worker             }
8668*8975f5c5SAndroid Build Coastguard Worker             break;
8669*8975f5c5SAndroid Build Coastguard Worker         }
8670*8975f5c5SAndroid Build Coastguard Worker 
8671*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLCopyBufferSubData:
8672*8975f5c5SAndroid Build Coastguard Worker         {
8673*8975f5c5SAndroid Build Coastguard Worker             // When using shadow memory, we need to mark the buffer shadowDirty bit to true
8674*8975f5c5SAndroid Build Coastguard Worker             // so it will be synchronized with real memory on the next glFinish call.
8675*8975f5c5SAndroid Build Coastguard Worker             if (mCoherentBufferTracker.isShadowMemoryEnabled())
8676*8975f5c5SAndroid Build Coastguard Worker             {
8677*8975f5c5SAndroid Build Coastguard Worker                 gl::BufferBinding target =
8678*8975f5c5SAndroid Build Coastguard Worker                     lastCall.params.getParam("writeTargetPacked", ParamType::TBufferBinding, 1)
8679*8975f5c5SAndroid Build Coastguard Worker                         .value.BufferBindingVal;
8680*8975f5c5SAndroid Build Coastguard Worker 
8681*8975f5c5SAndroid Build Coastguard Worker                 gl::Buffer *buffer = context->getState().getTargetBuffer(target);
8682*8975f5c5SAndroid Build Coastguard Worker                 if (mCoherentBufferTracker.haveBuffer(buffer->id()))
8683*8975f5c5SAndroid Build Coastguard Worker                 {
8684*8975f5c5SAndroid Build Coastguard Worker                     std::shared_ptr<CoherentBuffer> cb =
8685*8975f5c5SAndroid Build Coastguard Worker                         mCoherentBufferTracker.mBuffers[buffer->id().value];
8686*8975f5c5SAndroid Build Coastguard Worker                     // This needs to be synced on glFinish
8687*8975f5c5SAndroid Build Coastguard Worker                     cb->markShadowDirty();
8688*8975f5c5SAndroid Build Coastguard Worker                 }
8689*8975f5c5SAndroid Build Coastguard Worker             }
8690*8975f5c5SAndroid Build Coastguard Worker             break;
8691*8975f5c5SAndroid Build Coastguard Worker         }
8692*8975f5c5SAndroid Build Coastguard Worker         case EntryPoint::GLDispatchCompute:
8693*8975f5c5SAndroid Build Coastguard Worker         {
8694*8975f5c5SAndroid Build Coastguard Worker             // When using shadow memory, we need to mark all buffer's shadowDirty bit to true
8695*8975f5c5SAndroid Build Coastguard Worker             // so they will be synchronized with real memory on the next glFinish call.
8696*8975f5c5SAndroid Build Coastguard Worker             if (mCoherentBufferTracker.isShadowMemoryEnabled())
8697*8975f5c5SAndroid Build Coastguard Worker             {
8698*8975f5c5SAndroid Build Coastguard Worker                 mCoherentBufferTracker.markAllShadowDirty();
8699*8975f5c5SAndroid Build Coastguard Worker             }
8700*8975f5c5SAndroid Build Coastguard Worker             break;
8701*8975f5c5SAndroid Build Coastguard Worker         }
8702*8975f5c5SAndroid Build Coastguard Worker         default:
8703*8975f5c5SAndroid Build Coastguard Worker             break;
8704*8975f5c5SAndroid Build Coastguard Worker     }
8705*8975f5c5SAndroid Build Coastguard Worker }
8706*8975f5c5SAndroid Build Coastguard Worker 
captureClientArraySnapshot(const gl::Context * context,size_t vertexCount,size_t instanceCount)8707*8975f5c5SAndroid Build Coastguard Worker void FrameCaptureShared::captureClientArraySnapshot(const gl::Context *context,
8708*8975f5c5SAndroid Build Coastguard Worker                                                     size_t vertexCount,
8709*8975f5c5SAndroid Build Coastguard Worker                                                     size_t instanceCount)
8710*8975f5c5SAndroid Build Coastguard Worker {
8711*8975f5c5SAndroid Build Coastguard Worker     if (vertexCount == 0)
8712*8975f5c5SAndroid Build Coastguard Worker     {
8713*8975f5c5SAndroid Build Coastguard Worker         // Nothing to capture
8714*8975f5c5SAndroid Build Coastguard Worker         return;
8715*8975f5c5SAndroid Build Coastguard Worker     }
8716*8975f5c5SAndroid Build Coastguard Worker 
8717*8975f5c5SAndroid Build Coastguard Worker     const gl::VertexArray *vao = context->getState().getVertexArray();
8718*8975f5c5SAndroid Build Coastguard Worker 
8719*8975f5c5SAndroid Build Coastguard Worker     // Capture client array data.
8720*8975f5c5SAndroid Build Coastguard Worker     for (size_t attribIndex : context->getStateCache().getActiveClientAttribsMask())
8721*8975f5c5SAndroid Build Coastguard Worker     {
8722*8975f5c5SAndroid Build Coastguard Worker         const gl::VertexAttribute &attrib = vao->getVertexAttribute(attribIndex);
8723*8975f5c5SAndroid Build Coastguard Worker         const gl::VertexBinding &binding  = vao->getVertexBinding(attrib.bindingIndex);
8724*8975f5c5SAndroid Build Coastguard Worker 
8725*8975f5c5SAndroid Build Coastguard Worker         int callIndex = mClientVertexArrayMap[attribIndex];
8726*8975f5c5SAndroid Build Coastguard Worker 
8727*8975f5c5SAndroid Build Coastguard Worker         if (callIndex != -1)
8728*8975f5c5SAndroid Build Coastguard Worker         {
8729*8975f5c5SAndroid Build Coastguard Worker             size_t count = vertexCount;
8730*8975f5c5SAndroid Build Coastguard Worker 
8731*8975f5c5SAndroid Build Coastguard Worker             if (binding.getDivisor() > 0)
8732*8975f5c5SAndroid Build Coastguard Worker             {
8733*8975f5c5SAndroid Build Coastguard Worker                 count = rx::UnsignedCeilDivide(static_cast<uint32_t>(instanceCount),
8734*8975f5c5SAndroid Build Coastguard Worker                                                binding.getDivisor());
8735*8975f5c5SAndroid Build Coastguard Worker             }
8736*8975f5c5SAndroid Build Coastguard Worker 
8737*8975f5c5SAndroid Build Coastguard Worker             // The last capture element doesn't take up the full stride.
8738*8975f5c5SAndroid Build Coastguard Worker             size_t bytesToCapture = (count - 1) * binding.getStride() + attrib.format->pixelBytes;
8739*8975f5c5SAndroid Build Coastguard Worker 
8740*8975f5c5SAndroid Build Coastguard Worker             CallCapture &call   = mFrameCalls[callIndex];
8741*8975f5c5SAndroid Build Coastguard Worker             ParamCapture &param = call.params.getClientArrayPointerParameter();
8742*8975f5c5SAndroid Build Coastguard Worker             ASSERT(param.type == ParamType::TvoidConstPointer);
8743*8975f5c5SAndroid Build Coastguard Worker 
8744*8975f5c5SAndroid Build Coastguard Worker             ParamBuffer updateParamBuffer;
8745*8975f5c5SAndroid Build Coastguard Worker             updateParamBuffer.addValueParam<GLint>("arrayIndex", ParamType::TGLint,
8746*8975f5c5SAndroid Build Coastguard Worker                                                    static_cast<uint32_t>(attribIndex));
8747*8975f5c5SAndroid Build Coastguard Worker 
8748*8975f5c5SAndroid Build Coastguard Worker             ParamCapture updateMemory("pointer", ParamType::TvoidConstPointer);
8749*8975f5c5SAndroid Build Coastguard Worker             CaptureMemory(param.value.voidConstPointerVal, bytesToCapture, &updateMemory);
8750*8975f5c5SAndroid Build Coastguard Worker             updateParamBuffer.addParam(std::move(updateMemory));
8751*8975f5c5SAndroid Build Coastguard Worker 
8752*8975f5c5SAndroid Build Coastguard Worker             updateParamBuffer.addValueParam<GLuint64>("size", ParamType::TGLuint64, bytesToCapture);
8753*8975f5c5SAndroid Build Coastguard Worker 
8754*8975f5c5SAndroid Build Coastguard Worker             mFrameCalls.emplace_back("UpdateClientArrayPointer", std::move(updateParamBuffer));
8755*8975f5c5SAndroid Build Coastguard Worker 
8756*8975f5c5SAndroid Build Coastguard Worker             mClientArraySizes[attribIndex] =
8757*8975f5c5SAndroid Build Coastguard Worker                 std::max(mClientArraySizes[attribIndex], bytesToCapture);
8758*8975f5c5SAndroid Build Coastguard Worker         }
8759*8975f5c5SAndroid Build Coastguard Worker     }
8760*8975f5c5SAndroid Build Coastguard Worker }
8761*8975f5c5SAndroid Build Coastguard Worker 
captureCoherentBufferSnapshot(const gl::Context * context,gl::BufferID id)8762*8975f5c5SAndroid Build Coastguard Worker void FrameCaptureShared::captureCoherentBufferSnapshot(const gl::Context *context, gl::BufferID id)
8763*8975f5c5SAndroid Build Coastguard Worker {
8764*8975f5c5SAndroid Build Coastguard Worker     if (!hasBufferData(id))
8765*8975f5c5SAndroid Build Coastguard Worker     {
8766*8975f5c5SAndroid Build Coastguard Worker         // This buffer was not marked writable
8767*8975f5c5SAndroid Build Coastguard Worker         return;
8768*8975f5c5SAndroid Build Coastguard Worker     }
8769*8975f5c5SAndroid Build Coastguard Worker 
8770*8975f5c5SAndroid Build Coastguard Worker     const gl::State &apiState        = context->getState();
8771*8975f5c5SAndroid Build Coastguard Worker     const gl::BufferManager &buffers = apiState.getBufferManagerForCapture();
8772*8975f5c5SAndroid Build Coastguard Worker     gl::Buffer *buffer               = buffers.getBuffer(id);
8773*8975f5c5SAndroid Build Coastguard Worker     if (!buffer)
8774*8975f5c5SAndroid Build Coastguard Worker     {
8775*8975f5c5SAndroid Build Coastguard Worker         // Could not find buffer binding
8776*8975f5c5SAndroid Build Coastguard Worker         return;
8777*8975f5c5SAndroid Build Coastguard Worker     }
8778*8975f5c5SAndroid Build Coastguard Worker 
8779*8975f5c5SAndroid Build Coastguard Worker     ASSERT(buffer->isMapped());
8780*8975f5c5SAndroid Build Coastguard Worker 
8781*8975f5c5SAndroid Build Coastguard Worker     std::shared_ptr<angle::CoherentBuffer> coherentBuffer =
8782*8975f5c5SAndroid Build Coastguard Worker         mCoherentBufferTracker.mBuffers[id.value];
8783*8975f5c5SAndroid Build Coastguard Worker 
8784*8975f5c5SAndroid Build Coastguard Worker     std::vector<PageRange> dirtyPageRanges = coherentBuffer->getDirtyPageRanges();
8785*8975f5c5SAndroid Build Coastguard Worker 
8786*8975f5c5SAndroid Build Coastguard Worker     if (mCoherentBufferTracker.isShadowMemoryEnabled() && !dirtyPageRanges.empty())
8787*8975f5c5SAndroid Build Coastguard Worker     {
8788*8975f5c5SAndroid Build Coastguard Worker         coherentBuffer->updateBufferMemory();
8789*8975f5c5SAndroid Build Coastguard Worker     }
8790*8975f5c5SAndroid Build Coastguard Worker 
8791*8975f5c5SAndroid Build Coastguard Worker     AddressRange wholeRange = coherentBuffer->getRange();
8792*8975f5c5SAndroid Build Coastguard Worker 
8793*8975f5c5SAndroid Build Coastguard Worker     for (PageRange &pageRange : dirtyPageRanges)
8794*8975f5c5SAndroid Build Coastguard Worker     {
8795*8975f5c5SAndroid Build Coastguard Worker         // Write protect the memory already, so the app is blocked on writing during our capture
8796*8975f5c5SAndroid Build Coastguard Worker         coherentBuffer->protectPageRange(pageRange);
8797*8975f5c5SAndroid Build Coastguard Worker 
8798*8975f5c5SAndroid Build Coastguard Worker         // Create the parameters to our helper for use during replay
8799*8975f5c5SAndroid Build Coastguard Worker         ParamBuffer dataParamBuffer;
8800*8975f5c5SAndroid Build Coastguard Worker 
8801*8975f5c5SAndroid Build Coastguard Worker         // Pass in the target buffer ID
8802*8975f5c5SAndroid Build Coastguard Worker         dataParamBuffer.addValueParam("dest", ParamType::TGLuint, buffer->id().value);
8803*8975f5c5SAndroid Build Coastguard Worker 
8804*8975f5c5SAndroid Build Coastguard Worker         // Capture the current buffer data with a binary param
8805*8975f5c5SAndroid Build Coastguard Worker         ParamCapture captureData("source", ParamType::TvoidConstPointer);
8806*8975f5c5SAndroid Build Coastguard Worker 
8807*8975f5c5SAndroid Build Coastguard Worker         AddressRange dirtyRange = coherentBuffer->getDirtyAddressRange(pageRange);
8808*8975f5c5SAndroid Build Coastguard Worker         CaptureMemory(reinterpret_cast<void *>(dirtyRange.start), dirtyRange.size, &captureData);
8809*8975f5c5SAndroid Build Coastguard Worker         dataParamBuffer.addParam(std::move(captureData));
8810*8975f5c5SAndroid Build Coastguard Worker 
8811*8975f5c5SAndroid Build Coastguard Worker         // Also track its size for use with memcpy
8812*8975f5c5SAndroid Build Coastguard Worker         dataParamBuffer.addValueParam<GLsizeiptr>("size", ParamType::TGLsizeiptr,
8813*8975f5c5SAndroid Build Coastguard Worker                                                   static_cast<GLsizeiptr>(dirtyRange.size));
8814*8975f5c5SAndroid Build Coastguard Worker 
8815*8975f5c5SAndroid Build Coastguard Worker         if (wholeRange.start != dirtyRange.start)
8816*8975f5c5SAndroid Build Coastguard Worker         {
8817*8975f5c5SAndroid Build Coastguard Worker             // Capture with offset
8818*8975f5c5SAndroid Build Coastguard Worker             GLsizeiptr offset = dirtyRange.start - wholeRange.start;
8819*8975f5c5SAndroid Build Coastguard Worker 
8820*8975f5c5SAndroid Build Coastguard Worker             ASSERT(offset > 0);
8821*8975f5c5SAndroid Build Coastguard Worker 
8822*8975f5c5SAndroid Build Coastguard Worker             // The dirty page range is not at the start of the buffer, track the offset.
8823*8975f5c5SAndroid Build Coastguard Worker             dataParamBuffer.addValueParam<GLsizeiptr>("offset", ParamType::TGLsizeiptr, offset);
8824*8975f5c5SAndroid Build Coastguard Worker 
8825*8975f5c5SAndroid Build Coastguard Worker             // Call the helper that populates the buffer with captured data
8826*8975f5c5SAndroid Build Coastguard Worker             mFrameCalls.emplace_back("UpdateClientBufferDataWithOffset",
8827*8975f5c5SAndroid Build Coastguard Worker                                      std::move(dataParamBuffer));
8828*8975f5c5SAndroid Build Coastguard Worker         }
8829*8975f5c5SAndroid Build Coastguard Worker         else
8830*8975f5c5SAndroid Build Coastguard Worker         {
8831*8975f5c5SAndroid Build Coastguard Worker             // Call the helper that populates the buffer with captured data
8832*8975f5c5SAndroid Build Coastguard Worker             mFrameCalls.emplace_back("UpdateClientBufferData", std::move(dataParamBuffer));
8833*8975f5c5SAndroid Build Coastguard Worker         }
8834*8975f5c5SAndroid Build Coastguard Worker     }
8835*8975f5c5SAndroid Build Coastguard Worker }
8836*8975f5c5SAndroid Build Coastguard Worker 
captureMappedBufferSnapshot(const gl::Context * context,const CallCapture & call)8837*8975f5c5SAndroid Build Coastguard Worker void FrameCaptureShared::captureMappedBufferSnapshot(const gl::Context *context,
8838*8975f5c5SAndroid Build Coastguard Worker                                                      const CallCapture &call)
8839*8975f5c5SAndroid Build Coastguard Worker {
8840*8975f5c5SAndroid Build Coastguard Worker     // If the buffer was mapped writable, we need to restore its data, since we have no
8841*8975f5c5SAndroid Build Coastguard Worker     // visibility into what the client did to the buffer while mapped.
8842*8975f5c5SAndroid Build Coastguard Worker     // This sequence will result in replay calls like this:
8843*8975f5c5SAndroid Build Coastguard Worker     //   ...
8844*8975f5c5SAndroid Build Coastguard Worker     //   gMappedBufferData[gBufferMap[42]] = glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, 65536,
8845*8975f5c5SAndroid Build Coastguard Worker     //                                                        GL_MAP_WRITE_BIT);
8846*8975f5c5SAndroid Build Coastguard Worker     //   ...
8847*8975f5c5SAndroid Build Coastguard Worker     //   UpdateClientBufferData(42, &gBinaryData[164631024], 65536);
8848*8975f5c5SAndroid Build Coastguard Worker     //   glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
8849*8975f5c5SAndroid Build Coastguard Worker     //   ...
8850*8975f5c5SAndroid Build Coastguard Worker 
8851*8975f5c5SAndroid Build Coastguard Worker     // Re-map the buffer, using the info we tracked about the buffer
8852*8975f5c5SAndroid Build Coastguard Worker     gl::BufferBinding target =
8853*8975f5c5SAndroid Build Coastguard Worker         call.params.getParam("targetPacked", ParamType::TBufferBinding, 0).value.BufferBindingVal;
8854*8975f5c5SAndroid Build Coastguard Worker 
8855*8975f5c5SAndroid Build Coastguard Worker     FrameCaptureShared *frameCaptureShared = context->getShareGroup()->getFrameCaptureShared();
8856*8975f5c5SAndroid Build Coastguard Worker     gl::Buffer *buffer                     = context->getState().getTargetBuffer(target);
8857*8975f5c5SAndroid Build Coastguard Worker     if (!frameCaptureShared->hasBufferData(buffer->id()))
8858*8975f5c5SAndroid Build Coastguard Worker     {
8859*8975f5c5SAndroid Build Coastguard Worker         // This buffer was not marked writable, so we did not back it up
8860*8975f5c5SAndroid Build Coastguard Worker         return;
8861*8975f5c5SAndroid Build Coastguard Worker     }
8862*8975f5c5SAndroid Build Coastguard Worker 
8863*8975f5c5SAndroid Build Coastguard Worker     std::pair<GLintptr, GLsizeiptr> bufferDataOffsetAndLength =
8864*8975f5c5SAndroid Build Coastguard Worker         frameCaptureShared->getBufferDataOffsetAndLength(buffer->id());
8865*8975f5c5SAndroid Build Coastguard Worker     GLintptr offset   = bufferDataOffsetAndLength.first;
8866*8975f5c5SAndroid Build Coastguard Worker     GLsizeiptr length = bufferDataOffsetAndLength.second;
8867*8975f5c5SAndroid Build Coastguard Worker 
8868*8975f5c5SAndroid Build Coastguard Worker     // Map the buffer so we can copy its contents out
8869*8975f5c5SAndroid Build Coastguard Worker     ASSERT(!buffer->isMapped());
8870*8975f5c5SAndroid Build Coastguard Worker     angle::Result result = buffer->mapRange(context, offset, length, GL_MAP_READ_BIT);
8871*8975f5c5SAndroid Build Coastguard Worker     if (result != angle::Result::Continue)
8872*8975f5c5SAndroid Build Coastguard Worker     {
8873*8975f5c5SAndroid Build Coastguard Worker         ERR() << "Failed to mapRange of buffer" << std::endl;
8874*8975f5c5SAndroid Build Coastguard Worker     }
8875*8975f5c5SAndroid Build Coastguard Worker     const uint8_t *data = reinterpret_cast<const uint8_t *>(buffer->getMapPointer());
8876*8975f5c5SAndroid Build Coastguard Worker 
8877*8975f5c5SAndroid Build Coastguard Worker     // Create the parameters to our helper for use during replay
8878*8975f5c5SAndroid Build Coastguard Worker     ParamBuffer dataParamBuffer;
8879*8975f5c5SAndroid Build Coastguard Worker 
8880*8975f5c5SAndroid Build Coastguard Worker     // Pass in the target buffer ID
8881*8975f5c5SAndroid Build Coastguard Worker     dataParamBuffer.addValueParam("dest", ParamType::TGLuint, buffer->id().value);
8882*8975f5c5SAndroid Build Coastguard Worker 
8883*8975f5c5SAndroid Build Coastguard Worker     // Capture the current buffer data with a binary param
8884*8975f5c5SAndroid Build Coastguard Worker     ParamCapture captureData("source", ParamType::TvoidConstPointer);
8885*8975f5c5SAndroid Build Coastguard Worker     CaptureMemory(data, length, &captureData);
8886*8975f5c5SAndroid Build Coastguard Worker     dataParamBuffer.addParam(std::move(captureData));
8887*8975f5c5SAndroid Build Coastguard Worker 
8888*8975f5c5SAndroid Build Coastguard Worker     // Also track its size for use with memcpy
8889*8975f5c5SAndroid Build Coastguard Worker     dataParamBuffer.addValueParam<GLsizeiptr>("size", ParamType::TGLsizeiptr, length);
8890*8975f5c5SAndroid Build Coastguard Worker 
8891*8975f5c5SAndroid Build Coastguard Worker     // Call the helper that populates the buffer with captured data
8892*8975f5c5SAndroid Build Coastguard Worker     mFrameCalls.emplace_back("UpdateClientBufferData", std::move(dataParamBuffer));
8893*8975f5c5SAndroid Build Coastguard Worker 
8894*8975f5c5SAndroid Build Coastguard Worker     // Unmap the buffer and move on
8895*8975f5c5SAndroid Build Coastguard Worker     GLboolean dontCare;
8896*8975f5c5SAndroid Build Coastguard Worker     (void)buffer->unmap(context, &dontCare);
8897*8975f5c5SAndroid Build Coastguard Worker }
8898*8975f5c5SAndroid Build Coastguard Worker 
checkForCaptureTrigger()8899*8975f5c5SAndroid Build Coastguard Worker void FrameCaptureShared::checkForCaptureTrigger()
8900*8975f5c5SAndroid Build Coastguard Worker {
8901*8975f5c5SAndroid Build Coastguard Worker     // If the capture trigger has not been set, move on
8902*8975f5c5SAndroid Build Coastguard Worker     if (mCaptureTrigger == 0)
8903*8975f5c5SAndroid Build Coastguard Worker     {
8904*8975f5c5SAndroid Build Coastguard Worker         return;
8905*8975f5c5SAndroid Build Coastguard Worker     }
8906*8975f5c5SAndroid Build Coastguard Worker 
8907*8975f5c5SAndroid Build Coastguard Worker     // Otherwise, poll the value for a change
8908*8975f5c5SAndroid Build Coastguard Worker     std::string captureTriggerStr = GetCaptureTrigger();
8909*8975f5c5SAndroid Build Coastguard Worker     if (captureTriggerStr.empty())
8910*8975f5c5SAndroid Build Coastguard Worker     {
8911*8975f5c5SAndroid Build Coastguard Worker         return;
8912*8975f5c5SAndroid Build Coastguard Worker     }
8913*8975f5c5SAndroid Build Coastguard Worker 
8914*8975f5c5SAndroid Build Coastguard Worker     // If the value has changed, use the original value as the frame count
8915*8975f5c5SAndroid Build Coastguard Worker     // TODO (anglebug.com/42263521): Improve capture at unknown frame time. It is good to
8916*8975f5c5SAndroid Build Coastguard Worker     // avoid polling if the feature is not enabled, but not entirely intuitive to set
8917*8975f5c5SAndroid Build Coastguard Worker     // a value to zero when you want to trigger it.
8918*8975f5c5SAndroid Build Coastguard Worker     uint32_t captureTrigger = atoi(captureTriggerStr.c_str());
8919*8975f5c5SAndroid Build Coastguard Worker     if (captureTrigger != mCaptureTrigger)
8920*8975f5c5SAndroid Build Coastguard Worker     {
8921*8975f5c5SAndroid Build Coastguard Worker         // Start mid-execution capture for the current frame
8922*8975f5c5SAndroid Build Coastguard Worker         mCaptureStartFrame = mFrameIndex + 1;
8923*8975f5c5SAndroid Build Coastguard Worker 
8924*8975f5c5SAndroid Build Coastguard Worker         // Use the original trigger value as the frame count
8925*8975f5c5SAndroid Build Coastguard Worker         mCaptureEndFrame = mCaptureStartFrame + mCaptureTrigger - 1;
8926*8975f5c5SAndroid Build Coastguard Worker 
8927*8975f5c5SAndroid Build Coastguard Worker         INFO() << "Capture triggered after frame " << mFrameIndex << " for " << mCaptureTrigger
8928*8975f5c5SAndroid Build Coastguard Worker                << " frames";
8929*8975f5c5SAndroid Build Coastguard Worker 
8930*8975f5c5SAndroid Build Coastguard Worker         // Stop polling
8931*8975f5c5SAndroid Build Coastguard Worker         mCaptureTrigger = 0;
8932*8975f5c5SAndroid Build Coastguard Worker     }
8933*8975f5c5SAndroid Build Coastguard Worker }
8934*8975f5c5SAndroid Build Coastguard Worker 
scanSetupCalls(std::vector<CallCapture> & setupCalls)8935*8975f5c5SAndroid Build Coastguard Worker void FrameCaptureShared::scanSetupCalls(std::vector<CallCapture> &setupCalls)
8936*8975f5c5SAndroid Build Coastguard Worker {
8937*8975f5c5SAndroid Build Coastguard Worker     // Scan all the instructions in the list for tracking
8938*8975f5c5SAndroid Build Coastguard Worker     for (CallCapture &call : setupCalls)
8939*8975f5c5SAndroid Build Coastguard Worker     {
8940*8975f5c5SAndroid Build Coastguard Worker         updateReadBufferSize(call.params.getReadBufferSize());
8941*8975f5c5SAndroid Build Coastguard Worker         updateResourceCountsFromCallCapture(call);
8942*8975f5c5SAndroid Build Coastguard Worker     }
8943*8975f5c5SAndroid Build Coastguard Worker }
8944*8975f5c5SAndroid Build Coastguard Worker 
runMidExecutionCapture(gl::Context * mainContext)8945*8975f5c5SAndroid Build Coastguard Worker void FrameCaptureShared::runMidExecutionCapture(gl::Context *mainContext)
8946*8975f5c5SAndroid Build Coastguard Worker {
8947*8975f5c5SAndroid Build Coastguard Worker     // Set the capture active to ensure all GLES commands issued by the next frame are
8948*8975f5c5SAndroid Build Coastguard Worker     // handled correctly by maybeCapturePreCallUpdates() and maybeCapturePostCallUpdates().
8949*8975f5c5SAndroid Build Coastguard Worker     setCaptureActive();
8950*8975f5c5SAndroid Build Coastguard Worker 
8951*8975f5c5SAndroid Build Coastguard Worker     // Make sure all pending work for every Context in the share group has completed so all data
8952*8975f5c5SAndroid Build Coastguard Worker     // (buffers, textures, etc.) has been updated and no resources are in use.
8953*8975f5c5SAndroid Build Coastguard Worker     egl::ShareGroup *shareGroup = mainContext->getShareGroup();
8954*8975f5c5SAndroid Build Coastguard Worker     shareGroup->finishAllContexts();
8955*8975f5c5SAndroid Build Coastguard Worker 
8956*8975f5c5SAndroid Build Coastguard Worker     const gl::State &contextState = mainContext->getState();
8957*8975f5c5SAndroid Build Coastguard Worker     gl::State mainContextReplayState(
8958*8975f5c5SAndroid Build Coastguard Worker         nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, contextState.getClientVersion(),
8959*8975f5c5SAndroid Build Coastguard Worker         false, true, true, true, false, EGL_CONTEXT_PRIORITY_MEDIUM_IMG,
8960*8975f5c5SAndroid Build Coastguard Worker         contextState.hasRobustAccess(), contextState.hasProtectedContent(), false);
8961*8975f5c5SAndroid Build Coastguard Worker     mainContextReplayState.initializeForCapture(mainContext);
8962*8975f5c5SAndroid Build Coastguard Worker 
8963*8975f5c5SAndroid Build Coastguard Worker     CaptureShareGroupMidExecutionSetup(mainContext, &mShareGroupSetupCalls, &mResourceTracker,
8964*8975f5c5SAndroid Build Coastguard Worker                                        mainContextReplayState, mMaxAccessedResourceIDs);
8965*8975f5c5SAndroid Build Coastguard Worker 
8966*8975f5c5SAndroid Build Coastguard Worker     scanSetupCalls(mShareGroupSetupCalls);
8967*8975f5c5SAndroid Build Coastguard Worker 
8968*8975f5c5SAndroid Build Coastguard Worker     egl::Display *display = mainContext->getDisplay();
8969*8975f5c5SAndroid Build Coastguard Worker     egl::Surface *draw    = mainContext->getCurrentDrawSurface();
8970*8975f5c5SAndroid Build Coastguard Worker     egl::Surface *read    = mainContext->getCurrentReadSurface();
8971*8975f5c5SAndroid Build Coastguard Worker 
8972*8975f5c5SAndroid Build Coastguard Worker     for (auto shareContext : shareGroup->getContexts())
8973*8975f5c5SAndroid Build Coastguard Worker     {
8974*8975f5c5SAndroid Build Coastguard Worker         FrameCapture *frameCapture = shareContext.second->getFrameCapture();
8975*8975f5c5SAndroid Build Coastguard Worker         ASSERT(frameCapture->getSetupCalls().empty());
8976*8975f5c5SAndroid Build Coastguard Worker 
8977*8975f5c5SAndroid Build Coastguard Worker         if (shareContext.second->id() == mainContext->id())
8978*8975f5c5SAndroid Build Coastguard Worker         {
8979*8975f5c5SAndroid Build Coastguard Worker             CaptureMidExecutionSetup(shareContext.second, &frameCapture->getSetupCalls(),
8980*8975f5c5SAndroid Build Coastguard Worker                                      frameCapture->getStateResetHelper(), &mShareGroupSetupCalls,
8981*8975f5c5SAndroid Build Coastguard Worker                                      &mResourceIDToSetupCalls, &mResourceTracker,
8982*8975f5c5SAndroid Build Coastguard Worker                                      mainContextReplayState, mValidateSerializedState);
8983*8975f5c5SAndroid Build Coastguard Worker             scanSetupCalls(frameCapture->getSetupCalls());
8984*8975f5c5SAndroid Build Coastguard Worker 
8985*8975f5c5SAndroid Build Coastguard Worker             std::stringstream protoStream;
8986*8975f5c5SAndroid Build Coastguard Worker             std::stringstream headerStream;
8987*8975f5c5SAndroid Build Coastguard Worker             std::stringstream bodyStream;
8988*8975f5c5SAndroid Build Coastguard Worker 
8989*8975f5c5SAndroid Build Coastguard Worker             protoStream << "void "
8990*8975f5c5SAndroid Build Coastguard Worker                         << FmtSetupFunction(kNoPartId, mainContext->id(), FuncUsage::Prototype);
8991*8975f5c5SAndroid Build Coastguard Worker             std::string proto = protoStream.str();
8992*8975f5c5SAndroid Build Coastguard Worker 
8993*8975f5c5SAndroid Build Coastguard Worker             WriteCppReplayFunctionWithParts(mainContext->id(), ReplayFunc::Setup, mReplayWriter, 1,
8994*8975f5c5SAndroid Build Coastguard Worker                                             &mBinaryData, frameCapture->getSetupCalls(),
8995*8975f5c5SAndroid Build Coastguard Worker                                             headerStream, bodyStream, &mResourceIDBufferSize);
8996*8975f5c5SAndroid Build Coastguard Worker 
8997*8975f5c5SAndroid Build Coastguard Worker             mReplayWriter.addPrivateFunction(proto, headerStream, bodyStream);
8998*8975f5c5SAndroid Build Coastguard Worker         }
8999*8975f5c5SAndroid Build Coastguard Worker         else
9000*8975f5c5SAndroid Build Coastguard Worker         {
9001*8975f5c5SAndroid Build Coastguard Worker             const gl::State &shareContextState = shareContext.second->getState();
9002*8975f5c5SAndroid Build Coastguard Worker             gl::State auxContextReplayState(nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
9003*8975f5c5SAndroid Build Coastguard Worker                                             shareContextState.getClientVersion(), false, true, true,
9004*8975f5c5SAndroid Build Coastguard Worker                                             true, false, EGL_CONTEXT_PRIORITY_MEDIUM_IMG,
9005*8975f5c5SAndroid Build Coastguard Worker                                             shareContextState.hasRobustAccess(),
9006*8975f5c5SAndroid Build Coastguard Worker                                             shareContextState.hasProtectedContent(), false);
9007*8975f5c5SAndroid Build Coastguard Worker             auxContextReplayState.initializeForCapture(shareContext.second);
9008*8975f5c5SAndroid Build Coastguard Worker 
9009*8975f5c5SAndroid Build Coastguard Worker             egl::Error error = shareContext.second->makeCurrent(display, draw, read);
9010*8975f5c5SAndroid Build Coastguard Worker             if (error.isError())
9011*8975f5c5SAndroid Build Coastguard Worker             {
9012*8975f5c5SAndroid Build Coastguard Worker                 INFO() << "MEC unable to make secondary context current";
9013*8975f5c5SAndroid Build Coastguard Worker             }
9014*8975f5c5SAndroid Build Coastguard Worker 
9015*8975f5c5SAndroid Build Coastguard Worker             CaptureMidExecutionSetup(shareContext.second, &frameCapture->getSetupCalls(),
9016*8975f5c5SAndroid Build Coastguard Worker                                      frameCapture->getStateResetHelper(), &mShareGroupSetupCalls,
9017*8975f5c5SAndroid Build Coastguard Worker                                      &mResourceIDToSetupCalls, &mResourceTracker,
9018*8975f5c5SAndroid Build Coastguard Worker                                      auxContextReplayState, mValidateSerializedState);
9019*8975f5c5SAndroid Build Coastguard Worker 
9020*8975f5c5SAndroid Build Coastguard Worker             scanSetupCalls(frameCapture->getSetupCalls());
9021*8975f5c5SAndroid Build Coastguard Worker 
9022*8975f5c5SAndroid Build Coastguard Worker             WriteAuxiliaryContextCppSetupReplay(
9023*8975f5c5SAndroid Build Coastguard Worker                 mReplayWriter, mCompression, mOutDirectory, shareContext.second, mCaptureLabel, 1,
9024*8975f5c5SAndroid Build Coastguard Worker                 frameCapture->getSetupCalls(), &mBinaryData, mSerializeStateEnabled, *this,
9025*8975f5c5SAndroid Build Coastguard Worker                 &mResourceIDBufferSize);
9026*8975f5c5SAndroid Build Coastguard Worker         }
9027*8975f5c5SAndroid Build Coastguard Worker         // Track that this context was created before MEC started
9028*8975f5c5SAndroid Build Coastguard Worker         mActiveContexts.insert(shareContext.first);
9029*8975f5c5SAndroid Build Coastguard Worker     }
9030*8975f5c5SAndroid Build Coastguard Worker 
9031*8975f5c5SAndroid Build Coastguard Worker     egl::Error error = mainContext->makeCurrent(display, draw, read);
9032*8975f5c5SAndroid Build Coastguard Worker     if (error.isError())
9033*8975f5c5SAndroid Build Coastguard Worker     {
9034*8975f5c5SAndroid Build Coastguard Worker         INFO() << "MEC unable to make main context current again";
9035*8975f5c5SAndroid Build Coastguard Worker     }
9036*8975f5c5SAndroid Build Coastguard Worker }
9037*8975f5c5SAndroid Build Coastguard Worker 
onEndFrame(gl::Context * context)9038*8975f5c5SAndroid Build Coastguard Worker void FrameCaptureShared::onEndFrame(gl::Context *context)
9039*8975f5c5SAndroid Build Coastguard Worker {
9040*8975f5c5SAndroid Build Coastguard Worker     if (!enabled() || mFrameIndex > mCaptureEndFrame)
9041*8975f5c5SAndroid Build Coastguard Worker     {
9042*8975f5c5SAndroid Build Coastguard Worker         setCaptureInactive();
9043*8975f5c5SAndroid Build Coastguard Worker         mCoherentBufferTracker.onEndFrame();
9044*8975f5c5SAndroid Build Coastguard Worker         return;
9045*8975f5c5SAndroid Build Coastguard Worker     }
9046*8975f5c5SAndroid Build Coastguard Worker 
9047*8975f5c5SAndroid Build Coastguard Worker     FrameCapture *frameCapture = context->getFrameCapture();
9048*8975f5c5SAndroid Build Coastguard Worker 
9049*8975f5c5SAndroid Build Coastguard Worker     // Count resource IDs. This is also done on every frame. It could probably be done by
9050*8975f5c5SAndroid Build Coastguard Worker     // checking the GL state instead of the calls.
9051*8975f5c5SAndroid Build Coastguard Worker     for (const CallCapture &call : mFrameCalls)
9052*8975f5c5SAndroid Build Coastguard Worker     {
9053*8975f5c5SAndroid Build Coastguard Worker         for (const ParamCapture &param : call.params.getParamCaptures())
9054*8975f5c5SAndroid Build Coastguard Worker         {
9055*8975f5c5SAndroid Build Coastguard Worker             ResourceIDType idType = GetResourceIDTypeFromParamType(param.type);
9056*8975f5c5SAndroid Build Coastguard Worker             if (idType != ResourceIDType::InvalidEnum)
9057*8975f5c5SAndroid Build Coastguard Worker             {
9058*8975f5c5SAndroid Build Coastguard Worker                 mHasResourceType.set(idType);
9059*8975f5c5SAndroid Build Coastguard Worker             }
9060*8975f5c5SAndroid Build Coastguard Worker         }
9061*8975f5c5SAndroid Build Coastguard Worker     }
9062*8975f5c5SAndroid Build Coastguard Worker 
9063*8975f5c5SAndroid Build Coastguard Worker     mWindowSurfaceContextID = context->id();
9064*8975f5c5SAndroid Build Coastguard Worker 
9065*8975f5c5SAndroid Build Coastguard Worker     // On Android, we can trigger a capture during the run
9066*8975f5c5SAndroid Build Coastguard Worker     checkForCaptureTrigger();
9067*8975f5c5SAndroid Build Coastguard Worker 
9068*8975f5c5SAndroid Build Coastguard Worker     // Check for MEC. Done after checkForCaptureTrigger(), since that can modify mCaptureStartFrame.
9069*8975f5c5SAndroid Build Coastguard Worker     if (mFrameIndex < mCaptureStartFrame)
9070*8975f5c5SAndroid Build Coastguard Worker     {
9071*8975f5c5SAndroid Build Coastguard Worker         if (mFrameIndex == mCaptureStartFrame - 1)
9072*8975f5c5SAndroid Build Coastguard Worker         {
9073*8975f5c5SAndroid Build Coastguard Worker             // Trigger MEC.
9074*8975f5c5SAndroid Build Coastguard Worker             runMidExecutionCapture(context);
9075*8975f5c5SAndroid Build Coastguard Worker         }
9076*8975f5c5SAndroid Build Coastguard Worker         mFrameIndex++;
9077*8975f5c5SAndroid Build Coastguard Worker         reset();
9078*8975f5c5SAndroid Build Coastguard Worker         return;
9079*8975f5c5SAndroid Build Coastguard Worker     }
9080*8975f5c5SAndroid Build Coastguard Worker 
9081*8975f5c5SAndroid Build Coastguard Worker     ASSERT(isCaptureActive());
9082*8975f5c5SAndroid Build Coastguard Worker 
9083*8975f5c5SAndroid Build Coastguard Worker     if (!mFrameCalls.empty())
9084*8975f5c5SAndroid Build Coastguard Worker     {
9085*8975f5c5SAndroid Build Coastguard Worker         mActiveFrameIndices.push_back(getReplayFrameIndex());
9086*8975f5c5SAndroid Build Coastguard Worker     }
9087*8975f5c5SAndroid Build Coastguard Worker 
9088*8975f5c5SAndroid Build Coastguard Worker     // Make sure all pending work for every Context in the share group has completed so all data
9089*8975f5c5SAndroid Build Coastguard Worker     // (buffers, textures, etc.) has been updated and no resources are in use.
9090*8975f5c5SAndroid Build Coastguard Worker     egl::ShareGroup *shareGroup = context->getShareGroup();
9091*8975f5c5SAndroid Build Coastguard Worker     shareGroup->finishAllContexts();
9092*8975f5c5SAndroid Build Coastguard Worker 
9093*8975f5c5SAndroid Build Coastguard Worker     // Only validate the first frame for now to save on retracing time.
9094*8975f5c5SAndroid Build Coastguard Worker     if (mValidateSerializedState && mFrameIndex == mCaptureStartFrame)
9095*8975f5c5SAndroid Build Coastguard Worker     {
9096*8975f5c5SAndroid Build Coastguard Worker         CaptureValidateSerializedState(context, &mFrameCalls);
9097*8975f5c5SAndroid Build Coastguard Worker     }
9098*8975f5c5SAndroid Build Coastguard Worker 
9099*8975f5c5SAndroid Build Coastguard Worker     writeMainContextCppReplay(context, frameCapture->getSetupCalls(),
9100*8975f5c5SAndroid Build Coastguard Worker                               frameCapture->getStateResetHelper());
9101*8975f5c5SAndroid Build Coastguard Worker 
9102*8975f5c5SAndroid Build Coastguard Worker     if (mFrameIndex == mCaptureEndFrame)
9103*8975f5c5SAndroid Build Coastguard Worker     {
9104*8975f5c5SAndroid Build Coastguard Worker         // Write shared MEC after frame sequence so we can eliminate unused assets like programs
9105*8975f5c5SAndroid Build Coastguard Worker         WriteShareGroupCppSetupReplay(mReplayWriter, mCompression, mOutDirectory, mCaptureLabel, 1,
9106*8975f5c5SAndroid Build Coastguard Worker                                       1, mShareGroupSetupCalls, &mResourceTracker, &mBinaryData,
9107*8975f5c5SAndroid Build Coastguard Worker                                       mSerializeStateEnabled, mWindowSurfaceContextID,
9108*8975f5c5SAndroid Build Coastguard Worker                                       &mResourceIDBufferSize);
9109*8975f5c5SAndroid Build Coastguard Worker 
9110*8975f5c5SAndroid Build Coastguard Worker         // Save the index files after the last frame.
9111*8975f5c5SAndroid Build Coastguard Worker         writeCppReplayIndexFiles(context, false);
9112*8975f5c5SAndroid Build Coastguard Worker         SaveBinaryData(mCompression, mOutDirectory, kSharedContextId, mCaptureLabel, mBinaryData);
9113*8975f5c5SAndroid Build Coastguard Worker         mBinaryData.clear();
9114*8975f5c5SAndroid Build Coastguard Worker         mWroteIndexFile = true;
9115*8975f5c5SAndroid Build Coastguard Worker         INFO() << "Finished recording graphics API capture";
9116*8975f5c5SAndroid Build Coastguard Worker     }
9117*8975f5c5SAndroid Build Coastguard Worker 
9118*8975f5c5SAndroid Build Coastguard Worker     reset();
9119*8975f5c5SAndroid Build Coastguard Worker     mFrameIndex++;
9120*8975f5c5SAndroid Build Coastguard Worker }
9121*8975f5c5SAndroid Build Coastguard Worker 
onDestroyContext(const gl::Context * context)9122*8975f5c5SAndroid Build Coastguard Worker void FrameCaptureShared::onDestroyContext(const gl::Context *context)
9123*8975f5c5SAndroid Build Coastguard Worker {
9124*8975f5c5SAndroid Build Coastguard Worker     if (!mEnabled)
9125*8975f5c5SAndroid Build Coastguard Worker     {
9126*8975f5c5SAndroid Build Coastguard Worker         return;
9127*8975f5c5SAndroid Build Coastguard Worker     }
9128*8975f5c5SAndroid Build Coastguard Worker     if (!mWroteIndexFile && mFrameIndex > mCaptureStartFrame)
9129*8975f5c5SAndroid Build Coastguard Worker     {
9130*8975f5c5SAndroid Build Coastguard Worker         // If context is destroyed before end frame is reached and at least
9131*8975f5c5SAndroid Build Coastguard Worker         // 1 frame has been recorded, then write the index files.
9132*8975f5c5SAndroid Build Coastguard Worker         // It doesn't make sense to write the index files when no frame has been recorded
9133*8975f5c5SAndroid Build Coastguard Worker         mFrameIndex -= 1;
9134*8975f5c5SAndroid Build Coastguard Worker         mCaptureEndFrame = mFrameIndex;
9135*8975f5c5SAndroid Build Coastguard Worker         writeCppReplayIndexFiles(context, true);
9136*8975f5c5SAndroid Build Coastguard Worker         SaveBinaryData(mCompression, mOutDirectory, kSharedContextId, mCaptureLabel, mBinaryData);
9137*8975f5c5SAndroid Build Coastguard Worker         mBinaryData.clear();
9138*8975f5c5SAndroid Build Coastguard Worker         mWroteIndexFile = true;
9139*8975f5c5SAndroid Build Coastguard Worker     }
9140*8975f5c5SAndroid Build Coastguard Worker }
9141*8975f5c5SAndroid Build Coastguard Worker 
onMakeCurrent(const gl::Context * context,const egl::Surface * drawSurface)9142*8975f5c5SAndroid Build Coastguard Worker void FrameCaptureShared::onMakeCurrent(const gl::Context *context, const egl::Surface *drawSurface)
9143*8975f5c5SAndroid Build Coastguard Worker {
9144*8975f5c5SAndroid Build Coastguard Worker     if (!drawSurface)
9145*8975f5c5SAndroid Build Coastguard Worker     {
9146*8975f5c5SAndroid Build Coastguard Worker         return;
9147*8975f5c5SAndroid Build Coastguard Worker     }
9148*8975f5c5SAndroid Build Coastguard Worker 
9149*8975f5c5SAndroid Build Coastguard Worker     // Track the width, height and color space of the draw surface as provided to makeCurrent
9150*8975f5c5SAndroid Build Coastguard Worker     SurfaceParams &params = mDrawSurfaceParams[context->id()];
9151*8975f5c5SAndroid Build Coastguard Worker     params.extents        = gl::Extents(drawSurface->getWidth(), drawSurface->getHeight(), 1);
9152*8975f5c5SAndroid Build Coastguard Worker     params.colorSpace     = egl::FromEGLenum<egl::ColorSpace>(drawSurface->getGLColorspace());
9153*8975f5c5SAndroid Build Coastguard Worker }
9154*8975f5c5SAndroid Build Coastguard Worker 
9155*8975f5c5SAndroid Build Coastguard Worker DataCounters::DataCounters() = default;
9156*8975f5c5SAndroid Build Coastguard Worker 
9157*8975f5c5SAndroid Build Coastguard Worker DataCounters::~DataCounters() = default;
9158*8975f5c5SAndroid Build Coastguard Worker 
getAndIncrement(EntryPoint entryPoint,const std::string & paramName)9159*8975f5c5SAndroid Build Coastguard Worker int DataCounters::getAndIncrement(EntryPoint entryPoint, const std::string &paramName)
9160*8975f5c5SAndroid Build Coastguard Worker {
9161*8975f5c5SAndroid Build Coastguard Worker     Counter counterKey = {entryPoint, paramName};
9162*8975f5c5SAndroid Build Coastguard Worker     return mData[counterKey]++;
9163*8975f5c5SAndroid Build Coastguard Worker }
9164*8975f5c5SAndroid Build Coastguard Worker 
9165*8975f5c5SAndroid Build Coastguard Worker DataTracker::DataTracker() = default;
9166*8975f5c5SAndroid Build Coastguard Worker 
9167*8975f5c5SAndroid Build Coastguard Worker DataTracker::~DataTracker() = default;
9168*8975f5c5SAndroid Build Coastguard Worker 
9169*8975f5c5SAndroid Build Coastguard Worker StringCounters::StringCounters() = default;
9170*8975f5c5SAndroid Build Coastguard Worker 
9171*8975f5c5SAndroid Build Coastguard Worker StringCounters::~StringCounters() = default;
9172*8975f5c5SAndroid Build Coastguard Worker 
getStringCounter(const std::vector<std::string> & strings)9173*8975f5c5SAndroid Build Coastguard Worker int StringCounters::getStringCounter(const std::vector<std::string> &strings)
9174*8975f5c5SAndroid Build Coastguard Worker {
9175*8975f5c5SAndroid Build Coastguard Worker     const auto &id = mStringCounterMap.find(strings);
9176*8975f5c5SAndroid Build Coastguard Worker     if (id == mStringCounterMap.end())
9177*8975f5c5SAndroid Build Coastguard Worker     {
9178*8975f5c5SAndroid Build Coastguard Worker         return kStringsNotFound;
9179*8975f5c5SAndroid Build Coastguard Worker     }
9180*8975f5c5SAndroid Build Coastguard Worker     else
9181*8975f5c5SAndroid Build Coastguard Worker     {
9182*8975f5c5SAndroid Build Coastguard Worker         return mStringCounterMap[strings];
9183*8975f5c5SAndroid Build Coastguard Worker     }
9184*8975f5c5SAndroid Build Coastguard Worker }
9185*8975f5c5SAndroid Build Coastguard Worker 
setStringCounter(const std::vector<std::string> & strings,int & counter)9186*8975f5c5SAndroid Build Coastguard Worker void StringCounters::setStringCounter(const std::vector<std::string> &strings, int &counter)
9187*8975f5c5SAndroid Build Coastguard Worker {
9188*8975f5c5SAndroid Build Coastguard Worker     ASSERT(counter >= 0);
9189*8975f5c5SAndroid Build Coastguard Worker     mStringCounterMap[strings] = counter;
9190*8975f5c5SAndroid Build Coastguard Worker }
9191*8975f5c5SAndroid Build Coastguard Worker 
9192*8975f5c5SAndroid Build Coastguard Worker TrackedResource::TrackedResource() = default;
9193*8975f5c5SAndroid Build Coastguard Worker 
9194*8975f5c5SAndroid Build Coastguard Worker TrackedResource::~TrackedResource() = default;
9195*8975f5c5SAndroid Build Coastguard Worker 
9196*8975f5c5SAndroid Build Coastguard Worker ResourceTracker::ResourceTracker() = default;
9197*8975f5c5SAndroid Build Coastguard Worker 
9198*8975f5c5SAndroid Build Coastguard Worker ResourceTracker::~ResourceTracker() = default;
9199*8975f5c5SAndroid Build Coastguard Worker 
9200*8975f5c5SAndroid Build Coastguard Worker StateResetHelper::StateResetHelper() = default;
9201*8975f5c5SAndroid Build Coastguard Worker 
9202*8975f5c5SAndroid Build Coastguard Worker StateResetHelper::~StateResetHelper() = default;
9203*8975f5c5SAndroid Build Coastguard Worker 
setDefaultResetCalls(const gl::Context * context,angle::EntryPoint entryPoint)9204*8975f5c5SAndroid Build Coastguard Worker void StateResetHelper::setDefaultResetCalls(const gl::Context *context,
9205*8975f5c5SAndroid Build Coastguard Worker                                             angle::EntryPoint entryPoint)
9206*8975f5c5SAndroid Build Coastguard Worker {
9207*8975f5c5SAndroid Build Coastguard Worker     static const gl::BlendState kDefaultBlendState;
9208*8975f5c5SAndroid Build Coastguard Worker 
9209*8975f5c5SAndroid Build Coastguard Worker     // Populate default reset calls for entrypoints to support looping to beginning
9210*8975f5c5SAndroid Build Coastguard Worker     switch (entryPoint)
9211*8975f5c5SAndroid Build Coastguard Worker     {
9212*8975f5c5SAndroid Build Coastguard Worker         case angle::EntryPoint::GLUseProgram:
9213*8975f5c5SAndroid Build Coastguard Worker         {
9214*8975f5c5SAndroid Build Coastguard Worker             if (context->getActiveLinkedProgram() &&
9215*8975f5c5SAndroid Build Coastguard Worker                 context->getActiveLinkedProgram()->id().value != 0)
9216*8975f5c5SAndroid Build Coastguard Worker             {
9217*8975f5c5SAndroid Build Coastguard Worker                 Capture(&mResetCalls[angle::EntryPoint::GLUseProgram],
9218*8975f5c5SAndroid Build Coastguard Worker                         gl::CaptureUseProgram(context->getState(), true, {0}));
9219*8975f5c5SAndroid Build Coastguard Worker             }
9220*8975f5c5SAndroid Build Coastguard Worker             break;
9221*8975f5c5SAndroid Build Coastguard Worker         }
9222*8975f5c5SAndroid Build Coastguard Worker         case angle::EntryPoint::GLBindVertexArray:
9223*8975f5c5SAndroid Build Coastguard Worker         {
9224*8975f5c5SAndroid Build Coastguard Worker             if (context->getState().getVertexArray()->id().value != 0)
9225*8975f5c5SAndroid Build Coastguard Worker             {
9226*8975f5c5SAndroid Build Coastguard Worker                 VertexArrayCaptureFuncs vertexArrayFuncs(context->isGLES1());
9227*8975f5c5SAndroid Build Coastguard Worker                 Capture(&mResetCalls[angle::EntryPoint::GLBindVertexArray],
9228*8975f5c5SAndroid Build Coastguard Worker                         vertexArrayFuncs.bindVertexArray(context->getState(), true, {0}));
9229*8975f5c5SAndroid Build Coastguard Worker             }
9230*8975f5c5SAndroid Build Coastguard Worker             break;
9231*8975f5c5SAndroid Build Coastguard Worker         }
9232*8975f5c5SAndroid Build Coastguard Worker         case angle::EntryPoint::GLBlendFunc:
9233*8975f5c5SAndroid Build Coastguard Worker         {
9234*8975f5c5SAndroid Build Coastguard Worker             Capture(&mResetCalls[angle::EntryPoint::GLBlendFunc],
9235*8975f5c5SAndroid Build Coastguard Worker                     CaptureBlendFunc(context->getState(), true, kDefaultBlendState.sourceBlendRGB,
9236*8975f5c5SAndroid Build Coastguard Worker                                      kDefaultBlendState.destBlendRGB));
9237*8975f5c5SAndroid Build Coastguard Worker             break;
9238*8975f5c5SAndroid Build Coastguard Worker         }
9239*8975f5c5SAndroid Build Coastguard Worker         case angle::EntryPoint::GLBlendFuncSeparate:
9240*8975f5c5SAndroid Build Coastguard Worker         {
9241*8975f5c5SAndroid Build Coastguard Worker             Capture(&mResetCalls[angle::EntryPoint::GLBlendFuncSeparate],
9242*8975f5c5SAndroid Build Coastguard Worker                     CaptureBlendFuncSeparate(
9243*8975f5c5SAndroid Build Coastguard Worker                         context->getState(), true, kDefaultBlendState.sourceBlendRGB,
9244*8975f5c5SAndroid Build Coastguard Worker                         kDefaultBlendState.destBlendRGB, kDefaultBlendState.sourceBlendAlpha,
9245*8975f5c5SAndroid Build Coastguard Worker                         kDefaultBlendState.destBlendAlpha));
9246*8975f5c5SAndroid Build Coastguard Worker             break;
9247*8975f5c5SAndroid Build Coastguard Worker         }
9248*8975f5c5SAndroid Build Coastguard Worker         case angle::EntryPoint::GLBlendEquation:
9249*8975f5c5SAndroid Build Coastguard Worker         {
9250*8975f5c5SAndroid Build Coastguard Worker             UNREACHABLE();  // GLBlendEquationSeparate is always used instead
9251*8975f5c5SAndroid Build Coastguard Worker             break;
9252*8975f5c5SAndroid Build Coastguard Worker         }
9253*8975f5c5SAndroid Build Coastguard Worker         case angle::EntryPoint::GLBlendEquationSeparate:
9254*8975f5c5SAndroid Build Coastguard Worker         {
9255*8975f5c5SAndroid Build Coastguard Worker             Capture(&mResetCalls[angle::EntryPoint::GLBlendEquationSeparate],
9256*8975f5c5SAndroid Build Coastguard Worker                     CaptureBlendEquationSeparate(context->getState(), true,
9257*8975f5c5SAndroid Build Coastguard Worker                                                  kDefaultBlendState.blendEquationRGB,
9258*8975f5c5SAndroid Build Coastguard Worker                                                  kDefaultBlendState.blendEquationAlpha));
9259*8975f5c5SAndroid Build Coastguard Worker             break;
9260*8975f5c5SAndroid Build Coastguard Worker         }
9261*8975f5c5SAndroid Build Coastguard Worker         case angle::EntryPoint::GLColorMask:
9262*8975f5c5SAndroid Build Coastguard Worker         {
9263*8975f5c5SAndroid Build Coastguard Worker             Capture(&mResetCalls[angle::EntryPoint::GLColorMask],
9264*8975f5c5SAndroid Build Coastguard Worker                     CaptureColorMask(context->getState(), true,
9265*8975f5c5SAndroid Build Coastguard Worker                                      gl::ConvertToGLBoolean(kDefaultBlendState.colorMaskRed),
9266*8975f5c5SAndroid Build Coastguard Worker                                      gl::ConvertToGLBoolean(kDefaultBlendState.colorMaskGreen),
9267*8975f5c5SAndroid Build Coastguard Worker                                      gl::ConvertToGLBoolean(kDefaultBlendState.colorMaskBlue),
9268*8975f5c5SAndroid Build Coastguard Worker                                      gl::ConvertToGLBoolean(kDefaultBlendState.colorMaskAlpha)));
9269*8975f5c5SAndroid Build Coastguard Worker             break;
9270*8975f5c5SAndroid Build Coastguard Worker         }
9271*8975f5c5SAndroid Build Coastguard Worker         case angle::EntryPoint::GLBlendColor:
9272*8975f5c5SAndroid Build Coastguard Worker         {
9273*8975f5c5SAndroid Build Coastguard Worker             Capture(&mResetCalls[angle::EntryPoint::GLBlendColor],
9274*8975f5c5SAndroid Build Coastguard Worker                     CaptureBlendColor(context->getState(), true, 0, 0, 0, 0));
9275*8975f5c5SAndroid Build Coastguard Worker             break;
9276*8975f5c5SAndroid Build Coastguard Worker         }
9277*8975f5c5SAndroid Build Coastguard Worker         default:
9278*8975f5c5SAndroid Build Coastguard Worker             ERR() << "Unhandled entry point in setDefaultResetCalls: "
9279*8975f5c5SAndroid Build Coastguard Worker                   << GetEntryPointName(entryPoint);
9280*8975f5c5SAndroid Build Coastguard Worker             UNREACHABLE();
9281*8975f5c5SAndroid Build Coastguard Worker             break;
9282*8975f5c5SAndroid Build Coastguard Worker     }
9283*8975f5c5SAndroid Build Coastguard Worker }
9284*8975f5c5SAndroid Build Coastguard Worker 
setDeletedFenceSync(gl::SyncID sync)9285*8975f5c5SAndroid Build Coastguard Worker void ResourceTracker::setDeletedFenceSync(gl::SyncID sync)
9286*8975f5c5SAndroid Build Coastguard Worker {
9287*8975f5c5SAndroid Build Coastguard Worker     ASSERT(sync.value != 0);
9288*8975f5c5SAndroid Build Coastguard Worker     if (mStartingFenceSyncs.find(sync) == mStartingFenceSyncs.end())
9289*8975f5c5SAndroid Build Coastguard Worker     {
9290*8975f5c5SAndroid Build Coastguard Worker         // This is a fence sync created after MEC was initialized. Ignore it.
9291*8975f5c5SAndroid Build Coastguard Worker         return;
9292*8975f5c5SAndroid Build Coastguard Worker     }
9293*8975f5c5SAndroid Build Coastguard Worker 
9294*8975f5c5SAndroid Build Coastguard Worker     // In this case, the app is deleting a fence sync we started with, we need to regen on loop.
9295*8975f5c5SAndroid Build Coastguard Worker     mFenceSyncsToRegen.insert(sync);
9296*8975f5c5SAndroid Build Coastguard Worker }
9297*8975f5c5SAndroid Build Coastguard Worker 
setModifiedDefaultUniform(gl::ShaderProgramID programID,gl::UniformLocation location)9298*8975f5c5SAndroid Build Coastguard Worker void ResourceTracker::setModifiedDefaultUniform(gl::ShaderProgramID programID,
9299*8975f5c5SAndroid Build Coastguard Worker                                                 gl::UniformLocation location)
9300*8975f5c5SAndroid Build Coastguard Worker {
9301*8975f5c5SAndroid Build Coastguard Worker     // Pull up or create the list of uniform locations for this program and mark one dirty
9302*8975f5c5SAndroid Build Coastguard Worker     mDefaultUniformsToReset[programID].insert(location);
9303*8975f5c5SAndroid Build Coastguard Worker }
9304*8975f5c5SAndroid Build Coastguard Worker 
setDefaultUniformBaseLocation(gl::ShaderProgramID programID,gl::UniformLocation location,gl::UniformLocation baseLocation)9305*8975f5c5SAndroid Build Coastguard Worker void ResourceTracker::setDefaultUniformBaseLocation(gl::ShaderProgramID programID,
9306*8975f5c5SAndroid Build Coastguard Worker                                                     gl::UniformLocation location,
9307*8975f5c5SAndroid Build Coastguard Worker                                                     gl::UniformLocation baseLocation)
9308*8975f5c5SAndroid Build Coastguard Worker {
9309*8975f5c5SAndroid Build Coastguard Worker     // Track the base location used to populate arrayed uniforms in Setup
9310*8975f5c5SAndroid Build Coastguard Worker     mDefaultUniformBaseLocations[{programID, location}] = baseLocation;
9311*8975f5c5SAndroid Build Coastguard Worker }
9312*8975f5c5SAndroid Build Coastguard Worker 
getTrackedResource(gl::ContextID contextID,ResourceIDType type)9313*8975f5c5SAndroid Build Coastguard Worker TrackedResource &ResourceTracker::getTrackedResource(gl::ContextID contextID, ResourceIDType type)
9314*8975f5c5SAndroid Build Coastguard Worker {
9315*8975f5c5SAndroid Build Coastguard Worker     if (IsSharedObjectResource(type))
9316*8975f5c5SAndroid Build Coastguard Worker     {
9317*8975f5c5SAndroid Build Coastguard Worker         // No need to index with context if shared
9318*8975f5c5SAndroid Build Coastguard Worker         return mTrackedResourcesShared[static_cast<uint32_t>(type)];
9319*8975f5c5SAndroid Build Coastguard Worker     }
9320*8975f5c5SAndroid Build Coastguard Worker     else
9321*8975f5c5SAndroid Build Coastguard Worker     {
9322*8975f5c5SAndroid Build Coastguard Worker         // For per-context objects, track the resource per-context
9323*8975f5c5SAndroid Build Coastguard Worker         return mTrackedResourcesPerContext[contextID][static_cast<uint32_t>(type)];
9324*8975f5c5SAndroid Build Coastguard Worker     }
9325*8975f5c5SAndroid Build Coastguard Worker }
9326*8975f5c5SAndroid Build Coastguard Worker 
getContextIDs(std::set<gl::ContextID> & idsOut)9327*8975f5c5SAndroid Build Coastguard Worker void ResourceTracker::getContextIDs(std::set<gl::ContextID> &idsOut)
9328*8975f5c5SAndroid Build Coastguard Worker {
9329*8975f5c5SAndroid Build Coastguard Worker     for (const auto &trackedResourceIterator : mTrackedResourcesPerContext)
9330*8975f5c5SAndroid Build Coastguard Worker     {
9331*8975f5c5SAndroid Build Coastguard Worker         gl::ContextID contextID = trackedResourceIterator.first;
9332*8975f5c5SAndroid Build Coastguard Worker         idsOut.insert(contextID);
9333*8975f5c5SAndroid Build Coastguard Worker     }
9334*8975f5c5SAndroid Build Coastguard Worker }
9335*8975f5c5SAndroid Build Coastguard Worker 
setGennedResource(GLuint id)9336*8975f5c5SAndroid Build Coastguard Worker void TrackedResource::setGennedResource(GLuint id)
9337*8975f5c5SAndroid Build Coastguard Worker {
9338*8975f5c5SAndroid Build Coastguard Worker     if (mStartingResources.find(id) == mStartingResources.end())
9339*8975f5c5SAndroid Build Coastguard Worker     {
9340*8975f5c5SAndroid Build Coastguard Worker         // This is a resource created after MEC was initialized, track it
9341*8975f5c5SAndroid Build Coastguard Worker         mNewResources.insert(id);
9342*8975f5c5SAndroid Build Coastguard Worker     }
9343*8975f5c5SAndroid Build Coastguard Worker     else
9344*8975f5c5SAndroid Build Coastguard Worker     {
9345*8975f5c5SAndroid Build Coastguard Worker         // In this case, the app is genning a resource with starting ID after previously deleting it
9346*8975f5c5SAndroid Build Coastguard Worker         ASSERT(mResourcesToRegen.find(id) != mResourcesToRegen.end());
9347*8975f5c5SAndroid Build Coastguard Worker 
9348*8975f5c5SAndroid Build Coastguard Worker         // For this, we need to delete it again to recreate it.
9349*8975f5c5SAndroid Build Coastguard Worker         mResourcesToDelete.insert(id);
9350*8975f5c5SAndroid Build Coastguard Worker     }
9351*8975f5c5SAndroid Build Coastguard Worker }
9352*8975f5c5SAndroid Build Coastguard Worker 
resourceIsGenerated(GLuint id)9353*8975f5c5SAndroid Build Coastguard Worker bool TrackedResource::resourceIsGenerated(GLuint id)
9354*8975f5c5SAndroid Build Coastguard Worker {
9355*8975f5c5SAndroid Build Coastguard Worker     return mStartingResources.find(id) != mStartingResources.end() ||
9356*8975f5c5SAndroid Build Coastguard Worker            mNewResources.find(id) != mNewResources.end();
9357*8975f5c5SAndroid Build Coastguard Worker }
9358*8975f5c5SAndroid Build Coastguard Worker 
setDeletedResource(GLuint id)9359*8975f5c5SAndroid Build Coastguard Worker void TrackedResource::setDeletedResource(GLuint id)
9360*8975f5c5SAndroid Build Coastguard Worker {
9361*8975f5c5SAndroid Build Coastguard Worker     if (id == 0)
9362*8975f5c5SAndroid Build Coastguard Worker     {
9363*8975f5c5SAndroid Build Coastguard Worker         // Ignore ID 0
9364*8975f5c5SAndroid Build Coastguard Worker         return;
9365*8975f5c5SAndroid Build Coastguard Worker     }
9366*8975f5c5SAndroid Build Coastguard Worker 
9367*8975f5c5SAndroid Build Coastguard Worker     if (mNewResources.find(id) != mNewResources.end())
9368*8975f5c5SAndroid Build Coastguard Worker     {
9369*8975f5c5SAndroid Build Coastguard Worker         // This is a resource created after MEC was initialized, just clear it, since there will be
9370*8975f5c5SAndroid Build Coastguard Worker         // no actions required for it to return to starting state.
9371*8975f5c5SAndroid Build Coastguard Worker         mNewResources.erase(id);
9372*8975f5c5SAndroid Build Coastguard Worker         return;
9373*8975f5c5SAndroid Build Coastguard Worker     }
9374*8975f5c5SAndroid Build Coastguard Worker 
9375*8975f5c5SAndroid Build Coastguard Worker     if (mStartingResources.find(id) != mStartingResources.end())
9376*8975f5c5SAndroid Build Coastguard Worker     {
9377*8975f5c5SAndroid Build Coastguard Worker         // In this case, the app is deleting a resource we started with, we need to regen on loop
9378*8975f5c5SAndroid Build Coastguard Worker 
9379*8975f5c5SAndroid Build Coastguard Worker         // Mark that we don't need to delete this
9380*8975f5c5SAndroid Build Coastguard Worker         mResourcesToDelete.erase(id);
9381*8975f5c5SAndroid Build Coastguard Worker 
9382*8975f5c5SAndroid Build Coastguard Worker         // Generate the resource again
9383*8975f5c5SAndroid Build Coastguard Worker         mResourcesToRegen.insert(id);
9384*8975f5c5SAndroid Build Coastguard Worker 
9385*8975f5c5SAndroid Build Coastguard Worker         // Also restore its contents
9386*8975f5c5SAndroid Build Coastguard Worker         mResourcesToRestore.insert(id);
9387*8975f5c5SAndroid Build Coastguard Worker     }
9388*8975f5c5SAndroid Build Coastguard Worker 
9389*8975f5c5SAndroid Build Coastguard Worker     // If none of the above is true, the app is deleting a resource that was never genned.
9390*8975f5c5SAndroid Build Coastguard Worker }
9391*8975f5c5SAndroid Build Coastguard Worker 
setModifiedResource(GLuint id)9392*8975f5c5SAndroid Build Coastguard Worker void TrackedResource::setModifiedResource(GLuint id)
9393*8975f5c5SAndroid Build Coastguard Worker {
9394*8975f5c5SAndroid Build Coastguard Worker     // If this was a starting resource, we need to track it for restore
9395*8975f5c5SAndroid Build Coastguard Worker     if (mStartingResources.find(id) != mStartingResources.end())
9396*8975f5c5SAndroid Build Coastguard Worker     {
9397*8975f5c5SAndroid Build Coastguard Worker         mResourcesToRestore.insert(id);
9398*8975f5c5SAndroid Build Coastguard Worker     }
9399*8975f5c5SAndroid Build Coastguard Worker }
9400*8975f5c5SAndroid Build Coastguard Worker 
setBufferMapped(gl::ContextID contextID,GLuint id)9401*8975f5c5SAndroid Build Coastguard Worker void ResourceTracker::setBufferMapped(gl::ContextID contextID, GLuint id)
9402*8975f5c5SAndroid Build Coastguard Worker {
9403*8975f5c5SAndroid Build Coastguard Worker     // If this was a starting buffer, we may need to restore it to original state during Reset.
9404*8975f5c5SAndroid Build Coastguard Worker     // Skip buffers that were deleted after the starting point.
9405*8975f5c5SAndroid Build Coastguard Worker     const TrackedResource &trackedBuffers = getTrackedResource(contextID, ResourceIDType::Buffer);
9406*8975f5c5SAndroid Build Coastguard Worker     const ResourceSet &startingBuffers    = trackedBuffers.getStartingResources();
9407*8975f5c5SAndroid Build Coastguard Worker     const ResourceSet &buffersToRegen     = trackedBuffers.getResourcesToRegen();
9408*8975f5c5SAndroid Build Coastguard Worker     if (startingBuffers.find(id) != startingBuffers.end() &&
9409*8975f5c5SAndroid Build Coastguard Worker         buffersToRegen.find(id) == buffersToRegen.end())
9410*8975f5c5SAndroid Build Coastguard Worker     {
9411*8975f5c5SAndroid Build Coastguard Worker         // Track that its current state is mapped (true)
9412*8975f5c5SAndroid Build Coastguard Worker         mStartingBuffersMappedCurrent[id] = true;
9413*8975f5c5SAndroid Build Coastguard Worker     }
9414*8975f5c5SAndroid Build Coastguard Worker }
9415*8975f5c5SAndroid Build Coastguard Worker 
setBufferUnmapped(gl::ContextID contextID,GLuint id)9416*8975f5c5SAndroid Build Coastguard Worker void ResourceTracker::setBufferUnmapped(gl::ContextID contextID, GLuint id)
9417*8975f5c5SAndroid Build Coastguard Worker {
9418*8975f5c5SAndroid Build Coastguard Worker     // If this was a starting buffer, we may need to restore it to original state during Reset.
9419*8975f5c5SAndroid Build Coastguard Worker     // Skip buffers that were deleted after the starting point.
9420*8975f5c5SAndroid Build Coastguard Worker     const TrackedResource &trackedBuffers = getTrackedResource(contextID, ResourceIDType::Buffer);
9421*8975f5c5SAndroid Build Coastguard Worker     const ResourceSet &startingBuffers    = trackedBuffers.getStartingResources();
9422*8975f5c5SAndroid Build Coastguard Worker     const ResourceSet &buffersToRegen     = trackedBuffers.getResourcesToRegen();
9423*8975f5c5SAndroid Build Coastguard Worker     if (startingBuffers.find(id) != startingBuffers.end() &&
9424*8975f5c5SAndroid Build Coastguard Worker         buffersToRegen.find(id) == buffersToRegen.end())
9425*8975f5c5SAndroid Build Coastguard Worker     {
9426*8975f5c5SAndroid Build Coastguard Worker         // Track that its current state is unmapped (false)
9427*8975f5c5SAndroid Build Coastguard Worker         mStartingBuffersMappedCurrent[id] = false;
9428*8975f5c5SAndroid Build Coastguard Worker     }
9429*8975f5c5SAndroid Build Coastguard Worker }
9430*8975f5c5SAndroid Build Coastguard Worker 
getStartingBuffersMappedCurrent(GLuint id) const9431*8975f5c5SAndroid Build Coastguard Worker bool ResourceTracker::getStartingBuffersMappedCurrent(GLuint id) const
9432*8975f5c5SAndroid Build Coastguard Worker {
9433*8975f5c5SAndroid Build Coastguard Worker     const auto &foundBool = mStartingBuffersMappedCurrent.find(id);
9434*8975f5c5SAndroid Build Coastguard Worker     ASSERT(foundBool != mStartingBuffersMappedCurrent.end());
9435*8975f5c5SAndroid Build Coastguard Worker     return foundBool->second;
9436*8975f5c5SAndroid Build Coastguard Worker }
9437*8975f5c5SAndroid Build Coastguard Worker 
getStartingBuffersMappedInitial(GLuint id) const9438*8975f5c5SAndroid Build Coastguard Worker bool ResourceTracker::getStartingBuffersMappedInitial(GLuint id) const
9439*8975f5c5SAndroid Build Coastguard Worker {
9440*8975f5c5SAndroid Build Coastguard Worker     const auto &foundBool = mStartingBuffersMappedInitial.find(id);
9441*8975f5c5SAndroid Build Coastguard Worker     ASSERT(foundBool != mStartingBuffersMappedInitial.end());
9442*8975f5c5SAndroid Build Coastguard Worker     return foundBool->second;
9443*8975f5c5SAndroid Build Coastguard Worker }
9444*8975f5c5SAndroid Build Coastguard Worker 
onShaderProgramAccess(gl::ShaderProgramID shaderProgramID)9445*8975f5c5SAndroid Build Coastguard Worker void ResourceTracker::onShaderProgramAccess(gl::ShaderProgramID shaderProgramID)
9446*8975f5c5SAndroid Build Coastguard Worker {
9447*8975f5c5SAndroid Build Coastguard Worker     mMaxShaderPrograms = std::max(mMaxShaderPrograms, shaderProgramID.value + 1);
9448*8975f5c5SAndroid Build Coastguard Worker }
9449*8975f5c5SAndroid Build Coastguard Worker 
isCapturing() const9450*8975f5c5SAndroid Build Coastguard Worker bool FrameCaptureShared::isCapturing() const
9451*8975f5c5SAndroid Build Coastguard Worker {
9452*8975f5c5SAndroid Build Coastguard Worker     // Currently we will always do a capture up until the last frame. In the future we could improve
9453*8975f5c5SAndroid Build Coastguard Worker     // mid execution capture by only capturing between the start and end frames. The only necessary
9454*8975f5c5SAndroid Build Coastguard Worker     // reason we need to capture before the start is for attached program and shader sources.
9455*8975f5c5SAndroid Build Coastguard Worker     return mEnabled && mFrameIndex <= mCaptureEndFrame;
9456*8975f5c5SAndroid Build Coastguard Worker }
9457*8975f5c5SAndroid Build Coastguard Worker 
getFrameCount() const9458*8975f5c5SAndroid Build Coastguard Worker uint32_t FrameCaptureShared::getFrameCount() const
9459*8975f5c5SAndroid Build Coastguard Worker {
9460*8975f5c5SAndroid Build Coastguard Worker     return mCaptureEndFrame - mCaptureStartFrame + 1;
9461*8975f5c5SAndroid Build Coastguard Worker }
9462*8975f5c5SAndroid Build Coastguard Worker 
getReplayFrameIndex() const9463*8975f5c5SAndroid Build Coastguard Worker uint32_t FrameCaptureShared::getReplayFrameIndex() const
9464*8975f5c5SAndroid Build Coastguard Worker {
9465*8975f5c5SAndroid Build Coastguard Worker     return mFrameIndex - mCaptureStartFrame + 1;
9466*8975f5c5SAndroid Build Coastguard Worker }
9467*8975f5c5SAndroid Build Coastguard Worker 
9468*8975f5c5SAndroid Build Coastguard Worker // Serialize trace metadata into a JSON file. The JSON file will be named "trace_prefix.json".
9469*8975f5c5SAndroid Build Coastguard Worker //
9470*8975f5c5SAndroid Build Coastguard Worker // As of writing, it will have the format like so:
9471*8975f5c5SAndroid Build Coastguard Worker // {
9472*8975f5c5SAndroid Build Coastguard Worker //     "TraceMetadata":
9473*8975f5c5SAndroid Build Coastguard Worker //     {
9474*8975f5c5SAndroid Build Coastguard Worker //         "AreClientArraysEnabled" : 1, "CaptureRevision" : 16631, "ConfigAlphaBits" : 8,
9475*8975f5c5SAndroid Build Coastguard Worker //             "ConfigBlueBits" : 8, "ConfigDepthBits" : 24, "ConfigGreenBits" : 8,
9476*8975f5c5SAndroid Build Coastguard Worker // ... etc ...
writeJSON(const gl::Context * context)9477*8975f5c5SAndroid Build Coastguard Worker void FrameCaptureShared::writeJSON(const gl::Context *context)
9478*8975f5c5SAndroid Build Coastguard Worker {
9479*8975f5c5SAndroid Build Coastguard Worker     const gl::ContextID contextId           = context->id();
9480*8975f5c5SAndroid Build Coastguard Worker     const SurfaceParams &surfaceParams      = mDrawSurfaceParams.at(contextId);
9481*8975f5c5SAndroid Build Coastguard Worker     const gl::State &glState                = context->getState();
9482*8975f5c5SAndroid Build Coastguard Worker     const egl::Config *config               = context->getConfig();
9483*8975f5c5SAndroid Build Coastguard Worker     const egl::AttributeMap &displayAttribs = context->getDisplay()->getAttributeMap();
9484*8975f5c5SAndroid Build Coastguard Worker 
9485*8975f5c5SAndroid Build Coastguard Worker     unsigned int frameCount = getFrameCount();
9486*8975f5c5SAndroid Build Coastguard Worker 
9487*8975f5c5SAndroid Build Coastguard Worker     JsonSerializer json;
9488*8975f5c5SAndroid Build Coastguard Worker     json.startGroup("TraceMetadata");
9489*8975f5c5SAndroid Build Coastguard Worker     json.addScalar("CaptureRevision", GetANGLERevision());
9490*8975f5c5SAndroid Build Coastguard Worker     json.addScalar("ContextClientMajorVersion", context->getClientMajorVersion());
9491*8975f5c5SAndroid Build Coastguard Worker     json.addScalar("ContextClientMinorVersion", context->getClientMinorVersion());
9492*8975f5c5SAndroid Build Coastguard Worker     json.addHexValue("DisplayPlatformType", displayAttribs.getAsInt(EGL_PLATFORM_ANGLE_TYPE_ANGLE));
9493*8975f5c5SAndroid Build Coastguard Worker     json.addHexValue("DisplayDeviceType",
9494*8975f5c5SAndroid Build Coastguard Worker                      displayAttribs.getAsInt(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE));
9495*8975f5c5SAndroid Build Coastguard Worker     json.addScalar("FrameStart", 1);
9496*8975f5c5SAndroid Build Coastguard Worker     json.addScalar("FrameEnd", frameCount);
9497*8975f5c5SAndroid Build Coastguard Worker     json.addScalar("DrawSurfaceWidth", surfaceParams.extents.width);
9498*8975f5c5SAndroid Build Coastguard Worker     json.addScalar("DrawSurfaceHeight", surfaceParams.extents.height);
9499*8975f5c5SAndroid Build Coastguard Worker     json.addHexValue("DrawSurfaceColorSpace", ToEGLenum(surfaceParams.colorSpace));
9500*8975f5c5SAndroid Build Coastguard Worker     if (config)
9501*8975f5c5SAndroid Build Coastguard Worker     {
9502*8975f5c5SAndroid Build Coastguard Worker         json.addScalar("ConfigRedBits", config->redSize);
9503*8975f5c5SAndroid Build Coastguard Worker         json.addScalar("ConfigGreenBits", config->greenSize);
9504*8975f5c5SAndroid Build Coastguard Worker         json.addScalar("ConfigBlueBits", config->blueSize);
9505*8975f5c5SAndroid Build Coastguard Worker         json.addScalar("ConfigAlphaBits", config->alphaSize);
9506*8975f5c5SAndroid Build Coastguard Worker         json.addScalar("ConfigDepthBits", config->depthSize);
9507*8975f5c5SAndroid Build Coastguard Worker         json.addScalar("ConfigStencilBits", config->stencilSize);
9508*8975f5c5SAndroid Build Coastguard Worker     }
9509*8975f5c5SAndroid Build Coastguard Worker     else
9510*8975f5c5SAndroid Build Coastguard Worker     {
9511*8975f5c5SAndroid Build Coastguard Worker         json.addScalar("ConfigRedBits", EGL_DONT_CARE);
9512*8975f5c5SAndroid Build Coastguard Worker         json.addScalar("ConfigGreenBits", EGL_DONT_CARE);
9513*8975f5c5SAndroid Build Coastguard Worker         json.addScalar("ConfigBlueBits", EGL_DONT_CARE);
9514*8975f5c5SAndroid Build Coastguard Worker         json.addScalar("ConfigAlphaBits", EGL_DONT_CARE);
9515*8975f5c5SAndroid Build Coastguard Worker         json.addScalar("ConfigDepthBits", EGL_DONT_CARE);
9516*8975f5c5SAndroid Build Coastguard Worker         json.addScalar("ConfigStencilBits", EGL_DONT_CARE);
9517*8975f5c5SAndroid Build Coastguard Worker     }
9518*8975f5c5SAndroid Build Coastguard Worker     json.addBool("IsBinaryDataCompressed", mCompression);
9519*8975f5c5SAndroid Build Coastguard Worker     json.addBool("AreClientArraysEnabled", glState.areClientArraysEnabled());
9520*8975f5c5SAndroid Build Coastguard Worker     json.addBool("IsBindGeneratesResourcesEnabled", glState.isBindGeneratesResourceEnabled());
9521*8975f5c5SAndroid Build Coastguard Worker     json.addBool("IsWebGLCompatibilityEnabled", glState.isWebGL());
9522*8975f5c5SAndroid Build Coastguard Worker     json.addBool("IsRobustResourceInitEnabled", glState.isRobustResourceInitEnabled());
9523*8975f5c5SAndroid Build Coastguard Worker     json.endGroup();
9524*8975f5c5SAndroid Build Coastguard Worker 
9525*8975f5c5SAndroid Build Coastguard Worker     {
9526*8975f5c5SAndroid Build Coastguard Worker         const std::vector<std::string> &traceFiles = mReplayWriter.getAndResetWrittenFiles();
9527*8975f5c5SAndroid Build Coastguard Worker         json.addVectorOfStrings("TraceFiles", traceFiles);
9528*8975f5c5SAndroid Build Coastguard Worker     }
9529*8975f5c5SAndroid Build Coastguard Worker 
9530*8975f5c5SAndroid Build Coastguard Worker     json.addScalar("WindowSurfaceContextID", contextId.value);
9531*8975f5c5SAndroid Build Coastguard Worker 
9532*8975f5c5SAndroid Build Coastguard Worker     {
9533*8975f5c5SAndroid Build Coastguard Worker         std::stringstream jsonFileNameStream;
9534*8975f5c5SAndroid Build Coastguard Worker         jsonFileNameStream << mOutDirectory << FmtCapturePrefix(kNoContextId, mCaptureLabel)
9535*8975f5c5SAndroid Build Coastguard Worker                            << ".json";
9536*8975f5c5SAndroid Build Coastguard Worker         std::string jsonFileName = jsonFileNameStream.str();
9537*8975f5c5SAndroid Build Coastguard Worker 
9538*8975f5c5SAndroid Build Coastguard Worker         SaveFileHelper saveData(jsonFileName);
9539*8975f5c5SAndroid Build Coastguard Worker         saveData.write(reinterpret_cast<const uint8_t *>(json.data()), json.length());
9540*8975f5c5SAndroid Build Coastguard Worker     }
9541*8975f5c5SAndroid Build Coastguard Worker }
9542*8975f5c5SAndroid Build Coastguard Worker 
writeCppReplayIndexFiles(const gl::Context * context,bool writeResetContextCall)9543*8975f5c5SAndroid Build Coastguard Worker void FrameCaptureShared::writeCppReplayIndexFiles(const gl::Context *context,
9544*8975f5c5SAndroid Build Coastguard Worker                                                   bool writeResetContextCall)
9545*8975f5c5SAndroid Build Coastguard Worker {
9546*8975f5c5SAndroid Build Coastguard Worker     // Ensure the last frame is written. This will no-op if the frame is already written.
9547*8975f5c5SAndroid Build Coastguard Worker     mReplayWriter.saveFrame();
9548*8975f5c5SAndroid Build Coastguard Worker 
9549*8975f5c5SAndroid Build Coastguard Worker     const gl::ContextID contextId = context->id();
9550*8975f5c5SAndroid Build Coastguard Worker 
9551*8975f5c5SAndroid Build Coastguard Worker     {
9552*8975f5c5SAndroid Build Coastguard Worker         std::stringstream header;
9553*8975f5c5SAndroid Build Coastguard Worker 
9554*8975f5c5SAndroid Build Coastguard Worker         header << "#pragma once\n";
9555*8975f5c5SAndroid Build Coastguard Worker         header << "\n";
9556*8975f5c5SAndroid Build Coastguard Worker         header << "#include <EGL/egl.h>\n";
9557*8975f5c5SAndroid Build Coastguard Worker         header << "#include <stdint.h>\n";
9558*8975f5c5SAndroid Build Coastguard Worker 
9559*8975f5c5SAndroid Build Coastguard Worker         std::string includes = header.str();
9560*8975f5c5SAndroid Build Coastguard Worker         mReplayWriter.setHeaderPrologue(includes);
9561*8975f5c5SAndroid Build Coastguard Worker     }
9562*8975f5c5SAndroid Build Coastguard Worker 
9563*8975f5c5SAndroid Build Coastguard Worker     {
9564*8975f5c5SAndroid Build Coastguard Worker         std::stringstream source;
9565*8975f5c5SAndroid Build Coastguard Worker 
9566*8975f5c5SAndroid Build Coastguard Worker         source << "#include \"" << FmtCapturePrefix(contextId, mCaptureLabel) << ".h\"\n";
9567*8975f5c5SAndroid Build Coastguard Worker         source << "#include \"trace_fixture.h\"\n";
9568*8975f5c5SAndroid Build Coastguard Worker         source << "#include \"angle_trace_gl.h\"\n";
9569*8975f5c5SAndroid Build Coastguard Worker 
9570*8975f5c5SAndroid Build Coastguard Worker         std::string sourcePrologue = source.str();
9571*8975f5c5SAndroid Build Coastguard Worker         mReplayWriter.setSourcePrologue(sourcePrologue);
9572*8975f5c5SAndroid Build Coastguard Worker     }
9573*8975f5c5SAndroid Build Coastguard Worker 
9574*8975f5c5SAndroid Build Coastguard Worker     {
9575*8975f5c5SAndroid Build Coastguard Worker         std::string proto = "void InitReplay(void)";
9576*8975f5c5SAndroid Build Coastguard Worker 
9577*8975f5c5SAndroid Build Coastguard Worker         std::stringstream source;
9578*8975f5c5SAndroid Build Coastguard Worker         source << proto << "\n";
9579*8975f5c5SAndroid Build Coastguard Worker         source << "{\n";
9580*8975f5c5SAndroid Build Coastguard Worker         WriteInitReplayCall(mCompression, source, context->id(), mCaptureLabel,
9581*8975f5c5SAndroid Build Coastguard Worker                             MaxClientArraySize(mClientArraySizes), mReadBufferSize,
9582*8975f5c5SAndroid Build Coastguard Worker                             mResourceIDBufferSize, mMaxAccessedResourceIDs);
9583*8975f5c5SAndroid Build Coastguard Worker         source << "}\n";
9584*8975f5c5SAndroid Build Coastguard Worker 
9585*8975f5c5SAndroid Build Coastguard Worker         mReplayWriter.addPrivateFunction(proto, std::stringstream(), source);
9586*8975f5c5SAndroid Build Coastguard Worker     }
9587*8975f5c5SAndroid Build Coastguard Worker 
9588*8975f5c5SAndroid Build Coastguard Worker     {
9589*8975f5c5SAndroid Build Coastguard Worker         std::string proto = "void ReplayFrame(uint32_t frameIndex)";
9590*8975f5c5SAndroid Build Coastguard Worker 
9591*8975f5c5SAndroid Build Coastguard Worker         std::stringstream source;
9592*8975f5c5SAndroid Build Coastguard Worker 
9593*8975f5c5SAndroid Build Coastguard Worker         source << proto << "\n";
9594*8975f5c5SAndroid Build Coastguard Worker         source << "{\n";
9595*8975f5c5SAndroid Build Coastguard Worker         source << "    switch (frameIndex)\n";
9596*8975f5c5SAndroid Build Coastguard Worker         source << "    {\n";
9597*8975f5c5SAndroid Build Coastguard Worker         for (uint32_t frameIndex : mActiveFrameIndices)
9598*8975f5c5SAndroid Build Coastguard Worker         {
9599*8975f5c5SAndroid Build Coastguard Worker             source << "        case " << frameIndex << ":\n";
9600*8975f5c5SAndroid Build Coastguard Worker             source << "            " << FmtReplayFunction(contextId, FuncUsage::Call, frameIndex)
9601*8975f5c5SAndroid Build Coastguard Worker                    << ";\n";
9602*8975f5c5SAndroid Build Coastguard Worker             source << "            break;\n";
9603*8975f5c5SAndroid Build Coastguard Worker         }
9604*8975f5c5SAndroid Build Coastguard Worker         source << "        default:\n";
9605*8975f5c5SAndroid Build Coastguard Worker         source << "            break;\n";
9606*8975f5c5SAndroid Build Coastguard Worker         source << "    }\n";
9607*8975f5c5SAndroid Build Coastguard Worker         source << "}\n";
9608*8975f5c5SAndroid Build Coastguard Worker 
9609*8975f5c5SAndroid Build Coastguard Worker         mReplayWriter.addPublicFunction(proto, std::stringstream(), source);
9610*8975f5c5SAndroid Build Coastguard Worker     }
9611*8975f5c5SAndroid Build Coastguard Worker 
9612*8975f5c5SAndroid Build Coastguard Worker     if (writeResetContextCall)
9613*8975f5c5SAndroid Build Coastguard Worker     {
9614*8975f5c5SAndroid Build Coastguard Worker         std::string proto = "void ResetReplay(void)";
9615*8975f5c5SAndroid Build Coastguard Worker 
9616*8975f5c5SAndroid Build Coastguard Worker         std::stringstream source;
9617*8975f5c5SAndroid Build Coastguard Worker 
9618*8975f5c5SAndroid Build Coastguard Worker         source << proto << "\n";
9619*8975f5c5SAndroid Build Coastguard Worker         source << "{\n";
9620*8975f5c5SAndroid Build Coastguard Worker         source << "    // Reset context is empty because context is destroyed before end "
9621*8975f5c5SAndroid Build Coastguard Worker                   "frame is reached\n";
9622*8975f5c5SAndroid Build Coastguard Worker         source << "}\n";
9623*8975f5c5SAndroid Build Coastguard Worker 
9624*8975f5c5SAndroid Build Coastguard Worker         mReplayWriter.addPublicFunction(proto, std::stringstream(), source);
9625*8975f5c5SAndroid Build Coastguard Worker     }
9626*8975f5c5SAndroid Build Coastguard Worker 
9627*8975f5c5SAndroid Build Coastguard Worker     if (mSerializeStateEnabled)
9628*8975f5c5SAndroid Build Coastguard Worker     {
9629*8975f5c5SAndroid Build Coastguard Worker         std::string proto = "const char *GetSerializedContextState(uint32_t frameIndex)";
9630*8975f5c5SAndroid Build Coastguard Worker 
9631*8975f5c5SAndroid Build Coastguard Worker         std::stringstream source;
9632*8975f5c5SAndroid Build Coastguard Worker 
9633*8975f5c5SAndroid Build Coastguard Worker         source << proto << "\n";
9634*8975f5c5SAndroid Build Coastguard Worker         source << "{\n";
9635*8975f5c5SAndroid Build Coastguard Worker         source << "    switch (frameIndex)\n";
9636*8975f5c5SAndroid Build Coastguard Worker         source << "    {\n";
9637*8975f5c5SAndroid Build Coastguard Worker         for (uint32_t frameIndex = 1; frameIndex <= getFrameCount(); ++frameIndex)
9638*8975f5c5SAndroid Build Coastguard Worker         {
9639*8975f5c5SAndroid Build Coastguard Worker             source << "        case " << frameIndex << ":\n";
9640*8975f5c5SAndroid Build Coastguard Worker             source << "            return "
9641*8975f5c5SAndroid Build Coastguard Worker                    << FmtGetSerializedContextStateFunction(contextId, FuncUsage::Call, frameIndex)
9642*8975f5c5SAndroid Build Coastguard Worker                    << ";\n";
9643*8975f5c5SAndroid Build Coastguard Worker         }
9644*8975f5c5SAndroid Build Coastguard Worker         source << "        default:\n";
9645*8975f5c5SAndroid Build Coastguard Worker         source << "            return NULL;\n";
9646*8975f5c5SAndroid Build Coastguard Worker         source << "    }\n";
9647*8975f5c5SAndroid Build Coastguard Worker         source << "}\n";
9648*8975f5c5SAndroid Build Coastguard Worker 
9649*8975f5c5SAndroid Build Coastguard Worker         mReplayWriter.addPublicFunction(proto, std::stringstream(), source);
9650*8975f5c5SAndroid Build Coastguard Worker     }
9651*8975f5c5SAndroid Build Coastguard Worker 
9652*8975f5c5SAndroid Build Coastguard Worker     {
9653*8975f5c5SAndroid Build Coastguard Worker         std::stringstream fnameStream;
9654*8975f5c5SAndroid Build Coastguard Worker         fnameStream << mOutDirectory << FmtCapturePrefix(contextId, mCaptureLabel);
9655*8975f5c5SAndroid Build Coastguard Worker         std::string fnamePattern = fnameStream.str();
9656*8975f5c5SAndroid Build Coastguard Worker 
9657*8975f5c5SAndroid Build Coastguard Worker         mReplayWriter.setFilenamePattern(fnamePattern);
9658*8975f5c5SAndroid Build Coastguard Worker     }
9659*8975f5c5SAndroid Build Coastguard Worker 
9660*8975f5c5SAndroid Build Coastguard Worker     mReplayWriter.saveIndexFilesAndHeader();
9661*8975f5c5SAndroid Build Coastguard Worker 
9662*8975f5c5SAndroid Build Coastguard Worker     writeJSON(context);
9663*8975f5c5SAndroid Build Coastguard Worker }
9664*8975f5c5SAndroid Build Coastguard Worker 
writeMainContextCppReplay(const gl::Context * context,const std::vector<CallCapture> & setupCalls,StateResetHelper & stateResetHelper)9665*8975f5c5SAndroid Build Coastguard Worker void FrameCaptureShared::writeMainContextCppReplay(const gl::Context *context,
9666*8975f5c5SAndroid Build Coastguard Worker                                                    const std::vector<CallCapture> &setupCalls,
9667*8975f5c5SAndroid Build Coastguard Worker                                                    StateResetHelper &stateResetHelper)
9668*8975f5c5SAndroid Build Coastguard Worker {
9669*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mWindowSurfaceContextID == context->id());
9670*8975f5c5SAndroid Build Coastguard Worker 
9671*8975f5c5SAndroid Build Coastguard Worker     {
9672*8975f5c5SAndroid Build Coastguard Worker         std::stringstream header;
9673*8975f5c5SAndroid Build Coastguard Worker 
9674*8975f5c5SAndroid Build Coastguard Worker         header << "#include \"" << FmtCapturePrefix(context->id(), mCaptureLabel) << ".h\"\n";
9675*8975f5c5SAndroid Build Coastguard Worker         header << "#include \"angle_trace_gl.h\"\n";
9676*8975f5c5SAndroid Build Coastguard Worker 
9677*8975f5c5SAndroid Build Coastguard Worker         std::string headerString = header.str();
9678*8975f5c5SAndroid Build Coastguard Worker         mReplayWriter.setSourcePrologue(headerString);
9679*8975f5c5SAndroid Build Coastguard Worker     }
9680*8975f5c5SAndroid Build Coastguard Worker 
9681*8975f5c5SAndroid Build Coastguard Worker     uint32_t frameCount = getFrameCount();
9682*8975f5c5SAndroid Build Coastguard Worker     uint32_t frameIndex = getReplayFrameIndex();
9683*8975f5c5SAndroid Build Coastguard Worker 
9684*8975f5c5SAndroid Build Coastguard Worker     if (frameIndex == 1)
9685*8975f5c5SAndroid Build Coastguard Worker     {
9686*8975f5c5SAndroid Build Coastguard Worker         {
9687*8975f5c5SAndroid Build Coastguard Worker             std::string proto = "void SetupReplay(void)";
9688*8975f5c5SAndroid Build Coastguard Worker 
9689*8975f5c5SAndroid Build Coastguard Worker             std::stringstream out;
9690*8975f5c5SAndroid Build Coastguard Worker 
9691*8975f5c5SAndroid Build Coastguard Worker             out << proto << "\n";
9692*8975f5c5SAndroid Build Coastguard Worker             out << "{\n";
9693*8975f5c5SAndroid Build Coastguard Worker 
9694*8975f5c5SAndroid Build Coastguard Worker             // Setup all of the shared objects.
9695*8975f5c5SAndroid Build Coastguard Worker             out << "    InitReplay();\n";
9696*8975f5c5SAndroid Build Coastguard Worker             if (usesMidExecutionCapture())
9697*8975f5c5SAndroid Build Coastguard Worker             {
9698*8975f5c5SAndroid Build Coastguard Worker                 out << "    " << FmtSetupFunction(kNoPartId, kSharedContextId, FuncUsage::Call)
9699*8975f5c5SAndroid Build Coastguard Worker                     << ";\n";
9700*8975f5c5SAndroid Build Coastguard Worker                 out << "    "
9701*8975f5c5SAndroid Build Coastguard Worker                     << FmtSetupInactiveFunction(kNoPartId, kSharedContextId, FuncUsage::Call)
9702*8975f5c5SAndroid Build Coastguard Worker                     << "\n";
9703*8975f5c5SAndroid Build Coastguard Worker                 // Make sure that the current context is mapped correctly
9704*8975f5c5SAndroid Build Coastguard Worker                 out << "    SetCurrentContextID(" << context->id() << ");\n";
9705*8975f5c5SAndroid Build Coastguard Worker             }
9706*8975f5c5SAndroid Build Coastguard Worker 
9707*8975f5c5SAndroid Build Coastguard Worker             // Setup each of the auxiliary contexts.
9708*8975f5c5SAndroid Build Coastguard Worker             egl::ShareGroup *shareGroup            = context->getShareGroup();
9709*8975f5c5SAndroid Build Coastguard Worker             const egl::ContextMap &shareContextMap = shareGroup->getContexts();
9710*8975f5c5SAndroid Build Coastguard Worker             for (auto shareContext : shareContextMap)
9711*8975f5c5SAndroid Build Coastguard Worker             {
9712*8975f5c5SAndroid Build Coastguard Worker                 if (shareContext.first == context->id().value)
9713*8975f5c5SAndroid Build Coastguard Worker                 {
9714*8975f5c5SAndroid Build Coastguard Worker                     if (usesMidExecutionCapture())
9715*8975f5c5SAndroid Build Coastguard Worker                     {
9716*8975f5c5SAndroid Build Coastguard Worker                         // Setup the presentation (this) context first.
9717*8975f5c5SAndroid Build Coastguard Worker                         out << "    " << FmtSetupFunction(kNoPartId, context->id(), FuncUsage::Call)
9718*8975f5c5SAndroid Build Coastguard Worker                             << ";\n";
9719*8975f5c5SAndroid Build Coastguard Worker                         out << "\n";
9720*8975f5c5SAndroid Build Coastguard Worker                     }
9721*8975f5c5SAndroid Build Coastguard Worker 
9722*8975f5c5SAndroid Build Coastguard Worker                     continue;
9723*8975f5c5SAndroid Build Coastguard Worker                 }
9724*8975f5c5SAndroid Build Coastguard Worker 
9725*8975f5c5SAndroid Build Coastguard Worker                 // The SetupReplayContextXX() calls only exist if this is a mid-execution capture
9726*8975f5c5SAndroid Build Coastguard Worker                 // and we can only call them if they exist, so only output the calls if this is a
9727*8975f5c5SAndroid Build Coastguard Worker                 // MEC.
9728*8975f5c5SAndroid Build Coastguard Worker                 if (usesMidExecutionCapture())
9729*8975f5c5SAndroid Build Coastguard Worker                 {
9730*8975f5c5SAndroid Build Coastguard Worker                     // Only call SetupReplayContext for secondary contexts that were current before
9731*8975f5c5SAndroid Build Coastguard Worker                     // MEC started
9732*8975f5c5SAndroid Build Coastguard Worker                     if (mActiveContexts.find(shareContext.first) != mActiveContexts.end())
9733*8975f5c5SAndroid Build Coastguard Worker                     {
9734*8975f5c5SAndroid Build Coastguard Worker                         // TODO(http://anglebug.com/42264418): Support capture/replay of
9735*8975f5c5SAndroid Build Coastguard Worker                         // eglCreateContext() so this block can be moved into SetupReplayContextXX()
9736*8975f5c5SAndroid Build Coastguard Worker                         // by injecting them into the beginning of the setup call stream.
9737*8975f5c5SAndroid Build Coastguard Worker                         out << "    CreateContext(" << shareContext.first << ");\n";
9738*8975f5c5SAndroid Build Coastguard Worker 
9739*8975f5c5SAndroid Build Coastguard Worker                         out << "    "
9740*8975f5c5SAndroid Build Coastguard Worker                             << FmtSetupFunction(kNoPartId, shareContext.second->id(),
9741*8975f5c5SAndroid Build Coastguard Worker                                                 FuncUsage::Call)
9742*8975f5c5SAndroid Build Coastguard Worker                             << ";\n";
9743*8975f5c5SAndroid Build Coastguard Worker                     }
9744*8975f5c5SAndroid Build Coastguard Worker                 }
9745*8975f5c5SAndroid Build Coastguard Worker             }
9746*8975f5c5SAndroid Build Coastguard Worker 
9747*8975f5c5SAndroid Build Coastguard Worker             // If there are other contexts that were initialized, we need to make the main context
9748*8975f5c5SAndroid Build Coastguard Worker             // current again.
9749*8975f5c5SAndroid Build Coastguard Worker             if (shareContextMap.size() > 1)
9750*8975f5c5SAndroid Build Coastguard Worker             {
9751*8975f5c5SAndroid Build Coastguard Worker                 out << "\n";
9752*8975f5c5SAndroid Build Coastguard Worker                 out << "    eglMakeCurrent(NULL, NULL, NULL, gContextMap2[" << context->id()
9753*8975f5c5SAndroid Build Coastguard Worker                     << "]);\n";
9754*8975f5c5SAndroid Build Coastguard Worker             }
9755*8975f5c5SAndroid Build Coastguard Worker 
9756*8975f5c5SAndroid Build Coastguard Worker             out << "}\n";
9757*8975f5c5SAndroid Build Coastguard Worker 
9758*8975f5c5SAndroid Build Coastguard Worker             mReplayWriter.addPublicFunction(proto, std::stringstream(), out);
9759*8975f5c5SAndroid Build Coastguard Worker         }
9760*8975f5c5SAndroid Build Coastguard Worker     }
9761*8975f5c5SAndroid Build Coastguard Worker 
9762*8975f5c5SAndroid Build Coastguard Worker     // Emit code to reset back to starting state
9763*8975f5c5SAndroid Build Coastguard Worker     if (frameIndex == frameCount)
9764*8975f5c5SAndroid Build Coastguard Worker     {
9765*8975f5c5SAndroid Build Coastguard Worker         std::stringstream resetProtoStream;
9766*8975f5c5SAndroid Build Coastguard Worker         std::stringstream resetHeaderStream;
9767*8975f5c5SAndroid Build Coastguard Worker         std::stringstream resetBodyStream;
9768*8975f5c5SAndroid Build Coastguard Worker 
9769*8975f5c5SAndroid Build Coastguard Worker         resetProtoStream << "void ResetReplay(void)";
9770*8975f5c5SAndroid Build Coastguard Worker 
9771*8975f5c5SAndroid Build Coastguard Worker         resetBodyStream << resetProtoStream.str() << "\n";
9772*8975f5c5SAndroid Build Coastguard Worker         resetBodyStream << "{\n";
9773*8975f5c5SAndroid Build Coastguard Worker 
9774*8975f5c5SAndroid Build Coastguard Worker         // Grab the list of contexts to be reset
9775*8975f5c5SAndroid Build Coastguard Worker         std::set<gl::ContextID> contextIDs;
9776*8975f5c5SAndroid Build Coastguard Worker         mResourceTracker.getContextIDs(contextIDs);
9777*8975f5c5SAndroid Build Coastguard Worker 
9778*8975f5c5SAndroid Build Coastguard Worker         // TODO(http://anglebug.com/42264418): Look at moving this into the shared context file
9779*8975f5c5SAndroid Build Coastguard Worker         // since it's resetting shared objects.
9780*8975f5c5SAndroid Build Coastguard Worker 
9781*8975f5c5SAndroid Build Coastguard Worker         // TODO(http://anglebug.com/42263204): Support function parts when writing Reset functions
9782*8975f5c5SAndroid Build Coastguard Worker 
9783*8975f5c5SAndroid Build Coastguard Worker         // Track whether anything was written during Reset
9784*8975f5c5SAndroid Build Coastguard Worker         bool anyResourceReset = false;
9785*8975f5c5SAndroid Build Coastguard Worker 
9786*8975f5c5SAndroid Build Coastguard Worker         // Track whether we changed contexts during Reset
9787*8975f5c5SAndroid Build Coastguard Worker         bool contextChanged = false;
9788*8975f5c5SAndroid Build Coastguard Worker 
9789*8975f5c5SAndroid Build Coastguard Worker         // First emit shared object reset, including opaque and context state
9790*8975f5c5SAndroid Build Coastguard Worker         {
9791*8975f5c5SAndroid Build Coastguard Worker             std::stringstream protoStream;
9792*8975f5c5SAndroid Build Coastguard Worker             std::stringstream headerStream;
9793*8975f5c5SAndroid Build Coastguard Worker             std::stringstream bodyStream;
9794*8975f5c5SAndroid Build Coastguard Worker 
9795*8975f5c5SAndroid Build Coastguard Worker             protoStream << "void "
9796*8975f5c5SAndroid Build Coastguard Worker                         << FmtResetFunction(kNoPartId, kSharedContextId, FuncUsage::Prototype);
9797*8975f5c5SAndroid Build Coastguard Worker             bodyStream << protoStream.str() << "\n";
9798*8975f5c5SAndroid Build Coastguard Worker             bodyStream << "{\n";
9799*8975f5c5SAndroid Build Coastguard Worker 
9800*8975f5c5SAndroid Build Coastguard Worker             for (ResourceIDType resourceType : AllEnums<ResourceIDType>())
9801*8975f5c5SAndroid Build Coastguard Worker             {
9802*8975f5c5SAndroid Build Coastguard Worker                 if (!IsSharedObjectResource(resourceType))
9803*8975f5c5SAndroid Build Coastguard Worker                 {
9804*8975f5c5SAndroid Build Coastguard Worker                     continue;
9805*8975f5c5SAndroid Build Coastguard Worker                 }
9806*8975f5c5SAndroid Build Coastguard Worker                 // Use current context for shared reset
9807*8975f5c5SAndroid Build Coastguard Worker                 MaybeResetResources(context->getDisplay(), context->id(), resourceType,
9808*8975f5c5SAndroid Build Coastguard Worker                                     mReplayWriter, bodyStream, headerStream, &mResourceTracker,
9809*8975f5c5SAndroid Build Coastguard Worker                                     &mBinaryData, anyResourceReset, &mResourceIDBufferSize);
9810*8975f5c5SAndroid Build Coastguard Worker             }
9811*8975f5c5SAndroid Build Coastguard Worker 
9812*8975f5c5SAndroid Build Coastguard Worker             // Reset opaque type objects that don't have IDs, so are not ResourceIDTypes.
9813*8975f5c5SAndroid Build Coastguard Worker             MaybeResetOpaqueTypeObjects(mReplayWriter, bodyStream, headerStream, context,
9814*8975f5c5SAndroid Build Coastguard Worker                                         &mResourceTracker, &mBinaryData, &mResourceIDBufferSize);
9815*8975f5c5SAndroid Build Coastguard Worker 
9816*8975f5c5SAndroid Build Coastguard Worker             bodyStream << "}\n";
9817*8975f5c5SAndroid Build Coastguard Worker 
9818*8975f5c5SAndroid Build Coastguard Worker             mReplayWriter.addPrivateFunction(protoStream.str(), headerStream, bodyStream);
9819*8975f5c5SAndroid Build Coastguard Worker         }
9820*8975f5c5SAndroid Build Coastguard Worker 
9821*8975f5c5SAndroid Build Coastguard Worker         // Emit the call to shared object reset
9822*8975f5c5SAndroid Build Coastguard Worker         resetBodyStream << "    " << FmtResetFunction(kNoPartId, kSharedContextId, FuncUsage::Call)
9823*8975f5c5SAndroid Build Coastguard Worker                         << ";\n";
9824*8975f5c5SAndroid Build Coastguard Worker 
9825*8975f5c5SAndroid Build Coastguard Worker         // Reset our output tracker (Note: This was unused during shared reset)
9826*8975f5c5SAndroid Build Coastguard Worker         anyResourceReset = false;
9827*8975f5c5SAndroid Build Coastguard Worker 
9828*8975f5c5SAndroid Build Coastguard Worker         // Walk through all contexts that need Reset
9829*8975f5c5SAndroid Build Coastguard Worker         for (const gl::ContextID &contextID : contextIDs)
9830*8975f5c5SAndroid Build Coastguard Worker         {
9831*8975f5c5SAndroid Build Coastguard Worker             // Create a function to reset each context's non-shared objects
9832*8975f5c5SAndroid Build Coastguard Worker             {
9833*8975f5c5SAndroid Build Coastguard Worker                 std::stringstream protoStream;
9834*8975f5c5SAndroid Build Coastguard Worker                 std::stringstream headerStream;
9835*8975f5c5SAndroid Build Coastguard Worker                 std::stringstream bodyStream;
9836*8975f5c5SAndroid Build Coastguard Worker 
9837*8975f5c5SAndroid Build Coastguard Worker                 protoStream << "void "
9838*8975f5c5SAndroid Build Coastguard Worker                             << FmtResetFunction(kNoPartId, contextID, FuncUsage::Prototype);
9839*8975f5c5SAndroid Build Coastguard Worker                 bodyStream << protoStream.str() << "\n";
9840*8975f5c5SAndroid Build Coastguard Worker                 bodyStream << "{\n";
9841*8975f5c5SAndroid Build Coastguard Worker 
9842*8975f5c5SAndroid Build Coastguard Worker                 // Build the Reset calls in a separate stream so we can insert before them
9843*8975f5c5SAndroid Build Coastguard Worker                 std::stringstream resetStream;
9844*8975f5c5SAndroid Build Coastguard Worker 
9845*8975f5c5SAndroid Build Coastguard Worker                 for (ResourceIDType resourceType : AllEnums<ResourceIDType>())
9846*8975f5c5SAndroid Build Coastguard Worker                 {
9847*8975f5c5SAndroid Build Coastguard Worker                     if (IsSharedObjectResource(resourceType))
9848*8975f5c5SAndroid Build Coastguard Worker                     {
9849*8975f5c5SAndroid Build Coastguard Worker                         continue;
9850*8975f5c5SAndroid Build Coastguard Worker                     }
9851*8975f5c5SAndroid Build Coastguard Worker                     MaybeResetResources(context->getDisplay(), contextID, resourceType,
9852*8975f5c5SAndroid Build Coastguard Worker                                         mReplayWriter, resetStream, headerStream, &mResourceTracker,
9853*8975f5c5SAndroid Build Coastguard Worker                                         &mBinaryData, anyResourceReset, &mResourceIDBufferSize);
9854*8975f5c5SAndroid Build Coastguard Worker                 }
9855*8975f5c5SAndroid Build Coastguard Worker 
9856*8975f5c5SAndroid Build Coastguard Worker                 // Only call eglMakeCurrent if anything was actually reset in the function and the
9857*8975f5c5SAndroid Build Coastguard Worker                 // context differs from current
9858*8975f5c5SAndroid Build Coastguard Worker                 if (anyResourceReset && contextID != context->id())
9859*8975f5c5SAndroid Build Coastguard Worker                 {
9860*8975f5c5SAndroid Build Coastguard Worker                     contextChanged = true;
9861*8975f5c5SAndroid Build Coastguard Worker                     bodyStream << "    eglMakeCurrent(NULL, NULL, NULL, gContextMap2["
9862*8975f5c5SAndroid Build Coastguard Worker                                << contextID.value << "]);\n\n";
9863*8975f5c5SAndroid Build Coastguard Worker                 }
9864*8975f5c5SAndroid Build Coastguard Worker 
9865*8975f5c5SAndroid Build Coastguard Worker                 // Then append the Reset calls
9866*8975f5c5SAndroid Build Coastguard Worker                 bodyStream << resetStream.str();
9867*8975f5c5SAndroid Build Coastguard Worker 
9868*8975f5c5SAndroid Build Coastguard Worker                 bodyStream << "}\n";
9869*8975f5c5SAndroid Build Coastguard Worker                 mReplayWriter.addPrivateFunction(protoStream.str(), headerStream, bodyStream);
9870*8975f5c5SAndroid Build Coastguard Worker             }
9871*8975f5c5SAndroid Build Coastguard Worker 
9872*8975f5c5SAndroid Build Coastguard Worker             // Emit a call to reset each context's non-shared objects
9873*8975f5c5SAndroid Build Coastguard Worker             resetBodyStream << "    " << FmtResetFunction(kNoPartId, contextID, FuncUsage::Call)
9874*8975f5c5SAndroid Build Coastguard Worker                             << ";\n";
9875*8975f5c5SAndroid Build Coastguard Worker         }
9876*8975f5c5SAndroid Build Coastguard Worker 
9877*8975f5c5SAndroid Build Coastguard Worker         // Bind the main context again if we bound any additional contexts
9878*8975f5c5SAndroid Build Coastguard Worker         if (contextChanged)
9879*8975f5c5SAndroid Build Coastguard Worker         {
9880*8975f5c5SAndroid Build Coastguard Worker             resetBodyStream << "    eglMakeCurrent(NULL, NULL, NULL, gContextMap2["
9881*8975f5c5SAndroid Build Coastguard Worker                             << context->id().value << "]);\n";
9882*8975f5c5SAndroid Build Coastguard Worker         }
9883*8975f5c5SAndroid Build Coastguard Worker 
9884*8975f5c5SAndroid Build Coastguard Worker         // Now that we're back on the main context, reset any additional state
9885*8975f5c5SAndroid Build Coastguard Worker         resetBodyStream << "\n    // Reset main context state\n";
9886*8975f5c5SAndroid Build Coastguard Worker         MaybeResetContextState(mReplayWriter, resetBodyStream, resetHeaderStream, &mResourceTracker,
9887*8975f5c5SAndroid Build Coastguard Worker                                context, &mBinaryData, stateResetHelper, &mResourceIDBufferSize);
9888*8975f5c5SAndroid Build Coastguard Worker 
9889*8975f5c5SAndroid Build Coastguard Worker         resetBodyStream << "}\n";
9890*8975f5c5SAndroid Build Coastguard Worker 
9891*8975f5c5SAndroid Build Coastguard Worker         mReplayWriter.addPublicFunction(resetProtoStream.str(), resetHeaderStream, resetBodyStream);
9892*8975f5c5SAndroid Build Coastguard Worker     }
9893*8975f5c5SAndroid Build Coastguard Worker 
9894*8975f5c5SAndroid Build Coastguard Worker     if (!mFrameCalls.empty())
9895*8975f5c5SAndroid Build Coastguard Worker     {
9896*8975f5c5SAndroid Build Coastguard Worker         std::stringstream protoStream;
9897*8975f5c5SAndroid Build Coastguard Worker         protoStream << "void "
9898*8975f5c5SAndroid Build Coastguard Worker                     << FmtReplayFunction(context->id(), FuncUsage::Prototype, frameIndex);
9899*8975f5c5SAndroid Build Coastguard Worker         std::string proto = protoStream.str();
9900*8975f5c5SAndroid Build Coastguard Worker         std::stringstream headerStream;
9901*8975f5c5SAndroid Build Coastguard Worker         std::stringstream bodyStream;
9902*8975f5c5SAndroid Build Coastguard Worker 
9903*8975f5c5SAndroid Build Coastguard Worker         if (context->getShareGroup()->getContexts().size() > 1)
9904*8975f5c5SAndroid Build Coastguard Worker         {
9905*8975f5c5SAndroid Build Coastguard Worker             // Only ReplayFunc::Replay trace file output functions are affected by multi-context
9906*8975f5c5SAndroid Build Coastguard Worker             // call grouping so they can safely be special-cased here.
9907*8975f5c5SAndroid Build Coastguard Worker             WriteCppReplayFunctionWithPartsMultiContext(
9908*8975f5c5SAndroid Build Coastguard Worker                 context->id(), ReplayFunc::Replay, mReplayWriter, frameIndex, &mBinaryData,
9909*8975f5c5SAndroid Build Coastguard Worker                 mFrameCalls, headerStream, bodyStream, &mResourceIDBufferSize);
9910*8975f5c5SAndroid Build Coastguard Worker         }
9911*8975f5c5SAndroid Build Coastguard Worker         else
9912*8975f5c5SAndroid Build Coastguard Worker         {
9913*8975f5c5SAndroid Build Coastguard Worker             WriteCppReplayFunctionWithParts(context->id(), ReplayFunc::Replay, mReplayWriter,
9914*8975f5c5SAndroid Build Coastguard Worker                                             frameIndex, &mBinaryData, mFrameCalls, headerStream,
9915*8975f5c5SAndroid Build Coastguard Worker                                             bodyStream, &mResourceIDBufferSize);
9916*8975f5c5SAndroid Build Coastguard Worker         }
9917*8975f5c5SAndroid Build Coastguard Worker         mReplayWriter.addPrivateFunction(proto, headerStream, bodyStream);
9918*8975f5c5SAndroid Build Coastguard Worker     }
9919*8975f5c5SAndroid Build Coastguard Worker 
9920*8975f5c5SAndroid Build Coastguard Worker     if (mSerializeStateEnabled)
9921*8975f5c5SAndroid Build Coastguard Worker     {
9922*8975f5c5SAndroid Build Coastguard Worker         std::string serializedContextString;
9923*8975f5c5SAndroid Build Coastguard Worker         if (SerializeContextToString(const_cast<gl::Context *>(context),
9924*8975f5c5SAndroid Build Coastguard Worker                                      &serializedContextString) == Result::Continue)
9925*8975f5c5SAndroid Build Coastguard Worker         {
9926*8975f5c5SAndroid Build Coastguard Worker             std::stringstream protoStream;
9927*8975f5c5SAndroid Build Coastguard Worker             protoStream << "const char *"
9928*8975f5c5SAndroid Build Coastguard Worker                         << FmtGetSerializedContextStateFunction(context->id(), FuncUsage::Prototype,
9929*8975f5c5SAndroid Build Coastguard Worker                                                                 frameIndex);
9930*8975f5c5SAndroid Build Coastguard Worker             std::string proto = protoStream.str();
9931*8975f5c5SAndroid Build Coastguard Worker 
9932*8975f5c5SAndroid Build Coastguard Worker             std::stringstream bodyStream;
9933*8975f5c5SAndroid Build Coastguard Worker             bodyStream << proto << "\n";
9934*8975f5c5SAndroid Build Coastguard Worker             bodyStream << "{\n";
9935*8975f5c5SAndroid Build Coastguard Worker             bodyStream << "    return " << FmtMultiLineString(serializedContextString) << ";\n";
9936*8975f5c5SAndroid Build Coastguard Worker             bodyStream << "}\n";
9937*8975f5c5SAndroid Build Coastguard Worker 
9938*8975f5c5SAndroid Build Coastguard Worker             mReplayWriter.addPrivateFunction(proto, std::stringstream(), bodyStream);
9939*8975f5c5SAndroid Build Coastguard Worker         }
9940*8975f5c5SAndroid Build Coastguard Worker     }
9941*8975f5c5SAndroid Build Coastguard Worker 
9942*8975f5c5SAndroid Build Coastguard Worker     {
9943*8975f5c5SAndroid Build Coastguard Worker         std::stringstream fnamePatternStream;
9944*8975f5c5SAndroid Build Coastguard Worker         fnamePatternStream << mOutDirectory << FmtCapturePrefix(context->id(), mCaptureLabel);
9945*8975f5c5SAndroid Build Coastguard Worker         std::string fnamePattern = fnamePatternStream.str();
9946*8975f5c5SAndroid Build Coastguard Worker 
9947*8975f5c5SAndroid Build Coastguard Worker         mReplayWriter.setFilenamePattern(fnamePattern);
9948*8975f5c5SAndroid Build Coastguard Worker     }
9949*8975f5c5SAndroid Build Coastguard Worker 
9950*8975f5c5SAndroid Build Coastguard Worker     if (mFrameIndex == mCaptureEndFrame)
9951*8975f5c5SAndroid Build Coastguard Worker     {
9952*8975f5c5SAndroid Build Coastguard Worker         mReplayWriter.saveFrame();
9953*8975f5c5SAndroid Build Coastguard Worker     }
9954*8975f5c5SAndroid Build Coastguard Worker     else
9955*8975f5c5SAndroid Build Coastguard Worker     {
9956*8975f5c5SAndroid Build Coastguard Worker         mReplayWriter.saveFrameIfFull();
9957*8975f5c5SAndroid Build Coastguard Worker     }
9958*8975f5c5SAndroid Build Coastguard Worker }
9959*8975f5c5SAndroid Build Coastguard Worker 
reset()9960*8975f5c5SAndroid Build Coastguard Worker void FrameCaptureShared::reset()
9961*8975f5c5SAndroid Build Coastguard Worker {
9962*8975f5c5SAndroid Build Coastguard Worker     mFrameCalls.clear();
9963*8975f5c5SAndroid Build Coastguard Worker     mClientVertexArrayMap.fill(-1);
9964*8975f5c5SAndroid Build Coastguard Worker 
9965*8975f5c5SAndroid Build Coastguard Worker     // Do not reset replay-specific settings like the maximum read buffer size, client array sizes,
9966*8975f5c5SAndroid Build Coastguard Worker     // or the 'has seen' type map. We could refine this into per-frame and per-capture maximums if
9967*8975f5c5SAndroid Build Coastguard Worker     // necessary.
9968*8975f5c5SAndroid Build Coastguard Worker }
9969*8975f5c5SAndroid Build Coastguard Worker 
getShaderSource(gl::ShaderProgramID id) const9970*8975f5c5SAndroid Build Coastguard Worker const std::string &FrameCaptureShared::getShaderSource(gl::ShaderProgramID id) const
9971*8975f5c5SAndroid Build Coastguard Worker {
9972*8975f5c5SAndroid Build Coastguard Worker     const auto &foundSources = mCachedShaderSource.find(id);
9973*8975f5c5SAndroid Build Coastguard Worker     ASSERT(foundSources != mCachedShaderSource.end());
9974*8975f5c5SAndroid Build Coastguard Worker     return foundSources->second;
9975*8975f5c5SAndroid Build Coastguard Worker }
9976*8975f5c5SAndroid Build Coastguard Worker 
setShaderSource(gl::ShaderProgramID id,std::string source)9977*8975f5c5SAndroid Build Coastguard Worker void FrameCaptureShared::setShaderSource(gl::ShaderProgramID id, std::string source)
9978*8975f5c5SAndroid Build Coastguard Worker {
9979*8975f5c5SAndroid Build Coastguard Worker     mCachedShaderSource[id] = source;
9980*8975f5c5SAndroid Build Coastguard Worker }
9981*8975f5c5SAndroid Build Coastguard Worker 
getProgramSources(gl::ShaderProgramID id) const9982*8975f5c5SAndroid Build Coastguard Worker const ProgramSources &FrameCaptureShared::getProgramSources(gl::ShaderProgramID id) const
9983*8975f5c5SAndroid Build Coastguard Worker {
9984*8975f5c5SAndroid Build Coastguard Worker     const auto &foundSources = mCachedProgramSources.find(id);
9985*8975f5c5SAndroid Build Coastguard Worker     ASSERT(foundSources != mCachedProgramSources.end());
9986*8975f5c5SAndroid Build Coastguard Worker     return foundSources->second;
9987*8975f5c5SAndroid Build Coastguard Worker }
9988*8975f5c5SAndroid Build Coastguard Worker 
setProgramSources(gl::ShaderProgramID id,ProgramSources sources)9989*8975f5c5SAndroid Build Coastguard Worker void FrameCaptureShared::setProgramSources(gl::ShaderProgramID id, ProgramSources sources)
9990*8975f5c5SAndroid Build Coastguard Worker {
9991*8975f5c5SAndroid Build Coastguard Worker     mCachedProgramSources[id] = sources;
9992*8975f5c5SAndroid Build Coastguard Worker }
9993*8975f5c5SAndroid Build Coastguard Worker 
markResourceSetupCallsInactive(std::vector<CallCapture> * setupCalls,ResourceIDType type,GLuint id,gl::Range<size_t> range)9994*8975f5c5SAndroid Build Coastguard Worker void FrameCaptureShared::markResourceSetupCallsInactive(std::vector<CallCapture> *setupCalls,
9995*8975f5c5SAndroid Build Coastguard Worker                                                         ResourceIDType type,
9996*8975f5c5SAndroid Build Coastguard Worker                                                         GLuint id,
9997*8975f5c5SAndroid Build Coastguard Worker                                                         gl::Range<size_t> range)
9998*8975f5c5SAndroid Build Coastguard Worker {
9999*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mResourceIDToSetupCalls[type].find(id) == mResourceIDToSetupCalls[type].end());
10000*8975f5c5SAndroid Build Coastguard Worker 
10001*8975f5c5SAndroid Build Coastguard Worker     // Mark all of the calls that were used to initialize this resource as INACTIVE
10002*8975f5c5SAndroid Build Coastguard Worker     for (size_t index : range)
10003*8975f5c5SAndroid Build Coastguard Worker     {
10004*8975f5c5SAndroid Build Coastguard Worker         (*setupCalls)[index].isActive = false;
10005*8975f5c5SAndroid Build Coastguard Worker     }
10006*8975f5c5SAndroid Build Coastguard Worker 
10007*8975f5c5SAndroid Build Coastguard Worker     mResourceIDToSetupCalls[type][id] = range;
10008*8975f5c5SAndroid Build Coastguard Worker }
10009*8975f5c5SAndroid Build Coastguard Worker 
CaptureMemory(const void * source,size_t size,ParamCapture * paramCapture)10010*8975f5c5SAndroid Build Coastguard Worker void CaptureMemory(const void *source, size_t size, ParamCapture *paramCapture)
10011*8975f5c5SAndroid Build Coastguard Worker {
10012*8975f5c5SAndroid Build Coastguard Worker     std::vector<uint8_t> data(size);
10013*8975f5c5SAndroid Build Coastguard Worker     memcpy(data.data(), source, size);
10014*8975f5c5SAndroid Build Coastguard Worker     paramCapture->data.emplace_back(std::move(data));
10015*8975f5c5SAndroid Build Coastguard Worker }
10016*8975f5c5SAndroid Build Coastguard Worker 
CaptureString(const GLchar * str,ParamCapture * paramCapture)10017*8975f5c5SAndroid Build Coastguard Worker void CaptureString(const GLchar *str, ParamCapture *paramCapture)
10018*8975f5c5SAndroid Build Coastguard Worker {
10019*8975f5c5SAndroid Build Coastguard Worker     // include the '\0' suffix
10020*8975f5c5SAndroid Build Coastguard Worker     CaptureMemory(str, strlen(str) + 1, paramCapture);
10021*8975f5c5SAndroid Build Coastguard Worker }
10022*8975f5c5SAndroid Build Coastguard Worker 
CaptureStringLimit(const GLchar * str,uint32_t limit,ParamCapture * paramCapture)10023*8975f5c5SAndroid Build Coastguard Worker void CaptureStringLimit(const GLchar *str, uint32_t limit, ParamCapture *paramCapture)
10024*8975f5c5SAndroid Build Coastguard Worker {
10025*8975f5c5SAndroid Build Coastguard Worker     // Write the incoming string up to limit, including null terminator
10026*8975f5c5SAndroid Build Coastguard Worker     size_t length = strlen(str) + 1;
10027*8975f5c5SAndroid Build Coastguard Worker 
10028*8975f5c5SAndroid Build Coastguard Worker     if (length > limit)
10029*8975f5c5SAndroid Build Coastguard Worker     {
10030*8975f5c5SAndroid Build Coastguard Worker         // If too many characters, resize the string to fit in the limit
10031*8975f5c5SAndroid Build Coastguard Worker         std::string newStr = str;
10032*8975f5c5SAndroid Build Coastguard Worker         newStr.resize(limit - 1);
10033*8975f5c5SAndroid Build Coastguard Worker         CaptureString(newStr.c_str(), paramCapture);
10034*8975f5c5SAndroid Build Coastguard Worker     }
10035*8975f5c5SAndroid Build Coastguard Worker     else
10036*8975f5c5SAndroid Build Coastguard Worker     {
10037*8975f5c5SAndroid Build Coastguard Worker         CaptureMemory(str, length, paramCapture);
10038*8975f5c5SAndroid Build Coastguard Worker     }
10039*8975f5c5SAndroid Build Coastguard Worker }
10040*8975f5c5SAndroid Build Coastguard Worker 
CaptureVertexPointerGLES1(const gl::State & glState,gl::ClientVertexArrayType type,const void * pointer,ParamCapture * paramCapture)10041*8975f5c5SAndroid Build Coastguard Worker void CaptureVertexPointerGLES1(const gl::State &glState,
10042*8975f5c5SAndroid Build Coastguard Worker                                gl::ClientVertexArrayType type,
10043*8975f5c5SAndroid Build Coastguard Worker                                const void *pointer,
10044*8975f5c5SAndroid Build Coastguard Worker                                ParamCapture *paramCapture)
10045*8975f5c5SAndroid Build Coastguard Worker {
10046*8975f5c5SAndroid Build Coastguard Worker     paramCapture->value.voidConstPointerVal = pointer;
10047*8975f5c5SAndroid Build Coastguard Worker     if (!glState.getTargetBuffer(gl::BufferBinding::Array))
10048*8975f5c5SAndroid Build Coastguard Worker     {
10049*8975f5c5SAndroid Build Coastguard Worker         paramCapture->arrayClientPointerIndex =
10050*8975f5c5SAndroid Build Coastguard Worker             gl::GLES1Renderer::VertexArrayIndex(type, glState.gles1());
10051*8975f5c5SAndroid Build Coastguard Worker     }
10052*8975f5c5SAndroid Build Coastguard Worker }
10053*8975f5c5SAndroid Build Coastguard Worker 
GetProgramForCapture(const gl::State & glState,gl::ShaderProgramID handle)10054*8975f5c5SAndroid Build Coastguard Worker gl::Program *GetProgramForCapture(const gl::State &glState, gl::ShaderProgramID handle)
10055*8975f5c5SAndroid Build Coastguard Worker {
10056*8975f5c5SAndroid Build Coastguard Worker     gl::Program *program = glState.getShaderProgramManagerForCapture().getProgram(handle);
10057*8975f5c5SAndroid Build Coastguard Worker     return program;
10058*8975f5c5SAndroid Build Coastguard Worker }
10059*8975f5c5SAndroid Build Coastguard Worker 
CaptureGetActiveUniformBlockivParameters(const gl::State & glState,gl::ShaderProgramID handle,gl::UniformBlockIndex uniformBlockIndex,GLenum pname,ParamCapture * paramCapture)10060*8975f5c5SAndroid Build Coastguard Worker void CaptureGetActiveUniformBlockivParameters(const gl::State &glState,
10061*8975f5c5SAndroid Build Coastguard Worker                                               gl::ShaderProgramID handle,
10062*8975f5c5SAndroid Build Coastguard Worker                                               gl::UniformBlockIndex uniformBlockIndex,
10063*8975f5c5SAndroid Build Coastguard Worker                                               GLenum pname,
10064*8975f5c5SAndroid Build Coastguard Worker                                               ParamCapture *paramCapture)
10065*8975f5c5SAndroid Build Coastguard Worker {
10066*8975f5c5SAndroid Build Coastguard Worker     int numParams = 1;
10067*8975f5c5SAndroid Build Coastguard Worker 
10068*8975f5c5SAndroid Build Coastguard Worker     // From the OpenGL ES 3.0 spec:
10069*8975f5c5SAndroid Build Coastguard Worker     // If pname is UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, then a list of the
10070*8975f5c5SAndroid Build Coastguard Worker     // active uniform indices for the uniform block identified by uniformBlockIndex is
10071*8975f5c5SAndroid Build Coastguard Worker     // returned. The number of elements that will be written to params is the value of
10072*8975f5c5SAndroid Build Coastguard Worker     // UNIFORM_BLOCK_ACTIVE_UNIFORMS for uniformBlockIndex
10073*8975f5c5SAndroid Build Coastguard Worker     if (pname == GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES)
10074*8975f5c5SAndroid Build Coastguard Worker     {
10075*8975f5c5SAndroid Build Coastguard Worker         gl::Program *program = GetProgramForCapture(glState, handle);
10076*8975f5c5SAndroid Build Coastguard Worker         if (program)
10077*8975f5c5SAndroid Build Coastguard Worker         {
10078*8975f5c5SAndroid Build Coastguard Worker             gl::QueryActiveUniformBlockiv(program, uniformBlockIndex,
10079*8975f5c5SAndroid Build Coastguard Worker                                           GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &numParams);
10080*8975f5c5SAndroid Build Coastguard Worker         }
10081*8975f5c5SAndroid Build Coastguard Worker     }
10082*8975f5c5SAndroid Build Coastguard Worker 
10083*8975f5c5SAndroid Build Coastguard Worker     paramCapture->readBufferSizeBytes = sizeof(GLint) * numParams;
10084*8975f5c5SAndroid Build Coastguard Worker }
10085*8975f5c5SAndroid Build Coastguard Worker 
CaptureGetParameter(const gl::State & glState,GLenum pname,size_t typeSize,ParamCapture * paramCapture)10086*8975f5c5SAndroid Build Coastguard Worker void CaptureGetParameter(const gl::State &glState,
10087*8975f5c5SAndroid Build Coastguard Worker                          GLenum pname,
10088*8975f5c5SAndroid Build Coastguard Worker                          size_t typeSize,
10089*8975f5c5SAndroid Build Coastguard Worker                          ParamCapture *paramCapture)
10090*8975f5c5SAndroid Build Coastguard Worker {
10091*8975f5c5SAndroid Build Coastguard Worker     // kMaxReportedCapabilities is the biggest array we'll need to hold data from glGet calls.
10092*8975f5c5SAndroid Build Coastguard Worker     // This value needs to be updated if any new extensions are introduced that would allow for
10093*8975f5c5SAndroid Build Coastguard Worker     // more compressed texture formats. The current value is taken from:
10094*8975f5c5SAndroid Build Coastguard Worker     // http://opengles.gpuinfo.org/displaycapability.php?name=GL_NUM_COMPRESSED_TEXTURE_FORMATS&esversion=2
10095*8975f5c5SAndroid Build Coastguard Worker     constexpr unsigned int kMaxReportedCapabilities = 69;
10096*8975f5c5SAndroid Build Coastguard Worker     paramCapture->readBufferSizeBytes               = typeSize * kMaxReportedCapabilities;
10097*8975f5c5SAndroid Build Coastguard Worker }
10098*8975f5c5SAndroid Build Coastguard Worker 
CaptureGenHandlesImpl(GLsizei n,GLuint * handles,ParamCapture * paramCapture)10099*8975f5c5SAndroid Build Coastguard Worker void CaptureGenHandlesImpl(GLsizei n, GLuint *handles, ParamCapture *paramCapture)
10100*8975f5c5SAndroid Build Coastguard Worker {
10101*8975f5c5SAndroid Build Coastguard Worker     paramCapture->readBufferSizeBytes = sizeof(GLuint) * n;
10102*8975f5c5SAndroid Build Coastguard Worker     CaptureMemory(handles, paramCapture->readBufferSizeBytes, paramCapture);
10103*8975f5c5SAndroid Build Coastguard Worker }
10104*8975f5c5SAndroid Build Coastguard Worker 
CaptureShaderStrings(GLsizei count,const GLchar * const * strings,const GLint * length,ParamCapture * paramCapture)10105*8975f5c5SAndroid Build Coastguard Worker void CaptureShaderStrings(GLsizei count,
10106*8975f5c5SAndroid Build Coastguard Worker                           const GLchar *const *strings,
10107*8975f5c5SAndroid Build Coastguard Worker                           const GLint *length,
10108*8975f5c5SAndroid Build Coastguard Worker                           ParamCapture *paramCapture)
10109*8975f5c5SAndroid Build Coastguard Worker {
10110*8975f5c5SAndroid Build Coastguard Worker     // Concat the array elements of the string into one data vector,
10111*8975f5c5SAndroid Build Coastguard Worker     // append the terminating zero and use this as the captured shader
10112*8975f5c5SAndroid Build Coastguard Worker     // string. The string count and the length array are adjusted
10113*8975f5c5SAndroid Build Coastguard Worker     // accordingly in the capture post-processing
10114*8975f5c5SAndroid Build Coastguard Worker 
10115*8975f5c5SAndroid Build Coastguard Worker     std::vector<uint8_t> data;
10116*8975f5c5SAndroid Build Coastguard Worker     size_t offset = 0;
10117*8975f5c5SAndroid Build Coastguard Worker     for (GLsizei index = 0; index < count; ++index)
10118*8975f5c5SAndroid Build Coastguard Worker     {
10119*8975f5c5SAndroid Build Coastguard Worker         size_t len = ((length && length[index] >= 0) ? length[index] : strlen(strings[index]));
10120*8975f5c5SAndroid Build Coastguard Worker 
10121*8975f5c5SAndroid Build Coastguard Worker         // Count trailing zeros
10122*8975f5c5SAndroid Build Coastguard Worker         uint32_t i = 1;
10123*8975f5c5SAndroid Build Coastguard Worker         while (i < len && strings[index][len - i] == 0)
10124*8975f5c5SAndroid Build Coastguard Worker         {
10125*8975f5c5SAndroid Build Coastguard Worker             i++;
10126*8975f5c5SAndroid Build Coastguard Worker         }
10127*8975f5c5SAndroid Build Coastguard Worker 
10128*8975f5c5SAndroid Build Coastguard Worker         // Don't copy trailing zeros
10129*8975f5c5SAndroid Build Coastguard Worker         len -= (i - 1);
10130*8975f5c5SAndroid Build Coastguard Worker 
10131*8975f5c5SAndroid Build Coastguard Worker         data.resize(offset + len);
10132*8975f5c5SAndroid Build Coastguard Worker         std::copy(strings[index], strings[index] + len, data.begin() + offset);
10133*8975f5c5SAndroid Build Coastguard Worker         offset += len;
10134*8975f5c5SAndroid Build Coastguard Worker     }
10135*8975f5c5SAndroid Build Coastguard Worker 
10136*8975f5c5SAndroid Build Coastguard Worker     data.push_back(0);
10137*8975f5c5SAndroid Build Coastguard Worker     paramCapture->data.emplace_back(std::move(data));
10138*8975f5c5SAndroid Build Coastguard Worker }
10139*8975f5c5SAndroid Build Coastguard Worker 
10140*8975f5c5SAndroid Build Coastguard Worker // ReplayWriter implementation.
ReplayWriter()10141*8975f5c5SAndroid Build Coastguard Worker ReplayWriter::ReplayWriter()
10142*8975f5c5SAndroid Build Coastguard Worker     : mSourceFileExtension(kDefaultSourceFileExt),
10143*8975f5c5SAndroid Build Coastguard Worker       mSourceFileSizeThreshold(kDefaultSourceFileSizeThreshold),
10144*8975f5c5SAndroid Build Coastguard Worker       mFrameIndex(1)
10145*8975f5c5SAndroid Build Coastguard Worker {}
10146*8975f5c5SAndroid Build Coastguard Worker 
~ReplayWriter()10147*8975f5c5SAndroid Build Coastguard Worker ReplayWriter::~ReplayWriter()
10148*8975f5c5SAndroid Build Coastguard Worker {
10149*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mPrivateFunctionPrototypes.empty());
10150*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mPublicFunctionPrototypes.empty());
10151*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mPrivateFunctions.empty());
10152*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mPublicFunctions.empty());
10153*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mGlobalVariableDeclarations.empty());
10154*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mReplayHeaders.empty());
10155*8975f5c5SAndroid Build Coastguard Worker }
10156*8975f5c5SAndroid Build Coastguard Worker 
setSourceFileExtension(const char * ext)10157*8975f5c5SAndroid Build Coastguard Worker void ReplayWriter::setSourceFileExtension(const char *ext)
10158*8975f5c5SAndroid Build Coastguard Worker {
10159*8975f5c5SAndroid Build Coastguard Worker     mSourceFileExtension = ext;
10160*8975f5c5SAndroid Build Coastguard Worker }
10161*8975f5c5SAndroid Build Coastguard Worker 
setSourceFileSizeThreshold(size_t sourceFileSizeThreshold)10162*8975f5c5SAndroid Build Coastguard Worker void ReplayWriter::setSourceFileSizeThreshold(size_t sourceFileSizeThreshold)
10163*8975f5c5SAndroid Build Coastguard Worker {
10164*8975f5c5SAndroid Build Coastguard Worker     mSourceFileSizeThreshold = sourceFileSizeThreshold;
10165*8975f5c5SAndroid Build Coastguard Worker }
10166*8975f5c5SAndroid Build Coastguard Worker 
setFilenamePattern(const std::string & pattern)10167*8975f5c5SAndroid Build Coastguard Worker void ReplayWriter::setFilenamePattern(const std::string &pattern)
10168*8975f5c5SAndroid Build Coastguard Worker {
10169*8975f5c5SAndroid Build Coastguard Worker     if (mFilenamePattern != pattern)
10170*8975f5c5SAndroid Build Coastguard Worker     {
10171*8975f5c5SAndroid Build Coastguard Worker         mFilenamePattern = pattern;
10172*8975f5c5SAndroid Build Coastguard Worker     }
10173*8975f5c5SAndroid Build Coastguard Worker }
10174*8975f5c5SAndroid Build Coastguard Worker 
setCaptureLabel(const std::string & label)10175*8975f5c5SAndroid Build Coastguard Worker void ReplayWriter::setCaptureLabel(const std::string &label)
10176*8975f5c5SAndroid Build Coastguard Worker {
10177*8975f5c5SAndroid Build Coastguard Worker     mCaptureLabel = label;
10178*8975f5c5SAndroid Build Coastguard Worker }
10179*8975f5c5SAndroid Build Coastguard Worker 
setSourcePrologue(const std::string & prologue)10180*8975f5c5SAndroid Build Coastguard Worker void ReplayWriter::setSourcePrologue(const std::string &prologue)
10181*8975f5c5SAndroid Build Coastguard Worker {
10182*8975f5c5SAndroid Build Coastguard Worker     mSourcePrologue = prologue;
10183*8975f5c5SAndroid Build Coastguard Worker }
10184*8975f5c5SAndroid Build Coastguard Worker 
setHeaderPrologue(const std::string & prologue)10185*8975f5c5SAndroid Build Coastguard Worker void ReplayWriter::setHeaderPrologue(const std::string &prologue)
10186*8975f5c5SAndroid Build Coastguard Worker {
10187*8975f5c5SAndroid Build Coastguard Worker     mHeaderPrologue = prologue;
10188*8975f5c5SAndroid Build Coastguard Worker }
10189*8975f5c5SAndroid Build Coastguard Worker 
addPublicFunction(const std::string & functionProto,const std::stringstream & headerStream,const std::stringstream & bodyStream)10190*8975f5c5SAndroid Build Coastguard Worker void ReplayWriter::addPublicFunction(const std::string &functionProto,
10191*8975f5c5SAndroid Build Coastguard Worker                                      const std::stringstream &headerStream,
10192*8975f5c5SAndroid Build Coastguard Worker                                      const std::stringstream &bodyStream)
10193*8975f5c5SAndroid Build Coastguard Worker {
10194*8975f5c5SAndroid Build Coastguard Worker     mPublicFunctionPrototypes.push_back(functionProto);
10195*8975f5c5SAndroid Build Coastguard Worker 
10196*8975f5c5SAndroid Build Coastguard Worker     std::string header = headerStream.str();
10197*8975f5c5SAndroid Build Coastguard Worker     std::string body   = bodyStream.str();
10198*8975f5c5SAndroid Build Coastguard Worker 
10199*8975f5c5SAndroid Build Coastguard Worker     if (!header.empty())
10200*8975f5c5SAndroid Build Coastguard Worker     {
10201*8975f5c5SAndroid Build Coastguard Worker         mReplayHeaders.emplace_back(header);
10202*8975f5c5SAndroid Build Coastguard Worker     }
10203*8975f5c5SAndroid Build Coastguard Worker 
10204*8975f5c5SAndroid Build Coastguard Worker     if (!body.empty())
10205*8975f5c5SAndroid Build Coastguard Worker     {
10206*8975f5c5SAndroid Build Coastguard Worker         mPublicFunctions.emplace_back(body);
10207*8975f5c5SAndroid Build Coastguard Worker     }
10208*8975f5c5SAndroid Build Coastguard Worker }
10209*8975f5c5SAndroid Build Coastguard Worker 
addPrivateFunction(const std::string & functionProto,const std::stringstream & headerStream,const std::stringstream & bodyStream)10210*8975f5c5SAndroid Build Coastguard Worker void ReplayWriter::addPrivateFunction(const std::string &functionProto,
10211*8975f5c5SAndroid Build Coastguard Worker                                       const std::stringstream &headerStream,
10212*8975f5c5SAndroid Build Coastguard Worker                                       const std::stringstream &bodyStream)
10213*8975f5c5SAndroid Build Coastguard Worker {
10214*8975f5c5SAndroid Build Coastguard Worker     mPrivateFunctionPrototypes.push_back(functionProto);
10215*8975f5c5SAndroid Build Coastguard Worker 
10216*8975f5c5SAndroid Build Coastguard Worker     std::string header = headerStream.str();
10217*8975f5c5SAndroid Build Coastguard Worker     std::string body   = bodyStream.str();
10218*8975f5c5SAndroid Build Coastguard Worker 
10219*8975f5c5SAndroid Build Coastguard Worker     if (!header.empty())
10220*8975f5c5SAndroid Build Coastguard Worker     {
10221*8975f5c5SAndroid Build Coastguard Worker         mReplayHeaders.emplace_back(header);
10222*8975f5c5SAndroid Build Coastguard Worker     }
10223*8975f5c5SAndroid Build Coastguard Worker 
10224*8975f5c5SAndroid Build Coastguard Worker     if (!body.empty())
10225*8975f5c5SAndroid Build Coastguard Worker     {
10226*8975f5c5SAndroid Build Coastguard Worker         mPrivateFunctions.emplace_back(body);
10227*8975f5c5SAndroid Build Coastguard Worker     }
10228*8975f5c5SAndroid Build Coastguard Worker }
10229*8975f5c5SAndroid Build Coastguard Worker 
getInlineVariableName(EntryPoint entryPoint,const std::string & paramName)10230*8975f5c5SAndroid Build Coastguard Worker std::string ReplayWriter::getInlineVariableName(EntryPoint entryPoint, const std::string &paramName)
10231*8975f5c5SAndroid Build Coastguard Worker {
10232*8975f5c5SAndroid Build Coastguard Worker     int counter = mDataTracker.getCounters().getAndIncrement(entryPoint, paramName);
10233*8975f5c5SAndroid Build Coastguard Worker     return GetVarName(entryPoint, paramName, counter);
10234*8975f5c5SAndroid Build Coastguard Worker }
10235*8975f5c5SAndroid Build Coastguard Worker 
getInlineStringSetVariableName(EntryPoint entryPoint,const std::string & paramName,const std::vector<std::string> & strings,bool * isNewEntryOut)10236*8975f5c5SAndroid Build Coastguard Worker std::string ReplayWriter::getInlineStringSetVariableName(EntryPoint entryPoint,
10237*8975f5c5SAndroid Build Coastguard Worker                                                          const std::string &paramName,
10238*8975f5c5SAndroid Build Coastguard Worker                                                          const std::vector<std::string> &strings,
10239*8975f5c5SAndroid Build Coastguard Worker                                                          bool *isNewEntryOut)
10240*8975f5c5SAndroid Build Coastguard Worker {
10241*8975f5c5SAndroid Build Coastguard Worker     int counter    = mDataTracker.getStringCounters().getStringCounter(strings);
10242*8975f5c5SAndroid Build Coastguard Worker     *isNewEntryOut = (counter == kStringsNotFound);
10243*8975f5c5SAndroid Build Coastguard Worker     if (*isNewEntryOut)
10244*8975f5c5SAndroid Build Coastguard Worker     {
10245*8975f5c5SAndroid Build Coastguard Worker         // This is a unique set of strings, so set up their declaration and update the counter
10246*8975f5c5SAndroid Build Coastguard Worker         counter = mDataTracker.getCounters().getAndIncrement(entryPoint, paramName);
10247*8975f5c5SAndroid Build Coastguard Worker         mDataTracker.getStringCounters().setStringCounter(strings, counter);
10248*8975f5c5SAndroid Build Coastguard Worker 
10249*8975f5c5SAndroid Build Coastguard Worker         std::string varName = GetVarName(entryPoint, paramName, counter);
10250*8975f5c5SAndroid Build Coastguard Worker 
10251*8975f5c5SAndroid Build Coastguard Worker         std::stringstream declStream;
10252*8975f5c5SAndroid Build Coastguard Worker         declStream << "const char *const " << varName << "[]";
10253*8975f5c5SAndroid Build Coastguard Worker         std::string decl = declStream.str();
10254*8975f5c5SAndroid Build Coastguard Worker 
10255*8975f5c5SAndroid Build Coastguard Worker         mGlobalVariableDeclarations.push_back(decl);
10256*8975f5c5SAndroid Build Coastguard Worker 
10257*8975f5c5SAndroid Build Coastguard Worker         return varName;
10258*8975f5c5SAndroid Build Coastguard Worker     }
10259*8975f5c5SAndroid Build Coastguard Worker     else
10260*8975f5c5SAndroid Build Coastguard Worker     {
10261*8975f5c5SAndroid Build Coastguard Worker         return GetVarName(entryPoint, paramName, counter);
10262*8975f5c5SAndroid Build Coastguard Worker     }
10263*8975f5c5SAndroid Build Coastguard Worker }
10264*8975f5c5SAndroid Build Coastguard Worker 
getStoredReplaySourceSize() const10265*8975f5c5SAndroid Build Coastguard Worker size_t ReplayWriter::getStoredReplaySourceSize() const
10266*8975f5c5SAndroid Build Coastguard Worker {
10267*8975f5c5SAndroid Build Coastguard Worker     size_t sum = 0;
10268*8975f5c5SAndroid Build Coastguard Worker     for (const std::string &header : mReplayHeaders)
10269*8975f5c5SAndroid Build Coastguard Worker     {
10270*8975f5c5SAndroid Build Coastguard Worker         sum += header.size();
10271*8975f5c5SAndroid Build Coastguard Worker     }
10272*8975f5c5SAndroid Build Coastguard Worker     for (const std::string &publicFunc : mPublicFunctions)
10273*8975f5c5SAndroid Build Coastguard Worker     {
10274*8975f5c5SAndroid Build Coastguard Worker         sum += publicFunc.size();
10275*8975f5c5SAndroid Build Coastguard Worker     }
10276*8975f5c5SAndroid Build Coastguard Worker     for (const std::string &privateFunc : mPrivateFunctions)
10277*8975f5c5SAndroid Build Coastguard Worker     {
10278*8975f5c5SAndroid Build Coastguard Worker         sum += privateFunc.size();
10279*8975f5c5SAndroid Build Coastguard Worker     }
10280*8975f5c5SAndroid Build Coastguard Worker     return sum;
10281*8975f5c5SAndroid Build Coastguard Worker }
10282*8975f5c5SAndroid Build Coastguard Worker 
10283*8975f5c5SAndroid Build Coastguard Worker // static
GetVarName(EntryPoint entryPoint,const std::string & paramName,int counter)10284*8975f5c5SAndroid Build Coastguard Worker std::string ReplayWriter::GetVarName(EntryPoint entryPoint,
10285*8975f5c5SAndroid Build Coastguard Worker                                      const std::string &paramName,
10286*8975f5c5SAndroid Build Coastguard Worker                                      int counter)
10287*8975f5c5SAndroid Build Coastguard Worker {
10288*8975f5c5SAndroid Build Coastguard Worker     std::stringstream strstr;
10289*8975f5c5SAndroid Build Coastguard Worker     strstr << GetEntryPointName(entryPoint) << "_" << paramName << "_" << counter;
10290*8975f5c5SAndroid Build Coastguard Worker     return strstr.str();
10291*8975f5c5SAndroid Build Coastguard Worker }
10292*8975f5c5SAndroid Build Coastguard Worker 
saveFrame()10293*8975f5c5SAndroid Build Coastguard Worker void ReplayWriter::saveFrame()
10294*8975f5c5SAndroid Build Coastguard Worker {
10295*8975f5c5SAndroid Build Coastguard Worker     if (mReplayHeaders.empty() && mPublicFunctions.empty() && mPrivateFunctions.empty())
10296*8975f5c5SAndroid Build Coastguard Worker     {
10297*8975f5c5SAndroid Build Coastguard Worker         return;
10298*8975f5c5SAndroid Build Coastguard Worker     }
10299*8975f5c5SAndroid Build Coastguard Worker 
10300*8975f5c5SAndroid Build Coastguard Worker     ASSERT(!mSourceFileExtension.empty());
10301*8975f5c5SAndroid Build Coastguard Worker 
10302*8975f5c5SAndroid Build Coastguard Worker     std::stringstream strstr;
10303*8975f5c5SAndroid Build Coastguard Worker     strstr << mFilenamePattern << "_" << std::setfill('0') << std::setw(3) << mFrameIndex++ << "."
10304*8975f5c5SAndroid Build Coastguard Worker            << mSourceFileExtension;
10305*8975f5c5SAndroid Build Coastguard Worker 
10306*8975f5c5SAndroid Build Coastguard Worker     std::string frameFilePath = strstr.str();
10307*8975f5c5SAndroid Build Coastguard Worker 
10308*8975f5c5SAndroid Build Coastguard Worker     writeReplaySource(frameFilePath);
10309*8975f5c5SAndroid Build Coastguard Worker }
10310*8975f5c5SAndroid Build Coastguard Worker 
saveFrameIfFull()10311*8975f5c5SAndroid Build Coastguard Worker void ReplayWriter::saveFrameIfFull()
10312*8975f5c5SAndroid Build Coastguard Worker {
10313*8975f5c5SAndroid Build Coastguard Worker     if (getStoredReplaySourceSize() < mSourceFileSizeThreshold)
10314*8975f5c5SAndroid Build Coastguard Worker     {
10315*8975f5c5SAndroid Build Coastguard Worker         INFO() << "Merging captured frame: " << getStoredReplaySourceSize()
10316*8975f5c5SAndroid Build Coastguard Worker                << " less than threshold of " << mSourceFileSizeThreshold << " bytes";
10317*8975f5c5SAndroid Build Coastguard Worker         return;
10318*8975f5c5SAndroid Build Coastguard Worker     }
10319*8975f5c5SAndroid Build Coastguard Worker 
10320*8975f5c5SAndroid Build Coastguard Worker     saveFrame();
10321*8975f5c5SAndroid Build Coastguard Worker }
10322*8975f5c5SAndroid Build Coastguard Worker 
saveHeader()10323*8975f5c5SAndroid Build Coastguard Worker void ReplayWriter::saveHeader()
10324*8975f5c5SAndroid Build Coastguard Worker {
10325*8975f5c5SAndroid Build Coastguard Worker     std::stringstream headerPathStream;
10326*8975f5c5SAndroid Build Coastguard Worker     headerPathStream << mFilenamePattern << ".h";
10327*8975f5c5SAndroid Build Coastguard Worker     std::string headerPath = headerPathStream.str();
10328*8975f5c5SAndroid Build Coastguard Worker 
10329*8975f5c5SAndroid Build Coastguard Worker     SaveFileHelper saveH(headerPath);
10330*8975f5c5SAndroid Build Coastguard Worker 
10331*8975f5c5SAndroid Build Coastguard Worker     saveH << mHeaderPrologue << "\n";
10332*8975f5c5SAndroid Build Coastguard Worker 
10333*8975f5c5SAndroid Build Coastguard Worker     saveH << "// Public functions are declared in trace_fixture.h.\n";
10334*8975f5c5SAndroid Build Coastguard Worker     saveH << "\n";
10335*8975f5c5SAndroid Build Coastguard Worker     saveH << "// Private Functions\n";
10336*8975f5c5SAndroid Build Coastguard Worker     saveH << "\n";
10337*8975f5c5SAndroid Build Coastguard Worker 
10338*8975f5c5SAndroid Build Coastguard Worker     for (const std::string &proto : mPrivateFunctionPrototypes)
10339*8975f5c5SAndroid Build Coastguard Worker     {
10340*8975f5c5SAndroid Build Coastguard Worker         saveH << proto << ";\n";
10341*8975f5c5SAndroid Build Coastguard Worker     }
10342*8975f5c5SAndroid Build Coastguard Worker 
10343*8975f5c5SAndroid Build Coastguard Worker     saveH << "\n";
10344*8975f5c5SAndroid Build Coastguard Worker     saveH << "// Global variables\n";
10345*8975f5c5SAndroid Build Coastguard Worker     saveH << "\n";
10346*8975f5c5SAndroid Build Coastguard Worker 
10347*8975f5c5SAndroid Build Coastguard Worker     for (const std::string &globalVar : mGlobalVariableDeclarations)
10348*8975f5c5SAndroid Build Coastguard Worker     {
10349*8975f5c5SAndroid Build Coastguard Worker         saveH << "extern " << globalVar << ";\n";
10350*8975f5c5SAndroid Build Coastguard Worker     }
10351*8975f5c5SAndroid Build Coastguard Worker 
10352*8975f5c5SAndroid Build Coastguard Worker     mPublicFunctionPrototypes.clear();
10353*8975f5c5SAndroid Build Coastguard Worker     mPrivateFunctionPrototypes.clear();
10354*8975f5c5SAndroid Build Coastguard Worker     mGlobalVariableDeclarations.clear();
10355*8975f5c5SAndroid Build Coastguard Worker 
10356*8975f5c5SAndroid Build Coastguard Worker     addWrittenFile(headerPath);
10357*8975f5c5SAndroid Build Coastguard Worker }
10358*8975f5c5SAndroid Build Coastguard Worker 
saveIndexFilesAndHeader()10359*8975f5c5SAndroid Build Coastguard Worker void ReplayWriter::saveIndexFilesAndHeader()
10360*8975f5c5SAndroid Build Coastguard Worker {
10361*8975f5c5SAndroid Build Coastguard Worker     ASSERT(!mSourceFileExtension.empty());
10362*8975f5c5SAndroid Build Coastguard Worker 
10363*8975f5c5SAndroid Build Coastguard Worker     std::stringstream sourcePathStream;
10364*8975f5c5SAndroid Build Coastguard Worker     sourcePathStream << mFilenamePattern << "." << mSourceFileExtension;
10365*8975f5c5SAndroid Build Coastguard Worker     std::string sourcePath = sourcePathStream.str();
10366*8975f5c5SAndroid Build Coastguard Worker 
10367*8975f5c5SAndroid Build Coastguard Worker     writeReplaySource(sourcePath);
10368*8975f5c5SAndroid Build Coastguard Worker     saveHeader();
10369*8975f5c5SAndroid Build Coastguard Worker }
10370*8975f5c5SAndroid Build Coastguard Worker 
saveSetupFile()10371*8975f5c5SAndroid Build Coastguard Worker void ReplayWriter::saveSetupFile()
10372*8975f5c5SAndroid Build Coastguard Worker {
10373*8975f5c5SAndroid Build Coastguard Worker     ASSERT(!mSourceFileExtension.empty());
10374*8975f5c5SAndroid Build Coastguard Worker 
10375*8975f5c5SAndroid Build Coastguard Worker     std::stringstream strstr;
10376*8975f5c5SAndroid Build Coastguard Worker     strstr << mFilenamePattern << "." << mSourceFileExtension;
10377*8975f5c5SAndroid Build Coastguard Worker 
10378*8975f5c5SAndroid Build Coastguard Worker     std::string frameFilePath = strstr.str();
10379*8975f5c5SAndroid Build Coastguard Worker 
10380*8975f5c5SAndroid Build Coastguard Worker     writeReplaySource(frameFilePath);
10381*8975f5c5SAndroid Build Coastguard Worker }
10382*8975f5c5SAndroid Build Coastguard Worker 
writeReplaySource(const std::string & filename)10383*8975f5c5SAndroid Build Coastguard Worker void ReplayWriter::writeReplaySource(const std::string &filename)
10384*8975f5c5SAndroid Build Coastguard Worker {
10385*8975f5c5SAndroid Build Coastguard Worker     SaveFileHelper saveCpp(filename);
10386*8975f5c5SAndroid Build Coastguard Worker 
10387*8975f5c5SAndroid Build Coastguard Worker     saveCpp << mSourcePrologue << "\n";
10388*8975f5c5SAndroid Build Coastguard Worker     for (const std::string &header : mReplayHeaders)
10389*8975f5c5SAndroid Build Coastguard Worker     {
10390*8975f5c5SAndroid Build Coastguard Worker         saveCpp << header << "\n";
10391*8975f5c5SAndroid Build Coastguard Worker     }
10392*8975f5c5SAndroid Build Coastguard Worker 
10393*8975f5c5SAndroid Build Coastguard Worker     saveCpp << "// Private Functions\n";
10394*8975f5c5SAndroid Build Coastguard Worker     saveCpp << "\n";
10395*8975f5c5SAndroid Build Coastguard Worker 
10396*8975f5c5SAndroid Build Coastguard Worker     for (const std::string &func : mPrivateFunctions)
10397*8975f5c5SAndroid Build Coastguard Worker     {
10398*8975f5c5SAndroid Build Coastguard Worker         saveCpp << func << "\n";
10399*8975f5c5SAndroid Build Coastguard Worker     }
10400*8975f5c5SAndroid Build Coastguard Worker 
10401*8975f5c5SAndroid Build Coastguard Worker     saveCpp << "// Public Functions\n";
10402*8975f5c5SAndroid Build Coastguard Worker     saveCpp << "\n";
10403*8975f5c5SAndroid Build Coastguard Worker 
10404*8975f5c5SAndroid Build Coastguard Worker     if (mFilenamePattern == "cpp")
10405*8975f5c5SAndroid Build Coastguard Worker     {
10406*8975f5c5SAndroid Build Coastguard Worker         saveCpp << "extern \"C\"\n";
10407*8975f5c5SAndroid Build Coastguard Worker         saveCpp << "{\n";
10408*8975f5c5SAndroid Build Coastguard Worker     }
10409*8975f5c5SAndroid Build Coastguard Worker 
10410*8975f5c5SAndroid Build Coastguard Worker     for (const std::string &func : mPublicFunctions)
10411*8975f5c5SAndroid Build Coastguard Worker     {
10412*8975f5c5SAndroid Build Coastguard Worker         saveCpp << func << "\n";
10413*8975f5c5SAndroid Build Coastguard Worker     }
10414*8975f5c5SAndroid Build Coastguard Worker 
10415*8975f5c5SAndroid Build Coastguard Worker     if (mFilenamePattern == "cpp")
10416*8975f5c5SAndroid Build Coastguard Worker     {
10417*8975f5c5SAndroid Build Coastguard Worker         saveCpp << "}  // extern \"C\"\n";
10418*8975f5c5SAndroid Build Coastguard Worker     }
10419*8975f5c5SAndroid Build Coastguard Worker 
10420*8975f5c5SAndroid Build Coastguard Worker     mReplayHeaders.clear();
10421*8975f5c5SAndroid Build Coastguard Worker     mPrivateFunctions.clear();
10422*8975f5c5SAndroid Build Coastguard Worker     mPublicFunctions.clear();
10423*8975f5c5SAndroid Build Coastguard Worker 
10424*8975f5c5SAndroid Build Coastguard Worker     addWrittenFile(filename);
10425*8975f5c5SAndroid Build Coastguard Worker }
10426*8975f5c5SAndroid Build Coastguard Worker 
addWrittenFile(const std::string & filename)10427*8975f5c5SAndroid Build Coastguard Worker void ReplayWriter::addWrittenFile(const std::string &filename)
10428*8975f5c5SAndroid Build Coastguard Worker {
10429*8975f5c5SAndroid Build Coastguard Worker     std::string writtenFile = GetBaseName(filename);
10430*8975f5c5SAndroid Build Coastguard Worker     ASSERT(std::find(mWrittenFiles.begin(), mWrittenFiles.end(), writtenFile) ==
10431*8975f5c5SAndroid Build Coastguard Worker            mWrittenFiles.end());
10432*8975f5c5SAndroid Build Coastguard Worker     mWrittenFiles.push_back(writtenFile);
10433*8975f5c5SAndroid Build Coastguard Worker }
10434*8975f5c5SAndroid Build Coastguard Worker 
getAndResetWrittenFiles()10435*8975f5c5SAndroid Build Coastguard Worker std::vector<std::string> ReplayWriter::getAndResetWrittenFiles()
10436*8975f5c5SAndroid Build Coastguard Worker {
10437*8975f5c5SAndroid Build Coastguard Worker     std::vector<std::string> results = std::move(mWrittenFiles);
10438*8975f5c5SAndroid Build Coastguard Worker     std::sort(results.begin(), results.end());
10439*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mWrittenFiles.empty());
10440*8975f5c5SAndroid Build Coastguard Worker     return results;
10441*8975f5c5SAndroid Build Coastguard Worker }
10442*8975f5c5SAndroid Build Coastguard Worker }  // namespace angle
10443*8975f5c5SAndroid Build Coastguard Worker 
10444*8975f5c5SAndroid Build Coastguard Worker namespace egl
10445*8975f5c5SAndroid Build Coastguard Worker {
CaptureAttributeMap(const egl::AttributeMap & attribMap)10446*8975f5c5SAndroid Build Coastguard Worker angle::ParamCapture CaptureAttributeMap(const egl::AttributeMap &attribMap)
10447*8975f5c5SAndroid Build Coastguard Worker {
10448*8975f5c5SAndroid Build Coastguard Worker     switch (attribMap.getType())
10449*8975f5c5SAndroid Build Coastguard Worker     {
10450*8975f5c5SAndroid Build Coastguard Worker         case AttributeMapType::Attrib:
10451*8975f5c5SAndroid Build Coastguard Worker         {
10452*8975f5c5SAndroid Build Coastguard Worker             angle::ParamCapture paramCapture("attrib_list", angle::ParamType::TEGLAttribPointer);
10453*8975f5c5SAndroid Build Coastguard Worker             if (attribMap.isEmpty())
10454*8975f5c5SAndroid Build Coastguard Worker             {
10455*8975f5c5SAndroid Build Coastguard Worker                 paramCapture.value.EGLAttribPointerVal = nullptr;
10456*8975f5c5SAndroid Build Coastguard Worker             }
10457*8975f5c5SAndroid Build Coastguard Worker             else
10458*8975f5c5SAndroid Build Coastguard Worker             {
10459*8975f5c5SAndroid Build Coastguard Worker                 std::vector<EGLAttrib> attribs;
10460*8975f5c5SAndroid Build Coastguard Worker                 for (const auto &[key, value] : attribMap)
10461*8975f5c5SAndroid Build Coastguard Worker                 {
10462*8975f5c5SAndroid Build Coastguard Worker                     attribs.push_back(key);
10463*8975f5c5SAndroid Build Coastguard Worker                     attribs.push_back(value);
10464*8975f5c5SAndroid Build Coastguard Worker                 }
10465*8975f5c5SAndroid Build Coastguard Worker                 attribs.push_back(EGL_NONE);
10466*8975f5c5SAndroid Build Coastguard Worker 
10467*8975f5c5SAndroid Build Coastguard Worker                 angle::CaptureMemory(attribs.data(), attribs.size() * sizeof(EGLAttrib),
10468*8975f5c5SAndroid Build Coastguard Worker                                      &paramCapture);
10469*8975f5c5SAndroid Build Coastguard Worker             }
10470*8975f5c5SAndroid Build Coastguard Worker             return paramCapture;
10471*8975f5c5SAndroid Build Coastguard Worker         }
10472*8975f5c5SAndroid Build Coastguard Worker 
10473*8975f5c5SAndroid Build Coastguard Worker         case AttributeMapType::Int:
10474*8975f5c5SAndroid Build Coastguard Worker         {
10475*8975f5c5SAndroid Build Coastguard Worker             angle::ParamCapture paramCapture("attrib_list", angle::ParamType::TEGLintPointer);
10476*8975f5c5SAndroid Build Coastguard Worker             if (attribMap.isEmpty())
10477*8975f5c5SAndroid Build Coastguard Worker             {
10478*8975f5c5SAndroid Build Coastguard Worker                 paramCapture.value.EGLintPointerVal = nullptr;
10479*8975f5c5SAndroid Build Coastguard Worker             }
10480*8975f5c5SAndroid Build Coastguard Worker             else
10481*8975f5c5SAndroid Build Coastguard Worker             {
10482*8975f5c5SAndroid Build Coastguard Worker                 std::vector<EGLint> attribs;
10483*8975f5c5SAndroid Build Coastguard Worker                 for (const auto &[key, value] : attribMap)
10484*8975f5c5SAndroid Build Coastguard Worker                 {
10485*8975f5c5SAndroid Build Coastguard Worker                     attribs.push_back(static_cast<EGLint>(key));
10486*8975f5c5SAndroid Build Coastguard Worker                     attribs.push_back(static_cast<EGLint>(value));
10487*8975f5c5SAndroid Build Coastguard Worker                 }
10488*8975f5c5SAndroid Build Coastguard Worker                 attribs.push_back(EGL_NONE);
10489*8975f5c5SAndroid Build Coastguard Worker 
10490*8975f5c5SAndroid Build Coastguard Worker                 angle::CaptureMemory(attribs.data(), attribs.size() * sizeof(EGLint),
10491*8975f5c5SAndroid Build Coastguard Worker                                      &paramCapture);
10492*8975f5c5SAndroid Build Coastguard Worker             }
10493*8975f5c5SAndroid Build Coastguard Worker             return paramCapture;
10494*8975f5c5SAndroid Build Coastguard Worker         }
10495*8975f5c5SAndroid Build Coastguard Worker 
10496*8975f5c5SAndroid Build Coastguard Worker         default:
10497*8975f5c5SAndroid Build Coastguard Worker             UNREACHABLE();
10498*8975f5c5SAndroid Build Coastguard Worker             return angle::ParamCapture();
10499*8975f5c5SAndroid Build Coastguard Worker     }
10500*8975f5c5SAndroid Build Coastguard Worker }
10501*8975f5c5SAndroid Build Coastguard Worker }  // namespace egl
10502