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 const angle::FeaturesGL &features = GetFeaturesGL(context);
79
80 // Directly bind buffer (not through the StateManager methods) because the buffer bindings are
81 // tracked per transform feedback object
82 mStateManager->bindTransformFeedback(GL_TRANSFORM_FEEDBACK, mTransformFeedbackID);
83 if (binding.get() != nullptr)
84 {
85 const BufferGL *bufferGL = GetImplAs<BufferGL>(binding.get());
86
87 if (features.bindTransformFeedbackBufferBeforeBindBufferRange.enabled)
88 {
89 // Generic binding will be overwritten by the bindRange/bindBase below.
90 ANGLE_GL_TRY(context, mFunctions->bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER,
91 bufferGL->getBufferID()));
92 }
93
94 if (binding.getSize() != 0)
95 {
96 ANGLE_GL_TRY(context,
97 mFunctions->bindBufferRange(
98 GL_TRANSFORM_FEEDBACK_BUFFER, static_cast<GLuint>(index),
99 bufferGL->getBufferID(), binding.getOffset(), binding.getSize()));
100 }
101 else
102 {
103 ANGLE_GL_TRY(context, mFunctions->bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER,
104 static_cast<GLuint>(index),
105 bufferGL->getBufferID()));
106 }
107 }
108 else
109 {
110 ANGLE_GL_TRY(context, mFunctions->bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER,
111 static_cast<GLuint>(index), 0));
112 }
113 return angle::Result::Continue;
114 }
115
getTransformFeedbackID() const116 GLuint TransformFeedbackGL::getTransformFeedbackID() const
117 {
118 return mTransformFeedbackID;
119 }
120
syncActiveState(const gl::Context * context,bool active,gl::PrimitiveMode primitiveMode) const121 void TransformFeedbackGL::syncActiveState(const gl::Context *context,
122 bool active,
123 gl::PrimitiveMode primitiveMode) const
124 {
125 if (mIsActive != active)
126 {
127 mIsActive = active;
128 mIsPaused = false;
129
130 mStateManager->bindTransformFeedback(GL_TRANSFORM_FEEDBACK, mTransformFeedbackID);
131 if (mIsActive)
132 {
133 ASSERT(primitiveMode != gl::PrimitiveMode::InvalidEnum);
134 mActiveProgram = GetImplAs<ProgramGL>(mState.getBoundProgram())->getProgramID();
135 mStateManager->useProgram(mActiveProgram);
136 mFunctions->beginTransformFeedback(gl::ToGLenum(primitiveMode));
137 }
138 else
139 {
140 // Implementations disagree about what should happen if a different program is bound
141 // when calling EndTransformFeedback. We avoid the ambiguity by always re-binding the
142 // program associated with this transform feedback.
143 GLuint previousProgram = mStateManager->getProgramID();
144 mStateManager->useProgram(mActiveProgram);
145 mFunctions->endTransformFeedback();
146 // Restore the current program if we changed it.
147 mStateManager->useProgram(previousProgram);
148 }
149 }
150 }
151
syncPausedState(bool paused) const152 void TransformFeedbackGL::syncPausedState(bool paused) const
153 {
154 if (mIsActive && mIsPaused != paused)
155 {
156 mIsPaused = paused;
157
158 mStateManager->bindTransformFeedback(GL_TRANSFORM_FEEDBACK, mTransformFeedbackID);
159 if (mIsPaused)
160 {
161 mFunctions->pauseTransformFeedback();
162 }
163 else
164 {
165 mFunctions->resumeTransformFeedback();
166 }
167 }
168 }
169 } // namespace rx
170