• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 &&param);
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 &&paramsIn);
98     CallCapture(const std::string &customFunctionNameIn, ParamBuffer &&paramsIn);
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 &param)
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 &param)
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 &param)
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 &paramName);
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