1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "WebGLTransformFeedback.h"
9 #include "mozilla/dom/WebGL2RenderingContextBinding.h"
10 #include "mozilla/IntegerRange.h"
11 #include "WebGL2Context.h"
12 #include "WebGLBuffer.h"
13 #include "WebGLProgram.h"
17 WebGLTransformFeedback::WebGLTransformFeedback(WebGLContext
* webgl
, GLuint tf
)
18 : WebGLContextBoundObject(webgl
),
20 mIndexedBindings(webgl
->Limits().maxTransformFeedbackSeparateAttribs
),
24 WebGLTransformFeedback::~WebGLTransformFeedback() {
25 if (!mContext
) return;
27 mContext
->gl
->fDeleteTransformFeedbacks(1, &mGLName
);
31 ////////////////////////////////////////
33 void WebGLTransformFeedback::BeginTransformFeedback(GLenum primMode
) {
34 if (mIsActive
) return mContext
->ErrorInvalidOperation("Already active.");
39 case LOCAL_GL_TRIANGLES
:
42 mContext
->ErrorInvalidEnum(
43 "`primitiveMode` must be one of POINTS, LINES, or"
48 const auto& prog
= mContext
->mCurrentProgram
;
49 if (!prog
|| !prog
->IsLinked() ||
50 prog
->LinkInfo()->componentsPerTFVert
.empty()) {
51 mContext
->ErrorInvalidOperation(
52 "Current program not valid for transform"
57 const auto& linkInfo
= prog
->LinkInfo();
58 const auto& componentsPerTFVert
= linkInfo
->componentsPerTFVert
;
60 size_t minVertCapacity
= SIZE_MAX
;
61 for (size_t i
= 0; i
< componentsPerTFVert
.size(); i
++) {
62 const auto& indexedBinding
= mIndexedBindings
[i
];
63 const auto& componentsPerVert
= componentsPerTFVert
[i
];
65 const auto& buffer
= indexedBinding
.mBufferBinding
;
67 mContext
->ErrorInvalidOperation(
68 "No buffer attached to required transform"
69 " feedback index %u.",
74 for (const auto iBound
: IntegerRange(mIndexedBindings
.size())) {
75 const auto& bound
= mIndexedBindings
[iBound
].mBufferBinding
.get();
76 if (iBound
!= i
&& buffer
== bound
) {
77 mContext
->GenErrorIllegalUse(
78 LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER
, static_cast<uint32_t>(i
),
79 LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER
, static_cast<uint32_t>(iBound
));
84 const size_t vertCapacity
= buffer
->ByteLength() / 4 / componentsPerVert
;
85 minVertCapacity
= std::min(minVertCapacity
, vertCapacity
);
90 const auto& gl
= mContext
->gl
;
91 gl
->fBeginTransformFeedback(primMode
);
96 MOZ_ASSERT(!mIsPaused
);
98 mActive_Program
= prog
;
99 mActive_PrimMode
= primMode
;
100 mActive_VertPosition
= 0;
101 mActive_VertCapacity
= minVertCapacity
;
105 mActive_Program
->mNumActiveTFOs
++;
108 void WebGLTransformFeedback::EndTransformFeedback() {
109 if (!mIsActive
) return mContext
->ErrorInvalidOperation("Not active.");
113 const auto& gl
= mContext
->gl
;
114 gl
->fEndTransformFeedback();
116 if (gl
->WorkAroundDriverBugs()) {
118 // Multi-threaded GL on mac will generate INVALID_OP in some cases for at
119 // least BindBufferBase after an EndTransformFeedback if there is not a
120 // flush between the two. Single-threaded GL does not have this issue. This
121 // is likely due to not synchronizing client/server state, and erroring in
122 // BindBufferBase because the client thinks we're still in transform
135 mActive_Program
->mNumActiveTFOs
--;
138 void WebGLTransformFeedback::PauseTransformFeedback() {
139 if (!mIsActive
|| mIsPaused
) {
140 mContext
->ErrorInvalidOperation("Not active or is paused.");
146 const auto& gl
= mContext
->gl
;
147 gl
->fPauseTransformFeedback();
154 void WebGLTransformFeedback::ResumeTransformFeedback() {
155 if (!mIsPaused
) return mContext
->ErrorInvalidOperation("Not paused.");
157 if (mContext
->mCurrentProgram
!= mActive_Program
) {
158 mContext
->ErrorInvalidOperation("Active program differs from original.");
164 const auto& gl
= mContext
->gl
;
165 gl
->fResumeTransformFeedback();
169 MOZ_ASSERT(mIsActive
);
173 } // namespace mozilla