Line data Source code
1 : /* -*- Mode: C++; tab-width: 20; 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 "WebGLUniformLocation.h"
7 :
8 : #include "GLContext.h"
9 : #include "mozilla/SizePrintfMacros.h"
10 : #include "mozilla/dom/ToJSValue.h"
11 : #include "mozilla/dom/WebGLRenderingContextBinding.h"
12 : #include "WebGLActiveInfo.h"
13 : #include "WebGLContext.h"
14 : #include "WebGLProgram.h"
15 :
16 : namespace mozilla {
17 :
18 0 : WebGLUniformLocation::WebGLUniformLocation(WebGLContext* webgl,
19 : const webgl::LinkedProgramInfo* linkInfo,
20 : webgl::UniformInfo* info, GLuint loc,
21 0 : size_t arrayIndex)
22 : : WebGLContextBoundObject(webgl)
23 : , mLinkInfo(linkInfo)
24 : , mInfo(info)
25 : , mLoc(loc)
26 0 : , mArrayIndex(arrayIndex)
27 0 : { }
28 :
29 0 : WebGLUniformLocation::~WebGLUniformLocation()
30 0 : { }
31 :
32 : bool
33 0 : WebGLUniformLocation::ValidateForProgram(const WebGLProgram* prog,
34 : const char* funcName) const
35 : {
36 : // Check the weak-pointer.
37 0 : if (!mLinkInfo) {
38 0 : mContext->ErrorInvalidOperation("%s: This uniform location is obsolete because"
39 : " its program has been successfully relinked.",
40 0 : funcName);
41 0 : return false;
42 : }
43 :
44 0 : if (mLinkInfo->prog != prog) {
45 0 : mContext->ErrorInvalidOperation("%s: This uniform location corresponds to a"
46 0 : " different program.", funcName);
47 0 : return false;
48 : }
49 :
50 0 : return true;
51 : }
52 :
53 : static bool
54 0 : IsUniformSetterTypeValid(GLenum setterType, GLenum uniformType)
55 : {
56 : // The order in this switch matches table 2.10 from OpenGL ES
57 : // 3.0.4 (Aug 27, 2014) es_spec_3.0.4.pdf
58 0 : switch (uniformType) {
59 : case LOCAL_GL_FLOAT:
60 : case LOCAL_GL_FLOAT_VEC2:
61 : case LOCAL_GL_FLOAT_VEC3:
62 : case LOCAL_GL_FLOAT_VEC4:
63 0 : return setterType == LOCAL_GL_FLOAT;
64 :
65 : case LOCAL_GL_INT:
66 : case LOCAL_GL_INT_VEC2:
67 : case LOCAL_GL_INT_VEC3:
68 : case LOCAL_GL_INT_VEC4:
69 0 : return setterType == LOCAL_GL_INT;
70 :
71 : case LOCAL_GL_UNSIGNED_INT:
72 : case LOCAL_GL_UNSIGNED_INT_VEC2:
73 : case LOCAL_GL_UNSIGNED_INT_VEC3:
74 : case LOCAL_GL_UNSIGNED_INT_VEC4:
75 0 : return setterType == LOCAL_GL_UNSIGNED_INT;
76 :
77 : /* bool can be set via any function: 0, 0.0f -> FALSE, _ -> TRUE */
78 : case LOCAL_GL_BOOL:
79 : case LOCAL_GL_BOOL_VEC2:
80 : case LOCAL_GL_BOOL_VEC3:
81 : case LOCAL_GL_BOOL_VEC4:
82 0 : return (setterType == LOCAL_GL_INT ||
83 0 : setterType == LOCAL_GL_FLOAT ||
84 0 : setterType == LOCAL_GL_UNSIGNED_INT);
85 :
86 : case LOCAL_GL_FLOAT_MAT2:
87 : case LOCAL_GL_FLOAT_MAT3:
88 : case LOCAL_GL_FLOAT_MAT4:
89 : case LOCAL_GL_FLOAT_MAT2x3:
90 : case LOCAL_GL_FLOAT_MAT2x4:
91 : case LOCAL_GL_FLOAT_MAT3x2:
92 : case LOCAL_GL_FLOAT_MAT3x4:
93 : case LOCAL_GL_FLOAT_MAT4x2:
94 : case LOCAL_GL_FLOAT_MAT4x3:
95 0 : return setterType == LOCAL_GL_FLOAT;
96 :
97 : /* Samplers can only be set via Uniform1i */
98 : case LOCAL_GL_SAMPLER_2D:
99 : case LOCAL_GL_SAMPLER_3D:
100 : case LOCAL_GL_SAMPLER_CUBE:
101 : case LOCAL_GL_SAMPLER_2D_SHADOW:
102 : case LOCAL_GL_SAMPLER_2D_ARRAY:
103 : case LOCAL_GL_SAMPLER_2D_ARRAY_SHADOW:
104 : case LOCAL_GL_SAMPLER_CUBE_SHADOW:
105 :
106 : case LOCAL_GL_INT_SAMPLER_2D:
107 : case LOCAL_GL_INT_SAMPLER_3D:
108 : case LOCAL_GL_INT_SAMPLER_CUBE:
109 : case LOCAL_GL_INT_SAMPLER_2D_ARRAY:
110 :
111 : case LOCAL_GL_UNSIGNED_INT_SAMPLER_2D:
112 : case LOCAL_GL_UNSIGNED_INT_SAMPLER_3D:
113 : case LOCAL_GL_UNSIGNED_INT_SAMPLER_CUBE:
114 : case LOCAL_GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
115 0 : return setterType == LOCAL_GL_INT;
116 :
117 : default:
118 0 : MOZ_CRASH("GFX: Bad `uniformType`.");
119 : }
120 : }
121 :
122 : bool
123 0 : WebGLUniformLocation::ValidateSizeAndType(uint8_t setterElemSize, GLenum setterType,
124 : const char* funcName) const
125 : {
126 0 : MOZ_ASSERT(mLinkInfo);
127 :
128 0 : const auto& uniformElemSize = mInfo->mActiveInfo->mElemSize;
129 0 : if (setterElemSize != uniformElemSize) {
130 0 : mContext->ErrorInvalidOperation("%s: Function used differs from uniform size: %i",
131 0 : funcName, uniformElemSize);
132 0 : return false;
133 : }
134 :
135 0 : const auto& uniformElemType = mInfo->mActiveInfo->mElemType;
136 0 : if (!IsUniformSetterTypeValid(setterType, uniformElemType)) {
137 0 : mContext->ErrorInvalidOperation("%s: Function used is incompatible with uniform"
138 : " type: %i",
139 0 : funcName, uniformElemType);
140 0 : return false;
141 : }
142 :
143 0 : return true;
144 : }
145 :
146 : bool
147 0 : WebGLUniformLocation::ValidateArrayLength(uint8_t setterElemSize, size_t setterArraySize,
148 : const char* funcName) const
149 : {
150 0 : MOZ_ASSERT(mLinkInfo);
151 :
152 0 : if (setterArraySize == 0 ||
153 0 : setterArraySize % setterElemSize)
154 : {
155 0 : mContext->ErrorInvalidValue("%s: Expected an array of length a multiple of %d,"
156 : " got an array of length %" PRIuSIZE ".",
157 0 : funcName, setterElemSize, setterArraySize);
158 0 : return false;
159 : }
160 :
161 : /* GLES 2.0.25, Section 2.10, p38
162 : * When loading `N` elements starting at an arbitrary position `k` in a uniform
163 : * declared as an array, elements `k` through `k + N - 1` in the array will be
164 : * replaced with the new values. Values for any array element that exceeds the
165 : * highest array element index used, as reported by `GetActiveUniform`, will be
166 : * ignored by GL.
167 : */
168 0 : if (!mInfo->mActiveInfo->mIsArray &&
169 0 : setterArraySize != setterElemSize)
170 : {
171 0 : mContext->ErrorInvalidOperation("%s: Expected an array of length exactly %d"
172 : " (since this uniform is not an array uniform),"
173 : " got an array of length %" PRIuSIZE ".",
174 0 : funcName, setterElemSize, setterArraySize);
175 0 : return false;
176 : }
177 :
178 0 : return true;
179 : }
180 :
181 : JS::Value
182 0 : WebGLUniformLocation::GetUniform(JSContext* js) const
183 : {
184 0 : MOZ_ASSERT(mLinkInfo);
185 :
186 0 : const uint8_t elemSize = mInfo->mActiveInfo->mElemSize;
187 : static const uint8_t kMaxElemSize = 16;
188 0 : MOZ_ASSERT(elemSize <= kMaxElemSize);
189 :
190 0 : GLuint prog = mLinkInfo->prog->mGLName;
191 :
192 0 : gl::GLContext* gl = mContext->GL();
193 0 : gl->MakeCurrent();
194 :
195 0 : switch (mInfo->mActiveInfo->mElemType) {
196 : case LOCAL_GL_INT:
197 : case LOCAL_GL_INT_VEC2:
198 : case LOCAL_GL_INT_VEC3:
199 : case LOCAL_GL_INT_VEC4:
200 : case LOCAL_GL_SAMPLER_2D:
201 : case LOCAL_GL_SAMPLER_3D:
202 : case LOCAL_GL_SAMPLER_CUBE:
203 : case LOCAL_GL_SAMPLER_2D_SHADOW:
204 : case LOCAL_GL_SAMPLER_2D_ARRAY:
205 : case LOCAL_GL_SAMPLER_2D_ARRAY_SHADOW:
206 : case LOCAL_GL_SAMPLER_CUBE_SHADOW:
207 : case LOCAL_GL_INT_SAMPLER_2D:
208 : case LOCAL_GL_INT_SAMPLER_3D:
209 : case LOCAL_GL_INT_SAMPLER_CUBE:
210 : case LOCAL_GL_INT_SAMPLER_2D_ARRAY:
211 : case LOCAL_GL_UNSIGNED_INT_SAMPLER_2D:
212 : case LOCAL_GL_UNSIGNED_INT_SAMPLER_3D:
213 : case LOCAL_GL_UNSIGNED_INT_SAMPLER_CUBE:
214 : case LOCAL_GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
215 : {
216 0 : GLint buffer[kMaxElemSize] = {0};
217 0 : gl->fGetUniformiv(prog, mLoc, buffer);
218 :
219 0 : if (elemSize == 1)
220 0 : return JS::Int32Value(buffer[0]);
221 :
222 0 : JSObject* obj = dom::Int32Array::Create(js, mContext, elemSize, buffer);
223 0 : if (!obj) {
224 0 : mContext->ErrorOutOfMemory("getUniform: Out of memory.");
225 0 : return JS::NullValue();
226 : }
227 0 : return JS::ObjectOrNullValue(obj);
228 : }
229 :
230 : case LOCAL_GL_BOOL:
231 : case LOCAL_GL_BOOL_VEC2:
232 : case LOCAL_GL_BOOL_VEC3:
233 : case LOCAL_GL_BOOL_VEC4:
234 : {
235 0 : GLint buffer[kMaxElemSize] = {0};
236 0 : gl->fGetUniformiv(prog, mLoc, buffer);
237 :
238 0 : if (elemSize == 1)
239 0 : return JS::BooleanValue(buffer[0]);
240 :
241 : bool boolBuffer[kMaxElemSize];
242 0 : for (uint8_t i = 0; i < kMaxElemSize; i++)
243 0 : boolBuffer[i] = buffer[i];
244 :
245 0 : JS::RootedValue val(js);
246 : // Be careful: we don't want to convert all of |uv|!
247 0 : if (!dom::ToJSValue(js, boolBuffer, elemSize, &val)) {
248 0 : mContext->ErrorOutOfMemory("getUniform: Out of memory.");
249 0 : return JS::NullValue();
250 : }
251 0 : return val;
252 : }
253 :
254 : case LOCAL_GL_FLOAT:
255 : case LOCAL_GL_FLOAT_VEC2:
256 : case LOCAL_GL_FLOAT_VEC3:
257 : case LOCAL_GL_FLOAT_VEC4:
258 : case LOCAL_GL_FLOAT_MAT2:
259 : case LOCAL_GL_FLOAT_MAT3:
260 : case LOCAL_GL_FLOAT_MAT4:
261 : case LOCAL_GL_FLOAT_MAT2x3:
262 : case LOCAL_GL_FLOAT_MAT2x4:
263 : case LOCAL_GL_FLOAT_MAT3x2:
264 : case LOCAL_GL_FLOAT_MAT3x4:
265 : case LOCAL_GL_FLOAT_MAT4x2:
266 : case LOCAL_GL_FLOAT_MAT4x3:
267 : {
268 0 : GLfloat buffer[16] = {0.0f};
269 0 : gl->fGetUniformfv(prog, mLoc, buffer);
270 :
271 0 : if (elemSize == 1)
272 0 : return JS::DoubleValue(buffer[0]);
273 :
274 0 : JSObject* obj = dom::Float32Array::Create(js, mContext, elemSize, buffer);
275 0 : if (!obj) {
276 0 : mContext->ErrorOutOfMemory("getUniform: Out of memory.");
277 0 : return JS::NullValue();
278 : }
279 0 : return JS::ObjectOrNullValue(obj);
280 : }
281 :
282 : case LOCAL_GL_UNSIGNED_INT:
283 : case LOCAL_GL_UNSIGNED_INT_VEC2:
284 : case LOCAL_GL_UNSIGNED_INT_VEC3:
285 : case LOCAL_GL_UNSIGNED_INT_VEC4:
286 : {
287 0 : GLuint buffer[kMaxElemSize] = {0};
288 0 : gl->fGetUniformuiv(prog, mLoc, buffer);
289 :
290 0 : if (elemSize == 1)
291 0 : return JS::DoubleValue(buffer[0]); // This is Double because only Int32 is special cased.
292 :
293 0 : JSObject* obj = dom::Uint32Array::Create(js, mContext, elemSize, buffer);
294 0 : if (!obj) {
295 0 : mContext->ErrorOutOfMemory("getUniform: Out of memory.");
296 0 : return JS::NullValue();
297 : }
298 0 : return JS::ObjectOrNullValue(obj);
299 : }
300 :
301 : default:
302 0 : MOZ_CRASH("GFX: Invalid elemType.");
303 : }
304 : }
305 :
306 : ////////////////////////////////////////////////////////////////////////////////
307 :
308 : JSObject*
309 0 : WebGLUniformLocation::WrapObject(JSContext* js, JS::Handle<JSObject*> givenProto)
310 : {
311 0 : return dom::WebGLUniformLocationBinding::Wrap(js, this, givenProto);
312 : }
313 :
314 0 : NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WebGLUniformLocation)
315 :
316 0 : NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLUniformLocation, AddRef)
317 0 : NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLUniformLocation, Release)
318 :
319 : } // namespace mozilla
|