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 // Used by the CPP replay to filter out unnecessary code.
181 using HasResourceTypeMap = angle::PackedEnumBitSet<ResourceIDType>;
182
183 // Map of buffer ID to offset and size used when mapped
184 using BufferDataMap = std::map<gl::BufferID, std::pair<GLintptr, GLsizeiptr>>;
185
186 // A dictionary of sources indexed by shader type.
187 using ProgramSources = gl::ShaderMap<std::string>;
188
189 // Maps from IDs to sources.
190 using ShaderSourceMap = std::map<gl::ShaderProgramID, std::string>;
191 using ProgramSourceMap = std::map<gl::ShaderProgramID, ProgramSources>;
192
193 // Map from textureID to level and data
194 using TextureLevels = std::map<GLint, std::vector<uint8_t>>;
195 using TextureLevelDataMap = std::map<gl::TextureID, TextureLevels>;
196
197 class FrameCapture final : angle::NonCopyable
198 {
199 public:
200 FrameCapture();
201 ~FrameCapture();
202
203 void captureCall(const gl::Context *context, CallCapture &&call);
204 void onEndFrame(const gl::Context *context);
enabled()205 bool enabled() const { return mEnabled; }
206
207 bool isCapturing() const;
208 void replay(gl::Context *context);
209
210 private:
211 void captureClientArraySnapshot(const gl::Context *context,
212 size_t vertexCount,
213 size_t instanceCount);
214 void captureMappedBufferSnapshot(const gl::Context *context, const CallCapture &call);
215
216 void captureCompressedTextureData(const gl::Context *context, const CallCapture &call);
217
218 void reset();
219 void maybeCaptureClientData(const gl::Context *context, CallCapture &call);
220 void maybeCapturePostCallUpdates(const gl::Context *context);
221
222 static void ReplayCall(gl::Context *context,
223 ReplayContext *replayContext,
224 const CallCapture &call);
225
226 std::vector<CallCapture> mSetupCalls;
227 std::vector<CallCapture> mFrameCalls;
228 std::vector<CallCapture> mTearDownCalls;
229
230 // We save one large buffer of binary data for the whole CPP replay.
231 // This simplifies a lot of file management.
232 std::vector<uint8_t> mBinaryData;
233
234 bool mEnabled = false;
235 std::string mOutDirectory;
236 std::string mCaptureLabel;
237 bool mCompression;
238 gl::AttribArray<int> mClientVertexArrayMap;
239 uint32_t mFrameIndex;
240 uint32_t mFrameStart;
241 uint32_t mFrameEnd;
242 gl::AttribArray<size_t> mClientArraySizes;
243 size_t mReadBufferSize;
244 HasResourceTypeMap mHasResourceType;
245 BufferDataMap mBufferDataMap;
246
247 // Cache most recently compiled and linked sources.
248 ShaderSourceMap mCachedShaderSources;
249 ProgramSourceMap mCachedProgramSources;
250
251 // Cache a shadow copy of texture level data
252 TextureLevels mCachedTextureLevels;
253 TextureLevelDataMap mCachedTextureLevelData;
254 };
255
256 template <typename CaptureFuncT, typename... ArgsT>
CaptureCallToFrameCapture(CaptureFuncT captureFunc,bool isCallValid,gl::Context * context,ArgsT...captureParams)257 void CaptureCallToFrameCapture(CaptureFuncT captureFunc,
258 bool isCallValid,
259 gl::Context *context,
260 ArgsT... captureParams)
261 {
262 FrameCapture *frameCapture = context->getFrameCapture();
263 if (!frameCapture->isCapturing())
264 return;
265
266 CallCapture call = captureFunc(context->getState(), isCallValid, captureParams...);
267 frameCapture->captureCall(context, std::move(call));
268 }
269
270 template <typename T>
addValueParam(const char * paramName,ParamType paramType,T paramValue)271 void ParamBuffer::addValueParam(const char *paramName, ParamType paramType, T paramValue)
272 {
273 ParamCapture capture(paramName, paramType);
274 InitParamValue(paramType, paramValue, &capture.value);
275 mParamCaptures.emplace_back(std::move(capture));
276 }
277
278 template <typename T>
addEnumParam(const char * paramName,gl::GLenumGroup enumGroup,ParamType paramType,T paramValue)279 void ParamBuffer::addEnumParam(const char *paramName,
280 gl::GLenumGroup enumGroup,
281 ParamType paramType,
282 T paramValue)
283 {
284 ParamCapture capture(paramName, paramType);
285 InitParamValue(paramType, paramValue, &capture.value);
286 capture.enumGroup = enumGroup;
287 mParamCaptures.emplace_back(std::move(capture));
288 }
289
290 std::ostream &operator<<(std::ostream &os, const ParamCapture &capture);
291
292 // Pointer capture helpers.
293 void CaptureMemory(const void *source, size_t size, ParamCapture *paramCapture);
294 void CaptureString(const GLchar *str, ParamCapture *paramCapture);
295 void CaptureStringLimit(const GLchar *str, uint32_t limit, ParamCapture *paramCapture);
296
297 gl::Program *GetLinkedProgramForCapture(const gl::State &glState, gl::ShaderProgramID handle);
298
299 // For GetIntegerv, GetFloatv, etc.
300 void CaptureGetParameter(const gl::State &glState,
301 GLenum pname,
302 size_t typeSize,
303 ParamCapture *paramCapture);
304
305 void CaptureGenHandlesImpl(GLsizei n, GLuint *handles, ParamCapture *paramCapture);
306
307 template <typename T>
CaptureGenHandles(GLsizei n,T * handles,ParamCapture * paramCapture)308 void CaptureGenHandles(GLsizei n, T *handles, ParamCapture *paramCapture)
309 {
310 CaptureGenHandlesImpl(n, reinterpret_cast<GLuint *>(handles), paramCapture);
311 }
312
313 template <ParamType ParamT, typename T>
314 void WriteParamValueReplay(std::ostream &os, const CallCapture &call, T value);
315
316 template <>
317 void WriteParamValueReplay<ParamType::TGLboolean>(std::ostream &os,
318 const CallCapture &call,
319 GLboolean value);
320
321 template <>
322 void WriteParamValueReplay<ParamType::TvoidConstPointer>(std::ostream &os,
323 const CallCapture &call,
324 const void *value);
325
326 template <>
327 void WriteParamValueReplay<ParamType::TGLDEBUGPROCKHR>(std::ostream &os,
328 const CallCapture &call,
329 GLDEBUGPROCKHR value);
330
331 template <>
332 void WriteParamValueReplay<ParamType::TGLDEBUGPROC>(std::ostream &os,
333 const CallCapture &call,
334 GLDEBUGPROC value);
335
336 template <>
337 void WriteParamValueReplay<ParamType::TBufferID>(std::ostream &os,
338 const CallCapture &call,
339 gl::BufferID value);
340
341 template <>
342 void WriteParamValueReplay<ParamType::TFenceNVID>(std::ostream &os,
343 const CallCapture &call,
344 gl::FenceNVID value);
345
346 template <>
347 void WriteParamValueReplay<ParamType::TFramebufferID>(std::ostream &os,
348 const CallCapture &call,
349 gl::FramebufferID value);
350
351 template <>
352 void WriteParamValueReplay<ParamType::TMemoryObjectID>(std::ostream &os,
353 const CallCapture &call,
354 gl::MemoryObjectID value);
355
356 template <>
357 void WriteParamValueReplay<ParamType::TProgramPipelineID>(std::ostream &os,
358 const CallCapture &call,
359 gl::ProgramPipelineID value);
360
361 template <>
362 void WriteParamValueReplay<ParamType::TQueryID>(std::ostream &os,
363 const CallCapture &call,
364 gl::QueryID value);
365
366 template <>
367 void WriteParamValueReplay<ParamType::TRenderbufferID>(std::ostream &os,
368 const CallCapture &call,
369 gl::RenderbufferID value);
370
371 template <>
372 void WriteParamValueReplay<ParamType::TSamplerID>(std::ostream &os,
373 const CallCapture &call,
374 gl::SamplerID value);
375
376 template <>
377 void WriteParamValueReplay<ParamType::TSemaphoreID>(std::ostream &os,
378 const CallCapture &call,
379 gl::SemaphoreID value);
380
381 template <>
382 void WriteParamValueReplay<ParamType::TShaderProgramID>(std::ostream &os,
383 const CallCapture &call,
384 gl::ShaderProgramID value);
385
386 template <>
387 void WriteParamValueReplay<ParamType::TTextureID>(std::ostream &os,
388 const CallCapture &call,
389 gl::TextureID value);
390
391 template <>
392 void WriteParamValueReplay<ParamType::TTransformFeedbackID>(std::ostream &os,
393 const CallCapture &call,
394 gl::TransformFeedbackID value);
395
396 template <>
397 void WriteParamValueReplay<ParamType::TVertexArrayID>(std::ostream &os,
398 const CallCapture &call,
399 gl::VertexArrayID value);
400
401 template <>
402 void WriteParamValueReplay<ParamType::TUniformLocation>(std::ostream &os,
403 const CallCapture &call,
404 gl::UniformLocation value);
405
406 template <>
407 void WriteParamValueReplay<ParamType::TGLsync>(std::ostream &os,
408 const CallCapture &call,
409 GLsync value);
410
411 // General fallback for any unspecific type.
412 template <ParamType ParamT, typename T>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,T value)413 void WriteParamValueReplay(std::ostream &os, const CallCapture &call, T value)
414 {
415 os << value;
416 }
417 } // namespace angle
418
419 #endif // LIBANGLE_FRAME_CAPTURE_H_
420