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/ProgramExecutableGL.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 const gl::ProgramExecutable *executable = context->getState().getProgramExecutable();
47 ASSERT(executable);
48
49 const ProgramExecutableGL *executableGL = GetImplAs<ProgramExecutableGL>(executable);
50 mActiveProgram = executableGL->getProgramID();
51 mStateManager->onTransformFeedbackStateChange();
52 return angle::Result::Continue;
53 }
54
end(const gl::Context * context)55 angle::Result TransformFeedbackGL::end(const gl::Context *context)
56 {
57 mStateManager->onTransformFeedbackStateChange();
58
59 // Immediately end the transform feedback so that the results are visible.
60 syncActiveState(context, false, gl::PrimitiveMode::InvalidEnum);
61 return angle::Result::Continue;
62 }
63
pause(const gl::Context * context)64 angle::Result TransformFeedbackGL::pause(const gl::Context *context)
65 {
66 mStateManager->onTransformFeedbackStateChange();
67
68 syncPausedState(true);
69 return angle::Result::Continue;
70 }
71
resume(const gl::Context * context)72 angle::Result TransformFeedbackGL::resume(const gl::Context *context)
73 {
74 mStateManager->onTransformFeedbackStateChange();
75 return angle::Result::Continue;
76 }
77
bindIndexedBuffer(const gl::Context * context,size_t index,const gl::OffsetBindingPointer<gl::Buffer> & binding)78 angle::Result TransformFeedbackGL::bindIndexedBuffer(
79 const gl::Context *context,
80 size_t index,
81 const gl::OffsetBindingPointer<gl::Buffer> &binding)
82 {
83 const angle::FeaturesGL &features = GetFeaturesGL(context);
84
85 // Directly bind buffer (not through the StateManager methods) because the buffer bindings are
86 // tracked per transform feedback object
87 mStateManager->bindTransformFeedback(GL_TRANSFORM_FEEDBACK, mTransformFeedbackID);
88 if (binding.get() != nullptr)
89 {
90 const BufferGL *bufferGL = GetImplAs<BufferGL>(binding.get());
91
92 if (features.bindTransformFeedbackBufferBeforeBindBufferRange.enabled)
93 {
94 // Generic binding will be overwritten by the bindRange/bindBase below.
95 ANGLE_GL_TRY(context, mFunctions->bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER,
96 bufferGL->getBufferID()));
97 }
98
99 if (binding.getSize() != 0)
100 {
101 ANGLE_GL_TRY(context,
102 mFunctions->bindBufferRange(
103 GL_TRANSFORM_FEEDBACK_BUFFER, static_cast<GLuint>(index),
104 bufferGL->getBufferID(), binding.getOffset(), binding.getSize()));
105 }
106 else
107 {
108 ANGLE_GL_TRY(context, mFunctions->bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER,
109 static_cast<GLuint>(index),
110 bufferGL->getBufferID()));
111 }
112 }
113 else
114 {
115 ANGLE_GL_TRY(context, mFunctions->bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER,
116 static_cast<GLuint>(index), 0));
117 }
118 return angle::Result::Continue;
119 }
120
getTransformFeedbackID() const121 GLuint TransformFeedbackGL::getTransformFeedbackID() const
122 {
123 return mTransformFeedbackID;
124 }
125
syncActiveState(const gl::Context * context,bool active,gl::PrimitiveMode primitiveMode) const126 void TransformFeedbackGL::syncActiveState(const gl::Context *context,
127 bool active,
128 gl::PrimitiveMode primitiveMode) const
129 {
130 if (mIsActive != active)
131 {
132 mIsActive = active;
133 mIsPaused = false;
134
135 mStateManager->bindTransformFeedback(GL_TRANSFORM_FEEDBACK, mTransformFeedbackID);
136 if (mIsActive)
137 {
138 ASSERT(primitiveMode != gl::PrimitiveMode::InvalidEnum);
139 mStateManager->useProgram(mActiveProgram);
140 mFunctions->beginTransformFeedback(gl::ToGLenum(primitiveMode));
141 }
142 else
143 {
144 // Implementations disagree about what should happen if a different program is bound
145 // when calling EndTransformFeedback. We avoid the ambiguity by always re-binding the
146 // program associated with this transform feedback.
147 GLuint previousProgram = mStateManager->getProgramID();
148 mStateManager->useProgram(mActiveProgram);
149 mFunctions->endTransformFeedback();
150 // Restore the current program if we changed it.
151 mStateManager->useProgram(previousProgram);
152 }
153 }
154 }
155
syncPausedState(bool paused) const156 void TransformFeedbackGL::syncPausedState(bool paused) const
157 {
158 if (mIsActive && mIsPaused != paused)
159 {
160 mIsPaused = paused;
161
162 mStateManager->bindTransformFeedback(GL_TRANSFORM_FEEDBACK, mTransformFeedbackID);
163 if (mIsPaused)
164 {
165 mFunctions->pauseTransformFeedback();
166 }
167 else
168 {
169 mFunctions->resumeTransformFeedback();
170 }
171 }
172 }
173 } // namespace rx
174