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.h:
7 // ANGLE Frame capture inteface.
8 //
9
10 #ifndef LIBANGLE_FRAME_CAPTURE_H_
11 #define LIBANGLE_FRAME_CAPTURE_H_
12
13 #include "common/PackedEnums.h"
14 #include "libANGLE/Context.h"
15 #include "libANGLE/angletypes.h"
16 #include "libANGLE/entry_points_utils.h"
17 #include "libANGLE/frame_capture_utils_autogen.h"
18
19 namespace gl
20 {
21 enum class GLenumGroup;
22 }
23
24 namespace angle
25 {
26 struct ParamCapture : angle::NonCopyable
27 {
28 ParamCapture();
29 ParamCapture(const char *nameIn, ParamType typeIn);
30 ~ParamCapture();
31
32 ParamCapture(ParamCapture &&other);
33 ParamCapture &operator=(ParamCapture &&other);
34
35 std::string name;
36 ParamType type;
37 ParamValue value;
38 gl::GLenumGroup enumGroup; // only used for param type GLenum, GLboolean and GLbitfield
39 std::vector<std::vector<uint8_t>> data;
40 int arrayClientPointerIndex = -1;
41 size_t readBufferSizeBytes = 0;
42 };
43
44 class ParamBuffer final : angle::NonCopyable
45 {
46 public:
47 ParamBuffer();
48 ~ParamBuffer();
49
50 ParamBuffer(ParamBuffer &&other);
51 ParamBuffer &operator=(ParamBuffer &&other);
52
53 template <typename T>
54 void addValueParam(const char *paramName, ParamType paramType, T paramValue);
55 template <typename T>
56 void addEnumParam(const char *paramName,
57 gl::GLenumGroup enumGroup,
58 ParamType paramType,
59 T paramValue);
60
61 ParamCapture &getParam(const char *paramName, ParamType paramType, int index);
62 const ParamCapture &getParam(const char *paramName, ParamType paramType, int index) const;
63 ParamCapture &getParamFlexName(const char *paramName1,
64 const char *paramName2,
65 ParamType paramType,
66 int index);
67 const ParamCapture &getParamFlexName(const char *paramName1,
68 const char *paramName2,
69 ParamType paramType,
70 int index) const;
getReturnValue()71 const ParamCapture &getReturnValue() const { return mReturnValueCapture; }
72
73 void addParam(ParamCapture &¶m);
74 void addReturnValue(ParamCapture &&returnValue);
hasClientArrayData()75 bool hasClientArrayData() const { return mClientArrayDataParam != -1; }
76 ParamCapture &getClientArrayPointerParameter();
getReadBufferSize()77 size_t getReadBufferSize() const { return mReadBufferSize; }
78
getParamCaptures()79 const std::vector<ParamCapture> &getParamCaptures() const { return mParamCaptures; }
80
81 // These helpers allow us to track the ID of the buffer that was active when
82 // MapBufferRange was called. We'll use it during replay to track the
83 // buffer's contents, as they can be modified by the host.
setMappedBufferID(gl::BufferID bufferID)84 void setMappedBufferID(gl::BufferID bufferID) { mMappedBufferID = bufferID; }
getMappedBufferID()85 gl::BufferID getMappedBufferID() const { return mMappedBufferID; }
86
87 private:
88 std::vector<ParamCapture> mParamCaptures;
89 ParamCapture mReturnValueCapture;
90 int mClientArrayDataParam = -1;
91 size_t mReadBufferSize = 0;
92 gl::BufferID mMappedBufferID;
93 };
94
95 struct CallCapture
96 {
97 CallCapture(gl::EntryPoint entryPointIn, ParamBuffer &¶msIn);
98 CallCapture(const std::string &customFunctionNameIn, ParamBuffer &¶msIn);
99 ~CallCapture();
100
101 CallCapture(CallCapture &&other);
102 CallCapture &operator=(CallCapture &&other);
103
104 const char *name() const;
105
106 gl::EntryPoint entryPoint;
107 std::string customFunctionName;
108 ParamBuffer params;
109 };
110
111 class ReplayContext
112 {
113 public:
114 ReplayContext(size_t readBufferSizebytes, const gl::AttribArray<size_t> &clientArraysSizebytes);
115 ~ReplayContext();
116
117 template <typename T>
getReadBufferPointer(const ParamCapture & param)118 T getReadBufferPointer(const ParamCapture ¶m)
119 {
120 ASSERT(param.readBufferSizeBytes > 0);
121 ASSERT(mReadBuffer.size() >= param.readBufferSizeBytes);
122 return reinterpret_cast<T>(mReadBuffer.data());
123 }
124 template <typename T>
getAsConstPointer(const ParamCapture & param)125 T getAsConstPointer(const ParamCapture ¶m)
126 {
127 if (param.arrayClientPointerIndex != -1)
128 {
129 return reinterpret_cast<T>(mClientArraysBuffer[param.arrayClientPointerIndex].data());
130 }
131
132 if (!param.data.empty())
133 {
134 ASSERT(param.data.size() == 1);
135 return reinterpret_cast<T>(param.data[0].data());
136 }
137
138 return nullptr;
139 }
140
141 template <typename T>
getAsPointerConstPointer(const ParamCapture & param)142 T getAsPointerConstPointer(const ParamCapture ¶m)
143 {
144 static_assert(sizeof(typename std::remove_pointer<T>::type) == sizeof(uint8_t *),
145 "pointer size not match!");
146
147 ASSERT(!param.data.empty());
148 mPointersBuffer.clear();
149 mPointersBuffer.reserve(param.data.size());
150 for (const std::vector<uint8_t> &data : param.data)
151 {
152 mPointersBuffer.emplace_back(data.data());
153 }
154 return reinterpret_cast<T>(mPointersBuffer.data());
155 }
156
getClientArraysBuffer()157 gl::AttribArray<std::vector<uint8_t>> &getClientArraysBuffer() { return mClientArraysBuffer; }
158
159 private:
160 std::vector<uint8_t> mReadBuffer;
161 std::vector<const uint8_t *> mPointersBuffer;
162 gl::AttribArray<std::vector<uint8_t>> mClientArraysBuffer;
163 };
164
165 // Helper to use unique IDs for each local data variable.
166 class DataCounters final : angle::NonCopyable
167 {
168 public:
169 DataCounters();
170 ~DataCounters();
171
172 int getAndIncrement(gl::EntryPoint entryPoint, const std::string ¶mName);
173
174 private:
175 // <CallName, ParamName>
176 using Counter = std::pair<gl::EntryPoint, std::string>;
177 std::map<Counter, int> mData;
178 };
179
180 using BufferSet = std::set<gl::BufferID>;
181 using BufferCalls = std::map<gl::BufferID, std::vector<CallCapture>>;
182
183 // true means mapped, false means unmapped
184 using BufferMapStatusMap = std::map<gl::BufferID, bool>;
185
186 // Helper to track resource changes during the capture
187 class ResourceTracker final : angle::NonCopyable
188 {
189 public:
190 ResourceTracker();
191 ~ResourceTracker();
192
getBufferRegenCalls()193 BufferCalls &getBufferRegenCalls() { return mBufferRegenCalls; }
getBufferRestoreCalls()194 BufferCalls &getBufferRestoreCalls() { return mBufferRestoreCalls; }
getBufferMapCalls()195 BufferCalls &getBufferMapCalls() { return mBufferMapCalls; }
getBufferUnmapCalls()196 BufferCalls &getBufferUnmapCalls() { return mBufferUnmapCalls; }
197
getStartingBuffers()198 BufferSet &getStartingBuffers() { return mStartingBuffers; }
getNewBuffers()199 BufferSet &getNewBuffers() { return mNewBuffers; }
getBuffersToRegen()200 BufferSet &getBuffersToRegen() { return mBuffersToRegen; }
getBuffersToRestore()201 BufferSet &getBuffersToRestore() { return mBuffersToRestore; }
202
203 void setGennedBuffer(gl::BufferID id);
204 void setDeletedBuffer(gl::BufferID id);
205 void setBufferModified(gl::BufferID id);
206 void setBufferMapped(gl::BufferID id);
207 void setBufferUnmapped(gl::BufferID id);
208
getStartingBuffersMappedCurrent(gl::BufferID id)209 const bool &getStartingBuffersMappedCurrent(gl::BufferID id)
210 {
211 return mStartingBuffersMappedCurrent[id];
212 }
getStartingBuffersMappedInitial(gl::BufferID id)213 const bool &getStartingBuffersMappedInitial(gl::BufferID id)
214 {
215 return mStartingBuffersMappedInitial[id];
216 }
setStartingBufferMapped(gl::BufferID id,bool mapped)217 void setStartingBufferMapped(gl::BufferID id, bool mapped)
218 {
219 // Track the current state (which will change throughout the trace)
220 mStartingBuffersMappedCurrent[id] = mapped;
221
222 // And the initial state, to compare during frame loop reset
223 mStartingBuffersMappedInitial[id] = mapped;
224 }
225
226 private:
227 // Buffer regen calls will delete and gen a buffer
228 BufferCalls mBufferRegenCalls;
229 // Buffer restore calls will restore the contents of a buffer
230 BufferCalls mBufferRestoreCalls;
231 // Buffer map calls will map a buffer with correct offset, length, and access flags
232 BufferCalls mBufferMapCalls;
233 // Buffer unmap calls will bind and unmap a given buffer
234 BufferCalls mBufferUnmapCalls;
235
236 // Starting buffers include all the buffers created during setup for MEC
237 BufferSet mStartingBuffers;
238 // New buffers are those generated while capturing
239 BufferSet mNewBuffers;
240 // Buffers to regen are a list of starting buffers that need to be deleted and genned
241 BufferSet mBuffersToRegen;
242 // Buffers to restore include any starting buffers with contents modified during the run
243 BufferSet mBuffersToRestore;
244
245 // Whether a given buffer was mapped at the start of the trace
246 BufferMapStatusMap mStartingBuffersMappedInitial;
247 // The status of buffer mapping throughout the trace, modified with each Map/Unmap call
248 BufferMapStatusMap mStartingBuffersMappedCurrent;
249 };
250
251 // Used by the CPP replay to filter out unnecessary code.
252 using HasResourceTypeMap = angle::PackedEnumBitSet<ResourceIDType>;
253
254 // Map of buffer ID to offset and size used when mapped
255 using BufferDataMap = std::map<gl::BufferID, std::pair<GLintptr, GLsizeiptr>>;
256
257 // A dictionary of sources indexed by shader type.
258 using ProgramSources = gl::ShaderMap<std::string>;
259
260 // Maps from IDs to sources.
261 using ShaderSourceMap = std::map<gl::ShaderProgramID, std::string>;
262 using ProgramSourceMap = std::map<gl::ShaderProgramID, ProgramSources>;
263
264 // Map from textureID to level and data
265 using TextureLevels = std::map<GLint, std::vector<uint8_t>>;
266 using TextureLevelDataMap = std::map<gl::TextureID, TextureLevels>;
267
268 class FrameCapture final : angle::NonCopyable
269 {
270 public:
271 FrameCapture();
272 ~FrameCapture();
273
274 void captureCall(const gl::Context *context, CallCapture &&call);
275 void onEndFrame(const gl::Context *context);
enabled()276 bool enabled() const { return mEnabled; }
277
278 bool isCapturing() const;
279 void replay(gl::Context *context);
280
281 void trackBufferMapping(CallCapture *call,
282 gl::BufferID id,
283 GLintptr offset,
284 GLsizeiptr length,
285 GLbitfield accessFlags);
286
getResouceTracker()287 ResourceTracker &getResouceTracker() { return mResourceTracker; }
288
289 private:
290 void captureClientArraySnapshot(const gl::Context *context,
291 size_t vertexCount,
292 size_t instanceCount);
293 void captureMappedBufferSnapshot(const gl::Context *context, const CallCapture &call);
294
295 void captureCompressedTextureData(const gl::Context *context, const CallCapture &call);
296
297 void reset();
298 void maybeCaptureClientData(const gl::Context *context, CallCapture &call);
299 void maybeCapturePostCallUpdates(const gl::Context *context);
300
301 static void ReplayCall(gl::Context *context,
302 ReplayContext *replayContext,
303 const CallCapture &call);
304
305 std::vector<CallCapture> mSetupCalls;
306 std::vector<CallCapture> mFrameCalls;
307
308 // We save one large buffer of binary data for the whole CPP replay.
309 // This simplifies a lot of file management.
310 std::vector<uint8_t> mBinaryData;
311
312 bool mEnabled = false;
313 std::string mOutDirectory;
314 std::string mCaptureLabel;
315 bool mCompression;
316 gl::AttribArray<int> mClientVertexArrayMap;
317 uint32_t mFrameIndex;
318 uint32_t mFrameStart;
319 uint32_t mFrameEnd;
320 gl::AttribArray<size_t> mClientArraySizes;
321 size_t mReadBufferSize;
322 HasResourceTypeMap mHasResourceType;
323 BufferDataMap mBufferDataMap;
324
325 ResourceTracker mResourceTracker;
326
327 // Cache most recently compiled and linked sources.
328 ShaderSourceMap mCachedShaderSources;
329 ProgramSourceMap mCachedProgramSources;
330
331 // Cache a shadow copy of texture level data
332 TextureLevels mCachedTextureLevels;
333 TextureLevelDataMap mCachedTextureLevelData;
334 };
335
336 template <typename CaptureFuncT, typename... ArgsT>
CaptureCallToFrameCapture(CaptureFuncT captureFunc,bool isCallValid,gl::Context * context,ArgsT...captureParams)337 void CaptureCallToFrameCapture(CaptureFuncT captureFunc,
338 bool isCallValid,
339 gl::Context *context,
340 ArgsT... captureParams)
341 {
342 FrameCapture *frameCapture = context->getFrameCapture();
343 if (!frameCapture->isCapturing())
344 return;
345
346 CallCapture call = captureFunc(context->getState(), isCallValid, captureParams...);
347 frameCapture->captureCall(context, std::move(call));
348 }
349
350 template <typename T>
addValueParam(const char * paramName,ParamType paramType,T paramValue)351 void ParamBuffer::addValueParam(const char *paramName, ParamType paramType, T paramValue)
352 {
353 ParamCapture capture(paramName, paramType);
354 InitParamValue(paramType, paramValue, &capture.value);
355 mParamCaptures.emplace_back(std::move(capture));
356 }
357
358 template <typename T>
addEnumParam(const char * paramName,gl::GLenumGroup enumGroup,ParamType paramType,T paramValue)359 void ParamBuffer::addEnumParam(const char *paramName,
360 gl::GLenumGroup enumGroup,
361 ParamType paramType,
362 T paramValue)
363 {
364 ParamCapture capture(paramName, paramType);
365 InitParamValue(paramType, paramValue, &capture.value);
366 capture.enumGroup = enumGroup;
367 mParamCaptures.emplace_back(std::move(capture));
368 }
369
370 std::ostream &operator<<(std::ostream &os, const ParamCapture &capture);
371
372 // Pointer capture helpers.
373 void CaptureMemory(const void *source, size_t size, ParamCapture *paramCapture);
374 void CaptureString(const GLchar *str, ParamCapture *paramCapture);
375 void CaptureStringLimit(const GLchar *str, uint32_t limit, ParamCapture *paramCapture);
376
377 gl::Program *GetProgramForCapture(const gl::State &glState, gl::ShaderProgramID handle);
378
379 // For GetIntegerv, GetFloatv, etc.
380 void CaptureGetParameter(const gl::State &glState,
381 GLenum pname,
382 size_t typeSize,
383 ParamCapture *paramCapture);
384
385 void CaptureGenHandlesImpl(GLsizei n, GLuint *handles, ParamCapture *paramCapture);
386
387 template <typename T>
CaptureGenHandles(GLsizei n,T * handles,ParamCapture * paramCapture)388 void CaptureGenHandles(GLsizei n, T *handles, ParamCapture *paramCapture)
389 {
390 CaptureGenHandlesImpl(n, reinterpret_cast<GLuint *>(handles), paramCapture);
391 }
392
393 template <ParamType ParamT, typename T>
394 void WriteParamValueReplay(std::ostream &os, const CallCapture &call, T value);
395
396 template <>
397 void WriteParamValueReplay<ParamType::TGLboolean>(std::ostream &os,
398 const CallCapture &call,
399 GLboolean value);
400
401 template <>
402 void WriteParamValueReplay<ParamType::TvoidConstPointer>(std::ostream &os,
403 const CallCapture &call,
404 const void *value);
405
406 template <>
407 void WriteParamValueReplay<ParamType::TGLDEBUGPROCKHR>(std::ostream &os,
408 const CallCapture &call,
409 GLDEBUGPROCKHR value);
410
411 template <>
412 void WriteParamValueReplay<ParamType::TGLDEBUGPROC>(std::ostream &os,
413 const CallCapture &call,
414 GLDEBUGPROC value);
415
416 template <>
417 void WriteParamValueReplay<ParamType::TBufferID>(std::ostream &os,
418 const CallCapture &call,
419 gl::BufferID value);
420
421 template <>
422 void WriteParamValueReplay<ParamType::TFenceNVID>(std::ostream &os,
423 const CallCapture &call,
424 gl::FenceNVID value);
425
426 template <>
427 void WriteParamValueReplay<ParamType::TFramebufferID>(std::ostream &os,
428 const CallCapture &call,
429 gl::FramebufferID value);
430
431 template <>
432 void WriteParamValueReplay<ParamType::TMemoryObjectID>(std::ostream &os,
433 const CallCapture &call,
434 gl::MemoryObjectID value);
435
436 template <>
437 void WriteParamValueReplay<ParamType::TProgramPipelineID>(std::ostream &os,
438 const CallCapture &call,
439 gl::ProgramPipelineID value);
440
441 template <>
442 void WriteParamValueReplay<ParamType::TQueryID>(std::ostream &os,
443 const CallCapture &call,
444 gl::QueryID value);
445
446 template <>
447 void WriteParamValueReplay<ParamType::TRenderbufferID>(std::ostream &os,
448 const CallCapture &call,
449 gl::RenderbufferID value);
450
451 template <>
452 void WriteParamValueReplay<ParamType::TSamplerID>(std::ostream &os,
453 const CallCapture &call,
454 gl::SamplerID value);
455
456 template <>
457 void WriteParamValueReplay<ParamType::TSemaphoreID>(std::ostream &os,
458 const CallCapture &call,
459 gl::SemaphoreID value);
460
461 template <>
462 void WriteParamValueReplay<ParamType::TShaderProgramID>(std::ostream &os,
463 const CallCapture &call,
464 gl::ShaderProgramID value);
465
466 template <>
467 void WriteParamValueReplay<ParamType::TTextureID>(std::ostream &os,
468 const CallCapture &call,
469 gl::TextureID value);
470
471 template <>
472 void WriteParamValueReplay<ParamType::TTransformFeedbackID>(std::ostream &os,
473 const CallCapture &call,
474 gl::TransformFeedbackID value);
475
476 template <>
477 void WriteParamValueReplay<ParamType::TVertexArrayID>(std::ostream &os,
478 const CallCapture &call,
479 gl::VertexArrayID value);
480
481 template <>
482 void WriteParamValueReplay<ParamType::TUniformLocation>(std::ostream &os,
483 const CallCapture &call,
484 gl::UniformLocation value);
485
486 template <>
487 void WriteParamValueReplay<ParamType::TGLsync>(std::ostream &os,
488 const CallCapture &call,
489 GLsync value);
490
491 // General fallback for any unspecific type.
492 template <ParamType ParamT, typename T>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,T value)493 void WriteParamValueReplay(std::ostream &os, const CallCapture &call, T value)
494 {
495 os << value;
496 }
497 } // namespace angle
498
499 #endif // LIBANGLE_FRAME_CAPTURE_H_
500