summaryrefslogtreecommitdiffstats
path: root/dom/canvas/WebGLTransformFeedback.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/canvas/WebGLTransformFeedback.cpp')
-rw-r--r--dom/canvas/WebGLTransformFeedback.cpp173
1 files changed, 173 insertions, 0 deletions
diff --git a/dom/canvas/WebGLTransformFeedback.cpp b/dom/canvas/WebGLTransformFeedback.cpp
new file mode 100644
index 0000000000..ffcf7b6479
--- /dev/null
+++ b/dom/canvas/WebGLTransformFeedback.cpp
@@ -0,0 +1,173 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "WebGLTransformFeedback.h"
+
+#include "GLContext.h"
+#include "mozilla/dom/WebGL2RenderingContextBinding.h"
+#include "mozilla/IntegerRange.h"
+#include "WebGL2Context.h"
+#include "WebGLBuffer.h"
+#include "WebGLProgram.h"
+
+namespace mozilla {
+
+WebGLTransformFeedback::WebGLTransformFeedback(WebGLContext* webgl, GLuint tf)
+ : WebGLContextBoundObject(webgl),
+ mGLName(tf),
+ mIndexedBindings(webgl::kMaxTransformFeedbackSeparateAttribs),
+ mIsPaused(false),
+ mIsActive(false) {}
+
+WebGLTransformFeedback::~WebGLTransformFeedback() {
+ if (!mContext) return;
+ if (mGLName) {
+ mContext->gl->fDeleteTransformFeedbacks(1, &mGLName);
+ }
+}
+
+////////////////////////////////////////
+
+void WebGLTransformFeedback::BeginTransformFeedback(GLenum primMode) {
+ if (mIsActive) return mContext->ErrorInvalidOperation("Already active.");
+
+ switch (primMode) {
+ case LOCAL_GL_POINTS:
+ case LOCAL_GL_LINES:
+ case LOCAL_GL_TRIANGLES:
+ break;
+ default:
+ mContext->ErrorInvalidEnum(
+ "`primitiveMode` must be one of POINTS, LINES, or"
+ " TRIANGLES.");
+ return;
+ }
+
+ const auto& prog = mContext->mCurrentProgram;
+ if (!prog || !prog->IsLinked() ||
+ prog->LinkInfo()->componentsPerTFVert.empty()) {
+ mContext->ErrorInvalidOperation(
+ "Current program not valid for transform"
+ " feedback.");
+ return;
+ }
+
+ const auto& linkInfo = prog->LinkInfo();
+ const auto& componentsPerTFVert = linkInfo->componentsPerTFVert;
+
+ size_t minVertCapacity = SIZE_MAX;
+ for (size_t i = 0; i < componentsPerTFVert.size(); i++) {
+ const auto& indexedBinding = mIndexedBindings[i];
+ const auto& componentsPerVert = componentsPerTFVert[i];
+
+ const auto& buffer = indexedBinding.mBufferBinding;
+ if (!buffer) {
+ mContext->ErrorInvalidOperation(
+ "No buffer attached to required transform"
+ " feedback index %u.",
+ (uint32_t)i);
+ return;
+ }
+
+ for (const auto iBound : IntegerRange(mIndexedBindings.size())) {
+ const auto& bound = mIndexedBindings[iBound].mBufferBinding.get();
+ if (iBound != i && buffer == bound) {
+ mContext->GenErrorIllegalUse(
+ LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER, static_cast<uint32_t>(i),
+ LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER, static_cast<uint32_t>(iBound));
+ return;
+ }
+ }
+
+ const size_t vertCapacity = buffer->ByteLength() / 4 / componentsPerVert;
+ minVertCapacity = std::min(minVertCapacity, vertCapacity);
+ }
+
+ ////
+
+ const auto& gl = mContext->gl;
+ gl->fBeginTransformFeedback(primMode);
+
+ ////
+
+ mIsActive = true;
+ MOZ_ASSERT(!mIsPaused);
+
+ mActive_Program = prog;
+ mActive_PrimMode = primMode;
+ mActive_VertPosition = 0;
+ mActive_VertCapacity = minVertCapacity;
+
+ ////
+
+ mActive_Program->mNumActiveTFOs++;
+}
+
+void WebGLTransformFeedback::EndTransformFeedback() {
+ if (!mIsActive) return mContext->ErrorInvalidOperation("Not active.");
+
+ ////
+
+ const auto& gl = mContext->gl;
+ gl->fEndTransformFeedback();
+
+ if (gl->WorkAroundDriverBugs()) {
+#ifdef XP_MACOSX
+ // Multi-threaded GL on mac will generate INVALID_OP in some cases for at
+ // least BindBufferBase after an EndTransformFeedback if there is not a
+ // flush between the two. Single-threaded GL does not have this issue. This
+ // is likely due to not synchronizing client/server state, and erroring in
+ // BindBufferBase because the client thinks we're still in transform
+ // feedback.
+ gl->fFlush();
+#endif
+ }
+
+ ////
+
+ mIsActive = false;
+ mIsPaused = false;
+
+ ////
+
+ mActive_Program->mNumActiveTFOs--;
+}
+
+void WebGLTransformFeedback::PauseTransformFeedback() {
+ if (!mIsActive || mIsPaused) {
+ mContext->ErrorInvalidOperation("Not active or is paused.");
+ return;
+ }
+
+ ////
+
+ const auto& gl = mContext->gl;
+ gl->fPauseTransformFeedback();
+
+ ////
+
+ mIsPaused = true;
+}
+
+void WebGLTransformFeedback::ResumeTransformFeedback() {
+ if (!mIsPaused) return mContext->ErrorInvalidOperation("Not paused.");
+
+ if (mContext->mCurrentProgram != mActive_Program) {
+ mContext->ErrorInvalidOperation("Active program differs from original.");
+ return;
+ }
+
+ ////
+
+ const auto& gl = mContext->gl;
+ gl->fResumeTransformFeedback();
+
+ ////
+
+ MOZ_ASSERT(mIsActive);
+ mIsPaused = false;
+}
+
+} // namespace mozilla