-class TraceAnalyzer {
- /* Map for tracking resource dependencies between calls. */
- std::map<const char *, std::set<unsigned>, stringCompare > resources;
-
- /* The final set of calls required. This consists of calls added
- * explicitly with the require() method as well as all calls
- * implicitly required by those through resource dependencies. */
- std::set<unsigned> required;
-
- bool transformFeedbackActive;
- bool framebufferObjectActive;
- bool insideBeginEnd;
-
- /* Rendering often has no side effects, but it can in some cases,
- * (such as when transform feedback is active, or when rendering
- * targets a framebuffer object). */
- bool renderingHasSideEffect() {
- return transformFeedbackActive || framebufferObjectActive;
- }
-
- /* Provide: Record that the given call affects the given resource
- * as a side effect. */
- void provide(const char *resource, trace::CallNo call_no) {
- resources[resource].insert(call_no);
- }
-
- /* Consume: Add all calls that provide the given resource to the
- * required list, then clear the list for this resource. */
- void consume(const char *resource) {
-
- std::set<unsigned> *calls;
- std::set<unsigned>::iterator call;
-
- /* Insert as required all calls that provide 'resource',
- * then clear these calls. */
- if (resources.count(resource)) {
- calls = &resources[resource];
- for (call = calls->begin(); call != calls->end(); call++) {
- required.insert(*call);
- }
- resources.erase(resource);
- }
- }
-
- void stateTrackPreCall(trace::Call *call) {
-
- if (strcmp(call->name(), "glBegin") == 0) {
- insideBeginEnd = true;
- return;
- }
-
- if (strcmp(call->name(), "glBeginTransformFeedback") == 0) {
- transformFeedbackActive = true;
- return;
- }
-
- if (strcmp(call->name(), "glBindFramebuffer") == 0) {
- GLenum target;
- GLuint framebuffer;
-
- target = static_cast<GLenum>(call->arg(0).toSInt());
- framebuffer = call->arg(1).toUInt();
-
- if (target == GL_FRAMEBUFFER || target == GL_DRAW_FRAMEBUFFER) {
- if (framebuffer == 0) {
- framebufferObjectActive = false;
- } else {
- framebufferObjectActive = true;
- }
- }
- return;
- }
- }
-
- void stateTrackPostCall(trace::Call *call) {
-
- if (strcmp(call->name(), "glEnd") == 0) {
- insideBeginEnd = false;
- return;
- }
-
- if (strcmp(call->name(), "glEndTransformFeedback") == 0) {
- transformFeedbackActive = false;
- return;
- }
-
- if (call->flags & trace::CALL_FLAG_SWAP_RENDERTARGET &&
- call->flags & trace::CALL_FLAG_END_FRAME) {
- resources.erase("framebuffer");
- return;
- }
- }
-
- void recordSideEffects(trace::Call *call) {
- /* If call is flagged as no side effects, then we are done here. */
- if (call->flags & trace::CALL_FLAG_NO_SIDE_EFFECTS) {
- return;
- }
-
- /* Similarly, swap-buffers calls don't have interesting side effects. */
- if (call->flags & trace::CALL_FLAG_SWAP_RENDERTARGET &&
- call->flags & trace::CALL_FLAG_END_FRAME) {
- return;
- }
-
- /* Handle all rendering operations, (even though only glEnd is
- * flagged as a rendering operation we treat everything from
- * glBegin through glEnd as a rendering operation). */
- if (call->flags & trace::CALL_FLAG_RENDER ||
- insideBeginEnd) {
-
- provide("framebuffer", call->no);
-
- /* In some cases, rendering has side effects beyond the
- * framebuffer update. */
- if (renderingHasSideEffect()) {
- provide("state", call->no);
- }
-
- return;
- }
-
- /* By default, assume this call affects the state somehow. */
- resources["state"].insert(call->no);
- }
-
- void requireDependencies(trace::Call *call) {
-
- /* Swap-buffers calls depend on framebuffer state. */
- if (call->flags & trace::CALL_FLAG_SWAP_RENDERTARGET &&
- call->flags & trace::CALL_FLAG_END_FRAME) {
- consume("framebuffer");
- }
-
- /* By default, just assume this call depends on generic state. */
- consume("state");
- }
-
-
-public:
- TraceAnalyzer(): transformFeedbackActive(false),
- framebufferObjectActive(false),
- insideBeginEnd(false)
- {}
-
- ~TraceAnalyzer() {}
-
- /* Analyze this call by tracking state and recording all the
- * resources provided by this call as side effects.. */
- void analyze(trace::Call *call) {
-
- stateTrackPreCall(call);
-
- recordSideEffects(call);
-
- stateTrackPostCall(call);
- }
-
- /* Require this call and all of its dependencies to be included in
- * the final trace. */
- void require(trace::Call *call) {
-
- /* First, find and insert all calls that this call depends on. */
- requireDependencies(call);
-
- /* Then insert this call itself. */
- required.insert(call->no);
- }
-
- /* Return a set of all the required calls, (both those calls added
- * explicitly with require() and those implicitly depended
- * upon. */
- std::set<unsigned> *get_required(void) {
- return &required;
- }
-};
-