xref: /aosp_15_r20/external/angle/src/libANGLE/renderer/gl/TransformFeedbackGL.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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