1 //
2 // Copyright 2015 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
7 // TransformFeedbackGL.cpp: Implements the class methods for TransformFeedbackGL.
8
9 #include "libANGLE/renderer/gl/TransformFeedbackGL.h"
10
11 #include "common/debug.h"
12 #include "libANGLE/Context.h"
13 #include "libANGLE/State.h"
14 #include "libANGLE/renderer/gl/BufferGL.h"
15 #include "libANGLE/renderer/gl/FunctionsGL.h"
16 #include "libANGLE/renderer/gl/ProgramGL.h"
17 #include "libANGLE/renderer/gl/StateManagerGL.h"
18 #include "libANGLE/renderer/gl/renderergl_utils.h"
19
20 namespace rx
21 {
22
TransformFeedbackGL(const gl::TransformFeedbackState & state,const FunctionsGL * functions,StateManagerGL * stateManager)23 TransformFeedbackGL::TransformFeedbackGL(const gl::TransformFeedbackState &state,
24 const FunctionsGL *functions,
25 StateManagerGL *stateManager)
26 : TransformFeedbackImpl(state),
27 mFunctions(functions),
28 mStateManager(stateManager),
29 mTransformFeedbackID(0),
30 mIsActive(false),
31 mIsPaused(false),
32 mActiveProgram(0)
33 {
34 mFunctions->genTransformFeedbacks(1, &mTransformFeedbackID);
35 }
36
~TransformFeedbackGL()37 TransformFeedbackGL::~TransformFeedbackGL()
38 {
39 mStateManager->deleteTransformFeedback(mTransformFeedbackID);
40 mTransformFeedbackID = 0;
41 }
42
begin(const gl::Context * context,gl::PrimitiveMode primitiveMode)43 angle::Result TransformFeedbackGL::begin(const gl::Context *context,
44 gl::PrimitiveMode primitiveMode)
45 {
46 mStateManager->onTransformFeedbackStateChange();
47 return angle::Result::Continue;
48 }
49
end(const gl::Context * context)50 angle::Result TransformFeedbackGL::end(const gl::Context *context)
51 {
52 mStateManager->onTransformFeedbackStateChange();
53
54 // Immediately end the transform feedback so that the results are visible.
55 syncActiveState(context, false, gl::PrimitiveMode::InvalidEnum);
56 return angle::Result::Continue;
57 }
58
pause(const gl::Context * context)59 angle::Result TransformFeedbackGL::pause(const gl::Context *context)
60 {
61 mStateManager->onTransformFeedbackStateChange();
62
63 syncPausedState(true);
64 return angle::Result::Continue;
65 }
66
resume(const gl::Context * context)67 angle::Result TransformFeedbackGL::resume(const gl::Context *context)
68 {
69 mStateManager->onTransformFeedbackStateChange();
70 return angle::Result::Continue;
71 }
72
bindIndexedBuffer(const gl::Context * context,size_t index,const gl::OffsetBindingPointer<gl::Buffer> & binding)73 angle::Result TransformFeedbackGL::bindIndexedBuffer(
74 const gl::Context *context,
75 size_t index,
76 const gl::OffsetBindingPointer<gl::Buffer> &binding)
77 {
78 // Directly bind buffer (not through the StateManager methods) because the buffer bindings are
79 // tracked per transform feedback object
80 mStateManager->bindTransformFeedback(GL_TRANSFORM_FEEDBACK, mTransformFeedbackID);
81 if (binding.get() != nullptr)
82 {
83 const BufferGL *bufferGL = GetImplAs<BufferGL>(binding.get());
84 if (binding.getSize() != 0)
85 {
86 mFunctions->bindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, static_cast<GLuint>(index),
87 bufferGL->getBufferID(), binding.getOffset(),
88 binding.getSize());
89 }
90 else
91 {
92 mFunctions->bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, static_cast<GLuint>(index),
93 bufferGL->getBufferID());
94 }
95 }
96 else
97 {
98 mFunctions->bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, static_cast<GLuint>(index), 0);
99 }
100 return angle::Result::Continue;
101 }
102
getTransformFeedbackID() const103 GLuint TransformFeedbackGL::getTransformFeedbackID() const
104 {
105 return mTransformFeedbackID;
106 }
107
syncActiveState(const gl::Context * context,bool active,gl::PrimitiveMode primitiveMode) const108 void TransformFeedbackGL::syncActiveState(const gl::Context *context,
109 bool active,
110 gl::PrimitiveMode primitiveMode) const
111 {
112 if (mIsActive != active)
113 {
114 mIsActive = active;
115 mIsPaused = false;
116
117 mStateManager->bindTransformFeedback(GL_TRANSFORM_FEEDBACK, mTransformFeedbackID);
118 if (mIsActive)
119 {
120 ASSERT(primitiveMode != gl::PrimitiveMode::InvalidEnum);
121 mActiveProgram = GetImplAs<ProgramGL>(mState.getBoundProgram())->getProgramID();
122 mStateManager->useProgram(mActiveProgram);
123 mFunctions->beginTransformFeedback(gl::ToGLenum(primitiveMode));
124 }
125 else
126 {
127 // Implementations disagree about what should happen if a different program is bound
128 // when calling EndTransformFeedback. We avoid the ambiguity by always re-binding the
129 // program associated with this transform feedback.
130 GLuint previousProgram = mStateManager->getProgramID();
131 mStateManager->useProgram(mActiveProgram);
132 mFunctions->endTransformFeedback();
133 // Restore the current program if we changed it.
134 mStateManager->useProgram(previousProgram);
135 }
136 }
137 }
138
syncPausedState(bool paused) const139 void TransformFeedbackGL::syncPausedState(bool paused) const
140 {
141 if (mIsActive && mIsPaused != paused)
142 {
143 mIsPaused = paused;
144
145 mStateManager->bindTransformFeedback(GL_TRANSFORM_FEEDBACK, mTransformFeedbackID);
146 if (mIsPaused)
147 {
148 mFunctions->pauseTransformFeedback();
149 }
150 else
151 {
152 mFunctions->resumeTransformFeedback();
153 }
154 }
155 }
156 } // namespace rx
157