1 //
2 // Copyright 2019 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // FrameCapture.cpp:
7 // ANGLE Frame capture GL implementation.
8 //
9
10 #include "libANGLE/capture/FrameCapture.h"
11
12 #include <cerrno>
13 #include <cstring>
14 #include <fstream>
15 #include <queue>
16 #include <string>
17
18 #include "common/aligned_memory.h"
19 #include "common/angle_version_info.h"
20 #include "common/frame_capture_utils.h"
21 #include "common/gl_enum_utils.h"
22 #include "common/mathutil.h"
23 #include "common/serializer/JsonSerializer.h"
24 #include "common/string_utils.h"
25 #include "common/system_utils.h"
26 #include "gpu_info_util/SystemInfo.h"
27 #include "image_util/storeimage.h"
28 #include "libANGLE/Config.h"
29 #include "libANGLE/Context.h"
30 #include "libANGLE/Context.inl.h"
31 #include "libANGLE/Display.h"
32 #include "libANGLE/EGLSync.h"
33 #include "libANGLE/Fence.h"
34 #include "libANGLE/Framebuffer.h"
35 #include "libANGLE/GLES1Renderer.h"
36 #include "libANGLE/Query.h"
37 #include "libANGLE/ResourceMap.h"
38 #include "libANGLE/Shader.h"
39 #include "libANGLE/Surface.h"
40 #include "libANGLE/VertexArray.h"
41 #include "libANGLE/capture/capture_egl_autogen.h"
42 #include "libANGLE/capture/capture_gles_1_0_autogen.h"
43 #include "libANGLE/capture/capture_gles_2_0_autogen.h"
44 #include "libANGLE/capture/capture_gles_3_0_autogen.h"
45 #include "libANGLE/capture/capture_gles_3_1_autogen.h"
46 #include "libANGLE/capture/capture_gles_3_2_autogen.h"
47 #include "libANGLE/capture/capture_gles_ext_autogen.h"
48 #include "libANGLE/capture/serialize.h"
49 #include "libANGLE/entry_points_utils.h"
50 #include "libANGLE/queryconversions.h"
51 #include "libANGLE/queryutils.h"
52 #include "libANGLE/renderer/driver_utils.h"
53 #include "libANGLE/validationEGL.h"
54 #include "third_party/ceval/ceval.h"
55
56 #define USE_SYSTEM_ZLIB
57 #include "compression_utils_portable.h"
58
59 #if !ANGLE_CAPTURE_ENABLED
60 # error Frame capture must be enabled to include this file.
61 #endif // !ANGLE_CAPTURE_ENABLED
62
63 namespace angle
64 {
65
66 struct FramebufferCaptureFuncs
67 {
FramebufferCaptureFuncsangle::FramebufferCaptureFuncs68 FramebufferCaptureFuncs(bool isGLES1)
69 {
70 if (isGLES1)
71 {
72 // From GL_OES_framebuffer_object
73 framebufferTexture2D = &gl::CaptureFramebufferTexture2DOES;
74 framebufferRenderbuffer = &gl::CaptureFramebufferRenderbufferOES;
75 bindFramebuffer = &gl::CaptureBindFramebufferOES;
76 genFramebuffers = &gl::CaptureGenFramebuffersOES;
77 bindRenderbuffer = &gl::CaptureBindRenderbufferOES;
78 genRenderbuffers = &gl::CaptureGenRenderbuffersOES;
79 renderbufferStorage = &gl::CaptureRenderbufferStorageOES;
80 }
81 else
82 {
83 framebufferTexture2D = &gl::CaptureFramebufferTexture2D;
84 framebufferRenderbuffer = &gl::CaptureFramebufferRenderbuffer;
85 bindFramebuffer = &gl::CaptureBindFramebuffer;
86 genFramebuffers = &gl::CaptureGenFramebuffers;
87 bindRenderbuffer = &gl::CaptureBindRenderbuffer;
88 genRenderbuffers = &gl::CaptureGenRenderbuffers;
89 renderbufferStorage = &gl::CaptureRenderbufferStorage;
90 }
91 }
92
93 decltype(&gl::CaptureFramebufferTexture2D) framebufferTexture2D;
94 decltype(&gl::CaptureFramebufferRenderbuffer) framebufferRenderbuffer;
95 decltype(&gl::CaptureBindFramebuffer) bindFramebuffer;
96 decltype(&gl::CaptureGenFramebuffers) genFramebuffers;
97 decltype(&gl::CaptureBindRenderbuffer) bindRenderbuffer;
98 decltype(&gl::CaptureGenRenderbuffers) genRenderbuffers;
99 decltype(&gl::CaptureRenderbufferStorage) renderbufferStorage;
100 };
101
102 struct VertexArrayCaptureFuncs
103 {
VertexArrayCaptureFuncsangle::VertexArrayCaptureFuncs104 VertexArrayCaptureFuncs(bool isGLES1)
105 {
106 if (isGLES1)
107 {
108 // From GL_OES_vertex_array_object
109 bindVertexArray = &gl::CaptureBindVertexArrayOES;
110 deleteVertexArrays = &gl::CaptureDeleteVertexArraysOES;
111 genVertexArrays = &gl::CaptureGenVertexArraysOES;
112 isVertexArray = &gl::CaptureIsVertexArrayOES;
113 }
114 else
115 {
116 bindVertexArray = &gl::CaptureBindVertexArray;
117 deleteVertexArrays = &gl::CaptureDeleteVertexArrays;
118 genVertexArrays = &gl::CaptureGenVertexArrays;
119 isVertexArray = &gl::CaptureIsVertexArray;
120 }
121 }
122
123 decltype(&gl::CaptureBindVertexArray) bindVertexArray;
124 decltype(&gl::CaptureDeleteVertexArrays) deleteVertexArrays;
125 decltype(&gl::CaptureGenVertexArrays) genVertexArrays;
126 decltype(&gl::CaptureIsVertexArray) isVertexArray;
127 };
128
GetCaptureTrigger()129 std::string GetCaptureTrigger()
130 {
131 // Use the GetAndSet variant to improve future lookup times
132 return GetAndSetEnvironmentVarOrUnCachedAndroidProperty(kTriggerVarName, kAndroidTrigger);
133 }
134
135 struct FmtGetSerializedContextStateFunction
136 {
FmtGetSerializedContextStateFunctionangle::FmtGetSerializedContextStateFunction137 FmtGetSerializedContextStateFunction(gl::ContextID contextIdIn,
138 FuncUsage usageIn,
139 uint32_t frameIndexIn)
140 : contextId(contextIdIn), usage(usageIn), frameIndex(frameIndexIn)
141 {}
142 gl::ContextID contextId;
143 FuncUsage usage;
144 uint32_t frameIndex;
145 };
146
operator <<(std::ostream & os,const FmtGetSerializedContextStateFunction & fmt)147 std::ostream &operator<<(std::ostream &os, const FmtGetSerializedContextStateFunction &fmt)
148 {
149 os << "GetSerializedContext" << fmt.contextId << "StateFrame" << fmt.frameIndex << "Data"
150 << fmt.usage;
151 return os;
152 }
153
WriteGLFloatValue(std::ostream & out,GLfloat value)154 void WriteGLFloatValue(std::ostream &out, GLfloat value)
155 {
156 // Check for non-representable values
157 ASSERT(std::numeric_limits<float>::has_infinity);
158 ASSERT(std::numeric_limits<float>::has_quiet_NaN);
159
160 if (std::isinf(value))
161 {
162 float negativeInf = -std::numeric_limits<float>::infinity();
163 if (value == negativeInf)
164 {
165 out << "-";
166 }
167 out << "INFINITY";
168 }
169 else if (std::isnan(value))
170 {
171 out << "NAN";
172 }
173 else
174 {
175 // Write a decimal point to preserve the zero sign on replay
176 out << (value == 0.0 ? std::showpoint : std::noshowpoint);
177 out << std::setprecision(16);
178 out << value;
179 }
180 }
181
WriteStringParamReplay(ReplayWriter & replayWriter,std::ostream & out,std::ostream & header,const CallCapture & call,const ParamCapture & param,std::vector<uint8_t> * binaryData)182 void WriteStringParamReplay(ReplayWriter &replayWriter,
183 std::ostream &out,
184 std::ostream &header,
185 const CallCapture &call,
186 const ParamCapture ¶m,
187 std::vector<uint8_t> *binaryData)
188 {
189 const std::vector<uint8_t> &data = param.data[0];
190 // null terminate C style string
191 ASSERT(data.size() > 0 && data.back() == '\0');
192 std::string str(data.begin(), data.end() - 1);
193
194 constexpr size_t kMaxInlineStringLength = 20000;
195 if (str.size() > kMaxInlineStringLength)
196 {
197 // Store in binary file if the string is too long.
198 // Round up to 16-byte boundary for cross ABI safety.
199 size_t offset = rx::roundUpPow2(binaryData->size(), kBinaryAlignment);
200 binaryData->resize(offset + str.size() + 1);
201 memcpy(binaryData->data() + offset, str.data(), str.size() + 1);
202 out << "(const char *)&gBinaryData[" << offset << "]";
203 }
204 else if (str.find('\n') != std::string::npos)
205 {
206 std::string varName = replayWriter.getInlineVariableName(call.entryPoint, param.name);
207 header << "const char " << varName << "[] = \n" << FmtMultiLineString(str) << ";";
208 out << varName;
209 }
210 else
211 {
212 out << "\"" << str << "\"";
213 }
214 }
215
216 enum class Indent
217 {
218 Indent,
219 NoIdent,
220 };
221
UpdateResourceIDBuffer(std::ostream & out,Indent indent,size_t bufferIndex,ResourceIDType resourceIDType,gl::ContextID contextID,GLuint resourceID)222 void UpdateResourceIDBuffer(std::ostream &out,
223 Indent indent,
224 size_t bufferIndex,
225 ResourceIDType resourceIDType,
226 gl::ContextID contextID,
227 GLuint resourceID)
228 {
229 if (indent == Indent::Indent)
230 {
231 out << " ";
232 }
233 out << "UpdateResourceIDBuffer(" << bufferIndex << ", g"
234 << GetResourceIDTypeName(resourceIDType) << "Map";
235 if (IsTrackedPerContext(resourceIDType))
236 {
237 out << "PerContext[" << contextID.value << "]";
238 }
239 out << "[" << resourceID << "]);\n";
240 }
241
242 template <typename ParamT>
WriteResourceIDPointerParamReplay(ReplayWriter & replayWriter,std::ostream & out,std::ostream & header,const CallCapture & call,const ParamCapture & param,size_t * maxResourceIDBufferSize)243 void WriteResourceIDPointerParamReplay(ReplayWriter &replayWriter,
244 std::ostream &out,
245 std::ostream &header,
246 const CallCapture &call,
247 const ParamCapture ¶m,
248 size_t *maxResourceIDBufferSize)
249 {
250 const ResourceIDType resourceIDType = GetResourceIDTypeFromParamType(param.type);
251 ASSERT(resourceIDType != ResourceIDType::InvalidEnum);
252
253 if (param.dataNElements > 0)
254 {
255 ASSERT(param.data.size() == 1);
256
257 const ParamT *returnedIDs = reinterpret_cast<const ParamT *>(param.data[0].data());
258 for (GLsizei resIndex = 0; resIndex < param.dataNElements; ++resIndex)
259 {
260 ParamT id = returnedIDs[resIndex];
261 UpdateResourceIDBuffer(header, Indent::NoIdent, resIndex, resourceIDType,
262 call.contextID, id.value);
263 }
264
265 *maxResourceIDBufferSize = std::max<size_t>(*maxResourceIDBufferSize, param.dataNElements);
266 }
267
268 out << "gResourceIDBuffer";
269 }
270
WriteCppReplayForCall(const CallCapture & call,ReplayWriter & replayWriter,std::ostream & out,std::ostream & header,std::vector<uint8_t> * binaryData,size_t * maxResourceIDBufferSize)271 void WriteCppReplayForCall(const CallCapture &call,
272 ReplayWriter &replayWriter,
273 std::ostream &out,
274 std::ostream &header,
275 std::vector<uint8_t> *binaryData,
276 size_t *maxResourceIDBufferSize)
277 {
278 if (call.customFunctionName == "Comment")
279 {
280 // Just write it directly to the file and move on
281 WriteComment(out, call);
282 return;
283 }
284
285 std::ostringstream callOut;
286
287 callOut << call.name() << "(";
288
289 bool first = true;
290 for (const ParamCapture ¶m : call.params.getParamCaptures())
291 {
292 if (!first)
293 {
294 callOut << ", ";
295 }
296
297 if (param.arrayClientPointerIndex != -1 && param.value.voidConstPointerVal != nullptr)
298 {
299 callOut << "gClientArrays[" << param.arrayClientPointerIndex << "]";
300 }
301 else if (param.readBufferSizeBytes > 0)
302 {
303 callOut << "(" << ParamTypeToString(param.type) << ")gReadBuffer";
304 }
305 else if (param.data.empty())
306 {
307 if (param.type == ParamType::TGLenum)
308 {
309 OutputGLenumString(callOut, param.enumGroup, param.value.GLenumVal);
310 }
311 else if (param.type == ParamType::TGLbitfield)
312 {
313 OutputGLbitfieldString(callOut, param.enumGroup, param.value.GLbitfieldVal);
314 }
315 else if (param.type == ParamType::TGLfloat)
316 {
317 WriteGLFloatValue(callOut, param.value.GLfloatVal);
318 }
319 else if (param.type == ParamType::TGLsync)
320 {
321 callOut << "gSyncMap[" << FmtPointerIndex(param.value.GLsyncVal) << "]";
322 }
323 else if (param.type == ParamType::TGLuint64 && param.name == "timeout")
324 {
325 if (param.value.GLuint64Val == GL_TIMEOUT_IGNORED)
326 {
327 callOut << "GL_TIMEOUT_IGNORED";
328 }
329 else
330 {
331 WriteParamCaptureReplay(callOut, call, param);
332 }
333 }
334 else
335 {
336 WriteParamCaptureReplay(callOut, call, param);
337 }
338 }
339 else
340 {
341 switch (param.type)
342 {
343 case ParamType::TGLcharConstPointer:
344 WriteStringParamReplay(replayWriter, callOut, header, call, param, binaryData);
345 break;
346 case ParamType::TGLcharConstPointerPointer:
347 WriteStringPointerParamReplay(replayWriter, callOut, header, call, param);
348 break;
349 case ParamType::TBufferIDConstPointer:
350 WriteResourceIDPointerParamReplay<gl::BufferID>(
351 replayWriter, callOut, out, call, param, maxResourceIDBufferSize);
352 break;
353 case ParamType::TFenceNVIDConstPointer:
354 WriteResourceIDPointerParamReplay<gl::FenceNVID>(
355 replayWriter, callOut, out, call, param, maxResourceIDBufferSize);
356 break;
357 case ParamType::TFramebufferIDConstPointer:
358 WriteResourceIDPointerParamReplay<gl::FramebufferID>(
359 replayWriter, callOut, out, call, param, maxResourceIDBufferSize);
360 break;
361 case ParamType::TMemoryObjectIDConstPointer:
362 WriteResourceIDPointerParamReplay<gl::MemoryObjectID>(
363 replayWriter, callOut, out, call, param, maxResourceIDBufferSize);
364 break;
365 case ParamType::TProgramPipelineIDConstPointer:
366 WriteResourceIDPointerParamReplay<gl::ProgramPipelineID>(
367 replayWriter, callOut, out, call, param, maxResourceIDBufferSize);
368 break;
369 case ParamType::TQueryIDConstPointer:
370 WriteResourceIDPointerParamReplay<gl::QueryID>(replayWriter, callOut, out, call,
371 param, maxResourceIDBufferSize);
372 break;
373 case ParamType::TRenderbufferIDConstPointer:
374 WriteResourceIDPointerParamReplay<gl::RenderbufferID>(
375 replayWriter, callOut, out, call, param, maxResourceIDBufferSize);
376 break;
377 case ParamType::TSamplerIDConstPointer:
378 WriteResourceIDPointerParamReplay<gl::SamplerID>(
379 replayWriter, callOut, out, call, param, maxResourceIDBufferSize);
380 break;
381 case ParamType::TSemaphoreIDConstPointer:
382 WriteResourceIDPointerParamReplay<gl::SemaphoreID>(
383 replayWriter, callOut, out, call, param, maxResourceIDBufferSize);
384 break;
385 case ParamType::TTextureIDConstPointer:
386 WriteResourceIDPointerParamReplay<gl::TextureID>(
387 replayWriter, callOut, out, call, param, maxResourceIDBufferSize);
388 break;
389 case ParamType::TTransformFeedbackIDConstPointer:
390 WriteResourceIDPointerParamReplay<gl::TransformFeedbackID>(
391 replayWriter, callOut, out, call, param, maxResourceIDBufferSize);
392 break;
393 case ParamType::TVertexArrayIDConstPointer:
394 WriteResourceIDPointerParamReplay<gl::VertexArrayID>(
395 replayWriter, callOut, out, call, param, maxResourceIDBufferSize);
396 break;
397 default:
398 WriteBinaryParamReplay(replayWriter, callOut, header, call, param, binaryData);
399 break;
400 }
401 }
402
403 first = false;
404 }
405
406 callOut << ")";
407
408 out << callOut.str();
409 }
410
MaxClientArraySize(const gl::AttribArray<size_t> & clientArraySizes)411 size_t MaxClientArraySize(const gl::AttribArray<size_t> &clientArraySizes)
412 {
413 size_t found = 0;
414 for (size_t size : clientArraySizes)
415 {
416 if (size > found)
417 {
418 found = size;
419 }
420 }
421
422 return found;
423 }
424
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)425 void WriteInitReplayCall(bool compression,
426 std::ostream &out,
427 gl::ContextID contextID,
428 const std::string &captureLabel,
429 size_t maxClientArraySize,
430 size_t readBufferSize,
431 size_t resourceIDBufferSize,
432 const PackedEnumMap<ResourceIDType, uint32_t> &maxIDs)
433 {
434 std::string binaryDataFileName = GetBinaryDataFilePath(compression, captureLabel);
435
436 out << " // binaryDataFileName = " << binaryDataFileName << "\n";
437 out << " // maxClientArraySize = " << maxClientArraySize << "\n";
438 out << " // readBufferSize = " << readBufferSize << "\n";
439 out << " // resourceIDBufferSize = " << resourceIDBufferSize << "\n";
440 out << " // contextID = " << contextID << "\n";
441 for (ResourceIDType resourceID : AllEnums<ResourceIDType>())
442 {
443 const char *name = GetResourceIDTypeName(resourceID);
444 out << " // max" << name << " = " << maxIDs[resourceID] << "\n";
445 }
446 out << " InitializeReplay4(\"" << binaryDataFileName << "\", " << maxClientArraySize << ", "
447 << readBufferSize << ", " << resourceIDBufferSize << ", " << contextID;
448
449 for (ResourceIDType resourceID : AllEnums<ResourceIDType>())
450 {
451 // Sanity check for catching e.g. uninitialized memory reads like b/380296979
452 ASSERT(maxIDs[resourceID] < 1000000);
453 out << ", " << maxIDs[resourceID];
454 }
455
456 out << ");\n";
457 }
458
DeleteResourcesInReset(std::stringstream & out,const gl::ContextID contextID,const ResourceSet & newResources,const ResourceSet & resourcesToDelete,const ResourceIDType resourceIDType,size_t * maxResourceIDBufferSize)459 void DeleteResourcesInReset(std::stringstream &out,
460 const gl::ContextID contextID,
461 const ResourceSet &newResources,
462 const ResourceSet &resourcesToDelete,
463 const ResourceIDType resourceIDType,
464 size_t *maxResourceIDBufferSize)
465 {
466 if (!newResources.empty() || !resourcesToDelete.empty())
467 {
468 size_t count = 0;
469
470 for (GLuint oldResource : resourcesToDelete)
471 {
472 UpdateResourceIDBuffer(out, Indent::Indent, count++, resourceIDType, contextID,
473 oldResource);
474 }
475
476 for (GLuint newResource : newResources)
477 {
478 UpdateResourceIDBuffer(out, Indent::Indent, count++, resourceIDType, contextID,
479 newResource);
480 }
481
482 // Delete all the new and old buffers at once
483 out << " glDelete" << GetResourceIDTypeName(resourceIDType) << "s(" << count
484 << ", gResourceIDBuffer);\n";
485
486 *maxResourceIDBufferSize = std::max(*maxResourceIDBufferSize, count);
487 }
488 }
489
490 // 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)491 void MaybeResetResources(egl::Display *display,
492 gl::ContextID contextID,
493 ResourceIDType resourceIDType,
494 ReplayWriter &replayWriter,
495 std::stringstream &out,
496 std::stringstream &header,
497 ResourceTracker *resourceTracker,
498 std::vector<uint8_t> *binaryData,
499 bool &anyResourceReset,
500 size_t *maxResourceIDBufferSize)
501 {
502 // Track the initial output position so we can detect if it has moved
503 std::streampos initialOutPos = out.tellp();
504
505 switch (resourceIDType)
506 {
507 case ResourceIDType::Buffer:
508 {
509 TrackedResource &trackedBuffers =
510 resourceTracker->getTrackedResource(contextID, ResourceIDType::Buffer);
511 ResourceSet &newBuffers = trackedBuffers.getNewResources();
512 ResourceSet &buffersToDelete = trackedBuffers.getResourcesToDelete();
513 ResourceSet &buffersToRegen = trackedBuffers.getResourcesToRegen();
514 ResourceCalls &bufferRegenCalls = trackedBuffers.getResourceRegenCalls();
515 ResourceCalls &bufferRestoreCalls = trackedBuffers.getResourceRestoreCalls();
516
517 BufferCalls &bufferMapCalls = resourceTracker->getBufferMapCalls();
518 BufferCalls &bufferUnmapCalls = resourceTracker->getBufferUnmapCalls();
519
520 DeleteResourcesInReset(out, contextID, newBuffers, buffersToDelete, resourceIDType,
521 maxResourceIDBufferSize);
522
523 // If any of our starting buffers were deleted during the run, recreate them
524 for (GLuint id : buffersToRegen)
525 {
526 // Emit their regen calls
527 for (CallCapture &call : bufferRegenCalls[id])
528 {
529 out << " ";
530 WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
531 maxResourceIDBufferSize);
532 out << ";\n";
533 }
534 }
535
536 // If any of our starting buffers were modified during the run, restore their contents
537 ResourceSet &buffersToRestore = trackedBuffers.getResourcesToRestore();
538 for (GLuint id : buffersToRestore)
539 {
540 if (resourceTracker->getStartingBuffersMappedCurrent(id))
541 {
542 // Some drivers require the buffer to be unmapped before you can update data,
543 // which violates the spec. See gl::Buffer::bufferDataImpl().
544 for (CallCapture &call : bufferUnmapCalls[id])
545 {
546 out << " ";
547 WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
548 maxResourceIDBufferSize);
549 out << ";\n";
550 }
551 }
552
553 // Emit their restore calls
554 for (CallCapture &call : bufferRestoreCalls[id])
555 {
556 out << " ";
557 WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
558 maxResourceIDBufferSize);
559 out << ";\n";
560
561 // Also note that this buffer has been implicitly unmapped by this call
562 resourceTracker->setBufferUnmapped(contextID, id);
563 }
564 }
565
566 // Update the map/unmap of buffers to match the starting state
567 ResourceSet startingBuffers = trackedBuffers.getStartingResources();
568 for (GLuint id : startingBuffers)
569 {
570 // If the buffer was mapped at the start, but is not mapped now, we need to map
571 if (resourceTracker->getStartingBuffersMappedInitial(id) &&
572 !resourceTracker->getStartingBuffersMappedCurrent(id))
573 {
574 // Emit their map calls
575 for (CallCapture &call : bufferMapCalls[id])
576 {
577 out << " ";
578 WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
579 maxResourceIDBufferSize);
580 out << ";\n";
581 }
582 }
583 // If the buffer was unmapped at the start, but is mapped now, we need to unmap
584 if (!resourceTracker->getStartingBuffersMappedInitial(id) &&
585 resourceTracker->getStartingBuffersMappedCurrent(id))
586 {
587 // Emit their unmap calls
588 for (CallCapture &call : bufferUnmapCalls[id])
589 {
590 out << " ";
591 WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
592 maxResourceIDBufferSize);
593 out << ";\n";
594 }
595 }
596 }
597 break;
598 }
599 case ResourceIDType::Framebuffer:
600 {
601 TrackedResource &trackedFramebuffers =
602 resourceTracker->getTrackedResource(contextID, ResourceIDType::Framebuffer);
603 ResourceSet &newFramebuffers = trackedFramebuffers.getNewResources();
604 ResourceSet &framebuffersToDelete = trackedFramebuffers.getResourcesToDelete();
605 ResourceSet &framebuffersToRegen = trackedFramebuffers.getResourcesToRegen();
606 ResourceCalls &framebufferRegenCalls = trackedFramebuffers.getResourceRegenCalls();
607 ResourceCalls &framebufferRestoreCalls = trackedFramebuffers.getResourceRestoreCalls();
608
609 DeleteResourcesInReset(out, contextID, newFramebuffers, framebuffersToDelete,
610 resourceIDType, maxResourceIDBufferSize);
611
612 for (GLuint id : framebuffersToRegen)
613 {
614 // Emit their regen calls
615 for (CallCapture &call : framebufferRegenCalls[id])
616 {
617 out << " ";
618 WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
619 maxResourceIDBufferSize);
620 out << ";\n";
621 }
622 }
623
624 // If any of our starting framebuffers were modified during the run, restore their
625 // contents
626 ResourceSet &framebuffersToRestore = trackedFramebuffers.getResourcesToRestore();
627 for (GLuint id : framebuffersToRestore)
628 {
629 // Emit their restore calls
630 for (CallCapture &call : framebufferRestoreCalls[id])
631 {
632 out << " ";
633 WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
634 maxResourceIDBufferSize);
635 out << ";\n";
636 }
637 }
638 break;
639 }
640 case ResourceIDType::Renderbuffer:
641 {
642 TrackedResource &trackedRenderbuffers =
643 resourceTracker->getTrackedResource(contextID, ResourceIDType::Renderbuffer);
644 ResourceSet &newRenderbuffers = trackedRenderbuffers.getNewResources();
645 ResourceSet &renderbuffersToDelete = trackedRenderbuffers.getResourcesToDelete();
646 ResourceSet &renderbuffersToRegen = trackedRenderbuffers.getResourcesToRegen();
647 ResourceCalls &renderbufferRegenCalls = trackedRenderbuffers.getResourceRegenCalls();
648 ResourceCalls &renderbufferRestoreCalls =
649 trackedRenderbuffers.getResourceRestoreCalls();
650
651 DeleteResourcesInReset(out, contextID, newRenderbuffers, renderbuffersToDelete,
652 resourceIDType, maxResourceIDBufferSize);
653
654 for (GLuint id : renderbuffersToRegen)
655 {
656 // Emit their regen calls
657 for (CallCapture &call : renderbufferRegenCalls[id])
658 {
659 out << " ";
660 WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
661 maxResourceIDBufferSize);
662 out << ";\n";
663 }
664 }
665
666 // If any of our starting renderbuffers were modified during the run, restore their
667 // contents
668 ResourceSet &renderbuffersToRestore = trackedRenderbuffers.getResourcesToRestore();
669 for (GLuint id : renderbuffersToRestore)
670 {
671 // Emit their restore calls
672 for (CallCapture &call : renderbufferRestoreCalls[id])
673 {
674 out << " ";
675 WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
676 maxResourceIDBufferSize);
677 out << ";\n";
678 }
679 }
680 break;
681 }
682 case ResourceIDType::ShaderProgram:
683 {
684 TrackedResource &trackedShaderPrograms =
685 resourceTracker->getTrackedResource(contextID, ResourceIDType::ShaderProgram);
686 ResourceSet &newShaderPrograms = trackedShaderPrograms.getNewResources();
687 ResourceSet &shaderProgramsToDelete = trackedShaderPrograms.getResourcesToDelete();
688 ResourceSet &shaderProgramsToRegen = trackedShaderPrograms.getResourcesToRegen();
689 ResourceSet &shaderProgramsToRestore = trackedShaderPrograms.getResourcesToRestore();
690 ResourceCalls &shaderProgramRegenCalls = trackedShaderPrograms.getResourceRegenCalls();
691 ResourceCalls &shaderProgramRestoreCalls =
692 trackedShaderPrograms.getResourceRestoreCalls();
693
694 // If we have any new shaders or programs created and not deleted during the run, delete
695 // them now
696 for (const GLuint &newShaderProgram : newShaderPrograms)
697 {
698 if (resourceTracker->getShaderProgramType({newShaderProgram}) ==
699 ShaderProgramType::ShaderType)
700 {
701 out << " glDeleteShader(gShaderProgramMap[" << newShaderProgram << "]);\n";
702 }
703 else
704 {
705 ASSERT(resourceTracker->getShaderProgramType({newShaderProgram}) ==
706 ShaderProgramType::ProgramType);
707 out << " glDeleteProgram(gShaderProgramMap[" << newShaderProgram << "]);\n";
708 }
709 }
710
711 // Do the same for shaders/programs to be deleted
712 for (const GLuint &shaderProgramToDelete : shaderProgramsToDelete)
713 {
714 if (resourceTracker->getShaderProgramType({shaderProgramToDelete}) ==
715 ShaderProgramType::ShaderType)
716 {
717 out << " glDeleteShader(gShaderProgramMap[" << shaderProgramToDelete
718 << "]);\n";
719 }
720 else
721 {
722 ASSERT(resourceTracker->getShaderProgramType({shaderProgramToDelete}) ==
723 ShaderProgramType::ProgramType);
724 out << " glDeleteProgram(gShaderProgramMap[" << shaderProgramToDelete
725 << "]);\n";
726 }
727 }
728
729 for (const GLuint id : shaderProgramsToRegen)
730 {
731 // Emit their regen calls
732 for (CallCapture &call : shaderProgramRegenCalls[id])
733 {
734 out << " ";
735 WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
736 maxResourceIDBufferSize);
737 out << ";\n";
738 }
739 }
740
741 for (const GLuint id : shaderProgramsToRestore)
742 {
743 // Emit their restore calls
744 for (CallCapture &call : shaderProgramRestoreCalls[id])
745 {
746 out << " ";
747 WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
748 maxResourceIDBufferSize);
749 out << ";\n";
750 }
751 }
752
753 break;
754 }
755 case ResourceIDType::Texture:
756 {
757 TrackedResource &trackedTextures =
758 resourceTracker->getTrackedResource(contextID, ResourceIDType::Texture);
759 ResourceSet &newTextures = trackedTextures.getNewResources();
760 ResourceSet &texturesToDelete = trackedTextures.getResourcesToDelete();
761 ResourceSet &texturesToRegen = trackedTextures.getResourcesToRegen();
762 ResourceCalls &textureRegenCalls = trackedTextures.getResourceRegenCalls();
763 ResourceCalls &textureRestoreCalls = trackedTextures.getResourceRestoreCalls();
764
765 DeleteResourcesInReset(out, contextID, newTextures, texturesToDelete, resourceIDType,
766 maxResourceIDBufferSize);
767
768 // If any of our starting textures were deleted, regen them
769 for (GLuint id : texturesToRegen)
770 {
771 // Emit their regen calls
772 for (CallCapture &call : textureRegenCalls[id])
773 {
774 out << " ";
775 WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
776 maxResourceIDBufferSize);
777 out << ";\n";
778 }
779 }
780
781 // If any of our starting textures were modified during the run, restore their contents
782 ResourceSet &texturesToRestore = trackedTextures.getResourcesToRestore();
783
784 // Do some setup if we have any textures to restore
785 if (texturesToRestore.size() != 0)
786 {
787 // We need to unbind PIXEL_UNPACK_BUFFER before restoring textures
788 // The correct binding will be restored in context state reset
789 gl::Context *context = display->getContext(contextID);
790 if (context->getState().getTargetBuffer(gl::BufferBinding::PixelUnpack))
791 {
792 out << " // Clearing PIXEL_UNPACK_BUFFER binding for texture restore\n";
793 out << " ";
794 WriteCppReplayForCall(CaptureBindBuffer(context->getState(), true,
795 gl::BufferBinding::PixelUnpack, {0}),
796 replayWriter, out, header, binaryData,
797 maxResourceIDBufferSize);
798 out << ";\n";
799 }
800 }
801
802 for (GLuint id : texturesToRestore)
803 {
804 // Emit their restore calls
805 for (CallCapture &call : textureRestoreCalls[id])
806 {
807 out << " ";
808 WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
809 maxResourceIDBufferSize);
810 out << ";\n";
811 }
812 }
813 break;
814 }
815 case ResourceIDType::VertexArray:
816 {
817 TrackedResource &trackedVertexArrays =
818 resourceTracker->getTrackedResource(contextID, ResourceIDType::VertexArray);
819 ResourceSet &newVertexArrays = trackedVertexArrays.getNewResources();
820 ResourceSet &vertexArraysToDelete = trackedVertexArrays.getResourcesToDelete();
821 ResourceSet &vertexArraysToRegen = trackedVertexArrays.getResourcesToRegen();
822 ResourceSet &vertexArraysToRestore = trackedVertexArrays.getResourcesToRestore();
823 ResourceCalls &vertexArrayRegenCalls = trackedVertexArrays.getResourceRegenCalls();
824 ResourceCalls &vertexArrayRestoreCalls = trackedVertexArrays.getResourceRestoreCalls();
825
826 DeleteResourcesInReset(out, contextID, newVertexArrays, vertexArraysToDelete,
827 resourceIDType, maxResourceIDBufferSize);
828
829 // If any of our starting vertex arrays were deleted during the run, recreate them
830 for (GLuint id : vertexArraysToRegen)
831 {
832 // Emit their regen calls
833 for (CallCapture &call : vertexArrayRegenCalls[id])
834 {
835 out << " ";
836 WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
837 maxResourceIDBufferSize);
838 out << ";\n";
839 }
840 }
841
842 // If any of our starting vertex arrays were modified during the run, restore their
843 // contents
844 for (GLuint id : vertexArraysToRestore)
845 {
846 // Emit their restore calls
847 for (CallCapture &call : vertexArrayRestoreCalls[id])
848 {
849 out << " ";
850 WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
851 maxResourceIDBufferSize);
852 out << ";\n";
853 }
854 }
855 break;
856 }
857 case ResourceIDType::egl_Sync:
858 {
859 TrackedResource &trackedEGLSyncs =
860 resourceTracker->getTrackedResource(contextID, ResourceIDType::egl_Sync);
861 ResourceSet &newEGLSyncs = trackedEGLSyncs.getNewResources();
862 ResourceSet &eglSyncsToDelete = trackedEGLSyncs.getResourcesToDelete();
863 ResourceSet &eglSyncsToRegen = trackedEGLSyncs.getResourcesToRegen();
864 ResourceCalls &eglSyncRegenCalls = trackedEGLSyncs.getResourceRegenCalls();
865
866 if (!newEGLSyncs.empty() || !eglSyncsToDelete.empty())
867 {
868 for (GLuint oldResource : eglSyncsToDelete)
869 {
870 out << " eglDestroySyncKHR(gEGLDisplay, gEGLSyncMap[" << oldResource
871 << "]);\n";
872 }
873
874 for (GLuint newResource : newEGLSyncs)
875 {
876 out << " eglDestroySyncKHR(gEGLDisplay, gEGLSyncMap[" << newResource
877 << "]);\n";
878 }
879 }
880
881 // If any of our starting EGLsyncs were deleted during the run, recreate them
882 for (GLuint id : eglSyncsToRegen)
883 {
884 // Emit their regen calls
885 for (CallCapture &call : eglSyncRegenCalls[id])
886 {
887 out << " ";
888 WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
889 maxResourceIDBufferSize);
890 out << ";\n";
891 }
892 }
893 break;
894 }
895 case ResourceIDType::Image:
896 {
897 TrackedResource &trackedEGLImages =
898 resourceTracker->getTrackedResource(contextID, ResourceIDType::Image);
899 ResourceSet &newEGLImages = trackedEGLImages.getNewResources();
900 ResourceSet &eglImagesToDelete = trackedEGLImages.getResourcesToDelete();
901 ResourceSet &eglImagesToRegen = trackedEGLImages.getResourcesToRegen();
902 ResourceCalls &eglImageRegenCalls = trackedEGLImages.getResourceRegenCalls();
903
904 if (!newEGLImages.empty() || !eglImagesToDelete.empty())
905 {
906 for (GLuint oldResource : eglImagesToDelete)
907 {
908 out << " DestroyEGLImageKHR(gEGLDisplay, gEGLImageMap2[" << oldResource
909 << "], " << oldResource << ");\n";
910 }
911
912 for (GLuint newResource : newEGLImages)
913 {
914 out << " DestroyEGLImageKHR(gEGLDisplay, gEGLImageMap2[" << newResource
915 << "], " << newResource << ");\n";
916 }
917 }
918 // If any of our starting EGLImages were deleted during the run, recreate them
919 for (GLuint id : eglImagesToRegen)
920 {
921 // Emit their regen calls
922 for (CallCapture &call : eglImageRegenCalls[id])
923 {
924 out << " ";
925 WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
926 maxResourceIDBufferSize);
927 out << ";\n";
928 }
929 }
930 break;
931 }
932 default:
933 // TODO (http://anglebug.com/42263204): Reset more resource types
934 break;
935 }
936
937 // If the output position has moved, we Reset something
938 anyResourceReset = (initialOutPos != out.tellp());
939 }
940
MaybeResetFenceSyncObjects(std::stringstream & out,ReplayWriter & replayWriter,std::stringstream & header,ResourceTracker * resourceTracker,std::vector<uint8_t> * binaryData,size_t * maxResourceIDBufferSize)941 void MaybeResetFenceSyncObjects(std::stringstream &out,
942 ReplayWriter &replayWriter,
943 std::stringstream &header,
944 ResourceTracker *resourceTracker,
945 std::vector<uint8_t> *binaryData,
946 size_t *maxResourceIDBufferSize)
947 {
948 FenceSyncCalls &fenceSyncRegenCalls = resourceTracker->getFenceSyncRegenCalls();
949
950 // If any of our starting fence sync objects were deleted during the run, recreate them
951 FenceSyncSet &fenceSyncsToRegen = resourceTracker->getFenceSyncsToRegen();
952 for (const gl::SyncID syncID : fenceSyncsToRegen)
953 {
954 // Emit their regen calls
955 for (CallCapture &call : fenceSyncRegenCalls[syncID])
956 {
957 out << " ";
958 WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
959 maxResourceIDBufferSize);
960 out << ";\n";
961 }
962 }
963 }
964
Capture(std::vector<CallCapture> * setupCalls,CallCapture && call)965 void Capture(std::vector<CallCapture> *setupCalls, CallCapture &&call)
966 {
967 setupCalls->emplace_back(std::move(call));
968 }
969
CaptureUpdateCurrentProgram(const CallCapture & call,int programParamPos,std::vector<CallCapture> * callsOut)970 void CaptureUpdateCurrentProgram(const CallCapture &call,
971 int programParamPos,
972 std::vector<CallCapture> *callsOut)
973 {
974 const ParamCapture ¶m =
975 call.params.getParam("programPacked", ParamType::TShaderProgramID, programParamPos);
976 gl::ShaderProgramID programID = param.value.ShaderProgramIDVal;
977
978 ParamBuffer paramBuffer;
979 paramBuffer.addValueParam("program", ParamType::TGLuint, programID.value);
980
981 callsOut->emplace_back("UpdateCurrentProgram", std::move(paramBuffer));
982 }
983
ProgramNeedsReset(const gl::Context * context,ResourceTracker * resourceTracker,gl::ShaderProgramID programID)984 bool ProgramNeedsReset(const gl::Context *context,
985 ResourceTracker *resourceTracker,
986 gl::ShaderProgramID programID)
987 {
988 // Check whether the program is listed in programs to regen or restore
989 TrackedResource &trackedShaderPrograms =
990 resourceTracker->getTrackedResource(context->id(), ResourceIDType::ShaderProgram);
991
992 ResourceSet &shaderProgramsToRegen = trackedShaderPrograms.getResourcesToRegen();
993 if (shaderProgramsToRegen.count(programID.value) != 0)
994 {
995 return true;
996 }
997
998 ResourceSet &shaderProgramsToRestore = trackedShaderPrograms.getResourcesToRestore();
999 if (shaderProgramsToRestore.count(programID.value) != 0)
1000 {
1001 return true;
1002 }
1003
1004 // Deferred linked programs will also update their own uniforms
1005 FrameCaptureShared *frameCaptureShared = context->getShareGroup()->getFrameCaptureShared();
1006 if (frameCaptureShared->isDeferredLinkProgram(programID))
1007 {
1008 return true;
1009 }
1010
1011 return false;
1012 }
1013
MaybeResetDefaultUniforms(std::stringstream & out,ReplayWriter & replayWriter,std::stringstream & header,const gl::Context * context,ResourceTracker * resourceTracker,std::vector<uint8_t> * binaryData,size_t * maxResourceIDBufferSize)1014 void MaybeResetDefaultUniforms(std::stringstream &out,
1015 ReplayWriter &replayWriter,
1016 std::stringstream &header,
1017 const gl::Context *context,
1018 ResourceTracker *resourceTracker,
1019 std::vector<uint8_t> *binaryData,
1020 size_t *maxResourceIDBufferSize)
1021 {
1022 DefaultUniformLocationsPerProgramMap &defaultUniformsToReset =
1023 resourceTracker->getDefaultUniformsToReset();
1024
1025 for (const auto &uniformIter : defaultUniformsToReset)
1026 {
1027 gl::ShaderProgramID programID = uniformIter.first;
1028 const DefaultUniformLocationsSet &locations = uniformIter.second;
1029
1030 if (ProgramNeedsReset(context, resourceTracker, programID))
1031 {
1032 // Skip programs marked for reset as they will update their own uniforms
1033 return;
1034 }
1035
1036 // Bind the program to update its uniforms
1037 std::vector<CallCapture> bindCalls;
1038 Capture(&bindCalls, CaptureUseProgram(context->getState(), true, programID));
1039 CaptureUpdateCurrentProgram((&bindCalls)->back(), 0, &bindCalls);
1040 for (CallCapture &call : bindCalls)
1041 {
1042 out << " ";
1043 WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
1044 maxResourceIDBufferSize);
1045 out << ";\n";
1046 }
1047
1048 DefaultUniformCallsPerLocationMap &defaultUniformResetCalls =
1049 resourceTracker->getDefaultUniformResetCalls(programID);
1050
1051 // Uniform arrays might have been modified in the middle (i.e. location 5 out of 10)
1052 // We only have Reset calls for the entire array, so emit them once for the entire array
1053 std::set<gl::UniformLocation> alreadyReset;
1054
1055 // Emit the reset calls per modified location
1056 for (const gl::UniformLocation &location : locations)
1057 {
1058 gl::UniformLocation baseLocation =
1059 resourceTracker->getDefaultUniformBaseLocation(programID, location);
1060 if (alreadyReset.find(baseLocation) != alreadyReset.end())
1061 {
1062 // We've already Reset this array
1063 continue;
1064 }
1065 alreadyReset.insert(baseLocation);
1066
1067 ASSERT(defaultUniformResetCalls.find(baseLocation) != defaultUniformResetCalls.end());
1068 std::vector<CallCapture> &callsPerLocation = defaultUniformResetCalls[baseLocation];
1069
1070 for (CallCapture &call : callsPerLocation)
1071 {
1072 out << " ";
1073 WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
1074 maxResourceIDBufferSize);
1075 out << ";\n";
1076 }
1077 }
1078 }
1079 }
1080
MaybeResetOpaqueTypeObjects(ReplayWriter & replayWriter,std::stringstream & out,std::stringstream & header,const gl::Context * context,ResourceTracker * resourceTracker,std::vector<uint8_t> * binaryData,size_t * maxResourceIDBufferSize)1081 void MaybeResetOpaqueTypeObjects(ReplayWriter &replayWriter,
1082 std::stringstream &out,
1083 std::stringstream &header,
1084 const gl::Context *context,
1085 ResourceTracker *resourceTracker,
1086 std::vector<uint8_t> *binaryData,
1087 size_t *maxResourceIDBufferSize)
1088 {
1089 MaybeResetFenceSyncObjects(out, replayWriter, header, resourceTracker, binaryData,
1090 maxResourceIDBufferSize);
1091
1092 MaybeResetDefaultUniforms(out, replayWriter, header, context, resourceTracker, binaryData,
1093 maxResourceIDBufferSize);
1094 }
1095
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)1096 void MaybeResetContextState(ReplayWriter &replayWriter,
1097 std::stringstream &out,
1098 std::stringstream &header,
1099 ResourceTracker *resourceTracker,
1100 const gl::Context *context,
1101 std::vector<uint8_t> *binaryData,
1102 StateResetHelper &stateResetHelper,
1103 size_t *maxResourceIDBufferSize)
1104 {
1105 // Check dirty states per entrypoint
1106 for (const EntryPoint &entryPoint : stateResetHelper.getDirtyEntryPoints())
1107 {
1108 const CallResetMap *resetCalls = &stateResetHelper.getResetCalls();
1109
1110 // Create the default reset call for this entrypoint
1111 if (resetCalls->find(entryPoint) == resetCalls->end())
1112 {
1113 // If we don't have any reset calls for these entrypoints, that means we started capture
1114 // from the beginning, amd mid-execution capture was not invoked.
1115 stateResetHelper.setDefaultResetCalls(context, entryPoint);
1116 }
1117
1118 // Emit the calls, if we added any
1119 if (resetCalls->find(entryPoint) != resetCalls->end())
1120 {
1121 for (const auto &call : resetCalls->at(entryPoint))
1122 {
1123 out << " ";
1124 WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
1125 maxResourceIDBufferSize);
1126 out << ";\n";
1127 }
1128 }
1129 }
1130
1131 // Reset buffer bindings that weren't bound at the beginning
1132 for (const gl::BufferBinding &dirtyBufferBinding : stateResetHelper.getDirtyBufferBindings())
1133 {
1134 // Check to see if dirty binding was part of starting set
1135 bool dirtyStartingBinding = false;
1136 for (const BufferBindingPair &startingBufferBinding :
1137 stateResetHelper.getStartingBufferBindings())
1138 {
1139 gl::BufferBinding startingBinding = startingBufferBinding.first;
1140 if (startingBinding == dirtyBufferBinding)
1141 {
1142 dirtyStartingBinding = true;
1143 }
1144 }
1145
1146 // If the dirty binding was not part of starting bindings, clear it
1147 if (!dirtyStartingBinding)
1148 {
1149 out << " ";
1150 WriteCppReplayForCall(
1151 CaptureBindBuffer(context->getState(), true, dirtyBufferBinding, {0}), replayWriter,
1152 out, header, binaryData, maxResourceIDBufferSize);
1153 out << ";\n";
1154 }
1155 }
1156
1157 // Restore starting buffer bindings to initial state
1158 std::vector<CallCapture> &bufferBindingCalls = resourceTracker->getBufferBindingCalls();
1159 for (CallCapture &call : bufferBindingCalls)
1160 {
1161 out << " ";
1162 WriteCppReplayForCall(call, replayWriter, out, header, binaryData, maxResourceIDBufferSize);
1163 out << ";\n";
1164 }
1165
1166 // Restore texture bindings to initial state
1167 size_t activeTexture = context->getState().getActiveSampler();
1168 const TextureResetMap &resetBindings = stateResetHelper.getResetTextureBindings();
1169 for (const auto &textureBinding : stateResetHelper.getDirtyTextureBindings())
1170 {
1171 TextureResetMap::const_iterator id = resetBindings.find(textureBinding);
1172 if (id != resetBindings.end())
1173 {
1174 const auto &[unit, target] = textureBinding;
1175
1176 // Set active texture unit if necessary
1177 if (unit != activeTexture)
1178 {
1179 out << " ";
1180 WriteCppReplayForCall(CaptureActiveTexture(context->getState(), true,
1181 GL_TEXTURE0 + static_cast<GLenum>(unit)),
1182 replayWriter, out, header, binaryData,
1183 maxResourceIDBufferSize);
1184 out << ";\n";
1185 activeTexture = unit;
1186 }
1187
1188 // Bind texture for this target
1189 out << " ";
1190 WriteCppReplayForCall(CaptureBindTexture(context->getState(), true, target, id->second),
1191 replayWriter, out, header, binaryData, maxResourceIDBufferSize);
1192 out << ";\n";
1193 }
1194 }
1195
1196 // Restore active texture unit to initial state if necessary
1197 if (activeTexture != stateResetHelper.getResetActiveTexture())
1198 {
1199 out << " ";
1200 WriteCppReplayForCall(
1201 CaptureActiveTexture(
1202 context->getState(), true,
1203 GL_TEXTURE0 + static_cast<GLenum>(stateResetHelper.getResetActiveTexture())),
1204 replayWriter, out, header, binaryData, maxResourceIDBufferSize);
1205 out << ";\n";
1206 }
1207 }
1208
MarkResourceIDActive(ResourceIDType resourceType,GLuint id,std::vector<CallCapture> * setupCalls,const ResourceIDToSetupCallsMap * resourceIDToSetupCallsMap)1209 void MarkResourceIDActive(ResourceIDType resourceType,
1210 GLuint id,
1211 std::vector<CallCapture> *setupCalls,
1212 const ResourceIDToSetupCallsMap *resourceIDToSetupCallsMap)
1213 {
1214 const std::map<GLuint, gl::Range<size_t>> &resourceSetupCalls =
1215 (*resourceIDToSetupCallsMap)[resourceType];
1216 const auto iter = resourceSetupCalls.find(id);
1217 if (iter == resourceSetupCalls.end())
1218 {
1219 return;
1220 }
1221
1222 // Mark all of the calls that were used to initialize this resource as ACTIVE
1223 const gl::Range<size_t> &calls = iter->second;
1224 for (size_t index : calls)
1225 {
1226 (*setupCalls)[index].isActive = true;
1227 }
1228 }
1229
1230 // Some replay functions can get quite large. If over a certain size, this method breaks up the
1231 // 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)1232 void WriteCppReplayFunctionWithParts(const gl::ContextID contextID,
1233 ReplayFunc replayFunc,
1234 ReplayWriter &replayWriter,
1235 uint32_t frameIndex,
1236 std::vector<uint8_t> *binaryData,
1237 const std::vector<CallCapture> &calls,
1238 std::stringstream &header,
1239 std::stringstream &out,
1240 size_t *maxResourceIDBufferSize)
1241 {
1242 int callCount = 0;
1243 int partCount = 0;
1244
1245 if (calls.size() > kFunctionSizeLimit)
1246 {
1247 out << "void "
1248 << FmtFunction(replayFunc, contextID, FuncUsage::Definition, frameIndex, ++partCount)
1249 << "\n";
1250 }
1251 else
1252 {
1253 out << "void "
1254 << FmtFunction(replayFunc, contextID, FuncUsage::Definition, frameIndex, kNoPartId)
1255 << "\n";
1256 }
1257
1258 out << "{\n";
1259
1260 for (const CallCapture &call : calls)
1261 {
1262 // Process active calls for Setup and inactive calls for SetupInactive
1263 if ((call.isActive && replayFunc != ReplayFunc::SetupInactive) ||
1264 (!call.isActive && replayFunc == ReplayFunc::SetupInactive))
1265 {
1266 out << " ";
1267 WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
1268 maxResourceIDBufferSize);
1269 out << ";\n";
1270
1271 if (partCount > 0 && ++callCount % kFunctionSizeLimit == 0)
1272 {
1273 out << "}\n";
1274 out << "\n";
1275 out << "void "
1276 << FmtFunction(replayFunc, contextID, FuncUsage::Definition, frameIndex,
1277 ++partCount)
1278 << "\n";
1279 out << "{\n";
1280 }
1281 }
1282 }
1283 out << "}\n";
1284
1285 if (partCount > 0)
1286 {
1287 out << "\n";
1288 out << "void "
1289 << FmtFunction(replayFunc, contextID, FuncUsage::Definition, frameIndex, kNoPartId)
1290 << "\n";
1291 out << "{\n";
1292
1293 // Write out the main call which calls all the parts.
1294 for (int i = 1; i <= partCount; i++)
1295 {
1296 out << " " << FmtFunction(replayFunc, contextID, FuncUsage::Call, frameIndex, i)
1297 << ";\n";
1298 }
1299
1300 out << "}\n";
1301 }
1302 }
1303
1304 // Performance can be gained by reordering traced calls and grouping them by context.
1305 // Side context calls (as opposed to main context) can be grouped together paying attention
1306 // 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)1307 void WriteCppReplayFunctionWithPartsMultiContext(const gl::ContextID contextID,
1308 ReplayFunc replayFunc,
1309 ReplayWriter &replayWriter,
1310 uint32_t frameIndex,
1311 std::vector<uint8_t> *binaryData,
1312 std::vector<CallCapture> &calls,
1313 std::stringstream &header,
1314 std::stringstream &out,
1315 size_t *maxResourceIDBufferSize)
1316 {
1317 int callCount = 0;
1318 int partCount = 0;
1319
1320 if (calls.size() > kFunctionSizeLimit)
1321 {
1322 out << "void "
1323 << FmtFunction(replayFunc, contextID, FuncUsage::Definition, frameIndex, ++partCount)
1324 << "\n";
1325 }
1326 else
1327 {
1328 out << "void "
1329 << FmtFunction(replayFunc, contextID, FuncUsage::Definition, frameIndex, kNoPartId)
1330 << "\n";
1331 }
1332
1333 out << "{\n";
1334
1335 std::map<gl::ContextID, std::queue<int>> sideContextCallIndices;
1336
1337 // Helper lambda to write a context change command to the call stream
1338 auto writeMakeCurrentCall = [&](gl::ContextID cID) {
1339 CallCapture makeCurrentCall =
1340 egl::CaptureMakeCurrent(nullptr, true, nullptr, {0}, {0}, cID, EGL_TRUE);
1341 out << " ";
1342 WriteCppReplayForCall(makeCurrentCall, replayWriter, out, header, binaryData,
1343 maxResourceIDBufferSize);
1344 out << ";\n";
1345 callCount++;
1346 };
1347
1348 // Helper lambda to write a call to the call stream
1349 auto writeCall = [&](CallCapture &outCall, gl::ContextID cID) {
1350 out << " ";
1351 WriteCppReplayForCall(outCall, replayWriter, out, header, binaryData,
1352 maxResourceIDBufferSize);
1353 out << ";\n";
1354 if (cID != contextID)
1355 {
1356 sideContextCallIndices[cID].pop();
1357 }
1358 callCount++;
1359 };
1360
1361 int callIndex = 0;
1362 // Iterate through calls saving side context call indices in a per-side-context queue
1363 for (CallCapture &call : calls)
1364 {
1365 if (call.contextID != contextID)
1366 {
1367 sideContextCallIndices[call.contextID].push(callIndex);
1368 }
1369 callIndex++;
1370 }
1371
1372 // At the beginning of the frame, output all side context calls occuring before a sync point.
1373 // If no sync points are present, all calls in that side context are written at this time
1374 for (auto const &sideContext : sideContextCallIndices)
1375 {
1376 gl::ContextID sideContextID = sideContext.first;
1377
1378 // Make sidecontext current if there are commands before the first syncpoint
1379 if (!calls[sideContextCallIndices[sideContextID].front()].isSyncPoint)
1380 {
1381 writeMakeCurrentCall(sideContextID);
1382 }
1383 // Output all commands in sidecontext until a syncpoint is reached
1384 while (!sideContextCallIndices[sideContextID].empty() &&
1385 !calls[sideContextCallIndices[sideContextID].front()].isSyncPoint)
1386 {
1387 writeCall(calls[sideContextCallIndices[sideContextID].front()], sideContextID);
1388 }
1389 }
1390
1391 // Make mainContext current
1392 writeMakeCurrentCall(contextID);
1393
1394 // Iterate through calls writing out main context calls. When a sync point is reached, write the
1395 // next queued sequence of side context calls until another sync point is reached.
1396 for (CallCapture &call : calls)
1397 {
1398 if (call.contextID == contextID)
1399 {
1400 writeCall(call, call.contextID);
1401 }
1402 else
1403 {
1404 if (call.isSyncPoint)
1405 {
1406 // Make sideContext current
1407 writeMakeCurrentCall(call.contextID);
1408
1409 do
1410 {
1411 writeCall(calls[sideContextCallIndices[call.contextID].front()],
1412 call.contextID);
1413 } while (!sideContextCallIndices[call.contextID].empty() &&
1414 !calls[sideContextCallIndices[call.contextID].front()].isSyncPoint);
1415
1416 // Make mainContext current
1417 writeMakeCurrentCall(contextID);
1418
1419 if (partCount > 0 && ++callCount % kFunctionSizeLimit == 0)
1420 {
1421 out << "}\n";
1422 out << "\n";
1423 out << "void "
1424 << FmtFunction(replayFunc, contextID, FuncUsage::Definition, frameIndex,
1425 ++partCount)
1426 << "\n";
1427 out << "{\n";
1428 }
1429 }
1430 }
1431 }
1432 out << "}\n";
1433
1434 if (partCount > 0)
1435 {
1436 out << "\n";
1437 out << "void "
1438 << FmtFunction(replayFunc, contextID, FuncUsage::Definition, frameIndex, kNoPartId)
1439 << "\n";
1440 out << "{\n";
1441
1442 // Write out the main call which calls all the parts.
1443 for (int i = 1; i <= partCount; i++)
1444 {
1445 out << " " << FmtFunction(replayFunc, contextID, FuncUsage::Call, frameIndex, i)
1446 << ";\n";
1447 }
1448
1449 out << "}\n";
1450 }
1451 }
1452
1453 // Auxiliary contexts are other contexts in the share group that aren't the context calling
1454 // 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)1455 void WriteAuxiliaryContextCppSetupReplay(ReplayWriter &replayWriter,
1456 bool compression,
1457 const std::string &outDir,
1458 const gl::Context *context,
1459 const std::string &captureLabel,
1460 uint32_t frameIndex,
1461 const std::vector<CallCapture> &setupCalls,
1462 std::vector<uint8_t> *binaryData,
1463 bool serializeStateEnabled,
1464 const FrameCaptureShared &frameCaptureShared,
1465 size_t *maxResourceIDBufferSize)
1466 {
1467 ASSERT(frameCaptureShared.getWindowSurfaceContextID() != context->id());
1468
1469 {
1470 std::stringstream filenameStream;
1471 filenameStream << outDir << FmtCapturePrefix(context->id(), captureLabel);
1472 std::string filenamePattern = filenameStream.str();
1473 replayWriter.setFilenamePattern(filenamePattern);
1474 }
1475
1476 {
1477 std::stringstream include;
1478 include << "#include \""
1479 << FmtCapturePrefix(frameCaptureShared.getWindowSurfaceContextID(), captureLabel)
1480 << ".h\"\n";
1481 include << "#include \"angle_trace_gl.h\"\n";
1482
1483 std::string frameIncludes = include.str();
1484 replayWriter.setSourcePrologue(frameIncludes);
1485 replayWriter.setHeaderPrologue(frameIncludes);
1486 }
1487
1488 {
1489 std::stringstream protoStream;
1490 std::stringstream headerStream;
1491 std::stringstream bodyStream;
1492
1493 protoStream << "void " << FmtSetupFunction(kNoPartId, context->id(), FuncUsage::Prototype);
1494 std::string proto = protoStream.str();
1495
1496 WriteCppReplayFunctionWithParts(context->id(), ReplayFunc::Setup, replayWriter, frameIndex,
1497 binaryData, setupCalls, headerStream, bodyStream,
1498 maxResourceIDBufferSize);
1499
1500 replayWriter.addPrivateFunction(proto, headerStream, bodyStream);
1501 }
1502
1503 replayWriter.saveFrame();
1504 }
1505
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)1506 void WriteShareGroupCppSetupReplay(ReplayWriter &replayWriter,
1507 bool compression,
1508 const std::string &outDir,
1509 const std::string &captureLabel,
1510 uint32_t frameIndex,
1511 uint32_t frameCount,
1512 const std::vector<CallCapture> &setupCalls,
1513 ResourceTracker *resourceTracker,
1514 std::vector<uint8_t> *binaryData,
1515 bool serializeStateEnabled,
1516 gl::ContextID windowSurfaceContextID,
1517 size_t *maxResourceIDBufferSize)
1518 {
1519 {
1520
1521 std::stringstream include;
1522
1523 include << "#include \"angle_trace_gl.h\"\n";
1524 include << "#include \"" << FmtCapturePrefix(windowSurfaceContextID, captureLabel)
1525 << ".h\"\n";
1526
1527 std::string includeString = include.str();
1528
1529 replayWriter.setSourcePrologue(includeString);
1530 }
1531
1532 {
1533 std::stringstream protoStream;
1534 std::stringstream headerStream;
1535 std::stringstream bodyStream;
1536
1537 protoStream << "void "
1538 << FmtSetupFunction(kNoPartId, kSharedContextId, FuncUsage::Prototype);
1539 std::string proto = protoStream.str();
1540
1541 WriteCppReplayFunctionWithParts(kSharedContextId, ReplayFunc::Setup, replayWriter,
1542 frameIndex, binaryData, setupCalls, headerStream,
1543 bodyStream, maxResourceIDBufferSize);
1544
1545 replayWriter.addPrivateFunction(proto, headerStream, bodyStream);
1546
1547 protoStream.str("");
1548 headerStream.str("");
1549 bodyStream.str("");
1550 protoStream << "void "
1551 << FmtSetupInactiveFunction(kNoPartId, kSharedContextId, FuncUsage::Prototype);
1552 proto = protoStream.str();
1553
1554 WriteCppReplayFunctionWithParts(kSharedContextId, ReplayFunc::SetupInactive, replayWriter,
1555 frameIndex, binaryData, setupCalls, headerStream,
1556 bodyStream, maxResourceIDBufferSize);
1557 replayWriter.addPrivateFunction(proto, headerStream, bodyStream);
1558 }
1559
1560 {
1561 std::stringstream filenameStream;
1562 filenameStream << outDir << FmtCapturePrefix(kSharedContextId, captureLabel);
1563
1564 std::string filenamePattern = filenameStream.str();
1565
1566 replayWriter.setFilenamePattern(filenamePattern);
1567 }
1568
1569 replayWriter.saveSetupFile();
1570 }
1571
GetAttachedProgramSources(const gl::Context * context,const gl::Program * program)1572 ProgramSources GetAttachedProgramSources(const gl::Context *context, const gl::Program *program)
1573 {
1574 ProgramSources sources;
1575 for (gl::ShaderType shaderType : gl::AllShaderTypes())
1576 {
1577 const gl::Shader *shader = program->getAttachedShader(shaderType);
1578 if (shader)
1579 {
1580 sources[shaderType] = shader->getSourceString();
1581 }
1582 }
1583 return sources;
1584 }
1585
1586 template <typename IDType>
CaptureUpdateResourceIDs(const gl::Context * context,const CallCapture & call,const ParamCapture & param,ResourceTracker * resourceTracker,std::vector<CallCapture> * callsOut)1587 void CaptureUpdateResourceIDs(const gl::Context *context,
1588 const CallCapture &call,
1589 const ParamCapture ¶m,
1590 ResourceTracker *resourceTracker,
1591 std::vector<CallCapture> *callsOut)
1592 {
1593 GLsizei n = call.params.getParamFlexName("n", "count", ParamType::TGLsizei, 0).value.GLsizeiVal;
1594 ASSERT(param.data.size() == 1);
1595 ResourceIDType resourceIDType = GetResourceIDTypeFromParamType(param.type);
1596 ASSERT(resourceIDType != ResourceIDType::InvalidEnum &&
1597 resourceIDType != ResourceIDType::ShaderProgram);
1598 const char *resourceName = GetResourceIDTypeName(resourceIDType);
1599
1600 std::stringstream updateFuncNameStr;
1601 updateFuncNameStr << "Update" << resourceName << "ID";
1602 bool trackedPerContext = IsTrackedPerContext(resourceIDType);
1603 if (trackedPerContext)
1604 {
1605 // TODO (https://issuetracker.google.com/169868803) The '2' version can be removed after all
1606 // context-local objects are tracked per-context
1607 updateFuncNameStr << "2";
1608 }
1609 std::string updateFuncName = updateFuncNameStr.str();
1610
1611 const IDType *returnedIDs = reinterpret_cast<const IDType *>(param.data[0].data());
1612
1613 ResourceSet &startingSet =
1614 resourceTracker->getTrackedResource(context->id(), resourceIDType).getStartingResources();
1615
1616 for (GLsizei idIndex = 0; idIndex < n; ++idIndex)
1617 {
1618 IDType id = returnedIDs[idIndex];
1619 GLsizei readBufferOffset = idIndex * sizeof(gl::RenderbufferID);
1620 ParamBuffer params;
1621 if (trackedPerContext)
1622 {
1623 params.addValueParam("contextId", ParamType::TGLuint, context->id().value);
1624 }
1625 params.addValueParam("id", ParamType::TGLuint, id.value);
1626 params.addValueParam("readBufferOffset", ParamType::TGLsizei, readBufferOffset);
1627 callsOut->emplace_back(updateFuncName, std::move(params));
1628
1629 // Add only if not in starting resources.
1630 if (startingSet.find(id.value) == startingSet.end())
1631 {
1632 resourceTracker->getTrackedResource(context->id(), resourceIDType)
1633 .getNewResources()
1634 .insert(id.value);
1635 }
1636 }
1637 }
1638
CaptureUpdateUniformLocations(const gl::Program * program,std::vector<CallCapture> * callsOut)1639 void CaptureUpdateUniformLocations(const gl::Program *program, std::vector<CallCapture> *callsOut)
1640 {
1641 const gl::ProgramExecutable &executable = program->getExecutable();
1642 const std::vector<gl::LinkedUniform> &uniforms = executable.getUniforms();
1643 const std::vector<gl::VariableLocation> &locations = executable.getUniformLocations();
1644
1645 for (GLint location = 0; location < static_cast<GLint>(locations.size()); ++location)
1646 {
1647 const gl::VariableLocation &locationVar = locations[location];
1648
1649 // This handles the case where the application calls glBindUniformLocationCHROMIUM
1650 // on an unused uniform. We must still store a -1 into gUniformLocations in case the
1651 // application attempts to call a glUniform* call. To do this we'll pass in a blank name to
1652 // force glGetUniformLocation to return -1.
1653 std::string name;
1654 int count = 1;
1655 ParamBuffer params;
1656 params.addValueParam("program", ParamType::TGLuint, program->id().value);
1657
1658 if (locationVar.index >= uniforms.size())
1659 {
1660 name = "";
1661 }
1662 else
1663 {
1664 const gl::LinkedUniform &uniform = uniforms[locationVar.index];
1665
1666 name = executable.getUniformNameByIndex(locationVar.index);
1667
1668 if (uniform.isArray())
1669 {
1670 if (locationVar.arrayIndex > 0)
1671 {
1672 // Non-sequential array uniform locations are not currently handled.
1673 // In practice array locations shouldn't ever be non-sequential.
1674 ASSERT(uniform.getLocation() == -1 ||
1675 location ==
1676 uniform.getLocation() + static_cast<int>(locationVar.arrayIndex));
1677 continue;
1678 }
1679
1680 name = gl::StripLastArrayIndex(name);
1681 count = uniform.getBasicTypeElementCount();
1682 }
1683 }
1684
1685 ParamCapture nameParam("name", ParamType::TGLcharConstPointer);
1686 CaptureString(name.c_str(), &nameParam);
1687 params.addParam(std::move(nameParam));
1688 params.addValueParam("location", ParamType::TGLint, location);
1689 params.addValueParam("count", ParamType::TGLint, static_cast<GLint>(count));
1690 callsOut->emplace_back("UpdateUniformLocation", std::move(params));
1691 }
1692 }
1693
CaptureValidateSerializedState(const gl::Context * context,std::vector<CallCapture> * callsOut)1694 void CaptureValidateSerializedState(const gl::Context *context, std::vector<CallCapture> *callsOut)
1695 {
1696 INFO() << "Capturing validation checkpoint at position " << callsOut->size();
1697
1698 context->finishImmutable();
1699
1700 std::string serializedState;
1701 angle::Result result = angle::SerializeContextToString(context, &serializedState);
1702 if (result != angle::Result::Continue)
1703 {
1704 ERR() << "Internal error serializing context state.";
1705 return;
1706 }
1707 ParamCapture serializedStateParam("serializedState", ParamType::TGLcharConstPointer);
1708 CaptureString(serializedState.c_str(), &serializedStateParam);
1709
1710 ParamBuffer params;
1711 params.addParam(std::move(serializedStateParam));
1712
1713 callsOut->emplace_back("VALIDATE_CHECKPOINT", std::move(params));
1714 }
1715
CaptureUpdateUniformBlockIndexes(const gl::Program * program,std::vector<CallCapture> * callsOut)1716 void CaptureUpdateUniformBlockIndexes(const gl::Program *program,
1717 std::vector<CallCapture> *callsOut)
1718 {
1719 const std::vector<gl::InterfaceBlock> &uniformBlocks =
1720 program->getExecutable().getUniformBlocks();
1721
1722 for (GLuint index = 0; index < uniformBlocks.size(); ++index)
1723 {
1724 ParamBuffer params;
1725
1726 std::string name;
1727 params.addValueParam("program", ParamType::TShaderProgramID, program->id());
1728
1729 const std::string fullName = uniformBlocks[index].nameWithArrayIndex();
1730 ParamCapture nameParam("name", ParamType::TGLcharConstPointer);
1731 CaptureString(fullName.c_str(), &nameParam);
1732 params.addParam(std::move(nameParam));
1733
1734 params.addValueParam("index", ParamType::TGLuint, index);
1735 callsOut->emplace_back("UpdateUniformBlockIndex", std::move(params));
1736 }
1737 }
1738
CaptureDeleteUniformLocations(gl::ShaderProgramID program,std::vector<CallCapture> * callsOut)1739 void CaptureDeleteUniformLocations(gl::ShaderProgramID program, std::vector<CallCapture> *callsOut)
1740 {
1741 ParamBuffer params;
1742 params.addValueParam("program", ParamType::TShaderProgramID, program);
1743 callsOut->emplace_back("DeleteUniformLocations", std::move(params));
1744 }
1745
MaybeCaptureUpdateResourceIDs(const gl::Context * context,ResourceTracker * resourceTracker,std::vector<CallCapture> * callsOut)1746 void MaybeCaptureUpdateResourceIDs(const gl::Context *context,
1747 ResourceTracker *resourceTracker,
1748 std::vector<CallCapture> *callsOut)
1749 {
1750 const CallCapture &call = callsOut->back();
1751
1752 switch (call.entryPoint)
1753 {
1754 case EntryPoint::GLGenBuffers:
1755 {
1756 const ParamCapture &buffers =
1757 call.params.getParam("buffersPacked", ParamType::TBufferIDPointer, 1);
1758 CaptureUpdateResourceIDs<gl::BufferID>(context, call, buffers, resourceTracker,
1759 callsOut);
1760 break;
1761 }
1762
1763 case EntryPoint::GLGenFencesNV:
1764 {
1765 const ParamCapture &fences =
1766 call.params.getParam("fencesPacked", ParamType::TFenceNVIDPointer, 1);
1767 CaptureUpdateResourceIDs<gl::FenceNVID>(context, call, fences, resourceTracker,
1768 callsOut);
1769 break;
1770 }
1771
1772 case EntryPoint::GLGenFramebuffers:
1773 case EntryPoint::GLGenFramebuffersOES:
1774 {
1775 const ParamCapture &framebuffers =
1776 call.params.getParam("framebuffersPacked", ParamType::TFramebufferIDPointer, 1);
1777 CaptureUpdateResourceIDs<gl::FramebufferID>(context, call, framebuffers,
1778 resourceTracker, callsOut);
1779 break;
1780 }
1781
1782 case EntryPoint::GLGenProgramPipelines:
1783 {
1784 const ParamCapture &pipelines =
1785 call.params.getParam("pipelinesPacked", ParamType::TProgramPipelineIDPointer, 1);
1786 CaptureUpdateResourceIDs<gl::ProgramPipelineID>(context, call, pipelines,
1787 resourceTracker, callsOut);
1788 break;
1789 }
1790
1791 case EntryPoint::GLGenQueries:
1792 case EntryPoint::GLGenQueriesEXT:
1793 {
1794 const ParamCapture &queries =
1795 call.params.getParam("idsPacked", ParamType::TQueryIDPointer, 1);
1796 CaptureUpdateResourceIDs<gl::QueryID>(context, call, queries, resourceTracker,
1797 callsOut);
1798 break;
1799 }
1800
1801 case EntryPoint::GLGenRenderbuffers:
1802 case EntryPoint::GLGenRenderbuffersOES:
1803 {
1804 const ParamCapture &renderbuffers =
1805 call.params.getParam("renderbuffersPacked", ParamType::TRenderbufferIDPointer, 1);
1806 CaptureUpdateResourceIDs<gl::RenderbufferID>(context, call, renderbuffers,
1807 resourceTracker, callsOut);
1808 break;
1809 }
1810
1811 case EntryPoint::GLGenSamplers:
1812 {
1813 const ParamCapture &samplers =
1814 call.params.getParam("samplersPacked", ParamType::TSamplerIDPointer, 1);
1815 CaptureUpdateResourceIDs<gl::SamplerID>(context, call, samplers, resourceTracker,
1816 callsOut);
1817 break;
1818 }
1819
1820 case EntryPoint::GLGenSemaphoresEXT:
1821 {
1822 const ParamCapture &semaphores =
1823 call.params.getParam("semaphoresPacked", ParamType::TSemaphoreIDPointer, 1);
1824 CaptureUpdateResourceIDs<gl::SemaphoreID>(context, call, semaphores, resourceTracker,
1825 callsOut);
1826 break;
1827 }
1828
1829 case EntryPoint::GLGenTextures:
1830 {
1831 const ParamCapture &textures =
1832 call.params.getParam("texturesPacked", ParamType::TTextureIDPointer, 1);
1833 CaptureUpdateResourceIDs<gl::TextureID>(context, call, textures, resourceTracker,
1834 callsOut);
1835 break;
1836 }
1837
1838 case EntryPoint::GLGenTransformFeedbacks:
1839 {
1840 const ParamCapture &xfbs =
1841 call.params.getParam("idsPacked", ParamType::TTransformFeedbackIDPointer, 1);
1842 CaptureUpdateResourceIDs<gl::TransformFeedbackID>(context, call, xfbs, resourceTracker,
1843 callsOut);
1844 break;
1845 }
1846
1847 case EntryPoint::GLGenVertexArrays:
1848 case EntryPoint::GLGenVertexArraysOES:
1849 {
1850 const ParamCapture &vertexArrays =
1851 call.params.getParam("arraysPacked", ParamType::TVertexArrayIDPointer, 1);
1852 CaptureUpdateResourceIDs<gl::VertexArrayID>(context, call, vertexArrays,
1853 resourceTracker, callsOut);
1854 break;
1855 }
1856
1857 case EntryPoint::GLCreateMemoryObjectsEXT:
1858 {
1859 const ParamCapture &memoryObjects =
1860 call.params.getParam("memoryObjectsPacked", ParamType::TMemoryObjectIDPointer, 1);
1861 CaptureUpdateResourceIDs<gl::MemoryObjectID>(context, call, memoryObjects,
1862 resourceTracker, callsOut);
1863 break;
1864 }
1865
1866 default:
1867 break;
1868 }
1869 }
1870
IsDefaultCurrentValue(const gl::VertexAttribCurrentValueData & currentValue)1871 bool IsDefaultCurrentValue(const gl::VertexAttribCurrentValueData ¤tValue)
1872 {
1873 if (currentValue.Type != gl::VertexAttribType::Float)
1874 return false;
1875
1876 return currentValue.Values.FloatValues[0] == 0.0f &&
1877 currentValue.Values.FloatValues[1] == 0.0f &&
1878 currentValue.Values.FloatValues[2] == 0.0f && currentValue.Values.FloatValues[3] == 1.0f;
1879 }
1880
IsQueryActive(const gl::State & glState,gl::QueryID & queryID)1881 bool IsQueryActive(const gl::State &glState, gl::QueryID &queryID)
1882 {
1883 const gl::ActiveQueryMap &activeQueries = glState.getActiveQueriesForCapture();
1884 for (const auto &activeQueryIter : activeQueries)
1885 {
1886 const gl::Query *activeQuery = activeQueryIter.get();
1887 if (activeQuery && activeQuery->id() == queryID)
1888 {
1889 return true;
1890 }
1891 }
1892
1893 return false;
1894 }
1895
IsTextureUpdate(CallCapture & call)1896 bool IsTextureUpdate(CallCapture &call)
1897 {
1898 switch (call.entryPoint)
1899 {
1900 case EntryPoint::GLCompressedCopyTextureCHROMIUM:
1901 case EntryPoint::GLCompressedTexImage2D:
1902 case EntryPoint::GLCompressedTexImage2DRobustANGLE:
1903 case EntryPoint::GLCompressedTexImage3D:
1904 case EntryPoint::GLCompressedTexImage3DOES:
1905 case EntryPoint::GLCompressedTexImage3DRobustANGLE:
1906 case EntryPoint::GLCompressedTexSubImage2D:
1907 case EntryPoint::GLCompressedTexSubImage2DRobustANGLE:
1908 case EntryPoint::GLCompressedTexSubImage3D:
1909 case EntryPoint::GLCompressedTexSubImage3DOES:
1910 case EntryPoint::GLCompressedTexSubImage3DRobustANGLE:
1911 case EntryPoint::GLCopyTexImage2D:
1912 case EntryPoint::GLCopyTexSubImage2D:
1913 case EntryPoint::GLCopyTexSubImage3D:
1914 case EntryPoint::GLCopyTexSubImage3DOES:
1915 case EntryPoint::GLCopyTexture3DANGLE:
1916 case EntryPoint::GLCopyTextureCHROMIUM:
1917 case EntryPoint::GLTexImage2D:
1918 case EntryPoint::GLTexImage2DExternalANGLE:
1919 case EntryPoint::GLTexImage2DRobustANGLE:
1920 case EntryPoint::GLTexImage3D:
1921 case EntryPoint::GLTexImage3DOES:
1922 case EntryPoint::GLTexImage3DRobustANGLE:
1923 case EntryPoint::GLTexSubImage2D:
1924 case EntryPoint::GLTexSubImage2DRobustANGLE:
1925 case EntryPoint::GLTexSubImage3D:
1926 case EntryPoint::GLTexSubImage3DOES:
1927 case EntryPoint::GLTexSubImage3DRobustANGLE:
1928 case EntryPoint::GLCopyImageSubData:
1929 case EntryPoint::GLCopyImageSubDataEXT:
1930 case EntryPoint::GLCopyImageSubDataOES:
1931 return true;
1932 default:
1933 return false;
1934 }
1935 }
1936
IsImageUpdate(CallCapture & call)1937 bool IsImageUpdate(CallCapture &call)
1938 {
1939 switch (call.entryPoint)
1940 {
1941 case EntryPoint::GLDispatchCompute:
1942 case EntryPoint::GLDispatchComputeIndirect:
1943 return true;
1944 default:
1945 return false;
1946 }
1947 }
1948
IsVertexArrayUpdate(CallCapture & call)1949 bool IsVertexArrayUpdate(CallCapture &call)
1950 {
1951 switch (call.entryPoint)
1952 {
1953 case EntryPoint::GLVertexAttribFormat:
1954 case EntryPoint::GLVertexAttribIFormat:
1955 case EntryPoint::GLBindVertexBuffer:
1956 case EntryPoint::GLVertexAttribBinding:
1957 case EntryPoint::GLVertexAttribPointer:
1958 case EntryPoint::GLVertexAttribIPointer:
1959 case EntryPoint::GLEnableVertexAttribArray:
1960 case EntryPoint::GLDisableVertexAttribArray:
1961 case EntryPoint::GLVertexBindingDivisor:
1962 case EntryPoint::GLVertexAttribDivisor:
1963 return true;
1964 default:
1965 return false;
1966 }
1967 }
1968
IsSharedObjectResource(ResourceIDType type)1969 bool IsSharedObjectResource(ResourceIDType type)
1970 {
1971 // This helper function informs us which objects are shared vs. per context
1972 //
1973 // OpenGL ES Version 3.2 (October 22, 2019)
1974 // Chapter 5 Shared Objects and Multiple Contexts:
1975 //
1976 // - Objects that can be shared between contexts include buffer objects, program
1977 // and shader objects, renderbuffer objects, sampler objects, sync objects, and texture
1978 // objects (except for the texture objects named zero).
1979 // - Objects which contain references to other objects include framebuffer, program
1980 // pipeline, transform feedback, and vertex array objects. Such objects are called
1981 // container objects and are not shared.
1982 //
1983 // Notably absent from this list are Sync objects, which are not ResourceIDType, are handled
1984 // elsewhere, and are shared:
1985 // - 2.6.13 Sync Objects: Sync objects may be shared.
1986
1987 switch (type)
1988 {
1989 case ResourceIDType::Buffer:
1990 // 2.6.2 Buffer Objects: Buffer objects may be shared.
1991 return true;
1992
1993 case ResourceIDType::Framebuffer:
1994 // 2.6.9 Framebuffer Objects: Framebuffer objects are container objects including
1995 // references to renderbuffer and / or texture objects, and are not shared.
1996 return false;
1997
1998 case ResourceIDType::ProgramPipeline:
1999 // 2.6.5 Program Pipeline Objects: Program pipeline objects are container objects
2000 // including references to program objects, and are not shared.
2001 return false;
2002
2003 case ResourceIDType::TransformFeedback:
2004 // 2.6.11 Transform Feedback Objects: Transform feedback objects are container objects
2005 // including references to buffer objects, and are not shared
2006 return false;
2007
2008 case ResourceIDType::VertexArray:
2009 // 2.6.10 Vertex Array Objects: Vertex array objects are container objects including
2010 // references to buffer objects, and are not shared
2011 return false;
2012
2013 case ResourceIDType::FenceNV:
2014 // From https://registry.khronos.org/OpenGL/extensions/NV/NV_fence.txt
2015 // Are the fences sharable between multiple contexts?
2016 // RESOLUTION: No.
2017 return false;
2018
2019 case ResourceIDType::Renderbuffer:
2020 // 2.6.8 Renderbuffer Objects: Renderbuffer objects may be shared.
2021 return true;
2022
2023 case ResourceIDType::ShaderProgram:
2024 // 2.6.3 Shader Objects: Shader objects may be shared.
2025 // 2.6.4 Program Objects: Program objects may be shared.
2026 return true;
2027
2028 case ResourceIDType::Sampler:
2029 // 2.6.7 Sampler Objects: Sampler objects may be shared
2030 return true;
2031
2032 case ResourceIDType::Sync:
2033 // 2.6.13 Sync Objects: Sync objects may be shared.
2034 return true;
2035
2036 case ResourceIDType::Texture:
2037 // 2.6.6 Texture Objects: Texture objects may be shared
2038 return true;
2039
2040 case ResourceIDType::Query:
2041 // 2.6.12 Query Objects: Query objects are not shared
2042 return false;
2043
2044 case ResourceIDType::Semaphore:
2045 // From https://registry.khronos.org/OpenGL/extensions/EXT/EXT_external_objects.txt
2046 // 2.6.14 Semaphore Objects: Semaphore objects may be shared.
2047 return true;
2048
2049 case ResourceIDType::MemoryObject:
2050 // From https://registry.khronos.org/OpenGL/extensions/EXT/EXT_external_objects.txt
2051 // 2.6.15 Memory Objects: Memory objects may be shared.
2052 return true;
2053
2054 case ResourceIDType::Context:
2055 case ResourceIDType::Image:
2056 case ResourceIDType::Surface:
2057 case ResourceIDType::egl_Sync:
2058 // EGL types are associated with a display and not bound to a context
2059 // For the way this function is used, we can treat them as shared.
2060 return true;
2061
2062 case ResourceIDType::EnumCount:
2063 default:
2064 ERR() << "Unhandled ResourceIDType= " << static_cast<int>(type);
2065 UNREACHABLE();
2066 return false;
2067 }
2068 }
2069
2070 enum class DefaultUniformType
2071 {
2072 None,
2073 CurrentProgram,
2074 SpecifiedProgram,
2075 };
2076
GetDefaultUniformType(const CallCapture & call)2077 DefaultUniformType GetDefaultUniformType(const CallCapture &call)
2078 {
2079 switch (call.entryPoint)
2080 {
2081 case EntryPoint::GLProgramUniform1f:
2082 case EntryPoint::GLProgramUniform1fEXT:
2083 case EntryPoint::GLProgramUniform1fv:
2084 case EntryPoint::GLProgramUniform1fvEXT:
2085 case EntryPoint::GLProgramUniform1i:
2086 case EntryPoint::GLProgramUniform1iEXT:
2087 case EntryPoint::GLProgramUniform1iv:
2088 case EntryPoint::GLProgramUniform1ivEXT:
2089 case EntryPoint::GLProgramUniform1ui:
2090 case EntryPoint::GLProgramUniform1uiEXT:
2091 case EntryPoint::GLProgramUniform1uiv:
2092 case EntryPoint::GLProgramUniform1uivEXT:
2093 case EntryPoint::GLProgramUniform2f:
2094 case EntryPoint::GLProgramUniform2fEXT:
2095 case EntryPoint::GLProgramUniform2fv:
2096 case EntryPoint::GLProgramUniform2fvEXT:
2097 case EntryPoint::GLProgramUniform2i:
2098 case EntryPoint::GLProgramUniform2iEXT:
2099 case EntryPoint::GLProgramUniform2iv:
2100 case EntryPoint::GLProgramUniform2ivEXT:
2101 case EntryPoint::GLProgramUniform2ui:
2102 case EntryPoint::GLProgramUniform2uiEXT:
2103 case EntryPoint::GLProgramUniform2uiv:
2104 case EntryPoint::GLProgramUniform2uivEXT:
2105 case EntryPoint::GLProgramUniform3f:
2106 case EntryPoint::GLProgramUniform3fEXT:
2107 case EntryPoint::GLProgramUniform3fv:
2108 case EntryPoint::GLProgramUniform3fvEXT:
2109 case EntryPoint::GLProgramUniform3i:
2110 case EntryPoint::GLProgramUniform3iEXT:
2111 case EntryPoint::GLProgramUniform3iv:
2112 case EntryPoint::GLProgramUniform3ivEXT:
2113 case EntryPoint::GLProgramUniform3ui:
2114 case EntryPoint::GLProgramUniform3uiEXT:
2115 case EntryPoint::GLProgramUniform3uiv:
2116 case EntryPoint::GLProgramUniform3uivEXT:
2117 case EntryPoint::GLProgramUniform4f:
2118 case EntryPoint::GLProgramUniform4fEXT:
2119 case EntryPoint::GLProgramUniform4fv:
2120 case EntryPoint::GLProgramUniform4fvEXT:
2121 case EntryPoint::GLProgramUniform4i:
2122 case EntryPoint::GLProgramUniform4iEXT:
2123 case EntryPoint::GLProgramUniform4iv:
2124 case EntryPoint::GLProgramUniform4ivEXT:
2125 case EntryPoint::GLProgramUniform4ui:
2126 case EntryPoint::GLProgramUniform4uiEXT:
2127 case EntryPoint::GLProgramUniform4uiv:
2128 case EntryPoint::GLProgramUniform4uivEXT:
2129 case EntryPoint::GLProgramUniformMatrix2fv:
2130 case EntryPoint::GLProgramUniformMatrix2fvEXT:
2131 case EntryPoint::GLProgramUniformMatrix2x3fv:
2132 case EntryPoint::GLProgramUniformMatrix2x3fvEXT:
2133 case EntryPoint::GLProgramUniformMatrix2x4fv:
2134 case EntryPoint::GLProgramUniformMatrix2x4fvEXT:
2135 case EntryPoint::GLProgramUniformMatrix3fv:
2136 case EntryPoint::GLProgramUniformMatrix3fvEXT:
2137 case EntryPoint::GLProgramUniformMatrix3x2fv:
2138 case EntryPoint::GLProgramUniformMatrix3x2fvEXT:
2139 case EntryPoint::GLProgramUniformMatrix3x4fv:
2140 case EntryPoint::GLProgramUniformMatrix3x4fvEXT:
2141 case EntryPoint::GLProgramUniformMatrix4fv:
2142 case EntryPoint::GLProgramUniformMatrix4fvEXT:
2143 case EntryPoint::GLProgramUniformMatrix4x2fv:
2144 case EntryPoint::GLProgramUniformMatrix4x2fvEXT:
2145 case EntryPoint::GLProgramUniformMatrix4x3fv:
2146 case EntryPoint::GLProgramUniformMatrix4x3fvEXT:
2147 return DefaultUniformType::SpecifiedProgram;
2148
2149 case EntryPoint::GLUniform1f:
2150 case EntryPoint::GLUniform1fv:
2151 case EntryPoint::GLUniform1i:
2152 case EntryPoint::GLUniform1iv:
2153 case EntryPoint::GLUniform1ui:
2154 case EntryPoint::GLUniform1uiv:
2155 case EntryPoint::GLUniform2f:
2156 case EntryPoint::GLUniform2fv:
2157 case EntryPoint::GLUniform2i:
2158 case EntryPoint::GLUniform2iv:
2159 case EntryPoint::GLUniform2ui:
2160 case EntryPoint::GLUniform2uiv:
2161 case EntryPoint::GLUniform3f:
2162 case EntryPoint::GLUniform3fv:
2163 case EntryPoint::GLUniform3i:
2164 case EntryPoint::GLUniform3iv:
2165 case EntryPoint::GLUniform3ui:
2166 case EntryPoint::GLUniform3uiv:
2167 case EntryPoint::GLUniform4f:
2168 case EntryPoint::GLUniform4fv:
2169 case EntryPoint::GLUniform4i:
2170 case EntryPoint::GLUniform4iv:
2171 case EntryPoint::GLUniform4ui:
2172 case EntryPoint::GLUniform4uiv:
2173 case EntryPoint::GLUniformMatrix2fv:
2174 case EntryPoint::GLUniformMatrix2x3fv:
2175 case EntryPoint::GLUniformMatrix2x4fv:
2176 case EntryPoint::GLUniformMatrix3fv:
2177 case EntryPoint::GLUniformMatrix3x2fv:
2178 case EntryPoint::GLUniformMatrix3x4fv:
2179 case EntryPoint::GLUniformMatrix4fv:
2180 case EntryPoint::GLUniformMatrix4x2fv:
2181 case EntryPoint::GLUniformMatrix4x3fv:
2182 return DefaultUniformType::CurrentProgram;
2183
2184 default:
2185 return DefaultUniformType::None;
2186 }
2187 }
2188
CaptureFramebufferAttachment(std::vector<CallCapture> * setupCalls,const gl::State & replayState,const FramebufferCaptureFuncs & framebufferFuncs,const gl::FramebufferAttachment & attachment,std::vector<CallCapture> * shareGroupSetupCalls,ResourceIDToSetupCallsMap * resourceIDToSetupCalls)2189 void CaptureFramebufferAttachment(std::vector<CallCapture> *setupCalls,
2190 const gl::State &replayState,
2191 const FramebufferCaptureFuncs &framebufferFuncs,
2192 const gl::FramebufferAttachment &attachment,
2193 std::vector<CallCapture> *shareGroupSetupCalls,
2194 ResourceIDToSetupCallsMap *resourceIDToSetupCalls)
2195 {
2196 GLuint resourceID = attachment.getResource()->getId();
2197
2198 if (attachment.type() == GL_TEXTURE)
2199 {
2200 gl::ImageIndex index = attachment.getTextureImageIndex();
2201
2202 if (index.usesTex3D())
2203 {
2204 Capture(setupCalls, CaptureFramebufferTextureLayer(
2205 replayState, true, GL_FRAMEBUFFER, attachment.getBinding(),
2206 {resourceID}, index.getLevelIndex(), index.getLayerIndex()));
2207 }
2208 else
2209 {
2210 Capture(setupCalls,
2211 framebufferFuncs.framebufferTexture2D(
2212 replayState, true, GL_FRAMEBUFFER, attachment.getBinding(),
2213 index.getTargetOrFirstCubeFace(), {resourceID}, index.getLevelIndex()));
2214 }
2215
2216 std::vector<gl::TextureID> textureIDs;
2217 const CallCapture &call = setupCalls->back();
2218 if (FindResourceIDsInCall<gl::TextureID>(call, textureIDs))
2219 {
2220 // We skip the is active check on the assumption this call is made during MEC
2221 for (gl::TextureID textureID : textureIDs)
2222 {
2223 // Track that this call referenced a Texture, setting it active for Setup
2224 MarkResourceIDActive(ResourceIDType::Texture, textureID.value, shareGroupSetupCalls,
2225 resourceIDToSetupCalls);
2226 }
2227 }
2228 }
2229 else
2230 {
2231 ASSERT(attachment.type() == GL_RENDERBUFFER);
2232 Capture(setupCalls, framebufferFuncs.framebufferRenderbuffer(
2233 replayState, true, GL_FRAMEBUFFER, attachment.getBinding(),
2234 GL_RENDERBUFFER, {resourceID}));
2235 }
2236 }
2237
CaptureUpdateUniformValues(const gl::State & replayState,const gl::Context * context,gl::Program * program,ResourceTracker * resourceTracker,std::vector<CallCapture> * callsOut)2238 void CaptureUpdateUniformValues(const gl::State &replayState,
2239 const gl::Context *context,
2240 gl::Program *program,
2241 ResourceTracker *resourceTracker,
2242 std::vector<CallCapture> *callsOut)
2243 {
2244 if (!program->isLinked())
2245 {
2246 // We can't populate uniforms if the program hasn't been linked
2247 return;
2248 }
2249
2250 // We need to bind the program and update its uniforms
2251 if (!replayState.getProgram() || replayState.getProgram()->id() != program->id())
2252 {
2253 Capture(callsOut, CaptureUseProgram(replayState, true, program->id()));
2254 CaptureUpdateCurrentProgram(callsOut->back(), 0, callsOut);
2255 }
2256
2257 const gl::ProgramExecutable &executable = program->getExecutable();
2258
2259 for (GLuint uniformIndex = 0;
2260 uniformIndex < static_cast<GLuint>(executable.getUniforms().size()); uniformIndex++)
2261 {
2262 std::string uniformName = executable.getUniformNameByIndex(uniformIndex);
2263 const gl::LinkedUniform &uniform = executable.getUniformByIndex(uniformIndex);
2264
2265 int uniformCount = 1;
2266 if (uniform.isArray())
2267 {
2268 uniformCount = uniform.getBasicTypeElementCount();
2269 uniformName = gl::StripLastArrayIndex(uniformName);
2270 }
2271
2272 gl::UniformLocation uniformLoc = executable.getUniformLocation(uniformName);
2273 const gl::UniformTypeInfo &typeInfo = gl::GetUniformTypeInfo(uniform.getType());
2274 int componentCount = typeInfo.componentCount;
2275 int uniformSize = uniformCount * componentCount;
2276
2277 // For arrayed uniforms, we'll need to increment a read location
2278 gl::UniformLocation readLoc = uniformLoc;
2279
2280 // If the uniform is unused, just continue
2281 if (readLoc.value == -1)
2282 {
2283 continue;
2284 }
2285
2286 // Image uniforms are special and cannot be set this way
2287 if (typeInfo.isImageType)
2288 {
2289 continue;
2290 }
2291
2292 DefaultUniformCallsPerLocationMap &resetCalls =
2293 resourceTracker->getDefaultUniformResetCalls(program->id());
2294
2295 // Create two lists of calls for uniforms, one for Setup, one for Reset
2296 CallVector defaultUniformCalls({callsOut, &resetCalls[uniformLoc]});
2297
2298 // Samplers should be populated with GL_INT, regardless of return type
2299 if (typeInfo.isSampler)
2300 {
2301 std::vector<GLint> uniformBuffer(uniformSize);
2302 for (int index = 0; index < uniformCount; index++, readLoc.value++)
2303 {
2304 executable.getUniformiv(context, readLoc,
2305 uniformBuffer.data() + index * componentCount);
2306 resourceTracker->setDefaultUniformBaseLocation(program->id(), readLoc, uniformLoc);
2307 }
2308
2309 for (std::vector<CallCapture> *calls : defaultUniformCalls)
2310 {
2311 Capture(calls, CaptureUniform1iv(replayState, true, uniformLoc, uniformCount,
2312 uniformBuffer.data()));
2313 }
2314
2315 continue;
2316 }
2317
2318 switch (typeInfo.componentType)
2319 {
2320 case GL_FLOAT:
2321 {
2322 std::vector<GLfloat> uniformBuffer(uniformSize);
2323 for (int index = 0; index < uniformCount; index++, readLoc.value++)
2324 {
2325 executable.getUniformfv(context, readLoc,
2326 uniformBuffer.data() + index * componentCount);
2327 resourceTracker->setDefaultUniformBaseLocation(program->id(), readLoc,
2328 uniformLoc);
2329 }
2330 switch (typeInfo.type)
2331 {
2332 // Note: All matrix uniforms are populated without transpose
2333 case GL_FLOAT_MAT4x3:
2334 for (std::vector<CallCapture> *calls : defaultUniformCalls)
2335 {
2336 Capture(calls, CaptureUniformMatrix4x3fv(replayState, true, uniformLoc,
2337 uniformCount, false,
2338 uniformBuffer.data()));
2339 }
2340 break;
2341 case GL_FLOAT_MAT4x2:
2342 for (std::vector<CallCapture> *calls : defaultUniformCalls)
2343 {
2344 Capture(calls, CaptureUniformMatrix4x2fv(replayState, true, uniformLoc,
2345 uniformCount, false,
2346 uniformBuffer.data()));
2347 }
2348 break;
2349 case GL_FLOAT_MAT4:
2350 for (std::vector<CallCapture> *calls : defaultUniformCalls)
2351 {
2352 Capture(calls, CaptureUniformMatrix4fv(replayState, true, uniformLoc,
2353 uniformCount, false,
2354 uniformBuffer.data()));
2355 }
2356 break;
2357 case GL_FLOAT_MAT3x4:
2358 for (std::vector<CallCapture> *calls : defaultUniformCalls)
2359 {
2360 Capture(calls, CaptureUniformMatrix3x4fv(replayState, true, uniformLoc,
2361 uniformCount, false,
2362 uniformBuffer.data()));
2363 }
2364 break;
2365 case GL_FLOAT_MAT3x2:
2366 for (std::vector<CallCapture> *calls : defaultUniformCalls)
2367 {
2368 Capture(calls, CaptureUniformMatrix3x2fv(replayState, true, uniformLoc,
2369 uniformCount, false,
2370 uniformBuffer.data()));
2371 }
2372 break;
2373 case GL_FLOAT_MAT3:
2374 for (std::vector<CallCapture> *calls : defaultUniformCalls)
2375 {
2376 Capture(calls, CaptureUniformMatrix3fv(replayState, true, uniformLoc,
2377 uniformCount, false,
2378 uniformBuffer.data()));
2379 }
2380 break;
2381 case GL_FLOAT_MAT2x4:
2382 for (std::vector<CallCapture> *calls : defaultUniformCalls)
2383 {
2384 Capture(calls, CaptureUniformMatrix2x4fv(replayState, true, uniformLoc,
2385 uniformCount, false,
2386 uniformBuffer.data()));
2387 }
2388 break;
2389 case GL_FLOAT_MAT2x3:
2390 for (std::vector<CallCapture> *calls : defaultUniformCalls)
2391 {
2392 Capture(calls, CaptureUniformMatrix2x3fv(replayState, true, uniformLoc,
2393 uniformCount, false,
2394 uniformBuffer.data()));
2395 }
2396 break;
2397 case GL_FLOAT_MAT2:
2398 for (std::vector<CallCapture> *calls : defaultUniformCalls)
2399 {
2400 Capture(calls, CaptureUniformMatrix2fv(replayState, true, uniformLoc,
2401 uniformCount, false,
2402 uniformBuffer.data()));
2403 }
2404 break;
2405 case GL_FLOAT_VEC4:
2406 for (std::vector<CallCapture> *calls : defaultUniformCalls)
2407 {
2408 Capture(calls, CaptureUniform4fv(replayState, true, uniformLoc,
2409 uniformCount, uniformBuffer.data()));
2410 }
2411 break;
2412 case GL_FLOAT_VEC3:
2413 for (std::vector<CallCapture> *calls : defaultUniformCalls)
2414 {
2415 Capture(calls, CaptureUniform3fv(replayState, true, uniformLoc,
2416 uniformCount, uniformBuffer.data()));
2417 }
2418 break;
2419 case GL_FLOAT_VEC2:
2420 for (std::vector<CallCapture> *calls : defaultUniformCalls)
2421 {
2422 Capture(calls, CaptureUniform2fv(replayState, true, uniformLoc,
2423 uniformCount, uniformBuffer.data()));
2424 }
2425 break;
2426 case GL_FLOAT:
2427 for (std::vector<CallCapture> *calls : defaultUniformCalls)
2428 {
2429 Capture(calls, CaptureUniform1fv(replayState, true, uniformLoc,
2430 uniformCount, uniformBuffer.data()));
2431 }
2432 break;
2433 default:
2434 UNIMPLEMENTED();
2435 break;
2436 }
2437 break;
2438 }
2439 case GL_INT:
2440 {
2441 std::vector<GLint> uniformBuffer(uniformSize);
2442 for (int index = 0; index < uniformCount; index++, readLoc.value++)
2443 {
2444 executable.getUniformiv(context, readLoc,
2445 uniformBuffer.data() + index * componentCount);
2446 resourceTracker->setDefaultUniformBaseLocation(program->id(), readLoc,
2447 uniformLoc);
2448 }
2449 switch (componentCount)
2450 {
2451 case 4:
2452 for (std::vector<CallCapture> *calls : defaultUniformCalls)
2453 {
2454 Capture(calls, CaptureUniform4iv(replayState, true, uniformLoc,
2455 uniformCount, uniformBuffer.data()));
2456 }
2457 break;
2458 case 3:
2459 for (std::vector<CallCapture> *calls : defaultUniformCalls)
2460 {
2461 Capture(calls, CaptureUniform3iv(replayState, true, uniformLoc,
2462 uniformCount, uniformBuffer.data()));
2463 }
2464 break;
2465 case 2:
2466 for (std::vector<CallCapture> *calls : defaultUniformCalls)
2467 {
2468 Capture(calls, CaptureUniform2iv(replayState, true, uniformLoc,
2469 uniformCount, uniformBuffer.data()));
2470 }
2471 break;
2472 case 1:
2473 for (std::vector<CallCapture> *calls : defaultUniformCalls)
2474 {
2475 Capture(calls, CaptureUniform1iv(replayState, true, uniformLoc,
2476 uniformCount, uniformBuffer.data()));
2477 }
2478 break;
2479 default:
2480 UNIMPLEMENTED();
2481 break;
2482 }
2483 break;
2484 }
2485 case GL_BOOL:
2486 case GL_UNSIGNED_INT:
2487 {
2488 std::vector<GLuint> uniformBuffer(uniformSize);
2489 for (int index = 0; index < uniformCount; index++, readLoc.value++)
2490 {
2491 executable.getUniformuiv(context, readLoc,
2492 uniformBuffer.data() + index * componentCount);
2493 resourceTracker->setDefaultUniformBaseLocation(program->id(), readLoc,
2494 uniformLoc);
2495 }
2496 switch (componentCount)
2497 {
2498 case 4:
2499 for (std::vector<CallCapture> *calls : defaultUniformCalls)
2500 {
2501 Capture(calls, CaptureUniform4uiv(replayState, true, uniformLoc,
2502 uniformCount, uniformBuffer.data()));
2503 }
2504 break;
2505 case 3:
2506 for (std::vector<CallCapture> *calls : defaultUniformCalls)
2507 {
2508 Capture(calls, CaptureUniform3uiv(replayState, true, uniformLoc,
2509 uniformCount, uniformBuffer.data()));
2510 }
2511 break;
2512 case 2:
2513 for (std::vector<CallCapture> *calls : defaultUniformCalls)
2514 {
2515 Capture(calls, CaptureUniform2uiv(replayState, true, uniformLoc,
2516 uniformCount, uniformBuffer.data()));
2517 }
2518 break;
2519 case 1:
2520 for (std::vector<CallCapture> *calls : defaultUniformCalls)
2521 {
2522 Capture(calls, CaptureUniform1uiv(replayState, true, uniformLoc,
2523 uniformCount, uniformBuffer.data()));
2524 }
2525 break;
2526 default:
2527 UNIMPLEMENTED();
2528 break;
2529 }
2530 break;
2531 }
2532 default:
2533 UNIMPLEMENTED();
2534 break;
2535 }
2536 }
2537 }
2538
CaptureVertexPointerES1(std::vector<CallCapture> * setupCalls,gl::State * replayState,GLuint attribIndex,const gl::VertexAttribute & attrib,const gl::VertexBinding & binding)2539 void CaptureVertexPointerES1(std::vector<CallCapture> *setupCalls,
2540 gl::State *replayState,
2541 GLuint attribIndex,
2542 const gl::VertexAttribute &attrib,
2543 const gl::VertexBinding &binding)
2544 {
2545 switch (gl::GLES1Renderer::VertexArrayType(attribIndex))
2546 {
2547 case gl::ClientVertexArrayType::Vertex:
2548 Capture(setupCalls,
2549 CaptureVertexPointer(*replayState, true, attrib.format->channelCount,
2550 attrib.format->vertexAttribType, binding.getStride(),
2551 attrib.pointer));
2552 break;
2553 case gl::ClientVertexArrayType::Normal:
2554 Capture(setupCalls,
2555 CaptureNormalPointer(*replayState, true, attrib.format->vertexAttribType,
2556 binding.getStride(), attrib.pointer));
2557 break;
2558 case gl::ClientVertexArrayType::Color:
2559 Capture(setupCalls, CaptureColorPointer(*replayState, true, attrib.format->channelCount,
2560 attrib.format->vertexAttribType,
2561 binding.getStride(), attrib.pointer));
2562 break;
2563 case gl::ClientVertexArrayType::PointSize:
2564 Capture(setupCalls,
2565 CapturePointSizePointerOES(*replayState, true, attrib.format->vertexAttribType,
2566 binding.getStride(), attrib.pointer));
2567 break;
2568 case gl::ClientVertexArrayType::TextureCoord:
2569 Capture(setupCalls,
2570 CaptureTexCoordPointer(*replayState, true, attrib.format->channelCount,
2571 attrib.format->vertexAttribType, binding.getStride(),
2572 attrib.pointer));
2573 break;
2574 default:
2575 UNREACHABLE();
2576 }
2577 }
2578
CaptureTextureEnvironmentState(std::vector<CallCapture> * setupCalls,gl::State * replayState,const gl::State * apiState,unsigned int unit)2579 void CaptureTextureEnvironmentState(std::vector<CallCapture> *setupCalls,
2580 gl::State *replayState,
2581 const gl::State *apiState,
2582 unsigned int unit)
2583 {
2584 const gl::TextureEnvironmentParameters ¤tEnv = apiState->gles1().textureEnvironment(unit);
2585 const gl::TextureEnvironmentParameters &defaultEnv =
2586 replayState->gles1().textureEnvironment(unit);
2587
2588 if (currentEnv == defaultEnv)
2589 {
2590 return;
2591 }
2592
2593 auto capIfNe = [setupCalls](auto currentState, auto defaultState, CallCapture &&call) {
2594 if (currentState != defaultState)
2595 {
2596 setupCalls->emplace_back(std::move(call));
2597 }
2598 };
2599
2600 // When the texture env state differs on a non-default sampler unit, emit an ActiveTexture call.
2601 // The default sampler unit is GL_TEXTURE0.
2602 GLenum currentUnit = GL_TEXTURE0 + static_cast<GLenum>(unit);
2603 GLenum defaultUnit = GL_TEXTURE0 + static_cast<GLenum>(replayState->getActiveSampler());
2604 capIfNe(currentUnit, defaultUnit, CaptureActiveTexture(*replayState, true, currentUnit));
2605
2606 auto capEnum = [capIfNe, replayState](gl::TextureEnvParameter pname, auto currentState,
2607 auto defaultState) {
2608 capIfNe(currentState, defaultState,
2609 CaptureTexEnvi(*replayState, true, gl::TextureEnvTarget::Env, pname,
2610 ToGLenum(currentState)));
2611 };
2612
2613 capEnum(gl::TextureEnvParameter::Mode, currentEnv.mode, defaultEnv.mode);
2614
2615 capEnum(gl::TextureEnvParameter::CombineRgb, currentEnv.combineRgb, defaultEnv.combineRgb);
2616 capEnum(gl::TextureEnvParameter::CombineAlpha, currentEnv.combineAlpha,
2617 defaultEnv.combineAlpha);
2618
2619 capEnum(gl::TextureEnvParameter::Src0Rgb, currentEnv.src0Rgb, defaultEnv.src0Rgb);
2620 capEnum(gl::TextureEnvParameter::Src1Rgb, currentEnv.src1Rgb, defaultEnv.src1Rgb);
2621 capEnum(gl::TextureEnvParameter::Src2Rgb, currentEnv.src2Rgb, defaultEnv.src2Rgb);
2622
2623 capEnum(gl::TextureEnvParameter::Src0Alpha, currentEnv.src0Alpha, defaultEnv.src0Alpha);
2624 capEnum(gl::TextureEnvParameter::Src1Alpha, currentEnv.src1Alpha, defaultEnv.src1Alpha);
2625 capEnum(gl::TextureEnvParameter::Src2Alpha, currentEnv.src2Alpha, defaultEnv.src2Alpha);
2626
2627 capEnum(gl::TextureEnvParameter::Op0Rgb, currentEnv.op0Rgb, defaultEnv.op0Rgb);
2628 capEnum(gl::TextureEnvParameter::Op1Rgb, currentEnv.op1Rgb, defaultEnv.op1Rgb);
2629 capEnum(gl::TextureEnvParameter::Op2Rgb, currentEnv.op2Rgb, defaultEnv.op2Rgb);
2630
2631 capEnum(gl::TextureEnvParameter::Op0Alpha, currentEnv.op0Alpha, defaultEnv.op0Alpha);
2632 capEnum(gl::TextureEnvParameter::Op1Alpha, currentEnv.op1Alpha, defaultEnv.op1Alpha);
2633 capEnum(gl::TextureEnvParameter::Op2Alpha, currentEnv.op2Alpha, defaultEnv.op2Alpha);
2634
2635 auto capFloat = [capIfNe, replayState](gl::TextureEnvParameter pname, auto currentState,
2636 auto defaultState) {
2637 capIfNe(currentState, defaultState,
2638 CaptureTexEnvf(*replayState, true, gl::TextureEnvTarget::Env, pname, currentState));
2639 };
2640
2641 capFloat(gl::TextureEnvParameter::RgbScale, currentEnv.rgbScale, defaultEnv.rgbScale);
2642 capFloat(gl::TextureEnvParameter::AlphaScale, currentEnv.alphaScale, defaultEnv.alphaScale);
2643
2644 capIfNe(currentEnv.color, defaultEnv.color,
2645 CaptureTexEnvfv(*replayState, true, gl::TextureEnvTarget::Env,
2646 gl::TextureEnvParameter::Color, currentEnv.color.data()));
2647
2648 // PointCoordReplace is the only parameter that uses the PointSprite TextureEnvTarget.
2649 capIfNe(currentEnv.pointSpriteCoordReplace, defaultEnv.pointSpriteCoordReplace,
2650 CaptureTexEnvi(*replayState, true, gl::TextureEnvTarget::PointSprite,
2651 gl::TextureEnvParameter::PointCoordReplace,
2652 currentEnv.pointSpriteCoordReplace));
2653
2654 // In case of non-default sampler units, the default unit must be set back here.
2655 capIfNe(currentUnit, defaultUnit, CaptureActiveTexture(*replayState, true, defaultUnit));
2656 }
2657
VertexBindingMatchesAttribStride(const gl::VertexAttribute & attrib,const gl::VertexBinding & binding)2658 bool VertexBindingMatchesAttribStride(const gl::VertexAttribute &attrib,
2659 const gl::VertexBinding &binding)
2660 {
2661 if (attrib.vertexAttribArrayStride == 0 &&
2662 binding.getStride() == ComputeVertexAttributeTypeSize(attrib))
2663 {
2664 return true;
2665 }
2666
2667 return attrib.vertexAttribArrayStride == binding.getStride();
2668 }
2669
CaptureVertexArrayState(std::vector<CallCapture> * setupCalls,const gl::Context * context,const gl::VertexArray * vertexArray,gl::State * replayState)2670 void CaptureVertexArrayState(std::vector<CallCapture> *setupCalls,
2671 const gl::Context *context,
2672 const gl::VertexArray *vertexArray,
2673 gl::State *replayState)
2674 {
2675 const std::vector<gl::VertexAttribute> &vertexAttribs = vertexArray->getVertexAttributes();
2676 const std::vector<gl::VertexBinding> &vertexBindings = vertexArray->getVertexBindings();
2677
2678 gl::AttributesMask vertexPointerBindings;
2679
2680 ASSERT(vertexAttribs.size() <= vertexBindings.size());
2681 for (GLuint attribIndex = 0; attribIndex < vertexAttribs.size(); ++attribIndex)
2682 {
2683 const gl::VertexAttribute defaultAttrib(attribIndex);
2684 const gl::VertexBinding defaultBinding;
2685
2686 const gl::VertexAttribute &attrib = vertexAttribs[attribIndex];
2687 const gl::VertexBinding &binding = vertexBindings[attrib.bindingIndex];
2688
2689 if (attrib.enabled != defaultAttrib.enabled)
2690 {
2691 if (context->isGLES1())
2692 {
2693 Capture(setupCalls,
2694 CaptureEnableClientState(*replayState, false,
2695 gl::GLES1Renderer::VertexArrayType(attribIndex)));
2696 }
2697 else
2698 {
2699 Capture(setupCalls,
2700 CaptureEnableVertexAttribArray(*replayState, false, attribIndex));
2701 }
2702 }
2703
2704 // Don't capture CaptureVertexAttribPointer calls when a non-default VAO is bound, the array
2705 // buffer is null and a non-null attrib pointer is used.
2706 bool skipInvalidAttrib = vertexArray->id().value != 0 &&
2707 binding.getBuffer().get() == nullptr && attrib.pointer != nullptr;
2708
2709 if (!skipInvalidAttrib &&
2710 (attrib.format != defaultAttrib.format || attrib.pointer != defaultAttrib.pointer ||
2711 binding.getStride() != defaultBinding.getStride() ||
2712 attrib.bindingIndex != defaultAttrib.bindingIndex ||
2713 binding.getBuffer().get() != nullptr))
2714 {
2715 // Each attribute can pull from a separate buffer, so check the binding
2716 gl::Buffer *buffer = binding.getBuffer().get();
2717 if (buffer != replayState->getArrayBuffer())
2718 {
2719 replayState->setBufferBinding(context, gl::BufferBinding::Array, buffer);
2720
2721 gl::BufferID bufferID = {0};
2722 if (buffer)
2723 {
2724 bufferID = buffer->id();
2725 }
2726 Capture(setupCalls,
2727 CaptureBindBuffer(*replayState, true, gl::BufferBinding::Array, bufferID));
2728 }
2729
2730 // Establish the relationship between currently bound buffer and the VAO
2731 if (context->isGLES1())
2732 {
2733 // Track indexes that used ES1 calls
2734 vertexPointerBindings.set(attribIndex);
2735
2736 CaptureVertexPointerES1(setupCalls, replayState, attribIndex, attrib, binding);
2737 }
2738 else if (attrib.bindingIndex == attribIndex &&
2739 VertexBindingMatchesAttribStride(attrib, binding) &&
2740 (!buffer || binding.getOffset() == reinterpret_cast<GLintptr>(attrib.pointer)))
2741 {
2742 // Check if we can use strictly ES2 semantics, and track indexes that do.
2743 vertexPointerBindings.set(attribIndex);
2744
2745 if (attrib.format->isPureInt())
2746 {
2747 Capture(setupCalls, CaptureVertexAttribIPointer(*replayState, true, attribIndex,
2748 attrib.format->channelCount,
2749 attrib.format->vertexAttribType,
2750 attrib.vertexAttribArrayStride,
2751 attrib.pointer));
2752 }
2753 else
2754 {
2755 Capture(setupCalls,
2756 CaptureVertexAttribPointer(
2757 *replayState, true, attribIndex, attrib.format->channelCount,
2758 attrib.format->vertexAttribType, attrib.format->isNorm(),
2759 attrib.vertexAttribArrayStride, attrib.pointer));
2760 }
2761
2762 if (binding.getDivisor() != 0)
2763 {
2764 Capture(setupCalls, CaptureVertexAttribDivisor(*replayState, true, attribIndex,
2765 binding.getDivisor()));
2766 }
2767 }
2768 else
2769 {
2770 ASSERT(context->getClientVersion() >= gl::ES_3_1);
2771
2772 if (attrib.format->isPureInt())
2773 {
2774 Capture(setupCalls, CaptureVertexAttribIFormat(*replayState, true, attribIndex,
2775 attrib.format->channelCount,
2776 attrib.format->vertexAttribType,
2777 attrib.relativeOffset));
2778 }
2779 else
2780 {
2781 Capture(setupCalls, CaptureVertexAttribFormat(*replayState, true, attribIndex,
2782 attrib.format->channelCount,
2783 attrib.format->vertexAttribType,
2784 attrib.format->isNorm(),
2785 attrib.relativeOffset));
2786 }
2787
2788 Capture(setupCalls, CaptureVertexAttribBinding(*replayState, true, attribIndex,
2789 attrib.bindingIndex));
2790 }
2791 }
2792 }
2793
2794 // The loop below expects attribs and bindings to have equal counts
2795 static_assert(gl::MAX_VERTEX_ATTRIBS == gl::MAX_VERTEX_ATTRIB_BINDINGS,
2796 "Max vertex attribs and bindings count mismatch");
2797
2798 // Loop through binding indices that weren't used by VertexAttribPointer
2799 for (size_t bindingIndex : vertexPointerBindings.flip())
2800 {
2801 const gl::VertexBinding &binding = vertexBindings[bindingIndex];
2802
2803 if (binding.getBuffer().id().value != 0)
2804 {
2805 Capture(setupCalls,
2806 CaptureBindVertexBuffer(*replayState, true, static_cast<GLuint>(bindingIndex),
2807 binding.getBuffer().id(), binding.getOffset(),
2808 binding.getStride()));
2809 }
2810
2811 if (binding.getDivisor() != 0)
2812 {
2813 Capture(setupCalls, CaptureVertexBindingDivisor(*replayState, true,
2814 static_cast<GLuint>(bindingIndex),
2815 binding.getDivisor()));
2816 }
2817 }
2818
2819 // The element array buffer is not per attribute, but per VAO
2820 gl::Buffer *elementArrayBuffer = vertexArray->getElementArrayBuffer();
2821 if (elementArrayBuffer)
2822 {
2823 Capture(setupCalls, CaptureBindBuffer(*replayState, true, gl::BufferBinding::ElementArray,
2824 elementArrayBuffer->id()));
2825 }
2826 }
2827
CaptureTextureStorage(std::vector<CallCapture> * setupCalls,gl::State * replayState,const gl::Texture * texture)2828 void CaptureTextureStorage(std::vector<CallCapture> *setupCalls,
2829 gl::State *replayState,
2830 const gl::Texture *texture)
2831 {
2832 // Use mip-level 0 for the base dimensions
2833 gl::ImageIndex imageIndex = gl::ImageIndex::MakeFromType(texture->getType(), 0);
2834 const gl::ImageDesc &desc = texture->getTextureState().getImageDesc(imageIndex);
2835
2836 switch (texture->getType())
2837 {
2838 case gl::TextureType::_2D:
2839 case gl::TextureType::CubeMap:
2840 {
2841 Capture(setupCalls, CaptureTexStorage2D(*replayState, true, texture->getType(),
2842 texture->getImmutableLevels(),
2843 desc.format.info->internalFormat,
2844 desc.size.width, desc.size.height));
2845 break;
2846 }
2847 case gl::TextureType::_3D:
2848 case gl::TextureType::_2DArray:
2849 case gl::TextureType::CubeMapArray:
2850 {
2851 Capture(setupCalls, CaptureTexStorage3D(
2852 *replayState, true, texture->getType(),
2853 texture->getImmutableLevels(), desc.format.info->internalFormat,
2854 desc.size.width, desc.size.height, desc.size.depth));
2855 break;
2856 }
2857 case gl::TextureType::Buffer:
2858 {
2859 // Do nothing. This will already be captured as a buffer.
2860 break;
2861 }
2862 default:
2863 UNIMPLEMENTED();
2864 break;
2865 }
2866 }
2867
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)2868 void CaptureTextureContents(std::vector<CallCapture> *setupCalls,
2869 gl::State *replayState,
2870 const gl::Texture *texture,
2871 const gl::ImageIndex &index,
2872 const gl::ImageDesc &desc,
2873 GLuint size,
2874 const void *data)
2875 {
2876 const gl::InternalFormat &format = *desc.format.info;
2877
2878 if (index.getType() == gl::TextureType::Buffer)
2879 {
2880 // Zero binding size indicates full buffer bound
2881 if (texture->getBuffer().getSize() == 0)
2882 {
2883 Capture(setupCalls,
2884 CaptureTexBufferEXT(*replayState, true, index.getType(), format.internalFormat,
2885 texture->getBuffer().get()->id()));
2886 }
2887 else
2888 {
2889 Capture(setupCalls, CaptureTexBufferRangeEXT(*replayState, true, index.getType(),
2890 format.internalFormat,
2891 texture->getBuffer().get()->id(),
2892 texture->getBuffer().getOffset(),
2893 texture->getBuffer().getSize()));
2894 }
2895
2896 // For buffers, we're done
2897 return;
2898 }
2899
2900 bool is3D =
2901 (index.getType() == gl::TextureType::_3D || index.getType() == gl::TextureType::_2DArray ||
2902 index.getType() == gl::TextureType::CubeMapArray);
2903
2904 if (format.compressed || format.paletted)
2905 {
2906 if (is3D)
2907 {
2908 if (texture->getImmutableFormat())
2909 {
2910 Capture(setupCalls,
2911 CaptureCompressedTexSubImage3D(
2912 *replayState, true, index.getTarget(), index.getLevelIndex(), 0, 0, 0,
2913 desc.size.width, desc.size.height, desc.size.depth,
2914 format.internalFormat, size, data));
2915 }
2916 else
2917 {
2918 Capture(setupCalls,
2919 CaptureCompressedTexImage3D(*replayState, true, index.getTarget(),
2920 index.getLevelIndex(), format.internalFormat,
2921 desc.size.width, desc.size.height,
2922 desc.size.depth, 0, size, data));
2923 }
2924 }
2925 else
2926 {
2927 if (texture->getImmutableFormat())
2928 {
2929 Capture(setupCalls,
2930 CaptureCompressedTexSubImage2D(
2931 *replayState, true, index.getTarget(), index.getLevelIndex(), 0, 0,
2932 desc.size.width, desc.size.height, format.internalFormat, size, data));
2933 }
2934 else
2935 {
2936 Capture(setupCalls, CaptureCompressedTexImage2D(
2937 *replayState, true, index.getTarget(),
2938 index.getLevelIndex(), format.internalFormat,
2939 desc.size.width, desc.size.height, 0, size, data));
2940 }
2941 }
2942 }
2943 else
2944 {
2945 if (is3D)
2946 {
2947 if (texture->getImmutableFormat())
2948 {
2949 Capture(setupCalls,
2950 CaptureTexSubImage3D(*replayState, true, index.getTarget(),
2951 index.getLevelIndex(), 0, 0, 0, desc.size.width,
2952 desc.size.height, desc.size.depth, format.format,
2953 format.type, data));
2954 }
2955 else
2956 {
2957 Capture(
2958 setupCalls,
2959 CaptureTexImage3D(*replayState, true, index.getTarget(), index.getLevelIndex(),
2960 format.internalFormat, desc.size.width, desc.size.height,
2961 desc.size.depth, 0, format.format, format.type, data));
2962 }
2963 }
2964 else
2965 {
2966 if (texture->getImmutableFormat())
2967 {
2968 Capture(setupCalls,
2969 CaptureTexSubImage2D(*replayState, true, index.getTarget(),
2970 index.getLevelIndex(), 0, 0, desc.size.width,
2971 desc.size.height, format.format, format.type, data));
2972 }
2973 else
2974 {
2975 Capture(setupCalls, CaptureTexImage2D(*replayState, true, index.getTarget(),
2976 index.getLevelIndex(), format.internalFormat,
2977 desc.size.width, desc.size.height, 0,
2978 format.format, format.type, data));
2979 }
2980 }
2981 }
2982 }
2983
CaptureCustomUniformBlockBinding(const CallCapture & callIn,std::vector<CallCapture> & callsOut)2984 void CaptureCustomUniformBlockBinding(const CallCapture &callIn, std::vector<CallCapture> &callsOut)
2985 {
2986 const ParamBuffer ¶msIn = callIn.params;
2987
2988 const ParamCapture &programID =
2989 paramsIn.getParam("programPacked", ParamType::TShaderProgramID, 0);
2990 const ParamCapture &blockIndex =
2991 paramsIn.getParam("uniformBlockIndexPacked", ParamType::TUniformBlockIndex, 1);
2992 const ParamCapture &blockBinding =
2993 paramsIn.getParam("uniformBlockBinding", ParamType::TGLuint, 2);
2994
2995 ParamBuffer params;
2996 params.addValueParam("program", ParamType::TGLuint, programID.value.ShaderProgramIDVal.value);
2997 params.addValueParam("uniformBlockIndex", ParamType::TGLuint,
2998 blockIndex.value.UniformBlockIndexVal.value);
2999 params.addValueParam("uniformBlockBinding", ParamType::TGLuint, blockBinding.value.GLuintVal);
3000
3001 callsOut.emplace_back("UniformBlockBinding", std::move(params));
3002 }
3003
CaptureCustomMapBuffer(const char * entryPointName,CallCapture & call,std::vector<CallCapture> & callsOut,gl::BufferID mappedBufferID)3004 void CaptureCustomMapBuffer(const char *entryPointName,
3005 CallCapture &call,
3006 std::vector<CallCapture> &callsOut,
3007 gl::BufferID mappedBufferID)
3008 {
3009 call.params.addValueParam("buffer", ParamType::TGLuint, mappedBufferID.value);
3010 callsOut.emplace_back(entryPointName, std::move(call.params));
3011 }
3012
CaptureCustomShaderProgram(const char * name,CallCapture & call,std::vector<CallCapture> & callsOut)3013 void CaptureCustomShaderProgram(const char *name,
3014 CallCapture &call,
3015 std::vector<CallCapture> &callsOut)
3016 {
3017 call.params.addValueParam("shaderProgram", ParamType::TGLuint,
3018 call.params.getReturnValue().value.GLuintVal);
3019 call.customFunctionName = name;
3020 callsOut.emplace_back(std::move(call));
3021 }
3022
CaptureCustomFenceSync(CallCapture & call,std::vector<CallCapture> & callsOut)3023 void CaptureCustomFenceSync(CallCapture &call, std::vector<CallCapture> &callsOut)
3024 {
3025 ParamBuffer &¶ms = std::move(call.params);
3026 params.addValueParam("fenceSync", ParamType::TGLuint64,
3027 params.getReturnValue().value.GLuint64Val);
3028 call.customFunctionName = "FenceSync2";
3029 call.isSyncPoint = true;
3030 callsOut.emplace_back(std::move(call));
3031 }
3032
GetImageFromParam(const gl::Context * context,const ParamCapture & param)3033 const egl::Image *GetImageFromParam(const gl::Context *context, const ParamCapture ¶m)
3034 {
3035 const egl::ImageID eglImageID = egl::PackParam<egl::ImageID>(param.value.EGLImageVal);
3036 const egl::Image *eglImage = context->getDisplay()->getImage(eglImageID);
3037 ASSERT(eglImage != nullptr);
3038 return eglImage;
3039 }
3040
CaptureCustomCreateEGLImage(const gl::Context * context,const char * name,size_t width,size_t height,CallCapture & call,std::vector<CallCapture> & callsOut)3041 void CaptureCustomCreateEGLImage(const gl::Context *context,
3042 const char *name,
3043 size_t width,
3044 size_t height,
3045 CallCapture &call,
3046 std::vector<CallCapture> &callsOut)
3047 {
3048 ParamBuffer &¶ms = std::move(call.params);
3049 EGLImage returnVal = params.getReturnValue().value.EGLImageVal;
3050 egl::ImageID imageID = egl::PackParam<egl::ImageID>(returnVal);
3051 call.customFunctionName = name;
3052
3053 // Clear client buffer value if it is a pointer to a hardware buffer. It is
3054 // not used by replay and will not be portable to 32-bit builds
3055 if (params.getParam("target", ParamType::TEGLenum, 2).value.EGLenumVal ==
3056 EGL_NATIVE_BUFFER_ANDROID)
3057 {
3058 params.setValueParamAtIndex("buffer", ParamType::TEGLClientBuffer,
3059 reinterpret_cast<EGLClientBuffer>(static_cast<uintptr_t>(0)),
3060 3);
3061 }
3062
3063 // Record image dimensions in case a backing resource needs to be created during replay
3064 params.addValueParam("width", ParamType::TGLsizei, static_cast<GLsizei>(width));
3065 params.addValueParam("height", ParamType::TGLsizei, static_cast<GLsizei>(height));
3066
3067 params.addValueParam("image", ParamType::TGLuint, imageID.value);
3068 callsOut.emplace_back(std::move(call));
3069 }
3070
CaptureCustomDestroyEGLImage(const char * name,CallCapture & call,std::vector<CallCapture> & callsOut)3071 void CaptureCustomDestroyEGLImage(const char *name,
3072 CallCapture &call,
3073 std::vector<CallCapture> &callsOut)
3074 {
3075 call.customFunctionName = name;
3076 ParamBuffer &¶ms = std::move(call.params);
3077
3078 const ParamCapture &imageID = params.getParam("imagePacked", ParamType::TImageID, 1);
3079 params.addValueParam("imageID", ParamType::TGLuint, imageID.value.ImageIDVal.value);
3080
3081 callsOut.emplace_back(std::move(call));
3082 }
3083
CaptureCustomCreateEGLSync(const char * name,CallCapture & call,std::vector<CallCapture> & callsOut)3084 void CaptureCustomCreateEGLSync(const char *name,
3085 CallCapture &call,
3086 std::vector<CallCapture> &callsOut)
3087 {
3088 ParamBuffer &¶ms = std::move(call.params);
3089 EGLSync returnVal = params.getReturnValue().value.EGLSyncVal;
3090 egl::SyncID syncID = egl::PackParam<egl::SyncID>(returnVal);
3091 params.addValueParam("sync", ParamType::TGLuint, syncID.value);
3092 call.customFunctionName = name;
3093 callsOut.emplace_back(std::move(call));
3094 }
3095
CaptureCustomCreatePbufferSurface(CallCapture & call,std::vector<CallCapture> & callsOut)3096 void CaptureCustomCreatePbufferSurface(CallCapture &call, std::vector<CallCapture> &callsOut)
3097 {
3098 ParamBuffer &¶ms = std::move(call.params);
3099 EGLSurface returnVal = params.getReturnValue().value.EGLSurfaceVal;
3100 egl::SurfaceID surfaceID = egl::PackParam<egl::SurfaceID>(returnVal);
3101
3102 params.addValueParam("surface", ParamType::TGLuint, surfaceID.value);
3103 call.customFunctionName = "CreatePbufferSurface";
3104 callsOut.emplace_back(std::move(call));
3105 }
3106
CaptureCustomCreateNativeClientbuffer(CallCapture & call,std::vector<CallCapture> & callsOut)3107 void CaptureCustomCreateNativeClientbuffer(CallCapture &call, std::vector<CallCapture> &callsOut)
3108 {
3109 ParamBuffer &¶ms = std::move(call.params);
3110 params.addValueParam("clientBuffer", ParamType::TEGLClientBuffer,
3111 params.getReturnValue().value.EGLClientBufferVal);
3112 call.customFunctionName = "CreateNativeClientBufferANDROID";
3113 callsOut.emplace_back(std::move(call));
3114 }
3115
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)3116 void GenerateLinkedProgram(const gl::Context *context,
3117 const gl::State &replayState,
3118 ResourceTracker *resourceTracker,
3119 std::vector<CallCapture> *setupCalls,
3120 gl::Program *program,
3121 gl::ShaderProgramID id,
3122 gl::ShaderProgramID tempIDStart,
3123 const ProgramSources &linkedSources)
3124 {
3125 // A map to store the gShaderProgram map lookup index of the temp shaders we attached below. We
3126 // need this map to retrieve the lookup index to pass to CaptureDetachShader calls at the end of
3127 // GenerateLinkedProgram.
3128 PackedEnumMap<gl::ShaderType, gl::ShaderProgramID> tempShaderIDTracker;
3129
3130 const gl::ProgramExecutable &executable = program->getExecutable();
3131
3132 // Compile with last linked sources.
3133 for (gl::ShaderType shaderType : executable.getLinkedShaderStages())
3134 {
3135 // Bump the max shader program id for each new tempIDStart we use to create, compile, and
3136 // attach the temp shader object.
3137 resourceTracker->onShaderProgramAccess(tempIDStart);
3138 // Store the tempIDStart in the tempShaderIDTracker to retrieve for CaptureDetachShader
3139 // calls later.
3140 tempShaderIDTracker[shaderType] = tempIDStart;
3141 const std::string &sourceString = linkedSources[shaderType];
3142 const char *sourcePointer = sourceString.c_str();
3143
3144 if (sourceString.empty())
3145 {
3146 // If we don't have source for this shader, that means it was populated by the app
3147 // using glProgramBinary. We need to look it up from our cached copy.
3148 const ProgramSources &cachedLinkedSources =
3149 context->getShareGroup()->getFrameCaptureShared()->getProgramSources(id);
3150
3151 const std::string &cachedSourceString = cachedLinkedSources[shaderType];
3152 sourcePointer = cachedSourceString.c_str();
3153 ASSERT(!cachedSourceString.empty());
3154 }
3155
3156 // Compile and attach the temporary shader. Then free it immediately.
3157 CallCapture createShader =
3158 CaptureCreateShader(replayState, true, shaderType, tempIDStart.value);
3159 CaptureCustomShaderProgram("CreateShader", createShader, *setupCalls);
3160 Capture(setupCalls,
3161 CaptureShaderSource(replayState, true, tempIDStart, 1, &sourcePointer, nullptr));
3162 Capture(setupCalls, CaptureCompileShader(replayState, true, tempIDStart));
3163 Capture(setupCalls, CaptureAttachShader(replayState, true, id, tempIDStart));
3164 // Increment tempIDStart to get a new gShaderProgram map index for the next linked stage
3165 // shader object. We can't reuse the same tempIDStart as we need to retrieve the index of
3166 // each attached shader object later to pass to CaptureDetachShader calls.
3167 tempIDStart.value += 1;
3168 }
3169
3170 // Gather XFB varyings
3171 std::vector<std::string> xfbVaryings;
3172 for (const gl::TransformFeedbackVarying &xfbVarying :
3173 executable.getLinkedTransformFeedbackVaryings())
3174 {
3175 xfbVaryings.push_back(xfbVarying.nameWithArrayIndex());
3176 }
3177
3178 if (!xfbVaryings.empty())
3179 {
3180 std::vector<const char *> varyingsStrings;
3181 for (const std::string &varyingString : xfbVaryings)
3182 {
3183 varyingsStrings.push_back(varyingString.data());
3184 }
3185
3186 GLenum xfbMode = executable.getTransformFeedbackBufferMode();
3187 Capture(setupCalls, CaptureTransformFeedbackVaryings(replayState, true, id,
3188 static_cast<GLint>(xfbVaryings.size()),
3189 varyingsStrings.data(), xfbMode));
3190 }
3191
3192 // Force the attributes to be bound the same way as in the existing program.
3193 // This can affect attributes that are optimized out in some implementations.
3194 for (const gl::ProgramInput &attrib : executable.getProgramInputs())
3195 {
3196 if (gl::IsBuiltInName(attrib.name))
3197 {
3198 // Don't try to bind built-in attributes
3199 continue;
3200 }
3201
3202 // Separable programs may not have a VS, meaning it may not have attributes.
3203 if (executable.hasLinkedShaderStage(gl::ShaderType::Vertex))
3204 {
3205 ASSERT(attrib.getLocation() != -1);
3206 Capture(setupCalls, CaptureBindAttribLocation(replayState, true, id,
3207 static_cast<GLuint>(attrib.getLocation()),
3208 attrib.name.c_str()));
3209 }
3210 }
3211
3212 if (program->isSeparable())
3213 {
3214 // MEC manually recreates separable programs, rather than attempting to recreate a call
3215 // to glCreateShaderProgramv(), so insert a call to mark it separable.
3216 Capture(setupCalls,
3217 CaptureProgramParameteri(replayState, true, id, GL_PROGRAM_SEPARABLE, GL_TRUE));
3218 }
3219
3220 Capture(setupCalls, CaptureLinkProgram(replayState, true, id));
3221 CaptureUpdateUniformLocations(program, setupCalls);
3222 CaptureUpdateUniformValues(replayState, context, program, resourceTracker, setupCalls);
3223 CaptureUpdateUniformBlockIndexes(program, setupCalls);
3224
3225 // Capture uniform block bindings for each program
3226 for (uint32_t uniformBlockIndex = 0;
3227 uniformBlockIndex < static_cast<uint32_t>(executable.getUniformBlocks().size());
3228 uniformBlockIndex++)
3229 {
3230 GLuint blockBinding = executable.getUniformBlocks()[uniformBlockIndex].pod.inShaderBinding;
3231 CallCapture updateCallCapture =
3232 CaptureUniformBlockBinding(replayState, true, id, {uniformBlockIndex}, blockBinding);
3233 CaptureCustomUniformBlockBinding(updateCallCapture, *setupCalls);
3234 }
3235
3236 // Add DetachShader call if that's what the app does, so that the
3237 // ResourceManagerBase::mHandleAllocator can release the ShaderProgramID handle assigned to the
3238 // shader object when glDeleteShader is called. This ensures the ShaderProgramID handles used in
3239 // SetupReplayContextShared() are consistent with the ShaderProgramID handles used by the app.
3240 for (gl::ShaderType shaderType : executable.getLinkedShaderStages())
3241 {
3242 gl::Shader *attachedShader = program->getAttachedShader(shaderType);
3243 if (attachedShader == nullptr)
3244 {
3245 Capture(setupCalls,
3246 CaptureDetachShader(replayState, true, id, tempShaderIDTracker[shaderType]));
3247 }
3248 Capture(setupCalls,
3249 CaptureDeleteShader(replayState, true, tempShaderIDTracker[shaderType]));
3250 }
3251 }
3252
3253 // TODO(http://anglebug.com/42263204): Improve reset/restore call generation
3254 // There are multiple ways to track reset calls for individual resources. For now, we are tracking
3255 // separate lists of instructions that mirror the calls created during mid-execution setup. Other
3256 // methods could involve passing the original CallCaptures to this function, or tracking the
3257 // indices of original setup calls.
CaptureBufferResetCalls(const gl::Context * context,const gl::State & replayState,ResourceTracker * resourceTracker,gl::BufferID * id,const gl::Buffer * buffer)3258 void CaptureBufferResetCalls(const gl::Context *context,
3259 const gl::State &replayState,
3260 ResourceTracker *resourceTracker,
3261 gl::BufferID *id,
3262 const gl::Buffer *buffer)
3263 {
3264 GLuint bufferID = (*id).value;
3265
3266 // Track this as a starting resource that may need to be restored.
3267 TrackedResource &trackedBuffers =
3268 resourceTracker->getTrackedResource(context->id(), ResourceIDType::Buffer);
3269
3270 // Track calls to regenerate a given buffer
3271 ResourceCalls &bufferRegenCalls = trackedBuffers.getResourceRegenCalls();
3272 Capture(&bufferRegenCalls[bufferID], CaptureGenBuffers(replayState, true, 1, id));
3273 MaybeCaptureUpdateResourceIDs(context, resourceTracker, &bufferRegenCalls[bufferID]);
3274
3275 // Call glBufferStorageEXT when regenerating immutable buffers,
3276 // as we can't call glBufferData on restore.
3277 if (buffer->isImmutable())
3278 {
3279 Capture(&bufferRegenCalls[bufferID],
3280 CaptureBindBuffer(replayState, true, gl::BufferBinding::Array, *id));
3281 Capture(
3282 &bufferRegenCalls[bufferID],
3283 CaptureBufferStorageEXT(replayState, true, gl::BufferBinding::Array,
3284 static_cast<GLsizeiptr>(buffer->getSize()),
3285 buffer->getMapPointer(), buffer->getStorageExtUsageFlags()));
3286 }
3287
3288 // Track calls to restore a given buffer's contents
3289 ResourceCalls &bufferRestoreCalls = trackedBuffers.getResourceRestoreCalls();
3290 Capture(&bufferRestoreCalls[bufferID],
3291 CaptureBindBuffer(replayState, true, gl::BufferBinding::Array, *id));
3292
3293 // Mutable buffers will be restored here using glBufferData.
3294 // Immutable buffers need to be restored below, after maping.
3295 if (!buffer->isImmutable())
3296 {
3297 Capture(&bufferRestoreCalls[bufferID],
3298 CaptureBufferData(replayState, true, gl::BufferBinding::Array,
3299 static_cast<GLsizeiptr>(buffer->getSize()),
3300 buffer->getMapPointer(), buffer->getUsage()));
3301 }
3302
3303 if (buffer->isMapped())
3304 {
3305 // Track calls to remap a buffer that started as mapped
3306 BufferCalls &bufferMapCalls = resourceTracker->getBufferMapCalls();
3307
3308 Capture(&bufferMapCalls[bufferID],
3309 CaptureBindBuffer(replayState, true, gl::BufferBinding::Array, *id));
3310
3311 void *dontCare = nullptr;
3312 CallCapture mapBufferRange = CaptureMapBufferRange(
3313 replayState, true, gl::BufferBinding::Array,
3314 static_cast<GLsizeiptr>(buffer->getMapOffset()),
3315 static_cast<GLsizeiptr>(buffer->getMapLength()), buffer->getAccessFlags(), dontCare);
3316 CaptureCustomMapBuffer("MapBufferRange", mapBufferRange, bufferMapCalls[bufferID],
3317 buffer->id());
3318
3319 // Restore immutable mapped buffers. Needs to happen after mapping.
3320 if (buffer->isImmutable())
3321 {
3322 ParamBuffer dataParamBuffer;
3323 dataParamBuffer.addValueParam("dest", ParamType::TGLuint, buffer->id().value);
3324 ParamCapture captureData("source", ParamType::TvoidConstPointer);
3325 CaptureMemory(buffer->getMapPointer(), static_cast<GLsizeiptr>(buffer->getSize()),
3326 &captureData);
3327 dataParamBuffer.addParam(std::move(captureData));
3328 dataParamBuffer.addValueParam<GLsizeiptr>("size", ParamType::TGLsizeiptr,
3329 static_cast<GLsizeiptr>(buffer->getSize()));
3330 bufferMapCalls[bufferID].emplace_back("UpdateClientBufferData",
3331 std::move(dataParamBuffer));
3332 }
3333 }
3334
3335 // Track calls unmap a buffer that started as unmapped
3336 BufferCalls &bufferUnmapCalls = resourceTracker->getBufferUnmapCalls();
3337 Capture(&bufferUnmapCalls[bufferID],
3338 CaptureBindBuffer(replayState, true, gl::BufferBinding::Array, *id));
3339 Capture(&bufferUnmapCalls[bufferID],
3340 CaptureUnmapBuffer(replayState, true, gl::BufferBinding::Array, GL_TRUE));
3341 }
3342
CaptureFenceSyncResetCalls(const gl::Context * context,const gl::State & replayState,ResourceTracker * resourceTracker,gl::SyncID syncID,GLsync syncObject,const gl::Sync * sync)3343 void CaptureFenceSyncResetCalls(const gl::Context *context,
3344 const gl::State &replayState,
3345 ResourceTracker *resourceTracker,
3346 gl::SyncID syncID,
3347 GLsync syncObject,
3348 const gl::Sync *sync)
3349 {
3350 // Track calls to regenerate a given fence sync
3351 FenceSyncCalls &fenceSyncRegenCalls = resourceTracker->getFenceSyncRegenCalls();
3352 CallCapture fenceSync =
3353 CaptureFenceSync(replayState, true, sync->getCondition(), sync->getFlags(), syncObject);
3354 CaptureCustomFenceSync(fenceSync, fenceSyncRegenCalls[syncID]);
3355 MaybeCaptureUpdateResourceIDs(context, resourceTracker, &fenceSyncRegenCalls[syncID]);
3356 }
3357
CaptureEGLSyncResetCalls(const gl::Context * context,const gl::State & replayState,ResourceTracker * resourceTracker,egl::SyncID eglSyncID,EGLSync eglSyncObject,const egl::Sync * eglSync)3358 void CaptureEGLSyncResetCalls(const gl::Context *context,
3359 const gl::State &replayState,
3360 ResourceTracker *resourceTracker,
3361 egl::SyncID eglSyncID,
3362 EGLSync eglSyncObject,
3363 const egl::Sync *eglSync)
3364 {
3365 // Track this as a starting resource that may need to be restored.
3366 TrackedResource &trackedEGLSyncs =
3367 resourceTracker->getTrackedResource(context->id(), ResourceIDType::egl_Sync);
3368
3369 // Track calls to regenerate a given buffer
3370 ResourceCalls &eglSyncRegenCalls = trackedEGLSyncs.getResourceRegenCalls();
3371
3372 CallCapture createEGLSync =
3373 CaptureCreateSyncKHR(nullptr, true, context->getDisplay(), eglSync->getType(),
3374 eglSync->getAttributeMap(), eglSyncObject);
3375 CaptureCustomCreateEGLSync("CreateEGLSyncKHR", createEGLSync,
3376 eglSyncRegenCalls[eglSyncID.value]);
3377 MaybeCaptureUpdateResourceIDs(context, resourceTracker, &eglSyncRegenCalls[eglSyncID.value]);
3378 }
3379
CaptureBufferBindingResetCalls(const gl::State & replayState,ResourceTracker * resourceTracker,gl::BufferBinding binding,gl::BufferID id)3380 void CaptureBufferBindingResetCalls(const gl::State &replayState,
3381 ResourceTracker *resourceTracker,
3382 gl::BufferBinding binding,
3383 gl::BufferID id)
3384 {
3385 // Track the calls to reset it
3386 std::vector<CallCapture> &bufferBindingCalls = resourceTracker->getBufferBindingCalls();
3387 Capture(&bufferBindingCalls, CaptureBindBuffer(replayState, true, binding, id));
3388 }
3389
CaptureIndexedBuffers(const gl::State & glState,const gl::BufferVector & indexedBuffers,gl::BufferBinding binding,std::vector<CallCapture> * setupCalls)3390 void CaptureIndexedBuffers(const gl::State &glState,
3391 const gl::BufferVector &indexedBuffers,
3392 gl::BufferBinding binding,
3393 std::vector<CallCapture> *setupCalls)
3394 {
3395 for (unsigned int index = 0; index < indexedBuffers.size(); ++index)
3396 {
3397 const gl::OffsetBindingPointer<gl::Buffer> &buffer = indexedBuffers[index];
3398
3399 if (buffer.get() == nullptr)
3400 {
3401 continue;
3402 }
3403
3404 GLintptr offset = buffer.getOffset();
3405 GLsizeiptr size = buffer.getSize();
3406 gl::BufferID bufferID = buffer.get()->id();
3407
3408 // Context::bindBufferBase() calls Context::bindBufferRange() with size and offset = 0.
3409 if ((offset == 0) && (size == 0))
3410 {
3411 Capture(setupCalls, CaptureBindBufferBase(glState, true, binding, index, bufferID));
3412 }
3413 else
3414 {
3415 Capture(setupCalls,
3416 CaptureBindBufferRange(glState, true, binding, index, bufferID, offset, size));
3417 }
3418 }
3419 }
3420
CaptureDefaultVertexAttribs(const gl::State & replayState,const gl::State & apiState,std::vector<CallCapture> * setupCalls)3421 void CaptureDefaultVertexAttribs(const gl::State &replayState,
3422 const gl::State &apiState,
3423 std::vector<CallCapture> *setupCalls)
3424 {
3425 const std::vector<gl::VertexAttribCurrentValueData> ¤tValues =
3426 apiState.getVertexAttribCurrentValues();
3427
3428 for (GLuint attribIndex = 0; attribIndex < currentValues.size(); ++attribIndex)
3429 {
3430 const gl::VertexAttribCurrentValueData &defaultValue = currentValues[attribIndex];
3431 if (!IsDefaultCurrentValue(defaultValue))
3432 {
3433 Capture(setupCalls, CaptureVertexAttrib4fv(replayState, true, attribIndex,
3434 defaultValue.Values.FloatValues));
3435 }
3436 }
3437 }
3438
CaptureBindFramebufferForContext(const gl::Context * context,std::vector<CallCapture> * calls,FramebufferCaptureFuncs & framebufferFuncs,const gl::State & glState,GLenum target,const gl::FramebufferID & id)3439 void CaptureBindFramebufferForContext(const gl::Context *context,
3440 std::vector<CallCapture> *calls,
3441 FramebufferCaptureFuncs &framebufferFuncs,
3442 const gl::State &glState,
3443 GLenum target,
3444 const gl::FramebufferID &id)
3445 {
3446 Capture(calls, framebufferFuncs.bindFramebuffer(glState, true, target, id));
3447
3448 // Set current context for this CallCapture since we track these in gFramebufferMapPerContext
3449 calls->back().contextID = context->id();
3450 }
3451
CompressPalettedTexture(angle::MemoryBuffer & data,angle::MemoryBuffer & tmp,const gl::InternalFormat & compressedFormat,const gl::Extents & extents)3452 void CompressPalettedTexture(angle::MemoryBuffer &data,
3453 angle::MemoryBuffer &tmp,
3454 const gl::InternalFormat &compressedFormat,
3455 const gl::Extents &extents)
3456 {
3457 constexpr int uncompressedChannelCount = 4;
3458
3459 uint32_t indexBits = 0, redBlueBits = 0, greenBits = 0, alphaBits = 0;
3460 switch (compressedFormat.internalFormat)
3461 {
3462 case GL_PALETTE4_RGB8_OES:
3463 indexBits = 4;
3464 redBlueBits = 8;
3465 greenBits = 8;
3466 alphaBits = 0;
3467 break;
3468 case GL_PALETTE4_RGBA8_OES:
3469 indexBits = 4;
3470 redBlueBits = 8;
3471 greenBits = 8;
3472 alphaBits = 8;
3473 break;
3474 case GL_PALETTE4_R5_G6_B5_OES:
3475 indexBits = 4;
3476 redBlueBits = 5;
3477 greenBits = 6;
3478 alphaBits = 0;
3479 break;
3480 case GL_PALETTE4_RGBA4_OES:
3481 indexBits = 4;
3482 redBlueBits = 4;
3483 greenBits = 4;
3484 alphaBits = 4;
3485 break;
3486 case GL_PALETTE4_RGB5_A1_OES:
3487 indexBits = 4;
3488 redBlueBits = 5;
3489 greenBits = 5;
3490 alphaBits = 1;
3491 break;
3492 case GL_PALETTE8_RGB8_OES:
3493 indexBits = 8;
3494 redBlueBits = 8;
3495 greenBits = 8;
3496 alphaBits = 0;
3497 break;
3498 case GL_PALETTE8_RGBA8_OES:
3499 indexBits = 8;
3500 redBlueBits = 8;
3501 greenBits = 8;
3502 alphaBits = 8;
3503 break;
3504 case GL_PALETTE8_R5_G6_B5_OES:
3505 indexBits = 8;
3506 redBlueBits = 5;
3507 greenBits = 6;
3508 alphaBits = 0;
3509 break;
3510 case GL_PALETTE8_RGBA4_OES:
3511 indexBits = 8;
3512 redBlueBits = 4;
3513 greenBits = 4;
3514 alphaBits = 4;
3515 break;
3516 case GL_PALETTE8_RGB5_A1_OES:
3517 indexBits = 8;
3518 redBlueBits = 5;
3519 greenBits = 5;
3520 alphaBits = 1;
3521 break;
3522
3523 default:
3524 UNREACHABLE();
3525 break;
3526 }
3527
3528 bool result = data.resize(
3529 // Palette size
3530 (1 << indexBits) * (2 * redBlueBits + greenBits + alphaBits) / 8 +
3531 // Texels size
3532 indexBits * extents.width * extents.height * extents.depth / 8);
3533 ASSERT(result);
3534
3535 angle::StoreRGBA8ToPalettedImpl(
3536 extents.width, extents.height, extents.depth, indexBits, redBlueBits, greenBits, alphaBits,
3537 tmp.data(),
3538 uncompressedChannelCount * extents.width, // inputRowPitch
3539 uncompressedChannelCount * extents.width * extents.height, // inputDepthPitch
3540 data.data(), // output
3541 indexBits * extents.width / 8, // outputRowPitch
3542 indexBits * extents.width * extents.height / 8 // outputDepthPitch
3543 );
3544 }
3545
3546 // Capture the setup of the state that's shared by all of the contexts in the share group
3547 // 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)3548 void CaptureShareGroupMidExecutionSetup(
3549 gl::Context *context,
3550 std::vector<CallCapture> *setupCalls,
3551 ResourceTracker *resourceTracker,
3552 gl::State &replayState,
3553 const PackedEnumMap<ResourceIDType, uint32_t> &maxAccessedResourceIDs)
3554 {
3555 FrameCaptureShared *frameCaptureShared = context->getShareGroup()->getFrameCaptureShared();
3556 const gl::State &apiState = context->getState();
3557
3558 // Small helper function to make the code more readable.
3559 auto cap = [setupCalls](CallCapture &&call) { setupCalls->emplace_back(std::move(call)); };
3560
3561 // Capture Buffer data.
3562 const gl::BufferManager &buffers = apiState.getBufferManagerForCapture();
3563 for (const auto &bufferIter : gl::UnsafeResourceMapIter(buffers.getResourcesForCapture()))
3564 {
3565 gl::BufferID id = {bufferIter.first};
3566 gl::Buffer *buffer = bufferIter.second;
3567
3568 if (id.value == 0)
3569 {
3570 continue;
3571 }
3572
3573 // Generate binding.
3574 cap(CaptureGenBuffers(replayState, true, 1, &id));
3575
3576 resourceTracker->getTrackedResource(context->id(), ResourceIDType::Buffer)
3577 .getStartingResources()
3578 .insert(id.value);
3579
3580 MaybeCaptureUpdateResourceIDs(context, resourceTracker, setupCalls);
3581
3582 // glBufferData. Would possibly be better implemented using a getData impl method.
3583 // Saving buffers that are mapped during a swap is not yet handled.
3584 if (buffer->getSize() == 0)
3585 {
3586 resourceTracker->setStartingBufferMapped(buffer->id().value, false);
3587 continue;
3588 }
3589
3590 // Remember if the buffer was already mapped
3591 GLboolean bufferMapped = buffer->isMapped();
3592
3593 // If needed, map the buffer so we can capture its contents
3594 if (!bufferMapped)
3595 {
3596 (void)buffer->mapRange(context, 0, static_cast<GLsizeiptr>(buffer->getSize()),
3597 GL_MAP_READ_BIT);
3598 }
3599
3600 // Always use the array buffer binding point to upload data to keep things simple.
3601 if (buffer != replayState.getArrayBuffer())
3602 {
3603 replayState.setBufferBinding(context, gl::BufferBinding::Array, buffer);
3604 cap(CaptureBindBuffer(replayState, true, gl::BufferBinding::Array, id));
3605 }
3606
3607 if (buffer->isImmutable())
3608 {
3609 cap(CaptureBufferStorageEXT(replayState, true, gl::BufferBinding::Array,
3610 static_cast<GLsizeiptr>(buffer->getSize()),
3611 buffer->getMapPointer(),
3612 buffer->getStorageExtUsageFlags()));
3613 }
3614 else
3615 {
3616 cap(CaptureBufferData(replayState, true, gl::BufferBinding::Array,
3617 static_cast<GLsizeiptr>(buffer->getSize()),
3618 buffer->getMapPointer(), buffer->getUsage()));
3619 }
3620
3621 if (bufferMapped)
3622 {
3623 void *dontCare = nullptr;
3624 CallCapture mapBufferRange =
3625 CaptureMapBufferRange(replayState, true, gl::BufferBinding::Array,
3626 static_cast<GLsizeiptr>(buffer->getMapOffset()),
3627 static_cast<GLsizeiptr>(buffer->getMapLength()),
3628 buffer->getAccessFlags(), dontCare);
3629 CaptureCustomMapBuffer("MapBufferRange", mapBufferRange, *setupCalls, buffer->id());
3630
3631 resourceTracker->setStartingBufferMapped(buffer->id().value, true);
3632
3633 frameCaptureShared->trackBufferMapping(
3634 context, &setupCalls->back(), buffer->id(), buffer,
3635 static_cast<GLsizeiptr>(buffer->getMapOffset()),
3636 static_cast<GLsizeiptr>(buffer->getMapLength()),
3637 (buffer->getAccessFlags() & GL_MAP_WRITE_BIT) != 0,
3638 (buffer->getStorageExtUsageFlags() & GL_MAP_COHERENT_BIT_EXT) != 0);
3639 }
3640 else
3641 {
3642 resourceTracker->setStartingBufferMapped(buffer->id().value, false);
3643 }
3644
3645 // Generate the calls needed to restore this buffer to original state for frame looping
3646 CaptureBufferResetCalls(context, replayState, resourceTracker, &id, buffer);
3647
3648 // Unmap the buffer if it wasn't already mapped
3649 if (!bufferMapped)
3650 {
3651 GLboolean dontCare;
3652 (void)buffer->unmap(context, &dontCare);
3653 }
3654 }
3655
3656 // Clear the array buffer binding.
3657 if (replayState.getTargetBuffer(gl::BufferBinding::Array))
3658 {
3659 cap(CaptureBindBuffer(replayState, true, gl::BufferBinding::Array, {0}));
3660 replayState.setBufferBinding(context, gl::BufferBinding::Array, nullptr);
3661 }
3662
3663 // Set a unpack alignment of 1. Otherwise, computeRowPitch() will compute the wrong value,
3664 // leading to a crash in memcpy() when capturing the texture contents.
3665 gl::PixelUnpackState ¤tUnpackState = replayState.getUnpackState();
3666 if (currentUnpackState.alignment != 1)
3667 {
3668 cap(CapturePixelStorei(replayState, true, GL_UNPACK_ALIGNMENT, 1));
3669 replayState.getMutablePrivateStateForCapture()->setUnpackAlignment(1);
3670 }
3671
3672 const egl::ImageMap eglImageMap = context->getDisplay()->getImagesForCapture();
3673 for (const auto &[eglImageID, eglImage] : eglImageMap)
3674 {
3675 // Track this as a starting resource that may need to be restored.
3676 TrackedResource &trackedImages =
3677 resourceTracker->getTrackedResource(context->id(), ResourceIDType::Image);
3678 trackedImages.getStartingResources().insert(eglImageID);
3679
3680 ResourceCalls &imageRegenCalls = trackedImages.getResourceRegenCalls();
3681 CallVector imageGenCalls({setupCalls, &imageRegenCalls[eglImageID]});
3682
3683 auto eglImageAttribIter = resourceTracker->getImageToAttribTable().find(
3684 reinterpret_cast<EGLImage>(static_cast<uintptr_t>(eglImageID)));
3685 ASSERT(eglImageAttribIter != resourceTracker->getImageToAttribTable().end());
3686 const egl::AttributeMap &attribs = eglImageAttribIter->second;
3687
3688 for (std::vector<CallCapture> *calls : imageGenCalls)
3689 {
3690 // Create the image on demand with the same attrib retrieved above
3691 CallCapture eglCreateImageKHRCall = egl::CaptureCreateImageKHR(
3692 nullptr, true, nullptr, context->id(), EGL_GL_TEXTURE_2D,
3693 reinterpret_cast<EGLClientBuffer>(static_cast<uintptr_t>(0)), attribs,
3694 reinterpret_cast<EGLImage>(static_cast<uintptr_t>(eglImageID)));
3695
3696 // Convert the CaptureCreateImageKHR CallCapture to the customized CallCapture
3697 CaptureCustomCreateEGLImage(context, "CreateEGLImageKHR", eglImage->getWidth(),
3698 eglImage->getHeight(), eglCreateImageKHRCall, *calls);
3699 }
3700 }
3701
3702 // Capture Texture setup and data.
3703 const gl::TextureManager &textures = apiState.getTextureManagerForCapture();
3704
3705 for (const auto &textureIter : gl::UnsafeResourceMapIter(textures.getResourcesForCapture()))
3706 {
3707 gl::TextureID id = {textureIter.first};
3708 gl::Texture *texture = textureIter.second;
3709
3710 if (id.value == 0)
3711 {
3712 continue;
3713 }
3714
3715 size_t textureSetupStart = setupCalls->size();
3716
3717 // Track this as a starting resource that may need to be restored.
3718 TrackedResource &trackedTextures =
3719 resourceTracker->getTrackedResource(context->id(), ResourceIDType::Texture);
3720 ResourceSet &startingTextures = trackedTextures.getStartingResources();
3721 startingTextures.insert(id.value);
3722
3723 // For the initial texture creation calls, track in the generate list
3724 ResourceCalls &textureRegenCalls = trackedTextures.getResourceRegenCalls();
3725 CallVector texGenCalls({setupCalls, &textureRegenCalls[id.value]});
3726
3727 // Gen the Texture.
3728 for (std::vector<CallCapture> *calls : texGenCalls)
3729 {
3730 Capture(calls, CaptureGenTextures(replayState, true, 1, &id));
3731 MaybeCaptureUpdateResourceIDs(context, resourceTracker, calls);
3732 }
3733
3734 // For the remaining texture setup calls, track in the restore list
3735 ResourceCalls &textureRestoreCalls = trackedTextures.getResourceRestoreCalls();
3736 CallVector texSetupCalls({setupCalls, &textureRestoreCalls[id.value]});
3737
3738 // For each texture, set the correct active texture and binding
3739 // There is similar code in CaptureMidExecutionSetup for per-context setup
3740 const gl::TextureBindingMap ¤tBoundTextures = apiState.getBoundTexturesForCapture();
3741 const gl::TextureBindingVector ¤tBindings = currentBoundTextures[texture->getType()];
3742 const gl::TextureBindingVector &replayBindings =
3743 replayState.getBoundTexturesForCapture()[texture->getType()];
3744 ASSERT(currentBindings.size() == replayBindings.size());
3745
3746 // Look up the replay binding
3747 size_t replayActiveTexture = replayState.getActiveSampler();
3748 // If there ends up being no binding, just use the replay binding
3749 // TODO: We may want to start using index 0 for everything, mark it dirty, and restore it
3750 size_t currentActiveTexture = replayActiveTexture;
3751
3752 // Iterate through current bindings and find the correct index for this texture ID
3753 for (size_t bindingIndex = 0; bindingIndex < currentBindings.size(); ++bindingIndex)
3754 {
3755 gl::TextureID currentTextureID = currentBindings[bindingIndex].id();
3756 gl::TextureID replayTextureID = replayBindings[bindingIndex].id();
3757
3758 // Only check the texture we care about
3759 if (currentTextureID == texture->id())
3760 {
3761 // If the binding doesn't match, track it
3762 if (currentTextureID != replayTextureID)
3763 {
3764 currentActiveTexture = bindingIndex;
3765 }
3766
3767 break;
3768 }
3769 }
3770
3771 // Set the correct active texture before performing any state changes, including binding
3772 if (currentActiveTexture != replayActiveTexture)
3773 {
3774 for (std::vector<CallCapture> *calls : texSetupCalls)
3775 {
3776 Capture(calls, CaptureActiveTexture(
3777 replayState, true,
3778 GL_TEXTURE0 + static_cast<GLenum>(currentActiveTexture)));
3779 }
3780 replayState.getMutablePrivateStateForCapture()->setActiveSampler(
3781 static_cast<unsigned int>(currentActiveTexture));
3782 }
3783
3784 for (std::vector<CallCapture> *calls : texSetupCalls)
3785 {
3786 Capture(calls, CaptureBindTexture(replayState, true, texture->getType(), id));
3787 }
3788 replayState.setSamplerTexture(context, texture->getType(), texture);
3789
3790 // Capture sampler parameter states.
3791 // TODO(jmadill): More sampler / texture states. http://anglebug.com/42262323
3792 gl::SamplerState defaultSamplerState =
3793 gl::SamplerState::CreateDefaultForTarget(texture->getType());
3794 const gl::SamplerState &textureSamplerState = texture->getSamplerState();
3795
3796 auto capTexParam = [&replayState, texture, &texSetupCalls](GLenum pname, GLint param) {
3797 for (std::vector<CallCapture> *calls : texSetupCalls)
3798 {
3799 Capture(calls,
3800 CaptureTexParameteri(replayState, true, texture->getType(), pname, param));
3801 }
3802 };
3803
3804 auto capTexParamf = [&replayState, texture, &texSetupCalls](GLenum pname, GLfloat param) {
3805 for (std::vector<CallCapture> *calls : texSetupCalls)
3806 {
3807 Capture(calls,
3808 CaptureTexParameterf(replayState, true, texture->getType(), pname, param));
3809 }
3810 };
3811
3812 if (textureSamplerState.getMinFilter() != defaultSamplerState.getMinFilter())
3813 {
3814 capTexParam(GL_TEXTURE_MIN_FILTER, textureSamplerState.getMinFilter());
3815 }
3816
3817 if (textureSamplerState.getMagFilter() != defaultSamplerState.getMagFilter())
3818 {
3819 capTexParam(GL_TEXTURE_MAG_FILTER, textureSamplerState.getMagFilter());
3820 }
3821
3822 if (textureSamplerState.getWrapR() != defaultSamplerState.getWrapR())
3823 {
3824 capTexParam(GL_TEXTURE_WRAP_R, textureSamplerState.getWrapR());
3825 }
3826
3827 if (textureSamplerState.getWrapS() != defaultSamplerState.getWrapS())
3828 {
3829 capTexParam(GL_TEXTURE_WRAP_S, textureSamplerState.getWrapS());
3830 }
3831
3832 if (textureSamplerState.getWrapT() != defaultSamplerState.getWrapT())
3833 {
3834 capTexParam(GL_TEXTURE_WRAP_T, textureSamplerState.getWrapT());
3835 }
3836
3837 if (textureSamplerState.getMinLod() != defaultSamplerState.getMinLod())
3838 {
3839 capTexParamf(GL_TEXTURE_MIN_LOD, textureSamplerState.getMinLod());
3840 }
3841
3842 if (textureSamplerState.getMaxLod() != defaultSamplerState.getMaxLod())
3843 {
3844 capTexParamf(GL_TEXTURE_MAX_LOD, textureSamplerState.getMaxLod());
3845 }
3846
3847 if (textureSamplerState.getCompareMode() != defaultSamplerState.getCompareMode())
3848 {
3849 capTexParam(GL_TEXTURE_COMPARE_MODE, textureSamplerState.getCompareMode());
3850 }
3851
3852 if (textureSamplerState.getCompareFunc() != defaultSamplerState.getCompareFunc())
3853 {
3854 capTexParam(GL_TEXTURE_COMPARE_FUNC, textureSamplerState.getCompareFunc());
3855 }
3856
3857 // Texture parameters
3858 if (texture->getSwizzleRed() != GL_RED)
3859 {
3860 capTexParam(GL_TEXTURE_SWIZZLE_R, texture->getSwizzleRed());
3861 }
3862
3863 if (texture->getSwizzleGreen() != GL_GREEN)
3864 {
3865 capTexParam(GL_TEXTURE_SWIZZLE_G, texture->getSwizzleGreen());
3866 }
3867
3868 if (texture->getSwizzleBlue() != GL_BLUE)
3869 {
3870 capTexParam(GL_TEXTURE_SWIZZLE_B, texture->getSwizzleBlue());
3871 }
3872
3873 if (texture->getSwizzleAlpha() != GL_ALPHA)
3874 {
3875 capTexParam(GL_TEXTURE_SWIZZLE_A, texture->getSwizzleAlpha());
3876 }
3877
3878 if (texture->getBaseLevel() != 0)
3879 {
3880 capTexParam(GL_TEXTURE_BASE_LEVEL, texture->getBaseLevel());
3881 }
3882
3883 if (texture->getMaxLevel() != 1000)
3884 {
3885 capTexParam(GL_TEXTURE_MAX_LEVEL, texture->getMaxLevel());
3886 }
3887
3888 // If the texture is immutable, initialize it with TexStorage
3889 if (texture->getImmutableFormat())
3890 {
3891 // We can only call TexStorage *once* on an immutable texture, so it needs special
3892 // handling. To solve this, immutable textures will have a BindTexture and TexStorage as
3893 // part of their textureRegenCalls. The resulting regen sequence will be:
3894 //
3895 // const GLuint glDeleteTextures_texturesPacked_0[] = { gTextureMap[52] };
3896 // glDeleteTextures(1, glDeleteTextures_texturesPacked_0);
3897 // glGenTextures(1, reinterpret_cast<GLuint *>(gReadBuffer));
3898 // UpdateTextureID(52, 0);
3899 // glBindTexture(GL_TEXTURE_2D, gTextureMap[52]);
3900 // glTexStorage2D(GL_TEXTURE_2D, 1, GL_R8, 256, 512);
3901
3902 // Bind the texture first just for textureRegenCalls
3903 Capture(&textureRegenCalls[id.value],
3904 CaptureBindTexture(replayState, true, texture->getType(), id));
3905
3906 // Then add TexStorage to texGenCalls instead of texSetupCalls
3907 for (std::vector<CallCapture> *calls : texGenCalls)
3908 {
3909 CaptureTextureStorage(calls, &replayState, texture);
3910 }
3911 }
3912
3913 // Iterate texture levels and layers.
3914 gl::ImageIndexIterator imageIter = gl::ImageIndexIterator::MakeGeneric(
3915 texture->getType(), 0, texture->getMipmapMaxLevel() + 1, gl::ImageIndex::kEntireLevel,
3916 gl::ImageIndex::kEntireLevel);
3917 while (imageIter.hasNext())
3918 {
3919 gl::ImageIndex index = imageIter.next();
3920
3921 const gl::ImageDesc &desc = texture->getTextureState().getImageDesc(index);
3922
3923 if (desc.size.empty())
3924 {
3925 continue;
3926 }
3927
3928 const gl::InternalFormat &format = *desc.format.info;
3929
3930 bool supportedType = (index.getType() == gl::TextureType::_2D ||
3931 index.getType() == gl::TextureType::_3D ||
3932 index.getType() == gl::TextureType::_2DArray ||
3933 index.getType() == gl::TextureType::Buffer ||
3934 index.getType() == gl::TextureType::CubeMap ||
3935 index.getType() == gl::TextureType::CubeMapArray ||
3936 index.getType() == gl::TextureType::External);
3937
3938 // Check for supported textures
3939 if (!supportedType)
3940 {
3941 ERR() << "Unsupported texture type: " << index.getType();
3942 UNREACHABLE();
3943 }
3944
3945 if (index.getType() == gl::TextureType::Buffer)
3946 {
3947 // The buffer contents are already backed up, but we need to emit the TexBuffer
3948 // binding calls
3949 for (std::vector<CallCapture> *calls : texSetupCalls)
3950 {
3951 CaptureTextureContents(calls, &replayState, texture, index, desc, 0, 0);
3952 }
3953 continue;
3954 }
3955
3956 if (index.getType() == gl::TextureType::External)
3957 {
3958 // Lookup the eglImage ID associated with this texture when the app issued
3959 // glEGLImageTargetTexture2DOES()
3960 auto eglImageIter = resourceTracker->getTextureIDToImageTable().find(id.value);
3961 egl::ImageID eglImageID;
3962 if (eglImageIter != resourceTracker->getTextureIDToImageTable().end())
3963 {
3964 eglImageID = eglImageIter->second;
3965 }
3966 else
3967 {
3968 // Original image was deleted and needs to be recreated first
3969 eglImageID = {maxAccessedResourceIDs[ResourceIDType::Image] + 1};
3970 for (std::vector<CallCapture> *calls : texSetupCalls)
3971 {
3972 egl::AttributeMap attribs = egl::AttributeMap::CreateFromIntArray(nullptr);
3973 CallCapture eglCreateImageKHRCall = egl::CaptureCreateImageKHR(
3974 nullptr, true, nullptr, context->id(), EGL_GL_TEXTURE_2D,
3975 reinterpret_cast<EGLClientBuffer>(static_cast<uintptr_t>(0)), attribs,
3976 reinterpret_cast<EGLImage>(static_cast<uintptr_t>(eglImageID.value)));
3977 CaptureCustomCreateEGLImage(context, "CreateEGLImageKHR", desc.size.width,
3978 desc.size.height, eglCreateImageKHRCall,
3979 *calls);
3980 }
3981 }
3982 // Pass the eglImage to the texture that is bound to GL_TEXTURE_EXTERNAL_OES target
3983 for (std::vector<CallCapture> *calls : texSetupCalls)
3984 {
3985 Capture(calls, CaptureEGLImageTargetTexture2DOES(
3986 replayState, true, gl::TextureType::External, eglImageID));
3987 }
3988 }
3989 else if (context->getExtensions().getImageANGLE)
3990 {
3991 // Use ANGLE_get_image to read back pixel data.
3992 angle::MemoryBuffer data;
3993
3994 const gl::Extents extents(desc.size.width, desc.size.height, desc.size.depth);
3995
3996 gl::PixelPackState packState;
3997 packState.alignment = 1;
3998
3999 if (format.paletted)
4000 {
4001 // Read back the uncompressed texture, then re-compress it
4002 // to store in the trace.
4003
4004 angle::MemoryBuffer tmp;
4005
4006 // The uncompressed format (R8G8B8A8) is 4 bytes per texel
4007 bool result = tmp.resize(4 * extents.width * extents.height * extents.depth);
4008 ASSERT(result);
4009
4010 (void)texture->getTexImage(context, packState, nullptr, index.getTarget(),
4011 index.getLevelIndex(), GL_RGBA, GL_UNSIGNED_BYTE,
4012 tmp.data());
4013
4014 CompressPalettedTexture(data, tmp, format, extents);
4015 }
4016 else if (format.compressed)
4017 {
4018 // Calculate the size needed to store the compressed level
4019 GLuint sizeInBytes;
4020 bool result = format.computeCompressedImageSize(extents, &sizeInBytes);
4021 ASSERT(result);
4022
4023 result = data.resize(sizeInBytes);
4024 ASSERT(result);
4025
4026 (void)texture->getCompressedTexImage(context, packState, nullptr,
4027 index.getTarget(), index.getLevelIndex(),
4028 data.data());
4029 }
4030 else
4031 {
4032 GLenum getFormat = format.format;
4033 GLenum getType = format.type;
4034
4035 const gl::PixelUnpackState &unpack = apiState.getUnpackState();
4036
4037 GLuint endByte = 0;
4038 bool unpackSize =
4039 format.computePackUnpackEndByte(getType, extents, unpack, true, &endByte);
4040 ASSERT(unpackSize);
4041
4042 bool result = data.resize(endByte);
4043 ASSERT(result);
4044
4045 (void)texture->getTexImage(context, packState, nullptr, index.getTarget(),
4046 index.getLevelIndex(), getFormat, getType,
4047 data.data());
4048 }
4049
4050 for (std::vector<CallCapture> *calls : texSetupCalls)
4051 {
4052 CaptureTextureContents(calls, &replayState, texture, index, desc,
4053 static_cast<GLuint>(data.size()), data.data());
4054 }
4055 }
4056 else
4057 {
4058 for (std::vector<CallCapture> *calls : texSetupCalls)
4059 {
4060 CaptureTextureContents(calls, &replayState, texture, index, desc, 0, nullptr);
4061 }
4062 }
4063 }
4064
4065 size_t textureSetupEnd = setupCalls->size();
4066
4067 // Mark the range of calls used to setup this texture
4068 frameCaptureShared->markResourceSetupCallsInactive(
4069 setupCalls, ResourceIDType::Texture, id.value,
4070 gl::Range<size_t>(textureSetupStart, textureSetupEnd));
4071 }
4072
4073 // Capture Renderbuffers.
4074 const gl::RenderbufferManager &renderbuffers = apiState.getRenderbufferManagerForCapture();
4075 FramebufferCaptureFuncs framebufferFuncs(context->isGLES1());
4076
4077 for (const auto &renderbufIter :
4078 gl::UnsafeResourceMapIter(renderbuffers.getResourcesForCapture()))
4079 {
4080 gl::RenderbufferID id = {renderbufIter.first};
4081 const gl::Renderbuffer *renderbuffer = renderbufIter.second;
4082
4083 // Track this as a starting resource that may need to be restored.
4084 TrackedResource &trackedRenderbuffers =
4085 resourceTracker->getTrackedResource(context->id(), ResourceIDType::Renderbuffer);
4086 ResourceSet &startingRenderbuffers = trackedRenderbuffers.getStartingResources();
4087 startingRenderbuffers.insert(id.value);
4088
4089 // For the initial renderbuffer creation calls, track in the generate list
4090 ResourceCalls &renderbufferRegenCalls = trackedRenderbuffers.getResourceRegenCalls();
4091 CallVector rbGenCalls({setupCalls, &renderbufferRegenCalls[id.value]});
4092
4093 // Generate renderbuffer id.
4094 for (std::vector<CallCapture> *calls : rbGenCalls)
4095 {
4096 Capture(calls, framebufferFuncs.genRenderbuffers(replayState, true, 1, &id));
4097 MaybeCaptureUpdateResourceIDs(context, resourceTracker, calls);
4098 Capture(calls,
4099 framebufferFuncs.bindRenderbuffer(replayState, true, GL_RENDERBUFFER, id));
4100 }
4101
4102 GLenum internalformat = renderbuffer->getFormat().info->internalFormat;
4103
4104 if (renderbuffer->getSamples() > 0)
4105 {
4106 // Note: We could also use extensions if available.
4107 for (std::vector<CallCapture> *calls : rbGenCalls)
4108 {
4109 Capture(calls,
4110 CaptureRenderbufferStorageMultisample(
4111 replayState, true, GL_RENDERBUFFER, renderbuffer->getSamples(),
4112 internalformat, renderbuffer->getWidth(), renderbuffer->getHeight()));
4113 }
4114 }
4115 else
4116 {
4117 for (std::vector<CallCapture> *calls : rbGenCalls)
4118 {
4119 Capture(calls, framebufferFuncs.renderbufferStorage(
4120 replayState, true, GL_RENDERBUFFER, internalformat,
4121 renderbuffer->getWidth(), renderbuffer->getHeight()));
4122 }
4123 }
4124
4125 // TODO: Capture renderbuffer contents. http://anglebug.com/42262323
4126 }
4127
4128 // Capture Shaders and Programs.
4129 const gl::ShaderProgramManager &shadersAndPrograms =
4130 apiState.getShaderProgramManagerForCapture();
4131 const gl::ResourceMap<gl::Shader, gl::ShaderProgramID> &shaders =
4132 shadersAndPrograms.getShadersForCapture();
4133 const gl::ResourceMap<gl::Program, gl::ShaderProgramID> &programs =
4134 shadersAndPrograms.getProgramsForCaptureAndPerf();
4135
4136 TrackedResource &trackedShaderPrograms =
4137 resourceTracker->getTrackedResource(context->id(), ResourceIDType::ShaderProgram);
4138
4139 // Capture Program binary state.
4140 gl::ShaderProgramID tempShaderStartID = {resourceTracker->getMaxShaderPrograms()};
4141 std::map<gl::ShaderProgramID, std::vector<gl::ShaderProgramID>> deferredAttachCalls;
4142 for (const auto &programIter : gl::UnsafeResourceMapIter(programs))
4143 {
4144 gl::ShaderProgramID id = {programIter.first};
4145 gl::Program *program = programIter.second;
4146
4147 // Unlinked programs don't have an executable so track in case linking is deferred
4148 // Programs are shared by contexts in the share group and only need to be captured once.
4149 if (!program->isLinked())
4150 {
4151 frameCaptureShared->setDeferredLinkProgram(id);
4152
4153 if (program->getAttachedShadersCount() > 0)
4154 {
4155 // AttachShader calls will be generated at shader-handling time
4156 for (gl::ShaderType shaderType : gl::AllShaderTypes())
4157 {
4158 gl::Shader *shader = program->getAttachedShader(shaderType);
4159 if (shader != nullptr)
4160 {
4161 deferredAttachCalls[shader->getHandle()].push_back(id);
4162 }
4163 }
4164 }
4165 else
4166 {
4167 WARN() << "Deferred attachment of shaders is not yet supported";
4168 }
4169 }
4170
4171 size_t programSetupStart = setupCalls->size();
4172
4173 // Create two lists for program regen calls
4174 ResourceCalls &shaderProgramRegenCalls = trackedShaderPrograms.getResourceRegenCalls();
4175 CallVector programRegenCalls({setupCalls, &shaderProgramRegenCalls[id.value]});
4176
4177 for (std::vector<CallCapture> *calls : programRegenCalls)
4178 {
4179 CallCapture createProgram = CaptureCreateProgram(replayState, true, id.value);
4180 CaptureCustomShaderProgram("CreateProgram", createProgram, *calls);
4181 }
4182
4183 if (program->isLinked())
4184 {
4185 // Get last linked shader source.
4186 const ProgramSources &linkedSources =
4187 context->getShareGroup()->getFrameCaptureShared()->getProgramSources(id);
4188
4189 // Create two lists for program restore calls
4190 ResourceCalls &shaderProgramRestoreCalls =
4191 trackedShaderPrograms.getResourceRestoreCalls();
4192 CallVector programRestoreCalls({setupCalls, &shaderProgramRestoreCalls[id.value]});
4193
4194 for (std::vector<CallCapture> *calls : programRestoreCalls)
4195 {
4196 GenerateLinkedProgram(context, replayState, resourceTracker, calls, program, id,
4197 tempShaderStartID, linkedSources);
4198 }
4199
4200 // Update the program in replayState
4201 if (!replayState.getProgram() || replayState.getProgram()->id() != program->id())
4202 {
4203 // Note: We don't do this in GenerateLinkedProgram because it can't modify state
4204 (void)replayState.setProgram(context, program);
4205 }
4206 }
4207
4208 resourceTracker->getTrackedResource(context->id(), ResourceIDType::ShaderProgram)
4209 .getStartingResources()
4210 .insert(id.value);
4211 resourceTracker->setShaderProgramType(id, ShaderProgramType::ProgramType);
4212
4213 // Mark linked programs/shaders as inactive, leaving deferred-linked programs/shaders marked
4214 // as active
4215 if (!frameCaptureShared->isDeferredLinkProgram(id))
4216 {
4217 size_t programSetupEnd = setupCalls->size();
4218
4219 // Mark the range of calls used to setup this program
4220 frameCaptureShared->markResourceSetupCallsInactive(
4221 setupCalls, ResourceIDType::ShaderProgram, id.value,
4222 gl::Range<size_t>(programSetupStart, programSetupEnd));
4223 }
4224 }
4225
4226 // Handle shaders.
4227 for (const auto &shaderIter : gl::UnsafeResourceMapIter(shaders))
4228 {
4229 gl::ShaderProgramID id = {shaderIter.first};
4230 gl::Shader *shader = shaderIter.second;
4231
4232 // Skip shaders scheduled for deletion.
4233 // Shaders are shared by contexts in the share group and only need to be captured once.
4234 if (shader->hasBeenDeleted())
4235 {
4236 continue;
4237 }
4238
4239 size_t shaderSetupStart = setupCalls->size();
4240
4241 // Create two lists for shader regen calls
4242 ResourceCalls &shaderProgramRegenCalls = trackedShaderPrograms.getResourceRegenCalls();
4243 CallVector shaderRegenCalls({setupCalls, &shaderProgramRegenCalls[id.value]});
4244
4245 for (std::vector<CallCapture> *calls : shaderRegenCalls)
4246 {
4247 CallCapture createShader =
4248 CaptureCreateShader(replayState, true, shader->getType(), id.value);
4249 CaptureCustomShaderProgram("CreateShader", createShader, *calls);
4250
4251 // If unlinked programs have been created which reference this shader emit corresponding
4252 // attach calls
4253 for (const auto deferredAttachedProgramID : deferredAttachCalls[id])
4254 {
4255 CallCapture attachShader =
4256 CaptureAttachShader(replayState, true, deferredAttachedProgramID, id);
4257 calls->emplace_back(std::move(attachShader));
4258 }
4259 }
4260
4261 std::string shaderSource = shader->getSourceString();
4262 const char *sourcePointer = shaderSource.empty() ? nullptr : shaderSource.c_str();
4263
4264 // Create two lists for shader restore calls
4265 ResourceCalls &shaderProgramRestoreCalls = trackedShaderPrograms.getResourceRestoreCalls();
4266 CallVector shaderRestoreCalls({setupCalls, &shaderProgramRestoreCalls[id.value]});
4267
4268 // This does not handle some more tricky situations like attaching and then deleting a
4269 // shader.
4270 // TODO(jmadill): Handle trickier program uses. http://anglebug.com/42262323
4271 if (shader->isCompiled(context))
4272 {
4273 const std::string &capturedSource =
4274 context->getShareGroup()->getFrameCaptureShared()->getShaderSource(id);
4275 if (capturedSource != shaderSource)
4276 {
4277 ASSERT(!capturedSource.empty());
4278 sourcePointer = capturedSource.c_str();
4279 }
4280
4281 for (std::vector<CallCapture> *calls : shaderRestoreCalls)
4282 {
4283 Capture(calls,
4284 CaptureShaderSource(replayState, true, id, 1, &sourcePointer, nullptr));
4285 Capture(calls, CaptureCompileShader(replayState, true, id));
4286 }
4287 }
4288
4289 if (sourcePointer &&
4290 (!shader->isCompiled(context) || sourcePointer != shaderSource.c_str()))
4291 {
4292 for (std::vector<CallCapture> *calls : shaderRestoreCalls)
4293 {
4294 Capture(calls,
4295 CaptureShaderSource(replayState, true, id, 1, &sourcePointer, nullptr));
4296 }
4297 }
4298
4299 // Deferred-linked programs/shaders must be left marked as active
4300 if (deferredAttachCalls[id].empty())
4301 {
4302 // Mark the range of calls used to setup this shader
4303 frameCaptureShared->markResourceSetupCallsInactive(
4304 setupCalls, ResourceIDType::ShaderProgram, id.value,
4305 gl::Range<size_t>(shaderSetupStart, setupCalls->size()));
4306 }
4307
4308 resourceTracker->getTrackedResource(context->id(), ResourceIDType::ShaderProgram)
4309 .getStartingResources()
4310 .insert(id.value);
4311 resourceTracker->setShaderProgramType(id, ShaderProgramType::ShaderType);
4312 }
4313
4314 // Capture Sampler Objects
4315 const gl::SamplerManager &samplers = apiState.getSamplerManagerForCapture();
4316 for (const auto &samplerIter : gl::UnsafeResourceMapIter(samplers.getResourcesForCapture()))
4317 {
4318 gl::SamplerID samplerID = {samplerIter.first};
4319
4320 // Don't gen the sampler if we've seen it before, since they are shared across the context
4321 // share group.
4322 cap(CaptureGenSamplers(replayState, true, 1, &samplerID));
4323 MaybeCaptureUpdateResourceIDs(context, resourceTracker, setupCalls);
4324
4325 gl::Sampler *sampler = samplerIter.second;
4326 if (!sampler)
4327 {
4328 continue;
4329 }
4330
4331 gl::SamplerState defaultSamplerState;
4332 if (sampler->getMinFilter() != defaultSamplerState.getMinFilter())
4333 {
4334 cap(CaptureSamplerParameteri(replayState, true, samplerID, GL_TEXTURE_MIN_FILTER,
4335 sampler->getMinFilter()));
4336 }
4337 if (sampler->getMagFilter() != defaultSamplerState.getMagFilter())
4338 {
4339 cap(CaptureSamplerParameteri(replayState, true, samplerID, GL_TEXTURE_MAG_FILTER,
4340 sampler->getMagFilter()));
4341 }
4342 if (sampler->getWrapS() != defaultSamplerState.getWrapS())
4343 {
4344 cap(CaptureSamplerParameteri(replayState, true, samplerID, GL_TEXTURE_WRAP_S,
4345 sampler->getWrapS()));
4346 }
4347 if (sampler->getWrapR() != defaultSamplerState.getWrapR())
4348 {
4349 cap(CaptureSamplerParameteri(replayState, true, samplerID, GL_TEXTURE_WRAP_R,
4350 sampler->getWrapR()));
4351 }
4352 if (sampler->getWrapT() != defaultSamplerState.getWrapT())
4353 {
4354 cap(CaptureSamplerParameteri(replayState, true, samplerID, GL_TEXTURE_WRAP_T,
4355 sampler->getWrapT()));
4356 }
4357 if (sampler->getMinLod() != defaultSamplerState.getMinLod())
4358 {
4359 cap(CaptureSamplerParameterf(replayState, true, samplerID, GL_TEXTURE_MIN_LOD,
4360 sampler->getMinLod()));
4361 }
4362 if (sampler->getMaxLod() != defaultSamplerState.getMaxLod())
4363 {
4364 cap(CaptureSamplerParameterf(replayState, true, samplerID, GL_TEXTURE_MAX_LOD,
4365 sampler->getMaxLod()));
4366 }
4367 if (sampler->getCompareMode() != defaultSamplerState.getCompareMode())
4368 {
4369 cap(CaptureSamplerParameteri(replayState, true, samplerID, GL_TEXTURE_COMPARE_MODE,
4370 sampler->getCompareMode()));
4371 }
4372 if (sampler->getCompareFunc() != defaultSamplerState.getCompareFunc())
4373 {
4374 cap(CaptureSamplerParameteri(replayState, true, samplerID, GL_TEXTURE_COMPARE_FUNC,
4375 sampler->getCompareFunc()));
4376 }
4377 }
4378
4379 // Capture Sync Objects
4380 const gl::SyncManager &syncs = apiState.getSyncManagerForCapture();
4381 for (const auto &syncIter : gl::UnsafeResourceMapIter(syncs.getResourcesForCapture()))
4382 {
4383 gl::SyncID syncID = {syncIter.first};
4384 const gl::Sync *sync = syncIter.second;
4385 GLsync syncObject = gl::unsafe_int_to_pointer_cast<GLsync>(syncID.value);
4386
4387 if (!sync)
4388 {
4389 continue;
4390 }
4391 CallCapture fenceSync =
4392 CaptureFenceSync(replayState, true, sync->getCondition(), sync->getFlags(), syncObject);
4393 CaptureCustomFenceSync(fenceSync, *setupCalls);
4394 CaptureFenceSyncResetCalls(context, replayState, resourceTracker, syncID, syncObject, sync);
4395 resourceTracker->getStartingFenceSyncs().insert(syncID);
4396 }
4397
4398 // Capture EGL Sync Objects
4399 const egl::SyncMap &eglSyncMap = context->getDisplay()->getSyncsForCapture();
4400 for (const auto &eglSyncIter : eglSyncMap)
4401 {
4402 egl::SyncID eglSyncID = {eglSyncIter.first};
4403 const egl::Sync *eglSync = eglSyncIter.second.get();
4404 EGLSync eglSyncObject = gl::unsafe_int_to_pointer_cast<EGLSync>(eglSyncID.value);
4405
4406 if (!eglSync)
4407 {
4408 continue;
4409 }
4410 CallCapture createEGLSync =
4411 CaptureCreateSync(nullptr, true, context->getDisplay(), eglSync->getType(),
4412 eglSync->getAttributeMap(), eglSyncObject);
4413 CaptureCustomCreateEGLSync("CreateEGLSyncKHR", createEGLSync, *setupCalls);
4414 CaptureEGLSyncResetCalls(context, replayState, resourceTracker, eglSyncID, eglSyncObject,
4415 eglSync);
4416 resourceTracker->getTrackedResource(context->id(), ResourceIDType::egl_Sync)
4417 .getStartingResources()
4418 .insert(eglSyncID.value);
4419 }
4420
4421 GLint contextUnpackAlignment = context->getState().getUnpackState().alignment;
4422 if (currentUnpackState.alignment != contextUnpackAlignment)
4423 {
4424 cap(CapturePixelStorei(replayState, true, GL_UNPACK_ALIGNMENT, contextUnpackAlignment));
4425 replayState.getMutablePrivateStateForCapture()->setUnpackAlignment(contextUnpackAlignment);
4426 }
4427 }
4428
CaptureMidExecutionSetup(const gl::Context * context,std::vector<CallCapture> * setupCalls,StateResetHelper & resetHelper,std::vector<CallCapture> * shareGroupSetupCalls,ResourceIDToSetupCallsMap * resourceIDToSetupCalls,ResourceTracker * resourceTracker,gl::State & replayState,bool validationEnabled)4429 void CaptureMidExecutionSetup(const gl::Context *context,
4430 std::vector<CallCapture> *setupCalls,
4431 StateResetHelper &resetHelper,
4432 std::vector<CallCapture> *shareGroupSetupCalls,
4433 ResourceIDToSetupCallsMap *resourceIDToSetupCalls,
4434 ResourceTracker *resourceTracker,
4435 gl::State &replayState,
4436 bool validationEnabled)
4437 {
4438 const gl::State &apiState = context->getState();
4439
4440 // Small helper function to make the code more readable.
4441 auto cap = [setupCalls](CallCapture &&call) { setupCalls->emplace_back(std::move(call)); };
4442
4443 cap(egl::CaptureMakeCurrent(nullptr, true, nullptr, {0}, {0}, context->id(), EGL_TRUE));
4444
4445 // Vertex input states. Must happen after buffer data initialization. Do not capture on GLES1.
4446 if (!context->isGLES1())
4447 {
4448 CaptureDefaultVertexAttribs(replayState, apiState, setupCalls);
4449 }
4450
4451 // Capture vertex array objects
4452 VertexArrayCaptureFuncs vertexArrayFuncs(context->isGLES1());
4453
4454 const gl::VertexArrayMap &vertexArrayMap = context->getVertexArraysForCapture();
4455 gl::VertexArrayID boundVertexArrayID = {0};
4456 for (const auto &vertexArrayIter : gl::UnsafeResourceMapIter(vertexArrayMap))
4457 {
4458 TrackedResource &trackedVertexArrays =
4459 resourceTracker->getTrackedResource(context->id(), ResourceIDType::VertexArray);
4460
4461 gl::VertexArrayID vertexArrayID = {vertexArrayIter.first};
4462
4463 // Track this as a starting resource that may need to be restored
4464 resourceTracker->getTrackedResource(context->id(), ResourceIDType::VertexArray)
4465 .getStartingResources()
4466 .insert(vertexArrayID.value);
4467
4468 // Create two lists of calls for initial setup
4469 ResourceCalls &vertexArrayRegenCalls = trackedVertexArrays.getResourceRegenCalls();
4470 CallVector vertexArrayGenCalls({setupCalls, &vertexArrayRegenCalls[vertexArrayID.value]});
4471
4472 if (vertexArrayID.value != 0)
4473 {
4474 // Gen the vertex array
4475 for (std::vector<CallCapture> *calls : vertexArrayGenCalls)
4476 {
4477 Capture(calls,
4478 vertexArrayFuncs.genVertexArrays(replayState, true, 1, &vertexArrayID));
4479 MaybeCaptureUpdateResourceIDs(context, resourceTracker, calls);
4480 }
4481 }
4482
4483 // Create two lists of calls for populating the vertex array
4484 ResourceCalls &vertexArrayRestoreCalls = trackedVertexArrays.getResourceRestoreCalls();
4485 CallVector vertexArraySetupCalls(
4486 {setupCalls, &vertexArrayRestoreCalls[vertexArrayID.value]});
4487
4488 if (vertexArrayIter.second)
4489 {
4490 const gl::VertexArray *vertexArray = vertexArrayIter.second;
4491
4492 // Populate the vertex array
4493 for (std::vector<CallCapture> *calls : vertexArraySetupCalls)
4494 {
4495 // Bind the vertexArray (if needed) and populate it
4496 if (vertexArrayID != boundVertexArrayID)
4497 {
4498 Capture(calls,
4499 vertexArrayFuncs.bindVertexArray(replayState, true, vertexArrayID));
4500 }
4501 CaptureVertexArrayState(calls, context, vertexArray, &replayState);
4502 }
4503 boundVertexArrayID = vertexArrayID;
4504 }
4505 }
4506
4507 // Bind the current vertex array
4508 const gl::VertexArray *currentVertexArray = apiState.getVertexArray();
4509 if (currentVertexArray->id() != boundVertexArrayID)
4510 {
4511 cap(vertexArrayFuncs.bindVertexArray(replayState, true, currentVertexArray->id()));
4512 }
4513
4514 // Track the calls necessary to bind the vertex array back to initial state
4515 CallResetMap &resetCalls = resetHelper.getResetCalls();
4516 Capture(&resetCalls[angle::EntryPoint::GLBindVertexArray],
4517 vertexArrayFuncs.bindVertexArray(replayState, true, currentVertexArray->id()));
4518
4519 // Capture indexed buffer bindings.
4520 const gl::BufferVector &uniformIndexedBuffers =
4521 apiState.getOffsetBindingPointerUniformBuffers();
4522 const gl::BufferVector &atomicCounterIndexedBuffers =
4523 apiState.getOffsetBindingPointerAtomicCounterBuffers();
4524 const gl::BufferVector &shaderStorageIndexedBuffers =
4525 apiState.getOffsetBindingPointerShaderStorageBuffers();
4526 CaptureIndexedBuffers(replayState, uniformIndexedBuffers, gl::BufferBinding::Uniform,
4527 setupCalls);
4528 CaptureIndexedBuffers(replayState, atomicCounterIndexedBuffers,
4529 gl::BufferBinding::AtomicCounter, setupCalls);
4530 CaptureIndexedBuffers(replayState, shaderStorageIndexedBuffers,
4531 gl::BufferBinding::ShaderStorage, setupCalls);
4532
4533 // Capture Buffer bindings.
4534 const gl::BoundBufferMap &boundBuffers = apiState.getBoundBuffersForCapture();
4535 for (gl::BufferBinding binding : angle::AllEnums<gl::BufferBinding>())
4536 {
4537 gl::BufferID bufferID = boundBuffers[binding].id();
4538
4539 // Filter out redundant buffer binding commands. Note that the code in the previous section
4540 // only binds to ARRAY_BUFFER. Therefore we only check the array binding against the binding
4541 // we set earlier.
4542 const gl::Buffer *arrayBuffer = replayState.getArrayBuffer();
4543 bool isArray = binding == gl::BufferBinding::Array;
4544 bool isArrayBufferChanging = isArray && arrayBuffer && arrayBuffer->id() != bufferID;
4545 if (isArrayBufferChanging || (!isArray && bufferID.value != 0))
4546 {
4547 cap(CaptureBindBuffer(replayState, true, binding, bufferID));
4548 replayState.setBufferBinding(context, binding, boundBuffers[binding].get());
4549 }
4550
4551 // Restore all buffer bindings for Reset
4552 if (bufferID.value != 0 || isArrayBufferChanging)
4553 {
4554 CaptureBufferBindingResetCalls(replayState, resourceTracker, binding, bufferID);
4555
4556 // Track this as a starting binding
4557 resetHelper.setStartingBufferBinding(binding, bufferID);
4558 }
4559 }
4560
4561 // Set a unpack alignment of 1. Otherwise, computeRowPitch() will compute the wrong value,
4562 // leading to a crash in memcpy() when capturing the texture contents.
4563 gl::PixelUnpackState ¤tUnpackState = replayState.getUnpackState();
4564 if (currentUnpackState.alignment != 1)
4565 {
4566 cap(CapturePixelStorei(replayState, true, GL_UNPACK_ALIGNMENT, 1));
4567 replayState.getMutablePrivateStateForCapture()->setUnpackAlignment(1);
4568 }
4569
4570 // Capture Texture setup and data.
4571 const gl::TextureBindingMap &apiBoundTextures = apiState.getBoundTexturesForCapture();
4572 resetHelper.setResetActiveTexture(apiState.getActiveSampler());
4573
4574 // Set Texture bindings.
4575 for (gl::TextureType textureType : angle::AllEnums<gl::TextureType>())
4576 {
4577 const gl::TextureBindingVector &apiBindings = apiBoundTextures[textureType];
4578 const gl::TextureBindingVector &replayBindings =
4579 replayState.getBoundTexturesForCapture()[textureType];
4580 ASSERT(apiBindings.size() == replayBindings.size());
4581 for (size_t bindingIndex = 0; bindingIndex < apiBindings.size(); ++bindingIndex)
4582 {
4583 gl::TextureID apiTextureID = apiBindings[bindingIndex].id();
4584 gl::TextureID replayTextureID = replayBindings[bindingIndex].id();
4585
4586 if (apiTextureID != replayTextureID)
4587 {
4588 if (replayState.getActiveSampler() != bindingIndex)
4589 {
4590 cap(CaptureActiveTexture(replayState, true,
4591 GL_TEXTURE0 + static_cast<GLenum>(bindingIndex)));
4592 replayState.getMutablePrivateStateForCapture()->setActiveSampler(
4593 static_cast<unsigned int>(bindingIndex));
4594 }
4595
4596 cap(CaptureBindTexture(replayState, true, textureType, apiTextureID));
4597 replayState.setSamplerTexture(context, textureType,
4598 apiBindings[bindingIndex].get());
4599 }
4600
4601 if (apiTextureID.value)
4602 {
4603 // Set this texture as active so it will be generated in Setup
4604 MarkResourceIDActive(ResourceIDType::Texture, apiTextureID.value,
4605 shareGroupSetupCalls, resourceIDToSetupCalls);
4606 // Save currently bound textures for reset
4607 resetHelper.getResetTextureBindings().emplace(
4608 std::make_pair(bindingIndex, textureType), apiTextureID);
4609 }
4610 }
4611 }
4612
4613 // Capture Texture Environment
4614 if (context->isGLES1())
4615 {
4616 const gl::Caps &caps = context->getCaps();
4617 for (GLuint unit = 0; unit < caps.maxMultitextureUnits; ++unit)
4618 {
4619 CaptureTextureEnvironmentState(setupCalls, &replayState, &apiState, unit);
4620 }
4621 }
4622
4623 // Set active Texture.
4624 if (replayState.getActiveSampler() != apiState.getActiveSampler())
4625 {
4626 cap(CaptureActiveTexture(replayState, true,
4627 GL_TEXTURE0 + static_cast<GLenum>(apiState.getActiveSampler())));
4628 replayState.getMutablePrivateStateForCapture()->setActiveSampler(
4629 apiState.getActiveSampler());
4630 }
4631
4632 // Set Renderbuffer binding.
4633 FramebufferCaptureFuncs framebufferFuncs(context->isGLES1());
4634
4635 const gl::RenderbufferManager &renderbuffers = apiState.getRenderbufferManagerForCapture();
4636 gl::RenderbufferID currentRenderbuffer = {0};
4637 for (const auto &renderbufIter :
4638 gl::UnsafeResourceMapIter(renderbuffers.getResourcesForCapture()))
4639 {
4640 currentRenderbuffer = renderbufIter.second->id();
4641 }
4642
4643 if (currentRenderbuffer != apiState.getRenderbufferId())
4644 {
4645 cap(framebufferFuncs.bindRenderbuffer(replayState, true, GL_RENDERBUFFER,
4646 apiState.getRenderbufferId()));
4647 }
4648
4649 // Capture Framebuffers.
4650 const gl::FramebufferManager &framebuffers = apiState.getFramebufferManagerForCapture();
4651
4652 gl::FramebufferID currentDrawFramebuffer = {0};
4653 gl::FramebufferID currentReadFramebuffer = {0};
4654
4655 for (const auto &framebufferIter :
4656 gl::UnsafeResourceMapIter(framebuffers.getResourcesForCapture()))
4657 {
4658 gl::FramebufferID id = {framebufferIter.first};
4659 const gl::Framebuffer *framebuffer = framebufferIter.second;
4660
4661 // The default Framebuffer exists (by default).
4662 if (framebuffer->isDefault())
4663 {
4664 continue;
4665 }
4666
4667 // Track this as a starting resource that may need to be restored
4668 TrackedResource &trackedFramebuffers =
4669 resourceTracker->getTrackedResource(context->id(), ResourceIDType::Framebuffer);
4670 ResourceSet &startingFramebuffers = trackedFramebuffers.getStartingResources();
4671 startingFramebuffers.insert(id.value);
4672
4673 // Create two lists of calls for initial setup
4674 ResourceCalls &framebufferRegenCalls = trackedFramebuffers.getResourceRegenCalls();
4675 CallVector framebufferGenCalls({setupCalls, &framebufferRegenCalls[id.value]});
4676
4677 // Gen the framebuffer
4678 for (std::vector<CallCapture> *calls : framebufferGenCalls)
4679 {
4680 Capture(calls, framebufferFuncs.genFramebuffers(replayState, true, 1, &id));
4681 MaybeCaptureUpdateResourceIDs(context, resourceTracker, calls);
4682 }
4683
4684 // Create two lists of calls for remaining setup calls. One for setup, and one for restore
4685 // during reset.
4686 ResourceCalls &framebufferRestoreCalls = trackedFramebuffers.getResourceRestoreCalls();
4687 CallVector framebufferSetupCalls({setupCalls, &framebufferRestoreCalls[id.value]});
4688
4689 for (std::vector<CallCapture> *calls : framebufferSetupCalls)
4690 {
4691 CaptureBindFramebufferForContext(context, calls, framebufferFuncs, replayState,
4692 GL_FRAMEBUFFER, id);
4693 }
4694 currentDrawFramebuffer = currentReadFramebuffer = id;
4695
4696 // Color Attachments.
4697 for (const gl::FramebufferAttachment &colorAttachment : framebuffer->getColorAttachments())
4698 {
4699 if (!colorAttachment.isAttached())
4700 {
4701 continue;
4702 }
4703
4704 for (std::vector<CallCapture> *calls : framebufferSetupCalls)
4705 {
4706 CaptureFramebufferAttachment(calls, replayState, framebufferFuncs, colorAttachment,
4707 shareGroupSetupCalls, resourceIDToSetupCalls);
4708 }
4709 }
4710
4711 const gl::FramebufferAttachment *depthAttachment = framebuffer->getDepthAttachment();
4712 if (depthAttachment)
4713 {
4714 ASSERT(depthAttachment->getBinding() == GL_DEPTH_ATTACHMENT ||
4715 depthAttachment->getBinding() == GL_DEPTH_STENCIL_ATTACHMENT);
4716 for (std::vector<CallCapture> *calls : framebufferSetupCalls)
4717 {
4718 CaptureFramebufferAttachment(calls, replayState, framebufferFuncs, *depthAttachment,
4719 shareGroupSetupCalls, resourceIDToSetupCalls);
4720 }
4721 }
4722
4723 const gl::FramebufferAttachment *stencilAttachment = framebuffer->getStencilAttachment();
4724 if (stencilAttachment)
4725 {
4726 ASSERT(stencilAttachment->getBinding() == GL_STENCIL_ATTACHMENT ||
4727 depthAttachment->getBinding() == GL_DEPTH_STENCIL_ATTACHMENT);
4728 for (std::vector<CallCapture> *calls : framebufferSetupCalls)
4729 {
4730 CaptureFramebufferAttachment(calls, replayState, framebufferFuncs,
4731 *stencilAttachment, shareGroupSetupCalls,
4732 resourceIDToSetupCalls);
4733 }
4734 }
4735
4736 gl::FramebufferState defaultFramebufferState(
4737 context->getCaps(), framebuffer->getState().id(),
4738 framebuffer->getState().getFramebufferSerial());
4739 const gl::DrawBuffersVector<GLenum> &defaultDrawBufferStates =
4740 defaultFramebufferState.getDrawBufferStates();
4741 const gl::DrawBuffersVector<GLenum> &drawBufferStates = framebuffer->getDrawBufferStates();
4742
4743 if (drawBufferStates != defaultDrawBufferStates)
4744 {
4745 for (std::vector<CallCapture> *calls : framebufferSetupCalls)
4746 {
4747 Capture(calls, CaptureDrawBuffers(replayState, true,
4748 static_cast<GLsizei>(drawBufferStates.size()),
4749 drawBufferStates.data()));
4750 }
4751 }
4752 }
4753
4754 // Capture framebuffer bindings.
4755 if (apiState.getDrawFramebuffer())
4756 {
4757 ASSERT(apiState.getReadFramebuffer());
4758 gl::FramebufferID stateReadFramebuffer = apiState.getReadFramebuffer()->id();
4759 gl::FramebufferID stateDrawFramebuffer = apiState.getDrawFramebuffer()->id();
4760 if (stateDrawFramebuffer == stateReadFramebuffer)
4761 {
4762 if (currentDrawFramebuffer != stateDrawFramebuffer ||
4763 currentReadFramebuffer != stateReadFramebuffer)
4764 {
4765 CaptureBindFramebufferForContext(context, setupCalls, framebufferFuncs, replayState,
4766 GL_FRAMEBUFFER, stateDrawFramebuffer);
4767 currentDrawFramebuffer = currentReadFramebuffer = stateDrawFramebuffer;
4768 }
4769 }
4770 else
4771 {
4772 if (currentDrawFramebuffer != stateDrawFramebuffer)
4773 {
4774 CaptureBindFramebufferForContext(context, setupCalls, framebufferFuncs, replayState,
4775 GL_DRAW_FRAMEBUFFER, stateDrawFramebuffer);
4776 currentDrawFramebuffer = stateDrawFramebuffer;
4777 }
4778
4779 if (currentReadFramebuffer != stateReadFramebuffer)
4780 {
4781 CaptureBindFramebufferForContext(context, setupCalls, framebufferFuncs, replayState,
4782 GL_READ_FRAMEBUFFER, stateReadFramebuffer);
4783 currentReadFramebuffer = stateReadFramebuffer;
4784 }
4785 }
4786 }
4787
4788 // Capture Program Pipelines
4789 const gl::ProgramPipelineManager *programPipelineManager =
4790 apiState.getProgramPipelineManagerForCapture();
4791
4792 for (const auto &ppoIterator :
4793 gl::UnsafeResourceMapIter(programPipelineManager->getResourcesForCapture()))
4794 {
4795 gl::ProgramPipeline *pipeline = ppoIterator.second;
4796 gl::ProgramPipelineID id = {ppoIterator.first};
4797 cap(CaptureGenProgramPipelines(replayState, true, 1, &id));
4798 MaybeCaptureUpdateResourceIDs(context, resourceTracker, setupCalls);
4799
4800 // PPOs can contain graphics and compute programs, so loop through all shader types rather
4801 // than just the linked ones since getLinkedShaderStages() will return either only graphics
4802 // or compute stages.
4803 for (gl::ShaderType shaderType : gl::AllShaderTypes())
4804 {
4805 const gl::Program *program = pipeline->getShaderProgram(shaderType);
4806 if (!program)
4807 {
4808 continue;
4809 }
4810 ASSERT(program->isLinked());
4811 GLbitfield gLbitfield = GetBitfieldFromShaderType(shaderType);
4812 cap(CaptureUseProgramStages(replayState, true, pipeline->id(), gLbitfield,
4813 program->id()));
4814
4815 // Set this program as active so it will be generated in Setup
4816 // Note: We aren't filtering ProgramPipelines, so this could be setting programs
4817 // active that aren't actually used.
4818 MarkResourceIDActive(ResourceIDType::ShaderProgram, program->id().value,
4819 shareGroupSetupCalls, resourceIDToSetupCalls);
4820 }
4821
4822 gl::Program *program = pipeline->getActiveShaderProgram();
4823 if (program)
4824 {
4825 cap(CaptureActiveShaderProgram(replayState, true, id, program->id()));
4826 }
4827 }
4828
4829 // For now we assume the installed program executable is the same as the current program.
4830 // TODO(jmadill): Handle installed program executable. http://anglebug.com/42262323
4831 if (!context->isGLES1())
4832 {
4833 // If we have a program bound in the API, or if there is no program bound to the API at
4834 // time of capture and we bound a program for uniform updates during MEC, we must add
4835 // a set program call to replay the correct states.
4836 GLuint currentProgram = 0;
4837 if (apiState.getProgram())
4838 {
4839 cap(CaptureUseProgram(replayState, true, apiState.getProgram()->id()));
4840 CaptureUpdateCurrentProgram(setupCalls->back(), 0, setupCalls);
4841 (void)replayState.setProgram(context, apiState.getProgram());
4842
4843 // Set this program as active so it will be generated in Setup
4844 MarkResourceIDActive(ResourceIDType::ShaderProgram, apiState.getProgram()->id().value,
4845 shareGroupSetupCalls, resourceIDToSetupCalls);
4846
4847 currentProgram = apiState.getProgram()->id().value;
4848 }
4849 else if (replayState.getProgram())
4850 {
4851 cap(CaptureUseProgram(replayState, true, {0}));
4852 CaptureUpdateCurrentProgram(setupCalls->back(), 0, setupCalls);
4853 (void)replayState.setProgram(context, nullptr);
4854 }
4855
4856 // Track the calls necessary to reset active program back to initial state
4857 Capture(&resetCalls[angle::EntryPoint::GLUseProgram],
4858 CaptureUseProgram(replayState, true, {currentProgram}));
4859 CaptureUpdateCurrentProgram((&resetCalls[angle::EntryPoint::GLUseProgram])->back(), 0,
4860 &resetCalls[angle::EntryPoint::GLUseProgram]);
4861
4862 // Same for program pipelines as for programs, see comment above.
4863 if (apiState.getProgramPipeline())
4864 {
4865 cap(CaptureBindProgramPipeline(replayState, true, apiState.getProgramPipeline()->id()));
4866 }
4867 else if (replayState.getProgramPipeline())
4868 {
4869 cap(CaptureBindProgramPipeline(replayState, true, {0}));
4870 }
4871 }
4872
4873 // Capture Queries
4874 const gl::QueryMap &queryMap = context->getQueriesForCapture();
4875
4876 // Create existing queries. Note that queries may be genned and not yet started. In that
4877 // case the queries will exist in the query map as nullptr entries.
4878 // If any queries are active between frames, we want to defer creation and do them last,
4879 // otherwise you'll get GL errors about starting a query while one is already active.
4880 for (gl::QueryMap::Iterator queryIter = gl::UnsafeResourceMapIter(queryMap).beginWithNull(),
4881 endIter = gl::UnsafeResourceMapIter(queryMap).endWithNull();
4882 queryIter != endIter; ++queryIter)
4883 {
4884 ASSERT(queryIter->first);
4885 gl::QueryID queryID = {queryIter->first};
4886
4887 cap(CaptureGenQueries(replayState, true, 1, &queryID));
4888 MaybeCaptureUpdateResourceIDs(context, resourceTracker, setupCalls);
4889
4890 gl::Query *query = queryIter->second;
4891 if (query)
4892 {
4893 gl::QueryType queryType = query->getType();
4894
4895 // Defer active queries until we've created them all
4896 if (IsQueryActive(apiState, queryID))
4897 {
4898 continue;
4899 }
4900
4901 // Begin the query to generate the object
4902 cap(CaptureBeginQuery(replayState, true, queryType, queryID));
4903
4904 // End the query if it was not active
4905 cap(CaptureEndQuery(replayState, true, queryType));
4906 }
4907 }
4908
4909 const gl::ActiveQueryMap &activeQueries = apiState.getActiveQueriesForCapture();
4910 for (const auto &activeQueryIter : activeQueries)
4911 {
4912 const gl::Query *activeQuery = activeQueryIter.get();
4913 if (activeQuery)
4914 {
4915 cap(CaptureBeginQuery(replayState, true, activeQuery->getType(), activeQuery->id()));
4916 }
4917 }
4918
4919 // Transform Feedback
4920 const gl::TransformFeedbackMap &xfbMap = context->getTransformFeedbacksForCapture();
4921 for (const auto &xfbIter : gl::UnsafeResourceMapIter(xfbMap))
4922 {
4923 gl::TransformFeedbackID xfbID = {xfbIter.first};
4924
4925 // Do not capture the default XFB object.
4926 if (xfbID.value == 0)
4927 {
4928 continue;
4929 }
4930
4931 cap(CaptureGenTransformFeedbacks(replayState, true, 1, &xfbID));
4932 MaybeCaptureUpdateResourceIDs(context, resourceTracker, setupCalls);
4933
4934 gl::TransformFeedback *xfb = xfbIter.second;
4935 if (!xfb)
4936 {
4937 // The object was never created
4938 continue;
4939 }
4940
4941 // Bind XFB to create the object
4942 cap(CaptureBindTransformFeedback(replayState, true, GL_TRANSFORM_FEEDBACK, xfbID));
4943
4944 // Bind the buffers associated with this XFB object
4945 for (size_t i = 0; i < xfb->getIndexedBufferCount(); ++i)
4946 {
4947 const gl::OffsetBindingPointer<gl::Buffer> &xfbBuffer = xfb->getIndexedBuffer(i);
4948
4949 // Note: Buffers bound with BindBufferBase can be used with BindBuffer
4950 cap(CaptureBindBufferRange(replayState, true, gl::BufferBinding::TransformFeedback, 0,
4951 xfbBuffer.id(), xfbBuffer.getOffset(), xfbBuffer.getSize()));
4952 }
4953
4954 if (xfb->isActive() || xfb->isPaused())
4955 {
4956 // We don't support active XFB in MEC yet
4957 UNIMPLEMENTED();
4958 }
4959 }
4960
4961 // Bind the current XFB buffer after populating XFB objects
4962 gl::TransformFeedback *currentXFB = apiState.getCurrentTransformFeedback();
4963 if (currentXFB)
4964 {
4965 cap(CaptureBindTransformFeedback(replayState, true, GL_TRANSFORM_FEEDBACK,
4966 currentXFB->id()));
4967 }
4968
4969 // Bind samplers
4970 const gl::SamplerBindingVector &samplerBindings = apiState.getSamplers();
4971 for (GLuint bindingIndex = 0; bindingIndex < static_cast<GLuint>(samplerBindings.size());
4972 ++bindingIndex)
4973 {
4974 gl::SamplerID samplerID = samplerBindings[bindingIndex].id();
4975 if (samplerID.value != 0)
4976 {
4977 cap(CaptureBindSampler(replayState, true, bindingIndex, samplerID));
4978 }
4979 }
4980
4981 // Capture Image Texture bindings
4982 const std::vector<gl::ImageUnit> &imageUnits = apiState.getImageUnits();
4983 for (GLuint bindingIndex = 0; bindingIndex < static_cast<GLuint>(imageUnits.size());
4984 ++bindingIndex)
4985 {
4986 const gl::ImageUnit &imageUnit = imageUnits[bindingIndex];
4987
4988 if (imageUnit.texture == 0)
4989 {
4990 continue;
4991 }
4992
4993 cap(CaptureBindImageTexture(replayState, true, bindingIndex, imageUnit.texture.id(),
4994 imageUnit.level, imageUnit.layered, imageUnit.layer,
4995 imageUnit.access, imageUnit.format));
4996 }
4997
4998 // Capture GL Context states.
4999 auto capCap = [cap, &replayState](GLenum capEnum, bool capValue) {
5000 if (capValue)
5001 {
5002 cap(CaptureEnable(replayState, true, capEnum));
5003 }
5004 else
5005 {
5006 cap(CaptureDisable(replayState, true, capEnum));
5007 }
5008 };
5009
5010 // Capture GLES1 context states.
5011 if (context->isGLES1())
5012 {
5013 const bool currentTextureState = apiState.getEnableFeature(GL_TEXTURE_2D);
5014 const bool defaultTextureState = replayState.getEnableFeature(GL_TEXTURE_2D);
5015 if (currentTextureState != defaultTextureState)
5016 {
5017 capCap(GL_TEXTURE_2D, currentTextureState);
5018 }
5019
5020 cap(CaptureMatrixMode(replayState, true, gl::MatrixType::Projection));
5021 for (angle::Mat4 projectionMatrix :
5022 apiState.gles1().getMatrixStack(gl::MatrixType::Projection))
5023 {
5024 cap(CapturePushMatrix(replayState, true));
5025 cap(CaptureLoadMatrixf(replayState, true, projectionMatrix.elements().data()));
5026 }
5027
5028 cap(CaptureMatrixMode(replayState, true, gl::MatrixType::Modelview));
5029 for (angle::Mat4 modelViewMatrix :
5030 apiState.gles1().getMatrixStack(gl::MatrixType::Modelview))
5031 {
5032 cap(CapturePushMatrix(replayState, true));
5033 cap(CaptureLoadMatrixf(replayState, true, modelViewMatrix.elements().data()));
5034 }
5035
5036 gl::MatrixType currentMatrixMode = apiState.gles1().getMatrixMode();
5037 if (currentMatrixMode != gl::MatrixType::Modelview)
5038 {
5039 cap(CaptureMatrixMode(replayState, true, currentMatrixMode));
5040 }
5041
5042 // Alpha Test state
5043 const bool currentAlphaTestState = apiState.getEnableFeature(GL_ALPHA_TEST);
5044 const bool defaultAlphaTestState = replayState.getEnableFeature(GL_ALPHA_TEST);
5045
5046 if (currentAlphaTestState != defaultAlphaTestState)
5047 {
5048 capCap(GL_ALPHA_TEST, currentAlphaTestState);
5049 }
5050
5051 const gl::AlphaTestParameters currentAlphaTestParameters =
5052 apiState.gles1().getAlphaTestParameters();
5053 const gl::AlphaTestParameters defaultAlphaTestParameters =
5054 replayState.gles1().getAlphaTestParameters();
5055
5056 if (currentAlphaTestParameters != defaultAlphaTestParameters)
5057 {
5058 cap(CaptureAlphaFunc(replayState, true, currentAlphaTestParameters.func,
5059 currentAlphaTestParameters.ref));
5060 }
5061 }
5062
5063 // Rasterizer state. Missing ES 3.x features.
5064 const gl::RasterizerState &defaultRasterState = replayState.getRasterizerState();
5065 const gl::RasterizerState ¤tRasterState = apiState.getRasterizerState();
5066 if (currentRasterState.cullFace != defaultRasterState.cullFace)
5067 {
5068 capCap(GL_CULL_FACE, currentRasterState.cullFace);
5069 }
5070
5071 if (currentRasterState.cullMode != defaultRasterState.cullMode)
5072 {
5073 cap(CaptureCullFace(replayState, true, currentRasterState.cullMode));
5074 }
5075
5076 if (currentRasterState.frontFace != defaultRasterState.frontFace)
5077 {
5078 cap(CaptureFrontFace(replayState, true, currentRasterState.frontFace));
5079 }
5080
5081 if (currentRasterState.polygonMode != defaultRasterState.polygonMode)
5082 {
5083 if (context->getExtensions().polygonModeNV)
5084 {
5085 cap(CapturePolygonModeNV(replayState, true, GL_FRONT_AND_BACK,
5086 currentRasterState.polygonMode));
5087 }
5088 else if (context->getExtensions().polygonModeANGLE)
5089 {
5090 cap(CapturePolygonModeANGLE(replayState, true, GL_FRONT_AND_BACK,
5091 currentRasterState.polygonMode));
5092 }
5093 else
5094 {
5095 UNREACHABLE();
5096 }
5097 }
5098
5099 if (currentRasterState.polygonOffsetPoint != defaultRasterState.polygonOffsetPoint)
5100 {
5101 capCap(GL_POLYGON_OFFSET_POINT_NV, currentRasterState.polygonOffsetPoint);
5102 }
5103
5104 if (currentRasterState.polygonOffsetLine != defaultRasterState.polygonOffsetLine)
5105 {
5106 capCap(GL_POLYGON_OFFSET_LINE_NV, currentRasterState.polygonOffsetLine);
5107 }
5108
5109 if (currentRasterState.polygonOffsetFill != defaultRasterState.polygonOffsetFill)
5110 {
5111 capCap(GL_POLYGON_OFFSET_FILL, currentRasterState.polygonOffsetFill);
5112 }
5113
5114 if (currentRasterState.polygonOffsetFactor != defaultRasterState.polygonOffsetFactor ||
5115 currentRasterState.polygonOffsetUnits != defaultRasterState.polygonOffsetUnits ||
5116 currentRasterState.polygonOffsetClamp != defaultRasterState.polygonOffsetClamp)
5117 {
5118 if (currentRasterState.polygonOffsetClamp == 0.0f)
5119 {
5120 cap(CapturePolygonOffset(replayState, true, currentRasterState.polygonOffsetFactor,
5121 currentRasterState.polygonOffsetUnits));
5122 }
5123 else
5124 {
5125 cap(CapturePolygonOffsetClampEXT(
5126 replayState, true, currentRasterState.polygonOffsetFactor,
5127 currentRasterState.polygonOffsetUnits, currentRasterState.polygonOffsetClamp));
5128 }
5129 }
5130
5131 if (currentRasterState.depthClamp != defaultRasterState.depthClamp)
5132 {
5133 capCap(GL_DEPTH_CLAMP_EXT, currentRasterState.depthClamp);
5134 }
5135
5136 // pointDrawMode/multiSample are only used in the D3D back-end right now.
5137
5138 if (currentRasterState.rasterizerDiscard != defaultRasterState.rasterizerDiscard)
5139 {
5140 capCap(GL_RASTERIZER_DISCARD, currentRasterState.rasterizerDiscard);
5141 }
5142
5143 if (currentRasterState.dither != defaultRasterState.dither)
5144 {
5145 capCap(GL_DITHER, currentRasterState.dither);
5146 }
5147
5148 // Depth/stencil state.
5149 const gl::DepthStencilState &defaultDSState = replayState.getDepthStencilState();
5150 const gl::DepthStencilState ¤tDSState = apiState.getDepthStencilState();
5151 if (defaultDSState.depthFunc != currentDSState.depthFunc)
5152 {
5153 cap(CaptureDepthFunc(replayState, true, currentDSState.depthFunc));
5154 }
5155
5156 if (defaultDSState.depthMask != currentDSState.depthMask)
5157 {
5158 cap(CaptureDepthMask(replayState, true, gl::ConvertToGLBoolean(currentDSState.depthMask)));
5159 }
5160
5161 if (defaultDSState.depthTest != currentDSState.depthTest)
5162 {
5163 capCap(GL_DEPTH_TEST, currentDSState.depthTest);
5164 }
5165
5166 if (defaultDSState.stencilTest != currentDSState.stencilTest)
5167 {
5168 capCap(GL_STENCIL_TEST, currentDSState.stencilTest);
5169 }
5170
5171 if (currentDSState.stencilFunc == currentDSState.stencilBackFunc &&
5172 currentDSState.stencilMask == currentDSState.stencilBackMask)
5173 {
5174 // Front and back are equal
5175 if (defaultDSState.stencilFunc != currentDSState.stencilFunc ||
5176 defaultDSState.stencilMask != currentDSState.stencilMask ||
5177 apiState.getStencilRef() != 0)
5178 {
5179 cap(CaptureStencilFunc(replayState, true, currentDSState.stencilFunc,
5180 apiState.getStencilRef(), currentDSState.stencilMask));
5181 }
5182 }
5183 else
5184 {
5185 // Front and back are separate
5186 if (defaultDSState.stencilFunc != currentDSState.stencilFunc ||
5187 defaultDSState.stencilMask != currentDSState.stencilMask ||
5188 apiState.getStencilRef() != 0)
5189 {
5190 cap(CaptureStencilFuncSeparate(replayState, true, GL_FRONT, currentDSState.stencilFunc,
5191 apiState.getStencilRef(), currentDSState.stencilMask));
5192 }
5193
5194 if (defaultDSState.stencilBackFunc != currentDSState.stencilBackFunc ||
5195 defaultDSState.stencilBackMask != currentDSState.stencilBackMask ||
5196 apiState.getStencilBackRef() != 0)
5197 {
5198 cap(CaptureStencilFuncSeparate(
5199 replayState, true, GL_BACK, currentDSState.stencilBackFunc,
5200 apiState.getStencilBackRef(), currentDSState.stencilBackMask));
5201 }
5202 }
5203
5204 if (currentDSState.stencilFail == currentDSState.stencilBackFail &&
5205 currentDSState.stencilPassDepthFail == currentDSState.stencilBackPassDepthFail &&
5206 currentDSState.stencilPassDepthPass == currentDSState.stencilBackPassDepthPass)
5207 {
5208 // Front and back are equal
5209 if (defaultDSState.stencilFail != currentDSState.stencilFail ||
5210 defaultDSState.stencilPassDepthFail != currentDSState.stencilPassDepthFail ||
5211 defaultDSState.stencilPassDepthPass != currentDSState.stencilPassDepthPass)
5212 {
5213 cap(CaptureStencilOp(replayState, true, currentDSState.stencilFail,
5214 currentDSState.stencilPassDepthFail,
5215 currentDSState.stencilPassDepthPass));
5216 }
5217 }
5218 else
5219 {
5220 // Front and back are separate
5221 if (defaultDSState.stencilFail != currentDSState.stencilFail ||
5222 defaultDSState.stencilPassDepthFail != currentDSState.stencilPassDepthFail ||
5223 defaultDSState.stencilPassDepthPass != currentDSState.stencilPassDepthPass)
5224 {
5225 cap(CaptureStencilOpSeparate(replayState, true, GL_FRONT, currentDSState.stencilFail,
5226 currentDSState.stencilPassDepthFail,
5227 currentDSState.stencilPassDepthPass));
5228 }
5229
5230 if (defaultDSState.stencilBackFail != currentDSState.stencilBackFail ||
5231 defaultDSState.stencilBackPassDepthFail != currentDSState.stencilBackPassDepthFail ||
5232 defaultDSState.stencilBackPassDepthPass != currentDSState.stencilBackPassDepthPass)
5233 {
5234 cap(CaptureStencilOpSeparate(replayState, true, GL_BACK, currentDSState.stencilBackFail,
5235 currentDSState.stencilBackPassDepthFail,
5236 currentDSState.stencilBackPassDepthPass));
5237 }
5238 }
5239
5240 if (currentDSState.stencilWritemask == currentDSState.stencilBackWritemask)
5241 {
5242 // Front and back are equal
5243 if (defaultDSState.stencilWritemask != currentDSState.stencilWritemask)
5244 {
5245 cap(CaptureStencilMask(replayState, true, currentDSState.stencilWritemask));
5246 }
5247 }
5248 else
5249 {
5250 // Front and back are separate
5251 if (defaultDSState.stencilWritemask != currentDSState.stencilWritemask)
5252 {
5253 cap(CaptureStencilMaskSeparate(replayState, true, GL_FRONT,
5254 currentDSState.stencilWritemask));
5255 }
5256
5257 if (defaultDSState.stencilBackWritemask != currentDSState.stencilBackWritemask)
5258 {
5259 cap(CaptureStencilMaskSeparate(replayState, true, GL_BACK,
5260 currentDSState.stencilBackWritemask));
5261 }
5262 }
5263
5264 // Blend state.
5265 const gl::BlendState &defaultBlendState = replayState.getBlendState();
5266 const gl::BlendState ¤tBlendState = apiState.getBlendState();
5267
5268 if (currentBlendState.blend != defaultBlendState.blend)
5269 {
5270 capCap(GL_BLEND, currentBlendState.blend);
5271 }
5272
5273 if (currentBlendState.sourceBlendRGB != defaultBlendState.sourceBlendRGB ||
5274 currentBlendState.destBlendRGB != defaultBlendState.destBlendRGB ||
5275 currentBlendState.sourceBlendAlpha != defaultBlendState.sourceBlendAlpha ||
5276 currentBlendState.destBlendAlpha != defaultBlendState.destBlendAlpha)
5277 {
5278 if (context->isGLES1())
5279 {
5280 // Even though their states are tracked independently, in GLES1 blendAlpha
5281 // and blendRGB cannot be set separately and are always equal
5282 cap(CaptureBlendFunc(replayState, true, currentBlendState.sourceBlendRGB,
5283 currentBlendState.destBlendRGB));
5284 Capture(&resetCalls[angle::EntryPoint::GLBlendFunc],
5285 CaptureBlendFunc(replayState, true, currentBlendState.sourceBlendRGB,
5286 currentBlendState.destBlendRGB));
5287 }
5288 else
5289 {
5290 // Always use BlendFuncSeparate for non-GLES1 as it covers all cases
5291 cap(CaptureBlendFuncSeparate(
5292 replayState, true, currentBlendState.sourceBlendRGB, currentBlendState.destBlendRGB,
5293 currentBlendState.sourceBlendAlpha, currentBlendState.destBlendAlpha));
5294 Capture(&resetCalls[angle::EntryPoint::GLBlendFuncSeparate],
5295 CaptureBlendFuncSeparate(replayState, true, currentBlendState.sourceBlendRGB,
5296 currentBlendState.destBlendRGB,
5297 currentBlendState.sourceBlendAlpha,
5298 currentBlendState.destBlendAlpha));
5299 }
5300 }
5301
5302 if (currentBlendState.blendEquationRGB != defaultBlendState.blendEquationRGB ||
5303 currentBlendState.blendEquationAlpha != defaultBlendState.blendEquationAlpha)
5304 {
5305 // Similarly to BlendFunc, using BlendEquation in some cases complicates Reset.
5306 cap(CaptureBlendEquationSeparate(replayState, true, currentBlendState.blendEquationRGB,
5307 currentBlendState.blendEquationAlpha));
5308 Capture(&resetCalls[angle::EntryPoint::GLBlendEquationSeparate],
5309 CaptureBlendEquationSeparate(replayState, true, currentBlendState.blendEquationRGB,
5310 currentBlendState.blendEquationAlpha));
5311 }
5312
5313 if (currentBlendState.colorMaskRed != defaultBlendState.colorMaskRed ||
5314 currentBlendState.colorMaskGreen != defaultBlendState.colorMaskGreen ||
5315 currentBlendState.colorMaskBlue != defaultBlendState.colorMaskBlue ||
5316 currentBlendState.colorMaskAlpha != defaultBlendState.colorMaskAlpha)
5317 {
5318 cap(CaptureColorMask(replayState, true,
5319 gl::ConvertToGLBoolean(currentBlendState.colorMaskRed),
5320 gl::ConvertToGLBoolean(currentBlendState.colorMaskGreen),
5321 gl::ConvertToGLBoolean(currentBlendState.colorMaskBlue),
5322 gl::ConvertToGLBoolean(currentBlendState.colorMaskAlpha)));
5323 Capture(&resetCalls[angle::EntryPoint::GLColorMask],
5324 CaptureColorMask(replayState, true,
5325 gl::ConvertToGLBoolean(currentBlendState.colorMaskRed),
5326 gl::ConvertToGLBoolean(currentBlendState.colorMaskGreen),
5327 gl::ConvertToGLBoolean(currentBlendState.colorMaskBlue),
5328 gl::ConvertToGLBoolean(currentBlendState.colorMaskAlpha)));
5329 }
5330
5331 const gl::ColorF ¤tBlendColor = apiState.getBlendColor();
5332 if (currentBlendColor != gl::ColorF())
5333 {
5334 cap(CaptureBlendColor(replayState, true, currentBlendColor.red, currentBlendColor.green,
5335 currentBlendColor.blue, currentBlendColor.alpha));
5336 Capture(&resetCalls[angle::EntryPoint::GLBlendColor],
5337 CaptureBlendColor(replayState, true, currentBlendColor.red, currentBlendColor.green,
5338 currentBlendColor.blue, currentBlendColor.alpha));
5339 }
5340
5341 // Pixel storage states.
5342 gl::PixelPackState ¤tPackState = replayState.getPackState();
5343 if (currentPackState.alignment != apiState.getPackAlignment())
5344 {
5345 cap(CapturePixelStorei(replayState, true, GL_PACK_ALIGNMENT, apiState.getPackAlignment()));
5346 currentPackState.alignment = apiState.getPackAlignment();
5347 }
5348
5349 if (currentPackState.rowLength != apiState.getPackRowLength())
5350 {
5351 cap(CapturePixelStorei(replayState, true, GL_PACK_ROW_LENGTH, apiState.getPackRowLength()));
5352 currentPackState.rowLength = apiState.getPackRowLength();
5353 }
5354
5355 if (currentPackState.skipRows != apiState.getPackSkipRows())
5356 {
5357 cap(CapturePixelStorei(replayState, true, GL_PACK_SKIP_ROWS, apiState.getPackSkipRows()));
5358 currentPackState.skipRows = apiState.getPackSkipRows();
5359 }
5360
5361 if (currentPackState.skipPixels != apiState.getPackSkipPixels())
5362 {
5363 cap(CapturePixelStorei(replayState, true, GL_PACK_SKIP_PIXELS,
5364 apiState.getPackSkipPixels()));
5365 currentPackState.skipPixels = apiState.getPackSkipPixels();
5366 }
5367
5368 // We set unpack alignment above, no need to change it here
5369 ASSERT(currentUnpackState.alignment == 1);
5370 if (currentUnpackState.rowLength != apiState.getUnpackRowLength())
5371 {
5372 cap(CapturePixelStorei(replayState, true, GL_UNPACK_ROW_LENGTH,
5373 apiState.getUnpackRowLength()));
5374 currentUnpackState.rowLength = apiState.getUnpackRowLength();
5375 }
5376
5377 if (currentUnpackState.skipRows != apiState.getUnpackSkipRows())
5378 {
5379 cap(CapturePixelStorei(replayState, true, GL_UNPACK_SKIP_ROWS,
5380 apiState.getUnpackSkipRows()));
5381 currentUnpackState.skipRows = apiState.getUnpackSkipRows();
5382 }
5383
5384 if (currentUnpackState.skipPixels != apiState.getUnpackSkipPixels())
5385 {
5386 cap(CapturePixelStorei(replayState, true, GL_UNPACK_SKIP_PIXELS,
5387 apiState.getUnpackSkipPixels()));
5388 currentUnpackState.skipPixels = apiState.getUnpackSkipPixels();
5389 }
5390
5391 if (currentUnpackState.imageHeight != apiState.getUnpackImageHeight())
5392 {
5393 cap(CapturePixelStorei(replayState, true, GL_UNPACK_IMAGE_HEIGHT,
5394 apiState.getUnpackImageHeight()));
5395 currentUnpackState.imageHeight = apiState.getUnpackImageHeight();
5396 }
5397
5398 if (currentUnpackState.skipImages != apiState.getUnpackSkipImages())
5399 {
5400 cap(CapturePixelStorei(replayState, true, GL_UNPACK_SKIP_IMAGES,
5401 apiState.getUnpackSkipImages()));
5402 currentUnpackState.skipImages = apiState.getUnpackSkipImages();
5403 }
5404
5405 // Clear state. Missing ES 3.x features.
5406 // TODO(http://anglebug.com/42262323): Complete state capture.
5407 const gl::ColorF ¤tClearColor = apiState.getColorClearValue();
5408 if (currentClearColor != gl::ColorF())
5409 {
5410 cap(CaptureClearColor(replayState, true, currentClearColor.red, currentClearColor.green,
5411 currentClearColor.blue, currentClearColor.alpha));
5412 }
5413
5414 if (apiState.getDepthClearValue() != 1.0f)
5415 {
5416 cap(CaptureClearDepthf(replayState, true, apiState.getDepthClearValue()));
5417 }
5418
5419 if (apiState.getStencilClearValue() != 0)
5420 {
5421 cap(CaptureClearStencil(replayState, true, apiState.getStencilClearValue()));
5422 }
5423
5424 // Viewport / scissor / clipping planes.
5425 const gl::Rectangle ¤tViewport = apiState.getViewport();
5426 if (currentViewport != gl::Rectangle())
5427 {
5428 cap(CaptureViewport(replayState, true, currentViewport.x, currentViewport.y,
5429 currentViewport.width, currentViewport.height));
5430 }
5431
5432 if (apiState.getNearPlane() != 0.0f || apiState.getFarPlane() != 1.0f)
5433 {
5434 cap(CaptureDepthRangef(replayState, true, apiState.getNearPlane(), apiState.getFarPlane()));
5435 }
5436
5437 if (apiState.getClipOrigin() != gl::ClipOrigin::LowerLeft ||
5438 apiState.getClipDepthMode() != gl::ClipDepthMode::NegativeOneToOne)
5439 {
5440 cap(CaptureClipControlEXT(replayState, true, apiState.getClipOrigin(),
5441 apiState.getClipDepthMode()));
5442 }
5443
5444 if (apiState.isScissorTestEnabled())
5445 {
5446 capCap(GL_SCISSOR_TEST, apiState.isScissorTestEnabled());
5447 }
5448
5449 const gl::Rectangle ¤tScissor = apiState.getScissor();
5450 if (currentScissor != gl::Rectangle())
5451 {
5452 cap(CaptureScissor(replayState, true, currentScissor.x, currentScissor.y,
5453 currentScissor.width, currentScissor.height));
5454 }
5455
5456 // Allow the replayState object to be destroyed conveniently.
5457 replayState.setBufferBinding(context, gl::BufferBinding::Array, nullptr);
5458
5459 // Clean up the replay state.
5460 replayState.reset(context);
5461
5462 GLint contextUnpackAlignment = context->getState().getUnpackState().alignment;
5463 if (currentUnpackState.alignment != contextUnpackAlignment)
5464 {
5465 cap(CapturePixelStorei(replayState, true, GL_UNPACK_ALIGNMENT, contextUnpackAlignment));
5466 replayState.getMutablePrivateStateForCapture()->setUnpackAlignment(contextUnpackAlignment);
5467 }
5468
5469 if (validationEnabled)
5470 {
5471 CaptureValidateSerializedState(context, setupCalls);
5472 }
5473 }
5474
SkipCall(EntryPoint entryPoint)5475 bool SkipCall(EntryPoint entryPoint)
5476 {
5477 switch (entryPoint)
5478 {
5479 case EntryPoint::GLDebugMessageCallback:
5480 case EntryPoint::GLDebugMessageCallbackKHR:
5481 case EntryPoint::GLDebugMessageControl:
5482 case EntryPoint::GLDebugMessageControlKHR:
5483 case EntryPoint::GLDebugMessageInsert:
5484 case EntryPoint::GLDebugMessageInsertKHR:
5485 case EntryPoint::GLGetDebugMessageLog:
5486 case EntryPoint::GLGetDebugMessageLogKHR:
5487 case EntryPoint::GLGetObjectLabel:
5488 case EntryPoint::GLGetObjectLabelEXT:
5489 case EntryPoint::GLGetObjectLabelKHR:
5490 case EntryPoint::GLGetObjectPtrLabelKHR:
5491 case EntryPoint::GLGetPointervKHR:
5492 case EntryPoint::GLInsertEventMarkerEXT:
5493 case EntryPoint::GLLabelObjectEXT:
5494 case EntryPoint::GLObjectLabel:
5495 case EntryPoint::GLObjectLabelKHR:
5496 case EntryPoint::GLObjectPtrLabelKHR:
5497 case EntryPoint::GLPopDebugGroupKHR:
5498 case EntryPoint::GLPopGroupMarkerEXT:
5499 case EntryPoint::GLPushDebugGroupKHR:
5500 case EntryPoint::GLPushGroupMarkerEXT:
5501 // Purposefully skip entry points from:
5502 // - KHR_debug
5503 // - EXT_debug_label
5504 // - EXT_debug_marker
5505 // There is no need to capture these for replaying a trace in our harness
5506 return true;
5507
5508 case EntryPoint::GLGetActiveUniform:
5509 case EntryPoint::GLGetActiveUniformsiv:
5510 // Skip these calls because:
5511 // - We don't use the return values.
5512 // - Active uniform counts can vary between platforms due to cross stage optimizations
5513 // and asking about uniforms above GL_ACTIVE_UNIFORMS triggers errors.
5514 return true;
5515
5516 case EntryPoint::GLGetActiveAttrib:
5517 // Skip these calls because:
5518 // - We don't use the return values.
5519 // - Same as uniforms, the value can vary, asking above GL_ACTIVE_ATTRIBUTES is an error
5520 return true;
5521
5522 case EntryPoint::GLGetActiveUniformBlockiv:
5523 case EntryPoint::GLGetActiveUniformBlockName:
5524 // Skip these calls because:
5525 // - We don't use the return values.
5526 // - It reduces the number of references to the uniform block index map.
5527 return true;
5528
5529 case EntryPoint::EGLChooseConfig:
5530 case EntryPoint::EGLGetProcAddress:
5531 case EntryPoint::EGLGetConfigAttrib:
5532 case EntryPoint::EGLGetConfigs:
5533 case EntryPoint::EGLGetSyncAttrib:
5534 case EntryPoint::EGLGetSyncAttribKHR:
5535 case EntryPoint::EGLQueryContext:
5536 case EntryPoint::EGLQuerySurface:
5537 // Skip these calls because:
5538 // - We don't use the return values.
5539 // - Some EGL types and pointer parameters aren't yet implemented in EGL capture.
5540 return true;
5541
5542 case EntryPoint::EGLPrepareSwapBuffersANGLE:
5543 // Skip this call because:
5544 // - eglPrepareSwapBuffersANGLE is automatically called by eglSwapBuffers
5545 return true;
5546
5547 case EntryPoint::EGLSwapBuffers:
5548 // Skip these calls because:
5549 // - Swap is handled specially by the trace harness.
5550 return true;
5551
5552 default:
5553 break;
5554 }
5555
5556 return false;
5557 }
5558
PageRange(size_t start,size_t end)5559 PageRange::PageRange(size_t start, size_t end) : start(start), end(end) {}
5560 PageRange::~PageRange() = default;
5561
AddressRange()5562 AddressRange::AddressRange() {}
AddressRange(uintptr_t start,size_t size)5563 AddressRange::AddressRange(uintptr_t start, size_t size) : start(start), size(size) {}
5564 AddressRange::~AddressRange() = default;
5565
end()5566 uintptr_t AddressRange::end()
5567 {
5568 return start + size;
5569 }
5570
IsTrackedPerContext(ResourceIDType type)5571 bool IsTrackedPerContext(ResourceIDType type)
5572 {
5573 // This helper function informs us which context-local (not shared) objects are tracked
5574 // with per-context object maps.
5575 if (IsSharedObjectResource(type))
5576 {
5577 return false;
5578 }
5579
5580 // TODO (https://issuetracker.google.com/169868803): Remaining context-local resources (VAOs,
5581 // PPOs, Transform Feedback Objects, and Query Objects) must also tracked per-context. Once all
5582 // per-context resource handling is correctly updated then this function can be replaced with
5583 // !IsSharedObjectResource().
5584 switch (type)
5585 {
5586 case ResourceIDType::Framebuffer:
5587 return true;
5588
5589 default:
5590 return false;
5591 }
5592 }
5593
CoherentBuffer(uintptr_t start,size_t size,size_t pageSize,bool isShadowMemoryEnabled)5594 CoherentBuffer::CoherentBuffer(uintptr_t start,
5595 size_t size,
5596 size_t pageSize,
5597 bool isShadowMemoryEnabled)
5598 : mPageSize(pageSize),
5599 mShadowMemoryEnabled(isShadowMemoryEnabled),
5600 mBufferStart(start),
5601 mShadowMemory(nullptr),
5602 mShadowDirty(false)
5603 {
5604 if (mShadowMemoryEnabled)
5605 {
5606 // Shadow memory needs to have at least the size of one page, to not protect outside.
5607 size_t numShadowPages = (size / pageSize) + 1;
5608 mShadowMemory = AlignedAlloc(numShadowPages * pageSize, pageSize);
5609 ASSERT(mShadowMemory != nullptr);
5610 start = reinterpret_cast<uintptr_t>(mShadowMemory);
5611 }
5612
5613 mRange.start = start;
5614 mRange.size = size;
5615 mProtectionRange.start = rx::roundDownPow2(start, pageSize);
5616
5617 uintptr_t protectionEnd = rx::roundUpPow2(start + size, pageSize);
5618
5619 mProtectionRange.size = protectionEnd - mProtectionRange.start;
5620 mPageCount = mProtectionRange.size / pageSize;
5621
5622 mProtectionStartPage = mProtectionRange.start / mPageSize;
5623 mProtectionEndPage = mProtectionStartPage + mPageCount;
5624
5625 mDirtyPages = std::vector<bool>(mPageCount);
5626 mDirtyPages.assign(mPageCount, true);
5627 }
5628
getDirtyPageRanges()5629 std::vector<PageRange> CoherentBuffer::getDirtyPageRanges()
5630 {
5631 std::vector<PageRange> dirtyPageRanges;
5632
5633 bool inDirty = false;
5634 for (size_t i = 0; i < mPageCount; i++)
5635 {
5636 if (!inDirty && mDirtyPages[i])
5637 {
5638 // Found start of a dirty range
5639 inDirty = true;
5640 // Set end page as last page initially
5641 dirtyPageRanges.push_back(PageRange(i, mPageCount));
5642 }
5643 else if (inDirty && !mDirtyPages[i])
5644 {
5645 // Found end of a dirty range
5646 inDirty = false;
5647 dirtyPageRanges.back().end = i;
5648 }
5649 }
5650
5651 return dirtyPageRanges;
5652 }
5653
getRange()5654 AddressRange CoherentBuffer::getRange()
5655 {
5656 return mRange;
5657 }
5658
getDirtyAddressRange(const PageRange & dirtyPageRange)5659 AddressRange CoherentBuffer::getDirtyAddressRange(const PageRange &dirtyPageRange)
5660 {
5661 AddressRange range;
5662
5663 if (dirtyPageRange.start == 0)
5664 {
5665 // First page, use non page aligned buffer start.
5666 range.start = mRange.start;
5667 }
5668 else
5669 {
5670 range.start = mProtectionRange.start + dirtyPageRange.start * mPageSize;
5671 }
5672
5673 if (dirtyPageRange.end == mPageCount)
5674 {
5675 // Last page, use non page aligned buffer end.
5676 range.size = mRange.end() - range.start;
5677 }
5678 else
5679 {
5680 range.size = (dirtyPageRange.end - dirtyPageRange.start) * mPageSize;
5681 // This occurs when a buffer occupies 2 pages, but is smaller than a page.
5682 if (mRange.end() < range.end())
5683 {
5684 range.size = mRange.end() - range.start;
5685 }
5686 }
5687
5688 // Dirty range must be in buffer
5689 ASSERT(range.start >= mRange.start && mRange.end() >= range.end());
5690
5691 return range;
5692 }
5693
~CoherentBuffer()5694 CoherentBuffer::~CoherentBuffer()
5695 {
5696 if (mShadowMemory != nullptr)
5697 {
5698 AlignedFree(mShadowMemory);
5699 }
5700 }
5701
isDirty()5702 bool CoherentBuffer::isDirty()
5703 {
5704 return std::find(mDirtyPages.begin(), mDirtyPages.end(), true) != mDirtyPages.end();
5705 }
5706
contains(size_t page,size_t * relativePage)5707 bool CoherentBuffer::contains(size_t page, size_t *relativePage)
5708 {
5709 bool isInProtectionRange = page >= mProtectionStartPage && page < mProtectionEndPage;
5710 if (!isInProtectionRange)
5711 {
5712 return false;
5713 }
5714
5715 *relativePage = page - mProtectionStartPage;
5716
5717 ASSERT(page >= mProtectionStartPage);
5718
5719 return true;
5720 }
5721
protectPageRange(const PageRange & pageRange)5722 void CoherentBuffer::protectPageRange(const PageRange &pageRange)
5723 {
5724 for (size_t i = pageRange.start; i < pageRange.end; i++)
5725 {
5726 setDirty(i, false);
5727 }
5728 }
5729
protectAll()5730 void CoherentBuffer::protectAll()
5731 {
5732 for (size_t i = 0; i < mPageCount; i++)
5733 {
5734 setDirty(i, false);
5735 }
5736 }
5737
updateBufferMemory()5738 void CoherentBuffer::updateBufferMemory()
5739 {
5740 memcpy(reinterpret_cast<void *>(mBufferStart), reinterpret_cast<void *>(mRange.start),
5741 mRange.size);
5742 }
5743
updateShadowMemory()5744 void CoherentBuffer::updateShadowMemory()
5745 {
5746 memcpy(reinterpret_cast<void *>(mRange.start), reinterpret_cast<void *>(mBufferStart),
5747 mRange.size);
5748 mShadowDirty = false;
5749 }
5750
setDirty(size_t relativePage,bool dirty)5751 void CoherentBuffer::setDirty(size_t relativePage, bool dirty)
5752 {
5753 if (mDirtyPages[relativePage] == dirty)
5754 {
5755 // The page is already set.
5756 // This can happen when tracked buffers overlap in a page.
5757 return;
5758 }
5759
5760 uintptr_t pageStart = mProtectionRange.start + relativePage * mPageSize;
5761
5762 // Last page end must be the same as protection end
5763 if (relativePage + 1 == mPageCount)
5764 {
5765 ASSERT(mProtectionRange.end() == pageStart + mPageSize);
5766 }
5767
5768 bool ret;
5769 if (dirty)
5770 {
5771 ret = UnprotectMemory(pageStart, mPageSize);
5772 }
5773 else
5774 {
5775 ret = ProtectMemory(pageStart, mPageSize);
5776 }
5777
5778 if (!ret)
5779 {
5780 ERR() << "Could not set protection for buffer page " << relativePage << " at "
5781 << reinterpret_cast<void *>(pageStart) << " with size " << mPageSize;
5782 }
5783 mDirtyPages[relativePage] = dirty;
5784 }
5785
removeProtection(PageSharingType sharingType)5786 void CoherentBuffer::removeProtection(PageSharingType sharingType)
5787 {
5788 uintptr_t start = mProtectionRange.start;
5789 size_t size = mProtectionRange.size;
5790
5791 switch (sharingType)
5792 {
5793 case PageSharingType::FirstShared:
5794 case PageSharingType::FirstAndLastShared:
5795 start += mPageSize;
5796 break;
5797 default:
5798 break;
5799 }
5800
5801 switch (sharingType)
5802 {
5803 case PageSharingType::FirstShared:
5804 case PageSharingType::LastShared:
5805 size -= mPageSize;
5806 break;
5807 case PageSharingType::FirstAndLastShared:
5808 size -= (2 * mPageSize);
5809 break;
5810 default:
5811 break;
5812 }
5813
5814 if (size == 0)
5815 {
5816 return;
5817 }
5818
5819 if (!UnprotectMemory(start, size))
5820 {
5821 ERR() << "Could not remove protection for buffer at " << start << " with size " << size;
5822 }
5823 }
5824
canProtectDirectly(gl::Context * context)5825 bool CoherentBufferTracker::canProtectDirectly(gl::Context *context)
5826 {
5827 gl::BufferID bufferId = context->createBuffer();
5828
5829 gl::BufferBinding targetPacked = gl::BufferBinding::Array;
5830 context->bindBuffer(targetPacked, bufferId);
5831
5832 // Allocate 2 pages so we will always have a full aligned page to protect
5833 GLsizei size = static_cast<GLsizei>(mPageSize * 2);
5834
5835 context->bufferStorage(targetPacked, size, nullptr,
5836 GL_DYNAMIC_STORAGE_BIT_EXT | GL_MAP_WRITE_BIT |
5837 GL_MAP_PERSISTENT_BIT_EXT | GL_MAP_COHERENT_BIT_EXT);
5838
5839 gl::Buffer *buffer = context->getBuffer(bufferId);
5840
5841 angle::Result result = buffer->mapRange(
5842 context, 0, size, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT_EXT | GL_MAP_COHERENT_BIT_EXT);
5843 if (result != angle::Result::Continue)
5844 {
5845 ERR() << "Failed to mapRange of buffer.";
5846 }
5847
5848 void *map = buffer->getMapPointer();
5849 if (map == nullptr)
5850 {
5851 ERR() << "Failed to getMapPointer of buffer.";
5852 }
5853
5854 // Test mprotect
5855 auto start = reinterpret_cast<uintptr_t>(map);
5856
5857 // Only protect a whole page inside the allocated memory
5858 uintptr_t protectionStart = rx::roundUpPow2(start, mPageSize);
5859 uintptr_t protectionEnd = protectionStart + mPageSize;
5860
5861 ASSERT(protectionStart < protectionEnd);
5862
5863 angle::PageFaultCallback callback = [](uintptr_t address) {
5864 return angle::PageFaultHandlerRangeType::InRange;
5865 };
5866
5867 std::unique_ptr<angle::PageFaultHandler> handler(CreatePageFaultHandler(callback));
5868
5869 if (!handler->enable())
5870 {
5871 GLboolean unmapResult;
5872 if (buffer->unmap(context, &unmapResult) != angle::Result::Continue)
5873 {
5874 ERR() << "Could not unmap buffer.";
5875 }
5876 context->bindBuffer(targetPacked, {0});
5877
5878 // Page fault handler could not be enabled, memory can't be protected directly.
5879 return false;
5880 }
5881
5882 size_t protectionSize = protectionEnd - protectionStart;
5883
5884 ASSERT(protectionSize == mPageSize);
5885
5886 bool canProtect = angle::ProtectMemory(protectionStart, protectionSize);
5887 if (canProtect)
5888 {
5889 angle::UnprotectMemory(protectionStart, protectionSize);
5890 }
5891
5892 // Clean up
5893 handler->disable();
5894
5895 GLboolean unmapResult;
5896 if (buffer->unmap(context, &unmapResult) != angle::Result::Continue)
5897 {
5898 ERR() << "Could not unmap buffer.";
5899 }
5900 context->bindBuffer(targetPacked, {0});
5901 context->deleteBuffer(buffer->id());
5902
5903 return canProtect;
5904 }
5905
handleWrite(uintptr_t address)5906 PageFaultHandlerRangeType CoherentBufferTracker::handleWrite(uintptr_t address)
5907 {
5908 std::lock_guard<angle::SimpleMutex> lock(mMutex);
5909 auto pagesInBuffers = getBufferPagesForAddress(address);
5910
5911 if (pagesInBuffers.empty())
5912 {
5913 ERR() << "Didn't find a tracked buffer containing " << reinterpret_cast<void *>(address);
5914 }
5915
5916 for (const auto &page : pagesInBuffers)
5917 {
5918 std::shared_ptr<CoherentBuffer> buffer = page.first;
5919 size_t relativePage = page.second;
5920 buffer->setDirty(relativePage, true);
5921 }
5922
5923 return pagesInBuffers.empty() ? PageFaultHandlerRangeType::OutOfRange
5924 : PageFaultHandlerRangeType::InRange;
5925 }
5926
getBufferPagesForAddress(uintptr_t address)5927 HashMap<std::shared_ptr<CoherentBuffer>, size_t> CoherentBufferTracker::getBufferPagesForAddress(
5928 uintptr_t address)
5929 {
5930 HashMap<std::shared_ptr<CoherentBuffer>, size_t> foundPages;
5931
5932 #if defined(ANGLE_PLATFORM_ANDROID)
5933 size_t page;
5934 if (mShadowMemoryEnabled)
5935 {
5936 // Starting with Android 11 heap pointers get a tag which is stripped by the POSIX mprotect
5937 // callback. We need to add this tag manually to the untagged pointer in order to determine
5938 // the corresponding page.
5939 // See: https://source.android.com/docs/security/test/tagged-pointers
5940 // TODO(http://anglebug.com/42265874): Determine when heap pointer tagging is not enabled.
5941 constexpr unsigned long long POINTER_TAG = 0xb400000000000000;
5942 unsigned long long taggedAddress = address | POINTER_TAG;
5943 page = static_cast<size_t>(taggedAddress / mPageSize);
5944 }
5945 else
5946 {
5947 // VMA allocated memory pointers are not tagged.
5948 page = address / mPageSize;
5949 }
5950 #else
5951 size_t page = address / mPageSize;
5952 #endif
5953
5954 for (const auto &pair : mBuffers)
5955 {
5956 std::shared_ptr<CoherentBuffer> buffer = pair.second;
5957 size_t relativePage;
5958 if (buffer->contains(page, &relativePage))
5959 {
5960 foundPages.insert(std::make_pair(buffer, relativePage));
5961 }
5962 }
5963
5964 return foundPages;
5965 }
5966
isDirty(gl::BufferID id)5967 bool CoherentBufferTracker::isDirty(gl::BufferID id)
5968 {
5969 return mBuffers[id.value]->isDirty();
5970 }
5971
enable()5972 void CoherentBufferTracker::enable()
5973 {
5974 if (mEnabled)
5975 {
5976 return;
5977 }
5978
5979 PageFaultCallback callback = [this](uintptr_t address) { return handleWrite(address); };
5980
5981 // This needs to be initialized after canProtectDirectly ran and can only be initialized once.
5982 if (!mPageFaultHandler)
5983 {
5984 mPageFaultHandler = std::unique_ptr<PageFaultHandler>(CreatePageFaultHandler(callback));
5985 }
5986
5987 bool ret = mPageFaultHandler->enable();
5988 if (ret)
5989 {
5990 mEnabled = true;
5991 }
5992 else
5993 {
5994 ERR() << "Could not enable page fault handler.";
5995 }
5996 }
5997
haveBuffer(gl::BufferID id)5998 bool CoherentBufferTracker::haveBuffer(gl::BufferID id)
5999 {
6000 return mBuffers.find(id.value) != mBuffers.end();
6001 }
6002
onEndFrame()6003 void CoherentBufferTracker::onEndFrame()
6004 {
6005 std::lock_guard<angle::SimpleMutex> lock(mMutex);
6006
6007 if (!mEnabled)
6008 {
6009 return;
6010 }
6011
6012 mHasBeenReset = true;
6013
6014 // Remove protection from all buffers
6015 for (const auto &pair : mBuffers)
6016 {
6017 std::shared_ptr<CoherentBuffer> buffer = pair.second;
6018 buffer->removeProtection(PageSharingType::NoneShared);
6019 }
6020
6021 disable();
6022 }
6023
addBuffer(gl::BufferID id,uintptr_t start,size_t size)6024 uintptr_t CoherentBufferTracker::addBuffer(gl::BufferID id, uintptr_t start, size_t size)
6025 {
6026 std::lock_guard<angle::SimpleMutex> lock(mMutex);
6027
6028 if (haveBuffer(id))
6029 {
6030 auto buffer = mBuffers[id.value];
6031 return buffer->getRange().start;
6032 }
6033
6034 auto buffer = std::make_shared<CoherentBuffer>(start, size, mPageSize, mShadowMemoryEnabled);
6035 uintptr_t realOrShadowStart = buffer->getRange().start;
6036
6037 mBuffers.insert(std::make_pair(id.value, std::move(buffer)));
6038
6039 return realOrShadowStart;
6040 }
6041
maybeUpdateShadowMemory()6042 void CoherentBufferTracker::maybeUpdateShadowMemory()
6043 {
6044 for (const auto &pair : mBuffers)
6045 {
6046 std::shared_ptr<CoherentBuffer> cb = pair.second;
6047 if (cb->isShadowDirty())
6048 {
6049 cb->removeProtection(PageSharingType::NoneShared);
6050 cb->updateShadowMemory();
6051 cb->protectAll();
6052 }
6053 }
6054 }
6055
markAllShadowDirty()6056 void CoherentBufferTracker::markAllShadowDirty()
6057 {
6058 for (const auto &pair : mBuffers)
6059 {
6060 std::shared_ptr<CoherentBuffer> cb = pair.second;
6061 cb->markShadowDirty();
6062 }
6063 }
6064
doesBufferSharePage(gl::BufferID id)6065 PageSharingType CoherentBufferTracker::doesBufferSharePage(gl::BufferID id)
6066 {
6067 bool firstPageShared = false;
6068 bool lastPageShared = false;
6069
6070 std::shared_ptr<CoherentBuffer> buffer = mBuffers[id.value];
6071
6072 AddressRange range = buffer->getRange();
6073
6074 size_t firstPage = range.start / mPageSize;
6075 size_t lastPage = range.end() / mPageSize;
6076
6077 for (const auto &pair : mBuffers)
6078 {
6079 gl::BufferID otherId = {pair.first};
6080 if (otherId != id)
6081 {
6082 std::shared_ptr<CoherentBuffer> otherBuffer = pair.second;
6083 size_t relativePage;
6084 if (otherBuffer->contains(firstPage, &relativePage))
6085 {
6086 firstPageShared = true;
6087 }
6088 else if (otherBuffer->contains(lastPage, &relativePage))
6089 {
6090 lastPageShared = true;
6091 }
6092 }
6093 }
6094
6095 if (firstPageShared && !lastPageShared)
6096 {
6097 return PageSharingType::FirstShared;
6098 }
6099 else if (!firstPageShared && lastPageShared)
6100 {
6101 return PageSharingType::LastShared;
6102 }
6103 else if (firstPageShared && lastPageShared)
6104 {
6105 return PageSharingType::FirstAndLastShared;
6106 }
6107 else
6108 {
6109 return PageSharingType::NoneShared;
6110 }
6111 }
6112
removeBuffer(gl::BufferID id)6113 void CoherentBufferTracker::removeBuffer(gl::BufferID id)
6114 {
6115 std::lock_guard<angle::SimpleMutex> lock(mMutex);
6116
6117 if (!haveBuffer(id))
6118 {
6119 return;
6120 }
6121
6122 // Synchronize graphics buffer memory before the buffer is removed from the tracker.
6123 if (mShadowMemoryEnabled)
6124 {
6125 mBuffers[id.value]->updateBufferMemory();
6126 }
6127
6128 // If the buffer shares pages with other tracked buffers,
6129 // don't unprotect the overlapping pages.
6130 PageSharingType sharingType = doesBufferSharePage(id);
6131 mBuffers[id.value]->removeProtection(sharingType);
6132 mBuffers.erase(id.value);
6133 }
6134
maybeGetShadowMemoryPointer(gl::Buffer * buffer,GLsizeiptr length,GLbitfield access)6135 void *FrameCaptureShared::maybeGetShadowMemoryPointer(gl::Buffer *buffer,
6136 GLsizeiptr length,
6137 GLbitfield access)
6138 {
6139 if (!(access & GL_MAP_COHERENT_BIT_EXT) || !mCoherentBufferTracker.isShadowMemoryEnabled())
6140 {
6141 return buffer->getMapPointer();
6142 }
6143
6144 mCoherentBufferTracker.enable();
6145 uintptr_t realMapPointer = reinterpret_cast<uintptr_t>(buffer->getMapPointer());
6146 return (void *)mCoherentBufferTracker.addBuffer(buffer->id(), realMapPointer, length);
6147 }
6148
determineMemoryProtectionSupport(gl::Context * context)6149 void FrameCaptureShared::determineMemoryProtectionSupport(gl::Context *context)
6150 {
6151 // Skip this test if shadow memory was force enabled or shadow memory requirement was detected
6152 // previously
6153 if (mCoherentBufferTracker.isShadowMemoryEnabled())
6154 {
6155 return;
6156 }
6157
6158 // These known devices must use shadow memory
6159 HashMap<std::string, std::vector<std::string>> denyList = {
6160 {"Google", {"Pixel 6", "Pixel 6 Pro", "Pixel 6a", "Pixel 7", "Pixel 7 Pro"}},
6161 };
6162
6163 angle::SystemInfo info;
6164 angle::GetSystemInfo(&info);
6165 bool isDeviceDenyListed = false;
6166
6167 if (rx::GetAndroidSDKVersion() < 34)
6168 {
6169 // Before Android 14, there was a bug in Mali based Pixel preventing mprotect
6170 // on Vulkan surfaces. (https://b.corp.google.com/issues/269535398)
6171 // Check the denylist in this case.
6172 if (denyList.find(info.machineManufacturer) != denyList.end())
6173 {
6174 const std::vector<std::string> &models = denyList[info.machineManufacturer];
6175 isDeviceDenyListed =
6176 std::find(models.begin(), models.end(), info.machineModelName) != models.end();
6177 }
6178 }
6179
6180 if (isDeviceDenyListed)
6181 {
6182 WARN() << "Direct memory protection not possible on deny listed device '"
6183 << info.machineModelName
6184 << "', enabling shadow memory for coherent buffer tracking.";
6185 mCoherentBufferTracker.enableShadowMemory();
6186 }
6187 else
6188 {
6189 // Device is not on deny listed. Run a test if we actually can protect directly. Do this
6190 // only on assertion enabled builds.
6191 ASSERT(mCoherentBufferTracker.canProtectDirectly(context));
6192 }
6193 }
6194
trackBufferMapping(const gl::Context * context,CallCapture * call,gl::BufferID id,gl::Buffer * buffer,GLintptr offset,GLsizeiptr length,bool writable,bool coherent)6195 void FrameCaptureShared::trackBufferMapping(const gl::Context *context,
6196 CallCapture *call,
6197 gl::BufferID id,
6198 gl::Buffer *buffer,
6199 GLintptr offset,
6200 GLsizeiptr length,
6201 bool writable,
6202 bool coherent)
6203 {
6204 // Track that the buffer was mapped
6205 mResourceTracker.setBufferMapped(context->id(), id.value);
6206
6207 if (writable)
6208 {
6209 // If this buffer was mapped writable, we don't have any visibility into what
6210 // happens to it. Therefore, remember the details about it, and we'll read it back
6211 // on Unmap to repopulate it during replay.
6212 mBufferDataMap[id] = std::make_pair(offset, length);
6213
6214 // Track that this buffer was potentially modified
6215 mResourceTracker.getTrackedResource(context->id(), ResourceIDType::Buffer)
6216 .setModifiedResource(id.value);
6217
6218 // Track coherent buffer
6219 // Check if capture is active to not initialize the coherent buffer tracker on the
6220 // first coherent glMapBufferRange call.
6221 if (coherent && isCaptureActive())
6222 {
6223 if (mCoherentBufferTracker.hasBeenReset())
6224 {
6225 FATAL() << "Multi-capture not supprted for apps using persistent coherent memory";
6226 }
6227
6228 mCoherentBufferTracker.enable();
6229 // When not using shadow memory, adding buffers to the tracking happens here instead of
6230 // during mapping
6231 if (!mCoherentBufferTracker.isShadowMemoryEnabled())
6232 {
6233 uintptr_t data = reinterpret_cast<uintptr_t>(buffer->getMapPointer());
6234 mCoherentBufferTracker.addBuffer(id, data, length);
6235 }
6236 }
6237 }
6238 }
6239
trackTextureUpdate(const gl::Context * context,const CallCapture & call)6240 void FrameCaptureShared::trackTextureUpdate(const gl::Context *context, const CallCapture &call)
6241 {
6242 int index = 0;
6243 std::string paramName = "targetPacked";
6244 ParamType paramType = ParamType::TTextureTarget;
6245
6246 // Some calls provide the textureID directly
6247 // For the rest, look it up based on the currently bound texture
6248 switch (call.entryPoint)
6249 {
6250 case EntryPoint::GLCompressedCopyTextureCHROMIUM:
6251 index = 1;
6252 paramName = "destIdPacked";
6253 paramType = ParamType::TTextureID;
6254 break;
6255 case EntryPoint::GLCopyTextureCHROMIUM:
6256 case EntryPoint::GLCopySubTextureCHROMIUM:
6257 case EntryPoint::GLCopyTexture3DANGLE:
6258 index = 3;
6259 paramName = "destIdPacked";
6260 paramType = ParamType::TTextureID;
6261 break;
6262 case EntryPoint::GLCopyImageSubData:
6263 case EntryPoint::GLCopyImageSubDataEXT:
6264 case EntryPoint::GLCopyImageSubDataOES:
6265 index = 7;
6266 paramName = "dstTarget";
6267 paramType = ParamType::TGLenum;
6268 break;
6269 default:
6270 break;
6271 }
6272
6273 GLuint id = 0;
6274 switch (paramType)
6275 {
6276 case ParamType::TTextureTarget:
6277 {
6278 gl::TextureTarget targetPacked =
6279 call.params.getParam(paramName.c_str(), ParamType::TTextureTarget, index)
6280 .value.TextureTargetVal;
6281 gl::TextureType textureType = gl::TextureTargetToType(targetPacked);
6282 gl::Texture *texture = context->getState().getTargetTexture(textureType);
6283 id = texture->id().value;
6284 break;
6285 }
6286 case ParamType::TTextureID:
6287 {
6288 gl::TextureID destIDPacked =
6289 call.params.getParam(paramName.c_str(), ParamType::TTextureID, index)
6290 .value.TextureIDVal;
6291 id = destIDPacked.value;
6292 break;
6293 }
6294 case ParamType::TGLenum:
6295 {
6296 GLenum target =
6297 call.params.getParam(paramName.c_str(), ParamType::TGLenum, index).value.GLenumVal;
6298
6299 if (target == GL_TEXTURE_CUBE_MAP)
6300 {
6301 // CopyImageSubData doesn't support cube faces, but PackedParams requires one
6302 target = GL_TEXTURE_CUBE_MAP_POSITIVE_X;
6303 }
6304
6305 gl::TextureTarget targetPacked = gl::PackParam<gl::TextureTarget>(target);
6306 gl::TextureType textureType = gl::TextureTargetToType(targetPacked);
6307 gl::Texture *texture = context->getState().getTargetTexture(textureType);
6308 id = texture->id().value;
6309 break;
6310 }
6311 default:
6312 ERR() << "Unhandled paramType= " << static_cast<int>(paramType);
6313 UNREACHABLE();
6314 break;
6315 }
6316
6317 // Mark it as modified
6318 mResourceTracker.getTrackedResource(context->id(), ResourceIDType::Texture)
6319 .setModifiedResource(id);
6320 }
6321
6322 // Identify and mark writeable shader image textures as modified
trackImageUpdate(const gl::Context * context,const CallCapture & call)6323 void FrameCaptureShared::trackImageUpdate(const gl::Context *context, const CallCapture &call)
6324 {
6325 const gl::ProgramExecutable *executable = context->getState().getProgramExecutable();
6326 for (const gl::ImageBinding &imageBinding : executable->getImageBindings())
6327 {
6328 for (GLuint binding : imageBinding.boundImageUnits)
6329 {
6330 const gl::ImageUnit &imageUnit = context->getState().getImageUnit(binding);
6331 if (imageUnit.access != GL_READ_ONLY)
6332 {
6333 // Get image binding texture id and mark it as modified
6334 GLuint id = imageUnit.texture.id().value;
6335 mResourceTracker.getTrackedResource(context->id(), ResourceIDType::Texture)
6336 .setModifiedResource(id);
6337 }
6338 }
6339 }
6340 }
6341
trackDefaultUniformUpdate(const gl::Context * context,const CallCapture & call)6342 void FrameCaptureShared::trackDefaultUniformUpdate(const gl::Context *context,
6343 const CallCapture &call)
6344 {
6345 DefaultUniformType defaultUniformType = GetDefaultUniformType(call);
6346
6347 GLuint programID = 0;
6348 int location = 0;
6349
6350 // We track default uniform updates by program and location, so look them up in parameters
6351 if (defaultUniformType == DefaultUniformType::CurrentProgram)
6352 {
6353 programID = context->getActiveLinkedProgram()->id().value;
6354
6355 location = call.params.getParam("locationPacked", ParamType::TUniformLocation, 0)
6356 .value.UniformLocationVal.value;
6357 }
6358 else
6359 {
6360 ASSERT(defaultUniformType == DefaultUniformType::SpecifiedProgram);
6361
6362 programID = call.params.getParam("programPacked", ParamType::TShaderProgramID, 0)
6363 .value.ShaderProgramIDVal.value;
6364
6365 location = call.params.getParam("locationPacked", ParamType::TUniformLocation, 1)
6366 .value.UniformLocationVal.value;
6367 }
6368
6369 const TrackedResource &trackedShaderProgram =
6370 mResourceTracker.getTrackedResource(context->id(), ResourceIDType::ShaderProgram);
6371 const ResourceSet &startingPrograms = trackedShaderProgram.getStartingResources();
6372 const ResourceSet &programsToRegen = trackedShaderProgram.getResourcesToRegen();
6373
6374 // If this program was in our starting set, track its uniform updates. Unless it was deleted,
6375 // then its uniforms will all be regenned along wih with the program.
6376 if (startingPrograms.find(programID) != startingPrograms.end() &&
6377 programsToRegen.find(programID) == programsToRegen.end())
6378 {
6379 // Track that we need to set this default uniform value again
6380 mResourceTracker.setModifiedDefaultUniform({programID}, {location});
6381 }
6382 }
6383
trackVertexArrayUpdate(const gl::Context * context,const CallCapture & call)6384 void FrameCaptureShared::trackVertexArrayUpdate(const gl::Context *context, const CallCapture &call)
6385 {
6386 // Look up the currently bound vertex array
6387 gl::VertexArrayID id = context->getState().getVertexArray()->id();
6388
6389 // Mark it as modified
6390 mResourceTracker.getTrackedResource(context->id(), ResourceIDType::VertexArray)
6391 .setModifiedResource(id.value);
6392 }
6393
updateCopyImageSubData(CallCapture & call)6394 void FrameCaptureShared::updateCopyImageSubData(CallCapture &call)
6395 {
6396 // This call modifies srcName and dstName to no longer be object IDs (GLuint), but actual
6397 // packed types that can remapped using gTextureMap and gRenderbufferMap
6398
6399 GLint srcName = call.params.getParam("srcName", ParamType::TGLuint, 0).value.GLuintVal;
6400 GLenum srcTarget = call.params.getParam("srcTarget", ParamType::TGLenum, 1).value.GLenumVal;
6401 switch (srcTarget)
6402 {
6403 case GL_RENDERBUFFER:
6404 {
6405 // Convert the GLuint to RenderbufferID
6406 gl::RenderbufferID srcRenderbufferID = {static_cast<GLuint>(srcName)};
6407 call.params.setValueParamAtIndex("srcName", ParamType::TRenderbufferID,
6408 srcRenderbufferID, 0);
6409 break;
6410 }
6411 case GL_TEXTURE_2D:
6412 case GL_TEXTURE_2D_ARRAY:
6413 case GL_TEXTURE_3D:
6414 case GL_TEXTURE_CUBE_MAP:
6415 case GL_TEXTURE_EXTERNAL_OES:
6416 case GL_TEXTURE_2D_MULTISAMPLE:
6417 case GL_TEXTURE_2D_MULTISAMPLE_ARRAY_OES:
6418 {
6419 // Convert the GLuint to TextureID
6420 gl::TextureID srcTextureID = {static_cast<GLuint>(srcName)};
6421 call.params.setValueParamAtIndex("srcName", ParamType::TTextureID, srcTextureID, 0);
6422 break;
6423 }
6424 default:
6425 ERR() << "Unhandled srcTarget = " << srcTarget;
6426 UNREACHABLE();
6427 break;
6428 }
6429
6430 // Change dstName to the appropriate type based on dstTarget
6431 GLint dstName = call.params.getParam("dstName", ParamType::TGLuint, 6).value.GLuintVal;
6432 GLenum dstTarget = call.params.getParam("dstTarget", ParamType::TGLenum, 7).value.GLenumVal;
6433 switch (dstTarget)
6434 {
6435 case GL_RENDERBUFFER:
6436 {
6437 // Convert the GLuint to RenderbufferID
6438 gl::RenderbufferID dstRenderbufferID = {static_cast<GLuint>(dstName)};
6439 call.params.setValueParamAtIndex("dstName", ParamType::TRenderbufferID,
6440 dstRenderbufferID, 6);
6441 break;
6442 }
6443 case GL_TEXTURE_2D:
6444 case GL_TEXTURE_2D_ARRAY:
6445 case GL_TEXTURE_3D:
6446 case GL_TEXTURE_CUBE_MAP:
6447 case GL_TEXTURE_EXTERNAL_OES:
6448 case GL_TEXTURE_2D_MULTISAMPLE:
6449 case GL_TEXTURE_2D_MULTISAMPLE_ARRAY_OES:
6450 {
6451 // Convert the GLuint to TextureID
6452 gl::TextureID dstTextureID = {static_cast<GLuint>(dstName)};
6453 call.params.setValueParamAtIndex("dstName", ParamType::TTextureID, dstTextureID, 6);
6454 break;
6455 }
6456 default:
6457 ERR() << "Unhandled dstTarget = " << dstTarget;
6458 UNREACHABLE();
6459 break;
6460 }
6461 }
6462
overrideProgramBinary(const gl::Context * context,CallCapture & inCall,std::vector<CallCapture> & outCalls)6463 void FrameCaptureShared::overrideProgramBinary(const gl::Context *context,
6464 CallCapture &inCall,
6465 std::vector<CallCapture> &outCalls)
6466 {
6467 // Program binaries are inherently non-portable, even between two ANGLE builds.
6468 // If an application is using glProgramBinary in the middle of a trace, we need to replace
6469 // those calls with an equivalent sequence of portable calls.
6470 //
6471 // For example, here is a sequence an app could use for glProgramBinary:
6472 //
6473 // gShaderProgramMap[42] = glCreateProgram();
6474 // glProgramBinary(gShaderProgramMap[42], GL_PROGRAM_BINARY_ANGLE, gBinaryData[x], 1000);
6475 // glGetProgramiv(gShaderProgramMap[42], GL_LINK_STATUS, gReadBuffer);
6476 // glGetProgramiv(gShaderProgramMap[42], GL_PROGRAM_BINARY_LENGTH, gReadBuffer);
6477 //
6478 // With this override, the glProgramBinary call will be replaced like so:
6479 //
6480 // gShaderProgramMap[42] = glCreateProgram();
6481 // === Begin override ===
6482 // gShaderProgramMap[43] = glCreateShader(GL_VERTEX_SHADER);
6483 // glShaderSource(gShaderProgramMap[43], 1, string_0, &gBinaryData[100]);
6484 // glCompileShader(gShaderProgramMap[43]);
6485 // glAttachShader(gShaderProgramMap[42], gShaderProgramMap[43]);
6486 // glDeleteShader(gShaderProgramMap[43]);
6487 // gShaderProgramMap[43] = glCreateShader(GL_FRAGMENT_SHADER);
6488 // glShaderSource(gShaderProgramMap[43], 1, string_1, &gBinaryData[200]);
6489 // glCompileShader(gShaderProgramMap[43]);
6490 // glAttachShader(gShaderProgramMap[42], gShaderProgramMap[43]);
6491 // glDeleteShader(gShaderProgramMap[43]);
6492 // glBindAttribLocation(gShaderProgramMap[42], 0, "attrib1");
6493 // glBindAttribLocation(gShaderProgramMap[42], 1, "attrib2");
6494 // glLinkProgram(gShaderProgramMap[42]);
6495 // UpdateUniformLocation(gShaderProgramMap[42], "foo", 0, 20);
6496 // UpdateUniformLocation(gShaderProgramMap[42], "bar", 72, 1);
6497 // glUseProgram(gShaderProgramMap[42]);
6498 // UpdateCurrentProgram(gShaderProgramMap[42]);
6499 // glUniform4fv(gUniformLocations[gCurrentProgram][0], 20, &gBinaryData[300]);
6500 // glUniform1iv(gUniformLocations[gCurrentProgram][72], 1, &gBinaryData[400]);
6501 // === End override ===
6502 // glGetProgramiv(gShaderProgramMap[42], GL_LINK_STATUS, gReadBuffer);
6503 // glGetProgramiv(gShaderProgramMap[42], GL_PROGRAM_BINARY_LENGTH, gReadBuffer);
6504 //
6505 // To facilitate this override, we are serializing each shader stage source into the binary
6506 // itself. See Program::serialize and Program::deserialize. Once extracted from the binary,
6507 // they will be available via getProgramSources.
6508
6509 gl::ShaderProgramID id = inCall.params.getParam("programPacked", ParamType::TShaderProgramID, 0)
6510 .value.ShaderProgramIDVal;
6511
6512 gl::Program *program = context->getProgramResolveLink(id);
6513 ASSERT(program);
6514
6515 mResourceTracker.onShaderProgramAccess(id);
6516 gl::ShaderProgramID tempShaderStartID = {mResourceTracker.getMaxShaderPrograms()};
6517 GenerateLinkedProgram(context, context->getState(), &mResourceTracker, &outCalls, program, id,
6518 tempShaderStartID, getProgramSources(id));
6519 }
6520
captureCustomMapBufferFromContext(const gl::Context * context,const char * entryPointName,CallCapture & call,std::vector<CallCapture> & callsOut)6521 void FrameCaptureShared::captureCustomMapBufferFromContext(const gl::Context *context,
6522 const char *entryPointName,
6523 CallCapture &call,
6524 std::vector<CallCapture> &callsOut)
6525 {
6526 gl::BufferBinding binding =
6527 call.params.getParam("targetPacked", ParamType::TBufferBinding, 0).value.BufferBindingVal;
6528 gl::Buffer *buffer = context->getState().getTargetBuffer(binding);
6529
6530 if (call.entryPoint == EntryPoint::GLMapBufferRange ||
6531 call.entryPoint == EntryPoint::GLMapBufferRangeEXT)
6532 {
6533 GLintptr offset = call.params.getParam("offset", ParamType::TGLintptr, 1).value.GLintptrVal;
6534 GLsizeiptr length =
6535 call.params.getParam("length", ParamType::TGLsizeiptr, 2).value.GLsizeiptrVal;
6536 GLbitfield access =
6537 call.params.getParam("access", ParamType::TGLbitfield, 3).value.GLbitfieldVal;
6538
6539 trackBufferMapping(context, &call, buffer->id(), buffer, offset, length,
6540 access & GL_MAP_WRITE_BIT, access & GL_MAP_COHERENT_BIT_EXT);
6541 }
6542 else
6543 {
6544 ASSERT(call.entryPoint == EntryPoint::GLMapBufferOES);
6545 GLenum access = call.params.getParam("access", ParamType::TGLenum, 1).value.GLenumVal;
6546 bool writeAccess =
6547 (access == GL_WRITE_ONLY_OES || access == GL_WRITE_ONLY || access == GL_READ_WRITE);
6548 trackBufferMapping(context, &call, buffer->id(), buffer, 0,
6549 static_cast<GLsizeiptr>(buffer->getSize()), writeAccess, false);
6550 }
6551
6552 CaptureCustomMapBuffer(entryPointName, call, callsOut, buffer->id());
6553 }
6554
maybeOverrideEntryPoint(const gl::Context * context,CallCapture & inCall,std::vector<CallCapture> & outCalls)6555 void FrameCaptureShared::maybeOverrideEntryPoint(const gl::Context *context,
6556 CallCapture &inCall,
6557 std::vector<CallCapture> &outCalls)
6558 {
6559 switch (inCall.entryPoint)
6560 {
6561 case EntryPoint::GLCopyImageSubData:
6562 case EntryPoint::GLCopyImageSubDataEXT:
6563 case EntryPoint::GLCopyImageSubDataOES:
6564 {
6565 // We must look at the src and dst target types to determine which remap table to use
6566 updateCopyImageSubData(inCall);
6567 outCalls.emplace_back(std::move(inCall));
6568 break;
6569 }
6570 case EntryPoint::GLProgramBinary:
6571 case EntryPoint::GLProgramBinaryOES:
6572 {
6573 // Binary formats are not portable at all, so replace the calls with full linking
6574 // sequence
6575 overrideProgramBinary(context, inCall, outCalls);
6576 break;
6577 }
6578 case EntryPoint::GLUniformBlockBinding:
6579 {
6580 CaptureCustomUniformBlockBinding(inCall, outCalls);
6581 break;
6582 }
6583 case EntryPoint::GLMapBufferRange:
6584 {
6585 captureCustomMapBufferFromContext(context, "MapBufferRange", inCall, outCalls);
6586 break;
6587 }
6588 case EntryPoint::GLMapBufferRangeEXT:
6589 {
6590 captureCustomMapBufferFromContext(context, "MapBufferRangeEXT", inCall, outCalls);
6591 break;
6592 }
6593 case EntryPoint::GLMapBufferOES:
6594 {
6595 captureCustomMapBufferFromContext(context, "MapBufferOES", inCall, outCalls);
6596 break;
6597 }
6598 case EntryPoint::GLCreateShader:
6599 {
6600 CaptureCustomShaderProgram("CreateShader", inCall, outCalls);
6601 break;
6602 }
6603 case EntryPoint::GLCreateProgram:
6604 {
6605 CaptureCustomShaderProgram("CreateProgram", inCall, outCalls);
6606 break;
6607 }
6608 case EntryPoint::GLCreateShaderProgramv:
6609 {
6610 CaptureCustomShaderProgram("CreateShaderProgramv", inCall, outCalls);
6611 break;
6612 }
6613 case EntryPoint::GLFenceSync:
6614 {
6615 CaptureCustomFenceSync(inCall, outCalls);
6616 break;
6617 }
6618 case EntryPoint::EGLCreateImage:
6619 {
6620 const egl::Image *eglImage = GetImageFromParam(context, inCall.params.getReturnValue());
6621 CaptureCustomCreateEGLImage(context, "CreateEGLImage", eglImage->getWidth(),
6622 eglImage->getHeight(), inCall, outCalls);
6623 break;
6624 }
6625 case EntryPoint::EGLCreateImageKHR:
6626 {
6627 const egl::Image *eglImage = GetImageFromParam(context, inCall.params.getReturnValue());
6628 CaptureCustomCreateEGLImage(context, "CreateEGLImageKHR", eglImage->getWidth(),
6629 eglImage->getHeight(), inCall, outCalls);
6630 break;
6631 }
6632 case EntryPoint::EGLDestroyImage:
6633 {
6634 CaptureCustomDestroyEGLImage("DestroyEGLImage", inCall, outCalls);
6635 break;
6636 }
6637 case EntryPoint::EGLDestroyImageKHR:
6638 {
6639 CaptureCustomDestroyEGLImage("DestroyEGLImageKHR", inCall, outCalls);
6640 break;
6641 }
6642 case EntryPoint::EGLCreateSync:
6643 {
6644 CaptureCustomCreateEGLSync("CreateEGLSync", inCall, outCalls);
6645 break;
6646 }
6647 case EntryPoint::EGLCreateSyncKHR:
6648 {
6649 CaptureCustomCreateEGLSync("CreateEGLSyncKHR", inCall, outCalls);
6650 break;
6651 }
6652 case EntryPoint::EGLCreatePbufferSurface:
6653 {
6654 CaptureCustomCreatePbufferSurface(inCall, outCalls);
6655 break;
6656 }
6657 case EntryPoint::EGLCreateNativeClientBufferANDROID:
6658 {
6659 CaptureCustomCreateNativeClientbuffer(inCall, outCalls);
6660 break;
6661 }
6662
6663 default:
6664 {
6665 // Pass the single call through
6666 outCalls.emplace_back(std::move(inCall));
6667 break;
6668 }
6669 }
6670 }
6671
maybeCaptureCoherentBuffers(const gl::Context * context)6672 void FrameCaptureShared::maybeCaptureCoherentBuffers(const gl::Context *context)
6673 {
6674 if (!isCaptureActive())
6675 {
6676 return;
6677 }
6678
6679 std::lock_guard<angle::SimpleMutex> lock(mCoherentBufferTracker.mMutex);
6680
6681 for (const auto &pair : mCoherentBufferTracker.mBuffers)
6682 {
6683 gl::BufferID id = {pair.first};
6684 if (mCoherentBufferTracker.isDirty(id))
6685 {
6686 captureCoherentBufferSnapshot(context, id);
6687 }
6688 }
6689 }
6690
maybeCaptureDrawArraysClientData(const gl::Context * context,CallCapture & call,size_t instanceCount)6691 void FrameCaptureShared::maybeCaptureDrawArraysClientData(const gl::Context *context,
6692 CallCapture &call,
6693 size_t instanceCount)
6694 {
6695 if (!context->getStateCache().hasAnyActiveClientAttrib())
6696 {
6697 return;
6698 }
6699
6700 // Get counts from paramBuffer.
6701 GLint firstVertex =
6702 call.params.getParamFlexName("first", "start", ParamType::TGLint, 1).value.GLintVal;
6703 GLsizei drawCount = call.params.getParam("count", ParamType::TGLsizei, 2).value.GLsizeiVal;
6704 captureClientArraySnapshot(context, firstVertex + drawCount, instanceCount);
6705 }
6706
maybeCaptureDrawElementsClientData(const gl::Context * context,CallCapture & call,size_t instanceCount)6707 void FrameCaptureShared::maybeCaptureDrawElementsClientData(const gl::Context *context,
6708 CallCapture &call,
6709 size_t instanceCount)
6710 {
6711 if (!context->getStateCache().hasAnyActiveClientAttrib())
6712 {
6713 return;
6714 }
6715
6716 // if the count is zero then the index evaluation is not valid and we wouldn't be drawing
6717 // anything anyway, so skip capturing
6718 GLsizei count = call.params.getParam("count", ParamType::TGLsizei, 1).value.GLsizeiVal;
6719 if (count == 0)
6720 {
6721 return;
6722 }
6723
6724 gl::DrawElementsType drawElementsType =
6725 call.params.getParam("typePacked", ParamType::TDrawElementsType, 2)
6726 .value.DrawElementsTypeVal;
6727 const void *indices =
6728 call.params.getParam("indices", ParamType::TvoidConstPointer, 3).value.voidConstPointerVal;
6729
6730 gl::IndexRange indexRange;
6731
6732 bool restart = context->getState().isPrimitiveRestartEnabled();
6733
6734 gl::Buffer *elementArrayBuffer = context->getState().getVertexArray()->getElementArrayBuffer();
6735 if (elementArrayBuffer)
6736 {
6737 size_t offset = reinterpret_cast<size_t>(indices);
6738 (void)elementArrayBuffer->getIndexRange(context, drawElementsType, offset, count, restart,
6739 &indexRange);
6740 }
6741 else
6742 {
6743 ASSERT(indices);
6744 indexRange = gl::ComputeIndexRange(drawElementsType, indices, count, restart);
6745 }
6746
6747 // index starts from 0
6748 captureClientArraySnapshot(context, indexRange.end + 1, instanceCount);
6749 }
6750
6751 template <typename AttribT, typename FactoryT>
CreateEGLImagePreCallUpdate(const CallCapture & call,ResourceTracker & resourceTracker,ParamType paramType,FactoryT factory)6752 void CreateEGLImagePreCallUpdate(const CallCapture &call,
6753 ResourceTracker &resourceTracker,
6754 ParamType paramType,
6755 FactoryT factory)
6756 {
6757 EGLImage image = call.params.getReturnValue().value.EGLImageVal;
6758 const ParamCapture ¶m = call.params.getParam("attrib_list", paramType, 4);
6759 const AttribT *attribs =
6760 param.data.empty() ? nullptr : reinterpret_cast<const AttribT *>(param.data[0].data());
6761 egl::AttributeMap attributeMap = factory(attribs);
6762 attributeMap.initializeWithoutValidation();
6763 resourceTracker.getImageToAttribTable().insert(
6764 std::pair<EGLImage, egl::AttributeMap>(image, attributeMap));
6765 }
6766
maybeCapturePreCallUpdates(const gl::Context * context,CallCapture & call,std::vector<CallCapture> * shareGroupSetupCalls,ResourceIDToSetupCallsMap * resourceIDToSetupCalls)6767 void FrameCaptureShared::maybeCapturePreCallUpdates(
6768 const gl::Context *context,
6769 CallCapture &call,
6770 std::vector<CallCapture> *shareGroupSetupCalls,
6771 ResourceIDToSetupCallsMap *resourceIDToSetupCalls)
6772 {
6773 switch (call.entryPoint)
6774 {
6775 case EntryPoint::GLVertexAttribPointer:
6776 case EntryPoint::GLVertexPointer:
6777 case EntryPoint::GLColorPointer:
6778 case EntryPoint::GLTexCoordPointer:
6779 case EntryPoint::GLNormalPointer:
6780 case EntryPoint::GLPointSizePointerOES:
6781 {
6782 // Get array location
6783 GLuint index = 0;
6784 if (call.entryPoint == EntryPoint::GLVertexAttribPointer)
6785 {
6786 index = call.params.getParam("index", ParamType::TGLuint, 0).value.GLuintVal;
6787 }
6788 else
6789 {
6790 gl::ClientVertexArrayType type;
6791 switch (call.entryPoint)
6792 {
6793 case EntryPoint::GLVertexPointer:
6794 type = gl::ClientVertexArrayType::Vertex;
6795 break;
6796 case EntryPoint::GLColorPointer:
6797 type = gl::ClientVertexArrayType::Color;
6798 break;
6799 case EntryPoint::GLTexCoordPointer:
6800 type = gl::ClientVertexArrayType::TextureCoord;
6801 break;
6802 case EntryPoint::GLNormalPointer:
6803 type = gl::ClientVertexArrayType::Normal;
6804 break;
6805 case EntryPoint::GLPointSizePointerOES:
6806 type = gl::ClientVertexArrayType::PointSize;
6807 break;
6808 default:
6809 UNREACHABLE();
6810 type = gl::ClientVertexArrayType::InvalidEnum;
6811 }
6812 index = gl::GLES1Renderer::VertexArrayIndex(type, context->getState().gles1());
6813 }
6814
6815 if (call.params.hasClientArrayData())
6816 {
6817 mClientVertexArrayMap[index] = static_cast<int>(mFrameCalls.size());
6818 }
6819 else
6820 {
6821 mClientVertexArrayMap[index] = -1;
6822 }
6823 break;
6824 }
6825
6826 case EntryPoint::GLGenFramebuffers:
6827 case EntryPoint::GLGenFramebuffersOES:
6828 {
6829 GLsizei count = call.params.getParam("n", ParamType::TGLsizei, 0).value.GLsizeiVal;
6830 const gl::FramebufferID *framebufferIDs =
6831 call.params.getParam("framebuffersPacked", ParamType::TFramebufferIDPointer, 1)
6832 .value.FramebufferIDPointerVal;
6833 for (GLsizei i = 0; i < count; i++)
6834 {
6835 handleGennedResource(context, framebufferIDs[i]);
6836 }
6837 break;
6838 }
6839
6840 case EntryPoint::GLBindFramebuffer:
6841 case EntryPoint::GLBindFramebufferOES:
6842 maybeGenResourceOnBind<gl::FramebufferID>(context, call);
6843 break;
6844
6845 case EntryPoint::GLGenRenderbuffers:
6846 case EntryPoint::GLGenRenderbuffersOES:
6847 {
6848 GLsizei count = call.params.getParam("n", ParamType::TGLsizei, 0).value.GLsizeiVal;
6849 const gl::RenderbufferID *renderbufferIDs =
6850 call.params.getParam("renderbuffersPacked", ParamType::TRenderbufferIDPointer, 1)
6851 .value.RenderbufferIDPointerVal;
6852 for (GLsizei i = 0; i < count; i++)
6853 {
6854 handleGennedResource(context, renderbufferIDs[i]);
6855 }
6856 break;
6857 }
6858
6859 case EntryPoint::GLBindRenderbuffer:
6860 case EntryPoint::GLBindRenderbufferOES:
6861 maybeGenResourceOnBind<gl::RenderbufferID>(context, call);
6862 break;
6863
6864 case EntryPoint::GLDeleteRenderbuffers:
6865 case EntryPoint::GLDeleteRenderbuffersOES:
6866 {
6867 // Look up how many renderbuffers are being deleted
6868 GLsizei n = call.params.getParam("n", ParamType::TGLsizei, 0).value.GLsizeiVal;
6869
6870 // Look up the pointer to list of renderbuffers
6871 const gl::RenderbufferID *renderbufferIDs =
6872 call.params
6873 .getParam("renderbuffersPacked", ParamType::TRenderbufferIDConstPointer, 1)
6874 .value.RenderbufferIDConstPointerVal;
6875
6876 // For each renderbuffer listed for deletion
6877 for (int32_t i = 0; i < n; ++i)
6878 {
6879 // If we're capturing, track what renderbuffers have been deleted
6880 handleDeletedResource(context, renderbufferIDs[i]);
6881 }
6882 break;
6883 }
6884
6885 case EntryPoint::GLGenTextures:
6886 {
6887 GLsizei count = call.params.getParam("n", ParamType::TGLsizei, 0).value.GLsizeiVal;
6888 const gl::TextureID *textureIDs =
6889 call.params.getParam("texturesPacked", ParamType::TTextureIDPointer, 1)
6890 .value.TextureIDPointerVal;
6891 for (GLsizei i = 0; i < count; i++)
6892 {
6893 // If we're capturing, track what new textures have been genned
6894 handleGennedResource(context, textureIDs[i]);
6895 }
6896 break;
6897 }
6898
6899 case EntryPoint::GLBindTexture:
6900 maybeGenResourceOnBind<gl::TextureID>(context, call);
6901 if (isCaptureActive())
6902 {
6903 gl::TextureType target =
6904 call.params.getParam("targetPacked", ParamType::TTextureType, 0)
6905 .value.TextureTypeVal;
6906 context->getFrameCapture()->getStateResetHelper().setTextureBindingDirty(
6907 context->getState().getActiveSampler(), target);
6908 }
6909 break;
6910
6911 case EntryPoint::GLDeleteBuffers:
6912 {
6913 GLsizei count = call.params.getParam("n", ParamType::TGLsizei, 0).value.GLsizeiVal;
6914 const gl::BufferID *bufferIDs =
6915 call.params.getParam("buffersPacked", ParamType::TBufferIDConstPointer, 1)
6916 .value.BufferIDConstPointerVal;
6917 for (GLsizei i = 0; i < count; i++)
6918 {
6919 // For each buffer being deleted, check our backup of data and remove it
6920 const auto &bufferDataInfo = mBufferDataMap.find(bufferIDs[i]);
6921 if (bufferDataInfo != mBufferDataMap.end())
6922 {
6923 mBufferDataMap.erase(bufferDataInfo);
6924 }
6925 // If we're capturing, track what buffers have been deleted
6926 handleDeletedResource(context, bufferIDs[i]);
6927 }
6928 break;
6929 }
6930
6931 case EntryPoint::GLGenBuffers:
6932 {
6933 GLsizei count = call.params.getParam("n", ParamType::TGLsizei, 0).value.GLsizeiVal;
6934 const gl::BufferID *bufferIDs =
6935 call.params.getParam("buffersPacked", ParamType::TBufferIDPointer, 1)
6936 .value.BufferIDPointerVal;
6937 for (GLsizei i = 0; i < count; i++)
6938 {
6939 handleGennedResource(context, bufferIDs[i]);
6940 }
6941 break;
6942 }
6943
6944 case EntryPoint::GLBindBuffer:
6945 maybeGenResourceOnBind<gl::BufferID>(context, call);
6946 if (isCaptureActive())
6947 {
6948 gl::BufferBinding binding =
6949 call.params.getParam("targetPacked", ParamType::TBufferBinding, 0)
6950 .value.BufferBindingVal;
6951
6952 context->getFrameCapture()->getStateResetHelper().setBufferBindingDirty(binding);
6953 }
6954 break;
6955
6956 case EntryPoint::GLBindBufferBase:
6957 case EntryPoint::GLBindBufferRange:
6958 if (isCaptureActive())
6959 {
6960 WARN() << "Indexed buffer binding changed during capture, Reset doesn't handle it "
6961 "yet.";
6962 }
6963 break;
6964
6965 case EntryPoint::GLDeleteProgramPipelines:
6966 case EntryPoint::GLDeleteProgramPipelinesEXT:
6967 {
6968 GLsizei count = call.params.getParam("n", ParamType::TGLsizei, 0).value.GLsizeiVal;
6969 const gl::ProgramPipelineID *pipelineIDs =
6970 call.params
6971 .getParam("pipelinesPacked", ParamType::TProgramPipelineIDConstPointer, 1)
6972 .value.ProgramPipelineIDPointerVal;
6973 for (GLsizei i = 0; i < count; i++)
6974 {
6975 handleDeletedResource(context, pipelineIDs[i]);
6976 }
6977 break;
6978 }
6979
6980 case EntryPoint::GLGenProgramPipelines:
6981 case EntryPoint::GLGenProgramPipelinesEXT:
6982 {
6983 GLsizei count = call.params.getParam("n", ParamType::TGLsizei, 0).value.GLsizeiVal;
6984 const gl::ProgramPipelineID *pipelineIDs =
6985 call.params.getParam("pipelinesPacked", ParamType::TProgramPipelineIDPointer, 1)
6986 .value.ProgramPipelineIDPointerVal;
6987 for (GLsizei i = 0; i < count; i++)
6988 {
6989 handleGennedResource(context, pipelineIDs[i]);
6990 }
6991 break;
6992 }
6993
6994 case EntryPoint::GLDeleteSync:
6995 {
6996 gl::SyncID sync =
6997 call.params.getParam("syncPacked", ParamType::TSyncID, 0).value.SyncIDVal;
6998 FrameCaptureShared *frameCaptureShared =
6999 context->getShareGroup()->getFrameCaptureShared();
7000 // If we're capturing, track which fence sync has been deleted
7001 if (frameCaptureShared->isCaptureActive())
7002 {
7003 mResourceTracker.setDeletedFenceSync(sync);
7004 }
7005 break;
7006 }
7007
7008 case EntryPoint::GLDrawArrays:
7009 {
7010 maybeCaptureDrawArraysClientData(context, call, 1);
7011 maybeCaptureCoherentBuffers(context);
7012 break;
7013 }
7014
7015 case EntryPoint::GLDrawArraysInstanced:
7016 case EntryPoint::GLDrawArraysInstancedANGLE:
7017 case EntryPoint::GLDrawArraysInstancedEXT:
7018 {
7019 GLsizei instancecount =
7020 call.params.getParamFlexName("instancecount", "primcount", ParamType::TGLsizei, 3)
7021 .value.GLsizeiVal;
7022
7023 maybeCaptureDrawArraysClientData(context, call, instancecount);
7024 maybeCaptureCoherentBuffers(context);
7025 break;
7026 }
7027
7028 case EntryPoint::GLDrawElements:
7029 {
7030 maybeCaptureDrawElementsClientData(context, call, 1);
7031 maybeCaptureCoherentBuffers(context);
7032 break;
7033 }
7034
7035 case EntryPoint::GLDrawElementsInstanced:
7036 case EntryPoint::GLDrawElementsInstancedANGLE:
7037 case EntryPoint::GLDrawElementsInstancedEXT:
7038 {
7039 GLsizei instancecount =
7040 call.params.getParamFlexName("instancecount", "primcount", ParamType::TGLsizei, 4)
7041 .value.GLsizeiVal;
7042
7043 maybeCaptureDrawElementsClientData(context, call, instancecount);
7044 maybeCaptureCoherentBuffers(context);
7045 break;
7046 }
7047
7048 case EntryPoint::GLCreateShaderProgramv:
7049 {
7050 // Refresh the cached shader sources.
7051 // The command CreateShaderProgramv() creates a stand-alone program from an array of
7052 // null-terminated source code strings for a single shader type, so we need update the
7053 // Shader and Program sources, similar to GLCompileShader + GLLinkProgram handling.
7054 gl::ShaderProgramID programID = {call.params.getReturnValue().value.GLuintVal};
7055 const ParamCapture ¶mCapture =
7056 call.params.getParam("typePacked", ParamType::TShaderType, 0);
7057 const ParamCapture &lineCount = call.params.getParam("count", ParamType::TGLsizei, 1);
7058 const ParamCapture &strings =
7059 call.params.getParam("strings", ParamType::TGLcharConstPointerPointer, 2);
7060
7061 std::ostringstream sourceString;
7062 for (int i = 0; i < lineCount.value.GLsizeiVal; ++i)
7063 {
7064 sourceString << strings.value.GLcharConstPointerPointerVal[i];
7065 }
7066
7067 gl::ShaderType shaderType = paramCapture.value.ShaderTypeVal;
7068 ProgramSources source;
7069 source[shaderType] = sourceString.str();
7070 setProgramSources(programID, source);
7071 handleGennedResource(context, programID);
7072 mResourceTracker.setShaderProgramType(programID, ShaderProgramType::ProgramType);
7073 break;
7074 }
7075
7076 case EntryPoint::GLCreateProgram:
7077 {
7078 // If we're capturing, track which programs have been created
7079 gl::ShaderProgramID programID = {call.params.getReturnValue().value.GLuintVal};
7080 handleGennedResource(context, programID);
7081
7082 mResourceTracker.setShaderProgramType(programID, ShaderProgramType::ProgramType);
7083 break;
7084 }
7085
7086 case EntryPoint::GLDeleteProgram:
7087 {
7088 // If we're capturing, track which programs have been deleted
7089 const ParamCapture ¶m =
7090 call.params.getParam("programPacked", ParamType::TShaderProgramID, 0);
7091 handleDeletedResource(context, param.value.ShaderProgramIDVal);
7092
7093 // If this assert fires, it means a ShaderProgramID has changed from program to shader
7094 // which is unsupported
7095 ASSERT(mResourceTracker.getShaderProgramType(param.value.ShaderProgramIDVal) ==
7096 ShaderProgramType::ProgramType);
7097
7098 break;
7099 }
7100
7101 case EntryPoint::GLCreateShader:
7102 {
7103 // If we're capturing, track which shaders have been created
7104 gl::ShaderProgramID shaderID = {call.params.getReturnValue().value.GLuintVal};
7105 handleGennedResource(context, shaderID);
7106
7107 mResourceTracker.setShaderProgramType(shaderID, ShaderProgramType::ShaderType);
7108 break;
7109 }
7110
7111 case EntryPoint::GLDeleteShader:
7112 {
7113 // If we're capturing, track which shaders have been deleted
7114 const ParamCapture ¶m =
7115 call.params.getParam("shaderPacked", ParamType::TShaderProgramID, 0);
7116 handleDeletedResource(context, param.value.ShaderProgramIDVal);
7117
7118 // If this assert fires, it means a ShaderProgramID has changed from shader to program
7119 // which is unsupported
7120 ASSERT(mResourceTracker.getShaderProgramType(param.value.ShaderProgramIDVal) ==
7121 ShaderProgramType::ShaderType);
7122 break;
7123 }
7124
7125 case EntryPoint::GLCompileShader:
7126 {
7127 // Refresh the cached shader sources.
7128 gl::ShaderProgramID shaderID =
7129 call.params.getParam("shaderPacked", ParamType::TShaderProgramID, 0)
7130 .value.ShaderProgramIDVal;
7131 const gl::Shader *shader = context->getShaderNoResolveCompile(shaderID);
7132 // Shaders compiled for ProgramBinary will not have a shader created
7133 if (shader)
7134 {
7135 setShaderSource(shaderID, shader->getSourceString());
7136 }
7137 break;
7138 }
7139
7140 case EntryPoint::GLLinkProgram:
7141 {
7142 // Refresh the cached program sources.
7143 gl::ShaderProgramID programID =
7144 call.params.getParam("programPacked", ParamType::TShaderProgramID, 0)
7145 .value.ShaderProgramIDVal;
7146 const gl::Program *program = context->getProgramResolveLink(programID);
7147 // Programs linked in support of ProgramBinary will not have attached shaders
7148 if (program->getState().hasAnyAttachedShader())
7149 {
7150 setProgramSources(programID, GetAttachedProgramSources(context, program));
7151 }
7152 break;
7153 }
7154
7155 case EntryPoint::GLDeleteTextures:
7156 {
7157 // Free any TextureLevelDataMap entries being tracked for this texture
7158 // This is to cover the scenario where a texture has been created, its
7159 // levels cached, then texture deleted and recreated, receiving the same ID
7160
7161 // Look up how many textures are being deleted
7162 GLsizei n = call.params.getParam("n", ParamType::TGLsizei, 0).value.GLsizeiVal;
7163
7164 // Look up the pointer to list of textures
7165 const gl::TextureID *textureIDs =
7166 call.params.getParam("texturesPacked", ParamType::TTextureIDConstPointer, 1)
7167 .value.TextureIDConstPointerVal;
7168
7169 // For each texture listed for deletion
7170 for (int32_t i = 0; i < n; ++i)
7171 {
7172 // If we're capturing, track what textures have been deleted
7173 handleDeletedResource(context, textureIDs[i]);
7174 }
7175 break;
7176 }
7177
7178 case EntryPoint::GLMapBufferOES:
7179 {
7180 gl::BufferBinding target =
7181 call.params.getParam("targetPacked", ParamType::TBufferBinding, 0)
7182 .value.BufferBindingVal;
7183
7184 GLbitfield access =
7185 call.params.getParam("access", ParamType::TGLenum, 1).value.GLenumVal;
7186
7187 gl::Buffer *buffer = context->getState().getTargetBuffer(target);
7188
7189 GLintptr offset = 0;
7190 GLsizeiptr length = static_cast<GLsizeiptr>(buffer->getSize());
7191
7192 bool writable =
7193 access == GL_WRITE_ONLY_OES || access == GL_WRITE_ONLY || access == GL_READ_WRITE;
7194
7195 FrameCaptureShared *frameCaptureShared =
7196 context->getShareGroup()->getFrameCaptureShared();
7197 frameCaptureShared->trackBufferMapping(context, &call, buffer->id(), buffer, offset,
7198 length, writable, false);
7199 break;
7200 }
7201
7202 case EntryPoint::GLUnmapBuffer:
7203 case EntryPoint::GLUnmapBufferOES:
7204 {
7205 // See if we need to capture the buffer contents
7206 captureMappedBufferSnapshot(context, call);
7207
7208 // Track that the buffer was unmapped, for use during state reset
7209 gl::BufferBinding target =
7210 call.params.getParam("targetPacked", ParamType::TBufferBinding, 0)
7211 .value.BufferBindingVal;
7212 gl::Buffer *buffer = context->getState().getTargetBuffer(target);
7213 mResourceTracker.setBufferUnmapped(context->id(), buffer->id().value);
7214
7215 // Remove from CoherentBufferTracker
7216 mCoherentBufferTracker.removeBuffer(buffer->id());
7217 break;
7218 }
7219
7220 case EntryPoint::GLBufferData:
7221 case EntryPoint::GLBufferSubData:
7222 {
7223 gl::BufferBinding target =
7224 call.params.getParam("targetPacked", ParamType::TBufferBinding, 0)
7225 .value.BufferBindingVal;
7226
7227 gl::Buffer *buffer = context->getState().getTargetBuffer(target);
7228
7229 // Track that this buffer's contents have been modified
7230 mResourceTracker.getTrackedResource(context->id(), ResourceIDType::Buffer)
7231 .setModifiedResource(buffer->id().value);
7232
7233 // BufferData is equivalent to UnmapBuffer, for what we're tracking.
7234 // From the ES 3.1 spec in BufferData section:
7235 // If any portion of the buffer object is mapped in the current context or any
7236 // context current to another thread, it is as though UnmapBuffer (see section
7237 // 6.3.1) is executed in each such context prior to deleting the existing data
7238 // store.
7239 // Track that the buffer was unmapped, for use during state reset
7240 mResourceTracker.setBufferUnmapped(context->id(), buffer->id().value);
7241
7242 break;
7243 }
7244
7245 case EntryPoint::GLCopyBufferSubData:
7246 {
7247 maybeCaptureCoherentBuffers(context);
7248 break;
7249 }
7250 case EntryPoint::GLFinish:
7251 {
7252 // When using shadow memory we might need to synchronize it here.
7253 if (mCoherentBufferTracker.isShadowMemoryEnabled())
7254 {
7255 mCoherentBufferTracker.maybeUpdateShadowMemory();
7256 }
7257 break;
7258 }
7259 case EntryPoint::GLDeleteFramebuffers:
7260 case EntryPoint::GLDeleteFramebuffersOES:
7261 {
7262 // Look up how many framebuffers are being deleted
7263 GLsizei n = call.params.getParam("n", ParamType::TGLsizei, 0).value.GLsizeiVal;
7264
7265 // Look up the pointer to list of framebuffers
7266 const gl::FramebufferID *framebufferIDs =
7267 call.params.getParam("framebuffersPacked", ParamType::TFramebufferIDConstPointer, 1)
7268 .value.FramebufferIDConstPointerVal;
7269
7270 // For each framebuffer listed for deletion
7271 for (int32_t i = 0; i < n; ++i)
7272 {
7273 // If we're capturing, track what framebuffers have been deleted
7274 handleDeletedResource(context, framebufferIDs[i]);
7275 }
7276 break;
7277 }
7278
7279 case EntryPoint::GLUseProgram:
7280 {
7281 if (isCaptureActive())
7282 {
7283 context->getFrameCapture()->getStateResetHelper().setEntryPointDirty(
7284 EntryPoint::GLUseProgram);
7285 }
7286 break;
7287 }
7288
7289 case EntryPoint::GLGenVertexArrays:
7290 case EntryPoint::GLGenVertexArraysOES:
7291 {
7292 GLsizei count = call.params.getParam("n", ParamType::TGLsizei, 0).value.GLsizeiVal;
7293 const gl::VertexArrayID *arrayIDs =
7294 call.params.getParam("arraysPacked", ParamType::TVertexArrayIDPointer, 1)
7295 .value.VertexArrayIDPointerVal;
7296 for (GLsizei i = 0; i < count; i++)
7297 {
7298 handleGennedResource(context, arrayIDs[i]);
7299 }
7300 break;
7301 }
7302
7303 case EntryPoint::GLDeleteVertexArrays:
7304 case EntryPoint::GLDeleteVertexArraysOES:
7305 {
7306 GLsizei count = call.params.getParam("n", ParamType::TGLsizei, 0).value.GLsizeiVal;
7307 const gl::VertexArrayID *arrayIDs =
7308 call.params.getParam("arraysPacked", ParamType::TVertexArrayIDConstPointer, 1)
7309 .value.VertexArrayIDConstPointerVal;
7310 for (GLsizei i = 0; i < count; i++)
7311 {
7312 // If we're capturing, track which vertex arrays have been deleted
7313 handleDeletedResource(context, arrayIDs[i]);
7314 }
7315 break;
7316 }
7317
7318 case EntryPoint::GLBindVertexArray:
7319 case EntryPoint::GLBindVertexArrayOES:
7320 {
7321 if (isCaptureActive())
7322 {
7323 context->getFrameCapture()->getStateResetHelper().setEntryPointDirty(
7324 EntryPoint::GLBindVertexArray);
7325 }
7326 break;
7327 }
7328 case EntryPoint::GLBlendFunc:
7329 {
7330 if (isCaptureActive())
7331 {
7332 context->getFrameCapture()->getStateResetHelper().setEntryPointDirty(
7333 EntryPoint::GLBlendFunc);
7334 }
7335 break;
7336 }
7337 case EntryPoint::GLBlendFuncSeparate:
7338 {
7339 if (isCaptureActive())
7340 {
7341 context->getFrameCapture()->getStateResetHelper().setEntryPointDirty(
7342 EntryPoint::GLBlendFuncSeparate);
7343 }
7344 break;
7345 }
7346 case EntryPoint::GLBlendEquation:
7347 case EntryPoint::GLBlendEquationSeparate:
7348 {
7349 if (isCaptureActive())
7350 {
7351 context->getFrameCapture()->getStateResetHelper().setEntryPointDirty(
7352 EntryPoint::GLBlendEquationSeparate);
7353 }
7354 break;
7355 }
7356 case EntryPoint::GLColorMask:
7357 {
7358 if (isCaptureActive())
7359 {
7360 context->getFrameCapture()->getStateResetHelper().setEntryPointDirty(
7361 EntryPoint::GLColorMask);
7362 }
7363 break;
7364 }
7365 case EntryPoint::GLBlendColor:
7366 {
7367 if (isCaptureActive())
7368 {
7369 context->getFrameCapture()->getStateResetHelper().setEntryPointDirty(
7370 EntryPoint::GLBlendColor);
7371 }
7372 break;
7373 }
7374
7375 case EntryPoint::GLEGLImageTargetTexture2DOES:
7376 {
7377 gl::TextureType target =
7378 call.params.getParam("targetPacked", ParamType::TTextureType, 0)
7379 .value.TextureTypeVal;
7380 egl::ImageID imageID =
7381 call.params.getParam("imagePacked", ParamType::TImageID, 1).value.ImageIDVal;
7382 mResourceTracker.getTextureIDToImageTable().insert(std::pair<GLuint, egl::ImageID>(
7383 context->getState().getTargetTexture(target)->getId(), imageID));
7384 break;
7385 }
7386
7387 case EntryPoint::EGLCreateImage:
7388 {
7389 CreateEGLImagePreCallUpdate<EGLAttrib>(call, mResourceTracker,
7390 ParamType::TEGLAttribPointer,
7391 egl::AttributeMap::CreateFromAttribArray);
7392 if (isCaptureActive())
7393 {
7394 EGLImage eglImage = call.params.getReturnValue().value.EGLImageVal;
7395 egl::ImageID imageID = egl::PackParam<egl::ImageID>(eglImage);
7396 handleGennedResource(context, imageID);
7397 }
7398 break;
7399 }
7400 case EntryPoint::EGLCreateImageKHR:
7401 {
7402 CreateEGLImagePreCallUpdate<EGLint>(call, mResourceTracker, ParamType::TEGLintPointer,
7403 egl::AttributeMap::CreateFromIntArray);
7404 if (isCaptureActive())
7405 {
7406 EGLImageKHR eglImage = call.params.getReturnValue().value.EGLImageKHRVal;
7407 egl::ImageID imageID = egl::PackParam<egl::ImageID>(eglImage);
7408 handleGennedResource(context, imageID);
7409 }
7410 break;
7411 }
7412 case EntryPoint::EGLDestroyImage:
7413 case EntryPoint::EGLDestroyImageKHR:
7414 {
7415 egl::ImageID eglImageID =
7416 call.params.getParam("imagePacked", ParamType::TImageID, 1).value.ImageIDVal;
7417
7418 // Clear any texture->image mappings that involve this image
7419 for (auto texImageIter = mResourceTracker.getTextureIDToImageTable().begin();
7420 texImageIter != mResourceTracker.getTextureIDToImageTable().end();)
7421 {
7422 if (texImageIter->second == eglImageID)
7423 {
7424 texImageIter = mResourceTracker.getTextureIDToImageTable().erase(texImageIter);
7425 }
7426 else
7427 {
7428 ++texImageIter;
7429 }
7430 }
7431
7432 FrameCaptureShared *frameCaptureShared =
7433 context->getShareGroup()->getFrameCaptureShared();
7434 if (frameCaptureShared->isCaptureActive())
7435 {
7436 handleDeletedResource(context, eglImageID);
7437 }
7438 break;
7439 }
7440 case EntryPoint::EGLCreateSync:
7441 case EntryPoint::EGLCreateSyncKHR:
7442 {
7443 egl::SyncID eglSyncID = call.params.getReturnValue().value.egl_SyncIDVal;
7444 FrameCaptureShared *frameCaptureShared =
7445 context->getShareGroup()->getFrameCaptureShared();
7446 // If we're capturing, track which egl sync has been created
7447 if (frameCaptureShared->isCaptureActive())
7448 {
7449 handleGennedResource(context, eglSyncID);
7450 }
7451 break;
7452 }
7453 case EntryPoint::EGLDestroySync:
7454 case EntryPoint::EGLDestroySyncKHR:
7455 {
7456 egl::SyncID eglSyncID =
7457 call.params.getParam("syncPacked", ParamType::Tegl_SyncID, 1).value.egl_SyncIDVal;
7458 FrameCaptureShared *frameCaptureShared =
7459 context->getShareGroup()->getFrameCaptureShared();
7460 // If we're capturing, track which EGL sync has been deleted
7461 if (frameCaptureShared->isCaptureActive())
7462 {
7463 handleDeletedResource(context, eglSyncID);
7464 }
7465 break;
7466 }
7467 case EntryPoint::GLDispatchCompute:
7468 {
7469 // When using shadow memory we need to update the real memory here
7470 if (mCoherentBufferTracker.isShadowMemoryEnabled())
7471 {
7472 maybeCaptureCoherentBuffers(context);
7473 }
7474 break;
7475 }
7476 default:
7477 break;
7478 }
7479
7480 if (IsTextureUpdate(call))
7481 {
7482 // If this call modified texture contents, track it for possible reset
7483 trackTextureUpdate(context, call);
7484 }
7485
7486 if (IsImageUpdate(call))
7487 {
7488 // If this call modified shader image contents, track it for possible reset
7489 trackImageUpdate(context, call);
7490 }
7491
7492 if (isCaptureActive() && GetDefaultUniformType(call) != DefaultUniformType::None)
7493 {
7494 trackDefaultUniformUpdate(context, call);
7495 }
7496
7497 if (IsVertexArrayUpdate(call))
7498 {
7499 trackVertexArrayUpdate(context, call);
7500 }
7501
7502 updateReadBufferSize(call.params.getReadBufferSize());
7503
7504 std::vector<gl::ShaderProgramID> shaderProgramIDs;
7505 if (FindResourceIDsInCall<gl::ShaderProgramID>(call, shaderProgramIDs))
7506 {
7507 for (gl::ShaderProgramID shaderProgramID : shaderProgramIDs)
7508 {
7509 mResourceTracker.onShaderProgramAccess(shaderProgramID);
7510
7511 if (isCaptureActive())
7512 {
7513 // Track that this call referenced a ShaderProgram, setting it active for Setup
7514 MarkResourceIDActive(ResourceIDType::ShaderProgram, shaderProgramID.value,
7515 shareGroupSetupCalls, resourceIDToSetupCalls);
7516 }
7517 }
7518 }
7519
7520 std::vector<gl::TextureID> textureIDs;
7521 if (FindResourceIDsInCall<gl::TextureID>(call, textureIDs))
7522 {
7523 for (gl::TextureID textureID : textureIDs)
7524 {
7525 if (isCaptureActive())
7526 {
7527 // Track that this call referenced a Texture, setting it active for Setup
7528 MarkResourceIDActive(ResourceIDType::Texture, textureID.value, shareGroupSetupCalls,
7529 resourceIDToSetupCalls);
7530 }
7531 }
7532 }
7533 }
7534
7535 template <typename ParamValueType>
maybeGenResourceOnBind(const gl::Context * context,CallCapture & call)7536 void FrameCaptureShared::maybeGenResourceOnBind(const gl::Context *context, CallCapture &call)
7537 {
7538 const char *paramName = ParamValueTrait<ParamValueType>::name;
7539 const ParamType paramType = ParamValueTrait<ParamValueType>::typeID;
7540
7541 const ParamCapture ¶m = call.params.getParam(paramName, paramType, 1);
7542 const ParamValueType id = AccessParamValue<ParamValueType>(paramType, param.value);
7543
7544 // Don't inject the default resource or resources that are already generated
7545 if (id.value != 0 && !resourceIsGenerated(context, id))
7546 {
7547 handleGennedResource(context, id);
7548
7549 ResourceIDType resourceIDType = GetResourceIDTypeFromParamType(param.type);
7550 const char *resourceName = GetResourceIDTypeName(resourceIDType);
7551
7552 std::stringstream updateFuncNameStr;
7553 updateFuncNameStr << "Set" << resourceName << "ID";
7554 ParamBuffer params;
7555 if (IsTrackedPerContext(resourceIDType))
7556 {
7557 // TODO (https://issuetracker.google.com/169868803) The '2' version can be removed after
7558 // all context-local objects are tracked per-context
7559 updateFuncNameStr << "2";
7560 params.addValueParam("contextID", ParamType::TGLuint, context->id().value);
7561 }
7562 std::string updateFuncName = updateFuncNameStr.str();
7563 params.addValueParam("id", ParamType::TGLuint, id.value);
7564 mFrameCalls.emplace_back(updateFuncName, std::move(params));
7565 }
7566 }
7567
updateResourceCountsFromParamCapture(const ParamCapture & param,ResourceIDType idType)7568 void FrameCaptureShared::updateResourceCountsFromParamCapture(const ParamCapture ¶m,
7569 ResourceIDType idType)
7570 {
7571 if (idType != ResourceIDType::InvalidEnum)
7572 {
7573 mHasResourceType.set(idType);
7574
7575 // Capture resource IDs for non-pointer types.
7576 if (strcmp(ParamTypeToString(param.type), "GLuint") == 0)
7577 {
7578 mMaxAccessedResourceIDs[idType] =
7579 std::max(mMaxAccessedResourceIDs[idType], param.value.GLuintVal);
7580 }
7581 // Capture resource IDs for pointer types.
7582 if (strstr(ParamTypeToString(param.type), "GLuint *") != nullptr)
7583 {
7584 if (param.data.size() == 1u)
7585 {
7586 const GLuint *dataPtr = reinterpret_cast<const GLuint *>(param.data[0].data());
7587 size_t numHandles = param.data[0].size() / sizeof(GLuint);
7588 for (size_t handleIndex = 0; handleIndex < numHandles; ++handleIndex)
7589 {
7590 mMaxAccessedResourceIDs[idType] =
7591 std::max(mMaxAccessedResourceIDs[idType], dataPtr[handleIndex]);
7592 }
7593 }
7594 }
7595 if (idType == ResourceIDType::Sync)
7596 {
7597 mMaxAccessedResourceIDs[idType] =
7598 std::max(mMaxAccessedResourceIDs[idType], param.value.GLuintVal);
7599 }
7600 }
7601 }
7602
updateResourceCountsFromCallCapture(const CallCapture & call)7603 void FrameCaptureShared::updateResourceCountsFromCallCapture(const CallCapture &call)
7604 {
7605
7606 for (const ParamCapture ¶m : call.params.getParamCaptures())
7607 {
7608 ResourceIDType idType = GetResourceIDTypeFromParamType(param.type);
7609 updateResourceCountsFromParamCapture(param, idType);
7610 }
7611
7612 // Update resource IDs in the return value. Return values types are not stored as resource IDs,
7613 // but instead are stored as GLuints. Therefore we need to explicitly label the resource ID type
7614 // when we call update. Currently only shader and program creation are explicitly tracked.
7615 switch (call.entryPoint)
7616 {
7617 case EntryPoint::GLCreateShader:
7618 case EntryPoint::GLCreateProgram:
7619 updateResourceCountsFromParamCapture(call.params.getReturnValue(),
7620 ResourceIDType::ShaderProgram);
7621 break;
7622
7623 case EntryPoint::GLFenceSync:
7624 updateResourceCountsFromParamCapture(call.params.getReturnValue(),
7625 ResourceIDType::Sync);
7626 break;
7627 case EntryPoint::EGLCreateSync:
7628 case EntryPoint::EGLCreateSyncKHR:
7629 updateResourceCountsFromParamCapture(call.params.getReturnValue(),
7630 ResourceIDType::egl_Sync);
7631 break;
7632 default:
7633 break;
7634 }
7635 }
7636
captureCall(gl::Context * context,CallCapture && inCall,bool isCallValid)7637 void FrameCaptureShared::captureCall(gl::Context *context, CallCapture &&inCall, bool isCallValid)
7638 {
7639 if (SkipCall(inCall.entryPoint))
7640 {
7641 return;
7642 }
7643
7644 if (isCallValid)
7645 {
7646 // Save the call's contextID
7647 inCall.contextID = context->id();
7648
7649 // Update resource counts before we override entry points with custom calls.
7650 updateResourceCountsFromCallCapture(inCall);
7651
7652 size_t j = mFrameCalls.size();
7653
7654 std::vector<CallCapture> outCalls;
7655 maybeOverrideEntryPoint(context, inCall, outCalls);
7656
7657 // Need to loop on any new calls we added during override
7658 for (CallCapture &call : outCalls)
7659 {
7660 // During capture, consider all frame calls active
7661 if (isCaptureActive())
7662 {
7663 call.isActive = true;
7664 }
7665
7666 maybeCapturePreCallUpdates(context, call, &mShareGroupSetupCalls,
7667 &mResourceIDToSetupCalls);
7668 mFrameCalls.emplace_back(std::move(call));
7669 maybeCapturePostCallUpdates(context);
7670 }
7671
7672 // Tag all 'added' commands with this context
7673 for (size_t k = j; k < mFrameCalls.size(); k++)
7674 {
7675 mFrameCalls[k].contextID = context->id();
7676 }
7677
7678 // Evaluate the validation expression to determine if we insert a validation checkpoint.
7679 // This lets the user pick a subset of calls to check instead of checking every call.
7680 if (mValidateSerializedState && !mValidationExpression.empty())
7681 {
7682 // Example substitution for frame #2, call #110:
7683 // Before: (call == 2) && (frame >= 100) && (frame <= 120) && ((frame % 10) == 0)
7684 // After: (2 == 2) && (110 >= 100) && (110 <= 120) && ((110 % 10) == 0)
7685 // Evaluates to 1.0.
7686 std::string expression = mValidationExpression;
7687
7688 angle::ReplaceAllSubstrings(&expression, "frame", std::to_string(mFrameIndex));
7689 angle::ReplaceAllSubstrings(&expression, "call", std::to_string(mFrameCalls.size()));
7690
7691 double result = ceval_result(expression);
7692 if (result > 0)
7693 {
7694 CaptureValidateSerializedState(context, &mFrameCalls);
7695 }
7696 }
7697 }
7698 else
7699 {
7700 const int maxInvalidCallLogs = 3;
7701 size_t &callCount = isCaptureActive() ? mInvalidCallCountsActive[inCall.entryPoint]
7702 : mInvalidCallCountsInactive[inCall.entryPoint];
7703 callCount++;
7704 if (callCount <= maxInvalidCallLogs)
7705 {
7706 std::ostringstream msg;
7707 msg << "FrameCapture (capture " << (isCaptureActive() ? "active" : "inactive")
7708 << "): Not capturing invalid call to " << GetEntryPointName(inCall.entryPoint);
7709 if (callCount == maxInvalidCallLogs)
7710 {
7711 msg << " (will no longer repeat for this entry point)";
7712 }
7713 INFO() << msg.str();
7714 }
7715
7716 std::stringstream skipCall;
7717 skipCall << "Skipping invalid call to " << GetEntryPointName(inCall.entryPoint)
7718 << " with error: "
7719 << gl::GLenumToString(gl::GLESEnum::ErrorCode, context->getErrorForCapture());
7720 AddComment(&mFrameCalls, skipCall.str());
7721 }
7722 }
7723
maybeCapturePostCallUpdates(const gl::Context * context)7724 void FrameCaptureShared::maybeCapturePostCallUpdates(const gl::Context *context)
7725 {
7726 // Process resource ID updates.
7727 if (isCaptureActive())
7728 {
7729 MaybeCaptureUpdateResourceIDs(context, &mResourceTracker, &mFrameCalls);
7730 }
7731
7732 CallCapture &lastCall = mFrameCalls.back();
7733 switch (lastCall.entryPoint)
7734 {
7735 case EntryPoint::GLCreateShaderProgramv:
7736 {
7737 gl::ShaderProgramID programId;
7738 programId.value = lastCall.params.getReturnValue().value.GLuintVal;
7739 const gl::Program *program = context->getProgramResolveLink(programId);
7740 CaptureUpdateUniformLocations(program, &mFrameCalls);
7741 CaptureUpdateUniformBlockIndexes(program, &mFrameCalls);
7742 break;
7743 }
7744 case EntryPoint::GLLinkProgram:
7745 {
7746 const ParamCapture ¶m =
7747 lastCall.params.getParam("programPacked", ParamType::TShaderProgramID, 0);
7748 const gl::Program *program =
7749 context->getProgramResolveLink(param.value.ShaderProgramIDVal);
7750 CaptureUpdateUniformLocations(program, &mFrameCalls);
7751 CaptureUpdateUniformBlockIndexes(program, &mFrameCalls);
7752 break;
7753 }
7754 case EntryPoint::GLUseProgram:
7755 CaptureUpdateCurrentProgram(lastCall, 0, &mFrameCalls);
7756 break;
7757 case EntryPoint::GLActiveShaderProgram:
7758 CaptureUpdateCurrentProgram(lastCall, 1, &mFrameCalls);
7759 break;
7760 case EntryPoint::GLDeleteProgram:
7761 {
7762 const ParamCapture ¶m =
7763 lastCall.params.getParam("programPacked", ParamType::TShaderProgramID, 0);
7764 CaptureDeleteUniformLocations(param.value.ShaderProgramIDVal, &mFrameCalls);
7765 break;
7766 }
7767 case EntryPoint::GLShaderSource:
7768 {
7769 lastCall.params.setValueParamAtIndex("count", ParamType::TGLsizei, 1, 1);
7770
7771 ParamCapture ¶mLength =
7772 lastCall.params.getParam("length", ParamType::TGLintConstPointer, 3);
7773 paramLength.data.resize(1);
7774 // Set the length parameter to {-1} to signal that the actual string length
7775 // is to be used. Since we store the parameter blob as an array of four uint8_t
7776 // values, we have to pass the binary equivalent of -1.
7777 paramLength.data[0] = {0xff, 0xff, 0xff, 0xff};
7778 break;
7779 }
7780 case EntryPoint::GLBufferData:
7781 case EntryPoint::GLBufferSubData:
7782 {
7783 // When using shadow memory we need to update it from real memory here
7784 if (mCoherentBufferTracker.isShadowMemoryEnabled())
7785 {
7786 gl::BufferBinding target =
7787 lastCall.params.getParam("targetPacked", ParamType::TBufferBinding, 0)
7788 .value.BufferBindingVal;
7789
7790 gl::Buffer *buffer = context->getState().getTargetBuffer(target);
7791 if (mCoherentBufferTracker.haveBuffer(buffer->id()))
7792 {
7793 std::shared_ptr<CoherentBuffer> cb =
7794 mCoherentBufferTracker.mBuffers[buffer->id().value];
7795 cb->removeProtection(PageSharingType::NoneShared);
7796 cb->updateShadowMemory();
7797 cb->protectAll();
7798 }
7799 }
7800 break;
7801 }
7802
7803 case EntryPoint::GLCopyBufferSubData:
7804 {
7805 // When using shadow memory, we need to mark the buffer shadowDirty bit to true
7806 // so it will be synchronized with real memory on the next glFinish call.
7807 if (mCoherentBufferTracker.isShadowMemoryEnabled())
7808 {
7809 gl::BufferBinding target =
7810 lastCall.params.getParam("writeTargetPacked", ParamType::TBufferBinding, 1)
7811 .value.BufferBindingVal;
7812
7813 gl::Buffer *buffer = context->getState().getTargetBuffer(target);
7814 if (mCoherentBufferTracker.haveBuffer(buffer->id()))
7815 {
7816 std::shared_ptr<CoherentBuffer> cb =
7817 mCoherentBufferTracker.mBuffers[buffer->id().value];
7818 // This needs to be synced on glFinish
7819 cb->markShadowDirty();
7820 }
7821 }
7822 break;
7823 }
7824 case EntryPoint::GLDispatchCompute:
7825 {
7826 // When using shadow memory, we need to mark all buffer's shadowDirty bit to true
7827 // so they will be synchronized with real memory on the next glFinish call.
7828 if (mCoherentBufferTracker.isShadowMemoryEnabled())
7829 {
7830 mCoherentBufferTracker.markAllShadowDirty();
7831 }
7832 break;
7833 }
7834 default:
7835 break;
7836 }
7837 }
7838
captureClientArraySnapshot(const gl::Context * context,size_t vertexCount,size_t instanceCount)7839 void FrameCaptureShared::captureClientArraySnapshot(const gl::Context *context,
7840 size_t vertexCount,
7841 size_t instanceCount)
7842 {
7843 if (vertexCount == 0)
7844 {
7845 // Nothing to capture
7846 return;
7847 }
7848
7849 const gl::VertexArray *vao = context->getState().getVertexArray();
7850
7851 // Capture client array data.
7852 for (size_t attribIndex : context->getStateCache().getActiveClientAttribsMask())
7853 {
7854 const gl::VertexAttribute &attrib = vao->getVertexAttribute(attribIndex);
7855 const gl::VertexBinding &binding = vao->getVertexBinding(attrib.bindingIndex);
7856
7857 int callIndex = mClientVertexArrayMap[attribIndex];
7858
7859 if (callIndex != -1)
7860 {
7861 size_t count = vertexCount;
7862
7863 if (binding.getDivisor() > 0)
7864 {
7865 count = rx::UnsignedCeilDivide(static_cast<uint32_t>(instanceCount),
7866 binding.getDivisor());
7867 }
7868
7869 // The last capture element doesn't take up the full stride.
7870 size_t bytesToCapture = (count - 1) * binding.getStride() + attrib.format->pixelBytes;
7871
7872 CallCapture &call = mFrameCalls[callIndex];
7873 ParamCapture ¶m = call.params.getClientArrayPointerParameter();
7874 ASSERT(param.type == ParamType::TvoidConstPointer);
7875
7876 ParamBuffer updateParamBuffer;
7877 updateParamBuffer.addValueParam<GLint>("arrayIndex", ParamType::TGLint,
7878 static_cast<uint32_t>(attribIndex));
7879
7880 ParamCapture updateMemory("pointer", ParamType::TvoidConstPointer);
7881 CaptureMemory(param.value.voidConstPointerVal, bytesToCapture, &updateMemory);
7882 updateParamBuffer.addParam(std::move(updateMemory));
7883
7884 updateParamBuffer.addValueParam<GLuint64>("size", ParamType::TGLuint64, bytesToCapture);
7885
7886 mFrameCalls.emplace_back("UpdateClientArrayPointer", std::move(updateParamBuffer));
7887
7888 mClientArraySizes[attribIndex] =
7889 std::max(mClientArraySizes[attribIndex], bytesToCapture);
7890 }
7891 }
7892 }
7893
captureCoherentBufferSnapshot(const gl::Context * context,gl::BufferID id)7894 void FrameCaptureShared::captureCoherentBufferSnapshot(const gl::Context *context, gl::BufferID id)
7895 {
7896 if (!hasBufferData(id))
7897 {
7898 // This buffer was not marked writable
7899 return;
7900 }
7901
7902 const gl::State &apiState = context->getState();
7903 const gl::BufferManager &buffers = apiState.getBufferManagerForCapture();
7904 gl::Buffer *buffer = buffers.getBuffer(id);
7905 if (!buffer)
7906 {
7907 // Could not find buffer binding
7908 return;
7909 }
7910
7911 ASSERT(buffer->isMapped());
7912
7913 std::shared_ptr<angle::CoherentBuffer> coherentBuffer =
7914 mCoherentBufferTracker.mBuffers[id.value];
7915
7916 std::vector<PageRange> dirtyPageRanges = coherentBuffer->getDirtyPageRanges();
7917
7918 if (mCoherentBufferTracker.isShadowMemoryEnabled() && !dirtyPageRanges.empty())
7919 {
7920 coherentBuffer->updateBufferMemory();
7921 }
7922
7923 AddressRange wholeRange = coherentBuffer->getRange();
7924
7925 for (PageRange &pageRange : dirtyPageRanges)
7926 {
7927 // Write protect the memory already, so the app is blocked on writing during our capture
7928 coherentBuffer->protectPageRange(pageRange);
7929
7930 // Create the parameters to our helper for use during replay
7931 ParamBuffer dataParamBuffer;
7932
7933 // Pass in the target buffer ID
7934 dataParamBuffer.addValueParam("dest", ParamType::TGLuint, buffer->id().value);
7935
7936 // Capture the current buffer data with a binary param
7937 ParamCapture captureData("source", ParamType::TvoidConstPointer);
7938
7939 AddressRange dirtyRange = coherentBuffer->getDirtyAddressRange(pageRange);
7940 CaptureMemory(reinterpret_cast<void *>(dirtyRange.start), dirtyRange.size, &captureData);
7941 dataParamBuffer.addParam(std::move(captureData));
7942
7943 // Also track its size for use with memcpy
7944 dataParamBuffer.addValueParam<GLsizeiptr>("size", ParamType::TGLsizeiptr,
7945 static_cast<GLsizeiptr>(dirtyRange.size));
7946
7947 if (wholeRange.start != dirtyRange.start)
7948 {
7949 // Capture with offset
7950 GLsizeiptr offset = dirtyRange.start - wholeRange.start;
7951
7952 ASSERT(offset > 0);
7953
7954 // The dirty page range is not at the start of the buffer, track the offset.
7955 dataParamBuffer.addValueParam<GLsizeiptr>("offset", ParamType::TGLsizeiptr, offset);
7956
7957 // Call the helper that populates the buffer with captured data
7958 mFrameCalls.emplace_back("UpdateClientBufferDataWithOffset",
7959 std::move(dataParamBuffer));
7960 }
7961 else
7962 {
7963 // Call the helper that populates the buffer with captured data
7964 mFrameCalls.emplace_back("UpdateClientBufferData", std::move(dataParamBuffer));
7965 }
7966 }
7967 }
7968
captureMappedBufferSnapshot(const gl::Context * context,const CallCapture & call)7969 void FrameCaptureShared::captureMappedBufferSnapshot(const gl::Context *context,
7970 const CallCapture &call)
7971 {
7972 // If the buffer was mapped writable, we need to restore its data, since we have no
7973 // visibility into what the client did to the buffer while mapped.
7974 // This sequence will result in replay calls like this:
7975 // ...
7976 // gMappedBufferData[gBufferMap[42]] = glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, 65536,
7977 // GL_MAP_WRITE_BIT);
7978 // ...
7979 // UpdateClientBufferData(42, &gBinaryData[164631024], 65536);
7980 // glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
7981 // ...
7982
7983 // Re-map the buffer, using the info we tracked about the buffer
7984 gl::BufferBinding target =
7985 call.params.getParam("targetPacked", ParamType::TBufferBinding, 0).value.BufferBindingVal;
7986
7987 FrameCaptureShared *frameCaptureShared = context->getShareGroup()->getFrameCaptureShared();
7988 gl::Buffer *buffer = context->getState().getTargetBuffer(target);
7989 if (!frameCaptureShared->hasBufferData(buffer->id()))
7990 {
7991 // This buffer was not marked writable, so we did not back it up
7992 return;
7993 }
7994
7995 std::pair<GLintptr, GLsizeiptr> bufferDataOffsetAndLength =
7996 frameCaptureShared->getBufferDataOffsetAndLength(buffer->id());
7997 GLintptr offset = bufferDataOffsetAndLength.first;
7998 GLsizeiptr length = bufferDataOffsetAndLength.second;
7999
8000 // Map the buffer so we can copy its contents out
8001 ASSERT(!buffer->isMapped());
8002 angle::Result result = buffer->mapRange(context, offset, length, GL_MAP_READ_BIT);
8003 if (result != angle::Result::Continue)
8004 {
8005 ERR() << "Failed to mapRange of buffer" << std::endl;
8006 }
8007 const uint8_t *data = reinterpret_cast<const uint8_t *>(buffer->getMapPointer());
8008
8009 // Create the parameters to our helper for use during replay
8010 ParamBuffer dataParamBuffer;
8011
8012 // Pass in the target buffer ID
8013 dataParamBuffer.addValueParam("dest", ParamType::TGLuint, buffer->id().value);
8014
8015 // Capture the current buffer data with a binary param
8016 ParamCapture captureData("source", ParamType::TvoidConstPointer);
8017 CaptureMemory(data, length, &captureData);
8018 dataParamBuffer.addParam(std::move(captureData));
8019
8020 // Also track its size for use with memcpy
8021 dataParamBuffer.addValueParam<GLsizeiptr>("size", ParamType::TGLsizeiptr, length);
8022
8023 // Call the helper that populates the buffer with captured data
8024 mFrameCalls.emplace_back("UpdateClientBufferData", std::move(dataParamBuffer));
8025
8026 // Unmap the buffer and move on
8027 GLboolean dontCare;
8028 (void)buffer->unmap(context, &dontCare);
8029 }
8030
checkForCaptureTrigger()8031 void FrameCaptureShared::checkForCaptureTrigger()
8032 {
8033 // Determine if trigger has changed
8034 std::string captureTriggerStr = GetCaptureTrigger();
8035 if (captureTriggerStr.empty())
8036 {
8037 return;
8038 }
8039
8040 // If the value has changed, use the original value as the frame count
8041 uint32_t captureTrigger = atoi(captureTriggerStr.c_str());
8042 if ((mCaptureTrigger > 0) && (captureTrigger == 0))
8043 {
8044 // Start mid-execution capture for the current frame
8045 mCaptureStartFrame = mFrameIndex + 1;
8046
8047 // Use the original trigger value as the frame count
8048 mCaptureEndFrame = mCaptureStartFrame + mCaptureTrigger - 1;
8049
8050 INFO() << "Capture triggered after frame " << mFrameIndex << " for " << mCaptureTrigger
8051 << " frames";
8052
8053 // Stop polling
8054 mCaptureTrigger = 0;
8055 }
8056 else if (captureTrigger > 0)
8057 {
8058 // Update number of frames to capture in MEC
8059 mCaptureTrigger = captureTrigger;
8060 }
8061 }
8062
scanSetupCalls(std::vector<CallCapture> & setupCalls)8063 void FrameCaptureShared::scanSetupCalls(std::vector<CallCapture> &setupCalls)
8064 {
8065 // Scan all the instructions in the list for tracking
8066 for (CallCapture &call : setupCalls)
8067 {
8068 updateReadBufferSize(call.params.getReadBufferSize());
8069 updateResourceCountsFromCallCapture(call);
8070 }
8071 }
8072
runMidExecutionCapture(gl::Context * mainContext)8073 void FrameCaptureShared::runMidExecutionCapture(gl::Context *mainContext)
8074 {
8075 // Set the capture active to ensure all GLES commands issued by the next frame are
8076 // handled correctly by maybeCapturePreCallUpdates() and maybeCapturePostCallUpdates().
8077 setCaptureActive();
8078
8079 // Make sure all pending work for every Context in the share group has completed so all data
8080 // (buffers, textures, etc.) has been updated and no resources are in use.
8081 egl::ShareGroup *shareGroup = mainContext->getShareGroup();
8082 shareGroup->finishAllContexts();
8083
8084 const gl::State &contextState = mainContext->getState();
8085 gl::State mainContextReplayState(
8086 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, contextState.getClientVersion(),
8087 false, true, true, true, false, EGL_CONTEXT_PRIORITY_MEDIUM_IMG,
8088 contextState.hasRobustAccess(), contextState.hasProtectedContent(), false);
8089 mainContextReplayState.initializeForCapture(mainContext);
8090
8091 CaptureShareGroupMidExecutionSetup(mainContext, &mShareGroupSetupCalls, &mResourceTracker,
8092 mainContextReplayState, mMaxAccessedResourceIDs);
8093
8094 scanSetupCalls(mShareGroupSetupCalls);
8095
8096 egl::Display *display = mainContext->getDisplay();
8097 egl::Surface *draw = mainContext->getCurrentDrawSurface();
8098 egl::Surface *read = mainContext->getCurrentReadSurface();
8099
8100 for (auto shareContext : shareGroup->getContexts())
8101 {
8102 FrameCapture *frameCapture = shareContext.second->getFrameCapture();
8103 ASSERT(frameCapture->getSetupCalls().empty());
8104
8105 if (shareContext.second->id() == mainContext->id())
8106 {
8107 CaptureMidExecutionSetup(shareContext.second, &frameCapture->getSetupCalls(),
8108 frameCapture->getStateResetHelper(), &mShareGroupSetupCalls,
8109 &mResourceIDToSetupCalls, &mResourceTracker,
8110 mainContextReplayState, mValidateSerializedState);
8111 scanSetupCalls(frameCapture->getSetupCalls());
8112
8113 std::stringstream protoStream;
8114 std::stringstream headerStream;
8115 std::stringstream bodyStream;
8116
8117 protoStream << "void "
8118 << FmtSetupFunction(kNoPartId, mainContext->id(), FuncUsage::Prototype);
8119 std::string proto = protoStream.str();
8120
8121 WriteCppReplayFunctionWithParts(mainContext->id(), ReplayFunc::Setup, mReplayWriter, 1,
8122 &mBinaryData, frameCapture->getSetupCalls(),
8123 headerStream, bodyStream, &mResourceIDBufferSize);
8124
8125 mReplayWriter.addPrivateFunction(proto, headerStream, bodyStream);
8126 }
8127 else
8128 {
8129 const gl::State &shareContextState = shareContext.second->getState();
8130 gl::State auxContextReplayState(nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
8131 shareContextState.getClientVersion(), false, true, true,
8132 true, false, EGL_CONTEXT_PRIORITY_MEDIUM_IMG,
8133 shareContextState.hasRobustAccess(),
8134 shareContextState.hasProtectedContent(), false);
8135 auxContextReplayState.initializeForCapture(shareContext.second);
8136
8137 egl::Error error = shareContext.second->makeCurrent(display, draw, read);
8138 if (error.isError())
8139 {
8140 INFO() << "MEC unable to make secondary context current";
8141 }
8142
8143 CaptureMidExecutionSetup(shareContext.second, &frameCapture->getSetupCalls(),
8144 frameCapture->getStateResetHelper(), &mShareGroupSetupCalls,
8145 &mResourceIDToSetupCalls, &mResourceTracker,
8146 auxContextReplayState, mValidateSerializedState);
8147
8148 scanSetupCalls(frameCapture->getSetupCalls());
8149
8150 WriteAuxiliaryContextCppSetupReplay(
8151 mReplayWriter, mCompression, mOutDirectory, shareContext.second, mCaptureLabel, 1,
8152 frameCapture->getSetupCalls(), &mBinaryData, mSerializeStateEnabled, *this,
8153 &mResourceIDBufferSize);
8154 }
8155 // Track that this context was created before MEC started
8156 mActiveContexts.insert(shareContext.first);
8157 }
8158
8159 egl::Error error = mainContext->makeCurrent(display, draw, read);
8160 if (error.isError())
8161 {
8162 INFO() << "MEC unable to make main context current again";
8163 }
8164 }
8165
onEndFrame(gl::Context * context)8166 void FrameCaptureShared::onEndFrame(gl::Context *context)
8167 {
8168 if (!enabled() || mFrameIndex > mCaptureEndFrame)
8169 {
8170 setCaptureInactive();
8171 mCoherentBufferTracker.onEndFrame();
8172 if (enabled())
8173 {
8174 resetMidExecutionCapture(context);
8175 }
8176 resetCaptureStartEndFrames();
8177 mFrameIndex++;
8178 return;
8179 }
8180
8181 FrameCapture *frameCapture = context->getFrameCapture();
8182
8183 // Count resource IDs. This is also done on every frame. It could probably be done by
8184 // checking the GL state instead of the calls.
8185 for (const CallCapture &call : mFrameCalls)
8186 {
8187 for (const ParamCapture ¶m : call.params.getParamCaptures())
8188 {
8189 ResourceIDType idType = GetResourceIDTypeFromParamType(param.type);
8190 if (idType != ResourceIDType::InvalidEnum)
8191 {
8192 mHasResourceType.set(idType);
8193 }
8194 }
8195 }
8196
8197 mWindowSurfaceContextID = context->id();
8198
8199 // On Android, we can trigger a capture during the run
8200 checkForCaptureTrigger();
8201
8202 // Check for MEC. Done after checkForCaptureTrigger(), since that can modify mCaptureStartFrame.
8203 if (mFrameIndex < mCaptureStartFrame)
8204 {
8205 if (mFrameIndex == mCaptureStartFrame - 1)
8206 {
8207 // Update output directory location
8208 getOutputDirectory();
8209 // Trigger MEC.
8210 runMidExecutionCapture(context);
8211 }
8212 mFrameIndex++;
8213 reset();
8214 return;
8215 }
8216
8217 ASSERT(isCaptureActive());
8218
8219 if (!mFrameCalls.empty())
8220 {
8221 mActiveFrameIndices.push_back(getReplayFrameIndex());
8222 }
8223
8224 // Make sure all pending work for every Context in the share group has completed so all data
8225 // (buffers, textures, etc.) has been updated and no resources are in use.
8226 egl::ShareGroup *shareGroup = context->getShareGroup();
8227 shareGroup->finishAllContexts();
8228
8229 // Only validate the first frame for now to save on retracing time.
8230 if (mValidateSerializedState && mFrameIndex == mCaptureStartFrame)
8231 {
8232 CaptureValidateSerializedState(context, &mFrameCalls);
8233 }
8234
8235 writeMainContextCppReplay(context, frameCapture->getSetupCalls(),
8236 frameCapture->getStateResetHelper());
8237
8238 if (mFrameIndex == mCaptureEndFrame)
8239 {
8240 // Write shared MEC after frame sequence so we can eliminate unused assets like programs
8241 WriteShareGroupCppSetupReplay(mReplayWriter, mCompression, mOutDirectory, mCaptureLabel, 1,
8242 1, mShareGroupSetupCalls, &mResourceTracker, &mBinaryData,
8243 mSerializeStateEnabled, mWindowSurfaceContextID,
8244 &mResourceIDBufferSize);
8245
8246 // Save the index files after the last frame.
8247 writeCppReplayIndexFiles(context, false);
8248 SaveBinaryData(mCompression, mOutDirectory, kSharedContextId, mCaptureLabel, mBinaryData);
8249 mBinaryData.clear();
8250 mWroteIndexFile = true;
8251 INFO() << "Finished recording graphics API capture";
8252 }
8253
8254 reset();
8255 mFrameIndex++;
8256 }
8257
onDestroyContext(const gl::Context * context)8258 void FrameCaptureShared::onDestroyContext(const gl::Context *context)
8259 {
8260 if (!mEnabled)
8261 {
8262 return;
8263 }
8264 if (!mWroteIndexFile && mFrameIndex > mCaptureStartFrame)
8265 {
8266 // If context is destroyed before end frame is reached and at least
8267 // 1 frame has been recorded, then write the index files.
8268 // It doesn't make sense to write the index files when no frame has been recorded
8269 mFrameIndex -= 1;
8270 mCaptureEndFrame = mFrameIndex;
8271 writeCppReplayIndexFiles(context, true);
8272 SaveBinaryData(mCompression, mOutDirectory, kSharedContextId, mCaptureLabel, mBinaryData);
8273 mBinaryData.clear();
8274 mWroteIndexFile = true;
8275 }
8276 }
8277
onMakeCurrent(const gl::Context * context,const egl::Surface * drawSurface)8278 void FrameCaptureShared::onMakeCurrent(const gl::Context *context, const egl::Surface *drawSurface)
8279 {
8280 if (!drawSurface)
8281 {
8282 return;
8283 }
8284
8285 // Track the width, height and color space of the draw surface as provided to makeCurrent
8286 SurfaceParams ¶ms = mDrawSurfaceParams[context->id()];
8287 params.extents = gl::Extents(drawSurface->getWidth(), drawSurface->getHeight(), 1);
8288 params.colorSpace = egl::FromEGLenum<egl::ColorSpace>(drawSurface->getGLColorspace());
8289 }
8290
setDefaultResetCalls(const gl::Context * context,angle::EntryPoint entryPoint)8291 void StateResetHelper::setDefaultResetCalls(const gl::Context *context,
8292 angle::EntryPoint entryPoint)
8293 {
8294 static const gl::BlendState kDefaultBlendState;
8295
8296 // Populate default reset calls for entrypoints to support looping to beginning
8297 switch (entryPoint)
8298 {
8299 case angle::EntryPoint::GLUseProgram:
8300 {
8301 if (context->getActiveLinkedProgram() &&
8302 context->getActiveLinkedProgram()->id().value != 0)
8303 {
8304 Capture(&mResetCalls[angle::EntryPoint::GLUseProgram],
8305 gl::CaptureUseProgram(context->getState(), true, {0}));
8306 }
8307 break;
8308 }
8309 case angle::EntryPoint::GLBindVertexArray:
8310 {
8311 if (context->getState().getVertexArray()->id().value != 0)
8312 {
8313 VertexArrayCaptureFuncs vertexArrayFuncs(context->isGLES1());
8314 Capture(&mResetCalls[angle::EntryPoint::GLBindVertexArray],
8315 vertexArrayFuncs.bindVertexArray(context->getState(), true, {0}));
8316 }
8317 break;
8318 }
8319 case angle::EntryPoint::GLBlendFunc:
8320 {
8321 Capture(&mResetCalls[angle::EntryPoint::GLBlendFunc],
8322 CaptureBlendFunc(context->getState(), true, kDefaultBlendState.sourceBlendRGB,
8323 kDefaultBlendState.destBlendRGB));
8324 break;
8325 }
8326 case angle::EntryPoint::GLBlendFuncSeparate:
8327 {
8328 Capture(&mResetCalls[angle::EntryPoint::GLBlendFuncSeparate],
8329 CaptureBlendFuncSeparate(
8330 context->getState(), true, kDefaultBlendState.sourceBlendRGB,
8331 kDefaultBlendState.destBlendRGB, kDefaultBlendState.sourceBlendAlpha,
8332 kDefaultBlendState.destBlendAlpha));
8333 break;
8334 }
8335 case angle::EntryPoint::GLBlendEquation:
8336 {
8337 UNREACHABLE(); // GLBlendEquationSeparate is always used instead
8338 break;
8339 }
8340 case angle::EntryPoint::GLBlendEquationSeparate:
8341 {
8342 Capture(&mResetCalls[angle::EntryPoint::GLBlendEquationSeparate],
8343 CaptureBlendEquationSeparate(context->getState(), true,
8344 kDefaultBlendState.blendEquationRGB,
8345 kDefaultBlendState.blendEquationAlpha));
8346 break;
8347 }
8348 case angle::EntryPoint::GLColorMask:
8349 {
8350 Capture(&mResetCalls[angle::EntryPoint::GLColorMask],
8351 CaptureColorMask(context->getState(), true,
8352 gl::ConvertToGLBoolean(kDefaultBlendState.colorMaskRed),
8353 gl::ConvertToGLBoolean(kDefaultBlendState.colorMaskGreen),
8354 gl::ConvertToGLBoolean(kDefaultBlendState.colorMaskBlue),
8355 gl::ConvertToGLBoolean(kDefaultBlendState.colorMaskAlpha)));
8356 break;
8357 }
8358 case angle::EntryPoint::GLBlendColor:
8359 {
8360 Capture(&mResetCalls[angle::EntryPoint::GLBlendColor],
8361 CaptureBlendColor(context->getState(), true, 0, 0, 0, 0));
8362 break;
8363 }
8364 default:
8365 ERR() << "Unhandled entry point in setDefaultResetCalls: "
8366 << GetEntryPointName(entryPoint);
8367 UNREACHABLE();
8368 break;
8369 }
8370 }
8371
setDeletedFenceSync(gl::SyncID sync)8372 void ResourceTracker::setDeletedFenceSync(gl::SyncID sync)
8373 {
8374 ASSERT(sync.value != 0);
8375 if (mStartingFenceSyncs.find(sync) == mStartingFenceSyncs.end())
8376 {
8377 // This is a fence sync created after MEC was initialized. Ignore it.
8378 return;
8379 }
8380
8381 // In this case, the app is deleting a fence sync we started with, we need to regen on loop.
8382 mFenceSyncsToRegen.insert(sync);
8383 }
8384
setModifiedDefaultUniform(gl::ShaderProgramID programID,gl::UniformLocation location)8385 void ResourceTracker::setModifiedDefaultUniform(gl::ShaderProgramID programID,
8386 gl::UniformLocation location)
8387 {
8388 // Pull up or create the list of uniform locations for this program and mark one dirty
8389 mDefaultUniformsToReset[programID].insert(location);
8390 }
8391
setDefaultUniformBaseLocation(gl::ShaderProgramID programID,gl::UniformLocation location,gl::UniformLocation baseLocation)8392 void ResourceTracker::setDefaultUniformBaseLocation(gl::ShaderProgramID programID,
8393 gl::UniformLocation location,
8394 gl::UniformLocation baseLocation)
8395 {
8396 // Track the base location used to populate arrayed uniforms in Setup
8397 mDefaultUniformBaseLocations[{programID, location}] = baseLocation;
8398 }
8399
getTrackedResource(gl::ContextID contextID,ResourceIDType type)8400 TrackedResource &ResourceTracker::getTrackedResource(gl::ContextID contextID, ResourceIDType type)
8401 {
8402 if (IsSharedObjectResource(type))
8403 {
8404 // No need to index with context if shared
8405 return mTrackedResourcesShared[static_cast<uint32_t>(type)];
8406 }
8407 else
8408 {
8409 // For per-context objects, track the resource per-context
8410 return mTrackedResourcesPerContext[contextID][static_cast<uint32_t>(type)];
8411 }
8412 }
8413
getContextIDs(std::set<gl::ContextID> & idsOut)8414 void ResourceTracker::getContextIDs(std::set<gl::ContextID> &idsOut)
8415 {
8416 for (const auto &trackedResourceIterator : mTrackedResourcesPerContext)
8417 {
8418 gl::ContextID contextID = trackedResourceIterator.first;
8419 idsOut.insert(contextID);
8420 }
8421 }
8422
setGennedResource(GLuint id)8423 void TrackedResource::setGennedResource(GLuint id)
8424 {
8425 if (mStartingResources.find(id) == mStartingResources.end())
8426 {
8427 // This is a resource created after MEC was initialized, track it
8428 mNewResources.insert(id);
8429 }
8430 else
8431 {
8432 // In this case, the app is genning a resource with starting ID after previously deleting it
8433 ASSERT(mResourcesToRegen.find(id) != mResourcesToRegen.end());
8434
8435 // For this, we need to delete it again to recreate it.
8436 mResourcesToDelete.insert(id);
8437 }
8438 }
8439
resourceIsGenerated(GLuint id)8440 bool TrackedResource::resourceIsGenerated(GLuint id)
8441 {
8442 return mStartingResources.find(id) != mStartingResources.end() ||
8443 mNewResources.find(id) != mNewResources.end();
8444 }
8445
setDeletedResource(GLuint id)8446 void TrackedResource::setDeletedResource(GLuint id)
8447 {
8448 if (id == 0)
8449 {
8450 // Ignore ID 0
8451 return;
8452 }
8453
8454 if (mNewResources.find(id) != mNewResources.end())
8455 {
8456 // This is a resource created after MEC was initialized, just clear it, since there will be
8457 // no actions required for it to return to starting state.
8458 mNewResources.erase(id);
8459 return;
8460 }
8461
8462 if (mStartingResources.find(id) != mStartingResources.end())
8463 {
8464 // In this case, the app is deleting a resource we started with, we need to regen on loop
8465
8466 // Mark that we don't need to delete this
8467 mResourcesToDelete.erase(id);
8468
8469 // Generate the resource again
8470 mResourcesToRegen.insert(id);
8471
8472 // Also restore its contents
8473 mResourcesToRestore.insert(id);
8474 }
8475
8476 // If none of the above is true, the app is deleting a resource that was never genned.
8477 }
8478
setModifiedResource(GLuint id)8479 void TrackedResource::setModifiedResource(GLuint id)
8480 {
8481 // If this was a starting resource, we need to track it for restore
8482 if (mStartingResources.find(id) != mStartingResources.end())
8483 {
8484 mResourcesToRestore.insert(id);
8485 }
8486 }
8487
setBufferMapped(gl::ContextID contextID,GLuint id)8488 void ResourceTracker::setBufferMapped(gl::ContextID contextID, GLuint id)
8489 {
8490 // If this was a starting buffer, we may need to restore it to original state during Reset.
8491 // Skip buffers that were deleted after the starting point.
8492 const TrackedResource &trackedBuffers = getTrackedResource(contextID, ResourceIDType::Buffer);
8493 const ResourceSet &startingBuffers = trackedBuffers.getStartingResources();
8494 const ResourceSet &buffersToRegen = trackedBuffers.getResourcesToRegen();
8495 if (startingBuffers.find(id) != startingBuffers.end() &&
8496 buffersToRegen.find(id) == buffersToRegen.end())
8497 {
8498 // Track that its current state is mapped (true)
8499 mStartingBuffersMappedCurrent[id] = true;
8500 }
8501 }
8502
setBufferUnmapped(gl::ContextID contextID,GLuint id)8503 void ResourceTracker::setBufferUnmapped(gl::ContextID contextID, GLuint id)
8504 {
8505 // If this was a starting buffer, we may need to restore it to original state during Reset.
8506 // Skip buffers that were deleted after the starting point.
8507 const TrackedResource &trackedBuffers = getTrackedResource(contextID, ResourceIDType::Buffer);
8508 const ResourceSet &startingBuffers = trackedBuffers.getStartingResources();
8509 const ResourceSet &buffersToRegen = trackedBuffers.getResourcesToRegen();
8510 if (startingBuffers.find(id) != startingBuffers.end() &&
8511 buffersToRegen.find(id) == buffersToRegen.end())
8512 {
8513 // Track that its current state is unmapped (false)
8514 mStartingBuffersMappedCurrent[id] = false;
8515 }
8516 }
8517
getStartingBuffersMappedCurrent(GLuint id) const8518 bool ResourceTracker::getStartingBuffersMappedCurrent(GLuint id) const
8519 {
8520 const auto &foundBool = mStartingBuffersMappedCurrent.find(id);
8521 ASSERT(foundBool != mStartingBuffersMappedCurrent.end());
8522 return foundBool->second;
8523 }
8524
getStartingBuffersMappedInitial(GLuint id) const8525 bool ResourceTracker::getStartingBuffersMappedInitial(GLuint id) const
8526 {
8527 const auto &foundBool = mStartingBuffersMappedInitial.find(id);
8528 ASSERT(foundBool != mStartingBuffersMappedInitial.end());
8529 return foundBool->second;
8530 }
8531
onShaderProgramAccess(gl::ShaderProgramID shaderProgramID)8532 void ResourceTracker::onShaderProgramAccess(gl::ShaderProgramID shaderProgramID)
8533 {
8534 mMaxShaderPrograms = std::max(mMaxShaderPrograms, shaderProgramID.value + 1);
8535 }
8536
8537 // Serialize trace metadata into a JSON file. The JSON file will be named "trace_prefix.json".
8538 //
8539 // As of writing, it will have the format like so:
8540 // {
8541 // "TraceMetadata":
8542 // {
8543 // "AreClientArraysEnabled" : 1, "CaptureRevision" : 16631, "ConfigAlphaBits" : 8,
8544 // "ConfigBlueBits" : 8, "ConfigDepthBits" : 24, "ConfigGreenBits" : 8,
8545 // ... etc ...
writeJSON(const gl::Context * context)8546 void FrameCaptureShared::writeJSON(const gl::Context *context)
8547 {
8548 const gl::ContextID contextId = context->id();
8549 const SurfaceParams &surfaceParams = mDrawSurfaceParams.at(contextId);
8550 const gl::State &glState = context->getState();
8551 const egl::Config *config = context->getConfig();
8552 const egl::AttributeMap &displayAttribs = context->getDisplay()->getAttributeMap();
8553
8554 unsigned int frameCount = getFrameCount();
8555
8556 JsonSerializer json;
8557 json.startGroup("TraceMetadata");
8558 json.addScalar("CaptureRevision", GetANGLERevision());
8559 json.addScalar("ContextClientMajorVersion", context->getClientMajorVersion());
8560 json.addScalar("ContextClientMinorVersion", context->getClientMinorVersion());
8561 json.addHexValue("DisplayPlatformType", displayAttribs.getAsInt(EGL_PLATFORM_ANGLE_TYPE_ANGLE));
8562 json.addHexValue("DisplayDeviceType",
8563 displayAttribs.getAsInt(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE));
8564 json.addScalar("FrameStart", 1);
8565 json.addScalar("FrameEnd", frameCount);
8566 json.addScalar("DrawSurfaceWidth", surfaceParams.extents.width);
8567 json.addScalar("DrawSurfaceHeight", surfaceParams.extents.height);
8568 json.addHexValue("DrawSurfaceColorSpace", ToEGLenum(surfaceParams.colorSpace));
8569 if (config)
8570 {
8571 json.addScalar("ConfigRedBits", config->redSize);
8572 json.addScalar("ConfigGreenBits", config->greenSize);
8573 json.addScalar("ConfigBlueBits", config->blueSize);
8574 json.addScalar("ConfigAlphaBits", config->alphaSize);
8575 json.addScalar("ConfigDepthBits", config->depthSize);
8576 json.addScalar("ConfigStencilBits", config->stencilSize);
8577 }
8578 else
8579 {
8580 json.addScalar("ConfigRedBits", EGL_DONT_CARE);
8581 json.addScalar("ConfigGreenBits", EGL_DONT_CARE);
8582 json.addScalar("ConfigBlueBits", EGL_DONT_CARE);
8583 json.addScalar("ConfigAlphaBits", EGL_DONT_CARE);
8584 json.addScalar("ConfigDepthBits", EGL_DONT_CARE);
8585 json.addScalar("ConfigStencilBits", EGL_DONT_CARE);
8586 }
8587 json.addBool("IsBinaryDataCompressed", mCompression);
8588 json.addBool("AreClientArraysEnabled", glState.areClientArraysEnabled());
8589 json.addBool("IsBindGeneratesResourcesEnabled", glState.isBindGeneratesResourceEnabled());
8590 json.addBool("IsWebGLCompatibilityEnabled", glState.isWebGL());
8591 json.addBool("IsRobustResourceInitEnabled", glState.isRobustResourceInitEnabled());
8592 json.endGroup();
8593
8594 {
8595 const std::vector<std::string> &traceFiles = mReplayWriter.getAndResetWrittenFiles();
8596 json.addVectorOfStrings("TraceFiles", traceFiles);
8597 }
8598
8599 json.addScalar("WindowSurfaceContextID", contextId.value);
8600
8601 {
8602 std::stringstream jsonFileNameStream;
8603 jsonFileNameStream << mOutDirectory << FmtCapturePrefix(kNoContextId, mCaptureLabel)
8604 << ".json";
8605 std::string jsonFileName = jsonFileNameStream.str();
8606
8607 SaveFileHelper saveData(jsonFileName);
8608 saveData.write(reinterpret_cast<const uint8_t *>(json.data()), json.length());
8609 }
8610 }
8611
writeCppReplayIndexFiles(const gl::Context * context,bool writeResetContextCall)8612 void FrameCaptureShared::writeCppReplayIndexFiles(const gl::Context *context,
8613 bool writeResetContextCall)
8614 {
8615 // Ensure the last frame is written. This will no-op if the frame is already written.
8616 mReplayWriter.saveFrame();
8617
8618 const gl::ContextID contextId = context->id();
8619
8620 {
8621 std::stringstream header;
8622
8623 header << "#pragma once\n";
8624 header << "\n";
8625 header << "#include <EGL/egl.h>\n";
8626 header << "#include <stdint.h>\n";
8627
8628 std::string includes = header.str();
8629 mReplayWriter.setHeaderPrologue(includes);
8630 }
8631
8632 {
8633 std::stringstream source;
8634
8635 source << "#include \"" << FmtCapturePrefix(contextId, mCaptureLabel) << ".h\"\n";
8636 source << "#include \"trace_fixture.h\"\n";
8637 source << "#include \"angle_trace_gl.h\"\n";
8638
8639 std::string sourcePrologue = source.str();
8640 mReplayWriter.setSourcePrologue(sourcePrologue);
8641 }
8642
8643 {
8644 std::string proto = "void InitReplay(void)";
8645
8646 std::stringstream source;
8647 source << proto << "\n";
8648 source << "{\n";
8649 WriteInitReplayCall(mCompression, source, context->id(), mCaptureLabel,
8650 MaxClientArraySize(mClientArraySizes), mReadBufferSize,
8651 mResourceIDBufferSize, mMaxAccessedResourceIDs);
8652 source << "}\n";
8653
8654 mReplayWriter.addPrivateFunction(proto, std::stringstream(), source);
8655 }
8656
8657 {
8658 std::string proto = "void ReplayFrame(uint32_t frameIndex)";
8659
8660 std::stringstream source;
8661
8662 source << proto << "\n";
8663 source << "{\n";
8664 source << " switch (frameIndex)\n";
8665 source << " {\n";
8666 for (uint32_t frameIndex : mActiveFrameIndices)
8667 {
8668 source << " case " << frameIndex << ":\n";
8669 source << " " << FmtReplayFunction(contextId, FuncUsage::Call, frameIndex)
8670 << ";\n";
8671 source << " break;\n";
8672 }
8673 source << " default:\n";
8674 source << " break;\n";
8675 source << " }\n";
8676 source << "}\n";
8677
8678 mReplayWriter.addPublicFunction(proto, std::stringstream(), source);
8679 }
8680
8681 if (writeResetContextCall)
8682 {
8683 std::string proto = "void ResetReplay(void)";
8684
8685 std::stringstream source;
8686
8687 source << proto << "\n";
8688 source << "{\n";
8689 source << " // Reset context is empty because context is destroyed before end "
8690 "frame is reached\n";
8691 source << "}\n";
8692
8693 mReplayWriter.addPublicFunction(proto, std::stringstream(), source);
8694 }
8695
8696 if (mSerializeStateEnabled)
8697 {
8698 std::string proto = "const char *GetSerializedContextState(uint32_t frameIndex)";
8699
8700 std::stringstream source;
8701
8702 source << proto << "\n";
8703 source << "{\n";
8704 source << " switch (frameIndex)\n";
8705 source << " {\n";
8706 for (uint32_t frameIndex = 1; frameIndex <= getFrameCount(); ++frameIndex)
8707 {
8708 source << " case " << frameIndex << ":\n";
8709 source << " return "
8710 << FmtGetSerializedContextStateFunction(contextId, FuncUsage::Call, frameIndex)
8711 << ";\n";
8712 }
8713 source << " default:\n";
8714 source << " return NULL;\n";
8715 source << " }\n";
8716 source << "}\n";
8717
8718 mReplayWriter.addPublicFunction(proto, std::stringstream(), source);
8719 }
8720
8721 {
8722 std::stringstream fnameStream;
8723 fnameStream << mOutDirectory << FmtCapturePrefix(contextId, mCaptureLabel);
8724 std::string fnamePattern = fnameStream.str();
8725
8726 mReplayWriter.setFilenamePattern(fnamePattern);
8727 }
8728
8729 mReplayWriter.saveIndexFilesAndHeader();
8730
8731 writeJSON(context);
8732 }
8733
writeMainContextCppReplay(const gl::Context * context,const std::vector<CallCapture> & setupCalls,StateResetHelper & stateResetHelper)8734 void FrameCaptureShared::writeMainContextCppReplay(const gl::Context *context,
8735 const std::vector<CallCapture> &setupCalls,
8736 StateResetHelper &stateResetHelper)
8737 {
8738 ASSERT(mWindowSurfaceContextID == context->id());
8739
8740 {
8741 std::stringstream header;
8742
8743 header << "#include \"" << FmtCapturePrefix(context->id(), mCaptureLabel) << ".h\"\n";
8744 header << "#include \"angle_trace_gl.h\"\n";
8745
8746 std::string headerString = header.str();
8747 mReplayWriter.setSourcePrologue(headerString);
8748 }
8749
8750 uint32_t frameCount = getFrameCount();
8751 uint32_t frameIndex = getReplayFrameIndex();
8752
8753 if (frameIndex == 1)
8754 {
8755 {
8756 std::string proto = "void SetupReplay(void)";
8757
8758 std::stringstream out;
8759
8760 out << proto << "\n";
8761 out << "{\n";
8762
8763 // Setup all of the shared objects.
8764 out << " InitReplay();\n";
8765 if (usesMidExecutionCapture())
8766 {
8767 out << " " << FmtSetupFunction(kNoPartId, kSharedContextId, FuncUsage::Call)
8768 << ";\n";
8769 out << " "
8770 << FmtSetupInactiveFunction(kNoPartId, kSharedContextId, FuncUsage::Call)
8771 << "\n";
8772 // Make sure that the current context is mapped correctly
8773 out << " SetCurrentContextID(" << context->id() << ");\n";
8774 }
8775
8776 // Setup each of the auxiliary contexts.
8777 egl::ShareGroup *shareGroup = context->getShareGroup();
8778 const egl::ContextMap &shareContextMap = shareGroup->getContexts();
8779 for (auto shareContext : shareContextMap)
8780 {
8781 if (shareContext.first == context->id().value)
8782 {
8783 if (usesMidExecutionCapture())
8784 {
8785 // Setup the presentation (this) context first.
8786 out << " " << FmtSetupFunction(kNoPartId, context->id(), FuncUsage::Call)
8787 << ";\n";
8788 out << "\n";
8789 }
8790
8791 continue;
8792 }
8793
8794 // The SetupReplayContextXX() calls only exist if this is a mid-execution capture
8795 // and we can only call them if they exist, so only output the calls if this is a
8796 // MEC.
8797 if (usesMidExecutionCapture())
8798 {
8799 // Only call SetupReplayContext for secondary contexts that were current before
8800 // MEC started
8801 if (mActiveContexts.find(shareContext.first) != mActiveContexts.end())
8802 {
8803 // TODO(http://anglebug.com/42264418): Support capture/replay of
8804 // eglCreateContext() so this block can be moved into SetupReplayContextXX()
8805 // by injecting them into the beginning of the setup call stream.
8806 out << " CreateContext(" << shareContext.first << ");\n";
8807
8808 out << " "
8809 << FmtSetupFunction(kNoPartId, shareContext.second->id(),
8810 FuncUsage::Call)
8811 << ";\n";
8812 }
8813 }
8814 }
8815
8816 // If there are other contexts that were initialized, we need to make the main context
8817 // current again.
8818 if (shareContextMap.size() > 1)
8819 {
8820 out << "\n";
8821 out << " eglMakeCurrent(NULL, NULL, NULL, gContextMap2[" << context->id()
8822 << "]);\n";
8823 }
8824
8825 out << "}\n";
8826
8827 mReplayWriter.addPublicFunction(proto, std::stringstream(), out);
8828 }
8829 }
8830
8831 // Emit code to reset back to starting state
8832 if (frameIndex == frameCount)
8833 {
8834 std::stringstream resetProtoStream;
8835 std::stringstream resetHeaderStream;
8836 std::stringstream resetBodyStream;
8837
8838 resetProtoStream << "void ResetReplay(void)";
8839
8840 resetBodyStream << resetProtoStream.str() << "\n";
8841 resetBodyStream << "{\n";
8842
8843 // Grab the list of contexts to be reset
8844 std::set<gl::ContextID> contextIDs;
8845 mResourceTracker.getContextIDs(contextIDs);
8846
8847 // TODO(http://anglebug.com/42264418): Look at moving this into the shared context file
8848 // since it's resetting shared objects.
8849
8850 // TODO(http://anglebug.com/42263204): Support function parts when writing Reset functions
8851
8852 // Track whether anything was written during Reset
8853 bool anyResourceReset = false;
8854
8855 // Track whether we changed contexts during Reset
8856 bool contextChanged = false;
8857
8858 // First emit shared object reset, including opaque and context state
8859 {
8860 std::stringstream protoStream;
8861 std::stringstream headerStream;
8862 std::stringstream bodyStream;
8863
8864 protoStream << "void "
8865 << FmtResetFunction(kNoPartId, kSharedContextId, FuncUsage::Prototype);
8866 bodyStream << protoStream.str() << "\n";
8867 bodyStream << "{\n";
8868
8869 for (ResourceIDType resourceType : AllEnums<ResourceIDType>())
8870 {
8871 if (!IsSharedObjectResource(resourceType))
8872 {
8873 continue;
8874 }
8875 // Use current context for shared reset
8876 MaybeResetResources(context->getDisplay(), context->id(), resourceType,
8877 mReplayWriter, bodyStream, headerStream, &mResourceTracker,
8878 &mBinaryData, anyResourceReset, &mResourceIDBufferSize);
8879 }
8880
8881 // Reset opaque type objects that don't have IDs, so are not ResourceIDTypes.
8882 MaybeResetOpaqueTypeObjects(mReplayWriter, bodyStream, headerStream, context,
8883 &mResourceTracker, &mBinaryData, &mResourceIDBufferSize);
8884
8885 bodyStream << "}\n";
8886
8887 mReplayWriter.addPrivateFunction(protoStream.str(), headerStream, bodyStream);
8888 }
8889
8890 // Emit the call to shared object reset
8891 resetBodyStream << " " << FmtResetFunction(kNoPartId, kSharedContextId, FuncUsage::Call)
8892 << ";\n";
8893
8894 // Reset our output tracker (Note: This was unused during shared reset)
8895 anyResourceReset = false;
8896
8897 // Walk through all contexts that need Reset
8898 for (const gl::ContextID &contextID : contextIDs)
8899 {
8900 // Create a function to reset each context's non-shared objects
8901 {
8902 std::stringstream protoStream;
8903 std::stringstream headerStream;
8904 std::stringstream bodyStream;
8905
8906 protoStream << "void "
8907 << FmtResetFunction(kNoPartId, contextID, FuncUsage::Prototype);
8908 bodyStream << protoStream.str() << "\n";
8909 bodyStream << "{\n";
8910
8911 // Build the Reset calls in a separate stream so we can insert before them
8912 std::stringstream resetStream;
8913
8914 for (ResourceIDType resourceType : AllEnums<ResourceIDType>())
8915 {
8916 if (IsSharedObjectResource(resourceType))
8917 {
8918 continue;
8919 }
8920 MaybeResetResources(context->getDisplay(), contextID, resourceType,
8921 mReplayWriter, resetStream, headerStream, &mResourceTracker,
8922 &mBinaryData, anyResourceReset, &mResourceIDBufferSize);
8923 }
8924
8925 // Only call eglMakeCurrent if anything was actually reset in the function and the
8926 // context differs from current
8927 if (anyResourceReset && contextID != context->id())
8928 {
8929 contextChanged = true;
8930 bodyStream << " eglMakeCurrent(NULL, NULL, NULL, gContextMap2["
8931 << contextID.value << "]);\n\n";
8932 }
8933
8934 // Then append the Reset calls
8935 bodyStream << resetStream.str();
8936
8937 bodyStream << "}\n";
8938 mReplayWriter.addPrivateFunction(protoStream.str(), headerStream, bodyStream);
8939 }
8940
8941 // Emit a call to reset each context's non-shared objects
8942 resetBodyStream << " " << FmtResetFunction(kNoPartId, contextID, FuncUsage::Call)
8943 << ";\n";
8944 }
8945
8946 // Bind the main context again if we bound any additional contexts
8947 if (contextChanged)
8948 {
8949 resetBodyStream << " eglMakeCurrent(NULL, NULL, NULL, gContextMap2["
8950 << context->id().value << "]);\n";
8951 }
8952
8953 // Now that we're back on the main context, reset any additional state
8954 resetBodyStream << "\n // Reset main context state\n";
8955 MaybeResetContextState(mReplayWriter, resetBodyStream, resetHeaderStream, &mResourceTracker,
8956 context, &mBinaryData, stateResetHelper, &mResourceIDBufferSize);
8957
8958 resetBodyStream << "}\n";
8959
8960 mReplayWriter.addPublicFunction(resetProtoStream.str(), resetHeaderStream, resetBodyStream);
8961 }
8962
8963 if (!mFrameCalls.empty())
8964 {
8965 std::stringstream protoStream;
8966 protoStream << "void "
8967 << FmtReplayFunction(context->id(), FuncUsage::Prototype, frameIndex);
8968 std::string proto = protoStream.str();
8969 std::stringstream headerStream;
8970 std::stringstream bodyStream;
8971
8972 if (context->getShareGroup()->getContexts().size() > 1)
8973 {
8974 // Only ReplayFunc::Replay trace file output functions are affected by multi-context
8975 // call grouping so they can safely be special-cased here.
8976 WriteCppReplayFunctionWithPartsMultiContext(
8977 context->id(), ReplayFunc::Replay, mReplayWriter, frameIndex, &mBinaryData,
8978 mFrameCalls, headerStream, bodyStream, &mResourceIDBufferSize);
8979 }
8980 else
8981 {
8982 WriteCppReplayFunctionWithParts(context->id(), ReplayFunc::Replay, mReplayWriter,
8983 frameIndex, &mBinaryData, mFrameCalls, headerStream,
8984 bodyStream, &mResourceIDBufferSize);
8985 }
8986 mReplayWriter.addPrivateFunction(proto, headerStream, bodyStream);
8987 }
8988
8989 if (mSerializeStateEnabled)
8990 {
8991 std::string serializedContextString;
8992 if (SerializeContextToString(const_cast<gl::Context *>(context),
8993 &serializedContextString) == Result::Continue)
8994 {
8995 std::stringstream protoStream;
8996 protoStream << "const char *"
8997 << FmtGetSerializedContextStateFunction(context->id(), FuncUsage::Prototype,
8998 frameIndex);
8999 std::string proto = protoStream.str();
9000
9001 std::stringstream bodyStream;
9002 bodyStream << proto << "\n";
9003 bodyStream << "{\n";
9004 bodyStream << " return " << FmtMultiLineString(serializedContextString) << ";\n";
9005 bodyStream << "}\n";
9006
9007 mReplayWriter.addPrivateFunction(proto, std::stringstream(), bodyStream);
9008 }
9009 }
9010
9011 {
9012 std::stringstream fnamePatternStream;
9013 fnamePatternStream << mOutDirectory << FmtCapturePrefix(context->id(), mCaptureLabel);
9014 std::string fnamePattern = fnamePatternStream.str();
9015
9016 mReplayWriter.setFilenamePattern(fnamePattern);
9017 }
9018
9019 if (mFrameIndex == mCaptureEndFrame)
9020 {
9021 mReplayWriter.saveFrame();
9022 }
9023 else
9024 {
9025 mReplayWriter.saveFrameIfFull();
9026 }
9027 }
9028
getShaderSource(gl::ShaderProgramID id) const9029 const std::string &FrameCaptureShared::getShaderSource(gl::ShaderProgramID id) const
9030 {
9031 const auto &foundSources = mCachedShaderSource.find(id);
9032 ASSERT(foundSources != mCachedShaderSource.end());
9033 return foundSources->second;
9034 }
9035
setShaderSource(gl::ShaderProgramID id,std::string source)9036 void FrameCaptureShared::setShaderSource(gl::ShaderProgramID id, std::string source)
9037 {
9038 mCachedShaderSource[id] = source;
9039 }
9040
getProgramSources(gl::ShaderProgramID id) const9041 const ProgramSources &FrameCaptureShared::getProgramSources(gl::ShaderProgramID id) const
9042 {
9043 const auto &foundSources = mCachedProgramSources.find(id);
9044 ASSERT(foundSources != mCachedProgramSources.end());
9045 return foundSources->second;
9046 }
9047
setProgramSources(gl::ShaderProgramID id,ProgramSources sources)9048 void FrameCaptureShared::setProgramSources(gl::ShaderProgramID id, ProgramSources sources)
9049 {
9050 mCachedProgramSources[id] = sources;
9051 }
9052
markResourceSetupCallsInactive(std::vector<CallCapture> * setupCalls,ResourceIDType type,GLuint id,gl::Range<size_t> range)9053 void FrameCaptureShared::markResourceSetupCallsInactive(std::vector<CallCapture> *setupCalls,
9054 ResourceIDType type,
9055 GLuint id,
9056 gl::Range<size_t> range)
9057 {
9058 ASSERT(mResourceIDToSetupCalls[type].find(id) == mResourceIDToSetupCalls[type].end());
9059
9060 // Mark all of the calls that were used to initialize this resource as INACTIVE
9061 for (size_t index : range)
9062 {
9063 (*setupCalls)[index].isActive = false;
9064 }
9065
9066 mResourceIDToSetupCalls[type][id] = range;
9067 }
9068
CaptureStringLimit(const GLchar * str,uint32_t limit,ParamCapture * paramCapture)9069 void CaptureStringLimit(const GLchar *str, uint32_t limit, ParamCapture *paramCapture)
9070 {
9071 // Write the incoming string up to limit, including null terminator
9072 size_t length = strlen(str) + 1;
9073
9074 if (length > limit)
9075 {
9076 // If too many characters, resize the string to fit in the limit
9077 std::string newStr = str;
9078 newStr.resize(limit - 1);
9079 CaptureString(newStr.c_str(), paramCapture);
9080 }
9081 else
9082 {
9083 CaptureMemory(str, length, paramCapture);
9084 }
9085 }
9086
CaptureVertexPointerGLES1(const gl::State & glState,gl::ClientVertexArrayType type,const void * pointer,ParamCapture * paramCapture)9087 void CaptureVertexPointerGLES1(const gl::State &glState,
9088 gl::ClientVertexArrayType type,
9089 const void *pointer,
9090 ParamCapture *paramCapture)
9091 {
9092 paramCapture->value.voidConstPointerVal = pointer;
9093 if (!glState.getTargetBuffer(gl::BufferBinding::Array))
9094 {
9095 paramCapture->arrayClientPointerIndex =
9096 gl::GLES1Renderer::VertexArrayIndex(type, glState.gles1());
9097 }
9098 }
9099
GetProgramForCapture(const gl::State & glState,gl::ShaderProgramID handle)9100 gl::Program *GetProgramForCapture(const gl::State &glState, gl::ShaderProgramID handle)
9101 {
9102 gl::Program *program = glState.getShaderProgramManagerForCapture().getProgram(handle);
9103 return program;
9104 }
9105
CaptureGetActiveUniformBlockivParameters(const gl::State & glState,gl::ShaderProgramID handle,gl::UniformBlockIndex uniformBlockIndex,GLenum pname,ParamCapture * paramCapture)9106 void CaptureGetActiveUniformBlockivParameters(const gl::State &glState,
9107 gl::ShaderProgramID handle,
9108 gl::UniformBlockIndex uniformBlockIndex,
9109 GLenum pname,
9110 ParamCapture *paramCapture)
9111 {
9112 int numParams = 1;
9113
9114 // From the OpenGL ES 3.0 spec:
9115 // If pname is UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, then a list of the
9116 // active uniform indices for the uniform block identified by uniformBlockIndex is
9117 // returned. The number of elements that will be written to params is the value of
9118 // UNIFORM_BLOCK_ACTIVE_UNIFORMS for uniformBlockIndex
9119 if (pname == GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES)
9120 {
9121 gl::Program *program = GetProgramForCapture(glState, handle);
9122 if (program)
9123 {
9124 gl::QueryActiveUniformBlockiv(program, uniformBlockIndex,
9125 GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &numParams);
9126 }
9127 }
9128
9129 paramCapture->readBufferSizeBytes = sizeof(GLint) * numParams;
9130 }
9131
CaptureGetParameter(const gl::State & glState,GLenum pname,size_t typeSize,ParamCapture * paramCapture)9132 void CaptureGetParameter(const gl::State &glState,
9133 GLenum pname,
9134 size_t typeSize,
9135 ParamCapture *paramCapture)
9136 {
9137 // kMaxReportedCapabilities is the biggest array we'll need to hold data from glGet calls.
9138 // This value needs to be updated if any new extensions are introduced that would allow for
9139 // more compressed texture formats. The current value is taken from:
9140 // http://opengles.gpuinfo.org/displaycapability.php?name=GL_NUM_COMPRESSED_TEXTURE_FORMATS&esversion=2
9141 constexpr unsigned int kMaxReportedCapabilities = 69;
9142 paramCapture->readBufferSizeBytes = typeSize * kMaxReportedCapabilities;
9143 }
9144
CaptureGenHandlesImpl(GLsizei n,GLuint * handles,ParamCapture * paramCapture)9145 void CaptureGenHandlesImpl(GLsizei n, GLuint *handles, ParamCapture *paramCapture)
9146 {
9147 paramCapture->readBufferSizeBytes = sizeof(GLuint) * n;
9148 CaptureMemory(handles, paramCapture->readBufferSizeBytes, paramCapture);
9149 }
9150
CaptureShaderStrings(GLsizei count,const GLchar * const * strings,const GLint * length,ParamCapture * paramCapture)9151 void CaptureShaderStrings(GLsizei count,
9152 const GLchar *const *strings,
9153 const GLint *length,
9154 ParamCapture *paramCapture)
9155 {
9156 // Concat the array elements of the string into one data vector,
9157 // append the terminating zero and use this as the captured shader
9158 // string. The string count and the length array are adjusted
9159 // accordingly in the capture post-processing
9160
9161 std::vector<uint8_t> data;
9162 size_t offset = 0;
9163 for (GLsizei index = 0; index < count; ++index)
9164 {
9165 size_t len = ((length && length[index] >= 0) ? length[index] : strlen(strings[index]));
9166
9167 // Count trailing zeros
9168 uint32_t i = 1;
9169 while (i < len && strings[index][len - i] == 0)
9170 {
9171 i++;
9172 }
9173
9174 // Don't copy trailing zeros
9175 len -= (i - 1);
9176
9177 data.resize(offset + len);
9178 std::copy(strings[index], strings[index] + len, data.begin() + offset);
9179 offset += len;
9180 }
9181
9182 data.push_back(0);
9183 paramCapture->data.emplace_back(std::move(data));
9184 }
9185
9186 } // namespace angle
9187
9188 namespace egl
9189 {
CaptureAttributeMap(const egl::AttributeMap & attribMap)9190 angle::ParamCapture CaptureAttributeMap(const egl::AttributeMap &attribMap)
9191 {
9192 switch (attribMap.getType())
9193 {
9194 case AttributeMapType::Attrib:
9195 {
9196 angle::ParamCapture paramCapture("attrib_list", angle::ParamType::TEGLAttribPointer);
9197 if (attribMap.isEmpty())
9198 {
9199 paramCapture.value.EGLAttribPointerVal = nullptr;
9200 }
9201 else
9202 {
9203 std::vector<EGLAttrib> attribs;
9204 for (const auto &[key, value] : attribMap)
9205 {
9206 attribs.push_back(key);
9207 attribs.push_back(value);
9208 }
9209 attribs.push_back(EGL_NONE);
9210
9211 angle::CaptureMemory(attribs.data(), attribs.size() * sizeof(EGLAttrib),
9212 ¶mCapture);
9213 }
9214 return paramCapture;
9215 }
9216
9217 case AttributeMapType::Int:
9218 {
9219 angle::ParamCapture paramCapture("attrib_list", angle::ParamType::TEGLintPointer);
9220 if (attribMap.isEmpty())
9221 {
9222 paramCapture.value.EGLintPointerVal = nullptr;
9223 }
9224 else
9225 {
9226 std::vector<EGLint> attribs;
9227 for (const auto &[key, value] : attribMap)
9228 {
9229 attribs.push_back(static_cast<EGLint>(key));
9230 attribs.push_back(static_cast<EGLint>(value));
9231 }
9232 attribs.push_back(EGL_NONE);
9233
9234 angle::CaptureMemory(attribs.data(), attribs.size() * sizeof(EGLint),
9235 ¶mCapture);
9236 }
9237 return paramCapture;
9238 }
9239
9240 default:
9241 UNREACHABLE();
9242 return angle::ParamCapture();
9243 }
9244 }
9245 } // namespace egl
9246