Bug 1671598 [wpt PR 26128] - [AspectRatio] Fix divide by zero with a small float...
[gecko.git] / dom / canvas / WebGLTransformFeedback.cpp
blob2907f0e2a2a17b5cfe69789439a4dec5d270883e
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"
8 #include "GLContext.h"
9 #include "mozilla/dom/WebGL2RenderingContextBinding.h"
10 #include "mozilla/IntegerRange.h"
11 #include "WebGL2Context.h"
12 #include "WebGLBuffer.h"
13 #include "WebGLProgram.h"
15 namespace mozilla {
17 WebGLTransformFeedback::WebGLTransformFeedback(WebGLContext* webgl, GLuint tf)
18 : WebGLContextBoundObject(webgl),
19 mGLName(tf),
20 mIndexedBindings(webgl->Limits().maxTransformFeedbackSeparateAttribs),
21 mIsPaused(false),
22 mIsActive(false) {}
24 WebGLTransformFeedback::~WebGLTransformFeedback() {
25 if (!mContext) return;
26 if (mGLName) {
27 mContext->gl->fDeleteTransformFeedbacks(1, &mGLName);
31 ////////////////////////////////////////
33 void WebGLTransformFeedback::BeginTransformFeedback(GLenum primMode) {
34 if (mIsActive) return mContext->ErrorInvalidOperation("Already active.");
36 switch (primMode) {
37 case LOCAL_GL_POINTS:
38 case LOCAL_GL_LINES:
39 case LOCAL_GL_TRIANGLES:
40 break;
41 default:
42 mContext->ErrorInvalidEnum(
43 "`primitiveMode` must be one of POINTS, LINES, or"
44 " TRIANGLES.");
45 return;
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"
53 " feedback.");
54 return;
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;
66 if (!buffer) {
67 mContext->ErrorInvalidOperation(
68 "No buffer attached to required transform"
69 " feedback index %u.",
70 (uint32_t)i);
71 return;
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));
80 return;
84 const size_t vertCapacity = buffer->ByteLength() / 4 / componentsPerVert;
85 minVertCapacity = std::min(minVertCapacity, vertCapacity);
88 ////
90 const auto& gl = mContext->gl;
91 gl->fBeginTransformFeedback(primMode);
93 ////
95 mIsActive = true;
96 MOZ_ASSERT(!mIsPaused);
98 mActive_Program = prog;
99 mActive_PrimMode = primMode;
100 mActive_VertPosition = 0;
101 mActive_VertCapacity = minVertCapacity;
103 ////
105 mActive_Program->mNumActiveTFOs++;
108 void WebGLTransformFeedback::EndTransformFeedback() {
109 if (!mIsActive) return mContext->ErrorInvalidOperation("Not active.");
111 ////
113 const auto& gl = mContext->gl;
114 gl->fEndTransformFeedback();
116 if (gl->WorkAroundDriverBugs()) {
117 #ifdef XP_MACOSX
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
123 // feedback.
124 gl->fFlush();
125 #endif
128 ////
130 mIsActive = false;
131 mIsPaused = false;
133 ////
135 mActive_Program->mNumActiveTFOs--;
138 void WebGLTransformFeedback::PauseTransformFeedback() {
139 if (!mIsActive || mIsPaused) {
140 mContext->ErrorInvalidOperation("Not active or is paused.");
141 return;
144 ////
146 const auto& gl = mContext->gl;
147 gl->fPauseTransformFeedback();
149 ////
151 mIsPaused = true;
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.");
159 return;
162 ////
164 const auto& gl = mContext->gl;
165 gl->fResumeTransformFeedback();
167 ////
169 MOZ_ASSERT(mIsActive);
170 mIsPaused = false;
173 } // namespace mozilla