/src/mozilla-central/dom/canvas/WebGLTransformFeedback.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
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/. */ |
5 | | |
6 | | #include "WebGLTransformFeedback.h" |
7 | | |
8 | | #include "GLContext.h" |
9 | | #include "mozilla/dom/WebGL2RenderingContextBinding.h" |
10 | | #include "WebGL2Context.h" |
11 | | #include "WebGLProgram.h" |
12 | | |
13 | | namespace mozilla { |
14 | | |
15 | | WebGLTransformFeedback::WebGLTransformFeedback(WebGLContext* webgl, GLuint tf) |
16 | | : WebGLRefCountedObject(webgl) |
17 | | , mGLName(tf) |
18 | | , mIndexedBindings(webgl->mGLMaxTransformFeedbackSeparateAttribs) |
19 | | , mIsPaused(false) |
20 | | , mIsActive(false) |
21 | 0 | { |
22 | 0 | mContext->mTransformFeedbacks.insertBack(this); |
23 | 0 | } |
24 | | |
25 | | WebGLTransformFeedback::~WebGLTransformFeedback() |
26 | 0 | { |
27 | 0 | DeleteOnce(); |
28 | 0 | } |
29 | | |
30 | | void |
31 | | WebGLTransformFeedback::Delete() |
32 | 0 | { |
33 | 0 | if (mGLName) { |
34 | 0 | mContext->gl->fDeleteTransformFeedbacks(1, &mGLName); |
35 | 0 | } |
36 | 0 | removeFrom(mContext->mTransformFeedbacks); |
37 | 0 | } |
38 | | |
39 | | //////////////////////////////////////// |
40 | | |
41 | | void |
42 | | WebGLTransformFeedback::BeginTransformFeedback(GLenum primMode) |
43 | 0 | { |
44 | 0 | if (mIsActive) |
45 | 0 | return mContext->ErrorInvalidOperation("Already active."); |
46 | 0 | |
47 | 0 | switch (primMode) { |
48 | 0 | case LOCAL_GL_POINTS: |
49 | 0 | case LOCAL_GL_LINES: |
50 | 0 | case LOCAL_GL_TRIANGLES: |
51 | 0 | break; |
52 | 0 | default: |
53 | 0 | mContext->ErrorInvalidEnum("`primitiveMode` must be one of POINTS, LINES, or" |
54 | 0 | " TRIANGLES."); |
55 | 0 | return; |
56 | 0 | } |
57 | 0 | |
58 | 0 | const auto& prog = mContext->mCurrentProgram; |
59 | 0 | if (!prog || |
60 | 0 | !prog->IsLinked() || |
61 | 0 | prog->LinkInfo()->componentsPerTFVert.empty()) |
62 | 0 | { |
63 | 0 | mContext->ErrorInvalidOperation("Current program not valid for transform" |
64 | 0 | " feedback."); |
65 | 0 | return; |
66 | 0 | } |
67 | 0 | |
68 | 0 | const auto& linkInfo = prog->LinkInfo(); |
69 | 0 | const auto& componentsPerTFVert = linkInfo->componentsPerTFVert; |
70 | 0 |
|
71 | 0 | size_t minVertCapacity = SIZE_MAX; |
72 | 0 | for (size_t i = 0; i < componentsPerTFVert.size(); i++) { |
73 | 0 | const auto& indexedBinding = mIndexedBindings[i]; |
74 | 0 | const auto& componentsPerVert = componentsPerTFVert[i]; |
75 | 0 |
|
76 | 0 | const auto& buffer = indexedBinding.mBufferBinding; |
77 | 0 | if (!buffer) { |
78 | 0 | mContext->ErrorInvalidOperation("No buffer attached to required transform" |
79 | 0 | " feedback index %u.", |
80 | 0 | (uint32_t)i); |
81 | 0 | return; |
82 | 0 | } |
83 | 0 | |
84 | 0 | const size_t vertCapacity = buffer->ByteLength() / 4 / componentsPerVert; |
85 | 0 | minVertCapacity = std::min(minVertCapacity, vertCapacity); |
86 | 0 | } |
87 | 0 |
|
88 | 0 | //// |
89 | 0 |
|
90 | 0 | const auto& gl = mContext->gl; |
91 | 0 | gl->fBeginTransformFeedback(primMode); |
92 | 0 |
|
93 | 0 | //// |
94 | 0 |
|
95 | 0 | mIsActive = true; |
96 | 0 | MOZ_ASSERT(!mIsPaused); |
97 | 0 |
|
98 | 0 | mActive_Program = prog; |
99 | 0 | mActive_PrimMode = primMode; |
100 | 0 | mActive_VertPosition = 0; |
101 | 0 | mActive_VertCapacity = minVertCapacity; |
102 | 0 |
|
103 | 0 | //// |
104 | 0 |
|
105 | 0 | mActive_Program->mNumActiveTFOs++; |
106 | 0 | } |
107 | | |
108 | | |
109 | | void |
110 | | WebGLTransformFeedback::EndTransformFeedback() |
111 | 0 | { |
112 | 0 | if (!mIsActive) |
113 | 0 | return mContext->ErrorInvalidOperation("Not active."); |
114 | 0 | |
115 | 0 | //// |
116 | 0 | |
117 | 0 | const auto& gl = mContext->gl; |
118 | 0 | gl->fEndTransformFeedback(); |
119 | 0 |
|
120 | 0 | if (gl->WorkAroundDriverBugs()) { |
121 | | #ifdef XP_MACOSX |
122 | | // Multi-threaded GL on mac will generate INVALID_OP in some cases for at least |
123 | | // BindBufferBase after an EndTransformFeedback if there is not a flush between |
124 | | // the two. |
125 | | // Single-threaded GL does not have this issue. |
126 | | // This is likely due to not synchronizing client/server state, and erroring in |
127 | | // BindBufferBase because the client thinks we're still in transform feedback. |
128 | | gl->fFlush(); |
129 | | #endif |
130 | | } |
131 | 0 |
|
132 | 0 | //// |
133 | 0 |
|
134 | 0 | mIsActive = false; |
135 | 0 | mIsPaused = false; |
136 | 0 |
|
137 | 0 | //// |
138 | 0 |
|
139 | 0 | mActive_Program->mNumActiveTFOs--; |
140 | 0 | } |
141 | | |
142 | | void |
143 | | WebGLTransformFeedback::PauseTransformFeedback() |
144 | 0 | { |
145 | 0 | if (!mIsActive || |
146 | 0 | mIsPaused) |
147 | 0 | { |
148 | 0 | mContext->ErrorInvalidOperation("Not active or is paused."); |
149 | 0 | return; |
150 | 0 | } |
151 | 0 | |
152 | 0 | //// |
153 | 0 | |
154 | 0 | const auto& gl = mContext->gl; |
155 | 0 | gl->fPauseTransformFeedback(); |
156 | 0 |
|
157 | 0 | //// |
158 | 0 |
|
159 | 0 | mIsPaused = true; |
160 | 0 | } |
161 | | |
162 | | void |
163 | | WebGLTransformFeedback::ResumeTransformFeedback() |
164 | 0 | { |
165 | 0 | if (!mIsPaused) |
166 | 0 | return mContext->ErrorInvalidOperation("Not paused."); |
167 | 0 | |
168 | 0 | if (mContext->mCurrentProgram != mActive_Program) { |
169 | 0 | mContext->ErrorInvalidOperation("Active program differs from original."); |
170 | 0 | return; |
171 | 0 | } |
172 | 0 | |
173 | 0 | //// |
174 | 0 | |
175 | 0 | const auto& gl = mContext->gl; |
176 | 0 | gl->fResumeTransformFeedback(); |
177 | 0 |
|
178 | 0 | //// |
179 | 0 |
|
180 | 0 | MOZ_ASSERT(mIsActive); |
181 | 0 | mIsPaused = false; |
182 | 0 | } |
183 | | |
184 | | //////////////////////////////////////// |
185 | | |
186 | | void |
187 | | WebGLTransformFeedback::AddBufferBindCounts(int8_t addVal) const |
188 | 0 | { |
189 | 0 | const GLenum target = LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER; |
190 | 0 | for (const auto& binding : mIndexedBindings) { |
191 | 0 | WebGLBuffer::AddBindCount(target, binding.mBufferBinding.get(), addVal); |
192 | 0 | } |
193 | 0 | } |
194 | | |
195 | | //////////////////////////////////////// |
196 | | |
197 | | JSObject* |
198 | | WebGLTransformFeedback::WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto) |
199 | 0 | { |
200 | 0 | return dom::WebGLTransformFeedback_Binding::Wrap(cx, this, givenProto); |
201 | 0 | } |
202 | | |
203 | | NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLTransformFeedback, AddRef) |
204 | | NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLTransformFeedback, Release) |
205 | | NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebGLTransformFeedback, |
206 | | mIndexedBindings, |
207 | | mActive_Program) |
208 | | |
209 | | } // namespace mozilla |